0X01 前言

甲方扫描器其中一个很重要的功能重点,就是无害化,目的是尽量降低业务影响到可接受程度。

做过甲方扫描器,基本上对于反馈都有所熟悉。

“我们的服务有大量报错,请问和你们有关么”

“我们的接口昨晚请求量飙升,这是扫描器造成的么”

扫描,应该尽量无感知。

无害化,是扫描器不同于SAST/IAST的一个难点(当然IAST有部署上的性能问题,偶尔的OOM、过高的资源占用也是大问题),是生存下去的必须考虑的一个点。扫描要有产出、要有效率,而业务侧更注重安全、有无业务影响,尤为重要,毕竟谁也不想业务一出问题先来问问是不是安全部门的扫描器。

业务影响的大体场景分类,个人还是分成针对web接口扫描和主机端口扫描造成的业务影响。

0X02 web接口扫描无害化

2.1 QPS

2.1.1 为什么要控制qps

QPS(Queries-per-second),指扫描器每秒针对业务发出的请求量。

QPS不控制好,很容易随时导致业务反馈,业务经过一番辛苦排查,发现是扫描器,自然会带着情绪进行反馈;更严重者甚至会导致占用过多服务资源,导致影响正常业务(可能升级到事务报告,虽然没收到过)

常见的反馈场景分为几种:

a. 在nginx层的公司级监控中,扫描器发送的请求超过了某个接口设置的QPS阈值

b. 在web框架的监控中,请求QPS超过阈值

c. 业务自行设置的监控中,请求超过阈值

d. 业务接口本身没有超过阈值,但是后端的二次调用或多次调用(RPC或其他http服务)超过了阈值

怎么解决?

2.1.2 聚合方式控制qps的关键点

QPS控制需要确定两个点:

1 聚合方式:通过什么方式把不同的URL聚合到一个key中

为什么需要聚合?我们要控制的是对业务的接口的请求量,而不是我们看到的URL的访问量。

a 同一个path,但是参数不同,大多数情况下还是同一个接口同一个函数在处理;

b 而现在动态参数已经很普遍了,比如百度贴吧的帖子

https://tieba.baidu.com/p/1000000001

最后的十位数字不位于参数,而是位于路径中,后端读取这段路径的值来作为变量,不管数字怎么变都是同一个接口处理。

c 甚至于子域名也可能对应同一个接口

https://bj.meituan.com/meishi/

https://sh.meituan.com/meishi/

长这样多数情况下,不同的城市 北京bj、上海sh、广州gz等,都是对应到同一个美食列表页服务

如果不聚合,针对每个长得一模一样的url设置最低的1的qps,当同时对帖子进行扫描时,即使每个url每秒只发送一个请求,在同一段时间内url数量多时,对这个处理的接口发起的访问量也会变得极大。特别是在业务高峰期(早8点到晚10点业务请求量较大),接口压力本来就挺大,基于流量镜像模式的,接收到的url也很多,再做一次扫描,容易把业务打的叫苦不迭。

所以聚合理论上是将表面不一的url收束在属于它们自己的范围内,当然越接近接口越精准。

2 QPS值:对应的key能使用多少QPS、每秒能发送多少请求

QPS值,取决于这个接口的承接能力、设置报警的阈值。

值设置的高了,容易打爆业务接口;值设置的低了,扫描速率会较慢,流量大时可能消费不完。

最适合的值上限,是业务正常情况下的请求量均值或上限。

有的业务会按照一分钟请求总量来设置告警,一分钟 100-1000,也就对应着 1-17的QPS。平时访问量较低的接口,QPS为1就足以打报警。

2.1.3 不同的实现方式

a 域名聚合

同一个域名或子域名的请求不超过N(5-10)。

一刀切方式,优点是成本低、效果也挺好。

缺点是绝对平等,不管流量大小都使用同一个QPS,流量大时可能扫描不完。

和任务绑定起来适用于扫描任务多但每个任务流量不多的情况,比如多用户多任务的情况。

b 集群聚合

每一个url,根据nginx解析结果,获取url最终归属的业务集群。

结合内部监控数据,获取每个集群实时访问量,计算出每个集群的访问峰值;

使用峰值减去实时访问量(前n分钟),得到空余的可用访问量

缺点:

1 依赖于内部基建的资源

2 同一个集群下的接口,可用的访问量是基于整个集群的。比如A可用300、B可用300、C可用300,集群整体可用900,但A本身承受量只有500。这样就会出现QPS倾斜,访问都打到A,会把A打爆。

c 去重聚合

镜像模式下基本都会有一套去重程序、流量清洗服务,在去重的时候记录下每个key的实时访问量。

用去重的key作为聚合的值,QPS计算的方式和之前一样,计算每个key的峰值,再减去前n分钟(在可控范围内尽可能少)的qps,得到这个key在这一分钟的可用量。

结合路径相似度与页面相似度的去重,去重key接近于接口,效果比较理想。

2.1.4 QPS超限后的限制方式

如果插件最小任务单位已经拆分到请求级别,那么可以将请求任务丢到队列里,根据可用量来读取请求任务运行。

但插件有很多情况需要上下文关联,比如需要第一个请求获取登录凭证token、第二个请求使用该token进行后端RCE等。

这时当扫描规则发送请求时,该请求已经没有可用QPS了,怎么做限制

方法1

直接sleep,等待可用了再发送,但会导致任务hang住、占用节点。资源多无所谓。

方法2

超限后扔回重试队列中

但是下次扫描并不从头开始,而是从中断处开始继续扫描

不进行断点重扫,会有部分插件一定扫描不完,比如有的规则扫描时没有限制,1秒10个请求,无法成功;而QPS控制业务边缘归属于引擎,不应该影响规则本身的检测效果

记录每个扫描任务的每个请求hash (url + header + postBody),给插件分类(有无上下文关键);

对于没有上下文的规则,下次任务已经请求过的hash直接跳过;对于有上下文关联的规则,存储每个hash的返回,重试时已经请求过的hash,直接读取上一次的返回。

2.2 业务错误码报错

业务线会监控服务稳定性可用性,最简单的就是404/504等错误码的每分钟占比。

可用性有的会直接影响到业务的KPI与指标。

这里应该收集每一次的反馈,和内部监控平台沟通谈需求,识别到内部扫描时把这部分请求摘掉;如果是单个业务自身做的报错收集,只能靠他们自己去解决这些问题了。

这里注意扫描时要让业务溯源简单,自定义的header / ua / 出口IP等,否则溯源老半天才发现是内部扫描,业务会更生气。

2.3 脏数据

脏数据是一个无法避开不谈的问题。

镜像模式下,只过滤掉header与post,只扫描get,仍然可能会存在脏数据问题。

get理论上应该是做查询,select操作,但是业务想用来做增删改操作也无可厚非。

get中可能存在用户凭证,业务不把token放在cookie中了,而是放在get参数中、平时保存在localstorage中。这种情况带着get参数值去扫描,等于拿着用户的身份去扫描,有个信息增删改操作,就会导致用户脏数据。

再比如,业务写接口,登录界面获取手机验证码,getCode?phone=xxx&type=1,拿到这条流量进行扫描,在对type进行扫描的时候,重复发送给用户验证码,用户还以为账号是被黑了。

又或者,没有增删改等,只是单纯的查询,但因为带着用户信息,频繁访问,被反扒处置了,用户被封禁了。

方法1 清洗与打标

在2.1中,说过接口;在我们有了所有接口数据后,借用其他安全产品的能力(SAST/IAST),给接口打上标签,判断是增删改或者是查;增删改操作就小心跳过,可避免掉大部分脏数据业务影响情况。再设置参数名黑名单,过滤掉形如phone/token/tele等明显带有用户特性的参数名的值。

这种做法相对安全,覆盖率取决于SAST/IAST的能力,但也会导致这些接口的漏报

方法2 爬虫

通过爬虫,第一篇1.2.4,采用自身测试账号抓取的流量,通常脏数据问题会比较少,因为这些请求都是正常用户可以访问到发出的,也是外部扫描器会收集到的。

用户能访问到的接口,造成脏数据,说明外部的用户也可以造成,特别是外部的白帽子/黑客也会进行扫描。并不是不扫描问题就不存在,只是没暴露。

方法3 影子环境

直接将现有的DB环境、服务环境复制一份,通过nginx层转发扫描请求/压测请求到影子环境,风险极低,但成本极大(成本*2)。

或者单纯的复制DB环境,在数据库连接函数中作hook,把扫描请求的数据库链接改为影子库。但是操作起来很麻烦,开发维护成本较大,多层调用最后再到DB,和最初的请求关联起来判断是不是扫描的就很难。

而且除了常规DB mysql/mongo/redis/MQ/kafka等,还有其他的数据库甚至是本地log等,转了一部分但另一些操作没转,业务数据层方面就不一致了,只能通过反馈不断维护,比较麻烦,不太推荐。

方法4 测试环境

第一篇 1.2.6中,测试环境进行扫描。

把扫描作为一个能力开放给业务线,在业务可控的情况下,可以带cookie扫描、也不需要过滤各种参数,QA在明白风险的情况下进行扫描。

甚至可以进行流量打标,让业务自行选择是否对涉及增删改的接口进行扫描。

PS:

有的收购业务一扫系统就出问题,没有统一测试环境,没有统一上线流程可以获取代码进行接口打标,脆弱至到处都是未授权,这种情况无能为力。

2.4 扫描时间段

有的业务允许扫描,但希望扫描的时间段放在半夜,因为半夜业务访问量较低,出了脏数据或者QPS等问题,影响会比白天高峰期时小,到业务 "开门" 也有一定的缓冲时间。

2.5 限制带宽

虽然都是过滤就可以的,但是和静态文件影响扫描性能不同,这个会造成成本问题。

扫描时可能会遇到下载文件的接口,请求一次后,接口会把几十上百兆的文件内容返回给客户端。这QPS一上来,带宽蹭蹭蹭就起飞了。私有云场景可能是和云服务买带宽套餐,可能是阶梯式收费,也可能是按使用量收费。一旦超量,可能就要多花费个几百万,足以发个严重事故了。

所以流量过滤时,也要过滤掉content-length过长的、content-type属于下载类型的。

0X03 主机端口扫描无害化

3.1 内网HTTP服务报错

内网中有很多HTTP服务,对内网进行框架漏洞扫描时,可能会引起报错,影响与处理方法同2.2

3.2 指纹匹配过滤不符合端口的数据

内网有很多端口服务,端口服务有自己的报错姿势。

有业务自己写的socket服务,但是没有做数据校验,当接收到不符合格式的数据时,抛异常导致进程中断。

这样的业务,其实也算存在DOS漏洞,可以提交安全工单敦促业务修复。

也存在部分常规业务,打个比方,redis协议扫描mysql导致mysql处理时间过长hang住(可能不是这两个服务,时间长忘记了)。

这种可以通过端口指纹方式避免掉,通过给每个端口打上所属服务/框架的标签,规则设置一级指纹(URL/HOST等数据类型)、二级指纹(URL数据的框架、HOST端口的服务/框架),在任务处过滤掉不匹配不对应的,可避免数据不匹配导致的服务报错或者挂掉

3.3 业务方给定指纹

内网可能有RPC框架,接收到不符合端口的数据会报错,但是框架层面无法作数据校验、来直接过滤掉不符合的数据,因为使用方需要这些报错来判断服务是否有异常。也无法在框架层面直接判断来源IP和集群过滤掉扫描请求,这不符合框架的设计。

可以由框架提供探测指纹,端口连接后返回特定数据,标识本身服务。

3.4 限制服务同一时间的链接数

内网扫描出现的比较多的情况,是一个IP端口的服务被链接过多,导致服务异常。

一个要做的是限制同一个 IP+端口 单位的链接数,同一时间只能链接N个。

另一个,可能存在规则socket.connect后,没有close,即使任务关闭,但远程连接方没有收到关闭请求,还在等待接收数据。即使本身已经限制了链接数,还是会打爆。所以规则检测,需要判断connect后是否有close。

PS:

当然还可能会有层出不穷的报错,比如扫描弱口令 比如ssh/mysql/mssql/redis时,引起的大量报错信息与不停告警。遇到过业务方写个了mssql代理,扫描时导致DBA mssql各种报错,但是DBA不知道是哪个机器发送的请求,业务方也不知道自己的代理启动在哪里,只知道有扫描器弱口令规则的paylaod,也无法加白名单。最后把IP写进username里才定位出来。

也可能有内部业务与其他公司有服务对接,在自家内网开了个代理服务器,可映射到其他内网。扫描时检测到各种端口,其实是其他公司的内网各IP与端口。这种情况十分危险,有反馈最好先加白过滤。代理服务器可能链接到其他传统的、脆弱老旧内网,一扫过去可能就挂了,事故报告就来了。

0X04 规则无害化

4.1 场景

规则无害化由上述方式并不能很好控制。

有的友商扫描SMB (MS17-010)等漏洞的时候,没有把控好规则的危害程度...直接上了把业务打蓝屏的规则;

log4J常规payload,链接到dns,会导致log4J等待、hang住,qps过高可能会打挂服务。

4.2 靶场验证

规则扫描线上服务之前,需要设置靶场链接,经过验证后才能上线,不仅是验证规则是否有效,也是验证规则是否会对环境造成影响

4.3 插件审核机制

自动化检测一些常规规范,比如调用socket.connect后是否有close()等

对个人而言,代码得或多或少符合PEP8规范吧,杂乱无章的缩进、不明所以的换行、奇怪的dict有换行没换行交替,实在是看了有些尴尬

再是人工审核,审核时需要审核员(可以是固定资深人员、也可以是自选另外一个同事),迭代更新的规则展示更新的部分。审核主要是依靠经验判断有无不可控的风险。

DAST 黑盒漏洞扫描器 第三篇:无害化的更多相关文章

  1. DAST 黑盒漏洞扫描器 第四篇:扫描性能

    0X01 前言 大多数安全产品的大致框架 提高性能的目的是消费跟得上生产,不至于堆积,留有余力应对突增的流量,可以从以下几个方面考虑 流量:减少无效流量 规则:减少规则冗余请求 生产者:减少无效扫描任 ...

  2. DAST 黑盒漏洞扫描器 第六篇:运营篇(终)

    0X01 前言 转载请标明来源:https://www.cnblogs.com/huim/ 当项目功能逐渐成熟,同时需要实现的是运营流程和指标体系建设.需要工程化的功能逐渐少了,剩下的主要工作转变成持 ...

  3. DAST 黑盒漏洞扫描器 第五篇:漏洞扫描引擎与服务能力

    0X01 前言 转载请标明来源:https://www.cnblogs.com/huim/ 本身需要对外有良好的服务能力,对内流程透明,有日志.问题排查简便. 这里的服务能力指的是系统层面的服务,将扫 ...

  4. DAST 黑盒漏洞扫描器 第二篇:规则篇

    0X01 前言 怎么衡量一个扫描器的好坏,扫描覆盖率高.扫描快.扫描过程安全 而最直接的效果就是扫描覆盖率高(扫的全) 怎么扫描全面,1 流量全面 2 规则漏报低 流量方面上篇已经讲过,这篇主要讲扫描 ...

  5. web网络漏洞扫描器编写

    这两天看了很多web漏洞扫描器编写的文章,比如W12scan以及其前身W8scan,还有猪猪侠的自动化攻击背景下的过去.现在与未来,以及网上很多优秀的扫描器和博客,除了之前写了一部分的静湖ABC段扫描 ...

  6. 【第三篇】ASP.NET MVC快速入门之安全策略(MVC5+EF6)

    目录 [第一篇]ASP.NET MVC快速入门之数据库操作(MVC5+EF6) [第二篇]ASP.NET MVC快速入门之数据注解(MVC5+EF6) [第三篇]ASP.NET MVC快速入门之安全策 ...

  7. qqzoneQQ空间漏洞扫描器的设计attilax总结

    qqzoneQQ空间漏洞扫描器的设计attilax总结 1.1. 获取对方qq(第三方,以及其他机制)1 1.2. QQ空间的html流程1 1.3. 判断是否有权限1 1.4. 2015年度Web服 ...

  8. 第三篇——第二部分——第二文 计划搭建SQL Server镜像

    原文:第三篇--第二部分--第二文 计划搭建SQL Server镜像 本文紧跟上一章:SQL Server镜像简介 本文出处:http://blog.csdn.net/dba_huangzj/arti ...

  9. 【HANA系列】【第三篇】SAP HANA XS的JavaScript安全事项

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列][第三篇]SAP HANA XS ...

随机推荐

  1. Python入门-import导入模块功能

    1.啥是模块 模块(module):用来实现或者多个功能的Python代码,(包含变量.函数.类),本质就是*.py后缀文件. 包(package):定义了一个由模块和子包组成的Python应用程序执 ...

  2. k8s pod 在迁移zookeeper时出现的问题

    一次迁移中出现的问题,因为要搬迁机房,集群中的节点服务器分布在两个机房,通过专线打通了,现在需要整体都迁移到其中一个机房,所以pod要进行迁移,机器资源也比较紧张,在迁移中zookeeper迁移出现问 ...

  3. HTML/CSS+JS制作一个高考倒计时页面

    2020-07-09更新 修复倒计时归零后出现负数的bug 自动切换至下一年日期 ##效果展示 前言 在B站上找视频学习的,勉强搞出来了,写下此篇文章作为笔记,也希望有更多感兴趣的人能够有所收获. ( ...

  4. gin框架使用【5.路由分组】

    package mainimport ( "github.com/gin-gonic/gin")func main() { router := gin.Default() v1Ro ...

  5. qt在linux下引用x11库编译错误的解决办法

    首先安装x11的开发包,以debian9为例:sudo apt install xorg-dev这个解决.h头文件和.a库文件在qt的.pro文件中加入:LIBS += -lX11这个解决连接错误,注 ...

  6. Go能实现AOP吗?

    hello~大家好,我是小楼,今天分享的话题是Go是否能实现AOP? 背景 写Java的同学来写Go就特别喜欢将两者进行对比,就经常看到技术群里讨论,比如Go能不能实现Java那样的AOP啊?Go写个 ...

  7. 21天学通Python PDF完整版

    有需要的点击这里自取 内容简介  · · · · · · <21天学通Python>全面.系统.深入地讲解了Python编程基础语法与高级应用.在讲解过程中,通过大量实际操作的实例将Pyt ...

  8. 接口测试实战| GET/POST 请求区别详解

    1.请求行的 method 不同:2.POST 可以附加 body,可以支持 form.json.xml.binary等各种数据格式:3.从行业通用规范的角度来说,无状态变化的建议使用 GET 请求, ...

  9. OCI runtime exec failed: exec failed: container_linux.go:380: starting container process caused: exec: "ip": executable file not found in $PATH: unknown (Docker容器没有ip addr命令:exec ip addr 报错)

    一.报错 1.报错信息1: OCI runtime exec failed: exec failed: container_linux.go:380: starting container proce ...

  10. centos 7.0 下安装FFmpeg软件 过程

    这几天由于需要编写一个语音识别功能,用到了百度语音识别接口,从web端或小程序端传上来的音频文件是aac或者mp3或者wav格式的,需要使用FFmpeg进行格式转换,以符合百度api的要求. 安装FF ...