phisher_phinder 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -4
- data/README.md +10 -9
- data/lib/phisher_phinder.rb +3 -0
- data/lib/phisher_phinder/command.rb +8 -1
- data/lib/phisher_phinder/contact_finder.rb +37 -0
- data/lib/phisher_phinder/display.rb +7 -1
- data/lib/phisher_phinder/extended_ip.rb +1 -1
- data/lib/phisher_phinder/tracing_report.rb +10 -2
- data/lib/phisher_phinder/version.rb +1 -1
- data/lib/phisher_phinder/whois_email_extractor.rb +19 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cfb338171a5bca59a9682dfe8157475e7ac1a6283d9410a8367fdbe78fed0be1
|
4
|
+
data.tar.gz: db30dccf14c2184cd01f4cb27e4d0cc305fda0ddb0b58205a6e3a077893e1eae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 831b8c8a93dc8cf8105724960be8052c1aa47a16fb57336a683e9780b07ce89a72e2e081344826b5462582c1270ca3fcd8a359d8b5111f97c4925c37cd5c085e
|
7
|
+
data.tar.gz: c25e50d534e780eaeef883a8e6c4311c4c51176589ac80959adb880c0b9f190b5350dd752497f3b19eb8ede04c95bd527201cf18f5f96222890ba08893495dd9
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
phisher_phinder (0.
|
4
|
+
phisher_phinder (0.3.0)
|
5
5
|
dotenv (~> 2.7.5)
|
6
6
|
maxmind-geoip2 (~> 0.4.0)
|
7
7
|
nokogiri (~> 1.11.0)
|
@@ -61,10 +61,8 @@ GEM
|
|
61
61
|
http (~> 4.3)
|
62
62
|
maxmind-db (~> 1.1)
|
63
63
|
method_source (1.0.0)
|
64
|
-
mini_portile2 (2.5.0)
|
65
64
|
minitest (5.14.2)
|
66
|
-
nokogiri (1.11.0)
|
67
|
-
mini_portile2 (~> 2.5.0)
|
65
|
+
nokogiri (1.11.0-x86_64-linux)
|
68
66
|
racc (~> 1.4)
|
69
67
|
pry (0.13.1)
|
70
68
|
coderay (~> 1.1)
|
data/README.md
CHANGED
@@ -97,14 +97,14 @@ The output of PhisherPhinder will produce something similar to the below:
|
|
97
97
|
+-----------+---------------+------------------+
|
98
98
|
|
99
99
|
|
100
|
-
|
101
|
-
|
|
102
|
-
|
103
|
-
| Sender IP
|
104
|
-
|
105
|
-
| 10.0.0.1
|
106
|
-
| 10.0.0.2
|
107
|
-
|
100
|
+
+--------------+----------------------+-----------------------+--------------------------------+-----------------------+-----------------------+
|
101
|
+
| Trace |
|
102
|
+
+--------------+----------------------+-----------------------+--------------------------------+-----------------------+-----------------------+
|
103
|
+
| Sender IP | IP Contacts | Sender Host | Host Contacts | Advertised Sender | Recipient |
|
104
|
+
+--------------+----------------------+-----------------------+--------------------------------+-----------------------+-----------------------+
|
105
|
+
| 10.0.0.1 | abuse@hosttwo.zzz | host.test.zzz | support@test.zzz | dodgy.test.zzz | mx.google.com |
|
106
|
+
| 10.0.0.2 | abuse@hostone.zzz | | | dodgy.othertest.zzz | mail.hostthree.zzz |
|
107
|
+
+--------------+----------------------+-----------------------+--------------------------------+-----------------------+-----------------------+
|
108
108
|
|
109
109
|
```
|
110
110
|
|
@@ -116,7 +116,8 @@ be trusted.
|
|
116
116
|
|
117
117
|
The `Trace` secion shows a subset of the `Received` headers from the original (advertised, but not necessarily actual)
|
118
118
|
origin (the last entry in the table) to the last external server to process the email before the recipient's mail host
|
119
|
-
received the email.
|
119
|
+
received the email. The contacts are abuse contacts for the sender IP and the sender host as found in the results of a
|
120
|
+
WHOIS lookup. If this could not be resolved, these fields will be blank.
|
120
121
|
|
121
122
|
## Dependencies
|
122
123
|
1. [Maxmind GeoIP2 User Account](https://dev.maxmind.com/geoip/geoip2/web-services/) - pay as you go
|
data/lib/phisher_phinder.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
require "phisher_phinder/version"
|
2
2
|
|
3
3
|
require 'maxmind/geoip2'
|
4
|
+
require 'whois-parser'
|
4
5
|
|
5
6
|
require_relative './phisher_phinder/command'
|
6
7
|
require_relative './phisher_phinder/display'
|
7
8
|
|
8
9
|
require_relative './phisher_phinder/body_hyperlink'
|
9
10
|
require_relative './phisher_phinder/cached_geoip_client'
|
11
|
+
require_relative './phisher_phinder/contact_finder'
|
12
|
+
require_relative './phisher_phinder/whois_email_extractor'
|
10
13
|
require_relative './phisher_phinder/null_lookup_client'
|
11
14
|
require_relative './phisher_phinder/null_response'
|
12
15
|
require_relative './phisher_phinder/geoip_ip_data'
|
@@ -13,7 +13,14 @@ module PhisherPhinder
|
|
13
13
|
end
|
14
14
|
ip_factory = PhisherPhinder::ExtendedIpFactory.new(geoip_client: lookup_client)
|
15
15
|
mail_parser = PhisherPhinder::MailParser::Parser.new(ip_factory, line_ending)
|
16
|
-
|
16
|
+
whois_client = Whois::Client.new
|
17
|
+
tracing_report = PhisherPhinder::TracingReport.new(
|
18
|
+
mail_parser.parse(contents),
|
19
|
+
PhisherPhinder::ContactFinder.new(
|
20
|
+
whois_client: whois_client,
|
21
|
+
extractor: PhisherPhinder::WhoisEmailExtractor.new
|
22
|
+
)
|
23
|
+
)
|
17
24
|
tracing_report.report
|
18
25
|
end
|
19
26
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PhisherPhinder
|
4
|
+
class ContactFinder
|
5
|
+
def initialize(whois_client:, extractor:)
|
6
|
+
@whois_client = whois_client
|
7
|
+
@extractor = extractor
|
8
|
+
end
|
9
|
+
|
10
|
+
def contacts_for(address)
|
11
|
+
whois_content = nil
|
12
|
+
begin
|
13
|
+
whois_content = case address
|
14
|
+
when ExtendedIp
|
15
|
+
@whois_client.lookup(address.ip_address.to_s).content
|
16
|
+
when String
|
17
|
+
hostname_parts = address.split('.')
|
18
|
+
whois_content = nil
|
19
|
+
until whois_content do
|
20
|
+
address = hostname_parts.join('.')
|
21
|
+
whois_record = @whois_client.lookup(address)
|
22
|
+
if whois_record.parser.available?
|
23
|
+
hostname_parts = hostname_parts[1..-1]
|
24
|
+
else
|
25
|
+
whois_content = whois_record.content
|
26
|
+
end
|
27
|
+
end
|
28
|
+
whois_content
|
29
|
+
end
|
30
|
+
rescue Whois::ServerNotFound
|
31
|
+
rescue Whois::AttributeNotImplemented
|
32
|
+
end
|
33
|
+
|
34
|
+
whois_content ? @extractor.abuse_contact_emails(whois_content) : []
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -32,14 +32,16 @@ module PhisherPhinder
|
|
32
32
|
data = input_data[:tracing].map do |entry|
|
33
33
|
[
|
34
34
|
entry[:sender][:ip],
|
35
|
+
display_email_addresses(entry[:sender_contact_details][:ip][:email]),
|
35
36
|
entry[:sender][:host],
|
37
|
+
display_email_addresses(entry[:sender_contact_details][:host][:email]),
|
36
38
|
entry[:advertised_sender] || entry[:helo],
|
37
39
|
entry[:recipient]
|
38
40
|
]
|
39
41
|
end
|
40
42
|
|
41
43
|
trace_table = Terminal::Table.new(
|
42
|
-
headings: ['Sender IP', 'Sender Host', 'Advertised Sender', 'Recipient'],
|
44
|
+
headings: ['Sender IP', 'IP Contacts', 'Sender Host', 'Host Contacts', 'Advertised Sender', 'Recipient'],
|
43
45
|
title: 'Trace',
|
44
46
|
rows: data
|
45
47
|
)
|
@@ -60,5 +62,9 @@ module PhisherPhinder
|
|
60
62
|
output << [description, input_data[:origin][type].join(', ')]
|
61
63
|
end
|
62
64
|
end
|
65
|
+
|
66
|
+
def display_email_addresses(email_addresses)
|
67
|
+
email_addresses.map { |address| address.gsub(/[,<>]/, '') }.join(', ')
|
68
|
+
end
|
63
69
|
end
|
64
70
|
end
|
@@ -2,8 +2,9 @@
|
|
2
2
|
|
3
3
|
module PhisherPhinder
|
4
4
|
class TracingReport
|
5
|
-
def initialize(mail)
|
5
|
+
def initialize(mail, contact_finder)
|
6
6
|
@mail = mail
|
7
|
+
@contact_finder = contact_finder
|
7
8
|
end
|
8
9
|
|
9
10
|
def report
|
@@ -34,7 +35,14 @@ module PhisherPhinder
|
|
34
35
|
|
35
36
|
def extract_tracing_headers(received_headers, latest_spf_entry)
|
36
37
|
start = received_headers[:received].find_index { |h| h[:sender][:ip] == ip_address(latest_spf_entry) }
|
37
|
-
received_headers[:received][start..-1]
|
38
|
+
received_headers[:received][start..-1].map do |h|
|
39
|
+
h.merge(
|
40
|
+
sender_contact_details: {
|
41
|
+
host: {email: @contact_finder.contacts_for(h[:sender][:host])},
|
42
|
+
ip: {email: @contact_finder.contacts_for(h[:sender][:ip])},
|
43
|
+
}
|
44
|
+
)
|
45
|
+
end
|
38
46
|
end
|
39
47
|
|
40
48
|
def extract_origin_headers(headers)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PhisherPhinder
|
4
|
+
class WhoisEmailExtractor
|
5
|
+
def abuse_contact_emails(contents)
|
6
|
+
if contents =~ /OrgAbuseEmail/
|
7
|
+
contents.scan(/OrgAbuseEmail:\s+(\S+)/).flatten.uniq
|
8
|
+
elsif contents =~ /Abuse contact for .+? is '([^']+)'/
|
9
|
+
[$1]
|
10
|
+
elsif contents =~ /Registrar Abuse Contact Email:\s+([\S]+)/
|
11
|
+
[$1]
|
12
|
+
elsif contents =~ /(abuse@[\S]+)/
|
13
|
+
[$1]
|
14
|
+
else
|
15
|
+
[]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: phisher_phinder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rory McKinley
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-01-
|
11
|
+
date: 2021-01-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dotenv
|
@@ -249,6 +249,7 @@ files:
|
|
249
249
|
- lib/phisher_phinder/body_hyperlink.rb
|
250
250
|
- lib/phisher_phinder/cached_geoip_client.rb
|
251
251
|
- lib/phisher_phinder/command.rb
|
252
|
+
- lib/phisher_phinder/contact_finder.rb
|
252
253
|
- lib/phisher_phinder/display.rb
|
253
254
|
- lib/phisher_phinder/expanded_data_processor.rb
|
254
255
|
- lib/phisher_phinder/extended_ip.rb
|
@@ -276,6 +277,7 @@ files:
|
|
276
277
|
- lib/phisher_phinder/simple_ip.rb
|
277
278
|
- lib/phisher_phinder/tracing_report.rb
|
278
279
|
- lib/phisher_phinder/version.rb
|
280
|
+
- lib/phisher_phinder/whois_email_extractor.rb
|
279
281
|
- phisher_phinder.gemspec
|
280
282
|
homepage: https://capefox.co
|
281
283
|
licenses:
|