我要投搞

标签云

收藏小站

爱尚经典语录、名言、句子、散文、日志、唯美图片

当前位置:王中王 > 定界符 >

SQLServer应用程序中的高级SQL注入

归档日期:04-30       文本归类:定界符      文章编辑:爱尚语录

  SQL是一种用于关系数据库的结构化查询语言。它分为许多种,但大多数都松散地基于美国国家标准化组织最新的标准SQL-92。典型的执行语句是query,它能够收集比较有达标性的记录并返回一个单一的结果集。SQL语言可以修改数据库结构(数据定义语言)和操作数据库内容(数据操作语言)。在这份文档中,我们将特别讨论SQLSERVER所使用的Transact-SQL语言。

  当一个攻击者能够通过往query中插入一系列的sql语句来操作数据写入到应用程序中去,我们管这种方法定义成SQL注入。

  这条语句将返回authors表中所有行的id,forename和surname列。这个结果可以被限制,例如:

  需要着重指明的是字符串john和smith被单引号限制。明确的说,forename和surname字段是被用户提供的输入限制的,攻击者可以通过输入值来往这个查询中注入一些SQL语句,

  造成这种结果的原因是插入了.作为定界符的单引号。数据库尝试去执行hn,但是失败。如果攻击者提供特别的输入如:

  看上去好象通过从输入中去掉单引号或者通过某些方法避免它们都可以解决这个问题。这是可行的,但是用这种方法做解决方法会存在几个困难。第一,并不是所有用户提供的数据都是字符串。如果用户输入的是通过用户id来查询author,那我们的查询应该像这样:

  在这种情况下,一个攻击者可以非常简单地在数字的结尾添加SQL语句,在其他版本的SQL语言中,使用各种各样的限定符号;在数据库管理系统JET引擎中,数据可以被使用#限定。第二,避免单引号尽管看上去可以,但是是没必要的,原因我们稍后再讲。

  我们更进一步地使用一个简单的ASP登陆页面来指出哪些能进入SQLSERVER数据库并且尝试鉴别进入一些虚构的应用程序的权限。

  数据库中表users将被删除,拒绝任何用户进入应用程序。符号在Transact-SQL中表示忽略以后的语句,;符号表示一个查询的结束和另一个查询的开始。位于username字段中是必须的,它为了使这个特殊的查询终止,并且不返回错误。

  攻击者可以只需提供他们知道的用户名,就可以以任何用户登陆,使用如下输入:

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

  为了操作数据库中的数据,攻击者必须确定某些数据库和某些表的结构。例如我们可以使用如下语句创建user表:

  如果我们的攻击者想插入一个自己的用户。在不知道users表结构的情况下,他不可能成功。即使他比较幸运,至于privs字段不清楚。攻击者可能插入一个1,这样只给他自己一个低权限的用户。

  幸运地,如果从应用程序(默认为ASP行为)返回错误消息,那么攻击者可以确定整个数据库的结构,并且可以以程序中连接SQLSERVER的权限度曲任何值。

  首先,攻击者想获得建立用户的表的名字和字段的名字,要做这些,攻击者需要使用select语法的having子句:

  因此现在攻击者知道了表的名字和第一个地段的名字。他们仍然可以通过把字段放到groupby子句只能感去找到一个一个字段名,如下:

  这利用了SQLSERVER在确定两个结果集的字段是否相等前应用sum子句。尝试去计算sum会得到以下消息:

  这告诉了我们username字段的类型是varchar。如果是另一种情况,我们尝试去计算sum()的是数字类型,我们得到的错误消息告诉我们两个集合的字段数量不相等。

  这种技术的潜在影响不仅仅是这些。攻击者可以利用这些错误消息显示环境信息或数据库。通过运行一列一定格式的字符串可以获得标准的错误消息:

  一个特别有用的消息关系到类型转化。如果你尝试将一个字符串转化成一个整型数字,那么字符串的所有内容会返回到错误消息中。例如在我们简单的登陆页面中,在username后面会显示出SQLSERVER的版本和所运行的操作系统信息:

  这句尝试去将内置的version常量转化成一个整型数字,因为users表中的第一列是整型数字。

  这种技术可以用来读取数据库中任何表的任何值。自从攻击者对用户名和用户密码比较感兴趣后,他们比较喜欢去从users表中读取用户名,例如:

  这句选择users表中username大于a中的最小值,并试图把它转化成一个整型数字:

  因此攻击者已经知道用户admin是存在的。这样他就可以重复通过使用where子句和查询到的用户名去寻找下一个用户。

  一个更高级的技术是将所有用户名和密码连接长一个单独的字符串,然后尝试把它转化成整型数字。这个例子指出:Transavt-SQL语法能够在不改变相同的行的意思的情况下把它们连接起来。下面的脚本将把值连接起来:

  这就创建了一个foo表,里面只有一个单独的列ret,里面存放着我们得到的用户名和密码的字符串。正常情况下,一个低权限的用户能够在同一个数据库中创建表,或者创建临时数据库。

  这个例子仅仅是这种技术的一个表面的作用。没必要说,如果攻击者能够从数据库中获得足够的错误西,他们的工作就变的无限简单。

  一旦攻击者控制了数据库,他们就想利用那个权限去获得网络上更高的控制权。这可以通过许多途径来达到:

  1.在数据库服务器上,以SQLSERVER权限利用xp_cmdshell扩展存储过程执行命令。

  2.利用xp_regread扩展存储过程去读注册表的键值,当然包括SAM键(前提是SQLSERVER是以系统权限运行的)

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

  许多存储过程被创建在SQLSERVER中,执行各种各样的功能,例如发送电子邮件和与注册表交互。

  Xp_cmdshell是一个允许执行任意的命令行命令的内置的存储过程。例如:

  将提供服务器上所有用户的列表。当SQLSERVER正常以系统帐户或域帐户运行时,攻击者可以做出更严重的危害。

  这将显示服务器上所有SNMP团体配置。在SNMP团体很少被更改和在许多主机间共享的情况下,有了这些信息,攻击者或许会重新配置同一网络中的网络设备。

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

  xp_servicecontrol过程允许用户启动,停止,暂停和继续服务:

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

  扩展存储过程应用程序接口是相当简单的,创建一个携带恶意代码的扩展存储过程动态连接库是一个相当简单的任务。使用命令行有几个方法可以上传动态连接库到SQL服务器上,还有其它包括了多种自动通讯的通讯机制,比如HTTP下载和FTP脚本。

  一旦动态连接库文件在机器上运行即SQL服务器能够被访问这不需要它自己是SQL服务器攻击者就能够使用下面的命令添加扩展存储过程(这种情况下,我们的恶意存储过程就是一个能输出服务器的系统文件的小的木马):

  使用bulkinsert语法可以将一个文本文件插入到一个临时表中。简单地创建这个表:

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

  使用bulkinsert的相对技术可以很容易建立任意的文本文件。不幸的是这需要命令行工具。bcp,即bulkcopyprogram

  既然bcp可以从SQL服务进程外访问数据库,它需要登陆。这代表获得权限不是很困难,既然攻击者能建立,或者利用整体安全机制(如果服务器配置成可以使用它)。

  S参数为执行查询的服务器,U参数为用户名,P参数为密码,这里为foobar

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

  (1)这个例子使用wscript.shell对象建立了一个记事本的实例:

  需要指出的是如果运行的环境是WINNT4+IIS4平台上,那么通过这个程序运行的命令是以系统权限运行的。在IIS5中,它以一个比较低的权限IWAM_XXXaccount运行。

  我们可以在我们假定的例子中,通过指定在用户名后面来执行它(注意这个例子不仅仅是注入一个脚本,同时以admin权限登陆到应用程序):

  传说如果一个ASP应用程序在数据库中使用了存储过程,那么SQL注入是不可能的。这句话只对了一半,这要看ASP脚本中调用这个存储过程的方式。

  本质上,如果一个有参数的查询被执行,并且用户提供的参数通过安全检查才放入到查询中,那么SQL注入明显是不可能发生的。但是如果攻击者努力影响所执行查询语句的非数据部分,这样他们就可能能够控制数据库。

  ?如果一个ASP脚本能够产生一个被提交的SQL查询字符串,即使它使用了存储过程也是能够引起SQL注入的弱点。

  ?如果一个ASP脚本使用一个过程对象限制参数的往存储过程中分配(例如ADO的用于参数收集的command对象),那么通过这个对象的执行,它一般是安全的。

  明显地,既然新的攻击技术始终地被发现,好的惯例仍然是验证用户所有的输入。

  通常情况下,一个web应用程序将会过滤单引号(或其他符号),或者限定用户提交的数据的长度。

  在这部分,我们讨论一些能帮助攻击者饶过那些明显防范SQL注入,躲避被记录的技术。

  有时候开发人员会通过过滤所有的单引号来保护应用程序,他们可能使用VBScript中的replace函数或类似:

  无可否认地这防止了我们所有例子的攻击,再除去;符号也可以帮很多忙。但是在一个大型的应用程序中,好象个别值期望用户输入的是数字。这些值没有被限定,因此为攻击者提供了一个SQL注入的弱点。

  如果攻击者想不使用单引号产生一个字符串值,他可以使用char函数,例如:

  淡然,如果攻击者不介意使用一个数字用户名和密码,下面的语句也同样会起作用:

  即使应用程序总是过滤单引号,攻击者依然能够注入SQL同样通过应用程序使数据库中的数据重复使用。

  我们假设应用程序允许用户修改自己的密码。这个ASP脚本程序首先保证用户设置新密码前拥有正确的旧密码。代码如下:

  这样攻击者可以通过注册一个admin的用户来根据自己的想法来设置admin的密码。

  这是一个非常严重的问题,目前在大型的应用程序中试图去过滤数据。最好的解决方法是拒绝非法输入,这胜于简单地努力去修改它。这有时会导致一个问题,非法的字符在那里是必要的,例如在用户名中包含符号,例如

  从一个安全的观点来看,最好的解答是但引号不允许存在是一个简单的事实。如果这是无法接受的话,他们仍然要被过滤;在这种情况下,保证所有进入SQL查询的数据都是正确的是最好的方法。

  如果攻击者不使用任何应用程序莫名其妙地往系统中插入数据,这种方式的攻击也是可能的。应用程序可能有email接口,或者可能在数据库中可以存储错误日志,这样攻击者可以努力控制它。验证所有数据,包括数据库中已经存在的数据始终是个好的方法。确认函数将被简单地调用,例如:

  为了给攻击者更多的困难,有时输入数据的长度是被限制的。当这个阻碍了攻击时,一个小的SQL可以造成很严重的危害。例如:

  如果限定长度是在过滤字符串后应用将会引发另一个问题。假设用户名被限定16个字符,密码也被限定16个字符,那么下面的用户名和密码结合将会执行上面提到的shutdown命令:

  原因是应用程序尝试去过滤用户名最后的单引号,但是字符串被切断成16个字符,删除了过滤后的一个单引号。这样的结果就是如果密码字段以单引号开始,它可以包含一些SQL语句。既然这样查询看上去是:

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

  这种行为发生在所有的T-SQL日记记录中,即使sp_password发生在一个注释中。这个过程打算通过sp_password隐藏用户的密码,但这对于一个攻击者来说是非常有用的方法。

  因此,为了隐藏所有注入,攻击者需要简单地在注释字符后追加sp_password,例如:

  这部分讨论针对记述的攻击的一些防范。我们将讨论输入确认和提供一些简单的代码,然后我们将从事SQLSERVER锁定。

  输入验证是一个复杂的题目。比较有代表性的是,自从过于严密地确认倾向于引起部分应用程序的暂停,输入确认问题很难被解决,在项目开发中投入很少的注意力在输入确认上。输入确认不是倾向于将它加入到应用程序的功能当中,因此它一般会被忽视。

  下面是一个含有简单代码的讨论输入确认的大纲。这个简单的代码不能直接用于应用程序中,但是它十分清晰地阐明了不同的策略。

  第一种情况有一些概念上的问题;首先,开发人员没必要知道那些是错误数据,因为新的错误数据的形式始终被发现。其次,修改数据会引起上面描述过的数据的长度问题。最后,二次使用的问题包括系统中已经存在数据的重新使用。

  第二种情况也存在第一种情况中的问题;已知的错误输入随着攻击技术的发展变化。

  从安全角度看合并第二种方法和第三种方法可能是最好的方法只允许正确的输入,然后搜索输入中已知的错误数据。

  我们必须在正确输入中允许连接符号,但是我们也意识到字符序列对SQLSERVER很重要。

  当合并修改数据和字符序列确认时,会出现另一个问题。例如,如果我们应用一个错误过滤在除去单引号之后去探测,select和union,攻击者可以输入:

  既然单引号被除去,攻击者可以简单地散布单引号在自己的错误的字符串中躲避被发现。

  在这指出的重要一点是锁定SQLSERVER是必要的;外面的是不安全的。这是一个但创建SQLSERVER时需要做的事情的简短的列表:

  a.许多扩展存储过程能被安全地移除。如果这样做了,应该移除包含在扩展存储过程代码中的.dll文件

  a.应用程序进入数据库所使用的帐户应该有保证能够使用它需要的对象的最小权限

  a.针对SQLSERVER有一些缓冲区溢出和格式化字符串攻击,也有一些其他的安全补丁发布。应该存在很多。

本文链接:http://brazil-run.com/dingjiefu/206.html