Author: RickGray (知道创宇404安全实验室)
Date: 2016-06-01
好像很久没发文了,近日心血来潮准备谈谈 “漏洞检测的那些事儿”。现在有一个现象就是一旦有危害较高的漏洞的验证 PoC 或者利用 EXP 被公布出来,就会有一大群饥渴难忍的帽子们去刷洞,对于一个路人甲的我来说,看得有点眼红。XD
刷洞归刷洞,蛋还是要扯的。漏洞从披露到研究员分析验证,再到 PoC 编写,进而到大规模扫描检测,在这环环相扣的漏洞应急生命周期中,我认为最关键的部分应该算是 PoC编写 和 漏洞检测 这两个部分了:
首先来说说 PoC 编写。编写 PoC 在我看来是安全研究员或者漏洞分析者日常最基础的工作,编写者把漏洞验证分析的过程通过代码描述下来,根据不同类型的漏洞编写相应的 PoC。根据常年编写 PoC 积累下来的经验,个人认为在编写 PoC 时应遵循几个准侧,如下:
可能你会觉得我太学术了?那么我就一点一点地把他们讲清楚。
PoC 中所涉及的关键变量或数据应该具有随机性,切勿使用固定的变量值生成 Payload,能够随机生成的尽量随机生成(如:上传文件的文件名,webshell 密码,Alert 的字符串,MD5 值),下面来看几个例子(我可真没打广告,例子大都使用的 pocsuite PoC 框架):
上图所示的代码是 WordPress 中某个主题导致的任意文件上传漏洞的验证代码关键部分,可以看到上面使用了 "kstest.php" 作为每一次测试使用的上传文件名,很明显这里是用的固定的文件名,违背了上面所提到的随机性准侧。这里再多啰嗦一句,我并没有说在 PoC 中使用固定的变量或者数据有什么不对,而是觉得将能够随机的数据随机化能够降低在扫描检测的过程所承担的一些风险(具体有什么风险请自行脑补了)。
根据随机性准侧可修改代码如下:
更改后上传文件的文件名每次都为随机生成的 6 位字符,个人认为在一定程度上降低了扫描检测交互数据被追踪的可能性。
PoC 中能通过测试返回的内容找到唯一确定的标识来说明该漏洞是否存在,并且这个标识需要有针对性,切勿使用过于模糊的条件去判断(如:HTTP 请求返回状态,固定的页面可控内容)。同样的,下面通过实例来说明一下:
上图所示的代码是某 Web 应用一个 "UNION" 型 SQL 注入的漏洞验证代码,代码中直接通过拼接 "-1' union select 1,md5(1) -- " 来进行注入,因该漏洞有数据回显,所以如果测试注入成功页面上会打印出 md5(1) 的值 "c4ca4238a0b923820dcc509a6f75849b",显然的这个 PoC 看起来并没有什么问题,但是结合准则第一条随机性,我觉得这里应该使用 "md5(rand_num)" 作为标识确定更好,因为随机化后,准确率更高:
这里也不是坑你们,万一某个站点不存在漏洞,但页面中就是有个 "c4ca4238a0b923820dcc509a6f75849b",你们觉得呢?
讲到这里,再说说一个 Python "requests" 库使用者可能会忽视的一个问题。有时候,我们在获取到一个请求返回对象时,会像如下代码那样做一个前置判断:
可能有人会说了,Python 中条件判断非空即为真,但是这里真的是这么处理的么?并不是,经过实战遇到的坑和后来测试发现,"Response" 对象的条件判断是通过 HTTP 返回状态码来进行判断的,当状态码范围在 "[400, 600]" 之间时,条件判断会返回 "False"。(不信的自己测试咯)
我为什么要提一下这个点呢,那是因为有时候我们测试漏洞或者将 Payload 打过去时,目标可能会因为后端处理逻辑出错而返回 "500",但是这个时候其实页面中已经有漏洞存在的标识出现,如果这之前你用刚才说的方法提前对 "Response" 对象进行了一个条件判断,那么这一次就会导致漏报。So,你们知道该怎么做了吧?
PoC 中所使用的 Payload 或包含的检测代码应兼顾各个环境或平台,能够构造出通用的 Payload 就不要使用单一目标的检测代码,切勿只考虑漏洞复现的环境(如:文件包含中路径形式,命令执行中执行的命令)。下图是 WordPress 中某个插件导致的任意文件下载漏洞:
上面验证代码逻辑简单的说就是,通过任意文件下载漏洞去读取 "/etc/passwd" 文件的内容,并判断返回的文件内容是否包含关键的字符串或者标识。明显的,这个 Payload 只适用于 *nix 环境的情况,在 Windows 平台上并不适用。更好的做法应该是根据漏洞应用的环境找到一个必然能够体现漏洞存在的标识,这里,我们可以取 WordPress 配置文件 "wp-config.php" 来进行判断(当然,下图最终的判断方式可能不怎么严谨):
这么一改,Payload 就同时兼顾了多个平台环境,变成通用的了。
大大小小漏洞的 PoC 编写经验让我总结出这三点准则,你要是觉得是在扯蛋就不用往下看了。QWQ
“漏洞检测!漏洞检测?漏洞检测。。。”,说了这么多,到底如何去归纳漏洞检测的方法呢?在我看来,根据 Web 漏洞的类型特点和表现形式,可以分为两大类:直接判断 和 间接判断。
多说无益,还是直接上例子来体现一下吧(下列所示 Payloads 不完全通用)。
i. SQLi(回显)
对于有回显的 SQL 注入,检测方法比较固定,这里遵循 “随机性” 和 “确定性” 两点即可。
Error Based SQL Injection
condition: (rand_str1 + rand_str2) in response.content
1
2
payload
:
“… updatexml(1,concat(”
:
",rand_str1,rand_str2),1) …"
condition
:
(
rand_str1
+
rand_str2
)
in
response
.
content
针对报错注入来说,利用随机性进行 Payload 构造可以比较稳定和准确地识别出漏洞,固定字符串会因一些小概率事件造成误报。不知道大家是否明白上面两行代码的意思,简单的说就是 Payload 中包含一个可预测结果的随机数据,验证时只需要验证这个可预测结果是否存在就行了。
UNION SQL Injection