Présentation d’un write-up de résolution du challenge « Web – Sticky! Sticky! » du WARGAME de la Nuit du Hack 2016.
Le weekend du 02-03 juillet 2016 se déroulait le WARGAME de la Nuit du Hack 2016 sous forme d’un CTF Jeopardy. Ayant eu l’occasion et le temps d’y participer avec quelques collègues et amis, voici un write-up de résolution d’un des challenges auquel nous avons pu participer.
- Catégorie : Web
- Nom : Sticky! Sticky!
- Description : HEY! Welcome back!
- Hint 1 : check all the cookies!!!
- Hint 2 : resolution is in base32
- URL : http://sticky.wargame.ndh
- Points : 250
Vu le nom du challenge, « sticky », on se doute qu’une notion de cookie et de « persistance » va entrer en jeu…
En se rendant à l’URL du challenge, nous étions invités à renseigner un nom d’utilisateur :
Dès lors qu’un login était indiqué, une simple page « Welcome back » était affichée avec une réflexion du login :
En observant plus en détail les requêtes, nous avons un cookie de défini :
GET /index.php HTTP/1.1 Host: sticky.wargame.ndh User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate DNT: 1 Cookie: user_id=553241; validator=validator.wargame.ndh; resolution="YCUAACI=" Connection: close
- user_id : l’identifiant de l’utilisateur qui s’incrémente (généré côté serveur)
- validator : un nom d’hôte privée de « validation »
- resolution : une valeur encodée, en Base64 ? (l’obtention du second « hint » du challenge indiqua qu’elle était en Base32 finalement…).
En testant divers encodage / décodage en Base64 de la valeur « resolution », aucune information pertinente n’est révélée, mis à part des erreurs intéressantes (également visible après de multiples exécution de la requête) :
Dans le cas où l’on modifie la valeur du cookie « validator », on obtient une erreur de tentative d’hijack :
On poursuit les tests en tentant d’injecter un payload au travers du login. Mis à part une petite XSS persistante, rien d’exploitable :
La présence de cette XSS, stockée côté serveur (bien que les réponses paraissaient derrières un load-balancer), a permis à un malicieux troll d’injecter un faux-flag qui en a dérouté plus d’un ^^ ! Bien joué 😉 !
D’après les erreurs précédentes et les hints, on en déduit plusieurs choses :
- Le frontend est une simple application web de connexion et de réflexion d’un login
- Le login (et ses privilèges) semblent vérifiés auprès d’un domaine tiers inaccessible « validator.wargame.ndh », dont nous avons la main au travers des cookies
- Nous avons également la main sur le « user_id » via les cookies, valeur qui, positionnée à « 1 », permet d’afficher un « Welcome admin! »
- L’hôte de validation « validator.wargame.ndh » semble en écoute sur le port « 8888 » comme indiqué dans le précédent message d’erreur
- Lorsqu’on altère la valeur encodée « resolution » au travers des cookies, on a un message d’erreur lié à la résolution DNS de l’hôte « validator.wargame.com ». Serait-ce l’adresse arbitraire du « name server » de résolution DNS ?
Tentons d’intérroger le serveur « sticky.wargame.ndh » sur le port 8888 lui-même :
GET / HTTP/1.1 Host: sticky.wargame.ndh:8888 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate DNT: 1 Cookie: user_id=553241; validator=validator.wargame.ndh; resolution="YCUAACI=" Connection: close
Réponse :
HTTP/1.1 200 OK Server: nginx/1.6.2 Date: Sun, 03 Jul 2016 01:32:06 GMT Content-Type: text/plain; charset=utf-8 Connection: close Content-Length: 25 {"admin": 0, "name": "0"}
La résolution du challenge nécessite très certainement de forcer cette réponse avec un « admin:1 » !
Intéressons nous d’avantage à la valeur du cookie « resolution », qui, suite à la délivrance du second « hint », s’avère être en Base32 :
- Valeur par défaut : YCUAACI=
- Base32 to Hex : C0A80009
- ASCII : [192][168][0][9]
C’est donc une IP qui est encodée dans le champ « resolution » du cookie ! Tout devient censé :
Une requête émise vers l’application avec le cookie engendre les actions suivantes :
- Le serveur web interroge le serveur de nom (NS) dont l’IP est encodée en Base32, transmis dans le cookie « resolution ». Valeur par défaut : 192.168.0.9.
- Le serveur demande au NS l’IP correspondant au domaine indiqué dans le cookie « validator » : « Quelle est l’IP correspondante au domaine validator.wargame.ndh ? »
- Le serveur d’IP correspondante est interrogé sur le port 8888 pour valider le nom d’utilisateur. Ce serveur web retourne du JSON de type :
{"admin": 0, "name": "admin"}
Côté client, nous avons la main pour se faire passer pour ce serveur de noms, ce serveur de validation, et forcer une validation JSON avec :
{"admin": 1, "name": "admin"}
Mon poste, connecté au réseau du Wargame de la NDH, avait pour IP : 172.16.16.250, soit en hexadécimal : AC1010FA et donc en Base32 : VQIBB6Q= (convertisseur disponible ici).
La nouvelle valeur du cookie « resolution » sera donc VQIBB6Q=. Le serveur web cherchera à résoudre le nom d’hôte indiqué dans « validator » sur le NS qui sera finalement ma machine 172.16.16.250.
Il me faut donc transformer mon poste en tant que serveur DNS. Pour cela :
apt-get install dnsmasq echo validator.wargame.ndh 172.16.16.250 >> /etc/hosts /etc/init.d/dnsmasq start
C’est chose faite !
Maintenant que la résolution DNS de l’hôte « validator.wargame.ndh » est faites par mon poste, et qu’elle pointe sur mon poste, il ne reste plus qu’à monter un petit serveur web sur le port 8888 qui renverra le JSON « admin:1 » :
mkdir sticky cd sticky vi 1 # {"admin":1,"name":"admin"} python -m SimpleHTTPServer 8888
Notre serveur web est lancé sur le port 8888, et un fichier « 1 » délivre le JSON adéquat pour devenir admin.
Il ne reste plus qu’à réaliser la dernière requête vers « sticky.wargame.ndh », avec comme cookie :
- user_id=1 : l’admin
- validator=validator.wargame.ndh : qui sera résolu part notre propre serveur de nom
- resolution=VQIBB6Q= : l’IP en Base32 de notre serveur de nom
Bingo ! Flag : ndh2k16_e5f3eb90c4438c1a062125e3f74c2b41
Merci à toute l’équipe de la NDH2K16 pour cet événement et pour toute l’organisation !
Salutations à nj8, St0rn, Emiya, Mido, downgrade, Ryuk@n et tout ceux dont je n’ai hélas pas le pseudo :), on remet ça quand vous voulez ? // Gr3etZ
Sources & ressources :