Scris pe

Writeup Simon Challenge 2.0 CTF

Nu m-am gandit vreodata in viata asta ca voi participa candva la un CTF darămite sa mai il si castig. Fiind de ceva vreme in grupul IT-istilor (din 2016), am fost atent la postarile de acolo si din cand in cand am mai oferit si eu ajutor, in limita timpului disponibil. Insa mi-a atras atentia un post de-a lui Simon Cirstoiu, administratorul grupului, in care zicea ca vrea sa organizeze un CTF (capture the flag) pentru incepatori cu challenge-uri din diferite domenii ale IT-ului. Prima data nu ma gandeam ca particip, insa am facut cont si am incercat sa rezolv primul challenge si am fost instant hook-ed up! M-a prins asa tare ca am stat dupa lucru vreo doua nopti (in una din nopti ma durea maseaua oricum si as fi stat) pana sa il rezolv. Tot timpul am crezut ca altcineva mai experimentat va termina inaintea mea si nu castig premiul, dar se pare ca am fost prea determinat sa castig.

Destul cu bla-bla-urile, hai sa vedem rezolvarile si modul de gandire.

Level 1 – Warm-up

Proba de incalzire. Se da poza urmatoare:

In caz ca WordPress buseste metadata-ul la poza, o gasiti si aici. Cerinta acestui level ne cerea sa il gasim pe Waldo. Din ce am inteles, multi dadeau raspunsuri gen “stanga sus” “tipu cu rosu”. Totusi, acesta e un concurs de IT-isti, nu de artisti. Indiciul dat era N 44.232013, din start m-am gandit ca poza asta are coordonate GPS in metadata. I-am dat file info in macOS si bingo, am avut dreptate. Insa coordonatele GPS pot fi aratate in 2 feluri: in secunde minute si grade sau grade cu decimale. MacOS imi arata in primul format, site-ul cerea formatul 2. Am cautat repede un site care iti arata in alt format coordonatele si am gasit https://tool.geoimgr.com. Solutia deci a venit instant: N 44.232013 E 28.628411. Waldo era la balaceala in Constanta.

Level 2 – Crypto

Na, asta a fost una din probele la care am stat cel mai mult, nu e punctul meu forte. Indiciul era Romanian Security Agency (daca tin minte bine). M-am prins din start ca se refera la RSA. Trebuia sa decriptez un mesaj (ct care cred ca vine de la cypher text). Se dadea Ct-ul si N-ul. Nimic in plus. M-am pus pe facut research pe Google, am intrebat in stanga dreapta, n-am primit de la nimeni un raspuns (am primit unul dar nu l-am vazut decat dupa 8 ore de ne-somn si cand eram deja la alt level. Peste tot zicea ca trebuie factorizat numarul (N) sau sa il gasesti la cineva care deja l-a factorizat. Asa am descoperit factordb.com unde bagi un numar si iti zice numerele prime p si q. Bingo, am gasit aici valorile.

p = 3133337
q = 25478326064937419292200172136399497719081842914528228316455906211693118321971399936004729134841162974144246271486439695786036588117424611881955950996219646807378822278285638261582099108339438949573034101215141156156408742843820048066830863814362379885720395082318462850002901605689761876319151147352730090957556940842144299887394678743607766937828094478336401159449035878306853716216548374273462386508307367713112073004011383418967894930554067582453248981022011922883374442736848045920676341361871231787163441467533076890081721882179369168787287724769642665399992556052144845878600126283968890273067575342061776244939

Pe langa aceste date, mai ai nevoie de un numar “e” care este exponentul folosit la criptare. De obicei se foloseste 65535 pentru ca din cate am citit e cel mai sigur, orice valoare mica la “e” este nesigura si face cheia sa poata fi decripata usor.

Am pornit repede PyCharm si am scris un script in Python care sa ma ajute sa decriptez mesajul. M-am impotmolit pentru ca nu stiam E-ul, dar pana la urma am decis sa ii fac un Bruteforce si sa incerc orice numar pana la 65535 pana primesc flag-ul. Trebuia calculat si un phi (r) care este (p-1)*(q-1). Am gasit toate detaliile aici.

Scriptul final in Python care m-a ajutat sa gasesc flag-ul:

import gmpy2
N = 79832181757332818552764610761349592984614744432279135328398999801627880283610900361281249973175805069916210179560506497075132524902086881120372213626641879468491936860976686933630869673826972619938321951599146744807653301076026577949579618331502776303983485566046485431039541708467141408260220098592761245010678592347501894176269580510459729633673468068467144199744563731826362102608811033400887813754780282628099443490170016087838606998017490456601315802448567772411623826281747245660954245413781519794295336197555688543537992197142258053220453757666537840276416475602759374950715283890232230741542737319569819793988431443
c = 22664889071766405616690496399785883279231207366959076986000174995902109566326512157509415545853269926167142306045383664995281321739923970223879500117879944026276246525436227634860617854619525512053619560662996649951200811796801528090425787845765164402714344913585123206998080590432959321431995864620545971144189729623493103498363018416080784868466742318974248100809852320026471428934461327602519720825805102244094627982149433917907205104955402093330500449614081974490192338643001335940120183375623461498249077391842766534062010725477519205429490324934794491384638060162586113440961183506146605761469104391790439074962823353
p = 3133337
q = 25478326064937419292200172136399497719081842914528228316455906211693118321971399936004729134841162974144246271486439695786036588117424611881955950996219646807378822278285638261582099108339438949573034101215141156156408742843820048066830863814362379885720395082318462850002901605689761876319151147352730090957556940842144299887394678743607766937828094478336401159449035878306853716216548374273462386508307367713112073004011383418967894930554067582453248981022011922883374442736848045920676341361871231787163441467533076890081721882179369168787287724769642665399992556052144845878600126283968890273067575342061776244939
e = 1
r = (p - 1) * (q - 1)
def logit(m):
n = m
while e < 65535:
try:
d = gmpy2.divm(1, e, r)
except ZeroDivisionError:
logit('x')
m = gmpy2.powmod(c, d, N)
try:
text = hex(m)[2:].decode('hex')
if text.find("flag") != -1:
print text
print e
except:
pass
e += 1

Functia logit e aiurea pentru ca nu stiam cum sa prind o exceptie in Python fara ca sa fac nimic cu ea. Am pus codul exact cum era cand am gasit flag-ul, prostesc dar mergand.

Ruland acest script python test.py am primit raspunsul:

➜ in ctf python t.py
flag=Asteresti_si_Obelesti
1741
flag=Asteresti_si_Obelesti
1742
flag=Asteresti_si_Obelesti
1743
flag=Asteresti_si_Obelesti
1744

Am ceva bug care arata output si dupa E 1741, dar numai cu e=1741 merge. Flag-ul este Asteresti_si_Obelesti care habar n-am ce inseamna :)), dar merge.

Level 3 – Steganografie

Daca nu cunosti termenul, dai un quick search pe Google si gasim asta:

Steganography is the act of hiding nearly invisible text in images

https://ctfs.github.io/resources/topics/steganography/invisible-text/README.html

Deci stenografia e arta de a ascunde ceva in altceva, nu se aplica doar la imagini. Buun.

Ca indiciu primim o melodie si textul “You need that deep sound“.

Varianta .wav originala aici

Prima data m-am pus sa analizez versurile melodiei dar apoi iar mi-am amintit ca e concurs pt IT-isti nu pentru artisti. Cautand indicii pe Google am gasit asta. Deci in serialul Mr. Robot, personajul principal ascunde informatii in melodii si foloseste Deepsound. Hopa, “you need that deep sound”. Caut, bingo. Softul chiar exista. Problema e ca eu am mac. Softul e doar de Windows. Configureaza repede o masina virtuala cu Windows 10 for developers, iau jos softul, pornesc si incarc melodia. Cere parola. Ce truda, eu de unde sa mai iau parola?!?

Nu am mai spart niciodata vreo parola la ceva (parca la un .rar), asa ca am cautat iar pe Google. Am gasit unealta potrivita, prea multi au pomenit de John the Ripper password cracker. Inspectez codul sursa si vad un fisier interesant: deepsound2john.py. Bun, compilez pe Ionut pe Mac, rulez python3 deepsound2john.py s.wav > hashes.txt si primesc fisierul de hash-uri. Apoi ./john hashes.txt si primesc parola Miranda. A 1031-a cea mai comuna parola din lume. Super, merge parola si primesc fisierul ascuns “secret.wav”.

The invisible secret is 14753. Wav original aici.

Deci solutia la level 3: 14753. Mergeee, yey!

Level 4 – Misc

Nu avem niciun indiciu nimic decat o notificare in aplicatie “daca hint-ul este gol, poate ai omis ceva sau ai lasat ceva in urma”. Oh, super. Dupa ce am stat ore sa gasesc secretul, am omis ceva. Dar la ce pas? Ma intorc de la 1? Am deschis fisierul secret.wav in Audacity, incercam sa vad texte in spectograma (se poate ascunde un cuvant in frecvente si cand te uiti la spectograma sa vezi cuvantul). Nu era asta.

Trebuia sa re-analizez textul. Puteam primi 14753 direct, fara sa ne zica “the invisible secret is’. Sau putea sa zica “the solution is”, pentru ca noua ne trebuia solutia la level. Search pe Google, gasesc softul Invisible Secrets 4. Are trial, e tot de Windows only. Bine ca am de la pasul anterior masina virtuala inca deschisa.

Cand deschid wav-ul, cere si aici parola. Deja nu mai aveam chef, zic sa incerc pur si simplu parola din secret.wav: 14753. Merge, phew. Primim fisierul Skylar.png care este un cod qr.

Daca scanezi codul, se deschide o aplicatie de two factor authentication si primim un cod de two-factor pentru userul [email protected]. Asta ce mai e. Incerc sa intru pe site-ul skylar.redirectme.net. Connection refused. Dau un nmap, vad portul 22 deschis. Aha, merge ssh deci. Incerc ssh [email protected]. Authentication error. Hmm… cum sparg acum ssh? Aici m-a batut atentia la detalii: nu mergea ssh din cauza ca incercam skylar in loc de Skylar cu S mare. #@!)(qu89038q409. Bun, cu s mare merge. Cere codul de la aplicatia de twofactor. Il bag, ma loghez, arata MOTD-ul si ma scoate afara.

tcp 0 0 127.0.0.1:80 0.0.0.0: 80 LISTEN 20139/nginx: master

This account is currently not available. Connection closed

Hmm, deci are nginx si merge, doar ca nu asculta pe orice ip ci doar pe 127.0.0.1. Cum facem sa vedem totusi site-ul ala. Simplu daca ai putin de-a face cu un server si ssh: ssh tunnel & port forwarding. ssh -L 80:127.0.0.1:80 [email protected]. Doar ca nici asa nu mergea, ma scoatea afara. Din cauza ca ssh-ul incerca sa aloce un TTY. Trebuia dat flag-ul -nNT si asa a mers. Deci comanda e ssh -nNT -L 8000:127.0.0.1:80 [email protected]

Mergem repede la /etc/hosts pe masina locala si setam site-ul skylar.redirectme.net sa mearga la 127.0.0.1. Mergee! Vedem un site simplu. Un meniu si textul:

Felicitari! Flag-ul pentru Level 4 este: c9YeZ2GPueL7KUjT

Level 5 – Web

Aici e domeniul meu, eu lucrez cu web zilnic. A mers cred ca cel mai rapid. Am dat un click pe pagina din meniu “about” si am primit o pagina goala cu eroarea “unable to include about.php”. Ma gandeam din start, sa vezi ca scriptul incarca ?page=x $_GET[‘page’].php, adica orice pui dupa page= incarca sa ii faca include. In meniu mai era o pagina, next level dar cand intrai in ea era goala. Doar meniul. Deci cumva trebuie sa fie ceva acolo, sa citim fisierul ala. Am cautat pe Google metode de xss pe baza de file include, am gasit asta. Am facut un POST request la skylar.redirectme.net/?page=php:%2F%2Ffilter%2Fconvert.base64-encode%2Fresource%3Dnextlevel (php://filter/convert.base64-encode/resource=nextlevel) si am primit base64 cu codul sursa a paginii.

PD9waHAKCmRlZmluZWQoJ0lOQ0wnKSBvciBkaWUoaGVhZGVyKCdIVFRQLzEuMCA0MDMgRm9yYmlkZGVuJykpOwoKZnVuY3Rpb24gZ2ltbWVGbGFnKCRndWVzcykgewogICAgJGZsYWcgPSAkX0VOVlsiRkxBRyJdOwogICAgaWYgKHN0cmxlbigkZ3Vlc3MpICE9PSAxMCkgcmV0dXJuOwogICAgaWYgKCRndWVzc1szXSAhPT0gJGd1ZXNzWzVdICYmICRndWVzc1s1XSAhPSAkZ3Vlc3NbN10gJiYgJGd1ZXNzWzBdICogJGd1ZXNzWzFdICE9PSAzMCkgcmV0dXJuOwogICAgaWYgKCRndWVzc1sxXSAhPSAkZ3Vlc3NbMl0gKyAkZ3Vlc3NbNl0gJiYgJGd1ZXNzWzNdICE9ICRndWVzc1swXSArICRndWVzc1syXSkgcmV0dXJuOwogICAgaWYgKG1kNSgnel8nIC4gJGd1ZXNzIC4gJ180NDI0Nzg5NScpICE9IDApIHJldHVybjsKICAgIHJldHVybiAkZmxhZzsKfQoKcHJpbnQgZ2ltbWVGbGFnKCRfUE9TVFsnZyddKTsKCg==
<?php
defined('INCL') or die(header('HTTP/1.0 403 Forbidden'));
function gimmeFlag($guess) {
$flag = $_ENV["FLAG"];
if (strlen($guess) !== 10) return;
if ($guess[3] !== $guess[5] && $guess[5] != $guess[7] && $guess[0] * $guess[1] !== 30) return;
if ($guess[1] != $guess[2] + $guess[6] && $guess[3] != $guess[0] + $guess[2]) return;
if (md5('z_' . $guess . '_44247895') != 0) return;
return $flag;
}
print gimmeFlag($_POST['g']);

Interesant, trebuie facut un request post la pagina asta (/nextlevel) cu parametrul g sa satisfaca toate conditiile alea si vom primi flag-ul. Eram prea obosit deja si am chemat-o pe Catalina sa ma ajute, pentru ca mi-am dat seama din codul sursa ca trebuie sa fie un numar “g”-ul. I-am zis conditiile ei, a scris pe foaie combinatii. Am ajuns la concluzia ca pozitiile 5, 9 si 10 nu conteaza, deci am pus 0 din start acolo. Cata mi-a zis restul de cifre si am ajuns la numarul g 5638083800. Am facut un request si sure enough, am primit flag-ul. “FLAG: TUB6wgqeaqVa9Sf”.

Level 6 – Real World Engagement

Indiciu la level 6 primim asa:

46.97.198.231 porturi deschise: 80, 443 si 1337.

Nu faceti nmap. Nu faceti bruteforce.

e o camera video cu 128mb ram conectata la un modem 3G Vodafone, daca dati cu tool-uri in ea, crapa.

(deja am reparat-o de trei ori)

Intru pe ip, e o camera video. De la Simon din apartament. Lol. M-am uitat ca prostu la ea si nu stiam ce trebuie facut mai departe. Dar aveam indiciul pe feed:

Indiciu

Deci… trebuie sa fie undeva un cod qr si sa pot misca webcamu ala in asa fel incat sa vad codul qr si sa il scanez pentru flag-ul final.

Am inspectat codul sursa, requesturi, headere.. tot felul. Am vazut un fisier “/cgi-bin/action.cgi” care exista. Accepta un parametru cmd din ce am vazut intr-un fisier js. Am tot incercat https://46.97.198.231/cgi-bin/action.cgi?cmd=x si primeam raspuns ‘x’ successfully executed. Orice bagam raspunsul era la fel.

Caut codul pe google, cine stie poate aflu un model de camera. Am gasit pe Github un firmware custom de Xiaomi. Asa am aflat modelul camerei: Xiaomi Dafang (pentru ca trebuia sa se miste cumva, era cam singura ce putea). Am gasit si codul sursa la fisierul action.cgi. Super, stiam comenzile deja. motor_up, motor_down, left si right. Doar ca nu mergeau, truda lor. M-am gandit apoi sa incerc doar up. Nu merge. Down. Merge, dar se misca in sus, nu in jos. Hmm, deci e in oglinda. Up e jos si down e sus. Dar ce facem ca left right nu merge. Inspectam codul de pe Github si vedem comanda motor_calibrate. Folosind acelasi pattern, incerc doar calibrate. Mergee, se misca pana in dreapta 100% si apoi rapid revine la loc. Am vazut codul rapid dar nu apucasem sa il scanez. Apropo, erau 2 modalitati sa vezi webcam-ul: http, era o poza refreshuita la 1 secunda, sau rtsp (rtsp://46.97.198.231:1337/unicast). Iti dadeai seama si din cod si din hint: portul 1337 deschis. Rtsp mergea fluent, de asta aveam nevoie.

Codul final!

Flag-ul final a fost in qr code: 5979434732. Ma gandeam ca mai urmeaza ceva, dar am bagat flag-ul in sistem si m-a declarat castigator.

Concluzii

Challenge-ul a fost putin greu pentru unul care nu a mai participat la asa ceva, dar nu din cauza probelor neaparat ci din cauza ca nu aveam gandirea formata. Orice cuvant isi are rostul (invisible secret), orice clue trebuie sa fie tehnic (nu artistic sau eu stiu cum, sa-l cauti pe Waldo in poza).

Acum ca ma uit in urma, puteam termina in cateva ore nu in 2 nopti daca eram mai atent la indicii. In rest, trebuie doar sa ai cunostinte de baza din orice si sa stii sa te descurci. Cum zicea Simon Cirstoiu intr-un comentariu: in hacking trebuie sa fii descurcaret. Nu zicea nimeni aici ca e interzis sa te folosesti de Google sau Github. Asa ca daca te gandesti sa participi altadata la un alt CTF, tine minte: descurca-te cu orice resursa poti gasi pe net daca nu ti se interzice asta.

Quick stats

  • 600+ participanti
  • 6 castigatori
  • 2 echipe castigatoare
  • 4 persoane individuale castigatoare

Multu’ ca ai citit pana aici, scuze daca am mai facut greseli sau litere duble, I HATE BUTTERFLY keyboard de pe Macbook pro. Am taste ce ies, sau se apasa prea usor. De aia mi-a luat ceva timp sa scriu tot articolul. Sper sa apreciati, daca nu iau tastele si vi le bag pe gat ?. Apropo, in curand va arata asa si tastatura mea.

3 comentarii la acest articol

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *

Acest site folosește Akismet pentru a reduce spamul. Află cum sunt procesate datele comentariilor tale.

Copyright © 2024 toate drepturile
nu sunt
rezervate. Faceti ce vreti, e o tara libera.
Cred ca nu mai are rost sa zic, dar tema e facuta de mine cu TailwindCSS. Gasesti codul sursa aici.
Inca folosesc WordpPess 🧡. Tema e insa custom Laravel 😎.