WEB攻防-PHP-SQL注入扩展篇
上一期我们详细(真的详细吗)的过一一遍sql注入里面的基础应用,普通的拼接注入,然后就是sqlmap的使用,还有基于有无回显的盲注,相信你们现在对sql注入已经有了一个清晰的认识,可以简单的进行注入了,快去找个靶场练手吧~
而这一期我们就简单的提一下他另外的几个注入方法,这几个方法已经不算普通的方法了,所以这里就单开一期叽里咕噜
首先就是二次注入
什么是二次注入呢,其实很好理解,简单来说就是你现在进行sql注入,但是首先你是把数据给添加到数据库了,通过构造特殊的值先将值存入数据库,这时候检查通过了,数据就被存进去了,然后当你查询的时候,那个值与sql语句刚好拼成了一个payload,那不就触发了注入吗,比如用户注册
假如你注册了一个用户,但是你不老实,注册成一个:miku 'and updatexml(),结果这个用户名居然个你注册过了,然后你就点击修改密码,众所周知,一般登录过后你要修改密码他是不要你输入用户名的,所以现在假如他的修改语句是
update users set password='114514' where username='miku';
正常来说是这样的对不对,但是你的用户名是个sql语句啊,所以现在拼接成了
update users set password='114514' where username='miku' and updatexml();
这不就是一个注入语句吗,可恶
当然,这里是不考虑对方对你的限制,只是说一下原理
现在我们就来做个小实验
一个可以注册,登录和修改密码的网站,首先尝试一下注册用户看是否成功
可以看到上面的sql语句,成功的注册了,现在登录看看
功能验证现在没有问题了,现在我们就来尝试一下二次注入
首先注册一个不正常的用户
miku' and updatexml(1,concat(0x7e,(select database()),0x7e),1)#
现在可以看到我们的用户名现在就是一个sql语句了,现在我们来登录看看
现在我们的用户名你在这里还是正常登录,不会触发sql语句,然后我们要是修改密码呢
可以看到你随便输入什么东西,他都会触发这个sql语句然后报错输出我们需要的信息,这就是最典型的二次注入哈,通过这个例子你就明白了,首先是偷偷注入一个不会在前面生效的恶意用户,然后当有修改逻辑的时候,这个用户名就被拼接到sql语句中,然后就触发了报错
但是这里要注意的就是,在你注册和登录的时候,他是要对你输入的参数进行过滤的,也就是说完全把这个语句当成一个字符串来写进数据库,不然你连注册都注册不了,或者是直接干成普通的报错注入了
在这个insert参数中,我们前面已经输入了一个miku然后由于我们的引号给他闭合了,导致我们后面的参数没有地方可去了,然后后面的又因为#号导致后面的也都注释了,导致完全发挥不出作用
所以说这个二次注入其实也是有条件的。
注册和登录都需要进行转义或者预处理来过滤掉语句。这在防范sql注入的时候也是非常重要的,也是为了防止用户随意的进行sql注入,就像上次做的那个抓包实验那样,可以看到对方回显的带斜杠的参数,说明就是对我们的输入进行转义,然后导致语句无效
可以看到当你输入一个转义符之后,他就过滤掉了引号,然后把整个语句都当成一个字符串插入到数据库中,所以前面就没有出现错误的情况
然后在插入的时候可以看到,他转义符又消失了,所以后面修改密码的时候就会导致他执行这个sql语句,这就是二次注入的原理
不过其实感觉还是有点用的哈,因为后台并不会对数据库里的信息进行过滤,所以基本上都能成功,但是这个实在是太麻烦了,基本上在黑盒中基本不可能实现,一个一个太慢了,你并不知道他的逻辑,没办法,只能靠运了呗
这里简单的举一个cms的例子
他这里发布招聘这里有一个二次注入漏洞,我们来实验一下
在这个地方有漏洞,但是他限制了我们的字符长度,但是他这个是前端限制,所以直接修改就完事了
这不就好了吗
现在我们填好之后,这里为什么这样填呢
咦,这是怎么回事,我的名字怎么变成数据库连接信息了,蛙趣
现在我们就从黑盒的角度分析,为什么会出现这种漏洞
首先我们创建这个简历模版,不就是跟前面注册用户一样的吗,也是要把这个数据写进数据库,然后由于真实姓名这里调用的就是这个fullname,然后我们这把这个用户赋值给了这个字段,不就导致后面他要显示姓名的时候,结果是触发了这个sql语句了,不过其实还是挺难理解的哈,还是来看代码吧
首先根url判断源文件位置
然后根据这个确定他保存命令的函数
虽然有点乱码,但时候不影响哈,然后可以看到他所有的值都赋值了给了前面这个set什么什么的变量,然后下面有这个if的函数,我们追踪一下看看
这就是他整个的函数体,当所有的值都赋值过来后,就会执行最后的sql语句,然后那里的参数,不就是上面传过来的吗,所以到后面他就把我们写的sql语句拼接上去了,导致了前面的二次注入
所以白盒的思路就是insert后进入select或updatad的代码块
至于黑盒就更不用说了,有添加,有能对添加后的数据引用的地方,都可以测测
注入的条件就是插入时有转义函数配置,后续有利用插入的数据
但还是说,这个二次注入在黑盒中基本不推荐,太令人难受了捏
堆叠注入
这个甚至比二次注入更难绷哈,这个条件非常苛刻,简单来说就是同时执行多条sql语句
正常来说,一个sql语句是以分号结尾的,但是他也可以再后面接上语句同时执行两个语句
现在就是同时查询数据并且又新建了一个表,既然这样的话,我们尝试在新闻那个注入点来执行一下看看有没有用,首先删掉刚刚创建的表
可以看到虽然我们在数据库中确实创建成功了,但是在php中他却报错了,这是什么原因造成的呢
我们知道,在php中执行sql语句的时候,我们都会用上一个叫 mysqli_query()的函数,而这个函数只能执行一条sql命令,所以如果想要执行多条命令,需要用到mysqli_multi_query()这个函数
简单创建一个文件
<?php include 'config.php'; $id = $_GET['id'] ?? '1'; $sql = "SELECT * FROM news WHERE id = $id"; echo "<pre>$sql</pre>"; // 执行多个SQL语句 if (mysqli_multi_query($conn, $sql)) { do { // 获取当前结果集 if ($result = mysqli_store_result($conn)) { while ($row = mysqli_fetch_assoc($result)) { // 打印每条记录 foreach ($row as $key => $value) { echo htmlspecialchars("$key: $value") . "<br>"; } echo "<hr>"; } mysqli_free_result($result); } // 如果还有更多结果,继续处理 } while (mysqli_more_results($conn) && mysqli_next_result($conn)); } else { echo "Query failed: " . mysqli_error($conn); } mysqli_close($conn); ?>
现在我们再来尝试一下
可以看到他确实同时执行了两条sql语句,还挺好使哈,那么同样的会带来什么问题呢,这个堆叠注入已经是可以说直接忽略了对方前面写的查询了,一个分号结束后你后面想干啥就干啥,完全是没有限制,但是他的条件也是非常苛刻哈,我想应该没有砂纸会用这个函数去搭建项目吧
这个堆叠注入呢,简单来说就是要目标存在sql注入漏洞,然后还没有对分号过滤,其次就是看对方数据库是否支持多条语句操作,像MYSQL他就支持,还有什么MSSQL等等,所以说基本上也是用不到
这里找了一个靶场来演示一下
普通的提交就这个样子,既然是堆叠注入,我们就来尝试一下刚刚我们学到的
1';show databases;
尝试命令是否可用
既然可以执行命令,那我们现在就来查看表
看到了两个表,现在我们来查看表里的信息
查询发现他报错了,原来是他禁止了select的使用,那我们该怎么办呢
所以我们换一种查看的办法
通过show来同样查看字段名,现在我们看到了一个flag字段,所以现在来查看一下这个字段即可得出flag,但是前面我们知道不能直接用select,那现在该怎么办,当然是----
前面我们学过,如果过滤了引号该怎么办,当然是掏出16进制了,所以我们首先将语句转化成16进制前面加上0x
select flag from `1919810931114514` //原语句 0x73656c65637420666c61672066726f6d20603139313938313039333131313435313460 //加上0x的16进制语句
然后我们就要使用一个高端语句了
1';SET @a=0x73656c65637420666c61672066726f6d20603139313938313039333131313435313460; prepare execsql from @a; execute execsql;
这一段的意思就是
首先设置变量 @a
为一个十六进制的字符串:
然后将变量 @a
中的字符串作为一个 SQL 语句,预编译成可执行语句,句柄名为 execsql;
通过execute execsql;把前面的预编译语句执行,也就是等同于select flag from `191981093114514`;
现在我们来试试
记录咕噜一大堆,然后flag就出来咯,这道题的考点就是绕过过滤,通过预编译定义变量执行,好玩吧
还有一个带外注入,那个实在太鸡肋了,根本用不到,这里就不多说了
到这里这个扩展的也就差不都了哈,耶,是只是划过大脑的感jio