Class: Arachni::Checks::Emails
- Inherits:
-
Arachni::Check::Base
- Object
- Arachni::Component::Base
- Arachni::Check::Base
- Arachni::Checks::Emails
- Defined in:
- components/checks/passive/grep/emails.rb
Overview
Looks for and logs e-mail addresses.
Constant Summary collapse
- PATTERN =
/[A-Z0-9._%+-]+(?:@|\s*\[at\]\s*)[A-Z0-9.-]+(?:\.|\s*\[dot\]\s*)[A-Z]{2,4}/i
- MIN_THREADS =
0
- MAX_THREADS =
10
Constants included from Arachni::Check::Auditor
Arachni::Check::Auditor::DOM_ELEMENTS_WITH_INPUTS, Arachni::Check::Auditor::ELEMENTS_WITH_INPUTS, Arachni::Check::Auditor::FILE_SIGNATURES, Arachni::Check::Auditor::FILE_SIGNATURES_PER_PLATFORM, Arachni::Check::Auditor::Format, Arachni::Check::Auditor::SOURCE_CODE_SIGNATURES_PER_PLATFORM
Constants included from Arachni
BANNER, Arachni::Cookie, Form, Header, JSON, Link, LinkTemplate, NestedCookie, Severity, UIForm, UIInput, VERSION, WEBSITE, WIKI, XML
Instance Attribute Summary
Attributes included from Arachni::Check::Auditor
Class Method Summary collapse
-
.cache ⇒ Hash<String, Bool>
Cached results for domain resolutions through the entire scan.
- .info ⇒ Object
Instance Method Summary collapse
- #deobfuscate(email) ⇒ Object
-
#if_exists(email, &block) ⇒ Object
Checks whether or not an e-mail exists by resolving the domain.
- #pool(min_threads = nil) ⇒ Object
-
#resolve ⇒ Object
Process the #if_exists queue.
- #run ⇒ Object
-
#wait_for(domain, &block) ⇒ Object
If there are multiple checks for the same domain queue them, we can perform only one and notify the rest.
-
#waiting ⇒ Hash<String, Array<Block>] Callers waiting for the results of a resolution per domain.
Hash
] Callers waiting for the results of a resolution per domain.
Methods inherited from Arachni::Check::Base
#browser_cluster, #clean_up, elements, exempt_platforms, has_exempt_platforms?, has_platforms?, #initialize, platforms, #plugins, prefer, #preferred, preferred, #prepare, #session, supports_platforms?
Methods included from Arachni::Check::Auditor
#audit, #audit_differential, #audit_signature, #audit_timeout, #audited, #audited?, #buffered_audit, #each_candidate_dom_element, #each_candidate_element, has_timeout_candidates?, #http, #initialize, #log, #log_issue, #log_remote_file, #log_remote_file_if_exists, #match_and_log, #max_issues, #preferred, reset, #skip?, timeout_audit_run, #trace_taint, #with_browser, #with_browser_cluster
Methods inherited from Arachni::Component::Base
author, description, fullname, #shortname, shortname, shortname=, version
Methods included from Arachni::Component::Output
#depersonalize_output, #depersonalize_output?, #intercept_print_message
Methods included from UI::Output
#caller_location, #debug?, #debug_level, #debug_level_1?, #debug_level_2?, #debug_level_3?, #debug_level_4?, #debug_off, #debug_on, #disable_only_positives, #error_buffer, #error_log_fd, #error_logfile, #has_error_log?, #included, #log_error, #mute, #muted?, #only_positives, #only_positives?, #print_bad, #print_debug, #print_debug_backtrace, #print_debug_exception, #print_debug_level_1, #print_debug_level_2, #print_debug_level_3, #print_debug_level_4, #print_error, #print_error_backtrace, #print_exception, #print_info, #print_line, #print_ok, #print_status, #print_verbose, #reroute_to_file, #reroute_to_file?, reset_output_options, #set_error_logfile, #unmute, #verbose?, #verbose_off, #verbose_on
Methods included from Arachni::Component::Utilities
Methods included from Utilities
#available_port, available_port_mutex, #bytes_to_kilobytes, #bytes_to_megabytes, #caller_name, #caller_path, #cookie_decode, #cookie_encode, #cookies_from_file, #cookies_from_parser, #cookies_from_response, #exception_jail, #exclude_path?, #follow_protocol?, #form_decode, #form_encode, #forms_from_parser, #forms_from_response, #full_and_absolute_url?, #generate_token, #get_path, #hms_to_seconds, #html_decode, #html_encode, #include_path?, #links_from_parser, #links_from_response, #normalize_url, #page_from_response, #page_from_url, #parse_set_cookie, #path_in_domain?, #path_too_deep?, #port_available?, #rand_port, #random_seed, #redundant_path?, #regexp_array_match, #remove_constants, #request_parse_body, #seconds_to_hms, #skip_page?, #skip_path?, #skip_resource?, #skip_response?, #to_absolute, #uri_decode, #uri_encode, #uri_parse, #uri_parse_query, #uri_parser, #uri_rewrite
Methods included from Arachni
URI, collect_young_objects, #get_long_win32_filename, jruby?, null_device, profile?, windows?
Constructor Details
This class inherits a constructor from Arachni::Check::Base
Class Method Details
.cache ⇒ Hash<String, Bool>
Returns Cached results for domain resolutions through the entire scan.
22 23 24 |
# File 'components/checks/passive/grep/emails.rb', line 22 def self.cache @cache ||= Concurrent::Hash.new end |
.info ⇒ Object
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'components/checks/passive/grep/emails.rb', line 150 def self.info { name: 'E-mail address', description: %q{Greps pages for disclosed e-mail addresses.}, elements: [ Element::Body ], author: 'Tasos "Zapotek" Laskos <[email protected]>', version: '0.3', issue: { name: %q{E-mail address disclosure}, description: %q{ Email addresses are typically found on "Contact us" pages, however, they can also be found within scripts or code comments of the application. They are used to provide a legitimate means of contacting an organisation. As one of the initial steps in information gathering, cyber-criminals will spider a website and using automated methods collect as many email addresses as possible, that they may then use in a social engineering attack. Using the same automated methods, Arachni was able to detect one or more email addresses that were stored within the affected page. }, cwe: 200, severity: Severity::INFORMATIONAL, remedy_guidance: %q{E-mail addresses should be presented in such a way that it is hard to process them automatically.} } } end |
Instance Method Details
#deobfuscate(email) ⇒ Object
122 123 124 125 126 127 128 |
# File 'components/checks/passive/grep/emails.rb', line 122 def deobfuscate( email ) email = email.dup email.gsub!( '[at]', '@' ) email.gsub!( '[dot]', '.' ) email.gsub!( ' ', '' ) email end |
#if_exists(email, &block) ⇒ Object
Checks whether or not an e-mail exists by resolving the domain. #resolve will need to be called after all callbacks have been queued.
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'components/checks/passive/grep/emails.rb', line 62 def if_exists( email, &block ) print_info "Verifying: #{email}" domain = deobfuscate( email ).split( '@', 2 ).last # Same domain as the current page, gets a pass. if page.parsed_url.host == domain block.call true return end # In the cache, yay! if self.class.cache.include?( domain ) if self.class.cache[domain] print_info "Resolved: #{domain}" block.call return end print_info "Could not resolve: #{domain}" return end wait_for( domain, &block ) end |
#pool(min_threads = nil) ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 |
# File 'components/checks/passive/grep/emails.rb', line 43 def pool( min_threads = nil ) @pool ||= Concurrent::ThreadPoolExecutor.new( # Only spawn threads when necessary, not from the get go. min_threads: min_threads || MIN_THREADS, max_threads: MAX_THREADS, # No bounds on the amount of domains to be checked. max_queue: 0 ) end |
#resolve ⇒ Object
Process the #if_exists queue.
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'components/checks/passive/grep/emails.rb', line 89 def resolve return if waiting.empty? p = pool( [waiting.size, MAX_THREADS].min ) waiting.each do |domain, _| p.post do begin Resolv.getaddress domain print_info "Resolved: #{domain}" self.class.cache[domain] = true rescue Resolv::ResolvError print_info "Could not resolve: #{domain}" self.class.cache[domain] = false end end end http.after_run do pool.shutdown pool.wait_for_termination waiting.each do |domain, callbacks| next if !self.class.cache[domain] while (cb = callbacks.pop) cb.call end end end end |
#run ⇒ Object
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'components/checks/passive/grep/emails.rb', line 130 def run body = Element::Body.new( self.page.url ).tap { |b| b.auditor = self } page.body.scan( PATTERN ).flatten.uniq.compact.each do |email| next if audited?( email ) if_exists email do log( signature: PATTERN, proof: email, vector: body ) audited( email ) end end resolve end |
#wait_for(domain, &block) ⇒ Object
If there are multiple checks for the same domain queue them, we can perform only one and notify the rest.
38 39 40 41 |
# File 'components/checks/passive/grep/emails.rb', line 38 def wait_for( domain, &block ) waiting[domain] ||= [] waiting[domain] << block end |