Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Errors caused by NAT port mapping #42

Open
genxor opened this issue Mar 10, 2024 · 5 comments
Open

Errors caused by NAT port mapping #42

genxor opened this issue Mar 10, 2024 · 5 comments

Comments

@genxor
Copy link

genxor commented Mar 10, 2024

This issue has been troubling me for a long time. When encountering a JMX service in the internal network, and the jmxremote.port is mapped to the upstream IP through NAT port forwarding, all tests will fail. I look forward to a solution.

Here, my setup is as follows:
vmware workstation host
ip: 172.16.67.128
os: Ubuntu 20.04

docker container
ip:172.17.0.2
image: docker pull tomcat:7.0.68-jre8

a Docker container installed on VMHost, with Tomcat 7.0.68 running JMX service, IP mapped from 172.17.0.2:9999 to 172.16.67.128:39001.

The 1st screenshot describes the problem I encountered.
image

The 2nd screenshot shows that testing is successful when directly accessing the internal IP and port.
image

@qtc-de
Copy link
Owner

qtc-de commented Mar 16, 2024

Hi @genxor 👋

did you only map the 9999 port? This is not sufficient for RMI (or at least not with your JMX configuration). You can see this in the nmap output of your first screenshot that shows the endpoint 172.17.0.2:36119. This is the actual JMX service and beanshooter complains that it cannot reach this endpoint.

What you did is only mapping the RMI registry. This is the naming service of Java RMI that maps human readable bound names to the actual RMI endpoints (IP:PORT). In your case, the registry is listening on 9999. The actual JMX service seems to use a random port. It creates a listening socket on this port and informs the registry that the JMX service is now available on 172.17.0.2:36119.

Notice that regular RMI tools (e.g. jconsole) will completely fail here, as they will try to connect to 172.17.0.2, which is probably not reachable in your setup. beanshooter implements an auto-remapping and remaps the above endpoint to 172.16.67.128:36119. But since you did not forward that port, it reports that the connection was refused.

Now you probably ask how to map a randomly assigned port? Luckily, Java RMI allows multiple remote objects to run on the same port. Therefore, you can use the same port for the RMI registry and the JMX service. If you use Java's default JMX service, you can achieve this by using the following JAVA_OPTIONS:

-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.rmi.port=9999

If the above written stuff does not make sense to you, you may want to take a look at my Java RMI Arsenal talk. It starts with a beginner friendly overview of Java RMI :)

@genxor
Copy link
Author

genxor commented Mar 16, 2024

Hi @qtc-de ,

Thanks for your reply. I followed your instructions and modified the configuration, but it seems that beanshooter still doesn't work, like showing in the following pic

image
And the port maping is here
image
I also used nmap to scan the rmi port and confirmed that the JMX service has been bound on the port 9999.
image
And beanshooter still doesn't work
image

My additional inquiry concerns whether there are potential exploitation techniques available if the JMX service port is not mapped externally but is instead listening only within an internal network environment.

Looking forward to your answer.

@qtc-de
Copy link
Owner

qtc-de commented Mar 19, 2024

I'm sorry, I was missing this detail in my explanation above.

The problem is now the port mapping. The RMI registry now tells beanshooter to connect to port 9999, since it does not know, that the port is actually remapped. Therefore, beanshooter attempts to connect to this port and fails again. To fix this issue, you could configure the registry and JMX to run on the same port as you forward:

-Dcom.sun.management.jmxremote.port=39001
-Dcom.sun.management.jmxremote.rmi.port=39001

This should work. I may add an option to beanshooter in future that allows to overwrite the JMX IP/port. However, you will probably never encounter a configuration like yours in an productive environment. It is simply wrong configured and no Tool will be able to work with it. But well, never say never and administrators could of course fail to configure JMX properly. So I will add these options in future 👍

If the JMX service port is only available internally you can only exploit it if there are other vulnerabilities. E.g. the registry itself could be vulnerable (you can use https://github.com/qtc-de/remote-method-guesser to check this). Or you may have other services that allow to perform SSRF attacks (check this blog https://blog.tneitzel.eu/posts/01-attacking-java-rmi-via-ssrf/).

@genxor
Copy link
Author

genxor commented Mar 19, 2024

Hi @qtc-de,

Thank you for answering my doubts. Really appreciated your feeback. Btw, could you elaborate on how to overwrite the JMX IP/port? Many Thanks.

qtc-de added a commit that referenced this issue Mar 25, 2024
Added the --overwrite-host and --overwrite-port options that allow to
overwrite the destination endpoint pointed to by a bound name (see #42).
@qtc-de
Copy link
Owner

qtc-de commented Mar 25, 2024

Overwriting the JMX IP/Port is not that straight forward. These properties are deeply anchored within the internal Java types used during RMI communication. Luckily, beanshooter already implements host redirection (as mentioned above). This is done by defining a custom socket factory.

Java RMI lets you define which socket factory to use when RMI objects create outbound connection. beanshooter creates a custom socket factory on startup, which saves the initially entered target host as variable. Afterwards, if RMI connections attempt to connect to a different host, the socket factory will replace the new target with the previously specified one.

I extended this functionality a little bit. Users can now specify the --overwrite-host parameter to overwrite the destination host of an RMI object. This can be different than the actual target specified in beanshooters main arguments. Additionally, the --overwrite-port option allows you to overwrite the port.

With these options, you should now be able to solve your problem from above. The options are only available on the develop branch yet and were not tested. Feel free to report any bugs you encounter 🙃

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants