张金莉, 陈星辰, 王晓蕾, 陈庆旺, 代 峰, 李香龙,冯 云, 崔 翔,3
1中国科学院信息工程研究所 北京 中国 100093
2中国科学院大学网络空间安全学院 北京 中国 100049
3广州大学网络空间先进技术研究院 广州 中国 510006
当今世界, 互联网已渗透到人们生活的方方面面, 甚至影响着全球经济、政治、文化和社会的发展。Web作为互联网上最典型、最主流的应用之一, 在社会活动、经济活动中承担着重要角色, 各种高价值的数据和信息经由Web接收、处理、存储和转发。Web给人们带来可观经济效益和广泛社会影响的同时,也成为网络攻击的主要目标。攻击者在入侵一个网站后, 通常会上传一个Webshell来持久化地控制Web服务器。
研究表明[1], 将近一半的攻击者在发现Web应用上传漏洞后会上传一个Webshell。攻击者上传的Webshell与网站管理员远程管理所使用的功能类似,通过HTTP请求接收命令并提供响应, 可穿越防火墙, 难以检测。Webshell最初包含的功能强大, 但是文件较大、服务器端代码较多; 针对网站对文件大小上传的限制, 逐渐演变为代码量小、只有单一上传文件功能的小文件; 为了更加隐蔽, Webshell配合管理工具, 只需简单的脚本执行语句即可; 为了更好的躲避检测, Webshell还采用了加密、混淆等手段。但是随着近年来攻防双方的博弈, Webshell获得了越来越多的关注, 其检测方法也更加健全, 包括文本特征检测、行为特征分析、流量检测、日志检测、统计学检测等方法, 并结合机器学习、深度学习等算法提高了检测的准确率, 以及XDR(Extended Detection and Response, 扩展检测和响应)[2]等防御技术的提出,使得传统的以文件形式落地的Webshell生存空间越来越小。因此, 内存型Webshell应运而生。
内存型Webshell也被称为无文件Webshell, 是无文件攻击的一种。无文件攻击由来已久, 但是随着近年来攻防演练的热度再次被提起。据亚信安全的2020威胁情报态势分析[3], 病毒攻击的方式发生了很大的变化, 大多数采用无文件攻击技术, 报告数据显示, 在成功入侵的攻击事件中, 有80%是通过无文件攻击完成的, 传统的防病毒软件对此攻击基本无效。无文件攻击属于一种影响力非常大的安全威胁, 攻击者不会在目标主机的磁盘上写入任何可执行文件, 而是通过各种脚本执行, 因此得名“无文件攻击”。无文件攻击执行后不会留下任何痕迹, 所以难以被检测和清除。
内存型Webshell是在内存中写入恶意后门, 不会有文件落地, 利用中间件的进程执行这些恶意代码, 达到远程并持久控制Web服务器的目的。早在2017年[4], 内存型Webshell已经初露头角, 研究人员通过调试Tomcat代码, 在运行时动态插入Filter和Valve, 可以达到隐藏shell的效果, 只是这两种方法在Tomcat重启后会失效。2018年[5], 研究人员利用agent技术通过进程注入方式实现了内存型Webshell,并且使用ShutdownHook机制实现服务重启后Webshell复活的功能, 进一步拓宽了内存马的使用场景。2020年, 随着攻防演练的兴起, 内存型Webshell再次回归视野。乘着Java反序列化漏洞的东风, 内存型Webshell引发了更多的关注。2020年[6],研究人员基于特定框架Java Spring MVC的利用, 构造了一个Spring Controller Webshell, 利用多种技术注入到内存中, 实现无文件攻击。2021年[7], 研究人员利用Shiro的反序列化漏洞, 实现了内存型Webshell的注入及Tomcat通用回显。除此之外, 常用的Webshell管理工具, 如冰蝎、哥斯拉、蚁剑等, 都在最新版本中增加了内存型Webshell注入的功能。内存型Webshell已经成为了攻击方的必备工具, 针对内存型Webshell的检测和防护也越来越受重视。
目前针对内存型Webshell的攻击主要活跃在Java Web的框架、中间件等上, 且Java以其灵活、健壮、跨平台的特点, 是主流的编程语言。因此, 本文主要研究面向Java的内存型Webshell检测技术。通过收集近年来公开的内存型Webshell样本, 进行实验分析, 构建内存型Webshell模型, 提出一种高对抗内存型Webshell, 结合RASP动态检测技术和深度学习静态特征检测技术, 对高对抗内存型Webshell进行检测。本文的主要贡献如下:
(1) 分析内存型Webshell原理, 总结其不同阶段的行为特征, 构建内存型Webshell的威胁模型, 并提出一种高对抗内存型Webshell。
(2) 提出一种基于RASP技术和数据流分析的动态行为检测方法, 在不影响目标应用程序正常运行的情况下, 实时检测内存型Webshell。
(3) 提出一种基于文本特征的深度学习静态检测算法, 与动态方法结合, 提升对高对抗内存型Webshell的检测效率。
(4) 设计多组实验, 对本文检测方法进行测试评估。实验表明本文方法检测高对抗内存型Webshell准确率达96.45%, 性能消耗为7.74%, 具有可行性。
本文的其余部分组织如下: 第二章介绍了相关工作; 第三章讨论了内存型Webshell的威胁模型;第四章详细介绍了针对高对抗内存型Webshell的检测方法; 第五章是本文检测方法的实验评估与分析;第六章是对本文方法的总结与展望。
2.1 学术界Webshell检测方法
内存型Webshell是Webshell的一种, 学术界针对Webshell的检测方法有很多。从检测方式的角度分为静态检测和动态检测两类。从检测对象角度分为文本内容检测、流量检测、日志检测、行为特征检测、统计学检测等五类。如表1所示。
表1 Webshell检测相关工作总结Table 1 Summary of work related to Webshell detection
静态检测是不执行样本而是通过获取的检测对象进行分析, 挖掘对象的特征, 包括文本内容特征、日志访问特征、统计学特性等, 并结合机器学习[8-9]或深度学习[10-11]技术进行检测。静态检测又分为基于文本内容的检测、基于日志的检测、基于统计学的检测等方法。(1)基于文本内容的检测直接针对源代码进行特征工程, 通过提取词法、语法、语义等特征检测Webshell。该方法对已知的Webshell检测准确率高, 快速方便, 部署简单, 但只能检测已知特征的Webshell, 漏报率、误报率高。(2)基于日志的检测是针对Webshell访问网站后在Web日志中留下的页面访问数据, 通过对大量的日志文件建立请求模型从而检测出异常文件。该方法产生大量日志, 存在漏报,且具有一定滞后性。(3)基于统计学的检测是通过一些统计值来区分正常文件与恶意Webshell。重心在于识别混淆代码, 对未经模糊处理的代码检测机制较为透明, 误报漏报多。
Webshell传到服务器后, 攻击者总要去执行它,动态检测是根据Webshell执行时刻表现出来的行为模式、网络特性等进行检测。动态检测又分为基于流量的检测、基于行为的检测。(1)基于流量的检测对通信过程中Payload流量表现出的异常特征进行提取并分析, 从而实时检测网站变化。该方法部署成本高, 无法检测加密流量内容。(2)基于行为的检测是针对脚本在系统环境中的解析过程进行分析, 通常带有命令执行、文件操作和数据库操作等行为特征, 从而检测异常行为。该检测方法准确率相对较高, 但资源消耗较大, 检测效率较低。
目前学术界对内存型Webshell检测的研究极少,已有的检测方法无法适用于内存型Webshell。
2.2 内存型Webshell检测产品
攻防演练的热度升级备受工业界的关注, 许多工业界与时俱进地在产品中增加内存型Webshell的防御功能。
边界无限的靖云甲·RASP作为一款网络攻防产品[23], 能够对内存型Webshell进行防御, 以Java为例, 该功能是通过RASP在程序内部获取API接口信息, 利用Agent周期性地对JVM内存中的API进行风险筛查, 然后上报存在风险的类。但是该方法存在一定滞后性, 不能实时检测内存型Webshell的注入及存在。
微步在线的OneEDR是一款针对主机的入侵检测与响应的终端安全防护平台[24], 利用Agent在终端收集系统行为日志, 并结合威胁情报, 实现对主机的入侵发现与响应。针对无文件攻击方式的频繁出现, OneEDR集成了针对Java平台的内存型Webshell检测功能。针对Agent类内存型Webshell,OneEDR同样利用Java Agent技术对运行的JVM进行检测, 针对可疑高危的Class再做进一步检测。OneEDR也没有对用户实时的请求进行内存型Webshell的检测。
河马是一款专注于Webshell查杀的检测工具[25],拥有海量的Webshell样本及自主查杀的技术, 采用传统特征, 并结合深度检测、机器学习、云端大数据多引擎检测技术。河马1.0内测版本开始支持内存型Webshell的检测, 逐渐增加对冰蝎、哥斯拉内存型Webshell的检测功能。河马对内存型Webshell的检测也依赖于Java Agent技术, 将检测代码注入到Web服务的Java进程中对其进行恶意代码检测。河马目前还未发布官方版的内存型Webshell检测工具。
工业界针对内存型Webshell的检测产品虽然响应较快, 但还处于起步阶段, 检测方案并不全面, 还在持续优化过程中, 并且大多数产品没有开源。
2.3 Java RASP技术
RASP[26]是一种注入到应用程序内部或应用程序运行时环境的安全技术, 与应用程序融为一体,能够实时检测和阻断攻击。与传统的WAF(Web Application Firewall)技术相比, RASP技术准确性更高,更可靠。WAF是基于模式匹配并仅对所有输入流量进行检测, 而RASP是在发生攻击的关键节点处同时关注输入和输出, 能够根据数据流分析输入在应用程序内部的行为, 从而精准拦截攻击。RASP技术已在Web安全及漏洞检测领域被广泛应用, 例如在Web安全检测[27]、脚本注入安全[28]、Web框架漏洞检测[29]、智能合约漏洞防护[30]等方面得到了有效解决方案。
对Java而言, RASP技术是通过Java Agent方式实现的。Java Agent允许JVM在加载class文件之前,对其字节码进行修改, 通过在程序启动前注入RASP逻辑; 同时也支持对已加载的class文件进行重新加载, 通过attach方式在程序运行时附加Agent, 动态注入RASP逻辑。
Java RASP的技术实现主要依赖于JVMTI(JVM Tool Interface)、Instrumentation(Java Agent API)、字节码操作框架等。
JVMTI是一套由Java虚拟机提供的本地编程接口集合, 可以提供JVM相关工具开发的接口, 可以对虚拟机内部状态进行监测、分析, 并能控制JVM应用程序的执行。JVMTI的原理是在JVM内部的一些事件上进行了埋点, 外部程序通过实现一个JVMTI Agent, 并将Agent注册到JVM中, 当事件被触发时, JVM会回调Agent的方法来实现用户逻辑。并非所有JVM都支持JVMTI, 但一些主流虚拟机如Sun、IBM等都提供了JVMTI实现。但是基于JVMTI的开发是通过C/C++语言编写的Agent来实现的, 对于Java开发人员不太友好。
JDK 1.5开始, Java引入了Instrumentation机制。Instrumentation是由Java提供的监测运行在JVM程序的API, 可以基于Java编写Agent来监控或操作JVM。Instrumentation的底层实现是依赖于JVMTI。Instrumentation可以实现在已有的类上修改或插入额外的字节码来增强类的逻辑, 但这些实现不会改变原程序的状态或行为。Instrumentation提供两种方式注入Agent(即RASP逻辑), 一种是premain模式在主程序运行前注入, 另一种是agentmain模式, 在主程序运行时注入。
Java RASP除了依赖JVMTI和Instrumentation来完成Java Agent的编写外, 还需要利用字节码操作框架来完成相应的Hook操作, 即对已经是字节码的class文件进行操作, 主要有两种工具, ASM和Javassist。ASM字节码操作框架, 主要是在指令层面上操作字节码, 门槛高, 但体积小速度快, 性能好。Javassist重点在源代码层面上操作字节码, 提供了源代码级API对字节码操作, 相比ASM操作简单, 但执行效率慢。
3.1 内存型Webshell原理
内存型Webshell是无文件攻击的一种, 是将恶意代码注入到内存中, 利用中间件的进程执行某些恶意代码, 没有文件落地, 即服务器上不存在可远程访问的Webshell文件。其原理如图1所示, 攻击者首先构造与请求处理相关的恶意代码, 包括注册恶意组件的代码、修改已有类逻辑的代码, 通过漏洞等场景执行恶意代码, 成功添加恶意组件到JVM进程或修改内存中已有类的逻辑, 将恶意代码驻留在系统内存中, 因此得名内存型Webshell。注入成功后,攻击者通过访问特定(带参数的)URL, 达到命令执行、文件操作、数据库操作等远程控制Web服务器的目的。Java的反射机制和Instrumentation机制为内存型Webshell提供了良好的植入方式。根据内存型Webshell的利用技术不同, 将其分为两类, 一类是组件类(也称为非Agent类), 一类是Agent类。
图1 内存型Webshell原理Figure 1 Memory Webshell principle
(1) 组件类
组件类的内存型Webshell主要是通过动态注册一个包含恶意代码的组件到运行内存中, 将恶意代码长期驻留在内存中。常见的组件包括Java Web的三大组件, 分别为Filter、Servlet、Listener。除此之外, 还包括特定框架和容器的特有组件, 例如Spring框架的Controller、Interceptor组件, Tomcat容器的Valve组件等。
利用场景一般通过反序列化等漏洞直接注入恶意组件到内存, 或通过文件上传漏洞上传一个JSP文件(包含恶意组件注入程序), 执行后删除文件, 达到无文件Webshell的效果。该类型Webshell要求目标环境可以执行任意Java代码, 对目标环境依赖性较强, 通用性差。
其实现过程如图2所示。首先创建一个组件, 添加恶意逻辑到其中, 然后通过反序列化、代码执行等漏洞将注册组件代码执行, 注入到特定环境的目标应用程序中, 最后通过访问固定URL或带固定参数的URL来执行Payload, 达到Webshell的特权状态。
图2 组件类Webshell实现过程Figure 2 Components type Webshell implementation process
(2) Agent类
Agent类的内存型Webshell主要是利用Java Agent技术动态修改JVM中加载的类文件, 将恶意代码注入其中, 该类在磁盘上还是正常文件, 只有在运行内存中才会包含恶意代码, 达到无文件落地。
Agent类的内存型Webshell也包括premain和agentmain两种注入方式, 但是实际环境中, 目标应用程序一般都是已启动状态, 只能使用agentmain的方式注入。利用场景通常是通过漏洞上传一个Jar文件, 执行成功后删除该文件。该类型Webshell在Java虚拟机层操作, 通用性强。
其实现过程如图3所示。首先通过漏洞上传一个Jar包, 用于加载Java Agent程序, 将Jar包注入到目标程序运行内存后, 就可以删除该文件。然后通过访问固定URL或带固定参数的URL, 恶意逻辑会利用Agent技术修改类字节码, 再执行Payload, 达到Webshell的特权状态。
图3 Agent类Webshell实现过程Figure 3 Agent type Webshell implementation process
(3) 两种类型异同
组件类和Agent类的内存型Webshell, 相同之处都是利用漏洞将恶意程序注入目标程序内存中, 然后通过访问特定的请求连接Webshell, 执行Payload,达到各种控制服务器的特权状态的目的。
不同之处在于, 前者有创建并注册组件的动态过程, 新增了一个组件, 组件中包含恶意逻辑; 而后者是利用Agent技术直接修改JVM中已经存在的类的逻辑, 不产生新的类。
3.2 形式化定义
内存型Webshell是一种网站后门, 根据研究人员[31-32]对后门的定义, 可以将后门分为输入源、触发器、攻击载荷、特权状态4个组件。本节从这4个组件出发, 结合内存型Webshell的原理, 对其进行形式化定义。
如图4所示, 目标程序中存在内存型Webshell(θ)可表示为:
图4 后门模型Figure 4 Backdoor model
S表示目标程序的全部有限状态集合。I表示输入源, 即初始状态集合, I S⊆。E表示内存型Webshell触发后到达的特权状态集合, E⊆S。t表示状态转移函数, 也是触发器, 有t(I, c) = S, c表示状态转移条件。Σ表示后门触发条件。p为攻击载荷, 表示为达到特权状态而采用的有效代码。特别地, 当存在i∈I, c = Σ, e∈E, 且攻击载荷p被执行, 使得t(i, Σ) = e时, 表示后门被触发, 存在内存型Webshell。n表示后门没有被触发时的正常转移状态, n∈S。
输入源表示激活后门触发器的输入来源。内存型Webshell的输入源I包括(1)Java Web组件, 例如servlet、filter、listener等; (2)Java容器组件, 例如tomcat valve组件、weblogic的组件; (3)Java框架组件, Java的框架有很多, 包括spring、springboot等, 例如spring框架的controller组件; (4)二进制, 例如Agent类内存型Webshell的字节码。
触发器在满足一定条件的情况下, 会执行攻击载荷, 进而达到某种特权状态。内存型Webshell的触发器一般为反序列化漏洞、文件上传漏洞、RCE漏洞等。
攻击载荷p是一段有效功能代码, 是Webshell后续控制服务器的关键部分, 决定了特权状态的存在形式。
内存型Webshell触发后到达的特权状态集合E与一般的Webshell的特权状态相同, 都是为了达到远程控制服务器的目的, 包括系统命令执行、任意操作服务器上的文件、读取数据库数据等状态。
通过对内存型Webshell的原理分析及形式化定义, 本文将从内存型Webshell实现过程中的输入源、触发器、攻击载荷、特权状态4个方面进行分析, 实现内存型Webshell的检测。
3.3 威胁模型
内存型Webshell具有持久性、隐蔽性, 并且将在上节提到的4个组件中不断增强, 本节从攻击载荷、触发器两方面进行分析。
(1) 攻击载荷
目前公开的内存型Webshell样本基本都是明文的Payload, 主要关注点在Webshell存在于内存中而非磁盘上, 过于关注输入源、触发器的状态, 而忽略了攻击载荷的形态。随着无文件检测技术的不断发展和提升, 内存型Webshell将会在Payload上做更多的变形。
我们定义高对抗内存型Webshell, 为具备加密、编码、混淆等免杀功能的高级内存型Webshell。我们假设攻击者会使用高级具备免杀功能的内存型Webshell样本, 因此本文主要检测高对抗内存型Webshell攻击。由于高对抗内存型Webshell是基于内存型Webshell对攻击载荷的改造升级, 本文的静态检测方法主要检测高对抗内存型Webshell攻击,动态检测方法不对攻击载荷进行分析, 但依然能够对高对抗内存型Webshell的输入源、触发器、特权状态等行为特征进行检测, 因此文本主要面向高对抗内存型Webshell进行检测。
攻击者通常使用流行的冰蝎、哥斯拉等工具快捷地注入Agent类内存型Webshell, 并且注入的样本所属的包名为工具默认的, 例如net.rebeyond、com.metasploit等, 容易被检测到。我们假设高对抗内存型Webshell攻击者会修改默认的常见工具包名以绕过简单的字符串匹配等检测。我们避免因包名过滤造成的漏报, 而从其他方面进行检测。
(2) 触发器
我们假设攻击者在植入组件类高对抗内存型Webshell时, 触发器的场景包括1)通过反序列化漏洞等注入恶意字节码, 2)通过RMI、LDAP等远程方法调用恶意类, 3)通过文件上传等漏洞注入恶意JSP文件。前两种方式是无文件攻击, 目标应用程序的磁盘没有恶意文件落地, 但是也考虑攻击者故意写入磁盘文件的情况, 以绕过无文件这一特性。第三种方式的JSP文件在执行过程中, 会先被编译成class文件, 然后再执行程序, 即使执行完可以删除文件达到无文件攻击, 但动态检测是在执行过程中进行的,执行过程中不可避免的有文件落地。检测时需针对以上情况分别考虑。
本节针对内存型Webshell的原理和特征, 提出一种基于RASP技术的动静态结合的高对抗内存型Webshell检测方法, 其总体流程如图5所示。首先对应用程序进行监测, 在有用户请求的情况下, 利用RASP监测技术获取监测函数的上下文信息。根据获取的行为特征, 结合磁盘是否存在文件、黑白名单过滤、数据流分析技术进行动态特征检测; 获取JVM中所有加载的类, 通过特征过滤筛选出高危类, 利用深度网络ResNet50分类模型进行静态文本特征检测。动态检测中监测到的非JS场景的新增组件类及defineClass函数输入到静态检测中, 动静态检测方法结合判断请求或系统内部是否存在高对抗内存型Webshell。最后根据判定结果进行处置并发出告警信息。
图5 高对抗内存型Webshell检测框架Figure 5 High-adversarial memory Webshell detection framework
4.1 RASP监测技术
RASP技术是一种动态实时监测技术, 可以在不影响目标应用程序正常运行的前提下, 对其请求过程中的函数进行字节码增强。RASP通过Hook函数对其设置探针来进行监测, 从而收集函数运行时的上下文信息, 包括函数参数、函数返回值、函数调用栈等信息。针对内存型Webshell, RASP主要监测两类函数, 一类是与输入源中的组件相关的注册组件类函数, 另一类是为达到特权状态所请求的函数,称为特权类函数。结合内存型Webshell的原理可知,前者主要关注其在注入过程中的函数请求, 后者主要关注注入成功后访问Webshell时的函数请求。
(1) 注册组件类函数
内存型Webshell的输入源中包含组件, 该类型的Webshell需要依靠组件将Webshell驻留在运行内存中, 所以会通过调用注册组件类的方法以达到目的, 而其他的正常行为或攻击行为通常不会通过该方式添加一个组件。注册组件类函数通过调用某个类可以直接在内存中生成一个新的组件, 不同类型的组件注册的方式不同, 调用的函数也不同。以Tomcat添加Filter为例, 在内存型Webshell的实际环境中, Filter并不会按照在web.xml中注册的方式添加, 而是通过反射机制进行动态注册。
注册Tomcat的Filter组件关键步骤是:
1) 通过反射获取ServletContext对象。
2) 实例化一个包含Payload的恶意Filter对象。
3) 利用FilterDef对Filter进行封装, 定义其名称和类名等, 将FilterDef添加到FilterDefs中。
4) 创建FilterMap, 设置Filter和拦截的URL的映射关系, 并将该FilterMap作为第一个过滤器添加到FilterMaps中。
5) 创建FilterConfig, 封装FilterDef对象, 并添加到FilterConfigs中。
6) 最后把FilterDefs、FilterMaps、FilterConfigs注入到StandardContex即可。
整个过程中与Filter组件注册紧密相关的函数在第3步中, 如图6所示, 包括setFilter()和setFilterClass()方法, 这两个方法可以通过参数信息分别获取实例化的Filter对象和Filter的类名。
图6 Filter组件注册相关函数Figure 6 Filter component registers related functions
注册组件的方法根据不同容器或框架使用不同的函数, 这些方法根据参数等信息可获取新增的组件类名、类实例等信息。通过Hook这些函数, 可以在内存型Webshell注入过程中就检测和拦截。表2总结了部分注册组件类函数监测点。
表2 注册组件类函数Table 2 Register component class functions
(2) 特权类函数
内存型Webshell与普通的Webshell相似, 最终目标都是持久化控制目标服务器, 达到一定的特权状态。该特权状态包括任意系统命令执行、操作服务器文件、对数据库操作等恶意行为状态, 涉及的特权类函数包括命令执行函数、文件操作函数、数据库操作函数、编解码函数等敏感操作函数。通过Hook相关函数, 可以检测和拦截Webshell对系统造成危害行为的操作。除此之外, 针对内存型Webshell的特性, 还包括一类特殊函数。例如, 一般情况下, 内存型Webshell会随着组件的生命周期在Web服务器关闭或重启后, 也会随之销毁, 但是攻击者针对这一缺陷, 通过添加JVM的关闭钩子ShutdownHook, 使得服务器在关闭时启动一个线程将内存型Webshell落地磁盘, 当服务器重启后, 磁盘文件自动执行再删除, 内存型Webshell就可以长期驻留在运行内存中。在startUpClass中植入内存型Webshell, 同样可以做到持久化的效果。还有些内存型Webshell为了更隐蔽地达到特权状态, 在新增的组件类或Agent方式修改的类中通过defineClass方法加载字节码文件产生一个新的类, 在新的类中注入恶意代码, 使得检测难度增加, 攻击更加隐蔽。
通过监测特权类函数可以获取其上下文信息,例如命令执行函数可以获取执行的系统命令, 文件操作函数可获取操作的文件类型、文件名, 数据库操作函数可获取执行的数据库语句, 编解码函数可获取编解码的内容, 特殊函数可获取类线程、类名、执行的类字节码等信息。表3总结了部分特权类函数监测点。
表3 特权类函数Table 3 Privileged functions
除了对注册组件类函数和特权类函数监测外,RASP还需要监测Web请求类函数。一方面组件类的内存型Webshell一般是在有请求的情况下发生的,需要对请求进行标记; 另一方面需要获取Web请求的上下文信息用于告警处置。表4是请求类函数及其上下文信息。
表4 请求类函数Table 4 Request functions
4.2 动态特征检测算法
根据内存型Webshell的原理, 一般会注册一个新的组件到内存中, 达到磁盘上无文件的目的。所以可以根据新增组件和磁盘无文件两个特性判断是否为内存型Webshell。因为正常的服务请求或者其他的攻击行为一般不会新增一个Java Web组件, 这是内存型Webshell的独有特性。可以根据RASP监测的注册组件类函数, 获取上下文信息, 从拦截的函数参数中获取新增的组件类。然后检测磁盘上是否存在对应类文件, 根据触发器的不同场景, 分3种情况讨论。1)如果新增组件是通过字节码注入或远程方法调用实现, 并且磁盘上没有对应类文件, 则判定为内存型Webshell。2)新增组件是通过字节码注入或远程方法调用实现, 但是, 有的攻击者为了规避磁盘无文件这一特征, 故意将字节码文件写入到ClassPath路径下, 并在web.xml文件中配置相关信息, 来绕过检测。针对这种情况, 如果检查到磁盘上存在新增的组件类, 不能确定为非内存型Webshell,需要针对存在的新增类, 结合静态特征检测进一步判断, 将在下一节讨论。3)新增组件是通过JSP文件实现, 则JSP文件执行时, 即新增组件注册时, 一定会产生磁盘类文件, 动态检测是在新增组件注册时进行检测的, 无需检查磁盘是否有文件, 直接判定为内存型Webshell。
内存型Webshell在注入到目标应用程序之后,也跟正常Webshell一样, 最终会触发特权类函数来操控目标服务器, 例如操作文件、执行系统命令等行为或执行关闭钩子函数使Webshell更加持久化。但是对于应用程序内部也有可能执行特权类函数, 所以需要根据RASP监测获取的上下文信息判断是否为具有敏感行为的特权类函数以及是否有请求。应用程序内部的特权类函数调用, 例如命令类函数调用是程序内部函数的相互调用, 而内存型Webshell通常是在有请求的条件下进行的。通过设置黑白名单进一步过滤敏感行为, 如文件类特权函数设置上传文件后缀白名单, Webshell常访问的路径范围设置黑名单等。即使是敏感的行为操作也可能是其他攻击类型, 根据内存型Webshell的特性, 设计动态特征检测算法, 如图7所示。
图7 动态特征检测算法Figure 7 Dynamic feature detection algorithms
动态特征检测是在有请求的情况下对其行为进行检测的, 通过RASP对注册组件类函数和特权类函数的监测来检测内存型Webshell。当请求发生时,如果触发了注册组件类函数, 则获取其上下文信息,主要通过参数信息分析得到新增的组件类, 结合无文件的特性, 判断磁盘上是否存在新增的类文件。针对非JSP文件注册的组件类, 如果不存在相应的类文件, 则判定该组件类即为内存型Webshell, 如果存在, 则将该组件类标记为高危类需要进行静态特征检测。针对JSP文件注册的组件类, 无需检测类文件是否存在, 直接判定该组件类即为内存型Webshell。
如果在请求下触发了除defineClass之外的特权类函数的探针, 首先根据参数等上下文信息进行黑白名单的过滤, 如果是敏感行为, 则进一步获取调用栈等信息, 利用自下而上的数据流分析技术[33-34]计算特权类函数到注册组件类函数新增的组件之间是否可达。如果可达, 根据内存型Webshell的原理,说明该后门首先通过注册组件类函数注册了一个组件到内存中, 然后再次利用了该后门并触发了特权类函数, 则判定新增的组件类为内存型Webshell; 如果不可达, 则极有可能是其他危险类攻击触发了特权类函数。如果是defineClass的特权类函数, 不能根据参数等上下文信息直接判断是否为敏感行为, 需要由下一节的静态特征检测算法进一步根据内容进行检测。
动态特征检测算法的伪代码如算法1所示。输入包括请求上下文、注册组件类函数的上下文、特权类函数的上下文, 以及用于过滤敏感行为的黑白名单列表。输出为算法的判定结果。
算法1.动态特征检测算法.
输入: 请求上下文reqContext、注册组件类函数上下文compContext、特权类函数上下文priContext、黑白名单列表list
4.3 静态特征检测算法
RASP针对内存型Webshell的特权状态以及组件类内存型Webshell的输入源进行了监测, 并根据其特性进行了动态特征检测。由于Agent类内存型Webshell不会动态注册组件植入后门, 而是直接修改JVM中已经存在的类, 因此针对Agent类内存型Webshell需要获取JVM中已加载的类文件, 然后结合静态特征对其攻击载荷进行检测。
由于JVM中加载的类很多, 如果全部获取并检测则会影响检测效率, 因此根据内存型Webshell的原理和特性, 我们尝试在正常请求的完整函数调用栈上使用javassist框架对函数依次进行Agent字节码修改, 修改成功的类可能被攻击者利用为内存型Webshell攻击, 经过多轮请求测试, 提取了JVM中五种类型的高危类, 包括类名、父类、接口、ClassLoader、注解。
(1) 类名, 包含容易被修改的类的名字以及Agent类Webshell常使用的特殊的类名字。
(2) 父类, Webshell如果是自定义的类, 则需要继承父类以重写相应的方法执行恶意功能。
(3) 接口, 内存型Webshell为了最终能够执行恶意功能, 会实现某些接口。
(4) ClassLoader, 内存型Webshell使用的ClassLoader一般与反序列化、代码执行等漏洞相关,与正常的类加载器有所区别。
(5) 注解, 内存型Webshell实现时会使用一些注解, 例如Spring的Controller类型的Webshell通常使用Spring的注解来声明。
表5列举了JVM中部分内存型Webshell相关的高危类。
表5 内存型Webshell高危类Table 5 High-risk classess of memory Webshell
静态特征检测算法如图8所示。首先获取JVM中加载的所有类, 然后根据特征筛选出5种类型的高危类, 对高危类进一步检测。除此之外,高危类还包括动态特征检测中, 通过请求新增的组件类, 并且该组件类是通过非JSP注册的在磁盘上存在class文件的情况, 该新增的组件类也被归为高危类。
图8 静态特征检测算法Figure 8 Static feature detection algorithms
另外动态特征检测过程中, 如果触发的特权类函数是defineClass函数, 则根据RASP监测获取其上下文信息, 根据其加载的字节码文件进一步检测。
为了识别高对抗内存型Webshell的攻击载荷,对高危类或defineClass获取的字节码文件进行深度学习模型检测。使用深度学习, 通过学习文件中的鲁棒性特征, 实现对目标文件快速准确的识别。本文使用深度模型的核心思想是将文件转化成灰度图像进行学习, 从图像的角度捕获文件中的恶意特征, 从而实现对Webshell的识别。由于内存型Webshell与普通Webshell的Payload基本一致, 而内存型Webshell的样本较少, 因此样本集中包含了两者, 并且包含了具备免杀功能的普通Webshell样本, 以及自定义编写的具备免杀功能的内存型Webshell样本。最后深度模型所使用的数据集包含606个Webshell样本和819个白样本, 样本格式为“.jsp”或“.java”。整个数据集按照8:2划分训练集和测试集, 使用经典的深度网络ResNet50[35]作为分类模型。
模型训练之前, 先进行数据预处理。将样本以二进制的形式读取, 并以灰度图的形式保存。最终数据集中的每一个文件都对应一张灰度图, 用灰度图进行模型训练和测试。在训练阶段, 用训练集对应的灰度图进行网络的学习, 使用Adam优化器训练150轮次(Epoch), 其中学习率(Learning_rate)设置为0.001、批量大小(Batch_size)为32。每训练1个轮次, 都使用测试集对应的灰度图进行测试, 并记录准确率。经过不断的学习, 深度模型具备了对Webshell样本图像和白样本图像的分类能力。保存测试结果最优的那一轮次的模型用于最终任务的检测。在实际检测中, 首先将要检测的“.class”文件或字节码文件反编译为“.java”文件, 然后将“.java”文件转化成的灰度图输入深度检测模型中, 模型输出是Webshell样本或白样本。
静态特征检测算法的伪代码如算法2所示。以JVM中加载的所有类作为输入, 以筛选出高危类,同时高危类中也包含动态检测过程中输出的高危类;输入还包括defineClass函数中的字节码文件。最后输出为算法的判断结果。
算法2.静态特征检测算法.
输入: JVM加载类classes、defineClass的字节码文件bytecode
4.4 告警处置
告警处置用于对内存型Webshell检测结果进一步处理。针对有请求的动态检测结果, 在RASP监测模块已经对请求类函数进行了监测, 如果检测结果为正常, 则返回原始响应页面, 如果检测结果为内存型Webshell或者其他高危行为, 则对请求拦截并返回一个自定义的页面, 同时使用SimpleEmail[36]发送邮件告警的通知。针对JVM加载类的静态检测结果, 直接通过邮件方式发出告警通知管理人员。
告警通知的内容根据两种检测结果的不同, 如表6所示。
表6 告警信息内容Table 6 Alarm information content
本章通过内存型Webshell请求和正常请求对本文提出的基于RASP动静态结合的高对抗内存型Webshell检测方法进行评估。从准确率、精确率、召回率、F1值4个指标评估本文方法的检测能力, 并结合实际利用场景对两种类型Webshell的检测结果分析, 从时间开销和资源消耗两方面评估本文方法的检测性能, 最后对检测方法进行讨论。
5.1 实验环境与数据
本文的检测方法是运行时检测, 因此需要针对易被内存型Webshell注入的Java常见中间件和框架搭建Web测试环境进行测试, 包括Tomcat、Spring Web、Weblogic等环境。测试环境使用1台服务器, 操作系统为Ubuntu 20.04, 配置为双核处理器和16G内存。
实验采取的数据集来自于GitHub上的样本, 以及Webshell的管理工具, 例如冰蝎、哥斯拉等。样本覆盖组件类和Agent类的内存型Webshell, 组件类包括Filter、Servlet、Listener、Valve、Controller、Interceptor等。部分数据集来源如表7所示。
表7 部分数据来源Table 7 Partial dat a sources
5.2 检测能力分析
本实验对正常请求和内存型Webshell的请求分别测试, 从多个检测指标检测本文方法的检测能力。内存型Webshell请求分为两部分, 分别对其注入过程和利用过程进行测试。组件类是实时检测, 能够检测注入过程, Webshell注入成功后会被再次访问, 所以包含注入过程和利用过程两部分。Agent类是静态检测, 只包含利用过程。注入过程包括组件类的31个样本, 利用过程包括组件类和Agent类的全部样本,共40个, 目前Agent样本比较少, 实验数据共9条。内存型Webshell共71个样本; 正常请求共70个样本,如表8所示。本次实验对Tomcat容器、Spring框架、Weblogic容器进行了测试。
表8 实验数据Table 8 Experimental data
实验从准确率(Accuracy)、精确率(Precision)、召回率(Recall)、F1值(F1-score)4个指标测试评估。这些指标由以下4个基础指标计算, 如表9的混淆矩阵所示。左侧表示样本的真实值, 上侧表示样本的预测值。TP(True Positive)表示Webshell被正确检测为Webshell的个数; FN(False Negative)表示Webshell被错误检测为正常请求的个数, FP(False Positive)表示正常请求被错误检测为Webshell的个数;TN(True Negative)表示正常请求被正确检测为正常请求的个数。
表9 混淆矩阵Table 9 Confusion Matrix
准确率表示检测正确的结果占总样本的百分比,即预测正确的概率, 计算公式如下:
精确率是检测为Webshell的样本中实际为Webshell的概率, 表示对Webshell检测的准确程度,计算公式如下:
召回率是实际为Webshell的样本中被检测为Webshell的概率, 计算公式如下:
Precision和Recall都越高越好, 但两者是一对矛盾的度量,F1值是Precision和Recall的一种调和平均, 同时权衡这两个指标,F1值越高越好。计算公式如下:
本文选取三个同类型的工具进行对比和分析。百度开源项目OpenRASP[37], 该工具是RASP技术的开源实现, 能够对应用进行全面的监控和防护, 覆盖Webshell行为的部分场景。Copagent工具[38], 是目前比较主流的开源内存型Webshell检测工具, 很多研究是在该工具基础上进行的。某Beta版工具(以下简称某工具), 该工具专门用于检测Webshell, 也添加了内存型Webshell的检测功能。在测试内存型Webshell利用过程请求时, 由于请求会依次经过Listener、Filter、Servlet组件, 为避免先经过的组件类Webshell样本对后经过的组件类样本检测时的影响, 每轮请求完后会重启服务。
通过对71个Webshell和70个正常请求的测试,4个工具的检测结果如表9所示。
表10 实验检测结果Table 10 Experimental test results (%)
实验表明, 本文方法具有较高的准确率, 且精确率和召回率的综合F1值优于其他检测工具。
OpenRASP是基于RASP的动态检测工具, 目前只能在程序启动时指定Java Agent以premain的方式对程序进行检测, 在程序运行时无法嵌入检测程序,因此运行时如果检测需要重启服务。该工具只能检测内存型Webshell的利用过程, 对注入过程检测不到, 且实验测试发现, 对于Listener、Valve组件的命令执行后的利用过程也检测不到, 准确率和召回率较低。该工具无法识别内存型Webshell, 只能通过触发后门的方式拦截并报警, 本文将该工具对内存型Webshell攻击的拦截报警认为是检测到了内存型Webshell, 因此精确率为100%。该工具只收集了目标程序的运行时信息, 无法定位到存在后门的类。F1值也较低。
Copagent是一款基于规则匹配的静态检测工具。首先获取JVM中所有加载的类, 通过黑名单筛选出高危类, 再对高危类进行简单的字符串匹配来判断内存型Webshell。该工具无法对目标程序实时检测,无法对内存型Webshell的注入过程进行检测。该工具设定的字符串匹配比较单一, 只针对Webshell常使用的字符串, 所以精确率高。但设定的规则比较简单, 无法检测到Controller、Interceptor、Valve类的内存型Webshell, 并且实验可以绕过该工具匹配的字符串, 该工具无法检测高对抗内存型Webshell, 准确率、召回率、F1值都比较低。
某工具也是一款静态检测工具, 无法对目标程序实时检测, 无法对内存型Webshell的注入过程检测。分析发现, 该工具也是基于黑名单筛选出高危类, 然后基于高危字符串规则匹配来判断是否为内存型Webshell。该工具的匹配规则比Copagent多, 匹配了很多的特权函数字符串、编解码方法字符串、加解密方法字符串, 导致正常请求容易被误判, 准确率、精确率比较低。但该工具对高危类和高危字符串的匹配也不全, 实验中可以绕过该工具的匹配规则, 例如通过HEX编码的高对抗内存型Webshell无法检测到, 导致准确率和召回率比较低。该工具目前对Java项目的兼容性不太好, 无法检测Spring、Weblogic的Agent类内存型Webshell。
本文方法结合动静态检测技术, 动态检测方法中函数监测点比较全面, 能够在内存型Webshell注入阶段和利用阶段及时发现后门存在; 并且本文方法既能在程序启动前以premain方式检测, 也能够在程序运行时以agentmain的方式进行检测。静态检测方法中, 通过对内存型Webshell请求调用栈上函数的全面筛查, 筛选出比较全的高危类, 并结合深度学习模型训练, 能够很好地检测高对抗内存型Webshell, 准确率较高。本文方法在检测过程中记录多个监测点上下文信息, 能够准确的定位到Webshell后门存在的类。
5.3 案例分析
本小节搭建内存型Webshell实际利用场景, 分析本文检测方法对组件类和Agent类Webshell后门的检测过程案例分析。搭建反序列化漏洞的Web服务, 测试对组件类内存型Webshell的检测过程; 搭建任意文件上传漏洞的Web服务, 测试对Agent类内存型Webshell的检测过程。
(1) 组件类内存型Webshell
搭建Tomcat环境和Shiro框架, 利用Shiro的反序化漏洞注入组件类内存型Webshell。首先使用Shiro_Attack工具[39]爆破密钥, 然后使用反序列化攻击解除Shiro对header的长度限制, 之后选择一个Filter类内存型Webshell, 对其进行序列化、AES加密、base64编码, 最后将其作为cookie的字段值发送到目标应用程序中。
目标应用程序在本文检测方法的保护下, 能够发现并拦截到内存型Webshell的类并发送邮件。结果获取了RASP拦截的信息, 包括特权类函数信息、注册组件类函数信息, 以及请求的上下文信息, 同时也获取了函数调用栈信息。内存型Webshell调用的注册组件函数是org.apache.catalina.core. Application-Context@addFilter, 注册的组件类名为com.shiro.vu-ln.Controller.TomcatMemShellInject,Webshell注入过程中的调用栈信息如图9所示。
图9 组件类检测结果Figure 9 Component type detection result
(2) Agent类内存型WebShell
搭建Tomcat任意文件上传漏洞的测试环境, 改造冰蝎中的Agent内存型Webshell, 并注入混淆的高对抗代码, 通过冰蝎上传改造后的jar包, 注入Webshell后门。注入成功后, 可以访问到Webshell后门, 并且磁盘上不存在该文件。
用本文检测方法防御后, 成功检测到被内存型Webshell修改的系统类并发送邮件。结果显示内存型Webshell存在的类是org.apache.jasper.servlet.Jsp-Servlet, 高危类是javax/servlet/Servlet接口。如图 10所示。
图10 Agent类检测结果Figure 10 Agent type detection result
5.4 性能分析
因为本文动态检测方法是在应用程序运行时进行检测, 为了不影响用户的正常访问, 性能评估尤为重要。由于Copagent工具和某工具采用的静态检测方法, 不做性能测试分析。本节对本文检测方法和OpenRASP进行性能测试分析和对比。使用Apache公司的JMeter[40]性能测试工具进行测试。采用平均响应时间、性能消耗作为评估指标。以Tomcat服务作为实验环境, 每次请求将执行1000次哈希计算操作, 使系统响应时间更加接近实际情况下网站响应时间的用户体验度。在没有任何安全防护的情况下,测试服务的平均响应时间, 然后在服务上部署本文检测方法和OpenRASP后分别测试服务的平均响应时间。
设置JMeter的线程数为2000, Ramp-up period为60s, 来模拟2000个用户在60s内随机进行访问, 将此过程循环10次, 总体请求数为20000个。
假如运行检测工具前后的平均响应时间分别是T1、T2, 则性能消耗的计算公式T如下所示。
检测结果如表11所示。检测工具运行前系统的平均响应时间是1.55s, 本文检测方法运行后的平均响应时间是1.67s, 平均响应时间延迟0.12, 性能消耗是7.74%, 在可接受范围。OpenRASP运行后的平均响应时间是1.98s, 平均响应时间延迟0.43s, 性能消耗是27.74%, 较为明显。
表11 性能测试结果Table 11 Performance test results
根据运行检测工具前后的请求响应时间绘制了响应时间分布曲线图, 如图11所示。整体上, 运行本文检测方法和OpenRASP后系统的响应时间均略长, 但本文检测方法的分布曲线图更接近无安全防护情况下的系统响应时间分布, 且性能消耗小于OpenRASP。本文检测方法对目标应用程序的影响不大。
图11 运行检测工具前后的响应时间分布曲线图Figure 11 Response time distribution curve before and after running the detection tool
5.5 讨论
本文检测方法是动静态结合检测内存型Webshell, 动态方法可以实时检测目标程序, 静态方法需要获取JVM中加载的类再用于模型判定, 目前无法做到实时检测, 可以根据目标应用程序需求,定期或周期性检测, 以更全面地防护目标受内存型Webshell的入侵。
由于Copagent工具和某工具无法检测高对抗内存型Webshell, 为了测试其静态检测能力, 只对部分Agent类内存型Webshell改造为高对抗内存型Webshell进行测试。受限于内存型Webshell样本的稀缺, 无法达到更全面的检测效果。
本文对Java内存型Webshell进行了研究, 分析两种类型的内存型Webshell原理, 构建威胁模型, 并提出高对抗内存型Webshell定义, 设计了一种动静态相结合的方法检测高对抗内存型Webshell。从内存型Webshell的输入源、触发器、特征状态方面出发,利用RASP技术对输入源中的注册组件类函数, 以及特权类函数进行监测, 根据内存型Webshell的特性, 针对不同的触发器场景分析, 结合数据流分析技术进行动态检测; 针对攻击载荷改造的高对抗内存型Webshell, 基于深度学习模型训练, 进行静态文本特征的检测。对本文检测方法进行了实验评估, 对71个内存型Webshell样本和70正常样本进行测试,结果表明本文检测方法的准确率达到96.45%, 性能消耗为7.74%, 具有可行性。
下一步工作中, 将完善针对Java Web内存型Webshell的检测方案, 本文检测方案中在内存型Webshell注入过程中监测了注册组件类的函数, 没有对内存型Webshell注入过程中的可利用漏洞处进行监测, 后续将针对这部分内容进行补充, 增加内存型Webshell在注入时的检测效率。另外研究其他语言Web服务的内存型Webshell检测技术。
猜你喜欢特权内存组件无聊是一种特权好日子(2022年3期)2022-06-01无人机智能巡检在光伏电站组件诊断中的应用能源工程(2022年2期)2022-05-23不允许任何人有超越法律的特权:《毛泽东给雷经天的信》湘潮(上半月)(2021年12期)2022-01-18新型碎边剪刀盘组件重型机械(2020年2期)2020-07-24U盾外壳组件注塑模具设计装备制造技术(2019年12期)2019-12-25笔记本内存已经在涨价了,但幅度不大,升级扩容无须等待电脑报(2019年31期)2019-09-10“春夏秋冬”的内存当代陕西(2019年13期)2019-08-20内存搭配DDR4、DDR3L还是DDR3?电脑爱好者(2015年21期)2015-09-10风起新一代光伏组件膜层:SSG纳米自清洁膜层太阳能(2015年11期)2015-04-10『人大代表』不该成为特权符号浙江人大(2014年6期)2014-03-20