From 50e7a1c206fb7fc20676d1556d6784ec01512210 Mon Sep 17 00:00:00 2001 From: antisnatchor Date: Sat, 25 Aug 2012 10:18:56 +0100 Subject: [PATCH] Refactored WebSocket code. --- beef | 4 +- config.yaml | 8 +- core/main/client/websocket.js | 2 +- .../main/network_stack/websocket/websocket.rb | 204 ++++++++++++------ 4 files changed, 141 insertions(+), 77 deletions(-) diff --git a/beef b/beef index 5b84151e6..2a9672d46 100755 --- a/beef +++ b/beef @@ -124,9 +124,9 @@ 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").to_i}], secure [#{config.get("beef.http.websocket.secure")}], timer [#{config.get("beef.http.websocket.alive_timer")}]" + print_info "Starting WebSocket server on port [#{config.get("beef.http.websocket.port").to_i}], timer [#{config.get("beef.http.websocket.alive_timer")}]" if config.get("beef.http.websocket.secure") - print_info "Starting WebSocket-Secured server on port [#{config.get("beef.http.websocket.secure_port").to_i}], timer [#{config.get("beef.http.websocket.alive_timer")}]" + print_info "Starting WebSocketSecure server on port [#{config.get("beef.http.websocket.secure_port").to_i}], timer [#{config.get("beef.http.websocket.alive_timer")}]" end end diff --git a/config.yaml b/config.yaml index c746ca493..46c5e98c0 100644 --- a/config.yaml +++ b/config.yaml @@ -17,7 +17,7 @@ beef: version: '0.4.3.7-alpha' - debug: true + debug: false restrictions: # subnet of browser ip addresses that can hook to the framework @@ -42,9 +42,9 @@ beef: # Prefer WebSockets over XHR-polling when possible. websocket: enable: false - secure: false # use WebSocketSecure work only on https domain and whit https support enabled in BeEF - port: 61985 # good success rate through proxies - secure_port: 61986 #to accept wss connection + secure: true # use WebSocketSecure work only on https domain and whit https support enabled in BeEF + port: 61985 # WS: good success rate through proxies + secure_port: 61986 # WSS alive_timer: 1000 # poll BeEF every second # Imitate a specified web server (default root page, 404 default error page, 'Server' HTTP response header) diff --git a/core/main/client/websocket.js b/core/main/client/websocket.js index e1cca10ee..69ab27515 100644 --- a/core/main/client/websocket.js +++ b/core/main/client/websocket.js @@ -28,7 +28,7 @@ beef.websocket = { var webSocketSecure = <%= @websocket_secure %>; var protocol = "ws://"; //console.log("We are inside init"); - /*use wss only if hooked domain is under tls*/ + /*use wss only if hooked domain is under https. Mixed-content in WS is quite different from a non-WS context*/ if(webSocketSecure && window.location.protocol=="https:"){ protocol = "wss://"; webSocketPort= <%= @websocket_sec_port %>; diff --git a/core/main/network_stack/websocket/websocket.rb b/core/main/network_stack/websocket/websocket.rb index b5c6ec0e4..a17d3c35d 100644 --- a/core/main/network_stack/websocket/websocket.rb +++ b/core/main/network_stack/websocket/websocket.rb @@ -33,84 +33,150 @@ module BeEF def initialize - secure = @@config.get("beef.http.websocket.secure") #&& @@config.get("beef.http.https.enable") + secure = @@config.get("beef.http.websocket.secure") @root_dir = File.expand_path('../../../../../', __FILE__) if (secure) - #Thread for websocket-secure - Thread.new { - port = @@config.get("beef.http.websocket.secure_port") - sleep 2 # prevent issues when starting at the same time the TunnelingProxy, Thin and Evented WebSockets - EventMachine.run { - - wsopt = {:host => "0.0.0.0", :port => port, :secure => true, - :tls_options => { - :private_key_file => @root_dir+"/"+@@config.get("beef.http.https.key"), - :cert_chain_file => @root_dir+"/"+ @@config.get("beef.http.https.cert") - } - } - - - EventMachine::WebSocket.start(wsopt) do |ws| - begin - print_debug "New WebSocket-secured channel open." - ws.onmessage { |msg| - msg_hash = JSON.parse("#{msg}") - #@note messageHash[result] is Base64 encoded - if (msg_hash["cookie"]!= nil) - print_debug("WebSocket-secured - Browser says helo! WebSocket is running") - #insert new connection in activesocket - @@activeSocket["#{msg_hash["cookie"]}"] = ws - print_debug("WebSocket-secured - 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 - - #Check if new modules need to be sent - 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) } - - #@todo antisnatchor: - #@todo - re-use the pre_hook_send callback mechanisms to have a generic check for multipl extensions - #Check if new forged requests need to be sent (Requester/TunnelingProxy) - dhook = BeEF::Extension::Requester::API::Hook.new - dhook.requester_run(hooked_browser, '') - - #Check if new XssRays scan need to be started - xssrays = BeEF::Extension::Xssrays::API::Scan.new - xssrays.start_scan(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 - } - rescue Exception => e - print_error "WebSocket-secured error: #{e}" - end - end - } - + ws_secure_options = {:host => "0.0.0.0", :port => @@config.get("beef.http.websocket.secure_port"), :secure => true, + :tls_options => { + :private_key_file => @root_dir+"/"+@@config.get("beef.http.https.key"), + :cert_chain_file => @root_dir+"/"+ @@config.get("beef.http.https.cert") + } } + # @note Start a WSS server socket + start_websocket_server(ws_secure_options, true) end - #Thread for websocket + # @note Start a WS server socket + ws_options = {:host => "0.0.0.0", :port => @@config.get("beef.http.websocket.port")} + start_websocket_server(ws_options,false) + + # #Thread for websocket-secure + # Thread.new { + # port = @@config.get("beef.http.websocket.secure_port") + # sleep 2 # prevent issues when starting at the same time the TunnelingProxy, Thin and Evented WebSockets + # EventMachine.run { + # + # wsopt = {:host => "0.0.0.0", :port => port, :secure => true, + # :tls_options => { + # :private_key_file => @root_dir+"/"+@@config.get("beef.http.https.key"), + # :cert_chain_file => @root_dir+"/"+ @@config.get("beef.http.https.cert") + # } + # } + # + # + # EventMachine::WebSocket.start(wsopt) do |ws| + # begin + # print_debug "New WebSocket-secured channel open." + # ws.onmessage { |msg| + # msg_hash = JSON.parse("#{msg}") + # #@note messageHash[result] is Base64 encoded + # if (msg_hash["cookie"]!= nil) + # print_debug("WebSocket-secured - Browser says helo! WebSocket is running") + # #insert new connection in activesocket + # @@activeSocket["#{msg_hash["cookie"]}"] = ws + # print_debug("WebSocket-secured - 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 + # + # #Check if new modules need to be sent + # 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) } + # + # #@todo antisnatchor: + # #@todo - re-use the pre_hook_send callback mechanisms to have a generic check for multipl extensions + # #Check if new forged requests need to be sent (Requester/TunnelingProxy) + # dhook = BeEF::Extension::Requester::API::Hook.new + # dhook.requester_run(hooked_browser, '') + # + # #Check if new XssRays scan need to be started + # xssrays = BeEF::Extension::Xssrays::API::Scan.new + # xssrays.start_scan(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 + # } + # rescue Exception => e + # print_error "WebSocket-secured error: #{e}" + # end + # end + # } + # + # } + # + ##Thread for websocket + #Thread.new { + # port = @@config.get("beef.http.websocket.port") + # sleep 2 # prevent issues when starting at the same time the TunnelingProxy, Thin and Evented WebSockets + # EventMachine.run { + # + # wsopt = {:host => "0.0.0.0", :port => port} + # + # + # EventMachine::WebSocket.start(wsopt) 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 + # + # #Check if new modules need to be sent + # 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) } + # + # #@todo antisnatchor: + # #@todo - re-use the pre_hook_send callback mechanisms to have a generic check for multipl extensions + # #Check if new forged requests need to be sent (Requester/TunnelingProxy) + # dhook = BeEF::Extension::Requester::API::Hook.new + # dhook.requester_run(hooked_browser, '') + # + # #Check if new XssRays scan need to be started + # xssrays = BeEF::Extension::Xssrays::API::Scan.new + # xssrays.start_scan(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 + # } + # rescue Exception => e + # print_error "WebSocket error: #{e}" + # end + # end + # } + #} + + + end + + def start_websocket_server(ws_options, secure) Thread.new { - port = @@config.get("beef.http.websocket.port") sleep 2 # prevent issues when starting at the same time the TunnelingProxy, Thin and Evented WebSockets EventMachine.run { - - wsopt = {:host => "0.0.0.0", :port => port} - - - EventMachine::WebSocket.start(wsopt) do |ws| + EventMachine::WebSocket.start(ws_options) do |ws| begin - print_debug "New WebSocket channel open." + secure ? print_debug("New WebSocketSecure channel open.") : print_debug("New WebSocket channel open.") ws.onmessage { |msg| msg_hash = JSON.parse("#{msg}") #@note messageHash[result] is Base64 encoded @@ -153,8 +219,6 @@ module BeEF end } } - - end #@note retrieve the right websocket channel given an hooked browser session