diff --git a/Gemfile b/Gemfile index 4bad5ca86..127bb488a 100644 --- a/Gemfile +++ b/Gemfile @@ -42,7 +42,7 @@ end # Geolocation support group :geoip do - gem 'geoip' + gem 'maxmind-db' end gem 'parseconfig' diff --git a/beef b/beef index e5addf31a..edaf82cf3 100755 --- a/beef +++ b/beef @@ -215,6 +215,11 @@ end # print_info "RESTful API key: #{BeEF::Core::Crypto::api_token}" +# +# @note Load the GeoIP database +# +BeEF::Core::GeoIp.instance + # # @note Call the API method 'pre_http_start' # diff --git a/config.yaml b/config.yaml index a586768fe..4bd0c9c41 100644 --- a/config.yaml +++ b/config.yaml @@ -135,11 +135,12 @@ beef: # IP Geolocation # 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 + # /usr/bin/curl -O https://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz + # /bin/gunzip GeoLite2-City.tar.gz && /bin/tar xvf GeoLite2-City.tar && /bin/rm GeoLite2-City.tar + # /bin/mkdir -p /opt/GeoIP && /bin/mv GeoLite2-City_*/* /opt/GeoIP && /bin/rmdir GeoLite2-City_* geoip: - enable: false - database: '/opt/GeoIP/GeoLiteCity.dat' + enable: true + database: '/opt/GeoIP/GeoLite2-City.mmdb' # Integration with PhishingFrenzy # If enabled BeEF will try to get the UID parameter value from the hooked URI, as this is used by PhishingFrenzy diff --git a/core/core.rb b/core/core.rb index 70b26c936..dc5d49db8 100644 --- a/core/core.rb +++ b/core/core.rb @@ -32,6 +32,7 @@ require 'core/main/command' require 'core/main/crypto' require 'core/main/logger' require 'core/main/migration' +require 'core/main/geoip' # @note Include the command line parser and the banner printer require 'core/main/console/commandline' diff --git a/core/main/geoip.rb b/core/main/geoip.rb new file mode 100644 index 000000000..04b88a786 --- /dev/null +++ b/core/main/geoip.rb @@ -0,0 +1,59 @@ +# +# 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 + class GeoIp + include Singleton + + def initialize + @config = BeEF::Core::Configuration.instance + @enabled = @config.get('beef.geoip.enable') ? true : false + + return unless @enabled + + geoip_file = @config.get('beef.geoip.database') + + unless File.exists? geoip_file + print_error "[GeoIP] Could not find MaxMind GeoIP database: '#{geoip_file}'" + @enabled = false + return + end + + require 'maxmind/db' + @geoip_reader = MaxMind::DB.new(geoip_file, mode: MaxMind::DB::MODE_MEMORY) + @geoip_reader.freeze + rescue => e + print_error "[GeoIP] Failed to load GeoIP database: #{e.message}" + @enabled = false + end + + # + # Check if GeoIP functionality is enabled and functional + # + # @return [Boolean] GeoIP functionality enabled? + # + def enabled? + @enabled + end + + # + # Search the MaxMind GeoLite2 database for the specified IP address + # + # @param [String] The IP address to lookup + # + # @return [Hash] IP address lookup results + # + def lookup(ip) + raise Exception::TypeError, '"ip" needs to be a string' unless ip.string? + + return unless @enabled + + @geoip_reader.get(ip) + end + end +end +end diff --git a/core/main/handlers/browserdetails.rb b/core/main/handlers/browserdetails.rb index f289d6b84..0c3004dda 100644 --- a/core/main/handlers/browserdetails.rb +++ b/core/main/handlers/browserdetails.rb @@ -103,32 +103,53 @@ module BeEF # geolocation BD.set(session_id, 'LocationCity', 'Unknown') BD.set(session_id, 'LocationCountry', 'Unknown') - if config.get('beef.geoip.enable') - require 'geoip' - geoip_file = config.get('beef.geoip.database') - if File.exists? geoip_file - geoip = GeoIP.new(geoip_file).city(zombie.ip) - if geoip.nil? - print_debug "[INIT] Geolocation failed - No results for IP address '#{zombie.ip}'" - else - #print_debug "[INIT] Geolocation results: #{geoip}" - BeEF::Core::Logger.instance.register('Zombie', "#{zombie.ip} is connecting from: #{geoip}", "#{zombie.id}") - BD.set(session_id, 'LocationCity', "#{geoip['city_name']}") - BD.set(session_id, 'LocationCountry', "#{geoip['country_name']}") - BD.set(session_id, 'LocationCountryCode2', "#{geoip['country_code2']}") - BD.set(session_id, 'LocationCountryCode3', "#{geoip['country_code3']}") - BD.set(session_id, 'LocationContinentCode', "#{geoip['continent_code']}") - BD.set(session_id, 'LocationPostCode', "#{geoip['postal_code']}") - BD.set(session_id, 'LocationLatitude', "#{geoip['latitude']}") - BD.set(session_id, 'LocationLongitude', "#{geoip['longitude']}") - BD.set(session_id, 'LocationDMACode', "#{geoip['dma_code']}") - BD.set(session_id, 'LocationAreaCode', "#{geoip['area_code']}") - BD.set(session_id, 'LocationTimezone', "#{geoip['timezone']}") - BD.set(session_id, 'LocationRegionName', "#{geoip['real_region_name']}") - end + if BeEF::Core::GeoIp.instance.enabled? + geoip = BeEF::Core::GeoIp.instance.lookup(zombie.ip) + if geoip.nil? + print_debug "[INIT] Geolocation failed - No results for IP address '#{zombie.ip}'" else - print_error "[INIT] Geolocation failed - Could not find MaxMind GeoIP database '#{geoip_file}'" - print_more "Download: http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz" + # print_debug "[INIT] Geolocation results: #{geoip}" + BeEF::Core::Logger.instance.register('Zombie', "#{zombie.ip} is connecting from: #{geoip}", "#{zombie.id}") + BD.set( + session_id, + 'LocationCity', + "#{geoip['city']['names']['en'] rescue 'Unknown'}") + BD.set( + session_id, + 'LocationCountry', + "#{geoip['country']['names']['en'] rescue 'Unknown' }") + BD.set( + session_id, + 'LocationCountryIsoCode', + "#{geoip['country']['iso_code'] rescue ''}") + BD.set( + session_id, + 'LocationRegisteredCountry', + "#{geoip['registered_country']['names']['en'] rescue ''}") + BD.set( + session_id, + 'LocationRegisteredCountryIsoCode', + "#{geoip['registered_country']['iso_code'] rescue ''}") + BD.set( + session_id, + 'LocationContinent', + "#{geoip['continent']['names']['en'] rescue ''}") + BD.set( + session_id, + 'LocationContinentCode', + "#{geoip['continent']['code'] rescue ''}") + BD.set( + session_id, + 'LocationLatitude', + "#{geoip['location']['latitude'] rescue ''}") + BD.set( + session_id, + 'LocationLongitude', + "#{geoip['location']['longitude'] rescue ''}") + BD.set( + session_id, + 'LocationTimeZone', + "#{geoip['location']['time_zone'] rescue ''}") end end diff --git a/extensions/admin_ui/controllers/modules/modules.rb b/extensions/admin_ui/controllers/modules/modules.rb index 180133afb..e14bfc627 100644 --- a/extensions/admin_ui/controllers/modules/modules.rb +++ b/extensions/admin_ui/controllers/modules/modules.rb @@ -98,18 +98,16 @@ class Modules < BeEF::Extension::AdminUI::HttpController ['Browser Components', 'Foxit', 'HasFoxit'], # Geolocation - ['Location', 'City', 'LocationCity'], - ['Location', 'Country', 'LocationCountry'], - ['Location', 'CountryCode2', 'LocationCountryCode2'], - ['Location', 'CountryCode3', 'LocationCountryCode3'], - ['Location', 'Continent', 'LocationContinentCode'], - ['Location', 'Post Code', 'LocationPostCode'], - ['Location', 'Latitude', 'LocationLatitude'], - ['Location', 'Longitude', 'LocationLongitude'], - ['Location', 'DMA Code', 'LocationDMACode'], - ['Location', 'Area Code', 'LocationAreaCode'], - ['Location', 'Timezone', 'LocationTimezone'], - ['Location', 'Region', 'LocationRegionName'], + ['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'],