扫描器调度中心"进化史"
2023-11-5 15:10:58 Author: xz.aliyun.com(查看原文) 阅读量:13 收藏

前言

pokemonscan” 是最近捣鼓的“扫描器调度系统”。本文介绍一下实现过程中遇到的坑以及一些想法。以此抛砖引玉,给各位大佬带来一些新的思考。

来源

“pokemonscan” 名字里带着scan,但是几乎没咋干过 “scan” 的事儿。所以我更倾向于叫它扫描器调度中心。

为啥有这么个东西?主要还是出于懒。对于手里没有0day的业余红队选手来说,和防守方打的大多数都是一个信息差。防守方看到报告往往都会惊叹一句:“这玩意也是我们的资产?”。但是随着防御的建设不断完善,卷的攻击队日子也是越来越难过。原来爆破子域可能就能撸到不少年久失修的站,现在要学一套又一套的信息收集工具,漏洞扫描工具。人的精力都是有限的,在一个点上挖的很深入的人已经是业界翘楚,一个人把渗透的各个环节都实现的完美无缺的大手子恕小弟还未见过。

所以对于无论是攻击方还是防守方,对于安全工具的学习可以说是日常工作中必不可少的一部分。每当出现一个新的工具,就需要试一试,这东西诞生的来源是什么?他有什么其他工具不可替代性的作用?这工具的每个参数都有什么作用?即使是倚天屠龙此类神兵,也需要在内力深厚的人的手里才能发挥出自己的作用。最浅显的使用可能是把环境安装好,加一个 “-u http ://xxxxxx.com”,就能够将工具跑起来。但是在工具开发者的设想中,工具的作用远远不止于此。需要根据扫描的不同类型,配置各种参数,从而最优化扫描效果。引申一个题外话,今年随着GPT的爆火,凡是和GPT擦边的安全工具都能获得很高的关注度,但是仔细想想好像大多数是个外强中干,如果说通过GPT真正解决了什么解决不了的问题,我还真没有想到。我感觉只是从百度搜索进化到谷歌搜索的级别:可以用自然语言区描述一件事情,它能够给我返回一个结果。对我描述的准确性要求可能会变低了,可能之前对于百度搜索我要十分精准的描述出来每一个关键字,他才能帮我搜索到,现在对于谷歌搜索,我可以模糊的描述我的需求,GPT即能够猜测出来我想要什么。但是我觉得这还是属于伪需求。因为我觉得能够精准的提出来需求,还是一个(安全)工程师必备的素养。我一直认为人的创造力会强于机器,所以这种创造性的想法和需求,是人类不可代替的工作。但是人类的特性是会遗忘,过一段时间我就想不起来这个工具怎么用,甚至想不起这个工具叫什么了,所以这种记忆性的操作我觉得才是GPT的用武之地。我希望它能够学习会每种工具的使用方式,试用于哪个场景,我只需要告诉GPT,我期望对XX公司进行一次渗透,请你自行组织一次扫描。有好兄弟这里想说,你现在直接问GPT,他也能给你有模有样的回答出来。我只想说,好兄弟,骗骗兄弟可以,别把自己也骗了,你会拿这东西的结果直接用吗?综上,不可否认的是,大模型确实是大势所趋,无论是安全行业还是其他,但是我并不认为现在的大模型,或者说目前由大模型延伸出来的各个应用,可以一步到位达到安全生产力的水准。

实现

说的过于发散了,回到主题中来,我想做的事情就是在大模型真正生产力到来之前,在做一些“旧世界的残余”:将我之前的学习经验以配置的方式保存下来,在需要时候直接调用。比如之前为配置OneForALl 配置了大量token,并且清晰的学习了每个参数所对应的意义,将配置文件和命令行参数保存下来,下次直接调用即可。一个两个工具我就直接记录在我的小本本上了,但是对于十多个工具,每次看索引就够我喝一壶的,所以需要搞个平台把这些配置存起来。

既然存起来了,干脆帮我执行了吧。学工具的第一步必然是配置部署环境,感谢容器化技术,让我们也可以一次部署安装,多次运行。

现在我们可以一键触发各个工具的扫描,终于可以令我的大脑腾出来一些地方,去做一些创造性的工作。比如将上一个工具的输出交给下一个工具作为输入。想了想,我的大脑似乎还可以更空一些。这部分能力平台也帮我实现了吧!

就这样,一个究极缝合怪就此诞生。此刻搬出圣经:“计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决”。平台想做的就是在各个扫描工具之上,形成一个新的系统,使用者不需要再关心底层的调用逻辑,只需要关注于作用域和使用方式即可。这既开头所言“扫描调度系统”。

统一输入输出

功能似乎很简单,存数据,发任务,起容器,回传数据。但是做起来一堆的坑。首先面临的问题是,怎样统一各个工具的输入输出?参考了多个现有流式扫描平台的经验,有的是专门做一个流程给各个工具,用于清洗前一个流程的输入输出。有的是在命令中通过管道传递。感觉这两种都不够令我满意,我认为对于某个插件的输入输出处理,应该是插件的一部分能力,应该属于插件作者的工作。编排的作者只需要关心适用场景以及参数配置;通过管理传递适用的插件范围很小,插件多了会一团乱麻。所以最终决定将常用的资产(站点,域名,主机,URL,漏洞)提出来形成数据结构,插件的输入必须是这五个数据结构中的一种,输出也必须是这五个数据结构中的一种或多种,对各个插件有一个统一的格式化要求。虽然这可能会稍提升一些插件编写成本,但是将这些中间数据存储起来,应该是比较有意义的。首先,在不同情况下,希望传给下游的数据也不尽相同,比如,在之前的信息收集中,我们已经知道目标的某个C段下的都是虚拟主机,对于此类其实没有必要再进行端口扫描,遂可以在端口扫描阶段排除掉。其次,对于扫描结果,我们有的还是需要手动check一下。比如在扫描目标资产的时候,有些站点可能是存在口子,但是需要人工挖掘。反正下雨天打孩子,闲着也是闲着,我们可以趁扫描的功夫,可以找一些资产手动渗透一下。

调度策略

插件的问题大致解决了,“调度中心”核心的问题点还是在调度上,怎样去调度这个扫描任务呢。首先为了调试方便,最小的调度单位肯定是以插件为调度,可以直接下发一个“任务”,从而跑起来某个插件。进而就是将这个插件的返回结果,不断地产生新的任务下发下去。所以流程应该是这样的:我们提供一个输入 --> 跑起来第一个任务 --> 根据第一个任务结果创建一组任务 -->第一组任务跑完后,根据第一组任务结果创建第二组任务 -------......----> 直到没有任务可以产生。很明显,这里有一个“
模板”的概念,我们需要知道,任务完成后,接下来创建怎样一个任务组。通过对安全工具的使用经验来看,一类工具的一次性输出绝大多数都是一类资产。比如扫端口的nmap,输入资产类型一定是一个主机;爬虫页面的 Rad 输入资产一定是一个网站。所以我们可以用“资产类型”来标志一组任务,比如我们通常是这样的流程:通过根域名扫出来子域名和主机,然后主机再扫端口,端口中识别出网站,结合前面的域名扫出来的网站和端口中识别出的网站进行爬虫和漏洞扫描。所以任务组就是:“域名”-> "主机” -> “网站” 。从这个上面可能引申出很多种任务组合方式,比如我想先masscan 扫主机存活,再nmap扫端口协议,那么流程就是 : “域名”-> "主机” ->“主机” --> “网站”。有好兄弟可能会问,为啥两个主机任务组不能合并。因为在扫描过程中,“nmap” 的作业依赖于上游的 “masscan” 输出,需要等待所有 “masscan” 的主机任务完成后,将扫描出来的暴露的端口再用nmap扫一遍,所以必然是两个任务组。

遇到的坑

至此,调度中心的最核心的两个功能点确定:统一数据结构做workflow式扫描模板

worker “过劳卒”

看似即将接近胜利,实则是刚刚开始。在实现过程中,遇到了无数的坑。首先的问题是,作为一个调度系统,怎样极大程度的压榨我们的员工(扫描端),最大化扫描效果呢?一开始的想法是设置CPU和内存的上限。每次扫描端(worker)向调度测“要”任务的时候,带上当前的工作内存和CPU。调度中心配置中配置了最大CPU和内存值,如果超出这个值就不再给他发任务。在实现过程中发现,worker 段一直被卡死,仔细排查后发现。每次 worker 在要任务的时候,上一次的接到的任务刚刚起来,还没开始占用资源。所以CPU和内存还比较小,所以第二次要任务的时候,还是以一个小负载的状态要,然后所有作业突然一瞬间开始占用资源,直接卡死worker。其中典型代表就是浏览器爬虫,非常的吃内存,我的2c4G的机器反应时间大概是30s,30s后开始内存暴涨。所以这里需要根据不同的机器配置,配置不同的心跳时间,从而解决这个 “过劳卒” 的问题。

workflow “卡脖子”

在扫描过程中,还会遇到的问题是我们的扫描任务占用过高的带宽,导致和server失联。worker的状态就是拿着小灵通,站在风雨中,左手换右手,还是打不通,当然此时我们的 grpc 会有自己的“retryPolicy”策略来重试判定是不是真的失联了。亦或是某些意外导致worker出了bug,panic后被重新拉起。对于这一个任务来说,没有完成似乎没有什么大问题,但如果一个任务迟迟没有完成,服务端中此workflow的下一个任务组就会无法创建,整个workflow就会卡到这里。就会出现,所有的 worker 都在等服务端发任务,服务端也在等 worker 上报没有完成的任务,这个workflow直接卡死到这里。解决思路是每次worker重启的时候都会拉一下,看看有没有自己接了,但是没干完的活。服务端也定期回扫一下,是不是有的worker接了任务但是没干完,再给他发一次让他再跑。

成熟的woker应该学会偷偷打工

考虑到成本问题,将家中吃灰的笔记本,台式机拿出来做一个 worker 似乎是极好的。但是扫描必然是十分耗费网速的。一开始我把笔记本偷偷藏到了家里的角落里,防止被女朋友发现给我拔掉。不过还是被她发现了,因为扫描占用的带宽实在过于高,严重影响了她观看直播以及淘宝秒杀的速度。在女朋友的“卡脖子”威胁下,我停掉了家中的worker。为了充分利用资源(省钱),我设置了一个定时任务,晚上1点开扫,早上六点停止。运行了一段时间后,感觉白天都出去上班,家里没人也浪费了。但是有个问题,我必须在女朋友到家之前关闭我的worker,否则就会被一套天马横空烈空带走。等等,这不是一个经典的智能家居场景吗。遂写了个脚本,通过路由器接口轮询家中的连接设备,如果发现女朋友的手机在线,则马上关闭我的worker。从而爱情事业两丰收。

后记

限于篇幅,只对思路和架构做了一些粗略的介绍。具体到插件上的坑以及一些经验技巧,师傅们如果有兴趣,后续可能会另开贴再介绍。


文章来源: https://xz.aliyun.com/t/12976
如有侵权请联系:admin#unsafe.sh