BSidesTLV 2021 CTF — Are You Kidding Me? (Challenge Writeup)

Maor A.
5 min readJul 30, 2021
BSidesTLV 2021 CTF

BSidesTLV is one of Israel’s leading cyber conferences for hackers and security researchers — also hosting the annual Capture The Flag (CTF) competition

The challenge description:

Video URL: https://youtu.be/_GOR5gvQwDI

Challenge URL: https://are-you-kidding-me.ctf.bsidestlv.com/

Let’s get in

are-you-kidding-me.ctf.bsidestlv.com main page
Two Cookies are set upon first request (PHPSEEID, BSidesTLV)

We are not authenticated, and yet two Cookies are set upon first request (PHPSEEID, BSidesTLV)

(Note: we were told on the CTF description that the BSidesTLV Cookie is part of the infrastructure. This cookie seems to route us back to the same backend server)

let’s Login

Main page after login

Upon login, we got what seems like JWT Token

“auth” Cookie Received upon “login”

Let’s inspect the JWT Token we got (Using https://jwt.io/)

Decoded “auth” JWT Token received

Interesting, there is a custom JWT claim namely “admin” with the value false

Note: If we use an old JWT Token, we get the following error:

Error received while using an old or manipulated (invalid signature) JWT Token

let’s try to manipulate the original JWT Token

Manually manipulating the “admin” Claim

Directly using the modified JWT Token (“admin:True” with Invalid Signature)

Error Received when directly using the manipulated JWT Token (admin claim)

Upon sending the modified JWT Token (Invalid Signature) we receive an error (Failed to verify token)

After some tries, I figured that by adding the modified JWT Token (admin True) just before the valid token grant “Admin Access” (see the figure below)

Admin access is granted by using “admin JWT” before the valid JWT

Note about the issue:

• This situation is likely because the JWT Signature-validation and Access-control checks happen in different components.

  • So, the first component checks the Signature of the “Valid-Token” (the second token) and then forward it to the second component,
  • The second component check the “Admin-Token” (the first token) and grants admin access (this component assumes the signature was tested before, and so accept the content)

Let’s create a burp rule to add our “admin” Token just before any request to the server

Configuring Burp-Proxy match/replace Rule

Nice so we got a File Upload Page, Let’s inspect it

Usually, if there is a file upload for a PHP site, our goal will be to upload a PHP web shell so we can use it to run commands on the server-side. (And in this case, find and read the flag file)

Let’s try to upload a PHP file

Select a PHP File for upload

Notice the “File will be named: php” Part (we tried uploading “m2a.php”)

Upload the file

Our PHP file seems to upload to the web-server

Nice seems like we upload a file, Let’s look at it

Our PHP file did upload to the server — but no PHP “execution”

So, the file did Upload but it is not processed by the server as PHP “executable” the server returned our file content as text.

Let’s inspect the server’s upload folder for clues

Directory listing of our Uploads folder

We have a directory listing of our Uploads folder

Note: The path “<host>/uploads/” do not have a directory listing

Ok back to the PHP file

After some online research, I figured that this behavior can be configured on the Apache server by using the “.htaccess” file in the current directory

Let’s test if this file exists.

.htaccess file exists in our uploads folder — Notice the “engine off” php-flag

“.htaccess” file exists in our uploads folder — Notice the “engine off” php-flag

What do we know :)?

The file exists and we got the “php_flag engine off” which tells the (Apache) web-server to not process the PHP files

Reference: https://electrictoolbox.com/disable-php-apache-htaccess/

OK, so the plan now is to upload some PHP Web-shell (file) and update the “.htaccess” file to process our file.

First, let’s see if we can update the “.htaccess” file (do we got the relevant permissions?)

Trying to upload the .htaccess file directly (notice filename change)

If we try to directly upload a “.htaccess” file we see the filename will be changed to htaccess (without the dot).

ok this “filename renaming” seem to happen on the client-side, let’s inspect the code and see if we can update the “.htaccess” file

Inspecting the Client-side code used for the filename manipulations

While inspecting the source code of the page we notice there is a regex evaluation on the “fileToUpload” element — and this code “cut” our file prefix.

Notice the “.filter(Boolean).pop();” this will “pop” the last item in the returned JavaScript Array

So we need the regex “([\w]+\.?)(\.?\1)?$” to extract a filename that includes a dot at the beginning of the string.

let’s try to evaluate the regex expression and see if we can create the “.htaccess” filename

Using the following site for assistance: https://regex101.com/

Found a string that will return a “valid” filename (that starts with a dot)

After some trial and error, we found a valid string that in turn will create the requested filename (.htaccess)

let’s test it.

.htaccess file upload dialog (notice filename)

Now let’s figure out how can we make the web-server “execute” our php-file

After some retries, I managed to figure the required .htaccess settings that will execute our php-file

.htaccess configuration for PHP (execution) — engine on

Let’s test our PHP file

our PHP-file executing “system” (ls -la) command on server-side

Cool, we got command execution on the server, lets upload a web-shell for (easy navigation) and look for the flag.

a quick google search led me to this code:

A PHP-web-shell (by GitHub user: https://gist.github.com/joswr1ght)

Reference: https://gist.github.com/joswr1ght/22f40787de19d80d110b37fb79ac3985

Upload it to the server, and we have “interactive” command execution on the server.

Listing back directories till we find the flag

Command execution on the web-server listing folder and reading flag-file content

Well done we have the flag!

--

--