张小白的渗透之路(二)——SQL注入漏洞原理详解

SQL注入漏洞简介

乱七八糟的就不多说了,自己百度去

SQL注入原理

想要更好的学习SQL注入,那么我们就必须要深入的了解每种数据库的SQL语法及特性。下面通过一个经典的万能密码的例子带大家来拨开一下SQL注入漏洞的神秘面纱。本次环境为:DVWA的第一关(DVWA是一个渗透环境,可以用来当作学习渗透的靶机)。实验环境是PHP+MYSQL

如下图是一个正常登录的表单
张小白的渗透之路(二)——SQL注入漏洞原理详解_第1张图片
输入正确的密码后,php程序会查询数据库,如果存在此用户并且密码是正确的,那么登录肯定是成功的。用户不存在或者密码不正确,则会提示账号或者密码错误

登陆成功
张小白的渗透之路(二)——SQL注入漏洞原理详解_第2张图片
登录失败
张小白的渗透之路(二)——SQL注入漏洞原理详解_第3张图片
我们接下来使用一个比较特殊的用户“ admin’ or ‘1’='1 ”来登录,密码可以随意填写或者不填,在点击登录按钮之后发现是可以登录的。
结果如下
张小白的渗透之路(二)——SQL注入漏洞原理详解_第4张图片
那么问题到底出现在哪里呢?
我们通过查看源代码可以发现,登录处最终调用result来实现登录。
张小白的渗透之路(二)——SQL注入漏洞原理详解_第5张图片
上述SQL语句意思非常清楚:在获取到用户输入的username和password之后,和数据库进行比对。若返回结果==1,那么登陆成功。若返回其他值,那么登陆失败。
看起来这段代码是没有什么错误,现在我们提交账户admin,密码为password,再对应执行语句源代码,发现执行的SQL语句为

SELECT * FROM 'users' WHERE user = 'admin' AND password = 'password' 

在数据库中,存在admin用户,并且密码为password,所以此时返回结果为1,所以通过验证,用户可以成功登录。

接下来继续输入特殊用户admin’ or ‘1’='1 ,并对照执行语句,发现:

SELECT * FROM 'users' WHERE user = 'admin' or '1'='1' AND password = ''

终于找到问题的根源了
从开发人员的角度理解,SQL语句的本义是:
username=‘账户’ and password=‘密码’
现在却变为
username=‘账户’ or ‘1’=‘1’ and password=‘密码’
因为在SQL语句中and的优先级比or高,所以先运行’1’=‘1’ and password='密码’判断为假,然后因为username=‘admin’ or false为真,所以result=1即result=true顺利通过验证。
由此可见,SQL注入漏洞的形成原因就是:用户输入的数据被SQL解释器执行。

注入漏洞分类

在测试注入漏洞之前,我们首先要搞清楚注入有哪些分类,这样再去测试注入的时候就将会起到事半功倍的效果。
常见的SQL注入类型一般分为两大类:数字型和字符型。也有人分的更多,但不管注入的类型如何,攻击者的目标只有一个,就是绕过程序限制,使用户输入的数据带入数据库执行,利用数据库的特殊性获取更多的信息或者更大的权限。
数字型注入
当输入的参数为整型的时候,比如ID,年龄,页码等,如果存在注入漏洞,则可以认为是数字型注入,数字型注入是最为简单的一种。假设有URL为http://www.xxser.com/test.php?id=8,那么我们可以对SQL语句进行猜测。
测试步骤:

  • http://www.xxser.com/test.php?id=8'
    SQL语句为:select * from table where id=8',这样的语句肯定会出错,导致脚本程序无法从数据库中正常获取数据,从而使原来的页面出现异常。
  • http://www.xxser.com/test.php?id=8 and 1=1
    SQ语句为:select * from table where id =8 and 1=1,语句执行正常,返回的数据与原始请求无任何差异
  • http://www.xxser.com/test.php?id=8 and 1=2
    SQL语句为:select * from table where id=8 and 1=2语句执行正常,但是无法查询出数据,因为1=2始终为假,返回数据与原始请求有差异。
    如果以上三个步骤都满足,则程序就可能存在SQL注入漏洞。
    这种数字型的注入最多出现在ASP、PHP等弱类型的语言当中,因为弱类型的语言会自动推导出变量类型。打个比方,参数id=8,php会自动推导变量id的数据类型为int类型,那么id=8 and 1=1 则会推导为String类型,这就是弱类型语言的特性。而对于java、C#这些强类型的语言,如果试图把一个string转换为int类型,则会抛出异常,无法继续执行。所以,强类型二点语言很少存在数字型注入漏洞,强类型语言在这方面会比弱类型语言有优势。
    字符型注入
    当我们输入的参数是string类型时,称为字符型。数字型和字符型注入最大的区别在于:数字类型不需要单引号合并,而字符串类型一般需要使用单引号来闭合。
  • 数字型例句如下:
select * from table where id = 8
  • 字符型例句如下:
select * from table where username = 'admin'

字符型注入最关键的就是如何闭合SQL语句以及注释多余语句或者对SQL语句的执行进行逻辑上的更改。
当攻击者进行SQL注入时,如果输入 admin and 1=1 ,则无法进行注入。因为 admin and 1=1 会被数据库当作查询的字符串,SQL语句变为

select * from table where username = 'admin and 1=1'

这时候如果我们想要注入,那么就必须要注意字符串的闭合问题,输入admin’ and 1=1 - - 就可以继续注入,SQL语句如下

select * from table where username ='admin' and 1=1 - -'

只要是字符型的注入,都必须要闭合单引号以及注释多余的代码。

值得一提的SQL注入

通过翻阅大量的参考资料,张小白比较同意的一种观点是:SQL注入只分为数字型和字符型。
但是很多人可能要问了,那不是还有Cookie注入、POST注入、盲注、延时等注入吗?没错,但是大家可以仔细分析一下就会发现,这些类型的注入其实都是以上两大类二点不同展现形式或者不同的展现位置罢了。

那么怎么去理解上面这段话呢?
我们都知道,对数据库进行数据查询的时候,输入的数据一般只有两种;一个是数字类型,比如where id = 1、where age >20,另外一种是字符串类型,比如where name = ‘root’ 、where datetime > ‘2018-09-22’.
也许不同的数据库的比较方式不一样,但是代入数据库查询时一定是字符串(严格的说,数字也是字符串,在数据库当中进行数据查询时,where id ='1’也是合法的,只不过在查询条件为数字时一般不会加单引号)。所以,无论是POST注入还是其他类型的注入,都可以归纳为数字型或者字符型注入。

那么Cookie注入,POST注入等是怎么一回事呢?其实这类注入主要通过注入的位置来分辨,比如有以下请求

POST /user/login.php HTTP/1.1
Host:www.secbug.org
Proxy-Connection:keep-alive
Content-Length:53
Cache-Control:max-age=0
User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.17 (KHTML, like Gecko)
Chrom/24.0.1312.57 Safari/537.17 SE 2.X MetaSr 1.0
Content-type:application/x-www-form-urlencoded
Cookie:_jkb_10667=1

username=admin&password=123456

我想看了张小白的渗透之路(一)——HTTP详解的小伙伴一定能够很轻松的搞清楚上面这块代码想要表达什么意思。
我们可以看到此时呢为POST请求,但是POST数据中的username字段存在漏洞,一般就直接说POST注入,却不再考虑username是什么类型的注入
如果此时的HTTP请求如下:

GET /user/login.php?username=admin&password=123456 HTTP/1.1
Host:www.secbug.org
Proxy-Connection:keep-alive
Content-Length:53
Cache-Control:max-age=0
User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.17 (KHTML, like Gecko)
Chrom/24.0.1312.57 Safari/537.17 SE 2.X MetaSr 1.0
Content-type:application/x-www-form-urlencoded
Cookie:_jkb_10667=1

那么是不是应该又叫做GET注入呢?
下面呢是张小白整理的一些注入叫法,大家可以参考一下

  • POST注入:注入字段在POST数据中;
  • Cookie注入:注入字段在Cookie数据中;
  • 延时注入:使用数据库延时特性注入;
  • 搜索注入:注入处为搜索的地点;
  • base64注入:注入字符串需要经过base64加密;

对于SQL注入更加深入的了解,大家可以尝试在张小白的渗透之路(三)寻找到属于自己的答案

你可能感兴趣的:(渗透之路,渗透测试)