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:
@@ -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