CTFer成长记录——CTF之Web专题·攻防世界—easyphp
一、题目链接:
https://adworld.xctf.org.cn/challenges/list
二、解法步骤
本题给了一大段php代码,需要代码审计以及常见的绕过手法即可获得flag。
if(isset($a) && intval($a) > 6000000 && strlen($a) <= 3)
这一判断实际上需要我们找到一个a,使得它的长度小于3,且经过intval()函数处理后的值大于6000000;对此我们需要知道intval()函数会把参数变成整型,我们传入科学计数法即可。
?a=1e9
if(isset($b) && '8b184b' === substr(md5($b),-6,6))
这一层判断需要我我们让b的最后6位的md5值等于'8b184b'。substr是截取字符串的函数,第一个参数是需要截取的字符串,第二个参数是截取开始位置,如果是负数就倒着截取,第三个参数是截取长度;因此,我们需要写一个脚本暴力破解下:
$b=1;
while(substr(md5($b),-6,6) !='8b184b') {$b++;}
var_dump($b);
最后得出?b=53724。现在我们已经绕过了第一类判断。
$c=(array)json_decode(@$_GET['c']);
这代码是告诉我们$c的值最后会被json解码一次,并且被转换为数组类型,那么可以推测c是一个数组,且需要json编码。
if(is_array($c) && !is_numeric(@$c["m"]) && $c["m"] > 2022)
这个代码肯定了c一定是个数组,而且要求c[m]的值不是数组,还要c[m]的值大于2022,这是一对自相矛盾的条件。但是注意到字符串可以被is_numeric()函数解析成数字,只需要数字+英文字母即可。于是c[m]="2023x" ,对应传参方式为:array("m"=>"2023x")这是数组中只有m这一个元素的传参方式。
if(is_array(@$c["n"]) && count($c["n"]) == 2 && is_array($c["n"][0])){
$d = array_search("DGGJ", $c["n"]);
$d === false?die("no..."):NULL;
foreach($c["n"] as $key=>$val){
$val==="DGGJ"?die("no......"):NULL;
}
这段代码要求 c[n]元素是一个数组且包含两个元素,对应应该长这样:"n"=>array(元素1,元素2);接着需要元素1是一个数组:array();最后在c[n]的数组中找"DGGJ"这个字符串,找不到输出no...,然后遍历c[n]数组,如果有“DGGJ”就输出no...。这是自相矛盾的判断,但是注意array_search()函数在搜寻的时候用的是==弱比较,对于没有数字的字符串,最后的结果为0,因此我们把元素2赋值成0即可。最后:$c=array("m"=>"2023x","n"=>array(array(),0))。
最后把c进行json编码即可:
$b=array("m"=>"2023x","n"=>array(array(),0));
$b=json_encode($b);
var_dump($b);
传参?c={"m":"2023x","n":[[],0]}
payload:?a=1e9&&b=53724&&c={"m":"9999x","n":[[],0]}
三、总结
本题并不难,需要一定的php代码审计能力,还需要熟悉常见的弱比较绕过方式。