WonkaChallenge 2019

W

Cette année, lors de l’évènement LeHack 2019, nous avons assisté au lancement de la seconde édition du WonkaChallenge organisé 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 sont disponibles en ligne.

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.

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 sera agréable !

Le point d’entrée du challenge se trouve ici : https://willywonka.shop

I. Step 1 – Erreur de développeur

TL;DR

  1. Utiliser dirsearch et trouver le dossier .git ;
  2. Avec GitTools -> dumper -> extractor, récupérer le git et les anciens commits ;
  3. Le premier flag se situe dans le fichier .git/COMMIT_EDITMSG.

I.1. Directory listing

Fig 1 : Index du site

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 :

Fig 2 : Dossier git accessible

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

Ressources

  1. maurosoria, dirsearch, GitHub : https://github.com/maurosoria/dirsearch
  2. internetwache, GitTools, GitHub : https://github.com/internetwache/GitTools

II. Step 2 – Une histoire de JWT

TL;DR

  1. Faire de l’audit de code grâce au .git trouvé dans l’étape d’avant, trouver le debug=1 dans la configuration de Symphony ;
  2. Mettre la page /reset en mode debug afin de récupérer une stacktrace : https://willywonka.shop/reset?debug=1 ;
  3. Dans la stacktrace ,trouver un sous-domaine (backend.willywonka.shop) et un JSON Web Token (JWT) ;
  4. Il existe une autre page /reset sur le backend. Grâce à cette page, on sait que le site attend un JWT dans le cookie backend-session ;
  5. L’analyse du JWT récupéré dans la stacktrace montre qu’il est protégé par une clé secrète (HS256) ;
  6. Le bruteforcer avec rockyou et trouver la clé s3cr3t ;
  7. 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 ;
  8. 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 :

Fig 3 : Impossible de trouver l’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 :

Fig 4 : Enumération d’utilisateur 1/2

Si un utilisateur valide est soumis à 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 :

Fig 5 : Enumération d’utilisateurs 2/2

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 :

Fig 6 : Stacktrace de l’application

Cette trace divulgue des informations sensibles quant au SI de la cible :

backend.willywonka.shop

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0IiwiYXVkIjoiZnJvbnRlbmQud2lsbHl3b25rYS5zaG9wIiwiaWF0IjoxNTYyNjY0MzE1LCJleHAiOjE1NjI2NjQ5MTV9.UW7ZBlYilpv6g5oI-ryrnq1l00kfurcTbaG2FtSEU-o

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) :

Fig 7 : Cookie backend-session

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 :

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhYXMiLCJhdWQiOiJiYWNrZW5kLndpbGx5d29ua2Euc2hvcCIsImlhdCI6MTU2MjY2NDMxNSwiZXhwIjoxNTYyNjk0MzE1fQ.6yuVpu_jugKOZL9p9-M-wAF6knpArUJqnfgQzS4W9N4

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
Fig 8 : Nouveau jeton

Avec ce nouveau JWT, il est possible de passer outre l’authentification et d’accéder ainsi au backend de l’application :

https://backend.willywonka.shop/reset/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhYXMiLCJhdWQiOiJiYWNrZW5kLndpbGx5d29ua2Euc2hvcCIsImlhdCI6MTU2MjY2OTkxMiwiZXhwIjoxOTk5OTk5OTk5fQ.pZxLNOIrI1DCRdB-MBWDNtDnmeKeANTNm5btAoY6Pmw

Conformément à l’énoncé, le flag se situe dans les données du ticket deadbeef :

Fig 9 : Second flag

II.6. Flag

Ressources

  1. danielmiessler, SecLists – top-usernames-shortlist.txt, GitHub : https://raw.githubusercontent.com/danielmiessler/SecLists/master/Usernames/top-usernames-shortlist.txt
  2. Auth0, JSON Web Token debugger, jwt : https://jwt.io/
  3. ticarpi, jwt_tool, GitHub : https://github.com/ticarpi/jwt_tool

III. Step 3 – XXE Out-of-band

TL;DR

  1. Forger une XXE OOB via le fichier SVG ;
  2. Uploader le fichier SVG à l’adresse : http://willywonka.shop/profile?filetype=image%2fsvg%2bxml, ne pas oublier de changer le MIME type ;
  3. Remplir le formulaire avec aas en nom de victime et de la donnée random ;
  4. Récupérer l’id du ticket et y accéder dans le backend ;
  5. 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.

Fig 10 : Formulaire d’upload sur le frontend

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 :

Fig 11 : XXE OOB in a nutshell

Lors de CTF passés, j’ai déjà évoqué les XXE OOB : https://maki.bzh/walkthrough/santhacklaus2018/#archdrive-4-3

Dans cet article, le même serveur a été utilisé, mais il est aussi possible d’utiliser deux instances ngrok : https://maki.bzh/stupidthings/dontpayvps/.

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 :

Fig 12 : Formulaire frontend rempli

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.

Fig 13 : Ticket côté backend

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

Ressources

  1. alexbirsan, LFI and SSRF via XXE in emblem editor, HackerOne : https://hackerone.com/reports/347139
  2. 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

TL;DR

  1. 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/ ;
  2. Les informations du bucket se situent ici : http://169.254.169.254/latest/dynamic/instance-identity/document ;
  3. 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 ;
  4. Lister le contenu du bucket : aws s3 ls s3://willywonka-shop ;
  5. Récupérer le flag : aws s3 cp s3://willywonka-shop/Flag-04.txt . .

V.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

Ressources

  1. @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/
  2. 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

TL;DR

  1. Se connecter au VPN récupéré dans le bucket ;
  2. Une nouvelle route est apparue : 172.16.42.0/24 ;
  3. Effectuer une énumération de ce nouveau réseau et remarquer une machine avec le port 8080 (tomcat) ouvert ;
  4. Utiliser dirsearch avec une wordlist tomcat (seclist), et trouver la page /host-manager/ ;
  5. Se connecter avec les identifiants tomcat : tomcat ;
  6. Monter un partage samba nommé data avec un webshell (cmd.war) à l’intérieur ;
  7. Déployer le webshell en tant que nouvelle application via les UNC path ;
  8. Accéder au webshell à l’adresse : http://maki-lab:8080/cmd/index.jsp?cmd=whoami ;
  9. Utiliser netcat pour faire un reverse shell.

V.1. Reconnaissance

Lorsque le tunnel VPN est correctement monté, une nouvelle adresse apparaît :

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 :

  1. Connexions anonymes sur le partage Samba ;
  2. 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 à :

  1. Une connexion anonyme sur le RPC et SMB ;
  2. 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/.

Fig 14: Index du serveur web

En naviguant sur le site, il est possible de trouver une cartographie du réseau : http://172.16.42.11:8080/infra.jsp :

Fig 15 : Schéma réseau incomplet

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 :

Fig 16 : Page manager

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 :

Fig 17 : Host-manager page

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

Fig 18 : Webshell

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 :

Fig 19 : Reverse shell

Cette méthode permet de récupérer un accès shell plus ou moins interactif et plus ou moins stable.

Fig 20 : Flag

V.5. Flag

Ressources

  1. SecList, Discovery Web-content Tomcat, GitHub : https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/tomcat.txt
  2. 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/
  3. Eternallybored, Download netcat Windows binaries; eternallybored.org : https://eternallybored.org/misc/netcat/netcat-win32-1.11.zip

VI. Step 6 – Mimikatz you said ?

TL;DR

  1. Exécuter procdump.exe sur le serveur tomcat (SRV01-INTRANET) ;
  2. Récupérer le minidump du processus lsass.exe ;
  3. 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.

Fig 21 : Récupérer le minidump de lsass.exe

Toujours avec les UNC path, on copie les fichiers sur un partage distant :

Fig 22 : Copie du minidump vers notre partage

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 :

VI.4. Flag

Ressources

  1. sevagas, swap_digger, GitHub : https://github.com/sevagas/swap_digger
  2. Microsoft, Windows Sysinternals, Documentation Microsoft : https://docs.microsoft.com/en-us/sysinternals/
  3. Sebastien Macke – @lanjelot, Dumping Windows Credentials, securusglobal : https://www.securusglobal.com/community/2013/12/20/dumping-windows-credentials/
  4. 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/
  5. ired.team, Credential Access & Dumping, ired.team : https://ired.team/offensive-security/credential-access-and-credential-dumping
  6. Mark Russinovich and Andrew Richards, ProcDump v9.0,  Documentation Microsoft : https://docs.microsoft.com/en-us/sysinternals/downloads/procdump

VII. Step 7 – Spreading love

TL;DR

  1. Essayer d’accéder aux partages du réseau avec les identifiants récupérés ;
  2. Trouver le partage Users sur le serveur 172.16.42.5 ;
  3. 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

Ressources

  1. ShawnDEvans, SMBmap, GitHub : https://github.com/ShawnDEvans/smbmap
  2. 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

TL;DR

  1. Faire un bloodhound avec le compte adminServer ;
  2. Remarquer la relation AddAllowedToAct entre DC01-WW2.FACTORY.LAN et SvcJoinComputerToDom ;
  3. Grâce à la note précédente et à la relation trouvée, comprendre qu’il faut abuser du Ressources based constrained delegation ;
  4. Ajouter de la CommandoVM dans le domaine grâce au compte de service (SvcJoinComputerToDom) ;
  5. Créer un SPN et modifier sa valeur de msDS-AllowedToActOnBehalfOfOtherIdentity ;
  6. Abuser du mécanisme S4U (S4U2User et S4U2Proxy) avec Rubeus pour usurper l’identité de l’administrateur de domaine ;
  7. Lorsque Rubeus a forgé le ticket de l’administrateur, utiliser psexec sur le contrôleur de domaine ;
  8. Extraire le ntds.dit en utilisant vssadmin sur le contrôleur de domaine ;
  9. 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 :

Fig 23 : Adresse IP du serveur DNS (DC)

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_) :

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 :

  1. Pouvoir réécrire l’attribut msds-AllowedToActOnBehalfOfOtherIdentity, contenant les comptes de confiance ;
  2. 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 :

Fig 24 : Connexion de CommandoVM au domaine FACTORY.LAN

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

Fig 25 : Liste des utilisateurs du domaine

Harmj0y a écrit un article détaillé sur cette attaque et a même fourni 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 :

Fig 26 : Droit « WriteProperty »

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.

Fig 27 : AccessAllowed

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écanismes… Enfin presque. Pour des soucis de pérennité, l’organisateur a fait le choix de restaurer l’ensemble des machines à leur état d’origine toute les heures, causant ainsi l’erreur suivante :

Fig 28 : Erreur Kerberos

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.

Fig 29 : Erreur corrigée et exécution de Rubeus

La commande Rubeus s’étant terminée correctement, un ticket Administrator @ factory.lan a été créé en mémoire :

Fig 30 : Ticket Kerberos de l’administrateur de domaine

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 :

Fig 31 : Disque C du DC

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é :

Fig 32 : Copie du ntds.dit en passant par vssadmin

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 :

Fig 33 : Extraction de la base system

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 :

Fig 34 : Extracting hash

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

Ressources

  1. Pixis, BloodHound, hackndo : https://beta.hackndo.com/bloodhound/
  2. Rohan Vazarkar, BloodHound 2.1: The Fix Broken Stuff Update, cptjesus.com : https://blog.cptjesus.com/posts/bloodhound21
  3. PenTestPartners, Bloodhound walkthrough. A Tool for Many Tradecrafts, Blog de PenTestPartners : https://www.pentestpartners.com/security-blog/bloodhound-walkthrough-a-tool-for-many-tradecrafts/
  4. Pixis, Resource-Based Constrained Delegation – Risques, hackndo : https://beta.hackndo.com/resource-based-constrained-delegation-attack/
  5. 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/
  6. 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
  7. Microsoft, Security Descriptor Definition Language, Documentation Microsoft : https://docs.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-definition-language
  8. Dirk-jan Mollema, “Relaying” Kerberos – Having fun with unconstrained delegation, Blog de Dirk-jan Mollema : https://dirkjanm.io/krbrelayx-unconstrained-delegation-abuse-toolkit/
  9. 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/
  10. Microsoft, vssadmin, Documentation Microsoft : https://docs.microsoft.com/fr-fr/windows-server/administration/windows-commands/vssadmin
  11. swisskyrepo, PayloadsAllTheThings, GitHub : https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Ressources/Active%20Directory%20Attack.md#dumping-ad-domain-credentials-systemrootntdsntdsdit

IX. Step 9 – Not so hashed

TL;DR

  1. Il est possible de se connecter avec le hash de l’utilisateur adminWorkstation à la dernière machine (PC01-DEV) de ce LAN ;
  2. Remarquer que la machine utilise WinSCP ;
  3. N’ayant pas de master password sur WinSCP, il est possible de récupérer des informations dans les clés de registre ;
  4. 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 ;

  1. Décoder le hash et recueillir les identifiants : veruca : CuiiiiYEE3r3! ;
  2. Ajouter une route vers le sous réseau contenant la machine de veruca ;
  3. 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 :

Fig 35 : Connxion à 172.16.42.101

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 :

Fig 36 : Obtention des identifiants et de l’IP de Veruca 1/2

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.

Fig 37 : Obtention des identifiants et de l’IP de Veruca 2/2

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 :

Fig 38 : SSH connection and flag

X.4. Flag

Ressources

  1. Paul Lammertsma, Where does WinSCP store site’s password?, SuperUser : https://superuser.com/questions/100503/where-does-winscp-store-sites-password
  2. anoopengineer, WinSCP Password Extractor/Decrypter/Revealer, GitHub : https://github.com/anoopengineer/winscppasswd/
  3. Vivek Gite, Linux route Add Command Examples, cyberciti : https://www.cyberciti.biz/faq/linux-route-add/
  4. 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

TL;DR

  1. Trouver l’autre machine via ARP : cat /proc/net/arp ;
  2. Remarquer que nginx est installé ;
  3. Dans la configuration du nginx, trouver la racine du frontend : /usr/share/nginx/dev3.challenge.akerva.com ;
  4. Récupérer une clé privée SSH dans l’un des dossiers ;
  5. Grâce à l’indice de Akerva, on connait l’utilisateur de la machine distante : violet ;
  6. Atterrir dans un environnement restreint : lshell ;
  7. 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 réflexes 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 à 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 : https://mega.nz/#!Lj4DlAqD!QCLeAbjrbXU5QkCT8pGOXATWDV4jNjv4wuKc_nKoc9w

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 :

Fig 39 : SSH connection and restricted shell

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 :

Fig 40 : Evasion du shell restreint

Le flag est situé dans le home de violet :

X.4. Flag

Ressources

  1. ghantoos, lshell – SECURITY ISSUE: Inappropriate parsing of command syntax, GitHub : https://github.com/ghantoos/lshell/issues/151#issuecomment-303696754

XI. Step 11 – Free flag

TL;DR

  1. Remarquer qu’il existe des fichiers world readable dans le /home du système ;
  2. Lire la clé privée de l’utilisateur Georgina ;
  3. 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 :

Fig 41 : Clé privée disponible en lecture pour tous les utilisateurs

La clé privée est disponible :

https://mega.nz/#!7r5BEYBR!q02ij1f1vGJ8cgXDdrmfkKaHK16cFwngdTuDzqqJ6u8

Il ne reste plus qu’à se connecter au même serveur en tant que Georgina :

XI.2. Flag

XII. Step 12 – Return to PLankTon

TL;DR

  1. Utiliser LinEnum afin de trouver exportVIP un binaire SUID et SGID ;
  2. Trouver l’overflow de manière empirique ;
  3. Déterminer le padding (de 296 octets) nécessaire à la réécriture de RSP ;
  4. Regarder la plt du binaire et les protections mises en place et en déduire que l’exploitation est un ret2plt ;
  5. Récupérer l’adresse de la fonction system disponible dans la plt ;
  6. Trouver un gadget pop rdi; ret dans le binaire nécessaire pour le placement des arguments ;
  7. Trouver l’adresse d’une chaîne de caractère dans le binaire, par exemple GNU ;
  8. Faire un script exécutant un /bin/bash -p, l’appeler GNU et le rajouter dans le PATH ;
  9. Exploiter le ret2plt en appelant la fonction system en plaçant GNU en paramètre : 

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 :

https://mega.nz/#!DrxxwK6a!1hOFmmYMrImfOaGUC6aIfbTn8oPCyDqwDWgBcKSbz24

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.

Fig 42 : Type d’exploitation en fonction des protections

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 :

Fig 43 : Padding pour contrôler RIP

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 :

Fig 44 : Adresse de « GNU »

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.

Fig 45 : Accès root

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

Ressources

  1. Rémi Martin, Exploitation – ByPass ASLR+NX with ret2plt, shoxx-website : http://shoxx-website.com/2016/05/exploitation-bypass-aslrnx-with-ret2plt.html
  2. Geluchat, Petit Manuel du ROP à l’usage des débutants, dailysecurity : https://www.dailysecurity.fr/return_oriented_programming/

XIII. Step 13 – The final countdown

TL;DR

  1. Trouver la machine qui manque sur le schéma réseau avec arp : cat /proc/net/arp ;
  2. Mettre en place un proxychains avec la machine précédente en tant que pivot ;
  3. Faire un scan de port avec nmap sur la nouvelle cible, voir le nfs sur le port 2049 ;
  4. Monter le nfs distant sur la machine de pivot ;
  5. Copier les fichiers du partage réseau ;
  6. 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 tagué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 :

https://mega.nz/#!q25BzSLZ!w9_4B8q7YTCgrUoMYkWPmyRn374xBZhxarUtYmgJJGc

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 apparu : 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

Ressources

  1. Bima Fajar Ramadhan, ProxyChains Tutorial, linuxhint : https://linuxhint.com/proxychains-tutorial/
  2. 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 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 : C’était de belles épreuves, et j’ai hâte de jouer le Wonka3 l’année prochaine !

Alan Marrec |Pentester| Openminded| @maki_mitz