漏洞扫描:从fuzz到payload

在实现漏洞扫描的时候,部分开发者会使用payload直接进行fuzz,而且并没有对server端的拦截和过滤,有相对智能的反馈,这对扫描效率和成功率是影响比较大的。

那么,我们该如何去实现精细化定制呢?

字符fuzz

另外,在存在waf的时候,我们发送payload过多,可能直接会触发server端的拒绝服务或者ban ip的操作,所以要在保持一定的发包频率的情况下,尽可能少触发waf的规则。 另外,web系统本身可能自带了过滤,如果无脑发payload,可能fuzz了半天都是白费功夫。 在字符形态的时候,如果能直接过滤掉一批有害或者无效字符,能较大程度上提升扫描器的效率。

字符规则过滤

在检测时,先通过字符键值对进行探测,如果不通过,则在黑名单库里加上该字符键值对。然后,我们再接着尝试单边字符是否被过滤,过滤了再把单边字符加入黑名单,这样能在一定程度上提升检测效率。

校验存在键值对的流程: lEax00.png

graph LR
字符键值对-->payload流程

需要注意的是,我们在进行字符fuzz的时候,别忘了加入定位的keyword,不然在复杂的response响应中,不太容易匹配到。

键值对举例如下:

{payload}
--
<payload>
[payload]
(payload)
||
&&
/*payload*/

校验不存在键值对的流程:

lEavmq.png

graph LR
字符键值对-->单个字符
单个字符-->payload流程

单个字符举例如下:

?
'
"
+
#
;
,
~

当然,有人会问是不是每种漏洞类型的检测,都需要按照上述list。

很明显不是啊,每种漏洞检测需要用到的字符集是不一样的,所以需要根据实际检测的情况,以及所使用的payload库进行分类处理。

最后,我们可以根据需要,生成字符(键值对) 到黑名单库,从而转到payload流程进行下一步判断。

从fuzz到payload

那么我们已经获取到黑名单字符(键值对)以后,该如何去尝试fuzz payload呢?

每个人习惯不一样,这里可以直接提取黑名单里的内容作为list,接着挨个对payload进行对比尝试,如果满足黑名单条件,则从fuzz列表里去除掉。

这样一来,能在一定程度上减少fuzz发包数,简易代码示例:

# /usr/bin/python2.X
...
...

#init payload list
fuzz_payload = orig_payload

for y in orig_payload:
    for x in char_blacklist:
        #x may be: '(.*?)'
        if re.match(x, y):
            fuzz_payload.remove(x)

手工简化payload

拿刷众测举例,我们常常需要在短时间内定位到一个参数是否含有漏洞,配合自动化提交快人一步。

就sql注入而言,某某曾说过一个参数发两个包就能确认是否含有注入,发四个包就能确定是什么数据库。

当然可能讲的稍微夸张,但理确实是这个理。

我们先需要通过fuzz点,来确认单参数是否含有sql注入。这里可以提下,一旦结束单参数fuzz,我们可以直接结束掉该url所有参数的fuzz。

另外,不少厂商是是接受多点同类漏洞的,这意思是拿到某个或者某类参数,我们可以去尝试自动化类比fuzz其他地方,是否也存在相似问题。

过滤掉前面的的黑名单字符集,把poc打散然后闭合和注释,再通过判断content-length差距、页面hash变化、时间延时变化,分两步检测快速fuzz出初步结果。

or 8 < 9
or 0 between 8 and 9
and 8 > 9
xor 8 > 9
xor 0 between 8 and 9
or sleep(8)
and sleep(8)
xor sleep(8)
;select sleep(8)

接着,我们可以通过主流数据库的单个甄别性查询语句(比如mssql/oracle/mysql/…),分独立的包发送进行探测,这样能很快的作出判断。

可能有人会说,这样可能会漏掉部分特殊的点。

拜托,众测的时候就是比手快的,你说一个url所有参数都跑一遍的话,就拿sqlmap举例,如果某个点稍微有点特殊,可能几分钟都过去了,才能判断那个点是不是有注入。

如果你在半小时后找到个注入,人家已经在十来分钟的时候提交了,不把人气的吐血三升?

而且,并不是说我们就不关注细节。只不过是做深入fuzz的优先级是相对的,我们需要优先关注cover的广度,而不是cover的深度。

最后,我们可以最快速度得出结果后,再后续使用专用fuzz工具进行二段攻击。

分级fuzz

另外,在发送payload之前,我们能够检测到系统框架的类型,是一个比较有利的起手,这代表我们可以不用盲目尝试payload。

在使用网上的payload的同时,我们也需要去尽可能的去分级和简化。大家要相信,这玩意儿是给自己或者团队用的,不是用来忽悠客户的。

搞一堆华丽丽的东西,最后自己吃没吃饱,只有自家的肚子知道。

分级和简化payload后的结果就是,比如在使用传统扫描器(含接口)如sqlmap和awvs的时候,大家可能永远会觉得机器会帮你扫出来,永远有惰性不会去精简poc,别人一键化拿shell的时候,你可能才刚刚确认cms框架类型。

最终,我们根据测试的场景,可以将手中的扫描器按测试需求,分级别去发送payload:

  • level1: 最简单可以获取基础反馈的poc。
  • level2: 直接可以获取数据和证明危害的payload。
  • level3: 直接可以获取shell,或者证明rce/上传漏洞存在的txt文件。

当然,如果这里调的level比较高的话,低级别的poc检测成功后,是可以向上跃迁检测的。

另外,这里不建议优先采用公共dns平台,因为即使是使用了api交互,公共dns平台也一般会有延时的风险,更别提可能被GA监控管制,再者说证明截图啥的,也需要时间的。