攻击数据存储区
几乎所有的应用程序都依赖数据存储区来管理应用程序中处理的数据。
大多数数据存储区都保存有结构化、可以使用预测先定义的查询格式或语言访问的数据,并包含内部逻辑来管理这些数据。
如果攻击者能够破坏应用程序与数据存储的交互,使应用程序检索或修改各种数据,那么攻击者就可以避开应用层对数据访问实施的任何控制。
迄今为止,最常用的数据存储区是SQL数据库、基于XML的资料数据库、LDAP目录、一些常见示例。
注入解释型语言(interpreted language)
是一种在运行时由一个运行时组件(runtime component)解释语言代码并执行其中包含的指令的语言。
编译型语言(compiled language)
代码在生成时转换成机器指令,然后再运行时直接由使用该语言的计算机处理执行这些指令。
注释:
理论上任何语言都可以使用编译器或解释器来执行。这种区别并不是语言本身的内在特性。通常大多数语言只执行其中的一种方式。开发web应用程序使用的许多核心语言都是解释器执行。SQL、LDAP、Perl和PHP。
代码注入
任何有实际用途的应用程序都会收到用户提交的数据,对其进行处理并执行相应的操作。解释器处理的数据实际上是由程序员编写的代码和用户提交的数据组成。
代码注入的方式
1。使用解释型语言语法的具有特殊意义的句法,向应用程序攻击
2。注入机器代码而不是相应语言编写的指令。
避开登陆:Web应用程序对数据存储实施自主访问控制,构造查询基于用户的帐户和类型来检索添加或修改数据存储区中的数据。
Eg:SQL中知道管理员的帐户名
SELECT * FROM users WHERE username = ‘admin’—’ AND password=’foo’
其中(- -)是注释符号上面的语句等同于
SELECT * FROM users WHERE username=’admin’ 避开了密码检查
在大多数应用程序中,数据库的第一个账户为管理用户,因为这个账户通常手工创建,然后再通过它生成其他应用程序帐户。如果查询返回几个用户的资料,许多应用程序只会处理第一名用户
Eg:以数据库中的第一个用户身份登陆
OR 1=1 - -
执行下语句:
SELECT * FROM users WHERE username= ‘’ OR 1=1 - - AND password = ‘foo’
上语句等同于
SELECT * FROM users WHERE username=’’ OR 1=1
提示:有时候可以不使用注释符号处理字符串末尾部分的引号,而用引号包含的字符串数据结束注入的输入,“平衡引号”
Eg:SELECT author,title,year FROM books WHERE publisher = ‘Wiley’ OR ‘a’=’a’ and published=1 效果和 1=1相同
注入不同的语句类型
SELECT语句
最常用的语句,SQL注入攻击的进入点(entry point)通常是查询中的where子句,将用于提交的数据传送给数据库,以控制查询结果的范围。因为WHERE子句一般在SELECT语句的最后,攻击者可以使用注释符号将查询截断到其输入的结束位置,而不使整个查询语法失效。
SQL注入漏洞偶尔会影响SELECT查询的其他部分,如ORDER BY子句或表和列名称。
INSERT语句
INSERT语句用于在表中建立一个新的数据行。应用程序通常使用这种语句添加一条新的审计日志、创建一个新用户帐户或生成一个新订单。
Eg:如果username或password字段存在SQL漏洞,那么就可以在表中插入任何数据,包括自己的ID和privs值。
注意:必须确保VALUES子句的其他部分正常运行,特别是其中数据向的个数与类型必须正确。由于大多数的数据库都会隐式地将一个整数转换成一个字符串,因此可以在每一个位置都使用一个整数。
UPDATE语句
用于修改表中的一行或几行数据,运行机制和INSERT语句类似,只是UPDATE语句通常包含一个WHERE子句,告诉数据库更新表中那些行的数据
Eg:用户修改密码执行下面语句
UPDATE users SET password=’newsecret’ WHERE user=’marcus’ and password=’secret
注意:由于无法提前知道应用程序将根据专门设计的输入执行什么擦左,因此在一个远程应用程序中探查SQL注入漏洞往往非常危险。特别注意:修改UPDATE语句中的WHERE子句可能会使一个重要的数据库表发生彻底改变。
例如:UPDATE users SET password=’newsecret’ WHERE user=’admin’ or 1=1 它会重置每一个用户的密码。有时候,在用户成功登陆后,应用程序会使用用户提交的用户名执行各种UPDATE查询,这意味着任何针对WHERE子句的攻击可能会复制到其它语句中,给所有应用程序用户的资料造成严重破坏。
为规避风险,在开始测试前进行数据库备份非常重要
DELETE语句
用于删除表中的一行或几行数。与UPDATE语句一样,通常使用WHERE子句告诉数据库更新表中那行数据,并可能在这个子句中并入用户提交的数据
注入符号HTTP中的URL编码
1.&和=用于连接名/值对,建立查询字符串和POST数据块 & %26 = %3d
2.查询字符串不允许使用空格,如果使用空格整个字符串会立即中止。必须使用 + 或 %20对其编码
3.由于 + 用于编码空格,如果想在字符串中使用 + ,必须使用 %2b 对其编码
4.分号用于分割cookie字段,必须使用 %3b 对其编码
注入查询结构
如果用户提交的数据被插入SQL查询结构,而不是查询中的数据项,这时实施SQL注入攻击只需要直接应用有效的SQL语法,而不需要进行任何转义。
SQL查询结构中最常见的注入点是ORDER BY子句。
ORDER BY关键字接受某个列名或编号,并根据该列中的值对结果集进行排序。
“特征”识别数据库
一种最靠谱的方法:根据数据库联接字符串的不同方法进行识别。在控制某个字符串数据项的查询中,可以在一个请求中提交一个特殊值,然后测试这个连接方法,以生成那个字符串。如果得到相同的结果,就可以确定所使用的数据库类型。
Eg:数据库如何构建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() |
在识别数据库时,MySQL如何处理某些行内注释(inline comment)也是一个值得关注的问题:
如果一个注释以 ! 开头,接着是数据库版本字符串,那么只要数据的实际版本等于或高于该字符串,应用程序就会将注释内容解释为SQL;否则,应用程序就会忽略注释内容,将它作为注释处理。
Eg:/* !32302 and 1=0 */ 如果MySQL版本高于或等于 3.23.02,注入下面的字符串将使SELECT语句和WHERE子句为假
查找SQL注入漏洞
最简单的情况是,向应用输入一个意外输入,就可以发现并最终确定一个SQL注入漏洞。
复杂,通过检查提交给服务器和返回的任何数据包,检查数据错误信息。
注意:在探查SQL注入漏洞时,一定要确保完全遍历任何可以提交专门设计的输入的多阶段过程。程序通常会从几个请求中收集数据,一旦收集到全部数据,就将其请求保存在数据库中。如果仅在每个请求中提交专门设计的数据并监控应用,对数据的响应,就会遗漏许多SQL注入漏洞。
UNION操作符
将两个或几个SELECT语句的结果组合到一个独立的结果中。如果Web应用程序的SELECT语句存在SQL注入漏洞,通常可以使用UNION操作符执行另一次完全独立的查询,并将它的结果与第一次的结果组合在一起。
使用UNION操作符注入另外一个SELECT查询,并将查询结果附加在第一次查询结果之后,第二次查询能够从另外一个完全不同的数据库表中提取数据。
UNION的两个限制
1。使用UNION操作符组合两个查询结果,这两个结果必须结构相同。他们的列数必须使用按相同顺序出现的相同或兼容的数据类型。
2。为注入另一个返回有用结果的查询,攻击者必须知道他所针对的数据库表的名称以及有关列的名称
查明第一个查询的结构
1。第二个查询中每种数据要么必须与第一个查询中的对应类型完全相同,要么必须隐含的转换成任何数据类型。如果不知道1某个特殊字段的数据类型,只需要在那个字段输入SELECT NULL即可
2。如果数据库返回的错误信息被应用程序截获,还是可以轻易确定注入的查询是否得以执行。
3。很多时候,只需要在第一个查询中确定一个使用字符串数据类型的字段就可以达到查询的目的。