日期:
来源:安全客收集编辑:雁不过衡阳
这是分析Java反序列化系列的第四篇文章,内容的填充度已经过半。此系列的每一篇文章 都会对漏洞产生的原因进行剖析,理解事物的原理往往在攻击时发挥奇效。
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate、Spring等。
既然是反序列化漏洞必然要提起的就是序列化与反序列化,如果还有读者对这个概念不清楚请参考文章《前尘——与君再忆CC链》,在Java反序列化漏洞中,序列化和反序列化是理解这些漏洞的基本条件。
<dependencies><dependency><groupId>com.mchange</groupId><artifactId>c3p0</artifactId><version>0.9.5.5</version></dependency></dependencies>
此依赖为c3p0最新版本依赖,更新于2019年12月
最新版本没有修复此问题
直接进入网上公开的链条类打开就是一顿分析com/mchange/v2/c3p0/impl/PoolBackedDataSourceBase
分析了这么多的漏洞链条,其实道理很简单。将网上纰漏的漏洞类打开直接往下翻往下翻找到readObject()方法对其内容进行跟进就可以,三板斧直接一顿怼。
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {short version = ois.readShort();switch(version) {case 1:Object o = ois.readObject();if (o instanceof IndirectlySerialized) {o = ((IndirectlySerialized)o).getObject();}this.connectionPoolDataSource = (ConnectionPoolDataSource)o;this.dataSourceName = (String)ois.readObject();o = ois.readObject();if (o instanceof IndirectlySerialized) {o = ((IndirectlySerialized)o).getObject();}this.extensions = (Map)o;this.factoryClassLocation = (String)ois.readObject();this.identityToken = (String)ois.readObject();this.numHelperThreads = ois.readInt();this.pcs = new PropertyChangeSupport(this);this.vcs = new VetoableChangeSupport(this);return;default:throw new IOException("Unsupported Serialized Version: " + version);}}
Object o = ois.readObject();
此语句反序列化出一个referenceSerialized对象,instanceof关键字用来测试一个对象是否为一个类的实例。com.mchange.v2.naming.ReferenceIndirector类中存在内部类ReferenceSerialized实现了IndirectlySerialized接口,所以类型比对通过。
ReferenceSerialized( Reference reference,Name name,Name contextName,Hashtable env ){this.reference = reference;this.name = name;this.contextName = contextName;this.env = env;}
public Object getObject() throws ClassNotFoundException, IOException{try{Context initialContext;if ( env == null )initialContext = new InitialContext();elseinitialContext = new InitialContext( env );Context nameContext = null;if ( contextName != null )nameContext = (Context) initialContext.lookup( contextName );return ReferenceableUtils.referenceToObject方法将( reference, name, nameContext, env );}catch (NamingException e){//e.printStackTrace();if ( logger.isLoggable( MLevel.WARNING ) )logger.log( MLevel.WARNING, "Failed to acquire the Context necessary to lookup an Object.", e );throw new InvalidObjectException( "Failed to acquire the Context necessary to lookup an Object: " + e.toString() );}}
return中调用了ReferenceableUtils类的referenceToObject方法将构造函数中传入的四个值当作参数传入继续跟进。
接着就判断工厂类地址是否为空,不为空则去远程地址加载工厂类,这里用到了urlclassLoader,然后通过class.forname生成一个class 类型的实例,就加载到了工厂类,即我们的恶意字节码类
Java反序列化一直是一个老生常谈的问题,理解这些原理性的知识可以更好的帮助我们找到执行链,你我终有一天也会发现理解事物的本质是如此重要。
- 结尾 - 精彩推荐 【技术分享】供应链攻击之PHP Composer漏洞 【技术分享】企业建设DevSecOps流程梳理 【技术分享】对抗样本及其背后性质分析(实战导向) 戳“阅读原文”查看更多内容