本文是《Web攻击流量分析》系列的第二篇文章,上篇文章让安全处置更高效的“数据流分析”,助你洞察攻击流量交互向大家介绍了科来CSNA系统中,针对网络攻击流量的数据流分析研判方法。本文继续上篇文章的话题,继续和大家探讨关于Web攻击流量中常见的SQL注入攻击流量分析研判方法。
什么是SQL注入?
SQL注入是一种常见的网络安全攻击手段,攻击者通过在Web应用的输入字段中输入SQL代码,欺骗数据库执行“意料之外”的SQL查询,从而实现获取系统数据、绕过身份验证、篡改或删除数据、权限提升、执行系统命令、导致系统服务中断等结果。
注入攻击的本质是将用户输入的数据当作代码来执行。下面是一个SQL注入的举例:
某程序员设计了网站中的一个功能模块,用于输入年龄查询人数,例如大于25岁有XX人,后台代码是这样的:
SELECT name, age, location FROM Users WHERE age>
当用户输入25后,用户输入的25能够和后台原有的语句进行拼接,组成完整SQL语句,执行“查询当前年龄大于25的人数”这一功能:
SELECT name, age, location FROM Users WHERE age>25
假如用户输入的内容是100000 union select name, age, password from users呢?这时候网站后台执行的语句就变成了:
SELECT name, age, location FROM Users WHERE age>999 union select name, age, password from users
>999是不可能符合的条件,Union语法要求前后两句SQL中Select的数据项类型和数量一致。这样查询的结果就只剩第二句sql查询的内容,所有的数据都随着攻击者拼接的select name,age,password from users被泄露出去了。形成暴库攻击,Union暴库是常见的注入方法。
如何识别SQL注入流量?
要进行攻击,首先需明确SQL注入点的类型,常见SQL注入流量探测字符为:
单引号、等号、and、or、加减号、百分号、注释符
流量分析工程师需要警惕用户输入的字符部分出现上述字符,以及上述字符的URL编码以及其它编码变形。

图1 SQL注入探测
如图1所示,攻击者在网站输入了1’ or ‘1=1。判定确实为SQL注入探测流量。在分析研判流量时,看到%27、1、or、%3D这样的字符需要多加留意。
注入攻击成功了吗?
发现攻击后,我们最关心的问题就是“攻击成功了吗”?刚才那条SQL注入探测结果如何?此时需要在数据流中观察刚才会话的服务器返回结果,先观察响应头初步判断,再以响应体内容明确攻击是否成功。如图2所示:

图2 服务器针对注入探测的响应头
首先,响应头结果为HTTP 200 OK,这个响应代码表示服务器响应成功,但响应成功不代表刚才的攻击成功。在一些网络中,WAF系统可能通过HTTP 200 OK发送拦截页面。继续观察这条响应的响应体,如图3所示:

图3 服务器针对注入探测的响应体(部分截取)
响应体中,服务器泄露了admin admin、Gordon Brown、Hack Me、Pablo Picasso、Bob Smith这五个姓名信息,因此判断SQL注入探测成功。
完整的SQL注入流程包含哪些操作?
基于前文所述,攻击者已经确认了SQL注入点。作为攻击者,接下来将思考如何利用此漏洞获取更多信息。
首先是猜测当前网站后台数据库表的字段列数,如图4所示:

图4 攻击者第一次探测数据库中表的列数(请求)
如图所示,攻击者输入了1’ order by 3#,尝试按照表的第三列对数据进行排序,如果后台表中存在第三列,则排序可能成功,如果没有第三列,则排序失败。
排序成功了吗?观察服务器返回的结果,如下图所示:

图5 攻击者第一次探测数据库中表的列数(服务器响应)
服务器的响应体显示“Unknowd column 3”报错,排序失败,说明后台数据库表不含第三列,表中只有三列以下的数据。攻击者继续猜测能不能按第二列排序,如图6所示:

图6 攻击者第二次探测数据库中表的列数(请求)
排序成功了吗?观察服务器返回的结果,如图7所示:

图7 攻击者第二次探测数据库中表的列数(服务器响应)
没有得到报错,则说明成功,证实服务器后台数据库当前表的列数为2列。
接下来继续观察攻击者的动作,攻击者在获知表的列数后,希望获知注入数据的回显位置,因此执行了命令,如图8所示:

图8 攻击者探测回显位置的请求
图8中攻击者执行了1’ union select 1,2命令,用于测试服务器返回的流量中的位置,其结果如图9所示:

图9 服务器针对回显位置探测的响应(部分截取)
通过返回流量可以看到,受攻击服务器返回了两次First name和Surname,第一次为正常响应,第二次响应攻击者构建的语句,即SQL注入的数据泄漏点。
另外,在第一次First Name之前,我们可以看到未经编码的SQL注入语句1’ union select 1,2#,这是由于受攻击网站在显示结果前,也显示了攻击者输入的内容。因此,在针对仅此网站的分析过程中,后续可以通过此处同时观察到攻击者的输入和网站的输出结果。
接下来,我们通过此处观察攻击者的后续操作,攻击者执行了database()函数,获取到当前的数据库名为dvwa,如图10所示:

图10 服务器针对数据库名获取SQL注入的响应体(部分截取)
获取到数据库名之后,攻击者针对该数据库构建了新的SQL注入攻击语句,执行了group_concat(table_name) from information_schema.tables where table_schema=’dvwa’命令,获取到dvwa数据库中的表名,包含guestbook,users这两个表名,如图11所示:

图11 服务器针对表名获取SQL注入的响应体(部分截取)
攻击者认为users表中可能含有他希望获取的用户名和口令信息,于是攻击者执行了group_concat(column_name) from information_schema.columns where table_name=’users’命令,获取到users表中的列名,列名包含
user_id,first_name,last_name,user,password,avatar,last_login,failed_login,USER,
CURRENT_CONNECTIONS,TOTAL_CONNECTIONS,user_id,first_name,last_name,
user,password,avatar,last_login,failed_login
如图12所示:

图12 服务器针对列名获取SQL注入的响应体(部分截取)
攻击者希望获取全部users表中的user列和password列的数据,于是执行了1′ union select user,password from users命令,获取到了网站的关键信息,如图13所示:

图13 服务器针对暴库SQL注入攻击的响应体(部分截取)
针对图13中数据库暴露的信息,汇总为表格,如图14所示:

图14 服务器暴露的信息汇总
经过汇总,攻击者成功获取到网站的用户名和登录口令MD5值,后续通过MD5彩虹表查询即可获得MD5对应明文口令。
在没有回显的条件下,攻击者如何完成SQL注入
由于很多SQL注入没有回显,所以需要人为制造MySQL报错,通过在报错语句中夹带SQL注入语句,在报错回显中观察服务器返回结果。报错注入大致有十种,这些函数分别是: floor()、extractvalue()、updatexml()、geometrycollection()、multipoint()、polygon()、multipolygon()、linestring()、multilinestring()、exp()。
这里以floor()为例,观察攻击者的报错注入流量,如图15所示:

图15 floor()报错注入流量(请求)
攻击者在报错语句中夹带了’ union Select 1,count(*),concat(0x3a,0x3a,(select user()),0x3a,0x3a,floor(rand(0)*2))a from information_schema.columns group by a—语句,用于获取当前数据库的用户名。
服务器针对此请求,返回的结果如图16所示:

图16 floor()报错注入流量(应答)
图16展示了服务器返回了当前用户名Dhakkan,泄露了敏感信息。
关于前文提到的10种报错注入,原理大同小异,均是通过报错创造回显机会,这里不再分别针对每一种报错注入进行赘述。
关于报错注入,若要检测此类攻击,则需观察请求的数据包是否有这些敏感函数。若要判断攻击是否成功,则需观察响应的数据包是否存在报错回显和敏感数据。
如果连报错都没有机会,攻击者还有办法吗?
除报错注入外,还有一种名为盲注的SQL注入攻击,盲注顾名思义:在没有回显的时候利用其他条件,制造隐性回显协助判断。例如SQL语句执行成功则延迟十秒加载网页,执行失败直接接在网页。
盲注分为两种:基于时间的盲注、基于布尔的盲注。基于时间的盲注主要函数为sleep()、benchmark(),通过时间延迟来判断SQL语句的执行结果。常见payload形式如下:
http://127.0.0.1/Less-9/?id=1' and (if(ascii(substr(database(),1,1))>100,sleep(10),sleep(4))#
该语句的含义为,如果当前查询的当前数据库ascii(substr(database()),1,1)的第一个字符的ASCII码大于100,ture 沉睡10秒,FALSE 沉睡4秒。
基于时间的盲注,攻击流量如下图所示

图17 基于sleep函数的时间盲注
时间盲注执行是否成功,一方面需要看HTTP状态码,另一方面需要结合时序图观察返回的时间,如图18所示:
图18 时序图视角下的时间盲注
根据图18可以看出,6号数据包和4号数据包时间间隔为2秒,判断时间盲注执行成功。
除了时间盲注外,还有一种基于布尔的盲注,主要通过返回true或false判断命令执行是否成功,常见payload形式如下:
http://127.0.0.1/Less-8/index.php?id=1'and ascii(substr(database(),1,1))>114#
该语句的含义为,猜当前数据库第一个字符,利用二分法,115为ture,114为false。
一般情况下,盲注需要结合二分法使用,由于每次获取到的信息相当有限(仅为一个字符),因此需要大量的盲注才能实现获取到敏感数据。
如何防范SQL注入?
关于如何防范SQL注入漏洞,常见避免SQL注入漏洞的方法有如下几种:
检查数据类型:
对传递的参数做校验,如果不合法,直接拒绝请求;如果是数字类型,判断是否为数字,如果不是,直接拒绝请求;如果是有格式的类型(比如日期,email,电话,身份证号码等),判断是否符合格式,如果不符合格式,拒绝该请求;如果是字符串类型,没有特殊的格式,需要对字符串长度做校验,如果长度大于数据库该字段的定义长度,拒绝该请求;例如:姓名,数据库定义的是varchar(20),如果输入超过20个字符,则直接拒绝该请求。
使用预编译语句:
如PrepareStatement,其原理是:mysql执行树会根据预设的参数做转义,可以把注入的sql当作一个参数执行,而不会当作语句来执行;php应用可以使用PrepareStatement替代Statement写法。
对数据库权限做限制(最小权限原则):
不能对业务账号开select information_schema权限。因为一旦某个漏洞被成功注入,information_schema库将暴露所有库,所有表,字段的定义。给sql注入者提供了便利。注入者不需要猜测表结构,就能轻松获取所有表的定义,进而轻松获取所有表的数据。各个业务账号只能访问自己业务的数据。这样即使攻击者利用某个漏洞进行注入,也只是影响到该业务的数据,不会影响到其他业务模块的数据。
结语
本文介绍了SQL注入流量的攻击发现和研判方法,深入探讨了SQL注入攻击的流量现象,以及在CSNAS数据流功能中对于此类问题的分析方法,通过深入理解和掌握此类分析技巧,能够提升安全分析工程师在工作中快速发现分析此类攻击事件的能力。
暂无评论