首页 > 其他分享 >深度剖析GadgetInspector执行逻辑(上)

深度剖析GadgetInspector执行逻辑(上)

时间:2023-11-14 10:47:04浏览次数:103  
标签:包中 逻辑 对象 jar 剖析 获取 GadgetInspector 方法 war

该类是这个项目的主类

wKg0C2OlGBqANVpWAAA8PNUItXA861.png

首先就是配置日志格式

wKg0C2OlGCOANgjMAAByCbTB23A014.png

这里是使用的log4j进行控制台日志的输出,分别设置了了布局格式 / 日志级别 / 激活配置 等等操作

之后在主类中就是进行GIConfig接口的实现类

wKg0C2OlGC2ACBBvAAAmFZ4iLp8173.png

这里优先获取的是默认的反序列化规则,什么意思呢?我们跟进getConfig方法中看看(在gadgetinspector.config包的解释中)

之后我们这里返回的是普通的反序列化方式

之后继续回到主类的分析

wKg0C2OlGDyATNdAACKS9Ifzag725.png

这一部分主要是用来对添加参数的判断,怎么判断的呢?

首先通过判断在传入的参数中使用具有--这个关键词,如果没有会直接退出这部分代码进行接下来的jar类提取

而对于--resume这个参数,默认的resume值是为false这个布尔类型的,如果添加了该参数,将会将这个布尔值置为true,至于这个参数的作用是用来判断上次解析之后的结果还需不需要重复使用的标志,后面会一次提到

之后如果存在有--config这个参数,这个参数使用来指定是否是什么类型的反序列化,如果没有指定特定的参数,使用的是前面获取的普通的反序列化方式

直接接着看接下来的流程

wKg0C2OlGHOAASvoAACc3ZO4htA201.png

这里有两种格式,支持war / jar格式的提取,首先判断的是.war格式的文件

通过调用Util.getWarClassLoader方法来获取这个ClassLoader对象

但是如果不是.war的格式,将会调用Util.getJarClassLoader方法来创建一个ClassLoader对象,其中的参数为jar包的path数组

对于Util类的解释可以看后面的内容

之后就是将得到的classLoader传入ClassResourceEnumerator类的构造方法中,创建了一个ClassResourceEnumerator对象

对于该对象的解释在后面也可以找到

接着就是根据前面的resume的配置来判断是否删除已经存在的结果

wKg0C2OlGJKAZDyfAABM4Q5Baw176.png

接下来就是进行从传入的jar包中或者war中提取我们需要的数据并保存

wKg0C2OlGJAfQfgAABN474ziY315.png

这一步的目的是获取类 / 方法 / 继承图 等等的数据并保存

接下来的一步就是数据流的调用图

wKg0C2OlGNmAXV1EAABZm2u4c3Q106.png

后面就是通过类似的结构生成了callgraph.dat / sources.dat的文件

最后通过调用GadgetChainDiscovery#discover方法来生成利用链

首先大致来看一下包下有哪些类或者接口

wKg0C2OlGOuAMqqOAAA1FxawHG8702.png

我们可以看到在这个包下包含有一个接口GIConfig

wKg0C2OlGRSAUsYAABI1mPUpVs064.png

定义了一些方法getSerializableDecider / getImplementationFinder / getSourceDiscovery,分别用来进行对应的序列化选择器 / 实现类的方法 / 资源的发现这些功能

我们在前面提到了默认是通过调用ConfigRepository.getConfig("jserial");的方法来获取默认的配置

wKg0C2OlGVqAADNEAABtVhmYi2c250.png

通过不同的name来返回对应的反序列化配置,原始的gadgetInspector中内置了normal / Jackson / XStream这三种不同的反序列化方式

这三个包下面分别实现了不同类型的SerializableDecider / ImplementationFinder / SourceDiscovery

对于普通的SerializableDecider,为SimpleSerializableDecider类的实现

wKg0C2OlGW6AeJtHAABVbsDutc224.png

构造方法传入的是一个类的继承关系图

这个类主要是作者设定的工具类

里面主要存在有四个方法

wKg0C2OlGYOAbw85AACpuq57XqM724.png

他们分别的作用为:

  1. getWarClassLoader: 获取war包中的jar包依赖,返回一个ClassLoader对象
  2. getJarClassLoader: 获取jar包的存放路径的ClassLoader对象
  3. deleteDirectory : 递归删除根目录和其中所有的类型
  4. copy: 将输入流复制到输出流

这里可以仔细看看其中的逻辑

对于第二个方法来说,逻辑很简单,就是通过将传入的jar包路径转为URL对象之后将所有的jar包的路径放在了一个List集合中

之后创建了一个URLClassLoader对象进行返回

wKg0C2OlGbiASQKAABsfnkMQQ347.png

相比与使用jar包路径作为路径的方式,如果使用war作为路径当作参数进行传入

将会调用getWarClassLoader方法来获取其中war包中的所有jar的URL创建一个URLClassLoader进行返回

在这个方法中有几个关键步骤

  1. 需要提取war包中的jar文件
  2. 创建一个临时文件夹存放提取的所有jar包
  3. 将这些jar包作为URL创建一个URLCLassLoader进行返回

来看看作者是怎么实现这些功能的

wKg0C2OlGc2AVVN9AABgNJNKuIQ888.png

通过Files类创建了一个临时文件夹exploded-war用于存放jar包

这里设定了将会在程序执行结束的时候删掉我们创建的临时目录和其中的所有内容

是通过deleteDirectory方法进行实现的

wKg0C2OlGeiAXvfUAABstjhN5OU637.png

作者是通过使用Files#walkFileTree方法将文件夹作为一种树形结构进行访问,创建了一个SimpleFileVisitor的匿名对象

重写了其中的两个方法进行文件或者文件加的删除

接下来看看从war包中提取文件的方式

wKg0C2OlGfyAXTE7AACSsyKI7fM949.png

这里主要是通过创建了一个JarInputStream输入流对象获取每一个JarEntry之后通过调用copy方法将输入流复制进入输出流,实现了文件内容的写入,完整的提取了war包中的所有内容

之后就是创建一个URLClassLoader进行返回

wKg0C2OlGgyAbyP1AABanqL1Y2E693.png

这里的tmpDir就是我们创建的临时文件夹,通过拼接WEB-INF/classes目录来获取war中的类文件,添加进入了classPathUrls中

同时通过遍历WEB-INF/lib文件夹下的war包中包含的所有jar包,将其路径添加进入classPathUrls

这个类是一个类资源的枚举器

在这个类中存在有三个方法

wKg0C2OlGiGAf0CAABi2pwj55Y765.png

构造方法是传入的一个jar包的URLClassLoader对象

其中的getRuntimeClasses方法是用来提取当前JDK的 rt.jar包中的类

wKg0C2OlGjaAJLqOAACsRWOsMV4712.png

这一截是用来获取JDK8及以下版本的rt.jar类

作者这里主要是通过获取String.class的资源路径,进而通过JarURLConnection#getJarFileURL来获取JDK中的rt.jar这个jar包

其中对于jar包中类的提取主要是通过guava这个Google开源的开源项目来进行反射操作,主要是通过将前面得到的classLoader传入, 使用ClassPath.from方法获取ClassPath对象之后通过调用了getAllClasses方法来获取当前的class path下所有的可以加载的类

wKg0C2OlGkeAFbNkAABAcI6rCts805.png

其中返回的ClassPath.ClassInfo这个类是用来代表一个可以通过Load加载的类

之后通过传入了rt.jar的URLClassLoader和每个类ClassPath.ClassInfo的资源名(xx/xxx/xx/xxxx.class这种格式的类文件)创建了一个ClassLoaderClassResource对象,添加进入了result中

正好来看看ClassLoaderClassResource这个静态内部类把

wKg0C2OlGlqAE1b1AACPrskPkdQ272.png

主要是记录了资源名和类加载器,其中对应类的输入流是通过类加载器配合资源名进行获取的

之后就返回了我们从rt.jar包中的提取的ClassResource对象集合

如果你的JDK版本是8及一下到这里就结束了,但是,如果你的JDK是大于8版本的,使用这种方法进行jar包中类的获取是行不通的

作者在这里使用另一种思路来获取JDK的类

wKg0C2OlGm2AdvgpAABVdZS0B4365.png

这里更加直接,直接通过遍历classpath下jrt:/根下的所有的以.class结尾的资源,使用PathClassResource这个内部类进行封装了之后添加进入了result这个集合

wKg0C2OlGn6AZwHlAAB53Ur3fsA755.png

好了,对于getRuntimeClasses方法获取JDK的类文件就在这里结束了

回到getAllClasses方法来获取所有的类文件的实现

wKg0C2OlGpCAbLOSAABd4jcG2so698.png

这里,首先是获取了JDK中可加载的所有类资源,之后通过ClassPath.from(classLoader).getAllClasses方法来获取所有jar包中的类资源

这里的classloader是我们在前面从war或者jar文件中获取的URLClassLoader类对象

之后采取从JDK获取类资源相同的方法,将获取的资源添加进入result这个集合中,进行返回

这个类主要是用来进行类方法的发现和保存的功能

存在有两个方法,分别是discover / save两个

首先来看看discover方法是如何发现的

wKg0C2OlGrCAFD3bAACDLC6U7s8133.png

在获取所有类的输入流之后创建了一个asmjar包的ClassReader对象

之后调用该对象的accept方法使给定的访问者访问传递给此构造函数的 JVMS ClassFile 结构

wKg0C2OlGrAeIxCAABrTRQPc14528.png

作者这里继承了ClassVisitor类来实现自己的逻辑

wKg0C2OlGs6AJk5AACXEz0jIw385.png

这里定义了多个属性,并重写了ClassVisitor类的几个方法visit / visitField / visitMethod / visitEnd方法分别在遭遇到类之前 / 遭遇属性 / 遭遇方法 / 类的结尾的时候执行响应的逻辑

其中的visit方法

wKg0C2OlGt6ABWvSAABruIbYY84738.png

主要是记录下该类资源的名称 / 父类名 / 存在的接口 / 是否是接口 / 类的句柄

其中的visitField方法

wKg0C2OlGuAOkUQAACEil5vVf0028.png

主要是将遭遇的属性进行记录

其中的visitMethod方法

wKg0C2OlGwGAJAyfAABLA9Q5zM227.png

在创建了一个MethodReference对象之后将其添加进入discoveredMethods属性中

其中的visitEnd方法

wKg0C2OlGxSAXJLHAABpqjeAyjI750.png

主要是将收集到的类和其成员属性添加进discoveredClasses属性中

而其中的save方法

wKg0C2OlGyaABvdfAABbOd7IMbo374.png

  1. 调用了DataLoader.saveData方法进行数据的存储
  2. 分别将类相关的存入了classes.dat, 和方法相关的放入methods.dat文件
  3. 接下来就是进行继承关系图的计算了,怎么生成的呢?主要是通过遍历前面已经找到的所有的类,也即是ClassReference对象
  4. 将该对象的句柄Handle和该对象传入HashMap中进行保存,之后通过将这个map对象传入InheritanceDeriver#derive方法创建一个InheritanceMap对象,即是继承图
  5. 调用这个返回的InheritanceMap对象的save方法进行关系图的保存

这个类使用记录类的引用的

wKg0C2OlGzqAAIUKAABIA2OUInk243.png

用来存储类名/ 父类名 / 接口 / 是否是接口 / 类成员

同时具备获取对应值的getter方法

我们首先来看看其Member这个内部类

wKg0C2OlG0qAdvUeAACVhE5bKU082.png

其属性分别是用来记录该成员的名称 / 权限 / 句柄

其中Handle这个内部类

wKg0C2OlG12AR6zfAACz1LDQnbE316.png

其中还存在有Factory这个内部类,实现了DataFactory\<ClassReference>作为类引用的工厂实现类

实现了serialize方法,自定义对Class相关参考使用特定的格式进行构造

wKg0C2OlG3CAIpJkAADSIRpCeVE942.png

总结一下格式

  1. 对于存在的接口,通过,来连接接口
  2. 对于member属性, 通过!来进行连接,连接的顺序分别为属性名 / 权限 / 属性类型
  3. 返回一个字符串对象数组,返回的是类名 / 父类 / 接口 / 是否是接口 / member属性

标签:包中,逻辑,对象,jar,剖析,获取,GadgetInspector,方法,war
From: https://www.cnblogs.com/SecIN/p/17831065.html

相关文章

  • 不可撼动的逻辑—独孤九剑第三式
    在编程的宇宙中,我们扮演着上帝的角色,创造出一片宏伟的星空。在这个无边无际的宇宙中,有一类特殊的数据我们称之为常量。这些常量犹如银河系中的恒星,拥有不可撼动的特性。它们的存在就如同星球的直径和运转轨迹,是编程世界中永恒不变的基石。任何试图改变常量的尝试都可能导致宇宙的......
  • 对数据类型进行补充——逻辑类型及运算
    一.关于stdbool.h(布尔类型文件)(1)C语言标准(C89)没有定义布尔类型,使用true/false会出现错误;(2)头文件:#include<stdbool.h>;(3)输出仍然为整数,而不会是true/false的值;二.逻辑运算(对逻辑量进行运算,结果只有0或1)——————注明:逻辑量是关系运算或逻辑运算的结果(1)三种运算符及其......
  • 剖析网络测量:Counting and Measuring Network Traffic
    全文共18000字,讲解了网络测量和计数中的多方面知识:网络测量的意义、网络测量的手段分类、网络测量在实现上的挑战、以及解决这些挑战所用到的技术和协同方案等等。参考书籍有:《NetworkAlgorithmics:AnInterdisciplinaryApproachtoDesigningFastNetworkedDevices(2ndE......
  • 三角形的生命-NVIDIA的逻辑管道
    三角形的生命-NVIDIA的逻辑管道自从突破性的费米架构发布近5年以来,也许是时候刷新其下的主要图形架构了。费米是第一个实现完全可扩展图形引擎的NVIDIAGPU,其核心架构可以在开普勒和麦克斯韦中找到。本文关注GPU如何工作的图形,尽管一些原理(如着色器程序代码的执行方式)对于计算是......
  • 编程思维—为什么缺乏逻辑的人往往看不到问题的本质?
    为什么缺乏逻辑的人往往看不到问题的本质?柏拉图柏拉图《理想国》中洞穴寓言:在洞穴隐喻中,柏拉图设想一群人居住在洞穴中,他们从出生起就被束缚在洞穴里,只能看到投射到洞穴墙壁上的外界的影子,而无法看到真实的世界。某一天,一个人挣脱了束缚,走出了洞穴,他先是感到阳光刺眼,随后看到了......
  • 离散数学 第一章 命题逻辑 1-3命题公式与翻译
    前面已经提到,不包含任何联结词的命题叫做原子命题,至少包含一个联结词的命题称作复合命题。设p和q是任意两个命题,则┓p,p∨q,(p∧q)∨(p→q),p«(q∨┓p)等都是复合命题。若p和q是命题变元,则上述各式均称作命题公式。p和q称作命题公式的分量。必须注意:命题公式是没有真假值的,仅当在一个公式中......
  • 离散数学 第一章 命题逻辑 1-2 联结词
    在自然语言中,常常使用“或”,“与”,“但是”等一些联结词,对于这种联结词的使用,一般没有很严格的定义,因此有时显得不很确切。在数理逻辑中,复合命题是由原子命题与逻辑联结词组合而成,联结词是复合命题中的重要组成部分,为了便于书写和进行推演,必须对联结词作出明确规定并符号化。下面介......
  • 离散数学 第一篇 数理逻辑
    第一篇数理逻辑    逻辑学是一门研究思维形式及思维规律的科学。逻辑规律就是客观事物在人的主观意识中的反映。逻辑学分为辨证逻辑与形式逻辑两种,前者是以辨证法认识论的世界观为基础的逻辑学,而后者主要是对思维的形式结构和规律进行研究的类似于语法的一门工具性学科。......
  • 离散数学 第一章 命题逻辑 1-1 命题及其表示法
    在数理逻辑中,为了表达概念,陈述理论和规则,常常需要应用语言进行描述,但是日常使用的自然语言进行描述,往往叙述时不够确切,也易产生二义性,因此就需要引入一种目标语言,这种目标语言和一些公式符号,就形成了数理逻辑的形式符号体系。所谓目标语言就是表达判断的一些语言的汇集,而判断就是对......
  • GO语言构建高性能高并发的抽奖系统,剖析多种抽奖活动共性
    GO语言构建高性能高并发的抽奖系统,剖析多种抽奖活动共性每个生活在互联网时代的人,都一定经历过抢红包、秒杀、集卡、双色球等抽奖活动,这类活动其实有一个共同点:就是在某个时间点会瞬间涌入大量流量,给系统造成瞬间高于平时百倍、千倍甚至几十万倍的压力。在企业面试中,「如何设......