情人节约宝妹攻略
安全宝在情人节前出了一个网络安全闯关游戏,题目还是比较简单的。
Q1、世界上先有男人还是先有女人? 答案是“男人”。
Q2、世界上为什么先有男人? 答案是“先生”。
Q3、请从本页面找到密码并输入。 查看网页源码,可以看到一段源码:
1 2 3 4 5 6 7 8 9 <div class ="page page-3 invisible" > <div class ="dp c dp-4-1" > </div > <div class ="password-form dp c" > <input type ="text" class ="text" name ="" value ="" id ="password1" /> <a href ="javascript:;" class ="form-button h" onclick ="checkPassword(this)" > </a > </div > <div class ="dp c dp-logo" > </div > </div >
可见,输入密码后点击按钮会调用checkPassword函数,在源码里可以看到网页引用了一个index.js文件:
1 <script src ="js/index.js" type ="text/javascript" > </script >
访问该文件,里面有一段被混淆的js代码:
1 (function (b,a,c,d ) {b.showPage=function (e ) {c(".page" ).filter(".page-" +e).show().siblings().hide()};b.checkPassword=function (f ) {var e=c(f).prev().val();if (e=="wo ai anquanbao" ){showPage(4 )}else {c(f).prev().val("" ).focus()}}})(window ,document ,window .jQuery);
格式化一下js代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 (function (b, a, c, d ) { b.showPage = function (e ) { c(".page" ).filter(".page-" + e).show().siblings().hide() }; b.checkPassword = function (f ) { var e = c(f).prev().val(); if (e == "wo ai anquanbao" ) { showPage(4 ) } else { c(f).prev().val("" ).focus() } } })(window , document , window .jQuery);
可见,checkPassword函数会判断输入的密码是否为"wo ai anquanbao",是的话就调用showPage(4)函数显示第4个问题。
Q4、在这里我用.htaccess限制了访问所有图片,来找找约会地点吧。
图片里提示了"yuehui.png",访问http://yuebaomei.com/yuehui.png,发现访问不了。 查看网络请求,发现页面访问了一个地址http://yuebaomei.com/show.php?p=dGlzaGkucG5n,打开是上面那张图片。 所以show.php就是用来显示图片的脚本,参数p的值"dGlzaGkucG5n"看起来像base64编码,解码结果为"tishi.png"。
也就是说,参数p的值是图片名的base64编码,那么"yuehui.png"的base64编码为"eXVlaHVpLnBuZw=="。 访问http://yuebaomei.com/show.php?p=eXVlaHVpLnBuZw==,成功得到了约会地点:
要拿终极大奖的话可以继续答题。
Q5、在这里宝妹有三个问题,任选其一做对就有终极大奖哦。
A、我没安卓手机,不好调试。
B、我对SQL注入不太熟悉。
C、所以只能选择PHP了。
选择PHP代码审计,可以看到一段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 <?php $flag = "THIS IS FLAG" ;if ("POST" == $_SERVER ['REQUEST_METHOD' ]){ $password = $_POST ['password' ]; if (0 >= preg_match('/^[[:graph:]]{12,}$/' , $password )) { echo 'Wrong Format' ; exit ; } while (TRUE ) { $reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/' ; if (6 > preg_match_all($reg , $password , $arr )) break ; $c = 0 ; $ps = array ('punct' , 'digit' , 'upper' , 'lower' ); foreach ($ps as $pt ) { if (preg_match("/[[:$pt :]]+/" , $password )) $c += 1 ; } if ($c < 3 ) break ; if ("42" == $password ) echo $flag ; else echo 'Wrong password' ; exit ; } } ?>
Google一下,可以找到正则表达式里一些单词代表的含义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 [:graph:] #打印字符,不包括空格 [:punct:] #打印字符,匹配任何标点符号 [:digit:] #匹配任何数字 [:upper:] #匹配任何大写字母 [:lower:] #匹配任何小写字母 [:alnum:] #字母和数字 [:alpha:] #字母 [:ascii:] #0-127的ascii字符 [:blank:] #空格和制表符 [:cntrl:] #控制字符 [:print:] #打印字符,包括空格 [:space:] #空白字符(比/s多个垂直指标) [:word:] #单词字符(/w) [:xdigit:] #匹配任何16进制数字
从代码可以看出password必须符合以下条件:
1 2 3 4 5 6 7 8 9 if (0 >= preg_match('/^[[:graph:]]{12,}$/' , $password )){ echo 'Wrong Format' ; exit ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 $reg = '/([[:punct:]]+[[:digit:]]+[[:upper:]]+[[:lower:]]+)/' ;if (6 > preg_match_all($reg , $password , $arr )) break ;
1 2 3 4 5 6 7 8 9 10 11 12 $c = 0 ;$ps = array ('punct' , 'digit' , 'upper' , 'lower' );foreach ($ps as $pt ){ if (preg_match("/[[:$pt :]]+/" , $password )) $c += 1 ; } if ($c < 3 ) break ;
1 2 3 4 5 6 if ("42" == $password ) echo $flag ;else echo 'Wrong password' ;
既然密码必须等于"42",那么就和上面密码长度必须大于等于12位矛盾了,所以密码应该是在和"42"做比较的时候被转成了数字。 一个字符串,包含了数字、标点、字母,而且会被转成数字,很容易就想到了科学计数法。 比如"0.42E+2"表示0.42 * 10^2 = 42。"0.42E+2"刚好被各种字符分割成6部分,但是长度小于12,只需要补0就行了。 所以密码为"0.4200000E+2"。
输入后成功通关了:
暂时还不知道奖品是什么,期待中……