# 常用注释
#
: 注释#
至行尾--
: 注释--
至行尾(2 个-
跟上空格或一个其他字符)/**/
: 注释/*
至*/
之间的字符
# 寻找及确认 SQL 注入
'
和"
and
和or
# MySQL 基本函数
@@version
: 数据库版本@@basedir
: 数据库路径mid(str, pos, len)
和substring(str, pos, len)
: 对str
从pos
位置开始截取len
个字符concat(str1, str2)
: 连接两个字符串database()
: 当前数据库名length(str)
: 字符串长度user()
: 当前用户名sleep(second)
: 睡眠second
秒group_concat()
: 将一列值连接成字符串limit offset, count
: 显示从offset
开始的count
个结果
# 基于注入点值的属性
字符型需要闭合引号,数字型不需要
# 基于注入点的位置
注入点除了 GET 请求的参数及 POST 请求的 body 之外,也可能存在于 Cookie
或 Headers
中
# 基于注入的程度和顺序
- 一阶注入:注入语句直接对 Web 产生了影响
- 二阶注入:注入语句无法直接对 Web 产生影响,需要通过其他辅助间接产生危害
# 二阶注入示例
添加一个 admin'#
用户,登录该用户后修改密码,实际上能够修改 admin
的密码
修改该用户密码时的 SQL 语句如下
UPDATE users SET passwd="new_password" WHERE username='admin'#' AND password='old_password' |
实际上 #
后的字符都被注释了,相当于执行
UPDATE users SET passwd="new_password" WHERE username='admin' |
# 基于从服务器返回的响应
如果 Web 应用存在 SQL 注入,那么输入的 payload 总会导致响应上与正常的有所区别,可能体现在内容、长度、响应时间等方面
# 有回显
# 联合查询
UNION
关键字可以合并多条 SELECT
语句的查询结果,需要满足以下两个条件
- 查询语句的返回列数必须相同
- 查询语句返回的每列的数据类型必须相同
# 报错注入
页面会返回报错信息,可以将需要查询的结果放在报错信息里回显出来
# XPath 报错注入
涉及函数:
updatexml(XML_document, XPath_string, new_value)
: 更新 xmlextractvalue(XML_document, XPath_string)
: 查询 xml
XML_document
是 xml 文档对象名, XPath_string
是 XPath 路径, new_value
是需要替换的字符串
注入语句:
update(1, concat(0x7e, (select 查询语句), 0x7e), 1)
extractvalue(1, concat(0x7e, (select 查询语句), 0x7e))
# floor
+ group by
报错注入
SELECT count(*), (concat(floor(rand(0)*2), '@', (SELECT version())))x FROM users GROUP BY x |
floor(x)
返回小于等于 x
的最大整数
group by
语句会遍历某一列的值( group by
的 group_key
),将结果保存在临时表中:
- 当读取到某行的值不在临时表中,会插入一条数据
- 当读取到某行的值在临时表中,会更新临时表中的对应数据
group by floor(rand(0)*2)
中,由于 group_key
是随机数, group by
在检测临时表是否存在某个值和将值插入临时表的时候会分别执行 group_key
,因此有可能临时表中存在 1
, group by
检测时计算为 0
,而插入时计算为 1
的情况,最终导致插入主键重复的行而报错
# exp()
溢出报错注入
MySQL > 5.5.5
中,大于 709
的值传给 exp()
函数会引起溢出错误
# 堆叠注入
利用 ;
拼接多条 sql 语句
# 无回显
# 布尔盲注
页面的内容会改变,但不包含有用信息
涉及到的函数:
length()
: 字符串长度mid()
,substring()
: 取子字符串left()
,right()
: 取字符串的左 / 右n
个字符ord()
,ascii()
: 取字符 ASCII 值
# 延时盲注
不关注页面的返回内容,而关注页面的响应时间差
涉及到的函数:
sleep()
: 睡眠指定秒数benchmark(count, expr)
: 执行expr
count
次if(expr1, expr2, expr3)
: 相当于三元运算符,expr1
为真返回expr2
,为假返回expr3
WHEN condition THEN result1 ELSE result2
: 批量的三元运算符,如SELECT case WHEN age=19 THEN 'yes' ELSE 'no' FROM users
A regexp() B
: 正则表达式B
是否可以匹配A
# 特殊业务场景
# INSERT/UPDATE/DELETE 注入
注册、修改、删除信息时输入单引号返回异常信息,可能可以被利用
# LIKE 注入
%
闭合
# ORDER BY 注入
# 基于 IF
语句(数字型)
在知道列名 password
的情况下,使用 if(expr, id, password)
expr
为 True
按照 id
排序,为 False
按照 password
排序
不知道列名的情况下,使用类似 if(expr, 1, (SELECT id FROM information_schema.tables))
expr
为 True
时返回正常页面,为 False
时会报错
# 基于 rand()
盲注(数字型)
order by rand()
,排序结果可能不相同
# HTTP 参数污染
给同一个参数赋多个值,可能导致 Web 应用以意外的方式去解释这个参数
不同的程序组件对这类问题的处理方法也各不相同
# SQL 注入的读写
mysql.user
表中包含了数据库的用户信息,其中 file_priv
表示了用户是否可以读写外部文件
此外,全局变量 secure_file_priv
也对文件读写进行了限制:
- 值为
null
表示不允许导入导出 - 值为
/tmp
表示只能在/tmp
下进行导入导出 - 没有具体值则表示导入导出不受限制
通过 load_file(path)
函数读取文件, path
是绝对路径