Each year NVISO organizes a CTF for students passionate about cybersecurity. We get to show of our skills by solving challenges which are made by professionals in the field so most of the hard challenges are pretty close to realistic scenarios.

Below I'll describe how I managed to solve 2 of the hardest web challenges which both were similar to scenarios I encountered during my bug bounty adventures. One of the challenges was actually made by another bounty hunter Arne Swinnen.

challenge 1: COME OUT, COME OUT, WHEREVER YOU ARE!

This is the first challenge I'll be discussing. Let's have a look at the challenge description:

From this we can already learn a couple things:

Arne found this remarkably often during his Bug Bounty endeavours. In bug bounty there's lots of competition and you often deal with high level security so SQLi and friends are rather rare. I knew this was going to be a bit exotic.

Suggestion: start with /etc/issue, ok so we're safe to assume it's gonna be LFI with a twist, let's hack!

When we open the link we're presented with the following screen:

This reveals we're running an instance of GeoServer that's using Java as it's back-end. Let's have a look at the GeoServer thingy and proceed with our recon.

While getting to know the application I quickly stumble across the following demo page:

This is what we get if we open any of the listed map objects:

Ok so at this point I already know what the problem is. Before we procees to the exploit let's do 1 more recon thingy. At the end, this is a real product so maybe other hackers already looked at this? Google is out friend! Let's query Google for GeoServer exploits.

The following exploit showed up which confirmed my suspicions of an XXE. Ofcourse this exploit script didn't work, Arne put a twist to the actual exploit. This is where the real challenge starts.

Exploiting the XXE

From the public exploit we learn the injection point. From there on we rely on our own creativity. Let's have a look at what happens when we try to inject a couple basic XXE payloads:

Both payloads resulted in the following response:

Okay so using our basic payload we managed to trigger SSRF and ping our Burp Collaborator client. Since we're not being presented any response from our payload I assume we're dealing with an Out Of Band XXE which means we need another way to read that response. Let's find way to read /etc/issue

To tackle this I'll be using a technique called Out Of Band (OOB) XXE exploitation. This means that we'll force the server to send the result of a call to internal files to a server I control. This is the setup:

The following payload first calls for /etc/issue and then requests an external DTD file that will force the server to send the response that contains the file content to my server

The content of this DTD file:

This is the result:

It looks like we succeeded as the content of /etc/issue got shown in an error AND I received it in my Burp Collaborator Client. Now what happens if we try to read /etc/passwd?

We're getting an error: java.net.MalformedURLException: Illegal character in URL. So /etc/issue succeeds, but /etc/passwd doesn't? here's the twist. The difference between those two files is that /etc/issue is a one line file while /etc/passwd is a multiline file. Here's when the real pain of the challenge kicks in. The problem isn't the file we're trying to read, it's the way we're getting that file to our server.

We're currently working this way:

We send custom XML to the application's XML parser and tell it to read /etc/issue

Parser requests our DTD file and sends the content of /etc/issue to our server over HTTP.

After a lot of trial & error it turns out the problem is the way HTTP works. The HTTP 1.1 specification learns us that there should only be one CRLF character in the request between the headers and the body , so our multiline files are actually breaking the HTTP request which is why we are not receiving it's content on our server.

If this application was built in PHP we could easily solve this by base64 encoding the file's content by using the PHP:// URI< instead of HTTP in our DTD file. But PHP:// is no option here as we're working with JAVA. A quick google revaled Java supports the following URI schemes that can be used in XXE attacks:

JAR://

NETDOC://

While reading about both protocols I learned hat JAR:// also has issues with CRLF characters so I edited the DTD file to work with the NETDOC:// URI instead of the HTTP:// URI scheme. Result:

The result of our request utizing our new DTD file:

YES! we can read /etc/passwd! but we need the flag.. let's try if we can read the root of the server by simply requesting file:///

finally. We get the flag presented :) The flag itself was: cscbe{YouL33tOOBhaxxor^_^}. Hope you learned something here. :-)

challenge 2: MAD WITH POWER

This challenge is also pretty challenging from a technical perspective. Let's dive in by looking at the challenge description:

So, our goal is to obtain the e-mail of the server administrator. Let's start hacking.

The landing page of this application is nothing but a short description, a login form, a link to a status page and an option to change the langauge to Russian.

Given so few funcionality, I explored a bit more and found the start point of this challenge.

Cool, so we can log in now. Let's explore what's on the authenticated part of this website.

It looks like the admin panel introduced 3 extra functionalities:

Updating configurations

View a history of those configurations.

Control Valves.

Let's start with viewing a history of those configurations:

Ah, so we first have to upload a config file. Let's do this & intercept everything we do using Burp Suite.

There's not much to this, I selected a simple text file just to see what the normal upload flow looks like. below is an example of a successfull upload.

Hmm. we're not getting much out of this. Let's try to cause an error:

Oh this is huge! by uploading a bigger file we cause an error that reveals the location of uploaded files. If a file is uploaded it is stored in :

/var/www/html/firmware_updates/timestamp/.0

Let's try upload a PHP file and see what happens.

The request is an array where each value of the array represents the base64 encoded file value. if a file is empty it simply says '0'. I base64 encoded <?php echo 'Hacker detected!' ?> and uploaded it to the server. I got an OK back so now i had to search for my uploaded file.

Earlier we discoverd that uploaded configuration files can be viewed so let's that that:

From here we can assemble the location of our PHP file:

http://34.246.158.41/firmware_updates/ + timestamp + /.0 let's give this a try:

Okay so we got a PHP upload that actually runs. Note that the goal of this challenge is to obtain the admin's e-mail address but in a real world scenario it's game over for the company as we've achieve RCE.

PHP has a nice feature that displays it's configuration settings. You can obtain this by calling the phpinfo() function and writing it to the screen. In order to fetch phpinfo from this server I basically did the same when I uploaded my first PHP file but changed the content so that it outputs phpinfo(). When scrolling through this PHP info file I found the flag:

We're done hacking!

Big thanks to NVISO & everyone involved for organizing this CTF, I always enjoy the challenges and each time they push me to learn new techniques and attacks. I look forward to next year's CTF and other writeups from challenges I didn't manage to solve.