Advent of CTF - Challenge 21

“Obscure Sessions”


Todays challenge is based on that of the XCTF Final 2018 BestPHP. I thought it was such a neat trick that I wanted to share it with you. The challenge is about the affects a well intended PHP ability can have. What you will learn:

  • The call_user_func function
  • The extract function
  • PHP sessions


The challenge starts with a listing of code.

Figure 1: Start of the challenge

The code that is listed is reproduced below. Most notably, in the first section ini_set is used to limit where PHP is allowed to read files. Next the $function is set to the parameter function from the URL. This function is passed to the call_user_func function, which according to the documentation does the following:

call_user_func — Call the callback given by the first parameter

After that call, whatever is in the $file parameter will be included. The end of the function actually calls start_session to persist the name POST parameter for later use.


ini_set('display_errors', 0);
ini_set('open_basedir', '/var/www/html:/tmp');

# Make sure no evil things are passed in the URL
$file = 'filters.php';
$func = isset($_GET['function'])?$_GET['function']:'filters';

# Save the name for later
if ($_POST["name"]){
    $_SESSION["name"] = $_POST["name"];

header("Location: /index.php");

so, how can this be leveraged? In PHP there is a function called extract. The documentation says the following about it:

extract — Import variables into the current symbol table from an array

A little further down in the documentation is a warning about its use:

Warning Do not use extract() on untrusted data, like user input (e.g. $_GET, $_FILES).

Why is this? Well, the function will “import” variables into the current scope from the array passed. So if an array is passed with a file key, that entry will overwrite whatever is in $file. To try this out, lets extract the index.php file using a base64 encoder as we have used in the past.

Retrieving the flag will not work, as it is outside the base path. You will however find out that in /tmp the session files are stored. This can be leverated as you have the ability to add something to the session through the name post parameter. In the curl command below the PHP expression <?= is called, which will echo the result of the function call inside of it, in this case the system call. You have to use system as it is not possible for regular PHP functions to read outside of the base path.

curl -v -X POST -d "name=<?=system('cat /flag.txt');?>"

In the output it is important to note the PHPSESSID, as that session will contain the payload.

< Set-Cookie: PHPSESSID=232acdf771eaf2d75c03d7ef31960ce9; path=/

The last step is to use extract to override the file variable and point it to the session that is stored with the payload.

It will end up printing the payload to the screen.

Figure 2: The flag

Be sure to also grab the badge!


Go back to the homepage.