Sieberrsec CTF 3.0 Writeup

By spareus comprising Liu Jie Xu (@8061xjl) and Liu Weichu (@dabby9734)

šŸš§ WRITEUPS ARE INCOMPLETE AND STILL WORK IN PROGRESS šŸš§

Archive of CTF challenges can be found here (my manually archived version lol) or here (official).

Writeups are limited.


PWN

CRYPTO

RE

OSINT

WEB

FORENSICS

MISC

SANITY


PWN

rock farm simulator 2011

Challenge

We did not solve this challenge during the competition.

Summary of how this works:

Challenge exploit summary

This is not a complete writeup, just an extension of what I had to do to get it to work.

Working examples from challenge author main:

https://user-images.githubusercontent.com/44281062/147614438-253b789f-aea1-470b-9e2a-df09a5fa129c.mov

asciicast

The solution is to quickly buy 2 ponies during the delay. However, it was incredibly difficult for me to get that to work (perhaps Iā€™m just too slow lol), so I wrote a small AHK script to send the keys I need, hoping it would be faster:

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

KeyWait, LAlt, D
KeyWait, LAlt, L
Send b
Send t
Send b
Send b
Send p
Send h
Send h

It worked. scripts > humans

CRYPTO

Shalom Shalom

Challenge

This challenge provided us with a string to decrypt (xibkgltizksbrhxllo). The words AT and BASH were capitalised in the challenge description, indicating a clue.

Intended solution was to decipher the string with the Atbash cipher that the clues were referring to. By deciphering it, we get the flag cryptographyiscool

We ran the string through a cipher identifier to find out what cipher was used.

Cipher identifier output

We get the flag by deciphering the string with Affine Cipher in bruteforce mode. It is interesting to note that the Atbash cipher is just an Affine cipher with a fixed key šŸ™‚.

Diffieā€™s Key Exchange

Challenge

After staring at the challenge for a while, we discover that understanding math is important. We notice if priv-key, which is an input we control, is 0, B will be 1 (because math), and consequently shared_secret will also be 1. This allows us to get the flag as a long integer without any modification, which we can then convert using long_to_bytes() to get the flag.

I canā€™t open this file? Part 1

Challenge

Analysing the encryption method, we can see that after the flag is Base64 encoded, it is converted to a bunch of (zero-padded) double digit integers that represents the position of each character in the digits list. Therefore, we split the encrypted flag into groups of two digits, and then convert the integers to characters using the digits list, giving us SVJTe24wd195MHVfYzRuX2MwZDN9. We then Base64 decode to get the flag.

RE

Flag checker

Challenge

Opening the webpage given, we see an form we can check the flag with.

Flag checker form

Opening developer tools, we see that the Check button runs a javascript function.

function check_flag() {
    let flag = document.getElementById('flag');
    let result = document.getElementById('result');
    
    clearTimeout(hide);
    result.textContent = btoa(flag.value) === "SVJTe2luc3AzY3RfZTFlbWVudH0=" ?
        'Correct!' : 'Wrong.';
    hide = setTimeout(() => { result.textContent = ''; }, 500);

}

The user input is being encoded with Base64 and compared to the similarly encoded flag.

By decoding the flag with a base64 decoder, we get the flag (IRS{insp3ct_e1ement}).

Reverse

We modify the script slightly to accept a list of numbers so we can investigate the transformations done by the script.

print("Enter the flag and I will check it for you.")
- enteredFlag = input()
+ enteredFlag = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+               14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27]
coolarray = [[[], [], []], [[], [], []], [[], [], []]]
if len(enteredFlag) == 27:
    for i in range(3):
        for j in range(3):
            for k in range(3):
              print(i, j, k)
              coolarray[i][j].append(enteredFlag[i*9 + j*3 + k])
    newflag = ""
    for i in [coolarray[2], coolarray[0], coolarray[1]]:
        for j in i[::-1]:
            for k in [j[1], j[2], j[0]]:
+                newflag = newflag + "," + str(k) # convert int to str
+    newflag = newflag[1:]  # remove the first comma
    print(newflag)
    if newflag == "1}c5f1bbeb4580{RSI43db46731":
        print("Your flag is correct!")
    else:
        print("Your flag is incorrect. :(")
else:
    print("Your flag is incorrect. :(")

This generates the following output:

26,27,25,23,24,22,20,21,19,8,9,7,5,6,4,2,3,1,17,18,16,14,15,13,11,12,10

We can then write a script to reverse the transformation which yields the flag! (IRS{805b41736b4d43ebb15fc1})

# script to reverse the transformation
newflag = [26, 27, 25, 23, 24, 22, 20, 21, 19,
           8, 9, 7, 5, 6, 4, 2, 3, 1,
           17, 18, 16, 14, 15, 13, 11, 12, 10] # data to test with
newflag = list("1}c5f1bbeb4580{RSI43db46731") # transformed flag


# reassemble array in correct order
hyper_big_chunkus = []

for i in range(3):
    big_chunkus = []

    for j in range(3):
        chunk = [newflag[i*9 + j*3 + 2],
                 newflag[i*9 + j*3],
                 newflag[i*9 + j*3 + 1]]

        big_chunkus.append(chunk)

    big_chunkus = big_chunkus[::-1]
    hyper_big_chunkus.append(big_chunkus)

hyper_big_chunkus = [hyper_big_chunkus[1],
                     hyper_big_chunkus[2],
                     hyper_big_chunkus[0]]


# convert output array to string
nice_flag_bro = ""

for i in range(3):
    for j in range(3):
        for k in range(3):
            nice_flag_bro += hyper_big_chunkus[i][j][k]

print(nice_flag_bro)

OSINT

ā€œThe Sieberrā€ Heist Part 1

Challenge

By viewing the exif data of the image, we obtain the location where the image was taken (33Ā°49ā€™27.1ā€S 151Ā°15ā€™01.0ā€E).

From the satellite view, we get the street name (HUNTERRD) and the postal code (2088). A quick google search of the localities in the Mosman suburb yields the locality (BALMORAL).

Satellite view

From the street view, we get the unit number (3) and number of stories (2) of the building.

Street view

Assembling our information, we get the flag. (IRS{3_HUNTERRD_BALMORAL_2088_2})

ā€œThe Sieberrā€ Heist Part 3

Challenge

We find the individual ā€œCasrihms Myrertā€ on Facebook.

On his facebook post, we see that he is travelling from the Sydney CBD to a hospital somewhere in Northern Beaches. He also shares that this bus is quite direct.

A look at the comments section also reveals that the hospital is not Northern Beaches Hospital. It is also rather sad that someone asked him to go die šŸ˜­.

Facebook post

By searching for the hospitals near Northern Beaches, we find that Mona Vale Hospital has a direct bus (Route B1) from the Sydney CBD to it.

We can then obtain the destination station of route B1 (MONAVALE) from Moovit.

Assembling our information, we get the flag. (IRS{B1_MONAVALE_MONAVALEHOSPITAL})

ā€œThe Sieberrā€ Heist Part 2

From the given image, we get the bus route number (340). Knowing the route, we can find the destination station on Moovit (BONDIJUNCTION). We also notice that the bus is making a left turn at a T-intersection.

Given image

By following the route for bus 340, we find that it makes a left turn at a T-intersection after Wynyard Station. We plot the route using a bicycle path here as bus 340 is no longer in service and the driving route generated made no sense.

Bus 340 left turn

By zooming in with street view, we can confirm we have the correct location.

Street view of bus 340 left turn

We refer back to the satellite view, and we get the name of the street that the photo was taken on (YORKST) and the name of the cross street (DRUITTST).

We go back to the given image, which shows us the bus is gives us the bus fleet number (2213). This allows us to look up the brand (VOLVO) and model (B12BLEA) of the bus on the State Transport Authorityā€™s website.

Brand and model of the bus

Assembling our information, we get the flag. (IRS{YORKST_DRUITTST_VOLVO_B12BLEA_BONDIJUNCTION})

FORENSICS

Duck Delivery

Challenge

Notice that the file is rather large (around 12 mb) while the image itself is small. Playing around with the image (and deducible from the hint), we can extract the zip file embedded in the image using binwalk. The flag appears for a short while in the gif.

Birds?

Challenge

From experiences with other CTFs (also mentioned in the hint), we put the audio file into Audacity (other common software used for this purpose include Sonic Visualiser) and notice a very odd section near the middle when viewing the waveform:

suspiciousbirds.mp3 waveform

Looking at the spectrogram, we can see some text in that region.

suspiciousbirds.mp3 spectrogram

suspiciousbirds.mp3 hex

Zooming in, we get some hex: 68 74 74 70 73 3a 2f 2f 70 61 73 74 65 62 69 6e 2e 63 6f 6d 2f 5a 7a 6b 61 46 59 69 4c, which when decoded gives us a pastebin containing the flag.

Digging In The Dump Pt. I

Challenge

Using DB4S (or some online SQLite viewer), we can take a look at Alexā€™s Chrome history (stored in the SQLite database AppData/Local/Google/Chrome/User Data/Default/History). In the urls table, we see the last two URLs leads us to http://challs.sieberrsec.tech:23547/dcfa237943d4fd7e2a514ca54642efaccd2cdbd5003bfb19a1e70737273e1190/ where the flag is displayed:

Screenshot of the website

Digging In The Dump Pt. II

Challenge

We can easily get the username from the saved logins (stored in the logins table in the SQLite database AppData/Local/Google/Chrome/User Data/Default/Login Data), but the password is slightly more difficult to get since it is encrypted.

Intended solution using ChromePass is less tedious than what we did. There was also a unintended solution by a participant who found the flag in cached in Chrome (thereā€™s an useful tool for that as well).

We found a script, but it uses the local machineā€™s DPAPI functions, which we do not want. Therefore, we exported the ā€œmaster_keyā€ before the CryptUnprotectData function was called.

Using Mimikatz, we extracted the DPAPI master key with the user password given to us following this guide (dpapi::masterkey /in:"AppData\Roaming\Microsoft\Protect\S-1-5-21-1937579505-2679969469-2152769792-1001\37b49573-c2de-487a-81be-b8c2f9b4df15" /password:Password1 /protected). We can then use this masterkey to decrypt the exported master_key from the script (dpapi::blob /in:masterkey /unprotect, specifying the /masterkey: is unnecessary since Mimikatz keeps the DPAPI keys cached in the same session).

After decrypting the master_key blob, we can put it back into the script and run it to extract the password.

Getting the username (Alex24) and password (IHeartCookies), we log into the website from the previous part of this challenge series, and we get the flag:

Screenshot of the website

MISC

I lost my anime collection! Pt. II

Challenge

Add the given disk as a data source into Autopsy. We find a video file (Kimi No Na Wa Clips.mp4) where the flag is displayed.

Autopsy

I lost my anime collection! Pt. I

Challenge

We did not solve this challenge during the competition.

Create a Windows Server virtual machine (evaluation ISOs available at here), since ā€œA consumer version of Windows canā€™t read RAID 5!ā€ and we will have to use a Windows Server OS. After mounting the two disks onto the VM and creating a new empty disk, we can use Disk Management to rebuild the RAID5 array (right click on disks > Import Foreign Disksā€¦, then right click the RAID5 volume > Repair Volumeā€¦). We then assign the volume a drive letter and simply open the video stored in it (Tenki No Ko Clips.mp4) to see the flag.

flag