概述
数据库注入漏洞,主要是开发人员在构建代码时, 没有对输入边界进行安全考虑,导致攻击者可以通过合法的输入点提交一些精心构造的语句,从而欺骗后台数据库对其进行执行,导致数据库信息泄漏的一-种漏洞。
在owasp发布的top10排行榜里,注入漏洞一直是危害排名第一的漏洞,其中注入漏洞里面首当其冲的就是数据库注入漏洞。
一个严重的SQL注入漏洞,可能会直接导致一家公司破产!
SQL注入漏洞主要形成的原因是在数据交互中,前端的数据传入到后台处理时,没有做严格的判断,导致其传入的“数据”拼接到SQL语句中后,被当作SQL语句的一部分执行。 从而导致数据库受损(被脱裤、被删除、甚至整个服务器权限沦陷)。
在构建代码时,一般会从如下几个方面的策略来防止SQL注入漏洞:
1.对传进SQL语句里面的变量进行过滤,不允许危险字符传入;
2.使用参数化(Parameterized Query 或 Parameterized Statement);
3.还有就是,目前有很多ORM框架会自动使用参数化解决注入问题,但其也提供了"拼接"的方式,所以使用时需要慎重!
SQL注入漏洞攻击流程
第一步:注入点探测
自动方式:通过web漏洞扫描工具,自动进行注入点发现
手动方式:手工构造sql inject测试语句进行注入点发现
第二步:信息获取
通过注入点取期望得到的数据
- 环境信息: 数据库类型,数据库版本、操作系统版本、用户信息等
- 数据库信息: 数据库名称、数据库表、表字段,字段内容(加密内容破解)
第三步:获取权限
获取操作系统权限:通过数据库执行shell,上传木马
SQL注入漏洞-常见注入点类型
- 数字型 user_id=$id
- 字符型 user_id='$id'
- 搜索型 text LIKE '%{$_GET[''search]}%'
本次实验在pikachu靶场进行演示!!
数字型注入(post)
点击pikachu页面中的查询,查询id都会得到相对应的信息
打开burp suite工具,点击抓取到的post请求,发送到Repeater
点击Repeater中的GO,打开右边的Response中的Render,可以看到得出的信息是和在pikachu里查询的信息是一样的
接下来进行测试看是否存在SQL漏洞,修改Request中的信息,把id=3修改为id=3 or 1=1,点击Go,可以看到获取了所有用户的信息,确定存在着一个数字型的SQL注入漏洞!
也可以在id=3后面加单引号,显示报错,说明存在SQL注入!
还有一种测试方法,通过数据库shell进行验证,在shell输入SQL语句,验证是否存在SQL注入漏洞。
输入正确的SQL语句,可以到对应的id信息
select username,email from member where id=1;
再次输入修改后的SQL语句,可以看到获取到了数据库表中的所有用户的信息,再次验证了存在着一个数字型的SQL漏洞!
select username,email from member where id=1 or 1=1;
查看pikachu的后端源码,看漏洞是如何形成的。可以看到id=$id是从前端获取并且没有经过任何处理直接放进去的,可以看到$id没有单引号或者双引号,说明它是个数字型变量,可以用相关的函数连接数据库执行SQL语句,这样就导致了$id可以被直接控制,并且可以通过拼接构造合法的SQL语句造成信息的泄漏。
字符型注入(get)
在pikachu页面中随便输入内容xxx,显示用户名不存在,输入一个正确的用户名时,则显示出这个用户名的信息
在数据库shell中尝试输入猜想的SQL语句,可以看到获取了用户的信息
select username,email from member where username='lucy';
接下来进行闭合测试,构造合法的payload,输入到pikachu页面当中,可以看到存在着一个SQL注入!
lucy' or 1=1#
也可以像数字型的验证方法一样,在页面中输入一个单引号,显示报错,说明存在着SQL注入!
查看一下后端源码,可以看到字符型和数字型差不多一样,区别就是username中添加了单引号,把它当成字符串去处理。
搜索型注入
搜索型就是当记不住用户名时,可以输入字符,它就会查询中这个字符的所有结果
在数据库的shell中也可以通过SQL语句,搜索输入字符的所有信息
select * from member where username like '%l%';
接下来通过这个payload,构造出合法的闭合,测试SQL注入漏洞
l%' or 1=1#
可以看到获取到了所有用户的信息,存在着一个SQL注入!
xx型注入
在pikachu页面中输入1加单引号,可以看到显示报错
查看一下后端源码,可以看到xx型相对于之前的类型,它是用一个括号来拼接前端获取的字符,所有我们可以在此基础上,通过构造一个合法的闭合来进行测试!
通过后端源代码猜想出一个合法的闭合('xxxx') or 1=1#'),选取其中需要测试的部分输入到pikachu当中
xxx') or 1=1#
提交后,可以看到页面遍历出了所有用户的信息
insert/update注入
insert注入
打开pikachu靶场,在insert/update登录页面点击注册,在用户栏中输入单引号,密码栏随便输入内容然后提交。
提交后,会看到显示报错,说明了提交的内容参与到了后台的拼接导致了一个语法的错误!
到数据库的shell进行操作,输入一条正常的信息插入到数据库中
insert into member(username,pw,sex,phonenum,email,address) values('xiaolan',2222,1,2,3,4); select * from member;
利用updatexml()报错函数构造一个合法的payload,进行SQL注入的测试!
insert into member(username,pw,sex,phonenum,email,address) values('1'or updatexml(1,concat(0x7e,version()),0) or'',2222,1,2,3,4);
可以看到通过构造一个合法的闭合,获取了数据库的版本信息!
也可以把payload输入到pikachu靶场注册页面的用户栏里,密码随便写,提交后会获取相对应的信息
update注入
update演示,先在靶场页面中登录,然后点击修改个人信息,把insert演示中的payload输入到任意一栏中,点击提交,就能获取到数据库的信息了。
1' or updatexml(1, concat( 0x7e,version()) ,0) or '
delete注入
打开pikachu靶场,可以看到页面是和存储型XSS是一样的,把留言列表下的记录删除
打开burp suite,点击抓取到的get请求,发送到Repeater
把id修改为通过查看后端源代码所得到的payload,因为参数是通过URL提交的,所以要对闭合代码进行URL编码
1 or updatexml(1, concat( 0x7e,version()) ,0)
提交后,请求发送成功,返回报错的信息
http header注入
概述
有些时候,后台开发人员为了验证客户端头信息(比如常用的cookie验证)或者通过http header头信息获取客户端的一些信息,比如useragent、accept字段等等。会对客户端的http header信息进行获取并使用SQL进行处理,如果此时没有足够的安全考虑,则可能会导致基于http header的SQL inject漏洞。
点击pikachu靶场的右上角提示,输入账号密码
登录成功后就会看到此页面的信息
打开burp suite,右击抓取到的get请求,发送到Repeater
打开Repeater,把User-Agent的信息修改为单引号,右边的Response会报错,说明存在着一个SQL注入!
输入payload进行测试,也就是把之前的闭合代码输入到User-Agent,就会获取到相应的信息
1' or updatexml(1, concat( 0x7e,version()) ,0) or '
还有一种方法是cookie测试,获取到cookie后到数据库拼接进行相关的操作,也有可能会产生SQL注入漏洞的。
首先要先把之前在User-Agent输入的payload删掉,然后在cookie的用户名admin后面加入单引号,运行后可以看到显示报错
接下来在cookie用户名中输入payload,可以看到报错显示数据库版本信息
1' and updatexml(1, concat( 0x7e,version()) ,0)#
盲注
概述
在有些情况下,后台使用了错误信息屏蔽方法(比如@)屏蔽了报错,此时无法在根据报错信息来进行注入的判断,这种情况下的注入,称为"盲注"。根据表现形式的不同,盲注又分为based Boolean和based time两种类型。
盲注(based boolean)
基于boolean的盲注主要表现症状:
- 没有报错信息
- 不管是正确的输入,还是错误的输入,都只显示两种情况(我们可以认为是0或者1)
- 在正确的输入下,输入and 1=1/and 1=2发现可以判断
在pikachu靶场,按照之前的逻辑不管是输入单引号还是和之前一样输入kobe‘ or 1=1#都显示错误,说明之前的测试方法在盲注中是没有效果的!
换种方法输入kobe' and 1=1#,才会显示出信息,说明存在着一个SQL注入!
先在数据库shell中输入payload查询ASCII码或者长度的判断
select ascii(substr(database(),1,1)); select length(database());
知道长度后,在pikachu靶场中输入payload,获取到了用户信息
kobe' and ascii(substr(database(),1,1))>7# kobe' and ascii(substr(database(),1,1))=112#
还有一种方法是更改database()函数来获取用户信息
kobe' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>7#
盲注(based time)
概述
如果说基于boolean的盲注在页面上还可以看到0 or 1的回县的话,那么基于time的盲注完全就啥都看不到了!
但还有一个条件,就是"时间",通过特定的输入,判断后台执行的时间,从而确认注入!
在pikachu靶场中,F12打开控制台,点击网络,在页面中输入payload,会看到页面暂停了5秒,说明了存在着一个基于time盲注的SQL注入!
kobe' and sleep(5)#
接下来输入一个payload来测试,这个payload是根据时间的延迟来判断的,用if判断,通过substr函数把数据库中的第一个字符跟‘p’进行比较,如果相等则暂停5秒钟
kobe' and if((substr(database( ),1,1))= 'p' ,sleep(5),null)#
宽字节注入
因为在宽字节中,单引号会被转义为斜杠"\",这样会无法构造一个SQL语句。可以通过在单引号前面加" %df ",来让单引号逃过转义。
通过burp suite抓包,发送到Repeater,输入payload到name中
1%df' or 1=1#
点击Render可以看到获取了用户的信息
SQL注入漏洞的防范
- 代码层面
- 对输入进行严格的转义和过滤
- 使用预处理和参数化(parameterized)
- 网路层面
- 通过WAF设备启动防SQL inject注入策略(或类似防护系统)
- 云端防护(360网站卫士,阿里云盾等)
总结
不管是啥型,总而言之,就是对SQL中的各种类型的输入进行闭合测试,构成合法SQL,从而去欺骗后台执行!