我们在JSON.parseObject上打断点,跟进到这里
然后跟进到JSONScanner
到这个位置时token为
!!!我是煞笔!我没有仔细调试和看就说调不出来
上面那个截图取自我看的笔记,但是到我这里的代码长这个样子
我当时看到没有就武断的认为自己代码的版本有问题,但是其实没有问题,因为如果我但凡在调试的时候在这个位置进行跟进, 也不会没有发现它这里代码重构成了这样
我就说哪里莫名其妙来的这个
然后我们继续跟进
由于token是,于是走到了这里
然后在这里的时候我并没有如预期一样走到了case 的里面,经过我三次调试后还是没有找到parse这个方法在parseObject的这个重写方法中使用,于是我继续查找,发现存在在parseObject的这个重写方法中
之后我们一路跟进,走到case 这里,然后我们进到parseObject中
到这里的时候发现是对json进行一系列的操作
这时这里的key已经是@type了,然后我们继续跟进,发现下面还判定了对于开头是不是@type 的
然后我们发现它再次调用了scanSymbol,然后调用了 ...
TransformedMap
这是除yso中的LazyMap之外的另一种TransformedMap的链子
环境配置就不说了,网上太多教程了(实话说这环境配好好久了,每次调一半就开摆,这次一定一定不能摆了)
我们先从Transformer这个接口看起,来查找它的实现类
我们在直奔主题前看到这个东西
ChainedTransformer
这个代码我们瞅一眼它的transform方法
它的功能很显而易见就是实现了一个链式递归调用,将前一个的输出作为后一个的输入,gadget也是需要这样的东西来帮助自动调用链的
好了,我们现在直接进入主题
InvokerTransformer
很显然可以知道它继承了serializable,我们再去看看它的transform方法
显然它在用反射来动态调用我们输入的对象和方法,这些全是我们自己可控的,这一听就是个很危险的东西,专业点说就是任意方法调用
我们尝试用这个方法弹计算器(典!
// Runtime.getRuntime().exec("calc.exe");
但我们刚才的目的是要试试这个方法来实现任意方法调用, ...
为什么我不看CC,而是选择在看完CC之后去看CC,是因为它和CC的LazyMap有关系,所以我们将CC拉前头看
这里是因为发现了一个TiedMapEntry的类,发现它的hashcode方法(注意这里和URLDNS链不同的是URLDNS链用的是HashMap里的hashcode方法,而这里是需要通过HashMap中的readObject来调用TiedMapEntry中的hashcode方法,二者本质上不同)
我们先去看TiedMapEntry的构造方法
传完赋值
我们再去看看HashMap的readObject方法中是对key还是value调用hash
这里很显然是对key进行了hash操作,说到这可能有点不明白这个hash和hashcode方法有什么关系,我们再去跟踪一手就能看出来
其实它调用了key的hashcode方法,而这个key显然可控,所以我们需要将东西放到key里而不是value里
成功了,但是还记得URLDNS中的put方法中也有hash么
我们去看看它的hash方法
喵,眼熟了,所以说我们根本没有走我们设想的路,它直接通过hashMap的put方 ...
呜呜呜maven构建的好快,我猫猫都没看完
CC了喵,加油喵
直接看yso的吧
PriorityQueue.readObjet->TransformingComparator.compare->CC.InstantiateTransformer 之后
TransformingComparator
我们先分析一下cc和cc中不同之处的关键
点,就是这个compare方法,二者有什么不一样
CC中
CC中
二者所实现的接口不同,CC实现了Serializable接口而CC中没有
所以我们开始写代码咯
TemplatesImpl templates = new TemplatesImpl(); Class templatesClazz = templates.getClass(); Field nameField = templatesClazz.getDeclaredField("_name"); ...
终于!!!绕了一大圈终于过来力!!!
CC它其实是没有走TrAXFilter的这里
的实例化,而是尝试用InvokerTransformer去调用了
我们使用invokerTransformer方法调用代码如下
InvokerTransformer invokerTransformer = new InvokerTransformer<>("newTransformer",new Class[],new Object[]);
后面的就还和CC一样
但当我运行的时候说没有这个类,所以我考虑是template没有传进去
最后看了别人的说要在add那里加上templates,而且第一个必须是templates
我进行了一个调试
当我们还是用add和的时候我们跟进去看看
走到heapify
compare方法
找到原因了,因为它需要在这里调用它的method,而我们传的是数字,所以这里变成了这样
而当我们将和改成template后我们追到这里看看吧
compare方法
我们会发现这里加载到 ...
pre
CC和我们刚才调试的CC有一些不同,CC和CC我们可以知道命令执行的方式是Runtime.getRuntime().exec但众所周知Java还可以通过加载任意类来进行恶意行为
CC是基于这个的,所以我今天也花了不少时间来重新学习动态类加载,在初步学习之后的基础上,开始调试CC
根据动态类加载的学习我们可以知道利用点通常在defineClass中,它是从字节码中加载
这个链子鉴于之前学习动态类加载的时候对加载器包括defineClass有相关调试,我就不在这个笔记中过多赘述了
TemplatesImpl
本质问题出在这里
我们一路一路往上头找,找到了
newTransformer->getTransletInstance->defineTransletClasses->defineClass
所以我们开始调试,看看这样的调用链需要满足什么条件
首先是这里
因为它直接进行了判定,所以我们看看它的构造函数有没有对它赋值
我们发现是对它的_class不有赋值,这样我们才能进到defineTransletClasses里,然后我们继续跟进
发现by ...
我们尝试编写Person类如下
各类方法调用情况
无参方法
有参方法
静态方法
赋值
==所以说Java的类在初始化的时候就会调用静态代码块==
获取类
所以class关键字只对Java类进行加载,并不会进行初始化
==类在实例化的时候会调用构造代码块==
动态加载类
Class.forName()
我们跟进去看看
这里没有,我们可以看看它重载的另一种方法
它是否初始化的值是在这里确定的
也就是说它默认是初始化了的
我们尝试使用这个重载方法进行观察
代码如下
ClassLoader cl = ClassLoader.getSystemClassLoader(); Class.forName("Person",false,cl);
这样就被认为是没有初始化后的
输出如下
在这里我们用了一个类加载器,那么如果我们使用这个类加载器去加载类,也就是用它的loadClass方法,它是否会对类进行初始化呢
我们发现输出为空,那么很明显loadClass方法不会对类进行初始化
我们来瞅瞅类加载的具体实现
我们直接打断点调到loadClass方法里
...
我们首先编写一个接口IUser
public interface IUser void show(); void update();
再写一个类来实现这个接口
public class UserImpl implements IUser public UserImpl() @Override public void show() System.out.println("show~"); @Override public void update() System.out.println("update~");
我们再编写一个动态代理类UserInvocationHandler,并覆写它的invoke方法
...
URLDNS链的调试及反射
反射的各种
我们首先编写一个Person类,分别设置public和private类型的属性和方法,代码如下:
import java.io.IOException;import java.io.ObjectInputStream;import java.io.Serializable;import java.util.Map;public class Person implements Serializable// public transient String name;有这个“transient”标识的成员变量不参与序列化 public String name; private int age; public Person() public Person(String name ,int age) this.age=age; this.na ...
tomcat启动类Bootstrap,启动时会执行这个类里面的main方法
创建Bootstrap对象,执行init方法
初始化classloaders,三个加载器加载路径在conf/catalina.properties中定义(默认catalinaLoader与sharedLoader没有设置,两个类加载器默认都是commonLoader,如果设置了,父类是commonLoader),然后sharedLoader是后期加载项目中的class的父类加载器,有共享的class或者jar,可以配在这
通过反射创建Catalina对象(catalinaLoader.loadClass(“org.apache.catalina.startup.Catalina”))
设置tomcat容器父加载器 Catalina.setParentClassLoader(sharedLoader)
load: Catalina.load()责任链模式,一层往下一层执行
加载conf.server.xml
将xml解析成对象,digester.parse(inputSource)
一个tomcat对应 ...