0%

AWD Java Patch

AWD线下赛修复jar/war包一直手忙脚乱,此篇文章记录几种常用的Java jar包修复方法

反编译成Maven项目

对比于手动编译打包,反编译成Maven项目更加方便快捷(Maven其实也就是干这个事)

手动仅使用原始Java进行反编译并打包可以参考:AWD离线-Jar文件冷补丁

下面记录反编译成Maven项目并进行修复的步骤

  1. 反编译jar包,使用IDEA反编译插件还原源代码,反编译出来还是jar包,直接解压即可
1
/Library/Java/JavaVirtualMachines/jdk-17.0.11.jdk/Contents/Home/bin/java -cp "/Applications/IntelliJ IDEA.app/Contents/plugins/java-decompiler/lib/java-decompiler.jar" org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler -dgs=true <jar_path> <output_path>

最新版IDEA的反编译插件需要java17

  1. 导入源代码,创建一个空的Maven项目,然后将反编译后/BOOT-INF/classes下的源代码复制到/src/main/java 路径下。视check情况选择是否将resources 下资源文件一起导入

image

  1. 导入依赖库,将BOOT-INF/lib下的依赖复制到项目的lib文件文件夹下(没有这个文件夹,需要自己新建,一般在项目的第一级目录),在文件-项目结构-项目设置-库中将lib文件夹添加为库文件夹,此步骤是解决在离线情况下缺少依赖的问题
  2. 用反编译出的pom.xml 文件覆盖创建的Maven项目中的pom.xml 文件
  3. 修复代码并打包,修改Java源代码,或者根据漏洞点直接修改pom.xml 文件中依赖的版本号,然后使用Maven进行打包,当然也可以直接在在IDEA中点点点。Springboot项目在pom.xml 内置了打包插件,所以选择Maven打包而不是构建成工件的jar或者war包的形式,需要根据实际情况选择如何打包
1
mvn clean package

image

以上展示的是打包一个完整的jar包的步骤,成功完成后会在/target 目录输出修复好的jar包文件,直接-jar 运行即可,当然也可以直接选择使用压缩软件对编译好的class文件进行替换,看文章说Bandizip可以保证替换前后jar包和war包的可用性,使用Maczip测试确实出现如下报错

image

jar uf更新class文件

那么除了使用Bandizip还有其他方法可以更新class文件而不影响jar包和war包的可用性呢,答案是肯定的,可以使用jar uf命令来更新class文件

需要注意在jar包内class文件的真实包名,如下图,这里需要在包名前添加BOOT-INF/classes/ 前缀

image

同时注意根据包名创建文件夹,IDEA中直接把target目录改名为BOOT-INF 即可

image

命令示例

1
jar uf vulnspringboot-1.0-SNAPSHOT.jar BOOT-INF/classes/org/example/controller/SCtfController.class

Javassist修改jar包字节码

可以用以下项目作为脚手架:

非常便捷,在main函数中指定要修改的jar包路径,然后在ExamplePatch 类的patch 方法中编写Javassist修改字节码逻辑即可,同样因为jar包结构问题,需要注意BOOT-INF/classes/ 路径问题

image

修改jar包中class内容

1
2
3
CtClass c1 = new PatchClass("org.example.controller.SCtfController", "BOOT-INF/classes/").getCtClass();
CtMethod write1 = c1.getDeclaredMethod("index");
write1.insertBefore("System.out.println(\"Sakura\");");

修改jar包中依赖的class

1
2
3
4
PatchLibrary patchLibrary = new PatchLibrary("hessian-4.0.4.jar",  "BOOT-INF/lib/");
CtClass c4 = patchLibrary.getCtClass("com.alipay.hessian.NameBlackListFilter");
CtMethod write4 = c4.getDeclaredMethod("resolve");
write4.insertBefore("System.out.println(\"Sakura\");");

同时也支持直接修改class,主要针对tomcat环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// we want to change /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/com/ctf/BoardServlet.class

// addClassRootPath
patch.addClassRootPath("/usr/local/tomcat/webapps/ROOT/WEB-INF/classes/");

// rewrite it with Javassist
CtClass c2 = new PatchClass("com.ctf.BoardServlet", "").getCtClass();
CtMethod write2 = c2.getDeclaredMethod("index");
write2.insertBefore("System.out.println(\"Sakura\");");

// make sure you set `cleanAfterPatch` = false
patch.setCleanAfterPatch(false);

// then you'll find it in `patch/`

JarEditor修改jar包

比较推荐的方法,IDE插件直接修改jar包内容。对于外部包,右键jar包,Add Library ,就可以直接修改了

image

修改完成后,点击Save(Compile),编译并保存当前修改的java内容,最后点击Build Jar,将编译保存的类文件写入Jar包中

经测试,目前好像没有修改未在jar包中class的功能,对于tomcat环境,可以将classes文件夹压缩并修改为jar后缀即可修改

总结

几种方法优先推荐JarEditor修改jar包,其他思路比如JByteMod直接修改字节码因为普适性不高并没有做演示

同时也测试了arthas用于AWD修复jar包,但由于arthas采用agent原理,有些class并没有被jvm加载导致内存编译功能错误,还是更适用于应急响应以及bug诊断场景

image

Refference