Java反序列化学习记录
关键词: 漏洞 状态: 进行中
反序列化分享【226安全团队内部周分享内容】
https://www.bilibili.com/video/BV1pt411A7mX
从零开始Weblogic反序列化漏洞
https://www.bilibili.com/video/BV16Z4y1K7Rb
参考与致谢:
https://eviladan0s.github.io/2020/07/30/java-sec-newbee/
https://eviladan0s.github.io/2020/07/31/learn-CommonsCollections1/
JavaEE开发体系MVC
应用程序被划分成模型层model 视图层 view 控制层Controller
Servlet (处理用户请求controller)+ JSP(处理数据显示view ) + JavaBean(负责封装数据model )
- RMI
RMI调用远程Java对象和方法,能让程序员开发处基于Java的分布式应用,RMI目前使用JRMP进行通信。
- JRMP
JRMP时专门为Java的远程对象定制的协议
- JNDI
Java提供目录系统,将服务名称和对象关联,使得开发过程及漏洞利用过程中可以使用名称来访问对象
- T3协议
Weblogic RMI通信使用T3协议,和Web共用一个端口
利用工具
ysoserial:常见gadget链集合,如Commons Collections
Commons Collections是一个拓展Java标准库的Collection结构的第三方基础库
分析:https://www.anquanke.com/post/id/229108
marshalsec
Java反序列化利用工具,开启RMI、LDAP服务,查询可用GAdget,生成特定Payload
RMI
Java RMI(Remote Method Invocation)即Java远程方法调用,它允许一个 JVM 上的 object 调用另一个 JVM 上 object 方法。
RMI程序通常包括三部分:
RMI Registry,提供注册查询等功能,是一种特殊的Remote Object RMI Server,创建Remote Object,将其注册到RMI Registry RMI Client, 通过name向 RMI Registry获取Remote Object reference (stub),调用其方法
RMI程序示例
一个继承java.rmi.Remote的接口 一个实现此接口的类 一个用来创建Registry的主类,实例化后绑定地址
- 实现接口,接口继承java.rmi.Remote
package RMItest;
import java.rmi.Remote;
public interface RMIRemote extends Remote {
public void rmiTest();//声明函数
}
- 使用上述接口实现:
package RMItest;
public class RMIremoteTest implements RMIRemote{
@Override
public void rmiTest() {
System.out.println("hello");
}
}
- 服务端
package RMItest;
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Server {
public static void main(String[] args) throws RemoteException, AlreadyBoundException {
RMIRemote rmitest = new RMIremoteTest(); //接口需要使用实现的具体类去创建对象
Registry registry = LocateRegistry.createRegistry(1099);
registry.bind("rmi://127.0.0.1/test", rmitest);
}
}
- 客户端
package RMItest;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Client {
public static void main(String[] args) throws RemoteException, NotBoundException {
Registry registry = LocateRegistry.getRegistry("127.0.0.1",1099);
RMIRemote rmi = (RMIRemote) registry.lookup("rmi://127.0.0.1/test");
rmi.rmiTest();
}
}
反射
Java-反射-简 中反射介绍
利用反射命令执行
Java反序列化方法
- 找序列化入口 source
- 调用链 gadget
- 出发漏洞的目标方法 sink
触发漏洞的方法
Runtime.exec()方法命令执行
String [] cmd={"cmd","/C","copy exe1 exe2"};
Process proc =Runtime.getRuntime().exec(cmd);
Method.invoke() 需要释放的选择方法和参数,反射执行java方法
RMI/JNDI/JRMP引用远程对象,简介实现任意代码执行
Apache Commons Collections基础知识
使用transform方法反射调用任意对象函数
使用transform方法执行命令
import org.apache.commons.collections.functors.InvokerTransformer;
public class test {
public static void main(String[] args){
InvokerTransformer myInvoke = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{new String("c:\\windows\\system32\\notepad.exe")});
myInvoke.transform(Runtime.getRuntime());
}
}
InvokerTransformer 的构造方法
public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
this.iMethodName = methodName;
this.iParamTypes = paramTypes;
this.iArgs = args;
}
transform方法
public Object transform(Object input) {
if (input == null) {
return null;
} else {
try {
Class cls = input.getClass();
Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
return method.invoke(input, this.iArgs);
} catch (NoSuchMethodException var5) {
throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' does not exist");
} catch (IllegalAccessException var6) {
throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' cannot be accessed");
} catch (InvocationTargetException var7) {
throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' threw an exception", var7);
}
}
}
}