安全测试回顾(四)

SQL注入

几乎每一个web应用都需要使用数据库来保存操作所需的各种信息,所以web程序经常会建立用户提交的数据的SQL语句。如果,建立这种语句的方法不安全,那么应用程序就很容易受到SQL注入的攻击。最严重的情况下,攻击者可利用SQL注入读取甚至修改数据库中保存的所有数据。

由于互联网行业的入门门槛不高,程序员的水平及经验也参差不齐,相当大一部分程序员在编写代码的时候,没有对用户输入数据的合法性进行判断,使应用程序存在安全隐患。用户可以提交一段数据库查询代码,根据程序返回的结果,获得某些他想得知的数据,这就是所谓的SQL Injection,即SQL注入。

SQL注入是从正常的WWW端口访问,而且表面看起来跟一般的Web页面访问没什么区别,所以目前市面的防火墙都不会对SQL注入发出警报,如果管理员没查看IIS日志的习惯,可能被入侵很长时间都不会发觉。

恶意输入用户名:Username = ‘’or’1=1’ 和恶意输入密码 Password = ‘’or’1’=‘1’
得到的SQL会被篡改为:
SELECT id FROM Users WHERE Username = ‘’or’1=1’ AND Password = ‘’or’1’=‘1’
对于SQL解析器来说,这是一个可以正确解析并且可以被执行的SQL语句,它的结果等效为 SELECT id FROM Users 只要数据库里有数据,那么该语句就能够获取user表中每条记录,一般应用程序会选择返回第一个记录作为登录的用户,而很多系统第一个用户为管理员,情况就变得更加糟糕。

我们知道mysql代码的注释是使用 --来表示的,所以可以:

SELECT id FROM Users WHERE Username = ‘’or’1’=‘1’ ;drop table users;--’AND Password = ‘’
红色部分为我们的输入,这样我们注入的SQL仍能被正确解析,甚至可以导致users表被删除(如果有删除表权限的话);如果没有删除表的权限,那么也可以尝试用delete from user来代替drop table users。

 

注入的危害:
•1. 探知数据库的具体结构,为进一步攻击做准备
•2. 泄露数据,尤其是机密信息、账户信息等
•3. 取得更高权限,来修改表数据甚至是内部结构

 

SQL注入—简单可注入点判断

三步法:

如有一个url为:http://www.sample.com/test.asp?id=1可正常运行。测试步骤如下:
http://www.sample.com/test.asp?id=1’,如果提交的SQL语句变成 SELECT * from table where id=1’,那么页面返回异常;
http://www.sample.com/test.asp?id=1 and 1=1,页面运行正常且页面与http://www.sample.com/test.asp?id=1完全相同;
http://www.sample.com/test.asp?id=1 and 1=2,运行出现异常或页面与http://www.sample.com/test.asp?id=1不同,提示BOF或EOF(程序没做任何判断时)、或提示找不到记录(判断了rs.eof时)、或显示内容为空(程序加了on error resume next)
如果上面3步全满足,则一定存在SQL注入漏洞。

不可以注入就比较容易判断了,一般都会有程序定义的错误提示,或提示类型转换时出错。

当然,这只是传入参数是数字型的时候用的判断方法,实际应用的时候会有字符型和搜索型参数。需要有意识的进行分析,得出相应的注入测试语句。

根据注入参数类型,在脑海中重构SQL语句的原貌,按参数类型主要分为下面三种:
(A) ID=49 这类注入的参数是数字型,SQL语句原貌大致如下:
Select * from 表名 where 字段=49
注入的参数为ID=49 And [查询条件],即是生成语句:
Select * from 表名 where 字段=49 And [查询条件]
(B) Class=连续剧 这类注入的参数是字符型,SQL语句原貌大致概如下:
Select * from 表名 where 字段=’连续剧’
注入的参数为Class=连续剧’ and [查询条件] and ‘’=’ ,即是生成语句:
Select * from 表名 where 字段=’连续剧’ and [查询条件] and ‘’=’’
(C) 搜索时没过滤参数的,如keyword=关键字,SQL语句原貌大致如下:
Select * from 表名 where 字段like ’%关键字%’
注入的参数为keyword=’ and [查询条件] and ‘%25’=’, 即是生成语句:
Select * from 表名 where字段like ’%’ and [查询条件] and ‘%’=’%’

确定了SQL注入漏洞确实存在,作为测试人员,我们已经可以将这个漏洞报给开发人员进行修复了。

 

避免sql注入的方法:

1.针对输入值过滤

Select update delete drop insert  ‘ ()  and  or  =  ! , <>等过滤掉

2.参数化查询

Sql语句预处理

// 定义查询结构
String query = “SELECT username , role FROM USER WHERE username= ? And password =?”;
//预处理
stm= con.prepareStatement(query);
//将用户输入添加到第一个占位符?
stm.setString(1, request.getParameter(“name”));
Stm.setString(2, request.getParameter(“password”));
rs=stm.executeQuery;

 

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

攻击方面:

将查询条件替换成SQL语句,猜解表名,例如:
•And 1=1
•ID=49 And (Select Count(*) from Admin)>=0
•如果页面就与ID=49的相同,说明附加条件成立,即表Admin存在,反之,即不存在(请牢记这种方法)。如此循环,直至猜到表名为止。
•表名猜出来后,将Count(*)替换成Count(字段名),用同样的原理猜解字段名。
•有人会说:这里有一些偶然的成分,如果表名起得很复杂没规律的,那根本就没得玩下去了。说得很对,这世界根本就不存在100%成功的黑客技术,苍蝇不叮无缝的蛋,无论多技术多高深的黑客,都是因为别人的程序写得不严密或使用者保密意识不够,才有得下手。

SQL注入—破解字段值

在表名和列名猜解成功后,再使用SQL语句,得出字段的值,下面介绍一种最常用的方法-Ascii逐字解码法,虽然这种方法速度很慢,但肯定是可行的方法。
•我们举个例子,已知表Admin中存在username字段,首先,我们取第一条记录,测试长度:
•http://www.sample.com/showdetail.asp?id=1 and (select top 1 len(username) from Admin)>0
•先说明原理:如果top 1的username长度大于0,则条件成立;接着就是>1、>2、>3这样测试下去,一直到条件不成立为止,比如>7成立,>8不成立,就是len(username)=8
•当然没人会笨得从0,1,2,3一个个测试,怎么样才比较快就看各自发挥了。在得到username的长度后,用mid(username,N,1)截取第N位字符,再asc(mid(username,N,1))得到ASCII码,比如:
•id=1 and (select top 1 asc(mid(username,1,1)) from Admin)>0
•同样也是用逐步缩小范围的方法得到第1位字符的ASCII码,注意的是英文和数字的ASCII码在1-128之间,可以用折半法加速猜解,可以用Burp进行测试,效率会有极大的提高。

SQL注入—避开过滤

有时候,开发人员会有意识的执行某种输入过滤以防止攻击者输入如’、selecet等字符;
•1. 使用ASCII码动态构建替代,如在输入中,单引号被屏蔽,我们可以尝试使用字符的ASCII码代替,CHAR(39)。
•2. 如果select关键字被屏蔽,尝试使用URL hex编码:
•%00SELECT
•%53%45%4c%45%43%54

SQL注入—经验小结

1.有些人会过滤Select、Update、Delete这些关键字,但偏偏忘记区分大小写,所以大家可以用selecT这样尝试一下。
•2.在猜不到字段名时,不妨看看网站上的表单,一般为了方便起见,字段名都与表单的输入框取相同的名字。
•3.特别注意:http请求的+号传入程序后解释为空格,%2B解释为+号,%25解释为%号
•4.用Get方法注入时,IIS、apache等或者服务器会记录你所有的提交字符串,对Post方法做则不记录,所以能用Post的网址尽量不用Get。

•5. 一种实用的注入方法:
•(对于SQLSERVER数据库)
http://www.sample.com/test.asp?id=1 and user>0
这句语句包含了SQLServer特有注入方法的精髓。user是SQLServer的一个内置变量,它的值是当前连接的用户名,类型为nvarchar。一个nvarchar数据类型的值跟 int的数值0比较,系统会先试图将nvarchar的值转成int型,转的过程中就会出错,SQLServer的出错提示是:将nvarchar值 ”test” 转换数据类型为 int 的列时发生语法错误,这样test正是变量user的值,成功拿到了数据库的用户名。

 

posted @ 2017-12-27 10:23  明镜止水丨  阅读(161)  评论(0编辑  收藏  举报