SQL注入进阶——堆叠注入

文章讲述了如何利用PHP的mysql_multi_query函数进行注入,包括常规注入尝试、联合查询、报错注入,遇到WAF过滤后通过源码分析发现堆叠注入的可能性。通过预编译和hex绕过解决WAF限制,最终通过更改表名获取flag。
摘要由CSDN通过智能技术生成

目录

产生原因:

注入实例:

注入过程:

常规注入尝试:

源码分析:

堆叠注入:

预编译解决:

hex绕过waf:

更改表名解决:

总结:

思路总结:


产生原因:

        在网站有注入点的情况下,由于PHP mysql_multi_query()这个函数支持多个SQL语句同时执行,所以我们第一条查询语句输入正常的查询语句,在后续的查询语句传入我们的恶意查询语句,就可以拿到对应网站的数据了。

注入实例:

        本次注入环境以2019年强网杯随便注为例。

        在线靶机环境:BUUCTF在线评测 (buuoj.cn)

注入过程:

常规注入尝试:

进入靶机之后,我们发现输入框里面有个1,还有个提交按钮,我们提交一下看看。我们可以发现地址栏中出现了?inject=1,那就说明这是一个GET传参,那我们继续先试一下我们常规的注入流程,先试一下order by看看。​​​​​​​我们输入order by 3,发现有错误提示信息,那我们再试试2看看。order by 2就对了,我们在order by的过程中发现这张表有两个字段,并且有错误提示信息,那么我们就可以考虑union联合查询和报错注入两种方法,那我们就来试一试吧。先试一试联合查询吧。我们看看他返回的信息:

return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);

它把select、update、delete等等都给过滤掉了,后面还有个i,那完蛋了大写绕过也不行了,多写绕过也不顶用了。那咋办呢,卡到这里了,我们去看看源码找找有没有什么方式吧。

源码分析:

<html>

<head>
    <meta charset="UTF-8">
    <title>easy_sql</title>
</head>

<body>
<h1>取材于某次真实环境渗透,只说一句话:开发和安全缺一不可</h1>
<!-- sqlmap是没有灵魂的 -->
<form method="get">
    姿势: <input type="text" name="inject" value="1">
    <input type="submit">
</form>

<pre>
<?php
function waf1($inject) {
    preg_match("/select|update|delete|drop|insert|where|\./i",$inject) && die('return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);');
}

function waf2($inject) {
    strstr($inject, "set") && strstr($inject, "prepare") && die('strstr($inject, "set") && strstr($inject, "prepare")');
}

if(isset($_GET['inject'])) {
    $id = $_GET['inject'];
    waf1($id);
    waf2($id);
    $mysqli = new mysqli("127.0.0.1","root","root","supersqli");
    //多条sql语句
    $sql = "select * from `words` where id = '$id';";

    $res = $mysqli->multi_query($sql);

    if ($res){//使用multi_query()执行一条或多条sql语句
      do{
        if ($rs = $mysqli->store_result()){//store_result()方法获取第一条sql语句查询结果
          while ($row = $rs->fetch_row()){
            var_dump($row);
            echo "<br>";
          }
          $rs->Close(); //关闭结果集
          if ($mysqli->more_results()){  //判断是否还有更多结果集
            echo "<hr>";
          }
        }
      }while($mysqli->next_result()); //next_result()方法获取下一结果集,返回bool值
    } else {
      echo "error ".$mysqli->errno." : ".$mysqli->error;
    }
    $mysqli->close();  //关闭数据库连接
}


?>
</pre>

</body>

</html>

我们发现这个网站主体思路就是先拿到get传参,经过两次waf过滤进入到数据库查询,我发现multi_query()这个函数了,它支持SQL多条查询语句执行。

我们再来看看它的两个waf:waf1我们已经见到过了,看看waf2,我们可以发现waf2它过滤的是set 和 prepare,过滤这两有啥用啊,哪能过滤肯定有用,这是MySQL中的预编译。预编译的语句刚好适配multi_query(),哈哈哈这不就是解题思路么,我们正常走,顺便看一下还有没有其他的接替方法了。

堆叠注入:

我们现在知道可以使用堆叠注入了,我们就先查询它的基本信息。

我们先来查一下它的表,输入代码:1';show tables;#发现该数据库下有两个表,我们先看看wodrs里面有啥吧,

输入代码:1';desc words;desc `1919810931114514`#flag在1919810931114514这个表里,终于接近真相了,那么怎么能查询到flag呢,现在已知的解题方法就是预编译了,我们来试试吧。

预编译解决:

先来简单介绍一下预编译:

这是我自己的数据库,prepare语句是定义我们查询语句的模板,set是定义id变量,因为在这里变化的东西只有id所以id作为变量。execute语句是执行语句。

先来定义prepare预编译语句:prepare aaa from 'select * from users where where id=?'; 
再定义变量id:set @id=10; 
最后执行:execute aaa using @id;

这就是预编译。

回到这个靶场中,我们使用预编译看看吧,waf2中将prepare 和 set给过滤了,并且waf1 将select等字段过滤了,我们要考虑绕过。我的思路就是waf1中我们可以使用concat函数将select拼接绕过waf1,到了waf2中我们可以使用大小写绕过。我们来试一下。输入代码:1';Set @a = PREpare flag from @a;CONcat('sel','ect * from `1919810931114514`;');Execute flag;# 我们发现并没有出来结果,我们检查一下代码有什么问题没。代码并没有啥问题,那是怎么了?

在MySQL中预编译可以先定义prepare,在php中不能先定义prepare,因为prepare中有未定义的变量,而在MySQL中可以先用未定义变量。那我们就先定义变量吧,输入代码:1';Set @a = CONcat('sel','ect * from `1919810931114514`;'); PREpare flag from @a;Execute flag;#终于,我们拿到了flag。

hex绕过waf:

waf中过滤了select,我们可以使用16进制来绕过,结合预编译一起来试一试。输入代码:1';Set @a = 0x73656c656374202a2066726f6d20603139313938313039333131313435313460; PREpare flag from @a;Execute flag;#

更改表名解决:

我们可以发先inject参数拿到之后赋值给变量id,然后通过id在words表中查询数据,既然有了堆叠注入,那我们就可以将两个数据库名字改了,将words改成word1,将1919810931114514改成words,并且给它条件id字段并赋值为1,那我们传入inject参数为1,赋值给id,完了查出来的数据自然就是flag了。

输入代码:1'; rename table words to word1; rename table `1919810931114514` to words;alter table words add id int not null auto_increment primary key;zongjie

总结:

思路总结:

        我们最开始先进行常规注入,发现有报错,就考虑联合查询和报错注入,再发现select,update等都被waf过滤掉了,到这之后我们也没啥思路了, 我们去看了源码发现有multi_query()这个函数,我们就考虑了堆叠注入,完了之后就先查表数据,我们查到flag数据位919810931114514这个表中,我没想到的就是预编译,但是select、prepare、set、等都被waf过滤,源码可以发现预编译的关键词都可以使用大写来绕过,select绕不过去,于是我们就使用concat函数将进行拼接。完美的解决了问题拿到了flag,再后来select我们使用了hex进行绕过也是没有问题的。最后我们又想了一种方法就是更改表名,也是成功了。

        用随便注来学习堆叠注入,我很清楚看到了堆叠注入的威力了,那么怎么防御呢,我们要严格根据官方手册来使用pdo,这就非常安全了,当然这也是现在大部分企业在使用的安全策略。

  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哈hhhh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值