GadgetInspector原理分析

是在上发布的一个自动化反序列化链挖掘工具,它通过对字节码形式的JAVA项目进行污点分析,挖掘可能存在的反序列化链。我们从GadgetInspector的源代码进行分析。六个部分层层递进,最终完成反序列化链挖掘。...
摘要由CSDN通过智能技术生成

GadgetInspector 是 JackOfMostTrades 在 2018 BLACKHAT USA 上发布的一个自动化反序列化链挖掘工具,它通过对字节码形式的JAVA项目进行污点分析,挖掘可能存在的反序列化链。

我们从GadgetInspector的源代码进行分析。根据源代码的逻辑结构,可以看出其分成六个部分:

ClassResourceEnumerator 读取类文件,保存到自定义的数据结构里
MethodDiscovery         分析类文件包含的的类、方法信息
PassthrougthDiscovery   对方法进行局部污点分析
CallGraphDiscovery  枚举污点边
SourceDiscovery         枚举源点
GadgetChainDicovery 生成反序列化链

六个部分层层递进,最终完成反序列化链挖掘。

0x11 ClassResourceEnumerator

GadgetInspector的核心入口类是 GadgetInspector 这个类。它的main方法根据输入参数的区别,可以生成war包或者jar包对应的 ClassLoader ,并利用 ClassLoader 作为参数构造 ClassResourceEnumerator 对象

        final ClassLoader classLoader;
        if (args.length == argIndex+1 && args[argIndex].toLowerCase().endsWith(".war")) {
            Path path = Paths.get(args[argIndex]);
            classLoader = Util.getWarClassLoader(path);
        } else {
            final Path[] jarPaths = new Path[args.length - argIndex];
            for (int i = 0; i < args.length - argIndex; i++) {
                Path path = Paths.get(args[argIndex + i]).toAbsolutePath();
                jarPaths[i] = path;
            }
            classLoader = Util.getJarClassLoader(jarPaths);
        }
       final ClassResourceEnumerator classResourceEnumerator = new ClassResourceEnumerator(classLoader);

ClassResourceEnumerator 对象主要的作用就是获取用于分析的类文件,我们看一下它的主要方法 getAllClasses 。可以看到首先调用 getRuntimeClasses 获取JDK中的类文件,然后使用刚才创建的 ClassLoader 读取作为分析对象的JAVA项目的类文件

    public Collection<ClassResource> getAllClasses() throws IOException {
        Collection<ClassResource> result = new ArrayList<>(getRuntimeClasses());
        for (ClassPath.ClassInfo classInfo : ClassPath.from(classLoader).getAllClasses()) {
            result.add(new ClassLoaderClassResource(classLoader, classInfo.getResourceName()));
        }
        return result;
    }

在读取了类文件以后,GadgetInspector通过5个阶段的discovery来获取反序列化链,它们的实现框架大致相同:都是根据上一个阶段的分析结果,进行进一步分析,然后保存这个阶段的分析结果。

        // Perform the various discovery steps
        if (!Files.exists(Paths.get("classes.dat")) || !Files.exists(Paths.get("methods.dat"))
                || !Files.exists(Paths.get("inheritanceMap.dat"))) {
            MethodDiscovery methodDiscovery = new MethodDiscovery();
            methodDiscovery.discover(classResourceEnumerator);
            methodDiscovery.save();
        }

对应到具体的方法就是 discover 和 save 方法。这里先仔细分析MethodDiscovery部分的 discover 方法。

这里使用上一步创建的 ClassResourceEnumerator 对象获取类输入流

    public void discover(final ClassResourceEnumerator classResourceEnumerator) throws Exception {
        for (ClassResourceEnumerator.ClassResource classResource : classResourceEnumerator.getAllClasses()) {
            try (InputStream in = classResource.getInputStream()) {
                ClassReader cr = new ClassReader(in);
                cr.accept(new MethodDiscoveryClassVisitor(), ClassReader.EXPAND_FRAMES);
            }
        }
    }

注意这里的 ClassReader 和 MethodDiscoveryClassVistor 用到JAVA中的ASM技术,用来读取类文件并进行分析。

ASM是一种JAVA字节码操作,读取,增强技术。它直接分析类文件中的各种信息,例如常量池,操作码,要求其使用者对于JAVA类文件的结构有一定了解。其主要的类操作API为ClassVisitor类。使用者对ClassVisitor进行个性化实现,满足自己的需求。例如下面这一段代码就是ClassVisitor的API的使用步骤

java public static void main(String[] args) throws Exception{ //实现一个自己的ClassVistor类型的对象 ClassVisitor classVisitor=new ClassVisitor(Opcodes.ASM9) { //重载一个回调方法,当访问字段时会打印字段名称 @Override public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { System.out.println(name); return super.visitField(access, name, desc, signature, value); } }; //获取一个类文件,这里是Hello这个测试类 ClassLoader classLoader= VisitClass.class.getClassLoader(); String path= Hello.class.getCanonicalName().replace(".","/")+".class"; InputStream inputStream=classLoader.getResourceAsStream(path); //使用类文件构造一个ClassReader类型的对象 ClassReader classReader=new ClassReader(inputStream); //使用自定义的ClassVisitor类型的对象并解析ClassReader里面保存的对象流 classReader.accept(classVisitor,0); }

编译运行以后就会打印 Hello 这个类的所有字段名称

ASM主要的方法操作API为MethodVisitor类,使用者对MethodVisitor进行个性化实现,可以进一步解析类方法。MethodVisitor的用法下面再介绍

我们需要知道的就是 cr.accept 接收一个 ClassVistor 类型的对象,并且在分析类文件过程中回调式地触发 ClassVistor 类型的对象实现的各种方法。那么我们继续查看 MethodDiscoveryClassVistor 。里面两个关键的方法如下

    @Override
    public FieldVisitor visitField(int access, String name, String desc,
                                       String signature, Object value) {
            if ((access & Opcodes.ACC_STATIC) == 0) {
                Type type = Type.getType(desc);
                String typeName;
                if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
                    typeName = type.getInternalName();
                } else {
                    typeName = type.getDescriptor();
                }
                // 记录成员信息
                members.add(new ClassReference.Member(name, access, new ClassReference.Handle(typeName)));
            }
            return super.visitField(access, name, desc, signature, value);
        }

        @Override
        public MethodVisitor visitMethod(int access, String name, String d
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值