1. 首页
  2. IT资讯

Apache Commons Fileupload 漏洞,可恶意操作文件

“u003Cdivu003Eu003Cpu003E漏洞的来源是在于 DiskFileItem中的 readObject()进行文件写入的操作,这就意味着如果我们对已经序列化的 DiskFileItem对象进行反序列化操作就能够触发readObject()执行从而触发这个漏洞。u003Cu002Fpu003Eu003Cpu003E这个漏洞的危害是能够任意写、读文件或者目录。但是具体是对文件还是目录操作与FileUpload以及JDK的版本有关。u003Cu002Fpu003Eu003Cpu003E不同的漏洞环境能够达到的效果不一样。u003Cu002Fpu003Eu003Colu003Eu003Cli class=”ql-align-justify”u003EFileUpload的1.3.1之前的版本配合JDK1.7之前的版本,能够达到写入任意文件的漏洞;u003Cu002Fliu003Eu003Cli class=”ql-align-justify”u003EFileUpload的1.3.1之前的版本配合JDK1.7及其之后的版本,能够向任意目录写入文件;u003Cu002Fliu003Eu003Cli class=”ql-align-justify”u003EFileUpload的1.3.1以及之后的版本只能向特定目录写入文件,此目录也必须存在。(文件的的命名也无法控制);u003Cu002Fliu003Eu003Cu002Folu003Eu003Cpu003Eu003Cstrongu003E影响范围u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cp class=”ql-align-justify”u003Ecommons-fileupload<=1.3.2u003Cu002Fpu003Eu003Cpu003E下面进行详细地分析u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003EPayload构造u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E我们首先测试的版本是1.3的版本,JDK是1.8版本,所以这种组合只能达到向任意目录的文件写入的漏洞效果。我们测试的payload是 {“write;cve1000031;123456”},表示的含义就是向目录 cve1000031中写入 123456的内容。在 ysoserial中最终是由 ysoserial.payloads.FileUpload1::makePayload()来构建payload。代码如下:u003Cu002Fpu003Eu003Cpreu003Eprivate static DiskFileItem makePayload ( int thresh, String repoPath, String filePath, byte[] data ) throws IOException, Exception {u003Cbru003E u002Fu002F if thresh < written length, delete outputFile after copying to repository temp fileu003Cbru003E u002Fu002F otherwise write the contents to repository temp fileu003Cbru003E File repository = new File(repoPath);u003Cbru003E DiskFileItem diskFileItem = new DiskFileItem(“testxxx”, “applicationu002Foctet-stream”, u003Cbru003Efalse, “testxxx”, 100000, repository);u003Cbru003E File outputFile = new File(filePath);u003Cbru003E DeferredFileOutputStream dfos = new DeferredFileOutputStream(thresh, outputFile);u003Cbru003E OutputStream os = (OutputStream) Reflections.getFieldValue(dfos, “memoryOutputStream”);u003Cbru003E os.write(data);u003Cbru003E Reflections.getField(ThresholdingOutputStream.class, “written”).set(dfos, data.length);u003Cbru003E Reflections.setFieldValue(diskFileItem, “dfos”, dfos);u003Cbru003E Reflections.setFieldValue(diskFileItem, “sizeThreshold”, 0);u003Cbru003E return diskFileItem;u003Cbru003E}u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E当我们输入我们的Payload, {“write;cve1000031;123456″},其中的赋值情况是:u003Cu002Fpu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp3.pstatp.comu002Flargeu002Fpgc-imageu002Face0fdb64b6346e68cf4c20fcdfa6b85″ img_width=”891″ img_height=”216″ alt=”Apache Commons Fileupload 漏洞,可恶意操作文件” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003E而 thresh的值就是我们需要写入的内容的长度加1,即 len(123456)+1结果就是7。其中还有 filePath是 cve1000031u002Fwhatever是因为在这个漏洞环境中我们最终是向 cve1000031目录写入,所以后面是什么就没有意义了。最后在代码中还存在几个反序列化的操作:u003Cu002Fpu003Eu003Cpreu003EReflections.getField(ThresholdingOutputStream.class, “written”).set(dfos, data.length);u003Cbru003EReflections.setFieldValue(diskFileItem, “dfos”, dfos);u003Cbru003EReflections.setFieldValue(diskFileItem, “sizeThreshold”, 0);u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E发序列化的意义是在于我们无法通过 DiskFileItem的示例进行设置,只能通过反射的方式设置,这几个属性也是我们触发漏洞的必要条件。u003Cu002Fpu003Eu003Cpu003E之后对我们构造的这个进行序列化操作,反序列化之后就会触发DiskFileItem的 readObject()从而触发漏洞。u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E漏洞分析-1u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E漏洞环境:FileUpload1.3+ JDK1.7u003Cu002Fpu003Eu003Cpu003E当对 DiskFileItem的对象进行反序列化操作时,由 org.apache.commons.fileupload.disk.DiskFileItem::readObject()处理。u003Cu002Fpu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fpgc-imageu002F2f115b53ef08414ab313bed6306a09ee” img_width=”589″ img_height=”359″ alt=”Apache Commons Fileupload 漏洞,可恶意操作文件” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003E跟进 getOutputStream(),进入到:u003Cu002Fpu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp3.pstatp.comu002Flargeu002Fpgc-imageu002F8ea3c42e7a814f418de9605a743051c7″ img_width=”589″ img_height=”175″ alt=”Apache Commons Fileupload 漏洞,可恶意操作文件” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003E由于 dfos==null满足条件,会执行 FileoutputFile=getTempFile();方法。跟踪进入 getTempFile()到中u003Cu002Fpu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp3.pstatp.comu002Flargeu002Fpgc-imageu002F9f334989403d4545847a2c7b1af6902e” img_width=”837″ img_height=”290″ alt=”Apache Commons Fileupload 漏洞,可恶意操作文件” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003E其中的 tempDir就是我们设置的 repository,即 cve1000031。tmpFileName是由 DiskFileItem是自动生成的。最终和 tempDir组合得到的文件路径就是 cve1000031\\upload_7b496a67_4fc4_4b14_a4e7_ff5aceb82aaf_00000000.tmp。u003Cu002Fpu003Eu003Cpu003E最后返回至 readObject()方法中写入文件,如下:u003Cu002Fpu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp3.pstatp.comu002Flargeu002Fpgc-imageu002F5b247bb1c70047d385f0ad4a4bc63d55″ img_width=”699″ img_height=”308″ alt=”Apache Commons Fileupload 漏洞,可恶意操作文件” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003E其中的 cachedContent就是我们之前在Payload中设置的 123456。那么Payload的最终的效果就是在 cve1000031\\upload_7b496a67_4fc4_4b14_a4e7_ff5aceb82aaf_00000000.tmp文件中写入了 123456的内容。u003Cu002Fpu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp3.pstatp.comu002Flargeu002Fpgc-imageu002Ff3a377a4e5fa43bc8800b24248d4510a” img_width=”918″ img_height=”114″ alt=”Apache Commons Fileupload 漏洞,可恶意操作文件” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003Eu003Cstrongu003E漏洞分析-2u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E由于前面的一个漏洞分析是向任意目录写文件的功能,本次分析的是任意文件写入的功能。本次的漏洞环境是 FileUpload1.3+ JDK1.6。u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003EPayload构造u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E构造的Payload是 {“writeOld;cve1000031.txt;123456″}。同样会调用 makePayload()构造Payload。u003Cu002Fpu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp9.pstatp.comu002Flargeu002Fpgc-imageu002F4caf45700e39406b98dd3f59fe7ad4b5″ img_width=”929″ img_height=”407″ alt=”Apache Commons Fileupload 漏洞,可恶意操作文件” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003E但是其中的 repoPath最后一位是 \0,这个就类似于PHP中的截断,用于截断后面的路径,这样就可以达到任意文件写入的效果。具体的原理说明如下:u003Cu002Fpu003Eu003Cblockquoteu003Eu003Cpu003EJDK7以上在Java的file相关的基础类中都做了空字符的保护,这也是在针对java的string 和 c char的结束方式不一致,在Java中文件的操作中使用String这种char 数组,而C中的char 是以空字符为结束符,所以java操作的文件中很容易通过注入空字符来操作完全不同的文件。比如 JavaFilefile=newFile(“u002Ftestu002Ftest.txt\0.jsp”) 看起来再操作 test.txt\0.jsp实际上在底层调用的(本质还是c读写文件)是在操作test.txt。在JDK7以后的版本File 里面会有一个判断是否有空字符的函数u003Cu002Fpu003Eu003Cu002Fblockquoteu003Eu003Cpu003E这个意思就是在JDK7之前可以利用 \0进行目录截断,和php在5.3.4版本之前也可以进行目录截断是一样的道理。所以这个任意文件写入为什么要求是JDK7以下的版本才可以的原因。u003Cu002Fpu003Eu003Cpu003E漏洞的执行流程和前面分析的漏洞流程一样,不同是在 getTempFile()中:u003Cu002Fpu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fpgc-imageu002F26f1ecb461844d8eac007c0a30599fb5″ img_width=”936″ img_height=”234″ alt=”Apache Commons Fileupload 漏洞,可恶意操作文件” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003E其中 this.tempFile的路径是 cve1000031.txt \\upload_6982dc32_8ca4_4d7c_b658_0a9b44a60741_00000000.tmp。由于是在JDK1.6的环境下,后面的 \\upload_6982dc32_8ca4_4d7c_b658_0a9b44a60741_00000000.tmp在写入文件时会被忽略,所以最终是向 cve1000031.txt文件中写入内容。u003Cu002Fpu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fpgc-imageu002F3bae7282402a401c9864681a672b6fb9″ img_width=”527″ img_height=”138″ alt=”Apache Commons Fileupload 漏洞,可恶意操作文件” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003Eu003Cstrongu003E漏洞分析-3u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E漏洞环境:FileUpload1.3.1+ JDK1.7在 FileUpload1.3.1中对 readObject()的功能进行了修改。修改主要是对 repository进行了校验。u003Cu002Fpu003Eu003Cpreu003Eprivate void readObject(ObjectInputStream in)u003Cbru003E throws IOException, ClassNotFoundException {u003Cbru003E u002Fu002F read valuesu003Cbru003E in.defaultReadObject();u003Cbru003E u002F* One expected use of serialization is to migrate HTTP sessionsu003Cbru003E * containing a DiskFileItem between JVMs. Particularly if the JVMs areu003Cbru003E * on different machines It is possible that the repository location isu003Cbru003E * not valid so validate it.u003Cbru003E *u002Fu003Cbru003E if (repository != null) {u003Cbru003E if (repository.isDirectory()) {u003Cbru003E u002Fu002F Check path for nullsu003Cbru003E if (repository.getPath().contains(“\0”)) {u003Cbru003E throw new IOException(format(u003Cbru003E “The repository [%s] contains a null character”,u003Cbru003E repository.getPath()));u003Cbru003E }u003Cbru003E } else {u003Cbru003E throw new IOException(format(u003Cbru003E “The repository [%s] is not a directory”,u003Cbru003E repository.getAbsolutePath()));u003Cbru003E }u003Cbru003E }u003Cbru003E OutputStream output = getOutputStream();u003Cbru003E if (cachedContent != null) {u003Cbru003E output.write(cachedContent);u003Cbru003E } else {u003Cbru003E FileInputStream input = new FileInputStream(dfosFile);u003Cbru003E IOUtils.copy(input, output);u003Cbru003E dfosFile.delete();u003Cbru003E dfosFile = null;u003Cbru003E }u003Cbru003E output.close();u003Cbru003E cachedContent = null;u003Cbru003E}u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E通过对 repository.isDirectory()和 repository.getPath().contains(“\0″)的判断,就阻止了任意的文件写入的漏洞了。所以在这种环境下只能下特定的目录写入文件了。但是这种情况下,你也只能向临时目录写入文件。u003Cu002Fpu003Eu003Cu002Fdivu003E”

原文始发于:Apache Commons Fileupload 漏洞,可恶意操作文件

主题测试文章,只做测试使用。发布者:逗乐男神i,转转请注明出处:http://www.cxybcw.com/26514.html

联系我们

13687733322

在线咨询:点击这里给我发消息

邮件:1877088071@qq.com

工作时间:周一至周五,9:30-18:30,节假日休息

QR code