4.4 KiB
+++ author = "Maik de Kruif" title = "Challenge 14 - AdventOfCTF" date = 2020-12-14T19:45:51+01:00 description = "A writeup for challenge 14 of AdventOfCTF." cover = "img/adventofctf/2020/dd04640480d764ab09eea047cde749cd.png" tags = [ "AdventOfCTF", "challenge", "ctf", "hacking", "writeup", "web", "php", ] categories = [ "ctf", "writeups", "hacking", ] +++
- Points: 1400
Description
We are testing a new 2-factor security system for Santa's deepest secrets. It should be pretty secure!
Visit https://14.adventofctf.com to start the challenge.
Finding the vulnerability
Upon opening the challenge website we're greeted with some PHP code, as well as two input fields. The PHP code is the following:
<?php
ini_set('display_errors', 0);
include("flag.php");
if (isset($_POST["password"], $_POST["verifier"])) {
$password = $_POST["password"];
$verifier = $_POST["verifier"];
$hash = sha1($password + $secret_salt);
$reference = substr($hash, 0, 7);
if ($verifier === $reference) {
echo $flag;
die();
}
}
header("Location: /index.php?error=That was not right.");
exit();
?>
As we can see, we only get the flag if $verifier
is equal to $reference
, where $reference
is the SHA-1
hash of the password in our request together with $secret_salt
.
Note: when I started with this challenge, @credmp had already posted a hint which I, unfortunately, saw. It said "The salt is a number.".
Type Juggling
Because we already know $secret_salt
is a number, we can leverage PHP type juggling to generate a known value for the hashing algorithm. But first, what is type juggling?
Because PHP does not support explicit type definition in a variable declaration, a variable's type is determined by the context in which the variable is used. For instance, if a string
value is assigned to a variable $var
, $var
becomes a string. But if an int
value is then assigned to $var
, it becomes an int. This means that if we have a string
and add an int
to it, the outcome will be an int
. The value of this int
depends on what is inside the string
. If the string
starts with a number, it will be interpreted as an int
with the value of the number inside the string
, and if it starts with a letter, it will be interpreted as 0
.
For example, if we have a variable with the value "hello"
, it will be converted to 0
. And if we have a variable with the value "24"
or "12ab"
it will be interpreted as 24
and 12
respectively.
Generating a verifier value
To see what input will be converted to what output, we can create a little script that will generate those values for us. An example would be the following:
<?php
$password = "1a";
$secret_salt = "11";
$hash = sha1($password + $secret_salt);
$reference = substr($hash, 0, 7);
echo ($password + $secret_salt)."\n";
echo $hash."\n";
echo $reference."\n";
?>
We can then run this script on our local machine or on a website like https://sandbox.onlinephpfunctions.com/.
This script will take the two inputs and give us the outcome of the addition with the $secret_salt
(I used 11 as the salt number but it could be any number), the generated hash and thus the $verifier
input we need for the original script.
If we make $password
a really big number like 922337203685477580792233720368547758079223372036854775807
we see that the output of the addition will be written in the scientific notation if it is converted to a string. And because the sha1()
function wants a string
for the input, it will also get the shrunk-down version. This means that if we make $password
big enough, the value of $secret_salt
will not matter as it is not significant enough for the output.
If we thus enter 922337203685477580792233720368547758079223372036854775807
as $password
in the above script, we get the following output:
9.2233720368548E+56
48a888ebec04f516e8b765bc3879354411ac2387
48a888e
If we thus use 922337203685477580792233720368547758079223372036854775807
as the password and 48a888e
as the verifier, it should echo the flag.
Solution
After entering the above form data and submitting it, we get the flag: NOVI{typ3_juggl1ng_f0r_l1fe}
!
This flag can then be submitted for the challenge.