Optimus Prime
4 minutos de lectura
Se nos proporciona una instancia remota a la que conectarnos. Tenemos algunas opciones:
$ nc 167.99.202.193 31899
Your people must learn to be masters of their own fate.
1. View status of the Transformer.
2. View Serial ID's of the Transformer.
3. Register new Transformer.
4. Enter to the access panel.
Enter the option: 1
Battery: 60%
Mechanical damages: 14%
Heat: 64.76 ºC
Ncat: Broken pipe.
$ nc 167.99.202.193 31899
Your volume, like any capability, is also a responsibility.
1. View status of the Transformer.
2. View Serial ID's of the Transformer.
3. Register new Transformer.
4. Enter to the access panel.
Enter the option: 2
Processor ID: 5iG6i-u7gb5
Engine ID: XVZYI_278
Rotor ID: 788hdIVu
Controller ID: 435b7
UV RAY Laser: N-yg797
Lens ID: eye-455
Armor ID: 6fJKC-43efw
E.L.F ID: Yon6.oiL
Sensors ID: DGTX-486f
Ncat: Broken pipe.
$ nc 167.99.202.193 31899
Neither impossible, nor impassable!
1. View status of the Transformer.
2. View Serial ID's of the Transformer.
3. Register new Transformer.
4. Enter to the access panel.
Enter the option: 3
You can't register a new Transformer until you log in
Ncat: Broken pipe.
$ nc 167.99.202.193 31899
Neither impossible, nor impassable!
1. View status of the Transformer.
2. View Serial ID's of the Transformer.
3. Register new Transformer.
4. Enter to the access panel.
Enter the option: 4
PUBLIC KEY: 561530983183771644079081983133798886393315956842713837364876531649006798532220730114101411755795010319041295006801350917538756933499118617906317031195270077996926403624167003776056371107839368665181097764439194459189223899109973780067747737810092153902289460088036423880150476966442534774553341463189986208172232827051285526840902140313481364721901864123911011320463414816873164360267912578559507379639135636187433596948652766777666836886846836958378588268077971837472074268732874219872654681857716405976488231199626780398481640108544235249033287071829129695641174000782364626628385008069223240415794168792983331187517584059922896859393495222716472879930970681273918024127565161588448456637434626076495922878734813092660550806993569318588995667355672939047576853520827749232882520805817097901435167281301065520534686463750548527065004526512899978446933334931789991777691203140056028033711607116455127229004217741079025900939041650303633655036023592351427096299269324770012178470783507481318950193911934095464050789933973944959561340943805633191801390910919158965343251753924778364361992590415546653203022780846100722718253700076817407880515244228228331352925174426850015621965026601020231470421066275223297008742866239028201616549297
ENCRYPTED PASSWORD: 478433640659999909494191352317871798130455824918379548803426918434917846639343016566162840910865561178722256715981978209460254339146239711331342400226506789950101981589316626554270102018898421811117722378733550248600097683887697688604134869368517906548458208251021435357024461369811788365509479210707348656092869889564338136336543331671149450042893739237285802897073477565614570522656667036132585939975696784680815717851583346707640317324432358245031147929286213666773861704595122964859916902660079486583256859654560907207756060808745941468321485063015298630156644267999050346301234569247203357193989245850972352536744184424711523579547352961208825878553154832349587187344121773681413828873274598590409300089865600358498669459273494865441858894195460943962230569092193081568834701100790852366960295527607344882593597464702313029563578260916592447601774708819078699287065353277224184336953141401114989828012740785816597467134398795454332960168213069367520422690188330360363547402836335519018053996252884588054197617439636359408910390135159839471927018087222389985022566622381108776793949150510196977124060472434418599667191540426334403433398301838300639236441554597495553171237299370972025039094868074461193337336268675948069907974382
The private key has been sent to your email. Please use it to proceed:
Ncat: Broken pipe.
Parece que la única interesante es la cuarta. Se utiliza un criptosistema de clave pública (probablemente RSA).
Explicación de RSA
RSA funciona de la siguiente manera: Se cogen dos números primos grandes $p$ y $q$ y se toma $n = pq$ como módulo. Luego, se coge un exponente $e$ (típicamente $e = 65537$) y se cifra el mensage $m$ en formato decimal:
$$ c = m^e \mod{n} $$
La clave pública es la tupla $(n, e)$, y la clave privada está compuesta por los dos números primos. Para descifrar, se necesita calcular $\phi(n) = (p - 1) (q - 1)$ para calcular el inverso de $e$ respecto a la multiplicación, que es $d = e^{-1} \mod{\phi(n)}$. Luego, el texto cifrado $c$ se descifra como:
$$ m = c^d \mod{n} $$
Y esto funciona debido a que
$$ c = m^e \mod{n} \iff c^d = (m^e)^d = m^{ed} = m \mod{n} $$
Fallo de seguridad
Como el reto se llama “Optimus Prime”, podemos deducir que el servidor utiliza un número primo fijo para construir $n$ (podemos llamarlo $p_x$). Entonces, podemos solicitar dos claves públicas diferentes ($n_1$ y $n_2$), de forma que $n_1 = p_x \cdot p_1$ y $n_2 = p_x \cdot p_2$ (donde $p_1$ y $p_2$ son dos números primos diferentes).
Para poder conseguir $p_x$ podemos aplicar el Máximo Común Divisor (GCD) entre $n_1$ y $n_2$. Vamos a probar:
$ python3 -q
>>> n1 = 561530983183771644079081983133798886393315956842713837364876531649006798532220730114101411755795010319041295006801350917538756933499118617906317031195270077996926403624167003776056371107839368665181097764439194459189223899109973780067747737810092153902289460088036423880150476966442534774553341463189986208172232827051285526840902140313481364721901864123911011320463414816873164360267912578559507379639135636187433596948652766777666836886846836958378588268077971837472074268732874219872654681857716405976488231199626780398481640108544235249033287071829129695641174000782364626628385008069223240415794168792983331187517584059922896859393495222716472879930970681273918024127565161588448456637434626076495922878734813092660550806993569318588995667355672939047576853520827749232882520805817097901435167281301065520534686463750548527065004526512899978446933334931789991777691203140056028033711607116455127229004217741079025900939041650303633655036023592351427096299269324770012178470783507481318950193911934095464050789933973944959561340943805633191801390910919158965343251753924778364361992590415546653203022780846100722718253700076817407880515244228228331352925174426850015621965026601020231470421066275223297008742866239028201616549297
>>> n2 = 453473442250176875887884408494220813255318673548591420930808729711094153852669604421072095147310535852894196497701194495763934656918609242180114413009407095537822822748643497472849565895597043585990519691637441008444521268699797671965200208092597532516403402190454917233181150763224005871254278889048272186835605224243556324477564249866430027847480350925849946864753434500537411434272377354967175199633700713666315246294534992637512422841359051759213575691108707708370754825888159259774053850736224767423679354716176586323223030008253463691575953103663417515811761767764175251537126181846166669552092900829212085164322801334699759213430309486363444549508842349294988879068005189767324109391528329543985407116444501230761784856233364104610311903991726395798820046856030660523463227914493442647668650499386551929507449774406611125430990377567739666050143337985208270998972824314753324371044553546822349213844258163058860685053178159783903879568864036793018848540186772536917354390604909493147042812091520636469519583251810079508546092492522575089517856699654431120435334917909033314645473050982459170263445473946283036131237144416259114422589056262458804839224321263904326617355529086163074030618050603883415427312184962264005049090229
>>> import math
>>> px = math.gcd(n1, n2)
>>> from Crypto.Util.number import isPrime
>>> isPrime(px)
1
Y vemos que obtenemos dicho número primo $p_x$. Una vez que tenemos esto, podemos encontrar $p_2$ (por ejemplo), calcular $\phi(n_2)$, $d_2$ y descifrar el texto cifrado $c_2$. Podemos asumir que $e = 65537$:
>>> c2 = 343845506025778530795718670598666171710030663159821861076070623117224684551860690631782987313834807370036911786095234337597419898461321063261995350759485297249486660913049139886412600212877009756892583998498669904341883112438581954400464063594377774021723284323552120385379343484829380561610088720516935305926692406948937248751510032745753230120037423164658296389616587276180568248089558247676815598468834040711325058721414948264455314035303701042721613668068907350330619412586217479631982116371749767359269424273722566832487848362060917263112202535860565888767090305511288178082790987268616489182855115557905286226273617078447915074472302468279345661674845390745475541712501117665472557682177794539758420404949640140854189394151698888319404643070036167056321938905981038847592990485309538582614141417479562739031032638166131529167960622106245588847474016925660498629715572522834239181453232014679322906670345921157689374407549621116678227570482589299811459042126157149361175419596601660478163655408416055881341992948247566820045423428109130315763948267507723930247493194336446361745042850763049750188560485546096422316090260110018037330823331595681210532701821560508235962726792443805820567222233675381894097871026348225462856434914
>>> p2 = n2 // px
>>> phi_n2 = (px - 1) * (p2 - 1)
>>> e = 65537
>>> d2 = pow(e, -1, phi_n2)
>>> m = pow(c2, d2, n2)
>>> bytes.fromhex(hex(m)[2:])
b'zrevmbwrunv'
Flag
Vale, parece que esta es la clave que tenemos que enviar al servidor. En este punto, podemos agrupar los cálculos anteriores en un script que gestione la conexión y envíe la clave para obtener la flag:
$ python3 solve.py 167.99.202.193:31899
[+] Opening connection to 167.99.202.193 on port 31899: Done
[*] Closed connection to 167.99.202.193 port 31899
[+] Opening connection to 167.99.202.193 on port 31899: Done
HTB{3uc1id_w4z_th3_pr1me_h4x0r}
[*] Closed connection to 167.99.202.193 port 31899
El script completo se puede encontrar aquí: solve.py
.