qtc-de / beanshooter

JMX enumeration and attacking tool.
GNU General Public License v3.0
378 stars 45 forks source link

beanshooter issue #22

Closed dinosn closed 1 year ago

dinosn commented 1 year ago

Hi,

Thank you again for the awesome toolset both beanshooter and rmg are excellent tools.

I would like to write a question regarding an issue that I'm facing over a target, the setup is an old glassfish system.

From RMG:

root@system:~/tools/rmi/remote-method-guesser# java -jar rmg-4.3.1-jar-with-dependencies.jar enum ip 8686 --ssl
[+] RMI registry bound names:
[+]
[+]     - jmxrmi
[+]         --> javax.management.remote.rmi.RMIServerImpl_Stub (known class: JMX Server)
[+]             Endpoint: ip:8686  TLS: yes  ObjID: [-2d0c7c55:184e19f0930:-7fff, 7138797691780167918]
[+]
[+] RMI server codebase enumeration:
[+]
[+]     - The remote server does not expose any codebases.
[+]
[+] RMI server String unmarshalling enumeration:
[+]
[+]     - Caught ClassNotFoundException during lookup call.
[+]       --> The type java.lang.String is unmarshalled via readObject().
[+]       Configuration Status: Outdated
[+]
[+] RMI server useCodebaseOnly enumeration:
[+]
[+]     - Caught ClassCastException during lookup call.
[+]       --> The server ignored the provided codebase (useCodebaseOnly=true).
[+]       Configuration Status: Current Default
[+]
[+] RMI registry localhost bypass enumeration (CVE-2019-2684):
[+]
[+]     - Caught NotBoundException during unbind call (unbind was accepeted).
[+]       Vulnerability Status: Vulnerable
[+]
[+] RMI Security Manager enumeration:
[+]
[+]     - Caught Exception containing 'no security manager' during RMI call.
[+]       --> The server does not use a Security Manager.
[+]       Configuration Status: Current Default
[+]
[+] RMI server JEP290 enumeration:
[+]
[+]     - DGC rejected deserialization of java.util.HashMap (JEP290 is installed).
[+]       Vulnerability Status: Non Vulnerable
[+]
[+] RMI registry JEP290 bypass enumeration:
[+]
[+]     - Caught IllegalArgumentException after sending An Trinh gadget.
[+]       Vulnerability Status: Vulnerable
[+]
[+] RMI ActivationSystem enumeration:
[+]
[+]     - Caught NoSuchObjectException during activate call (activator not present).
[+]       Configuration Status: Current Default

From Beanshooter

root@system:~/tools/rmi/beanshooter# java -jar beanshooter-3.0.0-jar-with-dependencies.jar enum ip 8686 --ssl 
[+] Checking for unauthorized access:
[+]
[-] Caught java.io.NotSerializableException while invoking the newClient method.
[-] The exception occured unexpected and was not caught by beanshooter.
[-] Please report the exception to help improving the exception handling :)
[-] StackTrace:
java.rmi.UnmarshalException: Error unmarshaling return; nested exception is: 
    java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: com.sun.enterprise.admin.util.AdminLoginModule$PrincipalCallback
    at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:273)
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:164)
    at javax.management.remote.rmi.RMIServerImpl_Stub.newClient(Unknown Source)
    at javax.management.remote.rmi.RMIConnector.getConnection(RMIConnector.java:2430)
    at javax.management.remote.rmi.RMIConnector.connect(RMIConnector.java:308)
    at javax.management.remote.rmi.RMIConnector.connect(RMIConnector.java:249)
    at de.qtc.beanshooter.plugin.providers.RMIProvider.getMBeanServerConnection(RMIProvider.java:68)
    at de.qtc.beanshooter.plugin.PluginSystem.getMBeanServerConnectionUmanaged(PluginSystem.java:211)
    at de.qtc.beanshooter.operation.EnumHelper.enumAccess(EnumHelper.java:154)
    at de.qtc.beanshooter.operation.Dispatcher.enumerate(Dispatcher.java:147)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at de.qtc.beanshooter.operation.BeanshooterOperation.invoke(BeanshooterOperation.java:348)
    at de.qtc.beanshooter.Starter.main(Starter.java:22)
Caused by: java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: com.sun.enterprise.admin.util.AdminLoginModule$PrincipalCallback
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1676)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2431)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2355)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2213)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1669)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2431)
    at java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:633)
    at java.lang.Throwable.readObject(Throwable.java:915)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1184)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2322)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2213)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1669)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2431)
    at java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:633)
    at java.lang.Throwable.readObject(Throwable.java:915)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1184)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2322)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2213)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1669)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:503)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:461)
    at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:270)
    ... 15 more
Caused by: java.io.NotSerializableException: com.sun.enterprise.admin.util.AdminLoginModule$PrincipalCallback
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:441)
    at java.lang.Throwable.writeObject(Throwable.java:985)
    at sun.reflect.GeneratedMethodAccessor337.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:1140)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:441)
    at java.lang.Throwable.writeObject(Throwable.java:985)
    at sun.reflect.GeneratedMethodAccessor337.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:1140)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:396)
    at sun.rmi.transport.Transport$1.run(Transport.java:200)
    at sun.rmi.transport.Transport$1.run(Transport.java:197)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:573)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
[-] Cannot continue from here.

On a similar setup if a prior bind is issued from RMG on the service e.g.: java -jar rmg-4.3.1-jar-with-dependencies.jar bind ip 8686 127.0.0.1:4499 my-object3 --localhost-bypass --ssl

root@system:~/tools/rmi/remote-method-guesser# java -jar rmg-4.3.1-jar-with-dependencies.jar enum ip 8686 --ssl
[+] RMI registry bound names:
[+]
[+]     - my-object
[+]         --> javax.management.remote.rmi.RMIServerImpl_Stub (known class: JMX Server)
[+]             Endpoint: 127.0.0.1:4444  TLS: no  ObjID: [6633018:17cb5d1bb57:-7ff8, -8114172517417646722]
[+]     - my-object2
[+]         --> javax.management.remote.rmi.RMIServerImpl_Stub (known class: JMX Server)
[+]             Endpoint: 127.0.0.1:4455  TLS: no  ObjID: [6633018:17cb5d1bb57:-7ff8, -8114172517417646722]
[+]     - my-object3
[+]         --> javax.management.remote.rmi.RMIServerImpl_Stub (known class: JMX Server)
[+]             Endpoint: ip:4499  TLS: no  ObjID: [6633018:17cb5d1bb57:-7ff8, -8114172517417646722]
[+]     - jmxrmi
[+]         --> javax.management.remote.rmi.RMIServerImpl_Stub (known class: JMX Server)
[+]             Endpoint: ip:8686  TLS: yes  ObjID: [75fe59f:184e1b22228:-7fff, 2289227695834538993]
[+]
[+] RMI server codebase enumeration:
[+]
[+]     - The remote server does not expose any codebases.
[+]
[+] RMI server String unmarshalling enumeration:
[+]
[+]     - Caught ClassNotFoundException during lookup call.
[+]       --> The type java.lang.String is unmarshalled via readObject().
[+]       Configuration Status: Outdated
[+]
[+] RMI server useCodebaseOnly enumeration:
[+]
[+]     - Caught ClassCastException during lookup call.
[+]       --> The server ignored the provided codebase (useCodebaseOnly=true).
[+]       Configuration Status: Current Default
[+]
[+] RMI registry localhost bypass enumeration (CVE-2019-2684):
[+]
[+]     - Caught NotBoundException during unbind call (unbind was accepeted).
[+]       Vulnerability Status: Vulnerable
[+]
[+] RMI Security Manager enumeration:
[+]
[+]     - Caught Exception containing 'no security manager' during RMI call.
[+]       --> The server does not use a Security Manager.
[+]       Configuration Status: Current Default
[+]
[+] RMI server JEP290 enumeration:
[+]
[+]     - DGC rejected deserialization of java.util.HashMap (JEP290 is installed).
[+]       Vulnerability Status: Non Vulnerable
[+]
[+] RMI registry JEP290 bypass enumeration:
[+]
[+]     - Caught IllegalArgumentException after sending An Trinh gadget.
[+]       Vulnerability Status: Vulnerable
[+]
[+] RMI ActivationSystem enumeration:
[+]
[+]     - Caught NoSuchObjectException during activate call (activator not present).
[+]       Configuration Status: Current Default

Beanshooter will report:

root@system:~/tools/rmi/beanshooter# java -jar beanshooter-3.0.0-jar-with-dependencies.jar enum ip 8686 --ssl 
[+] Checking for unauthorized access:
[+]
[-] Caught java.net.ConnectException while invoking the newClient method.
[-] The JMX remote object refused the connection.
[-] The JMX bound name within the RMI registry is probably pointing to an invalid server.
[-] Cannot continue from here.

Regards, Nicolas

qtc-de commented 1 year ago

Hi Nicolas,

again, thanks for reporting :+1:

Lets start with the second output you reported as this one is easier to resolve. The recent versions of beanshooter do not look for a specific boundname like jmxrmi within the RMI registry, but take the first javax.management.remote.rmi.RMIServerImpl_Stub they find. In your case, this is probably some of your self created objects. Since these target a custom address (e.g. 127.0.0.1:4444) beanshooter attempts to connect to there. However, as the corresponding port is probably not opened, a ConnectionException is raised. This is expected behavior. To fix this, you need to target another bound name manually e.g. by specifying --bound-name jmxrmi

The other output is more confusing to me. Seems to be an odd glassfish behavior. If I understand the exception message correctly, you are running beanshooter also from the glassfish system? Have you also tried running it from another machine against the glassfish system? It would be interesting to see whether the issue occurs only on the client side, or also when communicating with a glassfish system in general :thinking:

dinosn commented 1 year ago

Hi!

Thank you for the response. All clear for the first item, the --bound-name can be used to proceed further.

For the second case, I'm running from a remote system, there is no access to the glassfish system. I have 2 similar setup of glassfish on the other end, on different ip and both of them respond the same. I will proceed with some tests using --bound-name to bind it on the correct address and revert back.

Regards, Nicolas

dinosn commented 1 year ago

Quick update on this, using --bound-name jmxrmi will cause a crash to the second system with multiple bound-names as it will also produce a crash on the case of one bound-name,

root@system:~/tools/rmi/beanshooter# java -jar beanshooter-3.0.0-jar-with-dependencies.jar enum IP 8686 --ssl --bound-name jmxrmi
[+] Checking for unauthorized access:
[+]
[-] Caught java.io.NotSerializableException while invoking the newClient method.
[-] The exception occured unexpected and was not caught by beanshooter.
[-] Please report the exception to help improving the exception handling :)
[-] StackTrace:
java.rmi.UnmarshalException: Error unmarshaling return; nested exception is: 
    java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: com.sun.enterprise.admin.util.AdminLoginModule$PrincipalCallback
    at java.rmi/sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:273)
    at java.rmi/sun.rmi.server.UnicastRef.invoke(UnicastRef.java:164)
    at java.management.rmi/javax.management.remote.rmi.RMIServerImpl_Stub.newClient(Unknown Source)
    at java.management.rmi/javax.management.remote.rmi.RMIConnector.getConnection(RMIConnector.java:2105)
    at java.management.rmi/javax.management.remote.rmi.RMIConnector.connect(RMIConnector.java:321)
    at java.management.rmi/javax.management.remote.rmi.RMIConnector.connect(RMIConnector.java:265)
    at de.qtc.beanshooter.plugin.providers.RMIProvider.getMBeanServerConnection(RMIProvider.java:68)
    at de.qtc.beanshooter.plugin.PluginSystem.getMBeanServerConnectionUmanaged(PluginSystem.java:211)
    at de.qtc.beanshooter.operation.EnumHelper.enumAccess(EnumHelper.java:154)
    at de.qtc.beanshooter.operation.Dispatcher.enumerate(Dispatcher.java:147)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at de.qtc.beanshooter.operation.BeanshooterOperation.invoke(BeanshooterOperation.java:348)
    at de.qtc.beanshooter.Starter.main(Starter.java:22)
Caused by: java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: com.sun.enterprise.admin.util.AdminLoginModule$PrincipalCallback
    at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1694)
    at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2496)
    at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2390)
    at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2228)
    at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1687)
    at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2496)
    at java.base/java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:625)
    at java.base/java.lang.Throwable.readObject(Throwable.java:896)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at java.base/java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1046)
    at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2357)
    at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2228)
    at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1687)
    at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2496)
    at java.base/java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:625)
    at java.base/java.lang.Throwable.readObject(Throwable.java:896)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at java.base/java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1046)
    at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2357)
    at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2228)
    at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1687)
    at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:489)
    at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:447)
    at java.rmi/sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:270)
    ... 15 more
Caused by: java.io.NotSerializableException: com.sun.enterprise.admin.util.AdminLoginModule$PrincipalCallback
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:441)
    at java.lang.Throwable.writeObject(Throwable.java:985)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:1140)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:441)
    at java.lang.Throwable.writeObject(Throwable.java:985)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:1140)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:396)
    at sun.rmi.transport.Transport$1.run(Transport.java:200)
    at sun.rmi.transport.Transport$1.run(Transport.java:197)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:573)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
[-] Cannot continue from here.

PS. rmg is working on the target by using AnTrihn gadget very well, but beanshooter has become my favorite for some time now for jmxrmi cases.

qtc-de commented 1 year ago

Thanks for the additional input. I will dig in the glassfish implementation of JMX to identify what is going wrong there. Probably takes some time, but I will come back to you :)

qtc-de commented 1 year ago

Hi @dinosn,

I finally found time to look at this issue again. As it turned out, it is a glassfish bug. I opened an issue in their repository. Here is a short summary:

GlassFish seems to use different LoginModules for login attempts with and without credentials. The LoginModule used for logins without credentials is the AdminLoginModule. This class also contains a corresponding description:

Handles the non-username/password ways an admin user can authenticate.

Within the AdminLoginModule, a custom callback is defined (PrincipalCallback). In contrast to all the default callbacks that ship with Java, this custom callback is not defined serializable. Finding this information was the easy part :D The difficult was to find out where the callback is serialized, because why should the server serialize a callback? After tracing the calls in the GlassFish source for a while, I found the following definition for a CallbackHandler:

private static class AuthenticationCallbackHandler implements CallbackHandler {
        private final String user;
        private final char[] pass;

        public AuthenticationCallbackHandler(String username, char[] password) {
            user = username;
            pass = password;
        }

        protected String getUsername() { return user; }
        protected char[] getPassword() { return pass; }

        @Override
        public void handle(Callback[] callbacks) throws UnsupportedCallbackException {
            for (Callback callback : callbacks) {
                if (callback instanceof NameCallback) {
                    ((NameCallback) callback).setName(user);
                } else if (callback instanceof PasswordCallback) {
                    ((PasswordCallback) callback).setPassword(pass);
                } else {
                    // TODO - Have configuration setting for throwing exception
                    throw new UnsupportedCallbackException(callback,
                        "AuthenticationCallbackHandler: Unrecognized Callback "
                            + callback.getClass().getName());
                }
            }
        }
    }

As one can see, this callback handler only handles NameCallback and PasswordCallback. All other callbacks (including the PrincipalCallback) cause an UnsupportedCallbackException that contains the unsupported callback as a property. When an exception is thrown during an RMI call, the exception is usually propagated back to the caller. Since RMI communication uses serialized objects, the exception needs to get serialized for this purpose. During this serialization process PrincipalCallback is attempted to be serialized too, which causes the exception.

I'm not totally sure whether GlassFish is going to fix that. This issue only occurs because we access the server in an incorrect way. Accessing the server with credentials works fine. Moreover, we all know that outdated RMI servers are a must have in each internal network. For this reason I will implement a workaround for the NotSerializableException. Might also be a good opportunity to catch the UnsupportedCallbackException, which is currently also not done :sweat_smile:

New release is coming soon :+1: