diff --git a/Gemfile b/Gemfile
index 2c7b9651e..a4035422e 100644
--- a/Gemfile
+++ b/Gemfile
@@ -26,6 +26,7 @@ end
gem "thin"
gem "sinatra", "1.3.2"
+gem "em-websocket", "~> 0.3.6"
gem "ansi"
gem "term-ansicolor", :require => "term/ansicolor"
gem "dm-core"
diff --git a/beef b/beef
index 0c1cc740f..b99cc5672 100755
--- a/beef
+++ b/beef
@@ -115,6 +115,7 @@ print_info "RESTful API key: #{BeEF::Core::Crypto::api_token}"
#@note Starts the WebSocket server
if config.get("beef.http.websocket.enable")
BeEF::Core::Websocket::Websocket.instance
+ print_info "Starting WebSocket server on port [#{config.get("beef.http.websocket.port")}], secure [#{config.get("beef.http.websocket.secure")}], timer [#{config.get("beef.http.websocket.alive_timer")}]"
end
diff --git a/core/bootstrap.rb b/core/bootstrap.rb
index 747720849..0ae748c22 100644
--- a/core/bootstrap.rb
+++ b/core/bootstrap.rb
@@ -55,5 +55,4 @@ require 'core/main/rest/handlers/admin'
require 'core/main/rest/api'
## @note Include Websocket
-require 'core/main/network_stack/websocket/lib/web_socket'
require 'core/main/network_stack/websocket/websocket'
diff --git a/core/main/handlers/modules/command.rb b/core/main/handlers/modules/command.rb
index 62d881378..e79516fd5 100644
--- a/core/main/handlers/modules/command.rb
+++ b/core/main/handlers/modules/command.rb
@@ -49,8 +49,8 @@ module BeEF
build_missing_beefjs_components(command_module.beefjs_components) if not command_module.beefjs_components.empty?
let= BeEF::Core::Websocket::Websocket.instance
- #@todo radoen debug this one
+ #todo antisnatchor: remove this gsub crap adding some hook packing.
if let.getsocket(hooked_browser.session)
funtosend=command_module.output.gsub('//
// Copyright 2012 Wade Alcorn wade@bindshell.net
@@ -68,10 +68,8 @@ module BeEF
// limitations under the License.
//', "")
let.sent(funtosend, hooked_browser.session)
- #print_info("We are sending #{funtosend}")
else
@body << command_module.output + "\n\n"
-
end
# @note prints the event to the console
if BeEF::Settings.console?
diff --git a/core/main/network_stack/websocket/lib/web_socket.rb b/core/main/network_stack/websocket/lib/web_socket.rb
deleted file mode 100644
index e2cbcb56c..000000000
--- a/core/main/network_stack/websocket/lib/web_socket.rb
+++ /dev/null
@@ -1,592 +0,0 @@
-# Copyright: Hiroshi Ichikawa
-# Lincense: New BSD Lincense
-# Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75
-# Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76
-# Reference: http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-07
-# Reference: http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10
-
-require "base64"
-require "socket"
-require "uri"
-require "digest/md5"
-require "digest/sha1"
-require "openssl"
-require "stringio"
-
-
-class WebSocket
-
- class << self
-
- attr_accessor(:debug)
-
- end
-
- class Error < RuntimeError
-
- end
-
- WEB_SOCKET_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
- OPCODE_CONTINUATION = 0x00
- OPCODE_TEXT = 0x01
- OPCODE_BINARY = 0x02
- OPCODE_CLOSE = 0x08
- OPCODE_PING = 0x09
- OPCODE_PONG = 0x0a
-
- def initialize(arg, params = {})
- if params[:server] # server
-
- @server = params[:server]
- @socket = arg
- line = gets().chomp()
- if !(line =~ /\AGET (\S+) HTTP\/1.1\z/n)
- raise(WebSocket::Error, "invalid request: #{line}")
- end
- @path = $1
- read_header()
- if @header["sec-websocket-version"]
- @web_socket_version = @header["sec-websocket-version"]
- @key3 = nil
- elsif @header["sec-websocket-key1"] && @header["sec-websocket-key2"]
- @web_socket_version = "hixie-76"
- @key3 = read(8)
- else
- @web_socket_version = "hixie-75"
- @key3 = nil
- end
- if !@server.accepted_origin?(self.origin)
- raise(WebSocket::Error,
- ("Unaccepted origin: %s (server.accepted_domains = %p)\n\n" +
- "To accept this origin, write e.g. \n" +
- " WebSocketServer.new(..., :accepted_domains => [%p]), or\n" +
- " WebSocketServer.new(..., :accepted_domains => [\"*\"])\n") %
- [self.origin, @server.accepted_domains, @server.origin_to_domain(self.origin)])
- end
- @handshaked = false
-
- else # client
-
- @web_socket_version = "hixie-76"
- uri = arg.is_a?(String) ? URI.parse(arg) : arg
-
- if uri.scheme == "ws"
- default_port = 80
- elsif uri.scheme = "wss"
- default_port = 443
- else
- raise(WebSocket::Error, "unsupported scheme: #{uri.scheme}")
- end
-
- @path = (uri.path.empty? ? "/" : uri.path) + (uri.query ? "?" + uri.query : "")
- host = uri.host + ((!uri.port || uri.port == default_port) ? "" : ":#{uri.port}")
- origin = params[:origin] || "http://#{uri.host}"
- key1 = generate_key()
- key2 = generate_key()
- key3 = generate_key3()
-
- socket = TCPSocket.new(uri.host, uri.port || default_port)
-
- if uri.scheme == "ws"
- @socket = socket
- else
- @socket = ssl_handshake(socket)
- end
-
- write(
- "GET #{@path} HTTP/1.1\r\n" +
- "Upgrade: WebSocket\r\n" +
- "Connection: Upgrade\r\n" +
- "Host: #{host}\r\n" +
- "Origin: #{origin}\r\n" +
- "Sec-WebSocket-Key1: #{key1}\r\n" +
- "Sec-WebSocket-Key2: #{key2}\r\n" +
- "\r\n" +
- "#{key3}")
- flush()
-
- line = gets().chomp()
- raise(WebSocket::Error, "bad response: #{line}") if !(line =~ /\AHTTP\/1.1 101 /n)
- read_header()
- if (@header["sec-websocket-origin"] || "").downcase() != origin.downcase()
- raise(WebSocket::Error,
- "origin doesn't match: '#{@header["sec-websocket-origin"]}' != '#{origin}'")
- end
- reply_digest = read(16)
- expected_digest = hixie_76_security_digest(key1, key2, key3)
- if reply_digest != expected_digest
- raise(WebSocket::Error,
- "security digest doesn't match: %p != %p" % [reply_digest, expected_digest])
- end
- @handshaked = true
-
- end
- @received = []
- @buffer = ""
- @closing_started = false
- end
-
- attr_reader(:server, :header, :path)
-
- def handshake(status = nil, header = {})
- if @handshaked
- raise(WebSocket::Error, "handshake has already been done")
- end
- status ||= "101 Switching Protocols"
- def_header = {}
- case @web_socket_version
- when "hixie-75"
- def_header["WebSocket-Origin"] = self.origin
- def_header["WebSocket-Location"] = self.location
- extra_bytes = ""
- when "hixie-76"
- def_header["Sec-WebSocket-Origin"] = self.origin
- def_header["Sec-WebSocket-Location"] = self.location
- extra_bytes = hixie_76_security_digest(
- @header["Sec-WebSocket-Key1"], @header["Sec-WebSocket-Key2"], @key3)
- else
- def_header["Sec-WebSocket-Accept"] = security_digest(@header["sec-websocket-key"])
- extra_bytes = ""
- end
- header = def_header.merge(header)
- header_str = header.map(){ |k, v| "#{k}: #{v}\r\n" }.join("")
- # Note that Upgrade and Connection must appear in this order.
- write(
- "HTTP/1.1 #{status}\r\n" +
- "Upgrade: websocket\r\n" +
- "Connection: Upgrade\r\n" +
- "#{header_str}\r\n#{extra_bytes}")
- flush()
- @handshaked = true
- end
-
- def send(data)
- if !@handshaked
- raise(WebSocket::Error, "call WebSocket\#handshake first")
- end
- case @web_socket_version
- when "hixie-75", "hixie-76"
- data = force_encoding(data.dup(), "ASCII-8BIT")
- write("\x00#{data}\xff")
- flush()
- else
- send_frame(OPCODE_TEXT, data, !@server)
- end
- end
-
- def receive()
- if !@handshaked
- raise(WebSocket::Error, "call WebSocket\#handshake first")
- end
- case @web_socket_version
-
- when "hixie-75", "hixie-76"
- packet = gets("\xff")
- return nil if !packet
- if packet =~ /\A\x00(.*)\xff\z/nm
- return force_encoding($1, "UTF-8")
- elsif packet == "\xff" && read(1) == "\x00" # closing
- close(1005, "", :peer)
- return nil
- else
- raise(WebSocket::Error, "input must be either '\\x00...\\xff' or '\\xff\\x00'")
- end
-
- else
- begin
- bytes = read(2).unpack("C*")
- fin = (bytes[0] & 0x80) != 0
- opcode = bytes[0] & 0x0f
- mask = (bytes[1] & 0x80) != 0
- plength = bytes[1] & 0x7f
- if plength == 126
- bytes = read(2)
- plength = bytes.unpack("n")[0]
- elsif plength == 127
- bytes = read(8)
- (high, low) = bytes.unpack("NN")
- plength = high * (2 ** 32) + low
- end
- if @server && !mask
- # Masking is required.
- @socket.close()
- raise(WebSocket::Error, "received unmasked data")
- end
- mask_key = mask ? read(4).unpack("C*") : nil
- payload = read(plength)
- payload = apply_mask(payload, mask_key) if mask
- case opcode
- when OPCODE_TEXT
- return force_encoding(payload, "UTF-8")
- when OPCODE_BINARY
- raise(WebSocket::Error, "received binary data, which is not supported")
- when OPCODE_CLOSE
- close(1005, "", :peer)
- return nil
- when OPCODE_PING
- raise(WebSocket::Error, "received ping, which is not supported")
- when OPCODE_PONG
- else
- raise(WebSocket::Error, "received unknown opcode: %d" % opcode)
- end
- rescue EOFError
- return nil
- end
-
- end
- end
-
- def tcp_socket
- return @socket
- end
-
- def host
- return @header["host"]
- end
-
- def origin
- case @web_socket_version
- when "7", "8"
- name = "sec-websocket-origin"
- else
- name = "origin"
- end
- if @header[name]
- return @header[name]
- else
- raise(WebSocket::Error, "%s header is missing" % name)
- end
- end
-
- def location
- return "ws://#{self.host}#{@path}"
- end
-
- # Does closing handshake.
- def close(code = 1005, reason = "", origin = :self)
- if !@closing_started
- case @web_socket_version
- when "hixie-75", "hixie-76"
- write("\xff\x00")
- else
- if code == 1005
- payload = ""
- else
- payload = [code].pack("n") + force_encoding(reason.dup(), "ASCII-8BIT")
- end
- send_frame(OPCODE_CLOSE, payload, false)
- end
- end
- @socket.close() if origin == :peer
- @closing_started = true
- end
-
- def close_socket()
- @socket.close()
- end
-
- private
-
- NOISE_CHARS = ("\x21".."\x2f").to_a() + ("\x3a".."\x7e").to_a()
-
- def read_header()
- @header = {}
- while line = gets()
- line = line.chomp()
- break if line.empty?
- if !(line =~ /\A(\S+): (.*)\z/n)
- raise(WebSocket::Error, "invalid request: #{line}")
- end
- @header[$1] = $2
- @header[$1.downcase()] = $2
- end
- if !@header["upgrade"]
- raise(WebSocket::Error, "Upgrade header is missing")
- end
- if !(@header["upgrade"] =~ /\AWebSocket\z/i)
- raise(WebSocket::Error, "invalid Upgrade: " + @header["upgrade"])
- end
- if !@header["connection"]
- raise(WebSocket::Error, "Connection header is missing")
- end
- if @header["connection"].split(/,/).grep(/\A\s*Upgrade\s*\z/i).empty?
- raise(WebSocket::Error, "invalid Connection: " + @header["connection"])
- end
- end
-
- def send_frame(opcode, payload, mask)
- payload = force_encoding(payload.dup(), "ASCII-8BIT")
- # Setting StringIO's encoding to ASCII-8BIT.
- buffer = StringIO.new(force_encoding("", "ASCII-8BIT"))
- write_byte(buffer, 0x80 | opcode)
- masked_byte = mask ? 0x80 : 0x00
- if payload.bytesize <= 125
- write_byte(buffer, masked_byte | payload.bytesize)
- elsif payload.bytesize < 2 ** 16
- write_byte(buffer, masked_byte | 126)
- buffer.write([payload.bytesize].pack("n"))
- else
- write_byte(buffer, masked_byte | 127)
- buffer.write([payload.bytesize / (2 ** 32), payload.bytesize % (2 ** 32)].pack("NN"))
- end
- if mask
- mask_key = Array.new(4){ rand(256) }
- buffer.write(mask_key.pack("C*"))
- payload = apply_mask(payload, mask_key)
- end
- buffer.write(payload)
- write(buffer.string)
- end
-
- def gets(rs = $/)
- line = @socket.gets(rs)
- $stderr.printf("recv> %p\n", line) if WebSocket.debug
- return line
- end
-
- def read(num_bytes)
- str = @socket.read(num_bytes)
- $stderr.printf("recv> %p\n", str) if WebSocket.debug
- if str && str.bytesize == num_bytes
- return str
- else
- raise(EOFError)
- end
- end
-
- def write(data)
- if WebSocket.debug
- data.scan(/\G(.*?(\n|\z))/n) do
- $stderr.printf("send> %p\n", $&) if !$&.empty?
- end
- end
- @socket.write(data)
- end
-
- def flush()
- @socket.flush()
- end
-
- def write_byte(buffer, byte)
- buffer.write([byte].pack("C"))
- end
-
- def security_digest(key)
- return Base64.encode64(Digest::SHA1.digest(key + WEB_SOCKET_GUID)).gsub(/\n/, "")
- end
-
- def hixie_76_security_digest(key1, key2, key3)
- bytes1 = websocket_key_to_bytes(key1)
- bytes2 = websocket_key_to_bytes(key2)
- return Digest::MD5.digest(bytes1 + bytes2 + key3)
- end
-
- def apply_mask(payload, mask_key)
- orig_bytes = payload.unpack("C*")
- new_bytes = []
- orig_bytes.each_with_index() do |b, i|
- new_bytes.push(b ^ mask_key[i % 4])
- end
- return new_bytes.pack("C*")
- end
-
- def generate_key()
- spaces = 1 + rand(12)
- max = 0xffffffff / spaces
- number = rand(max + 1)
- key = (number * spaces).to_s()
- (1 + rand(12)).times() do
- char = NOISE_CHARS[rand(NOISE_CHARS.size)]
- pos = rand(key.size + 1)
- key[pos...pos] = char
- end
- spaces.times() do
- pos = 1 + rand(key.size - 1)
- key[pos...pos] = " "
- end
- return key
- end
-
- def generate_key3()
- return [rand(0x100000000)].pack("N") + [rand(0x100000000)].pack("N")
- end
-
- def websocket_key_to_bytes(key)
- num = key.gsub(/[^\d]/n, "").to_i() / key.scan(/ /).size
- return [num].pack("N")
- end
-
- def force_encoding(str, encoding)
- if str.respond_to?(:force_encoding)
- return str.force_encoding(encoding)
- else
- return str
- end
- end
-
- def ssl_handshake(socket)
- ssl_context = OpenSSL::SSL::SSLContext.new()
- ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ssl_context)
- ssl_socket.sync_close = true
- ssl_socket.connect()
- return ssl_socket
- end
-
-end
-
-
-class WebSocketServer
-
- def initialize(params_or_uri, params = nil)
- if params
- uri = params_or_uri.is_a?(String) ? URI.parse(params_or_uri) : params_or_uri
- params[:port] ||= uri.port
- params[:accepted_domains] ||= [uri.host]
- else
- params = params_or_uri
- end
- @port = params[:port] || 80
- @accepted_domains = params[:accepted_domains]
- if !@accepted_domains
- raise(ArgumentError, "params[:accepted_domains] is required")
- end
- if params[:host]
- @tcp_server = TCPServer.open(params[:host], @port)
- else
- @tcp_server = TCPServer.open(@port)
- end
- end
-
- attr_reader(:tcp_server, :port, :accepted_domains)
-
- def run(&block)
- while true
- Thread.start(accept()) do |s|
- begin
- ws = create_web_socket(s)
- yield(ws) if ws
- rescue => ex
- print_backtrace(ex)
- ensure
- begin
- ws.close_socket() if ws
- rescue
- end
- end
- end
- end
- end
-
- def accept()
- return @tcp_server.accept()
- end
-
-
- def accepted_origin?(origin)
- #domain = origin_to_domain(origin)
- #return @accepted_domains.any?(){ |d| File.fnmatch(d, domain) }
-
- #todo antisnatchor -> we want to accept every origin
- true
- end
-
- def origin_to_domain(origin)
- if origin == "null" || origin == "file://" # local file
- return "null"
- else
- return URI.parse(origin).host
- end
- end
-
- def create_web_socket(socket)
- ch = socket.getc()
- if ch == ?<
- # This is Flash socket policy file request, not an actual Web Socket connection.
- send_flash_socket_policy_file(socket)
- return nil
- else
- socket.ungetc(ch)
- return WebSocket.new(socket, :server => self)
- end
- end
-
- private
-
- def print_backtrace(ex)
- $stderr.printf("%s: %s (%p)\n", ex.backtrace[0], ex.message, ex.class)
- for s in ex.backtrace[1..-1]
- $stderr.printf(" %s\n", s)
- end
- end
-
- # Handles Flash socket policy file request sent when web-socket-js is used:
- # http://github.com/gimite/web-socket-js/tree/master
- def send_flash_socket_policy_file(socket)
- socket.puts('')
- socket.puts('')
- socket.puts('')
- for domain in @accepted_domains
- next if domain == "file://"
- socket.puts("")
- end
- socket.puts('')
- socket.close()
- end
-
-end
-
-
-if __FILE__ == $0
- Thread.abort_on_exception = true
-
- if ARGV[0] == "server" && ARGV.size == 3
-
- server = WebSocketServer.new(
- :accepted_domains => [ARGV[1]],
- :port => ARGV[2].to_i())
- puts("Server is running at port %d" % server.port)
- server.run() do |ws|
- puts("Connection accepted")
- puts("Path: #{ws.path}, Origin: #{ws.origin}")
- if ws.path == "/"
- ws.handshake()
- while data = ws.receive()
- printf("Received: %p\n", data)
- ws.send(data)
- printf("Sent: %p\n", data)
- end
- elsif ws.path == "/badjs"
- printf("Received: %s\n", ws.path)
- #modules code here inject
-
- else
- ws.handshake("404 Not Found")
- end
- puts("Connection closed")
- end
-
- elsif ARGV[0] == "client" && ARGV.size == 2
-
- client = WebSocket.new(ARGV[1])
- puts("Connected")
- Thread.new() do
- while data = client.receive()
- printf("Received: %p\n", data)
- end
- end
- $stdin.each_line() do |line|
- data = line.chomp()
- client.send(data)
- printf("Sent: %p\n", data)
- end
-
- else
-
- $stderr.puts("Usage:")
- $stderr.puts(" ruby web_socket.rb server ACCEPTED_DOMAIN PORT")
- $stderr.puts(" ruby web_socket.rb client ws://HOST:PORT/")
- exit(1)
-
- end
-end
diff --git a/core/main/network_stack/websocket/websocket.rb b/core/main/network_stack/websocket/websocket.rb
index e66487426..134ea4007 100644
--- a/core/main/network_stack/websocket/websocket.rb
+++ b/core/main/network_stack/websocket/websocket.rb
@@ -13,64 +13,59 @@
# 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'
+ require 'em-websocket'
class Websocket
include Singleton
include BeEF::Core::Handlers::Modules::Command
- # @note obtain dynamic mount points from HttpHookServer
- MOUNTS = BeEF::Core::Server.instance.mounts
- @@activeSocket= Hash.new #empty at begin
+
+ @@activeSocket= Hash.new
@@lastalive= Hash.new
@@config = BeEF::Core::Configuration.instance
+
def initialize
port = @@config.get("beef.http.websocket.port")
secure = @@config.get("beef.http.websocket.secure")
- #todo antisnatchor: start websocket secure if beef.http.websocket.secure == true
- server = WebSocketServer.new :accepted_domains => "127.0.0.1",
- :port => port
- print_info("Started WebSocket server: port [#{port.to_s}], secure [#{secure.to_s}]")
-
Thread.new {
- server.run() do |ws|
- begin
- print_debug("Path requested #{ws.path} Origins #{ws.origin}")
- if ws.path == "/"
- ws.handshake() #accept and connect
- while true
- #command interpretation
- message = ws.receive()
- messageHash = JSON.parse("#{message}")
- #@note messageHash[result] is Base64 encoded
- if (messageHash["cookie"]!= nil)
- print_info("Browser #{ws.origin} says helo! WebSocket is running")
- #insert new connection in activesocket
- @@activeSocket["#{messageHash["cookie"]}"] = ws
- print_debug("In activesocket we have #{@@activeSocket}")
- elsif messageHash["alive"] != nil
- hooked_browser = BeEF::Core::Models::HookedBrowser.first(:session => messageHash["alive"])
+ sleep 2 # prevent issues when starting at the same time the TunnelingProxy, Thin and Evented WebSockets
+ EventMachine.run { #todo antisnatchor: add support for WebSocket secure (new object with different config options, then start)
+ EventMachine::WebSocket.start(:host => "0.0.0.0", :port => port) do |ws|
+ begin
+ print_debug "New WebSocket channel open."
+ ws.onmessage { |msg|
+ msg_hash = JSON.parse("#{msg}")
+ #@note messageHash[result] is Base64 encoded
+ if (msg_hash["cookie"]!= nil)
+ print_debug("WebSocket - Browser says helo! WebSocket is running")
+ #insert new connection in activesocket
+ @@activeSocket["#{msg_hash["cookie"]}"] = ws
+ print_debug("WebSocket - activeSocket content [#{@@activeSocket}]")
+ elsif msg_hash["alive"] != nil
+ hooked_browser = BeEF::Core::Models::HookedBrowser.first(:session => msg_hash["alive"])
+ unless hooked_browser.nil?
hooked_browser.lastseen = Time.new.to_i
hooked_browser.count!
hooked_browser.save
zombie_commands = BeEF::Core::Models::Command.all(:hooked_browser_id => hooked_browser.id, :instructions_sent => false)
- zombie_commands.each{|command| add_command_instructions(command, hooked_browser)}
- else
- #json recv is a cmd response decode and send all to
- #we have to call dynamicreconstructor handler camp must be websocket
- #print_debug("Received from WebSocket #{messageHash}")
- execute(messageHash)
+ zombie_commands.each { |command| add_command_instructions(command, hooked_browser) }
end
+ else
+ #json recv is a cmd response decode and send all to
+ #we have to call dynamicreconstructor handler camp must be websocket
+ #print_debug("Received from WebSocket #{messageHash}")
+ execute(msg_hash)
end
- end
- rescue Exception => e
- print_error "Hooked browser from origin #{ws.origin} abruptly disconnected. #{e}"
- end
- end
+ }
+ rescue Exception => e
+ print_error "WebSocket error: #{e}"
+ end
+ end
+ }
}
end
@@ -99,15 +94,14 @@ module BeEF
command_results=Hash.new
command_results["data"]=Base64.decode64(data["result"])
command_results["data"].force_encoding('UTF-8')
- (print_error "BeEFhook is invalid"; return) if not BeEF::Filters.is_valid_hook_session_id?(data["bh"])
+ hooked_browser = data["bh"]
+ (print_error "BeEFhook is invalid"; return) if not BeEF::Filters.is_valid_hook_session_id?(hooked_browser)
(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"],
- @@config.get("beef.module.#{data["handler"].gsub("/command/","").gsub(".js","")}.name"), command_results)
+ BeEF::Core::Models::Command.save_result(hooked_browser, data["cid"],
+ @@config.get("beef.module.#{data["handler"].gsub("/command/", "").gsub(".js", "")}.name"), command_results)
end
-
-
end
end
end