From d0cdb9ec90562321cc5ac0d6c9f30e52ed1ddff4 Mon Sep 17 00:00:00 2001 From: Brendan Coles Date: Tue, 22 Apr 2014 21:05:05 +1000 Subject: [PATCH 01/14] Update config.yaml Edit comments for consistency. --- config.yaml | 61 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/config.yaml b/config.yaml index 72fd6fa28..144c6989e 100644 --- a/config.yaml +++ b/config.yaml @@ -11,29 +11,44 @@ beef: debug: false # More verbose messages (client-side) client_debug: false + # Used for generating secure tokens + crypto_default_value_length: 80 + # Interface / IP restrictions restrictions: - # subnet of browser ip addresses that can hook to the framework + # subnet of IP addresses that can hook to the framework permitted_hooking_subnet: "0.0.0.0/0" - # subnet of browser ip addresses that can connect to the UI - # permitted_ui_subnet: "127.0.0.1/32" + # subnet of IP addresses that can connect to the admin UI + #permitted_ui_subnet: "127.0.0.1/32" permitted_ui_subnet: "0.0.0.0/0" + # HTTP server http: debug: false #Thin::Logging.debug, very verbose. Prints also full exception stack trace. host: "0.0.0.0" port: "3000" - # Decrease this setting up to 1000 if you want more responsiveness when sending modules and retrieving results. - # It's not advised to decrease it with tons of hooked browsers (more than 50), - # because it might impact performance. Also, enable WebSockets is generally better. + + # Decrease this setting to 1,000 (ms) if you want more responsiveness + # when sending modules and retrieving results. + # NOTE: A poll timeout of less than 5,000 (ms) might impact performance + # when hooking lots of browsers (50+). + # Enabling WebSockets is generally better (beef.websocket.enable) xhr_poll_timeout: 5000 - # if running behind a nat set the public ip address here - #public: "" - #public_port: "" # port setting is experimental + + # Reverse Proxy / NAT + # If BeEF is running behind a reverse proxy or NAT + # set the public hostname and port here + #public: "" # public hostname/IP address + #public_port: "" # experimental + # DNS dns_host: "localhost" dns_port: 53 + + # Web Admin user interface URI web_ui_basepath: "/ui" + + # Hook hook_file: "/hook.js" hook_session_name: "BEEFHOOK" session_cookie_name: "BEEFSESSION" @@ -46,11 +61,13 @@ beef: # Prefer WebSockets over XHR-polling when possible. websocket: - enable: false - secure: true # use 'WebSocketSecure' works only on HTTPS domains and with HTTPS support enabled in BeEF - port: 61985 # WS: good success rate through proxies - secure_port: 61986 # WSSecure - ws_poll_timeout: 1000 # poll BeEF every second + enable: false + port: 61985 # WS: good success rate through proxies + # Use encrypted 'WebSocketSecure' + # NOTE: works only on HTTPS domains and with HTTPS support enabled in BeEF + secure: true + secure_port: 61986 # WSSecure + ws_poll_timeout: 1000 # poll BeEF every second # Imitate a specified web server (default root page, 404 default error page, 'Server' HTTP response header) web_server_imitation: @@ -89,7 +106,8 @@ beef: db_passwd: "beef123" db_encoding: "UTF-8" - # Credentials to authenticate in BeEF. Used by both the RESTful API and the Admin_UI extension + # Credentials to authenticate in BeEF. + # Used by both the RESTful API and the Admin_UI extension credentials: user: "beef" passwd: "beef" @@ -98,17 +116,16 @@ beef: # NOTE: only modules with target type 'working' or 'user_notify' can be run automatically. autorun: enable: true - # set this to FALSE if you don't want to allow auto-run execution for modules with target->user_notify + # set this to TRUE if you want to allow auto-run execution for modules with target->user_notify allow_user_notify: true - crypto_default_value_length: 80 - # IP Geolocation - # Requires MaxMind database - # curl -O http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz + # NOTE: requires MaxMind database: + # curl -O http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz + # gunzip GeoLiteCity.dat.gz && mkdir /opt/GeoIP && mv GeoLiteCity.dat /opt/GeoIP geoip: - enable: false - database: '/opt/GeoIP/GeoLiteCity.dat' + enable: false + database: '/opt/GeoIP/GeoLiteCity.dat' # You may override default extension configuration parameters here extension: From 2ee9fb6ccc8dbce3501f8c7386a622929b757a0d Mon Sep 17 00:00:00 2001 From: bcoles Date: Tue, 22 Apr 2014 22:49:21 +0930 Subject: [PATCH 02/14] Add nginx imitation --- config.yaml | 2 +- core/main/router/router.rb | 44 ++++++++++++++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/config.yaml b/config.yaml index 144c6989e..00d5f90b7 100644 --- a/config.yaml +++ b/config.yaml @@ -72,7 +72,7 @@ beef: # Imitate a specified web server (default root page, 404 default error page, 'Server' HTTP response header) web_server_imitation: enable: true - type: "apache" #supported: apache, iis + type: "apache" # Supported: apache, iis, nginx # Experimental HTTPS support for the hook / admin / all other Thin managed web services https: diff --git a/core/main/router/router.rb b/core/main/router/router.rb index d9197c7af..0c851af18 100644 --- a/core/main/router/router.rb +++ b/core/main/router/router.rb @@ -66,6 +66,15 @@ module BeEF "and search for topics titled Web Site Setup, Common Administrative Tasks, and About Custom Error Messages." + "" + "" + when "nginx" + #response body + "\n"+ + "404 Not Found\n" + + "\n" + + "

404 Not Found

\n" + + "
nginx
\n" + + "\n" + + "\n" else "Not Found." end @@ -87,12 +96,15 @@ module BeEF headers "Server" => "Microsoft-IIS/6.0", "X-Powered-By" => "ASP.NET", "Content-Type" => "text/html; charset=UTF-8" + when "nginx" + headers "Server" => "nginx", + "Content-Type" => "text/html" else - print_error "You have and error in beef.http.web_server_imitation.type! Supported values are: apache, iis." + print_error "You have an error in beef.http.web_server_imitation.type! Supported values are: apache, iis, nginx." end end - # @note If CORS are enabled, expose the appropriate headers + # @note If CORS is enabled, expose the appropriate headers # this apparently duplicate code is needed to reply to preflight OPTIONS requests, which need to respond with a 200 # and be able to handle requests with a JSON content-type if request.request_method == 'OPTIONS' && config.get("beef.http.restful_api.allow_cors") @@ -103,7 +115,7 @@ module BeEF halt 200 end - # @note If CORS are enabled, expose the appropriate headers + # @note If CORS is enabled, expose the appropriate headers if config.get("beef.http.restful_api.allow_cors") allowed_domains = config.get("beef.http.restful_api.cors_allowed_domains") headers "Access-Control-Allow-Origin" => allowed_domains, @@ -255,6 +267,30 @@ module BeEF "" + "" + "" + when "nginx" + "\n" + + "\n" + + "\n" + + "Welcome to nginx!\n" + + "\n" + + "\n" + + "\n" + + "

Welcome to nginx!

\n" + + "

If you see this page, the nginx web server is successfully installed and\n" + + "working. Further configuration is required.

\n\n" + + "

For online documentation and support please refer to\n" + + "nginx.org.
\n" + + "Commercial support is available at\n" + + "nginx.com.

\n\n" + + "

Thank you for using nginx.

\n" + + "\n" + + "\n" else "" end @@ -264,4 +300,4 @@ module BeEF end end end -end \ No newline at end of file +end From f17569cc35e497ef67c341db39112ed71b51ad39 Mon Sep 17 00:00:00 2001 From: Christian Frichot Date: Thu, 24 Apr 2014 11:48:42 +0800 Subject: [PATCH 03/14] Chrome Browser detection up to v36 for Desktop and iOS --- core/filters/browser.rb | 2 +- core/filters/page.rb | 2 +- core/main/client/browser.js | 140 +++++++++++++++++++++++++++++++----- 3 files changed, 125 insertions(+), 19 deletions(-) diff --git a/core/filters/browser.rb b/core/filters/browser.rb index e73e0e0f7..f8cba5743 100644 --- a/core/filters/browser.rb +++ b/core/filters/browser.rb @@ -22,7 +22,7 @@ module Filters def self.is_valid_browsertype?(str) return false if not is_non_empty_string?(str) return false if str.length < 10 - return false if str.length > 250 + return false if str.length > 500 #CxF - had to increase this because the Chrome detection JSON String is getting bigger. return false if has_non_printable_char?(str) true end diff --git a/core/filters/page.rb b/core/filters/page.rb index 15f25ff68..6d6596c3a 100644 --- a/core/filters/page.rb +++ b/core/filters/page.rb @@ -12,7 +12,7 @@ module Filters def self.is_valid_pagetitle?(str) return false if not str.is_a? String return false if has_non_printable_char?(str) - return false if str.length > 50 + return false if str.length > 500 # CxF Increased this because some page titles are MUCH longer true end diff --git a/core/main/client/browser.js b/core/main/client/browser.js index 41331fe18..d91143946 100644 --- a/core/main/client/browser.js +++ b/core/main/client/browser.js @@ -677,6 +677,14 @@ beef.browser = { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 31) ? true : false); }, + /** + * Returns true if Chrome for iOS 31. + * @example: beef.browser.isC31iOS() + */ + isC31iOS: function () { + return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 31) ? true : false); + }, + /** * Returns true if Chrome 32. * @example: beef.browser.isC32() @@ -685,6 +693,14 @@ beef.browser = { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 32) ? true : false); }, + /** + * Returns true if Chrome for iOS 32. + * @example: beef.browser.isC32iOS() + */ + isC32iOS: function () { + return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 32) ? true : false); + }, + /** * Returns true if Chrome 33. * @example: beef.browser.isC33() @@ -694,19 +710,68 @@ beef.browser = { }, /** - * Returns true if Chrome for iOS 31. - * @example: beef.browser.isC31iOS() - */ - isC31iOS: function () { - return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 31) ? true : false); + * Returns true if Chrome for iOS 33. + * @example: beef.browser.isC33iOS() + */ + isC33iOS: function () { + return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 33) ? true : false); }, + /** + * Returns true if Chrome 34. + * @example: beef.browser.isC34() + */ + isC34: function () { + return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 34) ? true : false); + }, + + /** + * Returns true if Chrome for iOS 34. + * @example: beef.browser.isC34iOS() + */ + isC34iOS: function () { + return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 34) ? true : false); + }, + + /** + * Returns true if Chrome 35. + * @example: beef.browser.isC35() + */ + isC35: function () { + return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 35) ? true : false); + }, + + /** + * Returns true if Chrome for iOS 35. + * @example: beef.browser.isC35iOS() + */ + isC35iOS: function () { + return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 35) ? true : false); + }, + + /** + * Returns true if Chrome 36. + * @example: beef.browser.isC36() + */ + isC36: function () { + return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 36) ? true : false); + }, + + /** + * Returns true if Chrome for iOS 36. + * @example: beef.browser.isC36iOS() + */ + isC36iOS: function () { + return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 36) ? true : false); + }, + + /** * Returns true if Chrome. * @example: beef.browser.isC() */ isC: function () { - return this.isC5() || this.isC6() || this.isC7() || this.isC8() || this.isC9() || this.isC10() || this.isC11() || this.isC12() || this.isC13() || this.isC14() || this.isC15() || this.isC16() || this.isC17() || this.isC18() || this.isC19() || this.isC19iOS() || this.isC20() || this.isC20iOS() || this.isC21() || this.isC21iOS() || this.isC22() || this.isC22iOS() || this.isC23() || this.isC23iOS() || this.isC24() || this.isC24iOS() || this.isC25() || this.isC25iOS() || this.isC26() || this.isC26iOS() || this.isC27() || this.isC27iOS() || this.isC28() || this.isC28iOS() || this.isC29() || this.isC29iOS() || this.isC30() || this.isC30iOS() || this.isC31() || this.isC32() || this.isC33() || this.isC31iOS(); + return this.isC5() || this.isC6() || this.isC7() || this.isC8() || this.isC9() || this.isC10() || this.isC11() || this.isC12() || this.isC13() || this.isC14() || this.isC15() || this.isC16() || this.isC17() || this.isC18() || this.isC19() || this.isC19iOS() || this.isC20() || this.isC20iOS() || this.isC21() || this.isC21iOS() || this.isC22() || this.isC22iOS() || this.isC23() || this.isC23iOS() || this.isC24() || this.isC24iOS() || this.isC25() || this.isC25iOS() || this.isC26() || this.isC26iOS() || this.isC27() || this.isC27iOS() || this.isC28() || this.isC28iOS() || this.isC29() || this.isC29iOS() || this.isC30() || this.isC30iOS() || this.isC31() || this.isC31iOS() || this.isC32() || this.isC32iOS() || this.isC33() || this.isC33iOS() || this.isC34() || this.isC34iOS() || this.isC35() || this.isC35iOS() || this.isC36() || this.isC36iOS(); }, /** @@ -805,9 +870,18 @@ beef.browser = { C30: this.isC30(), // Chrome 30 C30iOS: this.isC30iOS(), // Chrome 30 on iOS C31: this.isC31(), // Chrome 31 - C31: this.isC32(), // Chrome 32 - C31: this.isC33(), // Chrome 33 C31iOS: this.isC31iOS(), // Chrome 31 on iOS + C32: this.isC32(), // Chrome 32 + C32iOS: this.isC32iOS(), // Chrome 32 on iOS + C33: this.isC33(), // Chrome 33 + C33iOS: this.isC33iOS(), // Chrome 33 on iOS + C34: this.isC34(), // Chrome 34 + C34iOS: this.isC34iOS(), // Chrome 34 on iOS + C35: this.isC35(), // Chrome 35 + C35iOS: this.isC35iOS(), // Chrome 35 on iOS + C36: this.isC36(), // Chrome 36 + C36iOS: this.isC36iOS(), // Chrome 36 on iOS + C: this.isC(), // Chrome any version FF2: this.isFF2(), // Firefox 2 @@ -1026,19 +1100,51 @@ beef.browser = { if (this.isC31()) { return '31' } - ; - if (this.isC32()) { - return '32' - } - ; - if (this.isC33()) { - return '33' - } - ;// Chrome 31 + ; // Chrome 31 if (this.isC31iOS()) { return '31' } ; // Chrome 31 for iOS + if (this.isC32()) { + return '32' + } + ; // Chrome 32 + if (this.isC32iOS()) { + return '32' + } + ; // Chrome 32 for iOS + if (this.isC33()) { + return '33' + } + ; // Chrome 33 + if (this.isC33iOS()) { + return '33' + } + ; // Chrome 33 for iOS + if (this.isC34()) { + return '34' + } + ; // Chrome 34 + if (this.isC34iOS()) { + return '34' + } + ; // Chrome 34 for iOS + if (this.isC35()) { + return '35' + } + ; // Chrome 35 + if (this.isC35iOS()) { + return '35' + } + ; // Chrome 35 for iOS + if (this.isC36()) { + return '36' + } + ; // Chrome 36 + if (this.isC36iOS()) { + return '36' + } + ; // Chrome 36 for iOS if (this.isFF2()) { return '2' } From 52c2ef45e1788c479a111a437aed3b8bc1465dab Mon Sep 17 00:00:00 2001 From: Wade Alcorn Date: Thu, 24 Apr 2014 14:44:26 +1000 Subject: [PATCH 04/14] Fixed reference to origin --- core/main/client/browser.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/core/main/client/browser.js b/core/main/client/browser.js index 41331fe18..8fe353798 100644 --- a/core/main/client/browser.js +++ b/core/main/client/browser.js @@ -1479,7 +1479,7 @@ beef.browser = { }, /** - * Checks if the Phonegap API is available from the hooked domain. + * Checks if the Phonegap API is available from the hooked origin. * @return: {Boolean} true or false. * * @example: if(beef.browser.hasPhonegap()) { ... } @@ -1871,9 +1871,9 @@ beef.browser = { if (has_session_cookies) details['hasSessionCookies'] = has_session_cookies; if (has_persistent_cookies) details['hasPersistentCookies'] = has_persistent_cookies; } catch (e) { - // the hooked domain is using HttpOnly. EverCookie is persisting the BeEF hook in a different way, + // the hooked origin is using HttpOnly. EverCookie is persisting the BeEF hook in a different way, // and there is no reason to read cookies at this point - details['Cookies'] = "Cookies can't be read. The hooked domain is most probably using HttpOnly."; + details['Cookies'] = "Cookies can't be read. The hooked origin is most probably using HttpOnly."; details['hasSessionCookies'] = "No"; details['hasPersistentCookies'] = "No"; } @@ -2146,10 +2146,9 @@ beef.browser = { if (scope == 'PER_DOMAIN') testUrl = "http://browserspy.dk/connections.php?img=1&random="; else - // The token will be replaced by a different number with each request(different domain). + // The token will be replaced by a different number with each request (different origin). testUrl = "http://.browserspy.dk/connections.php?img=1&random="; - var imagesLoaded = 0; // Number of responding images before timeout. var imagesRequested = 0; // Number of requested images. var testImages = new Array(); // Array of all images. From 94b636c6fd50e4bb983b535b0a72687a2679cbf5 Mon Sep 17 00:00:00 2001 From: Wade Alcorn Date: Thu, 24 Apr 2014 19:36:58 +1000 Subject: [PATCH 05/14] Fixed reference to origin --- core/main/client/net/cors.js | 2 +- core/main/client/timeout.js | 2 +- core/main/client/websocket.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/main/client/net/cors.js b/core/main/client/net/cors.js index 01cf86008..cf12dcffe 100644 --- a/core/main/client/net/cors.js +++ b/core/main/client/net/cors.js @@ -12,7 +12,7 @@ beef.net.cors = { }, /** - * Make a cross-domain request using CORS + * Make a cross-origin request using CORS * * @param method {String} HTTP verb ('GET', 'POST', 'DELETE', etc.) * @param url {String} url diff --git a/core/main/client/timeout.js b/core/main/client/timeout.js index c766ade42..77719a79a 100644 --- a/core/main/client/timeout.js +++ b/core/main/client/timeout.js @@ -6,7 +6,7 @@ /* Sometimes there are timing issues and looks like beef_init - is not called at all (always in cross-domain situations, + is not called at all (always in cross-origin situations, for example calling the hook with jquery getScript, or sometimes with event handler injections). diff --git a/core/main/client/websocket.js b/core/main/client/websocket.js index 551ce17c8..122e16631 100644 --- a/core/main/client/websocket.js +++ b/core/main/client/websocket.js @@ -20,7 +20,7 @@ beef.websocket = { /** * Initialize the WebSocket client object. - * Note: use WebSocketSecure only if the hooked domain is under https. + * Note: use WebSocketSecure only if the hooked origin is under https. * Mixed-content in WS is quite different from a non-WS context. */ init:function () { From 6fe877271060f5dca2811c1deb8069e1ab4eaea0 Mon Sep 17 00:00:00 2001 From: bcoles Date: Fri, 25 Apr 2014 02:11:58 +0930 Subject: [PATCH 06/14] Refactor browser component details --- core/main/handlers/browserdetails.rb | 124 +++------------------------ 1 file changed, 14 insertions(+), 110 deletions(-) diff --git a/core/main/handlers/browserdetails.rb b/core/main/handlers/browserdetails.rb index bbc1abde7..a048ac597 100644 --- a/core/main/handlers/browserdetails.rb +++ b/core/main/handlers/browserdetails.rb @@ -288,100 +288,20 @@ module BeEF self.err_msg "Invalid window size returned from the hook browser's initial connection." end - # get and store the yes|no value for VBScriptEnabled - vbscript_enabled = get_param(@data['results'], 'VBScriptEnabled') - if BeEF::Filters.is_valid_yes_no?(vbscript_enabled) - BD.set(session_id, 'VBScriptEnabled', vbscript_enabled) - else - self.err_msg "Invalid value for VBScriptEnabled returned from the hook browser's initial connection." - end - - # get and store the yes|no value for HasFlash - has_flash = get_param(@data['results'], 'HasFlash') - if BeEF::Filters.is_valid_yes_no?(has_flash) - BD.set(session_id, 'HasFlash', has_flash) - else - self.err_msg "Invalid value for HasFlash returned from the hook browser's initial connection." - end - - # get and store the yes|no value for HasPhonegap - has_phonegap = get_param(@data['results'], 'HasPhonegap') - if BeEF::Filters.is_valid_yes_no?(has_phonegap) - BD.set(session_id, 'HasPhonegap', has_phonegap) - else - self.err_msg "Invalid value for HasPhonegap returned from the hook browser's initial connection." - end - - # get and store the yes|no value for HasGoogleGears - has_googlegears = get_param(@data['results'], 'HasGoogleGears') - if BeEF::Filters.is_valid_yes_no?(has_googlegears) - BD.set(session_id, 'HasGoogleGears', has_googlegears) - else - self.err_msg "Invalid value for HasGoogleGears returned from the hook browser's initial connection." - end - - # get and store the yes|no value for HasFoxit - has_foxit = get_param(@data['results'], 'HasFoxit') - if BeEF::Filters.is_valid_yes_no?(has_foxit) - BD.set(session_id, 'HasFoxit', has_foxit) - else - self.err_msg "Invalid value for HasFoxit returned from the hook browser's initial connection." - end - - # get and store the yes|no value for HasWebSocket - has_web_socket = get_param(@data['results'], 'HasWebSocket') - if BeEF::Filters.is_valid_yes_no?(has_web_socket) - BD.set(session_id, 'HasWebSocket', has_web_socket) - else - self.err_msg "Invalid value for HasWebSocket returned from the hook browser's initial connection." - end - - # get and store the yes|no value for HasWebRTC - has_webrtc = get_param(@data['results'], 'HasWebRTC') - if BeEF::Filters.is_valid_yes_no?(has_webrtc) - BD.set(session_id, 'HasWebRTC', has_webrtc) - else - self.err_msg "Invalid value for HasWebRTC returned from the hook browser's initial connection." - end - - # get and store the yes|no value for HasActiveX - has_activex = get_param(@data['results'], 'HasActiveX') - if BeEF::Filters.is_valid_yes_no?(has_activex) - BD.set(session_id, 'HasActiveX', has_activex) - else - self.err_msg "Invalid value for HasActiveX returned from the hook browser's initial connection." - end - - # get and store the yes|no value for HasSilverlight - has_silverlight = get_param(@data['results'], 'HasSilverlight') - if BeEF::Filters.is_valid_yes_no?(has_silverlight) - BD.set(session_id, 'HasSilverlight', has_silverlight) - else - self.err_msg "Invalid value for HasSilverlight returned from the hook browser's initial connection." - end - - # get and store the yes|no value for HasQuickTime - has_quicktime = get_param(@data['results'], 'HasQuickTime') - if BeEF::Filters.is_valid_yes_no?(has_quicktime) - BD.set(session_id, 'HasQuickTime', has_quicktime) - else - self.err_msg "Invalid value for HasQuickTime returned from the hook browser's initial connection." - end - - # get and store the yes|no value for HasRealPlayer - has_realplayer = get_param(@data['results'], 'HasRealPlayer') - if BeEF::Filters.is_valid_yes_no?(has_realplayer) - BD.set(session_id, 'HasRealPlayer', has_realplayer) - else - self.err_msg "Invalid value for HasRealPlayer returned from the hook browser's initial connection." - end - - # get and store the yes|no value for HasWMP - has_wmp = get_param(@data['results'], 'HasWMP') - if BeEF::Filters.is_valid_yes_no?(has_wmp) - BD.set(session_id, 'HasWMP', has_wmp) - else - self.err_msg "Invalid value for HasWMP returned from the hook browser's initial connection." + # get and store the yes|no value for browser components + components = [ + 'VBScriptEnabled', 'HasFlash', 'HasPhonegap', 'HasGoogleGears', + 'HasFoxit', 'HasWebSocket', 'HasWebRTC', 'HasActiveX', + 'HasSilverlight', 'HasQuickTime', 'HasRealPlayer', 'HasWMP', + 'hasSessionCookies', 'hasPersistentCookies' + ] + components.each do |k| + v = get_param(@data['results'], k) + if BeEF::Filters.is_valid_yes_no?(v) + BD.set(session_id, k, v) + else + self.err_msg "Invalid value for #{k} returned from the hook browser's initial connection." + end end # get and store the value for CPU @@ -400,22 +320,6 @@ module BeEF self.err_msg "Invalid value for TouchEnabled returned from the hook browser's initial connection." end - # get and store whether the browser has session cookies enabled - has_session_cookies = get_param(@data['results'], 'hasSessionCookies') - if BeEF::Filters.is_valid_yes_no?(has_session_cookies) - BD.set(session_id, 'hasSessionCookies', has_session_cookies) - else - self.err_msg "Invalid value for hasSessionCookies returned from the hook browser's initial connection." - end - - # get and store whether the browser has persistent cookies enabled - has_persistent_cookies = get_param(@data['results'], 'hasPersistentCookies') - if BeEF::Filters.is_valid_yes_no?(has_persistent_cookies) - BD.set(session_id, 'hasPersistentCookies', has_persistent_cookies) - else - self.err_msg "Invalid value for hasPersistentCookies returned from the hook browser's initial connection." - end - # log a few info of newly hooked zombie in the console print_info "New Hooked Browser [id:#{zombie.id}, ip:#{zombie.ip}, type:#{browser_name}-#{browser_version}, os:#{os_name}], hooked domain [#{log_zombie_domain}:#{log_zombie_port.to_s}]" From a317b223ca0334b00e3dc79c03080dbe5df4eb71 Mon Sep 17 00:00:00 2001 From: Brendan Coles Date: Fri, 25 Apr 2014 03:52:57 +1000 Subject: [PATCH 07/14] Update description --- modules/browser/browser_fingerprinting/config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/browser/browser_fingerprinting/config.yaml b/modules/browser/browser_fingerprinting/config.yaml index 31b29f98b..27979730e 100644 --- a/modules/browser/browser_fingerprinting/config.yaml +++ b/modules/browser/browser_fingerprinting/config.yaml @@ -8,8 +8,8 @@ beef: browser_fingerprinting: enable: true category: "Browser" - name: "Fingerprint Browser" - description: "This module attempts to fingerprint the browser type and version using URI handlers unique to Safari, Internet Explorer and Mozilla Firefox. This method does not rely on JavaScript objects which may have been modified by the user or browser compatibility mode." + name: "Fingerprint Browser (PoC)" + description: "This module attempts to fingerprint the browser type and version using URI protocol handlers unique to Safari, Internet Explorer and Mozilla Firefox." authors: ["bcoles"] target: working: ["IE", "FF", "S"] From 9af8e6bd00160f4ea02628255d104aec6822b840 Mon Sep 17 00:00:00 2001 From: Brendan Coles Date: Fri, 25 Apr 2014 04:16:53 +1000 Subject: [PATCH 08/14] Add CPU type filter --- core/filters/browser.rb | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/core/filters/browser.rb b/core/filters/browser.rb index f8cba5743..86818efb9 100644 --- a/core/filters/browser.rb +++ b/core/filters/browser.rb @@ -12,7 +12,7 @@ module Filters def self.is_valid_browsername?(str) return false if not is_non_empty_string?(str) return false if str.length > 2 - return false if has_non_printable_char?(str) + return false if has_non_printable_char?(str) true end @@ -32,7 +32,7 @@ module Filters # @return [Boolean] If the string has valid Operating System name characters def self.is_valid_osname?(str) return false if not is_non_empty_string?(str) - return false if has_non_printable_char?(str) + return false if has_non_printable_char?(str) return false if str.length < 2 true end @@ -52,7 +52,7 @@ module Filters # @return [Boolean] If the string has valid browser version characters def self.is_valid_browserversion?(str) return false if not is_non_empty_string?(str) - return false if has_non_printable_char?(str) + return false if has_non_printable_char?(str) return true if str.eql? "UNKNOWN" return false if not nums_only?(str) and not is_valid_float?(str) return false if str.length > 10 @@ -64,7 +64,7 @@ module Filters # @return [Boolean] If the string has valid browser / ua string characters def self.is_valid_browserstring?(str) return false if not is_non_empty_string?(str) - return false if has_non_printable_char?(str) + return false if has_non_printable_char?(str) return false if str.length > 300 true end @@ -73,7 +73,7 @@ module Filters # @param [String] str String for testing # @return [Boolean] If the string has valid cookie characters def self.is_valid_cookies?(str) - return false if has_non_printable_char?(str) + return false if has_non_printable_char?(str) return false if str.length > 2000 true end @@ -82,7 +82,7 @@ module Filters # @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 if has_non_printable_char?(str) + return false if has_non_printable_char?(str) return false if str.length > 200 true end @@ -91,7 +91,7 @@ module Filters # @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 if has_non_printable_char?(str) + return false if has_non_printable_char?(str) return false if str.length > 200 true end @@ -114,6 +114,16 @@ module Filters true end + # Verify the CPU type string is valid + # @param [String] str String for testing + # @return [Boolean] If the string has valid CPU type characters + def self.is_valid_cpu?(str) + return false if not 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 From c1a7b1ec08a5936bc1135212a9996029f5f765d8 Mon Sep 17 00:00:00 2001 From: Brendan Coles Date: Fri, 25 Apr 2014 04:17:17 +1000 Subject: [PATCH 09/14] Use filter --- core/main/handlers/browserdetails.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/main/handlers/browserdetails.rb b/core/main/handlers/browserdetails.rb index a048ac597..03d593d83 100644 --- a/core/main/handlers/browserdetails.rb +++ b/core/main/handlers/browserdetails.rb @@ -306,7 +306,7 @@ module BeEF # get and store the value for CPU cpu_type = get_param(@data['results'], 'CPU') - if !cpu_type.nil? + if BeEF::Filters.is_valid_cpu?(cpu_type) BD.set(session_id, 'CPU', cpu_type) else self.err_msg "Invalid value for CPU returned from the hook browser's initial connection." From 34ec20cd0d69e6486a9473a93a8ddc5c6437f4e7 Mon Sep 17 00:00:00 2001 From: bcoles Date: Fri, 25 Apr 2014 16:12:25 +0930 Subject: [PATCH 10/14] Update version to 0.4.5.1-alpha --- VERSION | 2 +- config.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 644b60f8b..63fecfb58 100644 --- a/VERSION +++ b/VERSION @@ -4,4 +4,4 @@ # See the file 'doc/COPYING' for copying permission # -0.4.5.0-alpha +0.4.5.1-alpha diff --git a/config.yaml b/config.yaml index 00d5f90b7..ea678242d 100644 --- a/config.yaml +++ b/config.yaml @@ -6,7 +6,7 @@ # BeEF Configuration file beef: - version: '0.4.5.0-alpha' + version: '0.4.5.1-alpha' # More verbose messages (server-side) debug: false # More verbose messages (client-side) From fe14601dfcb665049e2d620765e7eec37bf3e50f Mon Sep 17 00:00:00 2001 From: Christian Frichot Date: Sun, 27 Apr 2014 07:12:53 +0800 Subject: [PATCH 11/14] Added -i --interactive option at commandline to launch console shell --- beef | 5 +++++ core/main/console/commandline.rb | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/beef b/beef index 2aa781350..30f446051 100755 --- a/beef +++ b/beef @@ -58,6 +58,11 @@ unless BeEF::Core::Console::CommandLine.parse[:ws_port].empty? config.set('beef.http.websocket.port', BeEF::Core::Console::CommandLine.parse[:ws_port]) end +# @note Check if interactive was specified from the command line, therefore override the extension to enable +if BeEF::Core::Console::CommandLine.parse[:interactive] == true + config.set('beef.extension.console.shell.enable',true) +end + # @note Prints BeEF welcome message BeEF::Core::Console::Banners.print_welcome_msg diff --git a/core/main/console/commandline.rb b/core/main/console/commandline.rb index f61af94b1..5dadde941 100644 --- a/core/main/console/commandline.rb +++ b/core/main/console/commandline.rb @@ -18,6 +18,7 @@ module BeEF @options[:ext_config] = "" @options[:port] = "" @options[:ws_port] = "" + @options[:interactive] = false @already_parsed = false @@ -54,6 +55,10 @@ module BeEF opts.on('-w', '--wsport WS_PORT', 'Change the default BeEF WebSocket listening port') do |ws_port| @options[:ws_port] = ws_port end + + opts.on('-i', '--interactive', 'Starts with the Console Shell activated') do + @options[:interactive] = true + end end optparse.parse! From 76c09aa38aa3a62e0d627063d640da041fa9f9cb Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Mon, 28 Apr 2014 15:35:01 -0400 Subject: [PATCH 12/14] Support pulling the server version through the REST API --- core/main/rest/handlers/server.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/main/rest/handlers/server.rb b/core/main/rest/handlers/server.rb index a2d02c6fb..e10a1a210 100644 --- a/core/main/rest/handlers/server.rb +++ b/core/main/rest/handlers/server.rb @@ -35,7 +35,11 @@ module BeEF error 400 end end + + get '/version' do + { 'version' => config.get('beef.version') }.to_json + end end end end -end \ No newline at end of file +end From c61dee72757943764f20c92c446b6af35570cdf9 Mon Sep 17 00:00:00 2001 From: Brendan Coles Date: Thu, 1 May 2014 02:33:43 +1000 Subject: [PATCH 13/14] Add support for Firefox 29 * https://developer.mozilla.org/en-US/Firefox/Releases/29 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt --- core/main/client/browser.js | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/core/main/client/browser.js b/core/main/client/browser.js index 22c17d90b..af4e0a7dd 100644 --- a/core/main/client/browser.js +++ b/core/main/client/browser.js @@ -322,7 +322,15 @@ beef.browser = { * @example: beef.browser.isFF28() */ isFF28: function () { - return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && window.navigator.userAgent.match(/Firefox\/28./) != null; + return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt !== 'function' && window.navigator.userAgent.match(/Firefox\/28./) != null; + }, + + /** + * Returns true if FF29 + * @example: beef.browser.isFF29() + */ + isFF29: function () { + return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && window.navigator.userAgent.match(/Firefox\/29./) != null; }, /** @@ -330,7 +338,7 @@ beef.browser = { * @example: beef.browser.isFF() */ isFF: function () { - return this.isFF2() || this.isFF3() || this.isFF3_5() || this.isFF3_6() || this.isFF4() || this.isFF5() || this.isFF6() || this.isFF7() || this.isFF8() || this.isFF9() || this.isFF10() || this.isFF11() || this.isFF12() || this.isFF13() || this.isFF14() || this.isFF15() || this.isFF16() || this.isFF17() || this.isFF18() || this.isFF19() || this.isFF20() || this.isFF21() || this.isFF22() || this.isFF23() || this.isFF24() || this.isFF25() || this.isFF26() || this.isFF27() || this.isFF28(); + return this.isFF2() || this.isFF3() || this.isFF3_5() || this.isFF3_6() || this.isFF4() || this.isFF5() || this.isFF6() || this.isFF7() || this.isFF8() || this.isFF9() || this.isFF10() || this.isFF11() || this.isFF12() || this.isFF13() || this.isFF14() || this.isFF15() || this.isFF16() || this.isFF17() || this.isFF18() || this.isFF19() || this.isFF20() || this.isFF21() || this.isFF22() || this.isFF23() || this.isFF24() || this.isFF25() || this.isFF26() || this.isFF27() || this.isFF28() || this.isFF29(); }, /** @@ -911,8 +919,9 @@ beef.browser = { FF24: this.isFF24(), // Firefox 24 FF25: this.isFF25(), // Firefox 25 FF26: this.isFF26(), // Firefox 26 - FF26: this.isFF27(), // Firefox 27 - FF26: this.isFF28(), // Firefox 28 + FF27: this.isFF27(), // Firefox 27 + FF28: this.isFF28(), // Firefox 28 + FF29: this.isFF29(), // Firefox 29 FF: this.isFF(), // Firefox any version IE6: this.isIE6(), // Internet Explorer 6 @@ -1261,6 +1270,10 @@ beef.browser = { return '28' } ; // Firefox 28 + if (this.isFF29()) { + return '29' + } + ; // Firefox 29 if (this.isIE6()) { return '6' From e8e4180eee272393df219a076d41aa3aacea073c Mon Sep 17 00:00:00 2001 From: Brendan Coles Date: Thu, 1 May 2014 16:36:01 +1000 Subject: [PATCH 14/14] Fix regex --- core/main/server.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/main/server.rb b/core/main/server.rb index f82eb9d7d..6b321d21f 100644 --- a/core/main/server.rb +++ b/core/main/server.rb @@ -109,7 +109,7 @@ module BeEF if @configuration.get('beef.http.https.enable') == true openssl_version = OpenSSL::OPENSSL_VERSION - if openssl_version =~ / 1\.0\.1([a-f])/ + if openssl_version =~ / 1\.0\.1([a-f])? / print_warning "Warning: #{openssl_version} is vulnerable to Heartbleed (CVE-2014-0160)." print_more "Upgrade OpenSSL to version 1.0.1g or newer." end