ZCTF线下赛php弱类型

0x01源码获取

源码泄露,通过源码泄露工具获得一个php文件

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<?php
error_reporting(0);
define('FLAG','CTF{THIS_IS_FLAG}');
$l01o=0;
$o1l0=0;
$o10l=0;
$lo10=0;
if (isset($_GET['vhghf'])) //GET传入一个vhghf
{
$vhghf = $_GET['vhghf'];
$vhghf=="1"?die("ha?"):NULL; //如果vhghf等于1则退出
switch ($vhghf)
{
case 0:
case 1: //如果vhghf等于1则$101o等于1
$l01o=1;
echo "1";
break;
}
}
$dfgdf=(array)json_decode(@$_GET['dfgdf']); //GET传入dfgdf且进行json_decode且创建一个数组
if(is_array($dfgdf)){ //如果为数组则进行接下来的
is_numeric(@$dfgdf["gvnghdjk"])?die("ha?"):NULL; //判断dfgdf中的gvnghdjk是否为数字或数字字符串
if(@$dfgdf["gvnghdjk"]){
($dfgdf["gvnghdjk"]>2017)?$o1l0=1:NULL; //gvnghdjk大于2017
}
var_dump($dfgdf["uxcndffznb"]);
if(is_array(@$dfgdf["uxcndffznb"])){ //uxcndffznb要为数组
echo "2";
if(count($dfgdf["uxcndffznb"])!==2 OR !is_array($dfgdf["uxcndffznb"][0])) die("ha?"); //数组中有两个值,且第一个还要为数组
$kghdhfghdfgbcvhgffg = array_search("ZCTF", $dfgdf["uxcndffznb"]); //查询uxcndffznb中有没有ZCTF有则返回1没则返回false
var_dump($kghdhfghdfgbcvhgffg);
$kghdhfghdfgbcvhgffg===false?die("ha?"):NULL; //如果为false则退出
foreach($dfgdf["uxcndffznb"] as $key=>$val){ //查询uxcndffznb中是否有ZCTF如果有则退出
var_dump($val);
$val==="ZCTF"?die("ha?"):NULL;
echo $val;
}
$o10l=1;
echo "3"."<br>";
}
}
$cdggjydcnfsdyjaq = $_GET['cdggjydcnfsdyjaq']; //MD5碰撞
if ($cdggjydcnfsdyjaq != '15562') {
if (strstr($cdggjydcnfsdyjaq, '2017ZCTF')) {
if (substr(md5($cdggjydcnfsdyjaq),8,16) == substr(md5('15562'),8,16)) {
echo "4"."<br>";
$lo10=1;
}
}
}
if($l01o && $o1l0 && $o10l && $lo10){
echo "success,flag:".FLAG;
}
?>

getflag前提:要求($l01o && $o1l0 && $o10l && $lo10)都符合要求了就出flag,而具体看就是要求这四个值都为1

0x02分析

l01o

1
将vhghf与1进行比较,而且是双等号,直接1+任意字母绕过

o1l0+o10l

1
2
3
4
5
6
7
8
9
10
dfgdf["gvnghdjk"]>2017与第一个相似,用大于2017的数值加任意字母绕过
array_search是弱类型的比较
var_dump(in_array("abc", $array1));</br>
var_dump(in_array("1bc", $array2));
它遍历了array的每个值,并且作"=="比较(“当设置了strict 用===”)
结果很明显了
如果array1里面有个值为0,那么第一条返回就会为真//intval('abc')=0
如果array2里面有个值为1,那么第二条就会为真//intval('1bc')=1
数字0双等于所有的无数字开头的字符串,可以用0去绕过array_search的比较

lo10

1
2
3
$cdggjydcnfsdyjaq != '15562'
(substr(md5($cdggjydcnfsdyjaq),8,16) == substr(md5('15562'),8,16))

线上赛已经出现过

0x03 测试

1
2
payload=
?vhghf=1a$&&dfgdf={"gvnghdjk":"2018aaa","uxcndffznb":[["ZCTF"],0]}&&cdggjydcnfsdyjaq=x2017ZCTF24834

------*** end*** ------