diff --git a/core/bootstrap.rb b/core/bootstrap.rb index 051612715..9be4b48b6 100644 --- a/core/bootstrap.rb +++ b/core/bootstrap.rb @@ -45,6 +45,7 @@ require 'core/hbmanager' ## @note Include RESTful API require 'core/main/rest/handlers/hookedbrowsers' +require 'core/main/rest/handlers/browserdetails' require 'core/main/rest/handlers/modules' require 'core/main/rest/handlers/categories' require 'core/main/rest/handlers/logs' diff --git a/core/filters/browser.rb b/core/filters/browser.rb index ec3926c95..051eb497a 100644 --- a/core/filters/browser.rb +++ b/core/filters/browser.rb @@ -93,26 +93,6 @@ module Filters true end - # Verify the screen size is valid - # @param [String] str String for testing - # @return [Boolean] If the string has valid screen size characters - def self.is_valid_screen_size?(str) - return false unless is_non_empty_string?(str) - return false if has_non_printable_char?(str) - return false if str.length > 200 - true - end - - # Verify the window size is valid - # @param [String] str String for testing - # @return [Boolean] If the string has valid window size characters - def self.is_valid_window_size?(str) - return false unless is_non_empty_string?(str) - return false if has_non_printable_char?(str) - return false if str.length > 200 - true - end - # Verify the system platform is valid # @param [String] str String for testing # @return [Boolean] If the string has valid system platform characters @@ -143,6 +123,26 @@ module Filters true end + # Verify the memory string is valid + # @param [String] str String for testing + # @return [Boolean] If the string has valid memory type characters + def self.is_valid_memory?(str) + return false unless is_non_empty_string?(str) + return false if has_non_printable_char?(str) + return false if str.length > 200 + true + end + + # Verify the GPU type string is valid + # @param [String] str String for testing + # @return [Boolean] If the string has valid GPU type characters + def self.is_valid_gpu?(str) + return false unless is_non_empty_string?(str) + return false if has_non_printable_char?(str) + return false if str.length > 200 + true + end + # Verify the browser_plugins string is valid # @param [String] str String for testing # @return [Boolean] If the string has valid browser plugin characters diff --git a/core/main/client/browser.js b/core/main/client/browser.js index 6339c3dd3..9a30a27b7 100644 --- a/core/main/client/browser.js +++ b/core/main/client/browser.js @@ -4214,28 +4214,42 @@ beef.browser = { var browser_reported_name = beef.browser.getBrowserReportedName(); var browser_language = beef.browser.getBrowserLanguage(); var page_title = (document.title) ? document.title : "Unknown"; + var origin = (window.origin) ? window.origin : "Unknown"; var page_uri = (document.location.href) ? document.location.href : "Unknown"; var page_referrer = (document.referrer) ? document.referrer : "Unknown"; - var hostname = (document.location.hostname) ? document.location.hostname : "Unknown"; + var page_hostname = (document.location.hostname) ? document.location.hostname : "Unknown"; + var default_port = ""; switch (document.location.protocol) { case "http:": var default_port = "80"; break; case "https:": var default_port = "443"; - break - default: - var default_port = ""; + break; } - var hostport = (document.location.port) ? document.location.port : default_port; + var page_hostport = (document.location.port) ? document.location.port : default_port; var browser_plugins = beef.browser.getPlugins(); var date_stamp = new Date().toString(); var os_name = beef.os.getName(); var os_version = beef.os.getVersion(); + var os_arch = beef.os.getArch(); var default_browser = beef.os.getDefaultBrowser(); - var hw_name = beef.hardware.getName(); + var hw_type = beef.hardware.getName(); + var battery_details = beef.hardware.getBatteryDetails(); + try { + var battery_charging_status = battery_details.chargingStatus; + var battery_level = battery_details.batteryLevel; + var battery_charging_time = battery_details.chargingTime; + var battery_discharging_time = battery_details.dischargingTime; + } catch(e) {} + var memory = beef.hardware.getMemory(); var cpu_arch = beef.hardware.getCpuArch(); var cpu_cores = beef.hardware.getCpuCores(); + var gpu_details = beef.hardware.getGpuDetails(); + try { + var gpu = gpu_details.gpu; + var gpu_vendor = gpu_details.vendor; + } catch(e) {} var touch_enabled = (beef.hardware.isTouchEnabled()) ? "Yes" : "No"; var browser_platform = (typeof(navigator.platform) != "undefined" && navigator.platform != "") ? navigator.platform : 'Unknown'; var browser_type = JSON.stringify(beef.browser.type(), function (key, value) { @@ -4244,7 +4258,16 @@ beef.browser = { else return undefined; }); var screen_size = beef.hardware.getScreenSize(); + try { + var screen_width = screen_size.width; + var screen_height = screen_size.height; + var screen_colordepth = screen_size.colordepth; + } catch(e) {} var window_size = beef.browser.getWindowSize(); + try { + window_width = window_size.width; + window_height = window_size.height; + } catch(e) {} var vbscript_enabled = (beef.browser.hasVBScript()) ? "Yes" : "No"; var has_flash = (beef.browser.hasFlash()) ? "Yes" : "No"; var has_phonegap = (beef.browser.hasPhonegap()) ? "Yes" : "No"; @@ -4257,50 +4280,72 @@ beef.browser = { var has_quicktime = (beef.browser.hasQuickTime()) ? "Yes" : "No"; var has_realplayer = (beef.browser.hasRealPlayer()) ? "Yes" : "No"; var has_wmp = (beef.browser.hasWMP()) ? "Yes" : "No"; + var has_vlc = (beef.browser.hasVLC()) ? "Yes" : "No"; + try { var cookies = document.cookie; /* Never stop the madness dear C. * var veglol = beef.browser.cookie.veganLol(); */ - if (cookies) details['Cookies'] = cookies; + if (cookies) details['browser.window.cookies'] = cookies; } catch (e) { - details['Cookies'] = "Cookies can't be read. The hooked origin is most probably using HttpOnly."; + beef.debug("Cookies can't be read. The hooked origin is most probably using HttpOnly."); + details['browser.window.cookies'] = ''; } - if (browser_name) details['BrowserName'] = browser_name; - if (browser_version) details['BrowserVersion'] = browser_version; - if (browser_reported_name) details['BrowserReportedName'] = browser_reported_name; - if (browser_language) details['BrowserLanguage'] = browser_language; - if (page_title) details['PageTitle'] = page_title; - if (page_uri) details['PageURI'] = page_uri; - if (page_referrer) details['PageReferrer'] = page_referrer; - if (hostname) details['HostName'] = hostname; - if (hostport) details['HostPort'] = hostport; - if (browser_plugins) details['BrowserPlugins'] = browser_plugins; - if (os_name) details['OsName'] = os_name; - if (os_version) details['OsVersion'] = os_version; - if (default_browser) details['DefaultBrowser'] = default_browser; - if (hw_name) details['Hardware'] = hw_name; - if (cpu_arch) details['CpuArch'] = cpu_arch; - if (cpu_cores) details['CpuCores'] = cpu_cores; - if (touch_enabled) details['TouchEnabled'] = touch_enabled; - if (date_stamp) details['DateStamp'] = date_stamp; - if (browser_platform) details['BrowserPlatform'] = browser_platform; - if (browser_type) details['BrowserType'] = browser_type; - if (screen_size) details['ScreenSize'] = screen_size; - if (window_size) details['WindowSize'] = window_size; - if (vbscript_enabled) details['VBScriptEnabled'] = vbscript_enabled; - if (has_flash) details['HasFlash'] = has_flash; - if (has_phonegap) details['HasPhonegap'] = has_phonegap; - if (has_web_socket) details['HasWebSocket'] = has_web_socket; - if (has_web_worker) details['HasWebWorker'] = has_web_worker; - if (has_web_gl) details['HasWebGL'] = has_web_gl; - if (has_googlegears) details['HasGoogleGears'] = has_googlegears; - if (has_webrtc) details['HasWebRTC'] = has_webrtc; - if (has_activex) details['HasActiveX'] = has_activex; - if (has_quicktime) details['HasQuickTime'] = has_quicktime; - if (has_realplayer) details['HasRealPlayer'] = has_realplayer; - if (has_wmp) details['HasWMP'] = has_wmp; + if (browser_type) details['browser.type'] = browser_type; + if (browser_name) details['browser.name'] = browser_name; + if (browser_version) details['browser.version'] = browser_version; + if (browser_reported_name) details['browser.name.reported'] = browser_reported_name; + if (browser_platform) details['browser.platform'] = browser_platform; + if (browser_language) details['browser.language'] = browser_language; + if (page_title) details['browser.window.title'] = page_title; + if (origin) details['browser.window.origin'] = origin; + if (page_hostname) details['browser.window.hostname'] = page_hostname; + if (page_hostport) details['browser.window.hostport'] = page_hostport; + if (page_uri) details['browser.window.uri'] = page_uri; + if (page_referrer) details['browser.window.referrer'] = page_referrer; + if (window_width) details['browser.window.size.width'] = window_width; + if (window_height) details['browser.window.size.height'] = window_height; + if (browser_plugins) details['browser.plugins'] = browser_plugins; + if (date_stamp) details['browser.date.datestamp'] = date_stamp; + + if (os_name) details['host.os.name'] = os_name; + if (os_version) details['host.os.version'] = os_version; + if (os_arch) details['host.os.arch'] = os_arch; + + if (default_browser) details['host.software.defaultbrowser'] = default_browser; + + if (hw_type) details['hardware.type'] = hw_type; + if (memory) details['hardware.memory'] = memory; + if (gpu) details['hardware.gpu'] = gpu; + if (gpu_vendor) details['hardware.gpu.vendor'] = gpu_vendor; + if (cpu_arch) details['hardware.cpu.arch'] = cpu_arch; + if (cpu_cores) details['hardware.cpu.cores'] = cpu_cores; + + if (battery_charging_status) details['hardware.battery.chargingstatus'] = battery_charging_status; + if (battery_level) details['hardware.battery.level'] = battery_level; + if (battery_charging_time) details['hardware.battery.chargingtime'] = battery_charging_time; + if (battery_discharging_time) details['hardware.battery.dischargingtime'] = battery_discharging_time; + + if (screen_width) details['hardware.screen.size.width'] = screen_width; + if (screen_height) details['hardware.screen.size.height'] = screen_height; + if (screen_colordepth) details['hardware.screen.colordepth'] = screen_colordepth; + if (touch_enabled) details['hardware.screen.touchenabled'] = touch_enabled; + + if (vbscript_enabled) details['browser.capabilities.vbscript'] = vbscript_enabled; + if (has_flash) details['browser.capabilities.flash'] = has_flash; + if (has_phonegap) details['browser.capabilities.phonegap'] = has_phonegap; + if (has_web_socket) details['browser.capabilities.websocket'] = has_web_socket; + if (has_webrtc) details['browser.capabilities.webrtc'] = has_webrtc; + if (has_web_worker) details['browser.capabilities.webworker'] = has_web_worker; + if (has_web_gl) details['browser.capabilities.webgl'] = has_web_gl; + if (has_googlegears) details['browser.capabilities.googlegears'] = has_googlegears; + if (has_activex) details['browser.capabilities.activex'] = has_activex; + if (has_quicktime) details['browser.capabilities.quicktime'] = has_quicktime; + if (has_realplayer) details['browser.capabilities.realplayer'] = has_realplayer; + if (has_wmp) details['browser.capabilities.wmp'] = has_wmp; + if (has_vlc) details['browser.capabilities.vlc'] = has_vlc; var pf_integration = "<%= @phishing_frenzy_enable %>"; if (pf_integration) { diff --git a/core/main/client/os.js b/core/main/client/os.js index 52ced7e6d..2caaefb99 100644 --- a/core/main/client/os.js +++ b/core/main/client/os.js @@ -212,6 +212,10 @@ beef.os = { return 'unknown'; }, + getArch: function() { + return 'unknown'; + }, + getVersion: function(){ //Windows if(this.isWindows()) { diff --git a/core/main/handlers/browserdetails.rb b/core/main/handlers/browserdetails.rb index 0c3004dda..2d59b39fe 100644 --- a/core/main/handlers/browserdetails.rb +++ b/core/main/handlers/browserdetails.rb @@ -37,13 +37,13 @@ module BeEF zombie = BeEF::Core::Models::HookedBrowser.new(:ip => @data['request'].ip, :session => session_id) zombie.firstseen = Time.new.to_i - # hostname + # hooked window host name log_zombie_port = 0 - if not @data['results']['HostName'].nil? then - log_zombie_domain=@data['results']['HostName'] + if not @data['results']['browser.window.hostname'].nil? + log_zombie_domain = @data['results']['browser.window.hostname'] elsif (not @data['request'].referer.nil?) and (not @data['request'].referer.empty?) referer = @data['request'].referer - if referer.start_with?("https://") then + if referer.start_with?("https://") log_zombie_port = 443 else log_zombie_port = 80 @@ -53,9 +53,9 @@ module BeEF log_zombie_domain="unknown" # Probably local file open end - # port - if not @data['results']['HostPort'].nil? then - log_zombie_port=@data['results']['HostPort'] + # hooked window host port + if not @data['results']['browser.window.hostport'].nil? + log_zombie_port = @data['results']['browser.window.hostport'] else log_zombie_domain_parts=log_zombie_domain.split(':') if log_zombie_domain_parts.length > 1 then @@ -78,31 +78,40 @@ module BeEF # add a log entry for the newly hooked browser BeEF::Core::Logger.instance.register('Zombie', "#{zombie.ip} just joined the horde from the domain: #{log_zombie_domain}:#{log_zombie_port.to_s}", "#{zombie.id}") + # get and store browser name - browser_name = get_param(@data['results'], 'BrowserName') + browser_name = get_param(@data['results'], 'browser.name') if BeEF::Filters.is_valid_browsername?(browser_name) - BD.set(session_id, 'BrowserName', browser_name) + BD.set(session_id, 'browser.name', browser_name) + + # lookup and store browser friendly name + browser_friendly_name = BeEF::Core::Constants::Browsers.friendly_name(browser_name) + BD.set(session_id, 'browser.name.friendly', browser_friendly_name) else self.err_msg "Invalid browser name returned from the hook browser's initial connection." end + if BeEF::Filters.is_valid_ip?(zombie.ip) + BD.set(session_id, 'host.ipaddress', zombie.ip) + else + self.err_msg "Invalid IP address returned from the hook browser's initial connection." + end + # lookup zombie host name - ip_str = zombie.ip if config.get('beef.dns_hostname_lookup') begin host_name = Resolv.getname(zombie.ip).to_s if BeEF::Filters.is_valid_hostname?(host_name) - ip_str += " [#{host_name}]" + BD.set(session_id, 'host.name', host_name) end rescue print_debug "[INIT] Reverse lookup failed - No results for IP address '#{zombie.ip}'" end end - BD.set(session_id, 'IP', ip_str) # geolocation - BD.set(session_id, 'LocationCity', 'Unknown') - BD.set(session_id, 'LocationCountry', 'Unknown') + BD.set(session_id, 'location.city', 'Unknown') + BD.set(session_id, 'location.country', 'Unknown') if BeEF::Core::GeoIp.instance.enabled? geoip = BeEF::Core::GeoIp.instance.lookup(zombie.ip) if geoip.nil? @@ -112,44 +121,44 @@ module BeEF BeEF::Core::Logger.instance.register('Zombie', "#{zombie.ip} is connecting from: #{geoip}", "#{zombie.id}") BD.set( session_id, - 'LocationCity', + 'location.city', "#{geoip['city']['names']['en'] rescue 'Unknown'}") BD.set( session_id, - 'LocationCountry', + 'location.country', "#{geoip['country']['names']['en'] rescue 'Unknown' }") BD.set( session_id, - 'LocationCountryIsoCode', - "#{geoip['country']['iso_code'] rescue ''}") + 'location.country.isocode', + "#{geoip['country']['iso_code'] rescue 'Unknown'}") BD.set( session_id, - 'LocationRegisteredCountry', - "#{geoip['registered_country']['names']['en'] rescue ''}") + 'location.country.registered_country', + "#{geoip['registered_country']['names']['en'] rescue 'Unknown'}") BD.set( session_id, - 'LocationRegisteredCountryIsoCode', - "#{geoip['registered_country']['iso_code'] rescue ''}") + 'location.country.registered_country.isocode', + "#{geoip['registered_country']['iso_code'] rescue 'Unknown'}") BD.set( session_id, - 'LocationContinent', - "#{geoip['continent']['names']['en'] rescue ''}") + 'location.continent', + "#{geoip['continent']['names']['en'] rescue 'Unknown'}") BD.set( session_id, - 'LocationContinentCode', - "#{geoip['continent']['code'] rescue ''}") + 'location.continent.code', + "#{geoip['continent']['code'] rescue 'Unknown'}") BD.set( session_id, - 'LocationLatitude', - "#{geoip['location']['latitude'] rescue ''}") + 'location.latitude', + "#{geoip['location']['latitude'] rescue 'Unknown'}") BD.set( session_id, - 'LocationLongitude', - "#{geoip['location']['longitude'] rescue ''}") + 'location.longitude', + "#{geoip['location']['longitude'] rescue 'Unknown'}") BD.set( session_id, - 'LocationTimeZone', - "#{geoip['location']['time_zone'] rescue ''}") + 'location.timezone', + "#{geoip['location']['time_zone'] rescue 'Unknown'}") end end @@ -210,144 +219,201 @@ module BeEF end # get and store browser version - browser_version = get_param(@data['results'], 'BrowserVersion') + browser_version = get_param(@data['results'], 'browser.version') if BeEF::Filters.is_valid_browserversion?(browser_version) - BD.set(session_id, 'BrowserVersion', browser_version) + BD.set(session_id, 'browser.version', browser_version) else self.err_msg "Invalid browser version returned from the hook browser's initial connection." end # get and store browser string - browser_string = get_param(@data['results'], 'BrowserReportedName') + browser_string = get_param(@data['results'], 'browser.name.reported') if BeEF::Filters.is_valid_browserstring?(browser_string) - BD.set(session_id, 'BrowserReportedName', browser_string) + BD.set(session_id, 'browser.name.reported', browser_string) else - self.err_msg "Invalid browser string returned from the hook browser's initial connection." + self.err_msg "Invalid value for 'browser.name.reported' returned from the hook browser's initial connection." end # get and store browser language - browser_lang = get_param(@data['results'], 'BrowserLanguage') - BD.set(session_id, 'BrowserLanguage', browser_lang) + browser_lang = get_param(@data['results'], 'browser.language') + BD.set(session_id, 'browser.language', browser_lang) # get and store the cookies - cookies = get_param(@data['results'], 'Cookies') + cookies = get_param(@data['results'], 'browser.window.cookies') if BeEF::Filters.is_valid_cookies?(cookies) - BD.set(session_id, 'Cookies', cookies) + BD.set(session_id, 'browser.window.cookies', cookies) else self.err_msg "Invalid cookies returned from the hook browser's initial connection." end # get and store the OS name - os_name = get_param(@data['results'], 'OsName') + os_name = get_param(@data['results'], 'host.os.name') if BeEF::Filters.is_valid_osname?(os_name) - BD.set(session_id, 'OsName', os_name) + BD.set(session_id, 'host.os.name', os_name) else self.err_msg "Invalid operating system name returned from the hook browser's initial connection." end - # get and store the OS version (without checks as it can be very different or even empty, for instance on linux/bsd) - os_version = get_param(@data['results'], 'OsVersion') - BD.set(session_id, 'OsVersion', os_version) + # get and store the OS version + # - without checks as it can be very different, for instance on linux/bsd) + os_version = get_param(@data['results'], 'host.os.version') + BD.set(session_id, 'host.os.version', os_version) + + # get and store the OS arch - without checks + os_arch = get_param(@data['results'], 'host.os.arch') + BD.set(session_id, 'host.os.arch', os_arch) # get and store default browser - default_browser = get_param(@data['results'], 'DefaultBrowser') - BD.set(session_id, 'DefaultBrowser', default_browser) + default_browser = get_param(@data['results'], 'host.software.defaultbrowser') + BD.set(session_id, 'host.software.defaultbrowser', default_browser) - # get and store the hardware name - hw_name = get_param(@data['results'], 'Hardware') - if BeEF::Filters.is_valid_hwname?(hw_name) - BD.set(session_id, 'Hardware', hw_name) + # get and store the hardware type + hw_type = get_param(@data['results'], 'hardware.type') + if BeEF::Filters.is_valid_hwname?(hw_type) + BD.set(session_id, 'hardware.type', hw_type) else - self.err_msg "Invalid hardware name returned from the hook browser's initial connection." + self.err_msg "Invalid value for 'hardware.type' returned from the hook browser's initial connection." end # get and store the date - date_stamp = get_param(@data['results'], 'DateStamp') + date_stamp = get_param(@data['results'], 'browser.date.datestamp') if BeEF::Filters.is_valid_date_stamp?(date_stamp) - BD.set(session_id, 'DateStamp', date_stamp) + BD.set(session_id, 'browser.date.datestamp', date_stamp) else self.err_msg "Invalid date returned from the hook browser's initial connection." end # get and store page title - page_title = get_param(@data['results'], 'PageTitle') + page_title = get_param(@data['results'], 'browser.window.title') if BeEF::Filters.is_valid_pagetitle?(page_title) - BD.set(session_id, 'PageTitle', page_title) + BD.set(session_id, 'browser.window.title', page_title) else - self.err_msg "Invalid page title returned from the hook browser's initial connection." + self.err_msg "Invalid value for 'browser.window.title' returned from the hook browser's initial connection." + end + + # get and store page origin + origin = get_param(@data['results'], 'browser.window.origin') + if BeEF::Filters.is_valid_url?(origin) + BD.set(session_id, 'browser.window.origin', origin) + else + self.err_msg "Invalid value for 'browser.window.uri' returned from the hook browser's initial connection." end # get and store page uri - page_uri = get_param(@data['results'], 'PageURI') + page_uri = get_param(@data['results'], 'browser.window.uri') if BeEF::Filters.is_valid_url?(page_uri) - BD.set(session_id, 'PageURI', page_uri) + BD.set(session_id, 'browser.window.uri', page_uri) else - self.err_msg "Invalid page URL returned from the hook browser's initial connection." + self.err_msg "Invalid value for 'browser.window.uri' returned from the hook browser's initial connection." end # get and store the page referrer - page_referrer = get_param(@data['results'], 'PageReferrer') + page_referrer = get_param(@data['results'], 'browser.window.referrer') if BeEF::Filters.is_valid_pagereferrer?(page_referrer) - BD.set(session_id, 'PageReferrer', page_referrer) + BD.set(session_id, 'browser.window.referrer', page_referrer) else - self.err_msg "Invalid page referrer returned from the hook browser's initial connection." + self.err_msg "Invalid value for 'browser.window.referrer' returned from the hook browser's initial connection." end - # get and store hostname - host_name = get_param(@data['results'], 'HostName') + # get and store hooked window host port + host_name = get_param(@data['results'], 'browser.window.hostname') if BeEF::Filters.is_valid_hostname?(host_name) - BD.set(session_id, 'HostName', host_name) + BD.set(session_id, 'browser.window.hostname', host_name) else - self.err_msg "Invalid host name returned from the hook browser's initial connection." + self.err_msg "Invalid valid for 'browser.window.hostname' returned from the hook browser's initial connection." + end + + # get and store hooked window host port + host_port = get_param(@data['results'], 'browser.window.hostport') + if BeEF::Filters.is_valid_port?(host_port) + BD.set(session_id, 'browser.window.hostport', host_port) + else + self.err_msg "Invalid valid for 'browser.window.hostport' returned from the hook browser's initial connection." end # get and store the browser plugins - browser_plugins = get_param(@data['results'], 'BrowserPlugins') + browser_plugins = get_param(@data['results'], 'browser.plugins') if BeEF::Filters.is_valid_browser_plugins?(browser_plugins) - BD.set(session_id, 'BrowserPlugins', browser_plugins) + BD.set(session_id, 'browser.plugins', browser_plugins) else self.err_msg "Invalid browser plugins returned from the hook browser's initial connection." end # get and store the system platform - system_platform = get_param(@data['results'], 'BrowserPlatform') + system_platform = get_param(@data['results'], 'browser.platform') if BeEF::Filters.is_valid_system_platform?(system_platform) - BD.set(session_id, 'BrowserPlatform', system_platform) + BD.set(session_id, 'browser.platform', system_platform) else self.err_msg "Invalid browser platform returned from the hook browser's initial connection." end # get and store the hooked browser type - browser_type = get_param(@data['results'], 'BrowserType') + browser_type = get_param(@data['results'], 'browser.type') if BeEF::Filters.is_valid_browsertype?(browser_type) - BD.set(session_id, 'BrowserType', browser_type) + BD.set(session_id, 'browser.type', browser_type) else self.err_msg "Invalid hooked browser type returned from the hook browser's initial connection." end - # get and store the zombie screen size and color depth - screen_size = get_param(@data['results'], 'ScreenSize') - if BeEF::Filters.is_valid_screen_size?(screen_size) - BD.set(session_id, 'ScreenSize', screen_size) + # get and store the zombie screen color depth + screen_colordepth = get_param(@data['results'], 'hardware.screen.colordepth') + if BeEF::Filters.nums_only?(screen_colordepth) + BD.set(session_id, 'hardware.screen.colordepth', screen_colordepth) else - self.err_msg "Invalid screen size returned from the hook browser's initial connection." + self.err_msg "Invalid value for 'hardware.screen.colordepth' returned from the hook browser's initial connection." end - # get and store the window size - window_size = get_param(@data['results'], 'WindowSize') - if BeEF::Filters.is_valid_window_size?(window_size) - BD.set(session_id, 'WindowSize', window_size) + # get and store the zombie screen width + screen_size_width = get_param(@data['results'], 'hardware.screen.size.width') + if BeEF::Filters.nums_only?(screen_size_width) + BD.set(session_id, 'hardware.screen.size.width', screen_size_width) else - self.err_msg "Invalid window size returned from the hook browser's initial connection." + self.err_msg "Invalid value for 'hardware.screen.size.width' returned from the hook browser's initial connection." end - # get and store the yes|no value for browser components - components = [ - 'VBScriptEnabled', 'HasFlash', 'HasPhonegap', 'HasGoogleGears', - 'HasWebSocket', 'HasWebWorker', 'HasWebGL', 'HasWebRTC', 'HasActiveX', - 'HasQuickTime', 'HasRealPlayer', 'HasWMP' + # get and store the zombie screen height + screen_size_height = get_param(@data['results'], 'hardware.screen.size.height') + if BeEF::Filters.nums_only?(screen_size_height) + BD.set(session_id, 'hardware.screen.size.height', screen_size_height) + else + self.err_msg "Invalid value for 'hardware.screen.size.height' returned from the hook browser's initial connection." + end + + + # get and store the window height + window_height = get_param(@data['results'], 'browser.window.size.height') + if BeEF::Filters.nums_only?(window_height) + BD.set(session_id, 'browser.window.size.height', window_height) + else + self.err_msg "Invalid value for 'browser.window.size.height' returned from the hook browser's initial connection." + end + + # get and store the window width + window_width = get_param(@data['results'], 'browser.window.size.width') + if BeEF::Filters.nums_only?(window_width) + BD.set(session_id, 'browser.window.size.width', window_width) + else + self.err_msg "Invalid value for 'browser.window.size.width' returned from the hook browser's initial connection." + end + + # get and store the yes|no value for browser capabilities + capabilities = [ + 'browser.capabilities.vbscript', + # 'browser.capabilities.java', + 'browser.capabilities.flash', + 'browser.capabilities.phonegap', + 'browser.capabilities.googlegears', + 'browser.capabilities.activex', + 'browser.capabilities.quicktime', + 'browser.capabilities.realplayer', + 'browser.capabilities.wmp', + 'browser.capabilities.vlc', + 'browser.capabilities.webworker', + 'browser.capabilities.websocket', + 'browser.capabilities.webgl', + 'browser.capabilities.webrtc', ] - components.each do |k| + capabilities.each do |k| v = get_param(@data['results'], k) if BeEF::Filters.is_valid_yes_no?(v) BD.set(session_id, k, v) @@ -356,28 +422,60 @@ module BeEF end end - # get and store the value for CpuArch - cpu_arch = get_param(@data['results'], 'CpuArch') + # get and store the value for hardware.memory + memory = get_param(@data['results'], 'hardware.memory') + if BeEF::Filters.is_valid_memory?(memory) + BD.set(session_id, 'hardware.memory', memory) + else + self.err_msg "Invalid value for 'hardware.memory' returned from the hook browser's initial connection." + end + + # get and store the value for hardware.gpu + gpu = get_param(@data['results'], 'hardware.gpu') + if BeEF::Filters.is_valid_gpu?(gpu) + BD.set(session_id, 'hardware.gpu', gpu) + else + self.err_msg "Invalid value for 'hardware.gpu' returned from the hook browser's initial connection." + end + + # get and store the value for hardware.gpu.vendor + gpu_vendor = get_param(@data['results'], 'hardware.gpu.vendor') + if BeEF::Filters.is_valid_gpu?(gpu_vendor) + BD.set(session_id, 'hardware.gpu.vendor', gpu_vendor) + else + self.err_msg "Invalid value for 'hardware.gpu.vendor' returned from the hook browser's initial connection." + end + + # get and store the value for hardware.cpu.arch + cpu_arch = get_param(@data['results'], 'hardware.cpu.arch') if BeEF::Filters.is_valid_cpu?(cpu_arch) - BD.set(session_id, 'CpuArch', cpu_arch) + BD.set(session_id, 'hardware.cpu.arch', cpu_arch) else - self.err_msg "Invalid value for CpuArch returned from the hook browser's initial connection." + self.err_msg "Invalid value for 'hardware.cpu.arch' returned from the hook browser's initial connection." end - # get and store the value for CpuCores - cpu_cores = get_param(@data['results'], 'CpuCores') + # get and store the value for hardware.cpu.cores + cpu_cores = get_param(@data['results'], 'hardware.cpu.cores') if BeEF::Filters.alphanums_only?(cpu_cores) - BD.set(session_id, 'CpuCores', cpu_cores) + BD.set(session_id, 'hardware.cpu.cores', cpu_cores) else - self.err_msg "Invalid value for CpuCores returned from the hook browser's initial connection." + self.err_msg "Invalid value for 'hardware.cpu.cores' returned from the hook browser's initial connection." end - # get and store the value for TouchEnabled - touch_enabled = get_param(@data['results'], 'TouchEnabled') - if BeEF::Filters.is_valid_yes_no?(touch_enabled) - BD.set(session_id, 'TouchEnabled', touch_enabled) + # get and store the value for hardware.battery.level + battery_level = get_param(@data['results'], 'hardware.battery.level') + if battery_level == 'unknown' || battery_level =~ /\A[\d\.]+%\z/ + BD.set(session_id, 'hardware.battery.level', battery_level) else - self.err_msg "Invalid value for TouchEnabled returned from the hook browser's initial connection." + self.err_msg "Invalid value for 'hardware.battery.level' returned from the hook browser's initial connection." + end + + # get and store the value for hardware.screen.touchenabled + touch_enabled = get_param(@data['results'], 'hardware.screen.touchenabled') + if BeEF::Filters.is_valid_yes_no?(touch_enabled) + BD.set(session_id, 'hardware.screen.touchenabled', touch_enabled) + else + self.err_msg "Invalid value for hardware.screen.touchenabled returned from the hook browser's initial connection." end if config.get('beef.integration.phishing_frenzy.enable') @@ -397,7 +495,7 @@ module BeEF # add localhost as network host if config.get('beef.extension.network.enable') print_debug("Hooked browser has network interface 127.0.0.1") - BeEF::Core::Models::NetworkHost.add(:hooked_browser_id => session_id, :ip => '127.0.0.1', :hostname => 'localhost', :os => BeEF::Core::Models::BrowserDetails.get(session_id, 'OsName')) + BeEF::Core::Models::NetworkHost.add(:hooked_browser_id => session_id, :ip => '127.0.0.1', :hostname => 'localhost', :os => BeEF::Core::Models::BrowserDetails.get(session_id, 'host.os.name')) end # check if any ARE rules shall be triggered only if the channel is != WebSockets (XHR). If the channel diff --git a/core/main/models/browserdetails.rb b/core/main/models/browserdetails.rb index 83d30178a..cb4f1c4f9 100644 --- a/core/main/models/browserdetails.rb +++ b/core/main/models/browserdetails.rb @@ -48,6 +48,7 @@ module Models else # update the browser details key/value result = browserdetails.update(:detail_value => detail_value || '') + print_debug "Browser has updated '#{detail_key}' to '#{detail_value}'" end # if the attempt to save the browser details fails return a bad request diff --git a/core/main/network_stack/websocket/websocket.rb b/core/main/network_stack/websocket/websocket.rb index 4854352cb..361fe8205 100644 --- a/core/main/network_stack/websocket/websocket.rb +++ b/core/main/network_stack/websocket/websocket.rb @@ -115,10 +115,10 @@ module BeEF next end - browser_name = BeEF::Core::Models::BrowserDetails.get(hb_session, 'BrowserName') - browser_version = BeEF::Core::Models::BrowserDetails.get(hb_session, 'BrowserVersion') - os_name = BeEF::Core::Models::BrowserDetails.get(hb_session, 'OsName') - os_version = BeEF::Core::Models::BrowserDetails.get(hb_session, 'OsVersion') + browser_name = BeEF::Core::Models::BrowserDetails.get(hb_session, 'browser.name') + browser_version = BeEF::Core::Models::BrowserDetails.get(hb_session, 'browser.version') + os_name = BeEF::Core::Models::BrowserDetails.get(hb_session, 'host.os.name') + os_version = BeEF::Core::Models::BrowserDetails.get(hb_session, 'host.os.version') BeEF::Core::AutorunEngine::Engine.instance.run(hooked_browser.id, browser_name, browser_version, os_name, os_version) next diff --git a/core/main/rest/api.rb b/core/main/rest/api.rb index fb1646d41..c68c4c311 100644 --- a/core/main/rest/api.rb +++ b/core/main/rest/api.rb @@ -13,6 +13,12 @@ module BeEF end end + module RegisterBrowserDetailsHandler + def self.mount_handler(server) + server.mount('/api/browserdetails', BeEF::Core::Rest::BrowserDetails.new) + end + end + module RegisterModulesHandler def self.mount_handler(server) server.mount('/api/modules', BeEF::Core::Rest::Modules.new) @@ -50,6 +56,7 @@ module BeEF end BeEF::API::Registrar.instance.register(BeEF::Core::Rest::RegisterHooksHandler, BeEF::API::Server, 'mount_handler') + BeEF::API::Registrar.instance.register(BeEF::Core::Rest::RegisterBrowserDetailsHandler, BeEF::API::Server, 'mount_handler') BeEF::API::Registrar.instance.register(BeEF::Core::Rest::RegisterModulesHandler, BeEF::API::Server, 'mount_handler') BeEF::API::Registrar.instance.register(BeEF::Core::Rest::RegisterCategoriesHandler, BeEF::API::Server, 'mount_handler') BeEF::API::Registrar.instance.register(BeEF::Core::Rest::RegisterLogsHandler, BeEF::API::Server, 'mount_handler') diff --git a/core/main/rest/handlers/autorun_engine.rb b/core/main/rest/handlers/autorun_engine.rb index b181fe997..0e8a008ad 100644 --- a/core/main/rest/handlers/autorun_engine.rb +++ b/core/main/rest/handlers/autorun_engine.rb @@ -59,10 +59,10 @@ module BeEF if online_hooks != nil online_hooks.each do |hb| hb_details = BeEF::Core::Models::BrowserDetails - browser_name = hb_details.get(hb.session, 'BrowserName') - browser_version = hb_details.get(hb.session, 'BrowserVersion') - os_name = hb_details.get(hb.session, 'OsName') - os_version = hb_details.get(hb.session, 'OsVersion') + browser_name = hb_details.get(hb.session, 'browser.name') + browser_version = hb_details.get(hb.session, 'browser.version') + os_name = hb_details.get(hb.session, 'host.os.name') + os_version = hb_details.get(hb.session, 'host.os.version') match_rules = are.match(browser_name, browser_version, os_name, os_version, rule_id) are.trigger(match_rules, hb.id) if match_rules.length > 0 @@ -130,4 +130,4 @@ module BeEF end end end -end \ No newline at end of file +end diff --git a/core/main/rest/handlers/browserdetails.rb b/core/main/rest/handlers/browserdetails.rb new file mode 100644 index 000000000..3854a9588 --- /dev/null +++ b/core/main/rest/handlers/browserdetails.rb @@ -0,0 +1,48 @@ +# +# Copyright (c) 2006-2019 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# + +module BeEF + module Core + module Rest + class BrowserDetails < BeEF::Core::Router::Router + + config = BeEF::Core::Configuration.instance + + before do + error 401 unless params[:token] == config.get('beef.api_token') + halt 401 if not BeEF::Core::Rest.permitted_source?(request.ip) + headers 'Content-Type' => 'application/json; charset=UTF-8', + 'Pragma' => 'no-cache', + 'Cache-Control' => 'no-cache', + 'Expires' => '0' + end + + # + # @note Get all browser details for the specified session + # + get '/:session' do + hb = BeEF::Core::Models::HookedBrowser.first(:session => params[:session]) + error 404 if hb.nil? + + details = BeEF::Core::Models::BrowserDetails.all(:session_id => hb.session) + error 404 if details.nil? + + result = [] + details.each do |d| + result << {key: d[:detail_key], value: d[:detail_value] } + end + + output = { + 'count' => result.length, + 'details' => result + } + + output.to_json + end + end + end + end +end diff --git a/core/main/rest/handlers/hookedbrowsers.rb b/core/main/rest/handlers/hookedbrowsers.rb index b4b72fe85..2acb551ce 100644 --- a/core/main/rest/handlers/hookedbrowsers.rb +++ b/core/main/rest/handlers/hookedbrowsers.rb @@ -143,12 +143,12 @@ module BeEF hb = BeEF::Core::Models::HookedBrowser.first(:session => params[:session]) error 401 unless hb != nil - BeEF::Core::Models::BrowserDetails.first(:session_id => hb.session, :detail_key => 'OsName').destroy - BeEF::Core::Models::BrowserDetails.first(:session_id => hb.session, :detail_key => 'OsVersion').destroy + BeEF::Core::Models::BrowserDetails.first(:session_id => hb.session, :detail_key => 'host.os.name').destroy + BeEF::Core::Models::BrowserDetails.first(:session_id => hb.session, :detail_key => 'host.os.version').destroy #BeEF::Core::Models::BrowserDetails.first(:session_id => hb.session, :detail_key => 'Arch').destroy - BeEF::Core::Models::BrowserDetails.new(:session_id => hb.session, :detail_key => 'OsName', :detail_value => os).save - BeEF::Core::Models::BrowserDetails.new(:session_id => hb.session, :detail_key => 'OsVersion', :detail_value => os_version).save + BeEF::Core::Models::BrowserDetails.new(:session_id => hb.session, :detail_key => 'host.os.name', :detail_value => os).save + BeEF::Core::Models::BrowserDetails.new(:session_id => hb.session, :detail_key => 'host.os.version', :detail_value => os_version).save BeEF::Core::Models::BrowserDetails.new(:session_id => hb.session, :detail_key => 'Arch', :detail_value => arch).save # TODO if there where any ARE rules defined for this hooked browser, @@ -172,22 +172,22 @@ module BeEF { 'id' => hb.id, 'session' => hb.session, - 'name' => details.get(hb.session, 'BrowserName'), - 'version' => details.get(hb.session, 'BrowserVersion'), - 'os' => details.get(hb.session, 'OsName'), - 'os_version' => details.get(hb.session, 'OsVersion'), - 'platform' => details.get(hb.session, 'BrowserPlatform'), - 'hardware' => details.get(hb.session, 'Hardware'), + 'name' => details.get(hb.session, 'browser.name'), + 'version' => details.get(hb.session, 'browser.version'), + 'platform' => details.get(hb.session, 'browser.platform'), + 'os' => details.get(hb.session, 'host.os.name'), + 'os_version' => details.get(hb.session, 'host.os.version'), + 'hardware' => details.get(hb.session, 'hardware.type'), 'ip' => hb.ip, - 'domain' => details.get(hb.session, 'HostName'), + 'domain' => details.get(hb.session, 'browser.window.hostname'), 'port' => hb.port.to_s, - 'page_uri' => details.get(hb.session, 'PageURI'), + 'page_uri' => details.get(hb.session, 'browser.window.uri'), 'firstseen' => hb.firstseen, 'lastseen' => hb.lastseen, - 'date_stamp' => details.get(hb.session, 'DateStamp'), - 'city' => details.get(hb.session, 'LocationCity'), - 'country' => details.get(hb.session, 'LocationCountry'), - 'country_code' => details.get(hb.session, 'LocationCountryIsoCode'), + 'date_stamp' => details.get(hb.session, 'browser.date.datestamp'), + 'city' => details.get(hb.session, 'location.city'), + 'country' => details.get(hb.session, 'location.country'), + 'country_code' => details.get(hb.session, 'location.country.isocode'), } end @@ -199,9 +199,9 @@ module BeEF # TODO jQuery.dataTables needs fixed array indexes, add emptry string if a value is blank pfuid = details.get(hb.session, 'PhishingFrenzyUID') != nil ? details.get(hb.session, 'PhishingFrenzyUID') : 'n/a' - bname = details.get(hb.session, 'BrowserName') != nil ? details.get(hb.session, 'BrowserName') : 'n/a' - bversion = details.get(hb.session, 'BrowserVersion') != nil ? details.get(hb.session, 'BrowserVersion') : 'n/a' - bplugins = details.get(hb.session, 'BrowserPlugins') != nil ? details.get(hb.session, 'BrowserPlugins') : 'n/a' + bname = details.get(hb.session, 'browser.name') != nil ? details.get(hb.session, 'browser.name') : 'n/a' + bversion = details.get(hb.session, 'browser.version') != nil ? details.get(hb.session, 'browser.version') : 'n/a' + bplugins = details.get(hb.session, 'browser.plugins') != nil ? details.get(hb.session, 'browser.plugins') : 'n/a' hooked_browsers << [ hb.id, @@ -209,14 +209,14 @@ module BeEF pfuid, bname, bversion, - details.get(hb.session, 'OsName'), - details.get(hb.session, 'BrowserPlatform'), - details.get(hb.session, 'BrowserLanguage'), + details.get(hb.session, 'host.os.name'), + details.get(hb.session, 'browser.platform'), + details.get(hb.session, 'browser.language'), bplugins, - details.get(hb.session, 'LocationCity'), - details.get(hb.session, 'LocationCountry'), - details.get(hb.session, 'LocationLatitude'), - details.get(hb.session, 'LocationLongitude') + details.get(hb.session, 'location.city'), + details.get(hb.session, 'location.country'), + details.get(hb.session, 'location.latitude'), + details.get(hb.session, 'location.longitude') ] end hooked_browsers diff --git a/extensions/admin_ui/api/handler.rb b/extensions/admin_ui/api/handler.rb index 91a9989df..ef107a68b 100644 --- a/extensions/admin_ui/api/handler.rb +++ b/extensions/admin_ui/api/handler.rb @@ -72,6 +72,7 @@ module API ui/panel/tabs/ZombieTabAutorun.js ui/panel/PanelViewer.js ui/panel/LogsDataGrid.js + ui/panel/BrowserDetailsDataGrid.js ui/panel/ZombieDataGrid.js ui/panel/MainPanel.js ui/panel/ZombieTab.js diff --git a/extensions/admin_ui/controllers/modules/modules.rb b/extensions/admin_ui/controllers/modules/modules.rb index e14bfc627..24bda8505 100644 --- a/extensions/admin_ui/controllers/modules/modules.rb +++ b/extensions/admin_ui/controllers/modules/modules.rb @@ -24,7 +24,6 @@ class Modules < BeEF::Extension::AdminUI::HttpController '/select/commandmodule.json' => method(:select_command_module), '/select/command.json' => method(:select_command), '/select/command_results.json' => method(:select_command_results), - '/select/zombie_summary.json' => method(:select_zombie_summary), '/commandmodule/commands.json' => method(:select_command_module_commands), '/commandmodule/new' => method(:attach_command_module), '/commandmodule/dynamicnew' => method(:attach_dynamic_command_module), @@ -46,135 +45,6 @@ class Modules < BeEF::Extension::AdminUI::HttpController }.to_json end - # Returns a JSON array containing the summary for a selected zombie. - def select_zombie_summary - - # get the zombie - zombie_session = @params['zombie_session'] || nil - (print_error "Zombie session is nil";return) if zombie_session.nil? - zombie = BeEF::Core::Models::HookedBrowser.first(:session => zombie_session) - (print_error "Zombie is nil";return) if zombie.nil? - - # init the summary grid - summary_grid_hash = { - 'success' => 'true', - 'results' => [] - } - - # zombie properties - # in the form of: category, UI label, value - zombie_properties = [ - - # Browser - ['Browser', 'Browser Name', 'BrowserName'], - ['Browser', 'Browser Version', 'BrowserVersion'], - ['Browser', 'Browser UA String', 'BrowserReportedName'], - ['Browser', 'Browser Language', 'BrowserLanguage'], - ['Browser', 'Browser Platform', 'BrowserPlatform'], - ['Browser', 'Browser Plugins', 'BrowserPlugins'], - ['Browser', 'Using Proxy', 'UsingProxy'], - ['Browser', 'Proxy Client', 'ProxyClient'], - ['Browser', 'Proxy Server', 'ProxyServer'], - ['Browser', 'Window Size', 'WindowSize'], - - # Browser Components - ['Browser Components', 'Flash', 'HasFlash'], - ['Browser Components', 'Java', 'JavaEnabled'], - ['Browser Components', 'VBScript', 'VBScriptEnabled'], - ['Browser Components', 'PhoneGap', 'HasPhonegap'], - ['Browser Components', 'Google Gears', 'HasGoogleGears'], - ['Browser Components', 'Web Sockets', 'HasWebSocket'], - ['Browser Components', 'Web Workers', 'HasWebWorker'], - ['Browser Components', 'WebGL', 'HasWebGL'], - ['Browser Components', 'QuickTime', 'HasQuickTime'], - ['Browser Components', 'RealPlayer', 'HasRealPlayer'], - ['Browser Components', 'Windows Media Player','HasWMP'], - ['Browser Components', 'VLC', 'HasVLC'], - ['Browser Components', 'WebRTC', 'HasWebRTC'], - ['Browser Components', 'ActiveX', 'HasActiveX'], - ['Browser Components', 'Session Cookies', 'hasSessionCookies'], - ['Browser Components', 'Persistent Cookies', 'hasPersistentCookies'], - ['Browser Components', 'Unity', 'HasUnity'], - ['Browser Components', 'Foxit', 'HasFoxit'], - - # Geolocation - ['Location', 'City', 'LocationCity'], - ['Location', 'Country', 'LocationCountry'], - ['Location', 'Country Code', 'LocationCountryIsoCode'], - ['Location', 'Registered Country', 'LocationRegisteredCountry'], - ['Location', 'Registered Country Code', 'LocationRegisteredCountryIsoCode'], - ['Location', 'Continent', 'LocationContinent'], - ['Location', 'Continent Code', 'LocationContinentCode'], - ['Location', 'Latitude', 'LocationLatitude'], - ['Location', 'Longitude', 'LocationLongitude'], - ['Location', 'Time Zone', 'LocationTimeZone'], - - # Hooked Page - ['Hooked Page', 'Page Title', 'PageTitle'], - ['Hooked Page', 'Page URI', 'PageURI'], - ['Hooked Page', 'Page Referrer', 'PageReferrer'], - ['Hooked Page', 'Host Name/IP', 'HostName'], - ['Hooked Page', 'Cookies', 'Cookies'], - - # Host - ['Host', 'Host Name/IP', 'IP'], - ['Host', 'Date', 'DateStamp'], - ['Host', 'Operating System', 'OsName'], - ['Host', 'Hardware', 'Hardware'], - ['Host', 'CPU Arch', 'CpuArch'], - ['Host', 'CPU Cores', 'CpuCores'], - ['Host', 'Default Browser', 'DefaultBrowser'], - ['Host', 'Screen Size', 'ScreenSize'], - ['Host', 'Touch Screen', 'TouchEnabled'] - ] - - # set and add the return values for each browser property - # in the form of: category, UI label, value - zombie_properties.each do |p| - - case p[2] - when "BrowserName" - data = BeEF::Core::Constants::Browsers.friendly_name(BD.get(zombie_session, p[2])) - - when "ScreenSize" - screen_size = BD.get(zombie_session, "ScreenSize") - if screen_size.nil? - data = "Unknown" - else - screen_size_hash = JSON.parse(screen_size.gsub(/\"\=\>/, '":')) # tidy up the string for JSON - width = screen_size_hash['width'] - height = screen_size_hash['height'] - cdepth = screen_size_hash['colordepth'] - data = "Width: #{width}, Height: #{height}, Colour Depth: #{cdepth}" - end - when "WindowSize" - window_size = BD.get(zombie_session, "WindowSize") - if window_size.nil? - data = "Unknown" - else - window_size_hash = JSON.parse(window_size.gsub(/\"\=\>/, '":')) # tidy up the string for JSON - width = window_size_hash['width'] - height = window_size_hash['height'] - data = "Width: #{width}, Height: #{height}" - end - else - data = BD.get(zombie_session, p[2]) - end - - # add property to summary hash - if not data.nil? - summary_grid_hash['results'].push({ - 'category' => p[0], - 'data' => { p[1] => CGI.escapeHTML("#{data}") }, - 'from' => 'Initialization' - }) - end - - end - - @body = summary_grid_hash.to_json - end - # Returns the list of all command_modules in a JSON format def select_all_command_modules @body = command_modules2json(BeEF::Modules.get_enabled.keys) @@ -205,7 +75,11 @@ class Modules < BeEF::Extension::AdminUI::HttpController if hook_session_id == nil return BeEF::Core::Constants::CommandModule::VERIFIED_UNKNOWN end - return BeEF::Module.support(mod, {'browser' => BD.get(hook_session_id, 'BrowserName'), 'ver' => BD.get(hook_session_id, 'BrowserVersion'), 'os' => [BD.get(hook_session_id, 'OsName')]}) + return BeEF::Module.support(mod, { + 'browser' => BD.get(hook_session_id, 'browser.name'), + 'ver' => BD.get(hook_session_id, 'browser.version'), + 'os' => [BD.get(hook_session_id, 'host.os.name')] + }) end # If we're adding a leaf to the command tree, and it's in a subfolder, we need to recurse diff --git a/extensions/admin_ui/media/javascript/ui/panel/BrowserDetailsDataGrid.js b/extensions/admin_ui/media/javascript/ui/panel/BrowserDetailsDataGrid.js new file mode 100644 index 000000000..f7e2331f0 --- /dev/null +++ b/extensions/admin_ui/media/javascript/ui/panel/BrowserDetailsDataGrid.js @@ -0,0 +1,97 @@ +// +// Copyright (c) 2006-2019 Wade Alcorn - wade@bindshell.net +// Browser Exploitation Framework (BeEF) - http://beefproject.com +// See the file 'doc/COPYING' for copying permission +// + + +BrowserDetailsDataGrid = function(url, page, base) { + this.page = page; + this.url = url; + this.base = typeof(base) != 'undefined' ? base : {}; + + // RESTful API token + var token = BeefWUI.get_rest_token(); + + this.store = new Ext.ux.data.PagingJsonStore({ + root: 'details', + autoDestroy: true, + autoLoad: true, + proxy: new Ext.data.HttpProxy({ + method: 'GET', + url: url + '?token=' + token + }), + storeId: 'details-store', + baseParams: this.base, + idProperty: 'id', + fields: ['key','value', 'source'], + totalProperty: 'count', + remoteSort: false, + sortInfo: {field: "key", direction: "ASC"} + }); + + this.bbar = new Ext.PagingToolbar({ + pageSize: this.page, + store: this.store, + displayInfo: true, + displayMsg: 'Displaying zombie browser details {0} - {1} of {2}', + emptyMsg: 'No zombie browser data to display' + }); + + this.columns = [{ + id: 'details-key', + header: 'Key', + dataIndex: 'key', + sortable: true, + width: 40, + renderer: function(value) { + return $jEncoder.encoder.encodeForHTML(value); + } + }, { + id: 'details-value', + header: "Value", + dataIndex: 'value', + sortable: true, + width: 60, + renderer: function(value) { + return $jEncoder.encoder.encodeForHTML(value); + } + }, + + ]; + + BrowserDetailsDataGrid.superclass.constructor.call(this, { + region: 'center', + id: 'topic-grid', + loadMask: {msg:'Loading Feed...'}, + + sm: new Ext.grid.RowSelectionModel({ + singleSelect: true + }), + + viewConfig: { + forceFit: true + }, + listeners: { + afterrender: function(datagrid) { + datagrid.store.reload({params:{start:0, limit:datagrid.page, sort:"key", dir:"ASC"}}); + }, + + rowclick: function(grid, rowIndex) { + var r = grid.getStore().getAt(rowIndex).data; + }, + containercontextmenu: function(view, e) { + e.preventDefault(); + }, + } + }) // BrowserDetailsDataGrid.superclass +} + +Ext.extend(BrowserDetailsDataGrid, Ext.grid.GridPanel, {}); + +Ext.override(Ext.PagingToolbar, { + doRefresh: function() { + delete this.store.lastParams; + this.doLoad(this.cursor); + } +}); diff --git a/extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabDetails.js b/extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabDetails.js index e7c4eba0f..d5fd6db63 100644 --- a/extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabDetails.js +++ b/extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabDetails.js @@ -8,83 +8,21 @@ * The main Tab panel for the selected zombie. */ ZombieTab_DetailsTab = function(zombie) { - - var store_summary = new Ext.data.GroupingStore({ - url: '<%= @base_path %>/modules/select/zombie_summary.json', - baseParams: {zombie_session: zombie.session} , - reader: new Ext.data.JsonReader({ - root: 'results' - },[ - {name: 'data'}, - {name: 'category'}, - {name: 'from'} - ]), - - autoLoad: false, - sortInfo:{field: 'from', direction: "ASC"}, - groupField:'category' - }); - - var grid_summary = new Ext.grid.GridPanel({ - store: store_summary, - border: false, - region: 'center', - layout: 'fit', - hideHeaders: true, - loadMask: {msg:'Loading Information...'}, - - view: new Ext.grid.GroupingView({ - forceFit:true, - groupTextTpl: '{text} ({[values.rs.length]} {[values.rs.length > 1 ? "Items" : "Item"]})', - emptyText: "No Record found: this tab gets populated after you've ran some command modules.", - enableRowBody:true - }), - - viewConfig: { - forceFit:true - }, - - columns:[ - { - header: 'information', - dataIndex: 'data', - renderer: function(value, p, record) { - html = ''; - - for(index in value) { - result = value[index]; - index = index.toString().replace('_', ' '); - - html += String.format('{0}: {1}
', index, $jEncoder.encoder.encodeForHTML(result)); - } - - return html; - } - }, - - {header: 'command_module', dataIndex:'from', width: 25, renderer: function(value){return $jEncoder.encoder.encodeForHTML(value);}}, - {header: 'Category', dataIndex:'category', hidden: true, renderer: function(value){return $jEncoder.encoder.encodeForHTML(value);}} - ] - }); - - ZombieTab_DetailsTab.superclass.constructor.call(this, { - id: 'zombie-details-tab'+zombie.session, - layout: 'fit', - title: 'Details', - - items: { - layout:'border', - border: false, - items:[grid_summary] - }, - - listeners:{ - activate : function(maintab){ - maintab.items.items[0].items.items[0].store.reload(); - } - } - }); - + + var zombieDetails = new BrowserDetailsDataGrid('/api/browserdetails/' + zombie.session, 30); + zombieDetails.border = false; + + ZombieTab_DetailsTab.superclass.constructor.call(this, { + id: 'browser-details-tab' + zombie.session, + layout: 'fit', + title: 'Details', + items: { + layout: 'border', + border: false, + items:[zombieDetails] + } + }); }; -Ext.extend(ZombieTab_DetailsTab, Ext.Panel, {}); +Ext.extend(ZombieTab_DetailsTab, Ext.Panel, {} ); + diff --git a/modules/browser/detect_activex/module.rb b/modules/browser/detect_activex/module.rb index 919068009..e4f5458bd 100644 --- a/modules/browser/detect_activex/module.rb +++ b/modules/browser/detect_activex/module.rb @@ -9,9 +9,9 @@ class Detect_activex < BeEF::Core::Command content = {} content['activex'] = @datastore['activex'] save content - if @datastore['results'] =~ /^activex=(Yes|No)/ - bd = BeEF::Core::Models::BrowserDetails.set(@datastore['beefhook'], 'HasActiveX', $1) - end + if @datastore['results'] =~ /^activex=(Yes|No)/ + bd = BeEF::Core::Models::BrowserDetails.set(@datastore['beefhook'], 'browser.capabilities.activex', $1) + end end end diff --git a/modules/browser/detect_vlc/module.rb b/modules/browser/detect_vlc/module.rb index 70c4e1a4f..180102aa7 100644 --- a/modules/browser/detect_vlc/module.rb +++ b/modules/browser/detect_vlc/module.rb @@ -5,10 +5,13 @@ # class Detect_vlc < BeEF::Core::Command - def post_execute - content = {} - content['vlc'] = @datastore['vlc'] - save content - end + def post_execute + content = {} + content['vlc'] = @datastore['vlc'] + save content + if @datastore['results'] =~ /^vlc=(Yes|No)/ + bd = BeEF::Core::Models::BrowserDetails.set(@datastore['beefhook'], 'browser.capabilities.vlc', $1) + end + end end diff --git a/modules/browser/detect_wmp/module.rb b/modules/browser/detect_wmp/module.rb index d3391d68a..4ab7dcf42 100644 --- a/modules/browser/detect_wmp/module.rb +++ b/modules/browser/detect_wmp/module.rb @@ -9,9 +9,9 @@ class Detect_wmp < BeEF::Core::Command content = {} content['wmp'] = @datastore['wmp'] save content - if @datastore['results'] =~ /^wmp=(Yes|No)/ - bd = BeEF::Core::Models::BrowserDetails.set(@datastore['beefhook'], 'HasWMP', $1) - end + if @datastore['results'] =~ /^wmp=(Yes|No)/ + bd = BeEF::Core::Models::BrowserDetails.set(@datastore['beefhook'], 'browser.capabilities.wmp', $1) + end end end diff --git a/modules/browser/spyder_eye/module.rb b/modules/browser/spyder_eye/module.rb index c4ed0aa2b..0e4b7704e 100644 --- a/modules/browser/spyder_eye/module.rb +++ b/modules/browser/spyder_eye/module.rb @@ -24,7 +24,7 @@ class Spyder_eye < BeEF::Core::Command # save screenshot file begin timestamp = Time.now.localtime.strftime("%Y-%m-%d_%H-%M-%S") - ip = BeEF::Core::Models::BrowserDetails.get(session_id, 'IP') + ip = BeEF::Core::Models::BrowserDetails.get(session_id, 'browser.ipaddress') filename = "#{$home_dir}/screenshot_#{ip}_-_#{timestamp}_#{@datastore['cid']}.png" File.open(filename, 'wb') do |file| data = @datastore['results'].gsub(/^image=data:image\/(png|jpg);base64,/, "") diff --git a/modules/host/get_internal_ip_webrtc/module.rb b/modules/host/get_internal_ip_webrtc/module.rb index 0f5d16074..cc15a9863 100755 --- a/modules/host/get_internal_ip_webrtc/module.rb +++ b/modules/host/get_internal_ip_webrtc/module.rb @@ -17,7 +17,7 @@ class Get_internal_ip_webrtc < BeEF::Core::Command if @datastore['results'] =~ /IP is ([\d\.,]+)/ ips = $1.to_s.split(/,/) if !ips.nil? && !ips.empty? - os = BeEF::Core::Models::BrowserDetails.get(session_id, 'OsName') + os = BeEF::Core::Models::BrowserDetails.get(session_id, 'host.os.name') ips.uniq.each do |ip| next unless ip =~ /^[\d\.]+$/ next if ip =~ /^0\.0\.0\.0$/ diff --git a/tools/rest_api_examples/browser-details b/tools/rest_api_examples/browser-details index 7d2e91ed3..cdd18943b 100755 --- a/tools/rest_api_examples/browser-details +++ b/tools/rest_api_examples/browser-details @@ -77,7 +77,7 @@ hooks.each do |hook| print_status "Retrieving details for browser [id: #{hook['id']}]" details = @api.browser_details(hook['session']) print_debug details - print_verbose "Hooked Browser [id:#{hook['id']}, ip:#{details['IP']}, type:#{details['BrowserName']}-#{details['BrowserVersion']}, os:#{details['OsName']}] on [#{details['PageURI']}]" + print_verbose "Hooked Browser [id:#{hook['id']}, ip:#{hook['ip']}]:\n#{details.map{|d| "#{d['key']}: #{d['value']}" }.flatten.join("\n")}" end # Retrieve hooked browser logs diff --git a/tools/rest_api_examples/lib/beef_rest_api.rb b/tools/rest_api_examples/lib/beef_rest_api.rb index c43bc8278..46bae859a 100644 --- a/tools/rest_api_examples/lib/beef_rest_api.rb +++ b/tools/rest_api_examples/lib/beef_rest_api.rb @@ -84,10 +84,11 @@ end # get hooked browser details by session def browser_details session begin - print_verbose "Retrieving details for hooked browser [session: #{session}]" - response = RestClient.get "#{@url}hooks/#{session}", {:params => {:token => @token}} - details = JSON.parse(response.body) - print_good "Retrieved browser details for #{details['IP']}" + print_verbose "Retrieving browser details for hooked browser [session: #{session}]" + response = RestClient.get "#{@url}browserdetails/#{session}", {:params => {:token => @token}} + result = JSON.parse(response.body) + details = result['details'] + print_good "Retrieved #{details.size} browser details" details rescue => e print_error "Could not retrieve browser details: #{e.message}"