本文主要系统性介绍在Linux平台下如何构建反入侵产品。
目前主流的方案还是基于Agent的方式,Agentless的限制比较明显。即Agent运行在端上负责数据采集、部分恶意行为判断和响应能力等,后端负责Agent管理和数据处理来发现恶意行为。
整体不详细展开,主要写一些设计过程中需要关注的问题或主要的设计思路。
端上CPU/内存/IO限制;
关键指标与监控数据的采集与上报,如TPS/CPU/MEM/磁盘IO/网络IO的占用情况等,便于监控和自证;
容器环境的适配,这部分主要会影响数据采集的质量,比如K8s下最好能关联到Pod和镜像信息,并且还有很多数据采集可能会需要进入到容器环境内进行,比如资产,弱口令,关键配置等;
不同发行版、CPU架构与新老版本内核和发行版版本的兼容与测试:
一方面是不同环境下可能部分功能实现就不一致,比如包管理不同导致的资产采集和文件完整性校验的实现差异;
还有一方面是可能存在的Agent本身的依赖问题,比如对openssl的依赖,对libc的依赖,这些依赖是否存在版本的要求的问题,是否要选择全静态编译。
不同Region以及内外网环境的适配,这个需要结合部署环境与实际情况综合判断;
自升级与插件升级能力,目前大部分应该都会设计成插件的模式,主要需要看是否支持Agent自升级和插件升级并且如何实现,延伸的问题是是否需要精细化的管理,比如不同的机器有不同的插件版本和插件配置,这部分需要更仔细的设计每个Agent的配置管理部分;自升级可能有些公司是不允许的,需要通过统一的包管理和包升级走。
通信加密性以及自保护能力,是否需要针对常见的kill,system stop或者离线掉线做检测或针对性的对抗;
Agent本身和插件的Crash或Error感知能力。
笔者认为以目前的对抗强度,目前的最佳方案一定是通过内核态进行数据采集,尤其是eBPF出现后;
主要的在内核态的Runtime数据采集范围还是围绕着:
进程:创建,权限变更,继承关系变更等;
文件:创建或打开,删除,更名,无文件,mount等;
网络:连接或被连接,端口监听,DNS等;
特殊权限:USB,Ptrace,Load Kernel Module等;
明确的攻击场景下的数据采集:端口扫描行为下的统计性数据采集,各种提权和常见的内核0day利用的内核函数调用采集。
内核态数据采集的技术方案比较明确:kprobe或tracepoint,应该也可以基于LSM;
也有基于LD_PRELOAD或者uprobe的实现,这部分需要注意容器场景的支持问题;
确定采集数据后还需要确认具体hook函数,这里会有比较多的工作,拿网络连接举例,可以选择connect syscall,也可以选择tcp_connect,这里会有细微差异,比如是否能得到正确的返回值,是否支持有connect syscall调用的udp等;另外说一句,如果这里使用Auditd的方案做connect的数据采集,你会发现由于hook点过于前置(应该是LSM有阻断的需求)连源端口都无法获取,所以具体的hook点的选择和组合很重要;
在这个过程中需要尽可能的了解目前方案的边界在哪里,比如rawsocket或无connect的udp请求可能无法被以上的hook点采集到,如何需要覆盖成本可能会很高,这里需要不断平衡这些问题,并且需要明确的清晰的了解这些能力边界和差异;
兼容性依然是很重要的问题,不同CPU架构和不同内核版本下的差异需要被重点关注,还有一些非主流的函数容易被忽略,如ia32;
还需要确认采集的是具体的采集字段,这部分主要分为两部分:
基础信息:负责标识进程或数据关联,如:PID,EXE,SID,PGID,COMM,CMDLINE,容器信息等;
支撑检测信息:不同的采集点不一样,负责该采集点对应的检测工作,比如connect下的5元组信息等;
这部分数据可以参考一些知名的开源方案或者逆向一些商业化产品进行学习,琢磨每个字段或者每个采集点的作用,然后不断结合自己的场景和积累进行迭代。
需要支持热更新的白名单,这点非常重要,在尽可能早的阶段将白名单内数据过滤来尽可能的降低其对于资源的占用,白名单可以是用户态计算完后传递给内核态进行过滤(比如在用户态计算完MD5或者其他复杂匹配后传到内核态的只是PID LIST等);
采集频率的限制,降级与熔断方案,其中不仅需要有整体的降级或熔断方案,也需要有针对不同极端场景下的方案,如高open/udp/connect等场景可以关闭对应的hook点;
其他数据采集:
登陆日志;
History:按需,针对build-in bypass execve场景;
各维度的资产数据:用户,进程列表,端口列表,包管理数据,中间件,数据库,定时任务,System Service等等,这部分就不赘述了;
合规和基线相关,漏洞检测相关,弱口令检测相关。
服务端整体的高可用设计,降级方案,配套的监控与应急能力;
各组件的横向扩容能力;
不同Region以及内外网环境的适配;
Agent管理能力,相关配置变更与变更管理能力;
关键数据的统计能力,一方面便于做整体的评估,另一方面可以做一些诸如自动调整端上白名单的工作。
有状态和无状态以及CEP场景的策略建设需求的满足,自定义函数,离线计算场景支持,流+离线计算场景支持;
高性能;
其他能力,如策略的灰度发布,namespace的支持,细粒度的监控,策略debug能力,横向扩容支持等等,即需要满足好用且易用,多人场景下好用且易用。
通过签名特征或者静态特征检测,目前主流还是会结合动态行为进行准实时检测,比如结合open或者create file再追加静态检测插件进行扫描。
因为静态策略建设比较依赖积累,这部分特征库一般可以选择开源裁剪(如clamav),或者外部采购商业检测引擎以及采购威胁情报。
自建可以考虑通过:
大规模外网蜜罐+自动化或半自动化提炼关键特征+人工校准;
购买恶意样本+自动化或半自动化提炼关键特征+人工校准;
构建动静态沙箱+Agent无差别上传未见过文件,这个比较暴力,但是是传统杀软和云厂商乃至微软都在采用的方案。
长期看不仅仅要建立各种动态静态策略,更重要的是要建立内部对于的各种样本、家族、手法分析能力和方法,并且能够不断的沉淀下来,这可以帮助我们感知不同纬度的攻击者的手法和创新,来不断的提高整体的检测能力。
我给基本策略的定义是:即基于单一数据就可以判断该行为为恶意的策略,比如一些基本的反弹shell,常见RAT行为特征,常见的恶意工具特征,常见挖矿蠕虫特征等等,除此之外还有一些简单的无状态频率检测,如爆破,扫描等。
这里可以根据ATT&CK和自己内部的归纳方法先进行攻击手法的收集归类和自动化验证工具的准备,再逐步进行策略的编写,并且需要长期查漏补缺。
在高级的对抗中往往很难通过基本策略进行检测,这一部分是因为服务器端有些时候已经是攻击的末端了,攻击者可能已经可以通过合法身份的渠道登陆到服务器上进行一些操作了,另一方面更高明的攻击者也会有尽量降低暴露自己的可能,直接使用常见RAT或者反弹shell等操作并不是一个好的选择。
因此无论是什么场景的入侵检测产品,最终的目的是希望通过引擎+算法+策略实现对于行为本身的理解,然后再进行判断。
那么多个弱告警+告警关联+综合打分是一个比较容易想到的方案。
基本策略需要考虑误报问题,其策略编写主要侧重针对恶意行为所特有的特征,因此对于准确度和误报率是有较高要求的,而弱告警策略构建因为不需要考虑到误报问题,比如cat xxx.conf
可以说是 Discovery行为,但是更多可能性是运维或研发同学的正常操作,不过没有关系,可以编写一个分数较低的弱告警策略。弱告警策略的编写方式就是针对ATT&CK的行为在不用考虑误报的情况下进行策略编写,力求全面而非准确,再举一些例子,比如tmp下创建文件,判断是否处于容器环境,java/php等web常见进程派生进程,访问配置文件,查找敏感配置,查看各种基础信息等。
我们有了自己的弱告警规则后,再基于进程,文件等关联关系将不同的告警进行关联,再进行聚合打分。
在早期的版本中,我们是混沌匹配的,即如果我们有3条来自同一进程派生的弱告警,并且有一个最基本的顺序性(比如符合 Initial Access -> Discovery的顺序性),那么会进行对应的弱告警累计并与告警阈值进行对比,如果高于则产生告警。注意这里实际上是不考虑弱告警与弱告警之间的逻辑的。该方案整体误报较高,可解释性较差,但是确实可以发现一些基本策略无法发现的恶意行为。
随着我们在这个方向的深入,我们发现比较明确的行为序列可以更好的降低混沌方案的缺点,因此相对窄化的但是明确的存在内在逻辑的弱告警关联方案逐步替代了之前的混沌方案。
行为序列检测(即通过跨越时空和主体,并通过多个明确的弱告警组合进行检测)带来了很好的可解释性,具体的行为序列需要从具体的攻击case中提炼,也可以从蜜罐中进行半自动化的提炼。比如:
从外网下载程序到tmp->给该文件可执行权限->运行该文件后,该文件访问多个内网服务器端口;
连续访问多个的系统配置->访问known_hosts->登陆其他内网服务器并且登陆成功;
多个web服务派生的行为触发弱告警。
提升行为序列检测能力需要:
场景的不断补充与提炼;
提升行为间关联能力:仅通过进程是不足的,如A进程写入定时任务,定时任务运行的场景;
跨机的关联场景,这部分可能收益比较低;
跨长周期的关联能力。
需要注意的是行为序列检测需要规则引擎支持CEP,并且可以引入一些基准数据来影响单个告警的分数权重,比如x%的历史时间或相同镜像业务没有该行为,则该告警的分数 = 基础分数 * (1-x%) *100等(公示瞎写的)。
这里有一个没有来得及实践的问题,即局部的混沌是否会带来更好的检测效果?
关于行为序列检测我们还可以基于大量的公网蜜罐数据进行行为序列自动化学习和生成,然后通过人工评估和生产环境灰度后再发布策略,这样可以大大提升对于新型恶意行为的捕获能力。
异常检测不是一个新鲜概念了,在几年前伴随着机器学习大热的时候热过一段时间,早期方案是比较暴力的针对部分类型的原始数据进行全量的异常检测,但是效果不好,性能差,可解释性差,误报高。
第二个阶段是通过对行为进行打标,然后再进行传统的异常检测(异常点检测或者分类),这个思路本质是通过标签让机器更加理解行为。
这个方案的Demo效果是不错的,恰好Demo出来没多久ChatGPT3.5就发布了,基于LLM对行为进行自动化打标极大的提高了效率,最后的检测部分还是选择了传统的异常检测算法进行,以便提高效率并且更好的调整告警阈值。
具体的标签化例子:
网络访问可以给以下标签:内网,外网,常见应用服务端口,常见存储服务端口,或者直接联动CMDB给业务归属标签等等;
普通的进程创建可以给以下标签:文件管理命令,系统管理命令,文本处理命令,网络管理命令,权限切换命令等等;
文件相关的:系统配置目录,临时目录,共享库目录, root 用户目录,系统日志目录等等;
其他:出现的概率,关联操作的人员属性(研发,测试,运维)等。
然后根据数据的各种操作对象,来源,进程树信息,特殊环境变量等等进行标签化,标签种类越多越好,然后通过LLM高效打标。
打好标签后再基于行为组为最小单位进行模型生成(可以选择一些传统的聚类或分类的机器学习方案),然后再用恶意行为进行测试来不断调整,注意这里需要基于一组行为序列进行训练和检测。
我们的Demo最后表现是可以将生产环境的抽样的数据分为100多类,并且对于已知的恶意行为有不错的区分度。
数据关联在行为序列检测和告警发生后基于告警数据对原始数据溯源有用到。
Linux Process Group Session ID 是一个很好的选择,需要注意setsid会变更SID信息,简单场景下可以直接用SID作为溯源用Key,效果会明显好于PPID/PGID等其他ID。
由于任何Runtime数据都会采集SID,因此在告警溯源的场景下,仅使用告警数据的SID就可以非常方便的把一个该行为前后的进程、文件、网络、权限等行为进行关联,再对其进行基于时间的关联绘图将会非常实用。
在超大数据量并且有自研规则引擎的情况下,可以在规则引擎内集成一段时间的原始数据离线存储与查询能力:将SID作为唯一索引,保存为索引文件(近期的存储在内存中),原始数据的压缩文件和压缩字典进行分片保存,遇到需要进行查询的场景,先查询索引文件,如有匹配,再进行对应压缩文件的解压缩进行提取,可以参考下LSM-Tree方案。
这样的好处是可以实现非常高的存储和计算性能,压缩比可以做到很高,并且可以极大的减少存储成本的运维成本(私有化部署方便),并且这样相当于让规则引擎支持流数据处理的同时有了离线数据的处理能力,有了原生支持流+离线的能力,策略编写也会更加便利。
这里主要指告警后除了原始数据外的数据关联场景,目的是提升告警数据的丰富度和上下文,提高IR人员效率:
告警相关的登陆行为:如有进程树中有sshd,关联具体登陆日志;
告警相关进程是否存在高危漏洞信息,高危基线风险,弱口令风险;
告警相关进程来源排查,比如crontab,linux service等;
告警相关进程的容器信息关联:Pod信息,容器ID,镜像信息;
其他日志关联:相关应用日志关联,nginx accesslog关联,所属 crond 日志关联,所属 linux service 日志关联等;
其他安全产品关联:RASP,K8s Auditing,网络层安全产品等。
其中部分场景的数据需要从端上采集而非全量实时采集,如某Java进程产生某告警,Server需要调度Agent的数据采集插件对该进程的相关日志进行采集上报,比如采集告警前2分钟后5分钟的该进程日志,然后再告警详情页供IR人员查看。
这样不仅仅能有效的提高IR人员的效率,还能帮助IR人员查漏补缺。
无论是Runtime原始数据溯源还是其他数据溯源,最好可以提供整体的图关联展示+表格数据展示,便于IR人员观察和检索分析。
提供最近服务器新增文件列表;
提供系统关键文件完整性校验;
提供ssh登陆记录,know hosts记录,登陆拓扑等;
提供人员操作记录(ssh登陆后的操作记录);
提供定时任务和系统服务调用记录与关键日志;
提供有基础权限的可交互的伪shell,便于应急响应人员第一时间无需登陆服务器即可获取一些基础数据,比如支持/proc下可读,并且支持ps,top,ss等这类命令。
这部分最好可以设计在告警详情页面中以便IR同学快速查看。
主动防御应该是针对100%确认的恶意的行为进行阻断,这里出现了1-2例误报就会让业务和安全工程师失去信心。
因此通过大量外部蜜罐数据明确了某些自动化攻击家族的pattern,再通过自动化+人工确认的方案提炼成行为序列检测策略,然后通过行为序列检测方法进行阻断,阻断后给出也可以恶意家族报告证明阻断的合法性,并且通过自动化的方式提升蜜罐数据到自动化阻断策略的效率。
还有一些比较强的特征比如明确的静态指纹特征,明确的挖矿/勒索/DDOS行为或静态文件特征,明确的基于内部情报的特征等可以使用。
总之不能基于普通的入侵检测策略进行阻断,应该要有非常强的阻断依据,目标应该是误报率为0%。
传统的致盲能力,如利用x32 syscall,udp,rawsorcket,icmp,build-in,elflodar,elf与so注入,绕过vfs,fileless等方式来避开常见hook点,从而实现从底层即数据采集层进行Bypass;
Ring3层对抗也不断有新的技巧出现,比如几年前的orbit,通过修改ld.so实现恶意so的注入确实在传统HIDS层面比较难检测,可能需要在Agent侧引入类似https://github.com/mempodippy/detect\_preload的方案来做检测;
Ring0层RAT,传统的Linux R0 Rootkit重点在隐藏用户态恶意进程,文件,网络等行为,让安全产品或相关人员无法发现其行为,但是随着主机安全产品逐步都在通过各种内核态方案进行数据采集,并且也比较容易针对性检测,这种方式上会逐步失效。但是实际上在R0可以完成所有RAT需要的功能,不必依赖用户态的能力,比如:
该例子是在内核态实现了劫持指定连接并且实现接收控制者命令并执行然后基于劫持的连接返回执行结果的Case,从HIDS视角不会产生任何数据,用户态也不会有任何相关进程或后门文件。这种场景下如果投入足够高可以完美的避开所有主机安全的监控,并且可以完成非常丰富和复杂的功能。这部分的对抗成本非常高,而且不排除投毒的可能性,建议是先一步掌握主动权,即:内核模块需要签名才可以进入内核。
Ring0层以下:笔者了解较少;
前置被入侵,相关导致权限丢失,导致横向移动到服务器端的行为从HIDS视角观察都是”正常“业务操作。
另外这里需要提一下,目前主机端的策略建设都太过于依赖进程创建了,很多场景下可能简单的mv bash abc
或者mv nmap 123
然后再执行相关操作都可以实现Bypass,这里我觉得可能是所有策略建设同学都需要思考的问题,一方面在实际生产环境确实不可能无限增加hook点来不断提升行为感知的覆盖率,另一方面各种针对绕过Execve的情况也越来越多,我之前有设想过一个方案:
根据服务器的业务属性,部署环境,漏洞基线层面的风险情况,具体组件,历史威胁情况动态的配置不同的数据采集能力,比如:RASP能力,应用层日志采集分析能力,默认不开启的Hook能力如Accept,File Write,File Read等;
举例如果A业务存在公网暴露,并且相关组件存在漏洞,服务器目前CPU和MEM资源还有较多剩余,动态开启了RSAP和File Write与FIle Read,业务漏洞修复完成后自动关闭了File Write和File Read的Hook。
最终还是需要增加新的数据感知能力来应对更复杂的场景,但是我们可以通过更加动态和精准的方式调整这些数据采集的开关或者检测模型,来尽可能降低成本和业务侧的影响。
还有一个问题是目前有些安全厂商构建策略的时候实际上考虑的并不是真正的对抗,而是面向竞品和招投标POC进行建设的,或者是噱头式的功能开发,很难真的在检测工程方面积累沉淀,在新型风险或者未知攻击行为面前能力很难说,不过实际上关注这部分的用户其实确实也很少就是了。
附很久之前画的一张草图:Linux下的对抗难度金字塔。
安全的本质是什么?这个问题我思考了很久,答案在几年前基本定型了,我的答案是:
保证业务在预期的环境内,执行预期的行为。
目前的基线检测,漏洞发现等是尽可能确保在预期的环境内运行。
而入侵检测是在不断尝试发现小部分非预期的行为。
如何更近一步?我觉得这个答案实际上很早就有了,就是所谓的MAC(mandatory access control),比如基于LSM的SeLinux,但是很显然,这不适用于现有的互联网公司的架构和需求。
我们设想一下,怎样的权限控制体系才是最优解,我们从一个发布到生产环境的二进制的视角看下:
编译成为镜像或二进制,镜像或二进制内有可以确认具体业务ID的凭证;
发布到生产环境后通过确认身份信息,操作系统授予对应的业务的网络和系统权限,比如:仅能访问自己的上下游业务端口,如果没有DBProxy那只能访问自己有权限的数据库等等,文件仅有公共日志目录的写权限,权限体系应该是最小粒度的控制;
如果这时候有外部入侵植入了后门,那么后门因为没有自己的业务身份信息,将不会有任何权限。
如果是一个开发人员登陆到某台服务器上,那么他的视角是:
从堡垒机登陆到某服务器,某服务器根据登陆信息确认该人员是A产品的开发人员,具有对于A产品的读写权限,并且具有基本的系统权限和白名单内的工具访问权限;
开发人员通过对系统日志,A产品日志访问,使用网络工具等工具等故障排查工作,均可以顺利展开;
该开发人员试图通过外网下载后门文件失败,因为不具备非白名单内外网访问权限,又试图自己运行自己编译的后门但失败,因为不具备非白名单二进制运行的权限,尝试修改关键配置如ssh配置失败,理由依然是不具备相关权限,尝试自己写nc脚本进行端口探测失败,因为不具备其他业务访问权限。
如果是一个运维人员的视角是:
如果是高权限的运维同学,那么将会拥有实际Root权限;
如果是一个权限较低的运维同学,可能需要通过命令下发平台进行作业,具体执行的命令需要其他同学审批,如果直接登陆到服务器端依然是Rootless的用户权限。
这些场景下的推演我们可以发现,实际上目前Linux本身的权限体系是比较难支撑这种限制和管理的,因为目前主流的Linux下的权限还是依赖于Linux用户体系,这显然无法应对复杂的权限关系,我认为最佳实践应该是基于LSM(Linux Security Modules)的能力将系统权限上进行业务场景的细分,如分为文件权限,系统权限,特殊权限,网络权限,然后和服务发现,服务权限,人员权限三者进行结合,从而尝试实现人员和应用的最小权限控制。
如果从实际推进落地的角度,可能一开始是只保护系统关键配置如sshd配置,dns配置,网络配置等,然后再逐步扩大保护的范围,比如再扩大到数据库服务关键应用等。
(应用程序的权限控制的草图)
关于XDR主要想聊的问题主要是:目前有多少攻击是无法基于单一安全产品检测到的?XDR排除告警后数据关联能力外,基于检测工程部分有多少价值值得挖掘?我无法给出比例,并且不同厂家下的产品能力可能也不一致,但是我估计可能不会特别高。
当然XDR是有价值的,只是我觉得目前网络,主机,各种Runtime下的检测和产品对于行为本身的理解能力还有非常大的空间可以成长。
目前基于安全知识库的大模型的支持,能做哪些工作?
策略建设部分感觉可以用于弱告警关联分析;
针对cmdline等告警内数据进行解释和总结,提高IR团队效率;
误报分析,判定新告警误报或真实告警的可能性;
通过预制专家库问题不断向Agent(AI智能体)进行提问,来帮助IR团队提高效率,比如:
这个IP在告警数据中最早出现时间是?
这个IP还在那些服务器访问过?
这个IP有哪些端口开放?
这个进程是什么业务的?
还有哪些机器存在这个进程?
这个进程的HASH是否在外部被标记为恶意?
这段Base64 or 16进制是什么意思?
这个日志中的报错内容涉及到哪些Java组件?
这些Java组件历史存在哪些安全漏洞?
其他的常规用法就不赘述了。
实在是没想到自从去年6月离开前团队后,我就基本算是离开反入侵建设领域了,这一年来也是感慨颇多。想到之前有太多未完成的工作和没来得及实践的想法,于是提笔写下了这篇文章,本来想尽可能详尽一些,但是没想到工作量要比预想的大得多,所以最后还是写成了一篇比较概括性的文章。总之希望这篇文章可以帮助其他还在这个领域的小伙伴,也在此感谢长期关注的小伙伴们。
也不知道是不是最后一篇主机安全或入侵检测相关的文章了,希望将来有缘再见吧。