non_RCE复现

·
Java代码审计 no tag September 28, 2021

non_RCE复现

首先放出官方WP

https://mp.weixin.qq.com/s/yQ-00YaykUe41S0DdlgoiQ

面向官方WP复现一下

认证绕过

首先直接访问admin的话会401。我们来看一下代码

因为LoginFilter和AdminServlet的urlPatterns是相同的。所以经过AdminServlet的时候一定会经过LoginFilter。

在这里,必须知道password才能通过认证,但是题目又说,不可能得到密码。所以就需要绕了。

image-20210812150847045

所以接下来的思路也很明确,就是如何能绕过LoginFilter。在AntiUrlAttackFilter中,有一段代码比较可疑:

image-20210812151110752

这里吧./和;替换成了空,然后使用forward进行了转发。通过forward就能绕过LoginFilter了。

image-20210812152711552

因为这里只拦截/admin/请求,所以我们从AntiUrlAttackFilter过来的请i去就不会拦截

http://127.0.0.1:8080/;admin/importData

这里把;替换为空后转发。

image-20210812154538109

现在能访问admin了。

image-20210812154507809

里面是一段mysql连接。

黑名单检测绕过

这里预期解是利用mysql jdbc的反序列化

jdbcUrl是我们可控的。但是有过滤

image-20210812155150593

搜一下autoDeserialize就能发现一些文章。

https://www.anquanke.com/post/id/203086

过滤之后dbc url包含%或者autoDeserialize关键字都无法通过校验,导致doGet中直接return而无法进入下面的jdbc连接部分。

这里的预期解是利用黑名单检测逻辑存在的条件竞争问题,来绕过黑名单检测机制,黑名单检测几个关键的逻辑如下:

image-20210812160540962

可以看到,这里生成了一个单例BlackListChecker对象,也就是说,在整个程序生命周期中,最多只会生成1个BlackListChecker对象,而tomcat在同时处理多个http请求时,会起多个线程,每个线程都会调用Servlet的处理逻辑,因此,在这里会有多个线程同时调用servlet.AdminServlet#doGet方法。

而如之前所说,整个程序生命周期中最多只会生成1个BlackListChecker对象,因此,这里存在多个线程对同一个对象做操作的情况。而在黑名单的检测逻辑checker.BlackListChecker#check方法中,会把待检测的字符串设置到BlackListChecker对象的toBeChecked成员变量中,再从toBeChecked中拿出来做字符串contains检测,因此,这里存在多个线程对同一个对象做写操作的情况,存在条件竞争问题。

这样一来,当恶意的jdbcUrl被绑定后。本来要进行check但接着马上有线程来一个正常的jdbcUrl,而只有一个实例,这时候会过了check,实例并不会进行拦截,因此恶意的jdbcUrl也得以继续执行。

然后就是自己搭一个恶意mysql服务器来打。

寻找利用链

为了方便调试,我们自己先写个exp框架用于本地调试

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;

public class exp {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }

    public static void main(String[] args){


        // ==================
        // 生成序列化字符串
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(handler);
        oos.close();

        // 本地测试触发
        // System.out.println(barr);
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        Object o = (Object) ois.readObject();
    }
}

image-20210812162222812

我们可以通过pom.xml发现使用了aspectjweaver。

image-20210812162257019

所以确定是用这个打的。

这道题和ysoserial不同的地方就是这道题是没有cc链的。而他自己写了一个DataMap类。是出题人为了防止不懂原理,直接用工具梭出来弄的。

在ysoserial中已经由gadget链了

image-20210812165152826

从这个链,我们可以得知漏洞触发点在SimpleCache$StorableCachingMap.writeToPath()

漏洞点:可以写文件

image-20210812165704481

所以我们需要找一个调用put函数,且参数可控的地方来触发这个漏洞。

我们从DataMap里寻找,发现了

image-20210812170311321

这里使用了put方法。所以我们要想办法往这里靠。

继续看DataMap源码。发现DataMap#Entry中有hashcode方法,其中调用getValue然后调用了get方法。

image-20210812180406365

而根据gadget chain。

image-20210812180449196

只需要将key设置为DataMap#Entry类即可

所以利用链

HashSet.readObject()
    HashMap.put()
        HashMap.hash()
            DataMap$Entry.hashcode
                DataMap$Entry.getValue()
                    DataMap.get()
                        SimpleCache$StorableCachingMap.put()
                            SimpleCache$StorableCachingMap.writeToPath()
                                FileOutputStream.write()

参考

https://www.cnblogs.com/sijidou/p/14631154.html

  • Fastjson 1.2.22-1.2.24反序列化漏洞分析
  • XCTF-final-dubbo
取消回复

说点什么?

© 2023 Yang_99的小窝. Using Typecho & Moricolor.