明天要面试,不想复习啊。
之前不怎么学习这个漏洞。但是最近被问了两次,而且后来我发现不同类型数据库的反序列化漏洞还挺多的。
看了看资料略写写还算简单。主要是分析反序列化部分,CC链部分不管,mysql协议部分不管。
利用点
jdbc连接数据库的过程中,配置连接地址以及一些连接参数就有可能造成反序列化漏洞。
如下是jdbc连接数据库代码。
Class.forName("com.mysql.jdbc.Driver");
String jdbc_url = "jdbc:mysql://127.0.0.1:3309/test?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai" +
"&autoDeserialize=true" +
"&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor";
Connection con = DriverManager.getConnection(jdbc_url, "root", "123123");
利用场景
可以修改jdbc连接数据库参数配置的地方如后台数据库配置或者一些配置文件。
以及对mysql-connector-java版本有要求,不同版本的利用参数略有区别,有些版本利用不了
payload&&复现环境工具
模拟mysql协议恶意请求包poc:
https://github.com/Drun1baby/JavaSecurityLearning/blob/main/JavaSecurity/JDBC/exp.py 【弹计算器】
大家需要其他exp可以自己利用ysoserial生成然后去修改exp.py中payload
分析
这是一个原生的反序列化漏洞,找到外部可控的readobject即可
-
在mysql-connector-java-8.0.13.jar搜索readobejct发现
ResultSetImpl.java类存在getObject方法中存在两处的readObject调用
@Override // java.sql.ResultSet
public Object getObject(int columnIndex) throws SQLException {
int columnIndexMinusOne;
try {
checkRowPos();
checkColumnBounds(columnIndex);
columnIndexMinusOne = columnIndex - 1;
} catch (CJException e) {
throw SQLExceptionsMapping.translateException(e, getExceptionInterceptor());
}
if (this.thisRow.getNull(columnIndexMinusOne)) {
return null;
}
Field field = this.columnDefinition.getFields()[columnIndexMinusOne];
switch (AnonymousClass1.$SwitchMap$com$mysql$cj$MysqlType[field.getMysqlType().ordinal()]) {
case 1:
if (!field.isBinary() && !field.isBlob()) {
return field.isSingleBit() ? Boolean.valueOf(getBoolean(columnIndex)) : getBytes(columnIndex);
}
byte[] data = getBytes(columnIndex);
if (this.connection.getPropertySet().getBooleanProperty(PropertyKey.autoDeserialize).getValue().booleanValue()) {
Object obj = data;
if (data != null && data.length >= 2) {
if (data[0] == -84 && data[1] == -19) {
try {
ByteArrayInputStream bytesIn = new ByteArrayInputStream(data);
ObjectInputStream objIn = new ObjectInputStream(bytesIn);
obj = objIn.readObject();
objIn.close();
bytesIn.close();
} catch (IOException e2) {
obj = data;
} catch (ClassNotFoundException cnfe) {
throw SQLError.createSQLException(Messages.getString("ResultSet.Class_not_found___91") + cnfe.toString() + Messages.getString("ResultSet._while_reading_serialized_object_92"), getExceptionInterceptor());
}
} else {
return getString(columnIndex);
}
}
-
搜索哪些方法调用了ResultSetImpl.getObject,idea 右键 find usages,最终找到了ResultSetUtil类的resultSetToMap方法
搜索谁调用了resultSetToMap 找到了
ServerStatusDiffInterceptor类中的populateMapWithSessionStatusValues 方法
ServerStatusDiffInterceptor是一个拦截器,populateMapWithSessionStatusValues方法在prepocess以及postProcess中调用,只有开启拦截器设置JDBC URL 中设定属性 queryInterceptors 为 ServerStatusDiffInterceptor 时,执行查询语句会调用拦截器的 preProcess 和 postProcess 方法
-
检查getObjetc函数
这块代码首先会判断是不是二进制binary形式,以及autoDeserialize的bool值所以要设置autoDeserialize值为true.
反序列化到这里就完成了一大半。
后面具体的payload需要分析mysql协议。exp主要是利用ysoserial cc链生成的以及需要符合mysql协议格式
为什么后面要使用CC链
java反序列化readobject过程中是需要使用类加载器找到对应的类才能进行反序列化的,如果类加载器在服务器上找不到对应类直接去执行readobject就会报错。
必须用服务器上存在的类,怎么让它在readObject执行过程中触发呢?这里就是CC链的重要意义了,如果反序列化的类定义了readObject方法,服务器上执行ObjectInputStream.readObject时,会自动调用反序列化类中的readObject方法,更进一步的,如果反序列化类的readObject方法中执行了该类成员变量的某些方法,而这些成员变量是可控的,一个反序列化利用或许就出现了
引用:
https://www.cnblogs.com/bitterz/p/15035581.html
https://xz.aliyun.com/t/8159#toc-1
原文始发于微信公众号(天才少女Alpha):Mysql JDBC反序列化
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论