TechWeekend CTF: A Writeup

Table of Contents

1 Misc

1.1 Discord

Server announcements.

1.2 Song

Ran the text in a whitespace (programming language) interpreter.

1.3 Invisible Ink

Couldn’t solve but highly likely it involves the zero width non joiners in document.xml

1.4 Amogus

Couldn’t solve, tried Morse code. “impostor to scan on their TV” could be a clue but visualisation didn’t work.

2 Web

2.1 Bargain

Our wallet is empty but the flag is too costly. Inspected HTML, took the value of param price from flag item’s href, decoded it from base64, modified it t0 zero, encrypted it again and appended to root url.

2.2 Biscuit

Similiar to induction ctf, biscuit ~ cookie, so I modified the cookie and set ADMIN to true.

2.3 Boogie

SQL injection with payload: 1 or 1.

2.4 reffffffffffferer

Title clearly refers (no pun intended) to Referer header in GET request. Changed it to www.google.com and got lucky.

2.5 Smartest Brick On The Planet

curl --user-agent 'Supreme Smart Brick' https://cte.bitskrieg.org/web_chall3/flag

2.6 Return to Monke

Couldn’t solve but tried lots of JWT tools on the token.

3 Rev

3.1 Raincheck?

Using strings gave me the flag now when I tried to solve it again, but if I remember correctly, I used buffer overflow back then to set id.

3.2 FILEFIBDOWNLOADERROR

We know the encoding process, and we know some of the cleartext (TECHWKND{}) so using that I fixed the missing symbols to match ciphertext, and then reversed the encoding process

flag = "TFDJZPVQ{S…ÃŁǘʖПځ੉Ⴉ᪞⫲䕽灐땑𒕆𝪐𯾅񍦣񽣥󋉴}"

x = len(flag)


def somefunc(i):
    a = 0
    b = 1
    if i == 0:
        return 0

    if i == 1:
        return 1

    if i >= 2:
        c = 0
        for ctr in range(1, i):
            c = a + b
            a = b
            b = c

        return c


for i in range(0, x):
    if flag[i] == '{' or flag[i] == '}':
        print(flag[i], end='')
    else:
        print(chr(ord(flag[i]) - somefunc(i)), end='')

3.3 h0me

Similiar to one of the induction CTF problems, all you had to do was keep spamming A’s till our location’s pointer got filled with the hex for A. Then, take into consideration little endian and a hex to ascii table to modify the last four letters to fill it with HOME’s hex instead of A’s hex 4 times.

3.4 Suspended

strings and done.

3.5 Ruthless, merciless, pitiless malware

Running file on the exe told me that it was a .NET executable. So I used Jetbrains dotPeek to decompile it to C#. The function that checked for the key was comparing the input to the reverse of the concat of 4 strings which were being initialised in the constructor. I added them, used Reverse + decode from Base64 recipe on Cyberchef which gave the flag.

3.6 Rogue

You expect me to decrypt 16-bit AES? No, thanks.

4 Crypto

4.1 Hero of the Village

“You realize Steve must have used a fine cipher”. “a fine cipher”. “affine cipher”. Decoded using “affine cipher”.

4.2 ArrghSA

Reasonably Secure Algorithm -> RSA. The text file contains the parameters for the RSA algorithm for which I found https://stackoverflow.com/questions/49878381/rsa-decryption-using-only-n-e-and-c.

4.3 Vitty-Fabian Dialogue Exchange

Nice pun on Hell. I looked for shared key generating mechanisms and found the Diffie-Hellman algorithm which used the same parameter names. I then found http://index-of.es/Miscellanous/How%20To%20Backdoor%20Diffie-Hellman.pdf which I implemented in the following Python script:

a = 1
p = 104729
g = 23
A = 69625
while True:
    if ((g**a) % p) == A:
        print(a)
        break
    a += 1
# used the above to find a and b, which came to be 6 and 9

print(g**(6*9) % p) # shared key

4.4 Unbreakable

Used the fact that if ciphertxt = msg ^ key, then key = msg ^ ciphertxt (XOR’s property). Thus, flag = ciphertxt2 ^ key.

4.5 h4xXOR

Reversed the encryption process of the Python script:

def main():
    outputfile = open("output.txt", "r")
    output = outputfile.read()

    OUT_LENGTH = len(output)

    flag = ['']*32
    for i in reversed(range(OUT_LENGTH)):
        # output[i] = chr(ord(flag[i]) ^ (1337 - ord(flag[(i + 1) % 32])))
        # ord(output[i]) = ord(flag[i]) ^ (1337 - ord(flag[(i + 1) % 32])
        # ord(flag[i]) = ord(output[i]) ^ (1337 - ord(flag[(i + 1) % 32]))
        if i == 31:
            flag[i] = '}'
        else:
            flag[i] = chr(ord(output[i]) ^ (1337 - ord(flag[i+1])))

    flagfile = open("flag.txt", "w")
    flagfile.write(''.join(flag))


if __name__ == "__main__":
    main()

5 Forensics

5.1 The Mask

xcf file, so open it in GIMP. There’s a layer mask (nice pun again) which hides the layer, so fill it with white to make it visible. It was a QR code which gave the flag on scanning.

5.2 Weird Music

Sonic (pun pun pun) Visualiser. Use spectrogram to get a QR code. Improve contrast by switching to black on white and turning the dials all the way UP and scan it.

5.3 Oh Boy!

Run the Gameboy ROM in VisualBoyAdvance and then inspect the tiles one by one.

5.4 .pcapn00b

Open the file in Wireshark, Statistics > Protocol Hierarchy. Apply http text filter and go through the contents one by one. The text/plain line has the flag in Base64.

5.5 .pcapn00b2

Same as before but now we’ll need to save a zip file, unzip it and decode from base64 the flag in the docx file.

5.6 Experiment669

Run

steghide extract -sf experiment_669.jpg

and use 669 as the password. This gives a text file which on running in a Brainfuck interpreter gives the flag.

Author: himi

Created: 2021-07-07 Wed 15:29