Write-Up Registration Challenge Hacker Contest Winter 2023/24

7. November 2023

In the winter semester of 2023, our "Hacker Contest" will be held again at Technical University of Darmstadt (TU). In the popular course, students get real insights into IT security and gain hands-on experience with tools and methods to search for vulnerabilities in networks and systems within our PentestLab.
As in every semester, prospective participants took on the Hacker Contest Challenge to qualify for participation.
If you are curious to know what a Hacker Contest Challenge looks like, or which flags you might have missed this time: This is our sample solution for the winter semester Hacker Contest Challenge.

Table of Contents

  1. Scenario
  2. Challenge
  3. Disclaimer
  4. Tokens


Your friend found an old hard drive in his drawer that contains his old operating system. He can still remember his passwords, but lost six very important access tokens for his Bitcoin-Wallet from 2017. They are hidden somewhere on the hard drive, but he doesn't remember where and doesn't know how to regain access. This is a welcome change from the usual printer issues by family members, and since he is a very good friend, you agree to help him.


You are provided with a virtual disk image. It is your task to find all six tokens hidden somewhere on it.
All tokens are in the format of usd{$32_digit_hex_number}.
Since we already have passwords for both users, logging in is not a problem:

user: asdf
root: usdsuperhero


This challenge is a fairly artificial one, more akin to a CTF challenge than anything one would encounter in a real-world scenario. However, having a local disc image provides an opportunity to test for weaknesses that usually are not part of remotely hosted CTF challenges, such as offline brute-forcing.


By examining the file system, we initially find some files not usually present in the user's home directory. Those files are worthy of further investigation but finding all six tokens requires a bit more digging. In the following, we go through each token on the machine in no particular order.


The token is located in /home/user/Desktop/USB_IMAGE.img.
As we might suspect from the filename, the file contains a USB image. We can try to mount the USB image, but we are not able to find anything on it, since its contents were deleted. We could use elaborate forensic tools in order to recover the deleted contents, but the easiest solution merely requires running strings on the image in order to recover the token:

strings /home/user/Desktop/USB_IMAGE.img

Encrypted PDF

A hidden file is located in /home/user/.secret.pdf, which can be revealed using ls -la /home/user.
Since it is encrypted, we have to first extract the PDFs hash using John the Ripper:

pdf2john .secret.pdf >> hash

This makes it possible to view the hash separately from its original file and brute-force the password.
The password is part of the popular rockyou wordlist and can therefore be easily found.

john hash --wordlist=/usr/share/wordlists/rockyou.txt


The next token we will look at is located in /home/user/Picures/sloth.jpg.
We cannot open the file using an image viewer because contrary to its file extension sloth.jpg is a zip file.
We therefore can rename it to avoid further confusion.

mv sloth.jpg token.zip

We then have to repair its offset with

zip -FF token.zip --out fixed_token.zip

After that, we can unzip the repaired file, but it still has password protection. Therefore, we have to crack the zip's encryption. Again, we can use John the Ripper to do so.

zip2john fixed_token.zip >> hash2
john hash2 --wordlist=/usr/share/wordlists/rockyou.txt

Now we can unzip the file, using the revealed password.

unzip fixed_token.zip

Encrypted PDF 2

Two interesting files are located in the users Documents directory, important.enc.pdf and encryption_guidelines.txt.

We can use the hint in encryption_guidelines.txt in order to generate our own password wordlist. There are many different ways to do so. We could write a simple script, but there is also a useful and easy-to-use GitHub project we can use to generate the dates. We still have to prepend the username, which in our case is user.

python3 date_generator.py 1900 2030 0 > custom_date_wordlist
sed -e 's/^/user/' custom_date_wordlist > accurate_list

Then we can use John the Ripper again to crack the PDF.

pdf2john important.enc.pdf > pdf_hash
john pdf_hash --wordlist accurate_list

Find the hidden program

There is another hidden program with an interesting name, located in /usr/bin/thide .

This program is hidden by some shared library for tools like ps.
After locating the binary, we could reverse-engineer it with tools like ghidra in order to find out that it opens a connection to a socket and sends some data. We can then run ps -ef | grep thide which reveals that the program is running, as well as its process ID. Using wireshark, we can observe the local network traffic and see that there are several connection attempts to port 63333 being made. We now can listen on port 63333 and get the token.

nc -lvp 63333

Reverse engineer binary

The last token we look for can be found in the executable located at /home/user/bin/token.
It is necessary to run chmod -R 777 /home/user/bin which gives 'user' access to the directory.
We can use ghidra to reverse engineer the program. There are many different ways to solve this challenge. The following code serves as an example for one possible solution to the problem.

#!/usr/bin/env python3

# $ python3 cobb_solver.py /home/user/bin/token

import os
import re
import sys

if len(sys.argv) != 2:
    print("usage: {} <path to cobb>".format(sys.argv[0]))

#call cobb to get the character count
cobb_stream = os.popen(sys.argv[1])
char_count = int(re.search('<(.*) character', cobb_stream.read()).group(1))
print("app has a {} byte key".format(char_count))

byte_array = []

for i in range(0, char_count * 8):

objdump_stream = os.popen("objdump -d {}".format(sys.argv[1]))
prev_func_number = None

for line in objdump_stream:
    #0000000000001273 <check_2>:
    function_def_match = re.search('^00000.* <check_(.*)>:$', line)

    #1291:    0f 95 c0                setne  %al
    bit_set_match = re.search('setne  \%al', line)
    if bit_set_match and prev_func_number is not None:
        byte_array[int(prev_func_number)] = True
        prev_func_number = None
    if function_def_match:
        prev_func_number = int(function_def_match.group(1))

sys.stdout.write("The key is \"")
character = 0
for idx,elem in enumerate(byte_array):
    if elem:
        character = character | (1 << idx % 8)
    if idx % 8 == 7:
        character = 0

Also interesting:

Security Advisory on WeKan

The pentest professionals at usd HeroLab examined the open source application WeKan during their pentests. This application offers users a solution for organising projects...

read more

Security Advisory on Gambio

The pentest professionals at usd HeroLab examined the online shop software Gambio during their pentests. The software offers merchants various functions that support the...

read more