三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

内网不出网环境下Fastjson反序列化漏洞攻击的应急响应与流量特征分析

内网不出网环境下Fastjson反序列化漏洞攻击的应急响应与流量特征分析

1. 项目概述:一次典型的内部网络安全事件

前几天,我处理了一起让我印象深刻的内部安全事件。一个核心业务系统突然出现CPU占用率飙升、响应缓慢的情况,但网络监控显示一切正常,系统并未对外暴露任何端口。这属于典型的“不出网”环境下的安全事件,排查起来比常规的互联网攻击要棘手得多。经过一系列分析,最终定位到问题根源是应用内部一个老版本的Fastjson组件存在反序列化漏洞,被内部某个已被攻陷的跳板机利用,植入了内存Webshell。

这种场景在金融、政务、大型企业的内网中并不少见。系统看似安全地运行在内网,但一旦边界被突破,攻击者在内网横向移动时,这类漏洞就是绝佳的跳板。整个应急响应的过程,就像一次侦探破案,而“流量特征”就是现场留下的最关键的指纹。这次复盘,我就重点聊聊,在无法直接看到外联行为(不出网)的情况下,我是如何从海量的内部应用流量中,抽丝剥茧,锁定Fastjson攻击特征的。这对于从事安全运维、应急响应的朋友来说,是一个非常有价值的实战案例。

2. 应急响应的核心思路与前期研判

当接到系统异常告警时,我的第一反应不是直奔服务器去查日志,而是先建立一个清晰的排查框架。在不出网的环境中,攻击者的目标通常不是直接窃取数据外传(因为出不去),而是进行权限维持、横向移动或作为下一步攻击的跳板。因此,我的核心思路围绕以下几点展开:

2.1 建立“由果溯因”的排查模型

异常现象是CPU高、服务慢。这可能是资源耗尽型攻击(如内存马循环执行消耗CPU),也可能是漏洞利用过程中执行了高负载命令(如编译、文件遍历)。我首先排除了业务高峰和硬件故障,将焦点锁定在应用层。

  1. 进程与线程分析:通过top -Hp [pid]arthas工具的thread命令,查看是哪个Java线程占用了大量CPU。当时发现是几个名为“http-nio-8080-exec-xxx”的线程池线程持续高占用,这提示问题很可能出在处理HTTP请求的业务逻辑上,而非GC或系统线程。
  2. 内存快照初步筛查:使用jmap -histo:live [pid]快速查看存活对象实例。我特别注意是否有大量不常见的、与反序列化或动态类加载相关的类实例,比如TemplatesImplTransformer数组等。虽然这次没直接发现,但这步能为后续分析提供方向。
  3. 网络连接确认:用netstat -antp | grep [pid]仔细检查了该Java进程的所有网络连接。确认只有预期的内部服务调用(如数据库、Redis)和负载均衡器的健康检查连接,没有陌生的、尤其是向非业务地址的TCP连接。这再次印证了“不出网”的判断。

注意:所谓“不出网”,严格来说是指没有主动向互联网或非授权内网地址发起连接的能力。但攻击者可能使用DNS、ICMP、HTTP代理隧道等更隐蔽的方式外联。在初期,我们基于常规TCP连接判断,可以快速缩小范围。

2.2 锁定关键数据源:应用日志与网络流量

在不出网环境下,攻击痕迹主要留存在两个地方:应用日志内部网络流量。很多运维会优先看日志,这没错,但高明的攻击者会清理或绕过日志记录。因此,网络流量镜像分析成为了不可或缺甚至更可靠的手段。

我立即协调网络团队,在核心交换机上对异常服务器的业务网卡进行了流量镜像,将流量导到我的安全分析平台。同时,我开始收集应用日志(如Tomcat的localhost_access_log、应用自身的业务日志)。我的策略是:流量分析为主,日志验证为辅。因为流量是原始通信的复现,难以被彻底抹除。

3. 核心流量特征解析:如何识别Fastjson攻击

流量抓取下来后,面对的是海量的HTTP数据包。如何快速定位恶意流量?这就需要我们对Fastjson反序列化漏洞的利用流量特征有深刻的理解。根据公开的漏洞利用方式和实战经验,我总结了以下几个关键特征点进行筛查:

3.1 特征一:HTTP POST请求体中的“@type”标志

这是Fastjson反序列化漏洞最直接、最核心的特征。Fastjson在解析JSON时,如果启用了AutoType功能(早期版本默认开启),攻击者可以通过在JSON对象中设置@type属性,指定一个任意的、应用ClassPath中存在的类名,Fastjson会尝试实例化这个类。

在流量中如何识别?

  1. 请求方法:通常是POST请求,因为攻击Payload(JSON数据)放在请求体(Body)中。
  2. Content-Type:一般为application/json,这是标准JSON API的格式,本身无异常。
  3. 请求体内容:你需要仔细查看POST数据。恶意Payload的JSON结构里,根对象或嵌套较深的对象中,会有一个键名为@type,其值是一个完整的Java类名。例如:
    { "@type": "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl", "_bytecodes": ["yv66vgAAADQA...(base64编码的恶意字节码)"], "_name": "a.b", "_tfactory": {}, "_outputProperties": {} }
    或者利用Tomcat DBCP的:
    { "@type": "org.apache.tomcat.dbcp.dbcp2.BasicDataSource", "driverClassName": "com.mysql.jdbc.Driver", "driverClassLoader": {"@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"}, "connectionProperties": "user=xxx;password=xxx;..." }

实操心得:在Wireshark或流量分析系统里,你可以直接过滤HTTP POST请求 (http.request.method == "POST"),然后追踪TCP流,查看HTTP请求体。用搜索功能在整个抓包文件中搜索@type这个关键字,效率极高。但要注意,正常的业务请求也可能包含@type字段(如果业务设计如此),所以需要结合类名进行判断。

3.2 特征二:异常的Java类名与依赖利用链

光有@type不够,关键看它指向什么类。攻击者利用的类通常具有以下特点:

  1. 非常用业务类:如com.sun.*,org.apache.xalan.*,org.apache.tomcat.dbcp.*等。这些是JDK或中间件自带的类,正常业务逻辑极少会直接通过JSON反序列化来构造它们。
  2. 涉及类加载或代码执行:如TemplatesImpl(用于加载字节码)、BasicDataSource(用于触发类加载器加载恶意驱动)。在流量中,你会看到这些类名后面跟着一大串经过Base64编码的_bytecodes字段,或者包含driverClassLoader等用于指向恶意类加载器的属性。

排查技巧:我整理了一个“黑名单类名”列表,在流量分析工具中设置告警规则。一旦发现POST数据中出现这些类名,立即高亮标记。例如:

  • com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
  • org.apache.tomcat.dbcp.dbcp2.BasicDataSource
  • org.apache.tomcat.dbcp.dbcp.BasicDataSource(Tomcat 8.0以下)
  • com.sun.rowset.JdbcRowSetImpl(JNDI注入利用链,但在不出网环境可能失效)

3.3 特征三:Payload的编码与结构特征

攻击Payload为了绕过WAF或隐藏意图,经常进行编码处理。

  1. Base64编码_bytecodes字段的值通常是很长的一段Base64字符串,这是Java字节码(.class文件)编码后的结果。在流量中表现为一串由A-Z, a-z, 0-9, +, /, = 组成的密集字符段,非常醒目。
  2. Hex编码:有时也会使用16进制编码。
  3. 嵌套结构:利用链往往需要多个对象嵌套。例如,BasicDataSource利用方式中,driverClassLoader本身又是一个包含@type的JSON对象。在流量中,你会看到多层嵌套的大括号{}结构。

分析方法:在Wireshark中,你可以使用json显示过滤器,它会尝试将TCP流解析为JSON并格式化显示,这样嵌套结构一目了然。对于Base64部分,可以右键选择“导出分组字节流”到一个文件,然后用base64 -d命令解码,再用file命令查看是否是Java类文件(通常显示为“compiled Java class data”)。

3.4 特征四:关联的Webshell流量特征

Fastjson漏洞利用成功后,攻击者通常会植入一个Webshell以便持久化控制。在不出网环境下,这个Webshell的通信流量也混杂在内部HTTP流量中。需要结合已知的Webshell工具流量特征进行关联分析。

  1. 冰蝎(Behinder)特征

    • 静态路径,可变参数:请求URL路径通常固定(如/upload/test.jsp),但每次请求的参数(密码、命令)不同。
    • Content-Type异常:POST请求的Content-Type常为application/octet-streamapplication/x-www-form-urlencoded,但请求体是加密的二进制数据或乱码。
    • Accept头等长:冰蝎客户端的AcceptAccept-Language等头部信息长度固定,而浏览器请求的这些头部长度会因环境略有变化。
    • 连接保持Connection: keep-alive,且会话时间较长。
  2. 哥斯拉(Godzilla)特征

    • Cookie尾部有分号:早期版本在Cookie值的末尾会多一个分号;,这是一个比较独特的特征。
    • 三次响应:哥斯拉的服务端响应包有时会连续收到多个(如3个)TCP包,这与普通HTTP请求的响应模式不同。
    • Payload加密:流量全程加密,无明文,但加密后的数据块大小可能呈现规律性。

关联分析实战:在本次事件中,我首先通过@type特征锁定了攻击注入的时间点(例如,某日10:05:23)。然后,我以这个时间点为起点,向后分析同一源IP(攻击者内网跳板机)对同一目标服务器的后续请求。很快,我就发现了一个固定的URL路径(如/api/v1/health,这是一个原本就存在的健康检查接口,被当作了Webshell的隐藏路径)在频繁被访问,且其POST请求的流量特征(如固定的Content-Type: application/octet-stream)与冰蝎高度吻合。这就形成了完整的攻击证据链:利用Fastjson漏洞注入内存马 -> 通过内存马访问特定路径实现Webshell功能

4. 完整的应急响应与取证操作流程

基于以上的特征分析,我梳理出了一套针对此类不出网Fastjson攻击的标准化应急流程。这套流程不仅用于本次事件的处理,也成为了我们团队后续的响应手册。

4.1 第一步:紧急抑制与隔离

发现确凿攻击流量后,首要任务是止损。

  1. 网络隔离:立即在防火墙或交换机上添加策略,阻断攻击源IP(那个内网跳板机)对受害服务器的所有访问。如果暂时无法精确定位,可以考虑将受害服务器从业务集群中临时下线,或限制其只接受来自管理网段的访问。
  2. 进程保留切勿立即重启服务!重启会清空内存,导致内存Webshell等驻留内存的证据丢失。应该先保存现场。
    • 使用jmap -dump:live,format=b,file=heap.bin [pid]导出完整的堆内存快照。
    • 使用jstack -l [pid] > thread.txt导出线程栈信息。
    • 使用arthasjadscsm命令动态反编译和查看已加载的类,寻找可疑的内存马类。

4.2 第二步:深度取证与漏洞确认

隔离后,进行深入分析,确定漏洞点和影响范围。

  1. 分析内存快照:使用MAT或JProfiler加载heap.bin文件。重点搜索:
    • 可疑的类名:如包含shellmemshellfilteragent等关键词的类。
    • 查找javax.servlet.Filterjavax.servlet.Servlet的实现类实例,检查其filterChainservlet字段是否被替换成了恶意类。
    • 查看TemplatesImpl或动态生成的类加载器实例。
  2. 检查应用依赖:进入服务器,查看应用部署目录下的WEB-INF/lib/或检查项目的pom.xml,确认Fastjson的版本。版本号<= 1.2.80的都存在已知的高危反序列化漏洞。使用shaded打包方式可能会重命名包路径,需要仔细核对。
  3. 日志回溯:结合攻击时间点,翻看应用日志、Tomcat访问日志,寻找是否有相关的错误堆栈信息。有时漏洞利用不成功也会留下ClassNotFoundExceptionNoClassDefFoundError的日志,这同样是重要的攻击证据。
  4. Webshell文件排查:虽然攻击者可能只用了内存马,但仍需检查Web目录下是否有新增的、可疑的JSP、JSPX或静态文件(如图片、文本文件,可能用于存放加密的Payload)。使用find命令结合文件修改时间(-mtime)和特征字符串(-exec grep -l)进行查找。

4.3 第三步:漏洞根除与系统恢复

取证完成后,开始清理和修复。

  1. 清除内存马:最彻底的方法是重启应用服务器。重启前,确保已备份所有取证数据。如果条件不允许立即重启,可以考虑使用Java Agent工具(如Java-Memshell-Scanner)进行动态检测和清除,但这需要较高的技术门槛,且可能不彻底。
  2. 升级/修复Fastjson
    • 首选方案:将Fastjson升级到最新安全版本(如1.2.83及以上)。新版本默认关闭了AutoType,并提供了安全的白名单机制。
    • 临时加固:如果无法立即升级,可以在启动JVM时添加以下参数来全局关闭AutoType:-Dfastjson.parser.autoTypeSupport=false。同时,在代码中明确指定ParserConfig.getGlobalInstance().addAccept("你的包名.")来设置严格的白名单。
  3. 修复被利用的跳板机:通知相关团队对攻击源IP(内网跳板机)进行彻查,清除其上的后门,修复其自身的安全漏洞,防止攻击再次发生。
  4. 恢复服务:在完成漏洞修复、安全加固(如增加WAF规则、配置RASP防护)后,将服务器重新上线,并持续监控一段时间。

4.4 第四步:复盘与加固建议

事件处理完毕,必须进行复盘,提升整体安全水位。

  1. 规则沉淀:将本次发现的攻击流量特征(如特定的@type类名、Webshell的HTTP头特征)固化到IDS/IPS、WAF或流量审计系统中,形成检测规则。
  2. 资产梳理:在全公司范围内扫描所有Java应用,建立Fastjson组件使用清单,强制要求升级或制定迁移计划。
  3. 安全开发规范:推动研发团队在反序列化操作中,使用更安全的Jackson(配置ObjectMapper禁用危险特性)或Gson。如果必须使用Fastjson,强制要求开启SafeMode或配置精确的白名单。
  4. 纵深防御:在不出网环境中,同样需要部署主机安全HIDS、RASP等产品。RASP能在应用运行时深度检测反序列化等危险行为,即使流量加密也能有效防护。

5. 常见问题排查与实战技巧实录

在实际操作中,总会遇到一些预料之外的情况。这里记录几个我踩过的坑和总结的技巧。

5.1 问题一:流量太大,如何快速定位可疑数据包?

场景:全流量镜像一天可能产生TB级数据,逐包分析不现实。技巧

  1. 时间范围聚焦:根据系统异常开始的时间点,前后截取15-30分钟的流量包进行分析。
  2. 协议与端口过滤:先过滤出目标服务器业务端口(如80、8080、8443)的HTTP/HTTPS流量。tcp.port == 8080 && http
  3. 请求方法过滤:重点关注POST请求,特别是请求体较大的POST请求。http.request.method == "POST" && http.content_length > 500(阈值可根据业务调整)。
  4. 关键字搜索:在过滤后的数据包中,直接搜索关键词,如@typeTemplatesImplBasicDataSource_bytecodes记住我(针对Shiro)等。Wireshark支持在分组字节流中搜索。
  5. 使用专业工具:Suricata、Zeek等NIDS工具可以实时解析流量并应用规则。你可以编写自定义规则来匹配Fastjson特征。例如,一个简单的Suricata规则思路:alert http any any -> any any (msg:"Potential Fastjson Exploit"; http.method; content:"POST"; http.header; content:"application/json"; pcre:"/@type\\s*:/"; sid:1000001;)

5.2 问题二:攻击Payload被GZIP压缩了怎么办?

场景:请求头显示Content-Encoding: gzip,导致请求体是乱码,无法直接看到@type解决

  1. Wireshark自动解码:Wireshark通常能自动解码GZIP压缩的HTTP Body。确保在Preferences -> Protocols -> HTTP中启用了“解压GZIP内容”的选项。解码后,就可以像查看明文一样查看JSON内容了。
  2. 手动解压:如果工具没有自动解压,你可以将HTTP请求体的原始字节(从Content-Length后开始,到TCP流结束)复制出来,保存为.gz文件,然后用gzip -d命令解压,或者使用Python的gzip模块解压查看。

5.3 问题三:如何区分恶意的@type和业务正常的@type?

场景:有些基于JSON-RPC或自定义协议的系统,也会使用@type字段来标识对象类型。鉴别方法

  1. 类名白名单:与业务研发确认,系统合法的@type值有哪些。通常只允许如com.company.project.dto.User这样的业务DTO类。任何超出此名单的,特别是JDK、第三方库的类,都应视为高危。
  2. 上下文分析:观察包含@type的请求发生的频率、来源IP、时间。一次性的、来自非常规IP的、在非业务时间发生的请求,恶意可能性极高。
  3. 参数分析:恶意Payload的@type对象后面,通常会跟随着_bytecodesdriverClassLoader等与类加载、代码执行强相关的属性。而业务对象的属性都是业务字段,如usernameorderId等。

5.4 问题四:内存马排查有哪些高级技巧?

场景:重启服务器后,所有内存证据消失,但担心攻击者留有后门文件或计划任务。高级排查

  1. 计划任务与服务:检查系统的crontab (crontab -l)、systemd服务 (systemctl list-units --type=service)、以及/etc/init.d/等目录,看是否有新增的、可疑的定时任务或服务。
  2. 进程文件映射:使用lsof -p [pid]pmap [pid]查看Java进程打开的文件和内存映射。关注是否有从/tmp/dev/shm等临时目录加载的JAR或Class文件。
  3. Java Agent检测:使用jcmd [pid] VM.command_line查看JVM启动参数,检查是否有未知的-javaagent参数。也可以检查$JAVA_HOME/lib$JAVA_HOME/jre/lib目录下的instrument相关JAR包是否被篡改。
  4. 网络连接深度检查:使用ss -antpnetstat结合lsof,不仅看ESTABLISHED状态的连接,还要看LISTEN和CLOSE_WAIT状态的连接。有些后门会绑定一个本地端口等待连接。

处理这次不出网的Fastjson漏洞攻击,让我深刻体会到,在纵深防御体系中,流量分析能力就像安全人员的“火眼金睛”。尤其是在内网环境中,攻击者以为隐藏在网络边界之后就可以为所欲为,殊不知其攻击动作在流量层面会留下难以磨灭的痕迹。掌握这些漏洞和工具的流量特征,构建基于流量的实时检测与回溯能力,是从被动响应转向主动防御的关键一步。这件事之后,我们团队花了大力气优化了内部的流量审计平台,将Fastjson、Log4j2、Shiro等常见漏洞的利用特征都做成了自动化的检测规则,现在再有类似的情况,告警会在几分钟内就发出来,响应效率提升了不止一个量级。

← 返回列表