phisher_phinder 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.env.example +2 -1
- data/.gitignore +3 -0
- data/Gemfile +0 -11
- data/Gemfile.lock +45 -13
- data/README.md +108 -2
- data/exe/phisher_phinder +61 -0
- data/lib/phisher_phinder.rb +11 -2
- data/lib/phisher_phinder/command.rb +20 -0
- data/lib/phisher_phinder/display.rb +64 -0
- data/lib/phisher_phinder/extended_ip.rb +4 -0
- data/lib/phisher_phinder/extended_ip_factory.rb +4 -2
- data/lib/phisher_phinder/geoip_ip_data.rb +9 -2
- data/lib/phisher_phinder/mail.rb +10 -3
- data/lib/phisher_phinder/mail_parser.rb +43 -30
- data/lib/phisher_phinder/mail_parser/authentication_headers/auth_results_parser.rb +150 -0
- data/lib/phisher_phinder/mail_parser/authentication_headers/parser.rb +25 -0
- data/lib/phisher_phinder/mail_parser/authentication_headers/received_spf_parser.rb +222 -0
- data/lib/phisher_phinder/mail_parser/body/block_classifier.rb +106 -0
- data/lib/phisher_phinder/mail_parser/body/block_parser.rb +37 -0
- data/lib/phisher_phinder/mail_parser/body_parser.rb +26 -31
- data/lib/phisher_phinder/mail_parser/header_value_parser.rb +25 -10
- data/lib/phisher_phinder/mail_parser/received_headers/by_parser.rb +35 -5
- data/lib/phisher_phinder/mail_parser/received_headers/for_parser.rb +25 -5
- data/lib/phisher_phinder/mail_parser/received_headers/from_parser.rb +50 -6
- data/lib/phisher_phinder/mail_parser/received_headers/parser.rb +50 -29
- data/lib/phisher_phinder/mail_parser/received_headers/starttls_parser.rb +8 -1
- data/lib/phisher_phinder/null_lookup_client.rb +9 -0
- data/lib/phisher_phinder/null_response.rb +12 -0
- data/lib/phisher_phinder/sender_extractor.rb +74 -0
- data/lib/phisher_phinder/simple_ip.rb +4 -0
- data/lib/phisher_phinder/tracing_report.rb +47 -0
- data/lib/phisher_phinder/version.rb +1 -1
- data/phisher_phinder.gemspec +15 -1
- metadata +208 -13
@@ -4,12 +4,11 @@ module PhisherPhinder
|
|
4
4
|
module MailParser
|
5
5
|
module ReceivedHeaders
|
6
6
|
class Parser
|
7
|
-
def initialize(by_parser:, for_parser:, from_parser:,
|
7
|
+
def initialize(by_parser:, for_parser:, from_parser:, timestamp_parser:, classifier:)
|
8
8
|
@parsers = {
|
9
9
|
by: by_parser,
|
10
10
|
for: for_parser,
|
11
11
|
from: from_parser,
|
12
|
-
starttls: starttls_parser,
|
13
12
|
time: timestamp_parser,
|
14
13
|
}
|
15
14
|
@classifier = classifier
|
@@ -24,7 +23,13 @@ module PhisherPhinder
|
|
24
23
|
components = extract_value_components(header_value).merge(time: timestamp)
|
25
24
|
|
26
25
|
output = @parsers.inject({}) do |memo, (component_name, parser)|
|
27
|
-
memo.merge(parser.parse(components[component_name]))
|
26
|
+
memo.merge(parser.parse(components[component_name])) do |key, old_value, new_value|
|
27
|
+
if key == :starttls && old_value
|
28
|
+
old_value
|
29
|
+
else
|
30
|
+
new_value
|
31
|
+
end
|
32
|
+
end
|
28
33
|
end
|
29
34
|
|
30
35
|
output.merge(@classifier.classify(output))
|
@@ -33,40 +38,56 @@ module PhisherPhinder
|
|
33
38
|
private
|
34
39
|
|
35
40
|
def extract_value_components(header_value)
|
36
|
-
require 'strscan'
|
37
41
|
|
38
|
-
|
42
|
+
values = {
|
43
|
+
time: [],
|
44
|
+
for: [],
|
45
|
+
by: [],
|
46
|
+
from: []
|
47
|
+
}
|
48
|
+
|
49
|
+
cleaned_value = header_value.gsub(/\A\(([^\)]+)\)/, '\1')
|
39
50
|
|
40
|
-
|
51
|
+
tokenised_value = cleaned_value.split(" ")
|
52
|
+
current_component = nil
|
41
53
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
elsif scanner.check(/from\s[^)(]+\sby/)
|
47
|
-
from_part = scanner.scan(/from.+?(?=by)/)
|
48
|
-
else
|
49
|
-
from_part = scanner.scan(/from\s.+?\([^)]+?\)/)
|
54
|
+
tokenised_value.each do |val|
|
55
|
+
current_component = component_start(val, values) || current_component
|
56
|
+
|
57
|
+
values[current_component] << val if current_component
|
50
58
|
end
|
51
59
|
|
52
|
-
|
53
|
-
|
54
|
-
by_part = scanner.scan(/\s?by.+?\sid\s[\S]+\s?/)
|
55
|
-
for_part = scanner.scan(/for\s+\S+/)
|
56
|
-
elsif scanner.check(/\s?by.+?\s(id|ID)\s[\S]+\s?/)
|
57
|
-
by_part = scanner.scan(/\s?by.+?\s(id|ID)\s[\S]+\s?/) unless scanner.eos?
|
58
|
-
for_part = scanner.scan(/for\s+\S+/) unless scanner.eos?
|
59
|
-
starttls_part = scanner.rest unless scanner.eos?
|
60
|
-
elsif scanner.check(/by.+(?!\sid)/)
|
61
|
-
by_part = scanner.scan(/.+/)
|
60
|
+
values.inject({}) do |memo, (component, values)|
|
61
|
+
memo.merge(component => (values.any? ? values.join(' ') : nil))
|
62
62
|
end
|
63
|
+
end
|
63
64
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
65
|
+
def for_scan(scanner)
|
66
|
+
return nil if scanner.eos?
|
67
|
+
|
68
|
+
scanner.check(/for\s<[^>]+>/) ? scanner.scan(/for\s<[^>]+>/) : scanner.scan(/for\s+\S+/)
|
69
|
+
end
|
70
|
+
|
71
|
+
def component_start(token, values)
|
72
|
+
markers = {
|
73
|
+
'from' => :from,
|
74
|
+
'by' => :by,
|
75
|
+
'for' => :for
|
76
|
+
}
|
77
|
+
|
78
|
+
return nil unless component = markers[token]
|
79
|
+
|
80
|
+
blocking_components = {
|
81
|
+
from: [:by, :for],
|
82
|
+
by: [:for],
|
83
|
+
for: []
|
69
84
|
}
|
85
|
+
|
86
|
+
if blocking_components[component].any? { |blocking_comp| values[blocking_comp].any? }
|
87
|
+
nil
|
88
|
+
else
|
89
|
+
component
|
90
|
+
end
|
70
91
|
end
|
71
92
|
end
|
72
93
|
end
|
@@ -9,6 +9,7 @@ module PhisherPhinder
|
|
9
9
|
|
10
10
|
patterns = [
|
11
11
|
/\(version=(?<version>\S+)\scipher=(?<cipher>\S+)\sbits=(?<bits>\S+)\)/,
|
12
|
+
/\(version=(?<version>\S+),\scipher=(?<cipher>\S+)\)/,
|
12
13
|
/using\s(?<version>\S+)\swith cipher\s(?<cipher>\S+)\s\((?<bits>.+?) bits\)/
|
13
14
|
]
|
14
15
|
|
@@ -16,7 +17,13 @@ module PhisherPhinder
|
|
16
17
|
memo || component.match(pattern)
|
17
18
|
end
|
18
19
|
|
19
|
-
{
|
20
|
+
{
|
21
|
+
starttls: {
|
22
|
+
version: matches[:version],
|
23
|
+
cipher: matches[:cipher],
|
24
|
+
bits: matches.names.include?('bits') ? matches[:bits] : nil,
|
25
|
+
}
|
26
|
+
}
|
20
27
|
end
|
21
28
|
end
|
22
29
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PhisherPhinder
|
4
|
+
class SenderExtractor
|
5
|
+
def extract(mail)
|
6
|
+
auth_senders = {
|
7
|
+
hosts: [],
|
8
|
+
email_addresses: []
|
9
|
+
}
|
10
|
+
|
11
|
+
processed_authservs = []
|
12
|
+
|
13
|
+
authentication_results = mail.authentication_headers[:authentication_results]
|
14
|
+
|
15
|
+
if authentication_results.any?
|
16
|
+
trusted_auth_header = authentication_results.first
|
17
|
+
untrusted_auth_headers = authentication_results[1..-1]
|
18
|
+
|
19
|
+
auth_senders[:hosts] << {
|
20
|
+
entry_type: :ip,
|
21
|
+
host: trusted_auth_header[:spf].first[:ip],
|
22
|
+
spf: {present: true, trusted: true}
|
23
|
+
}
|
24
|
+
auth_senders[:email_addresses] << {
|
25
|
+
email_address: trusted_auth_header[:spf].first[:from],
|
26
|
+
spf: {present: true, trusted: true, result: trusted_auth_header[:spf].first[:result]},
|
27
|
+
}
|
28
|
+
|
29
|
+
processed_authservs << trusted_auth_header[:authserv_id]
|
30
|
+
|
31
|
+
untrusted_auth_headers.each do |header|
|
32
|
+
next if processed_authservs.include? header[:authserv_id]
|
33
|
+
|
34
|
+
auth_senders[:hosts] << {entry_type: :ip, host: header[:spf].first[:ip], spf: {present: true, trusted: false}}
|
35
|
+
unless auth_senders[:email_addresses].find { |entry| entry[:email_address] == header[:spf].first[:from] }
|
36
|
+
auth_senders[:email_addresses] << {
|
37
|
+
email_address: header[:spf].first[:from],
|
38
|
+
spf: {present: true, trusted: false, result: header[:spf].first[:result]},
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
tracing_senders = []
|
45
|
+
|
46
|
+
mail.tracing_headers[:received].each do |header|
|
47
|
+
if tracing_senders.empty?
|
48
|
+
if header[:sender] && header[:sender][:ip] == trusted_auth_sender_ip(auth_senders)
|
49
|
+
tracing_senders << header[:sender]
|
50
|
+
end
|
51
|
+
|
52
|
+
next
|
53
|
+
end
|
54
|
+
|
55
|
+
if header[:sender] && header[:recipient] == tracing_senders.last[:host]
|
56
|
+
tracing_senders << header[:sender]
|
57
|
+
else
|
58
|
+
break
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
{
|
63
|
+
authentication_senders: auth_senders,
|
64
|
+
tracing_senders: tracing_senders
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def trusted_auth_sender_ip(authentication_senders)
|
71
|
+
(authentication_senders[:hosts].find { |e| e[:spf][:trusted] })[:host]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PhisherPhinder
|
4
|
+
class TracingReport
|
5
|
+
def initialize(mail)
|
6
|
+
@mail = mail
|
7
|
+
end
|
8
|
+
|
9
|
+
def report
|
10
|
+
{
|
11
|
+
authentication: {
|
12
|
+
mechanisms: [:spf],
|
13
|
+
spf: {
|
14
|
+
success: latest_spf_entry[:result] == :pass,
|
15
|
+
ip: latest_spf_entry[:ip],
|
16
|
+
from_address: latest_spf_entry[:mailfrom],
|
17
|
+
client_ip: latest_spf_entry[:client_ip],
|
18
|
+
}
|
19
|
+
},
|
20
|
+
origin: extract_origin_headers(@mail.headers),
|
21
|
+
tracing: extract_tracing_headers(@mail.tracing_headers, latest_spf_entry)
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def latest_spf_entry
|
28
|
+
@mail.authentication_headers[:received_spf].first
|
29
|
+
end
|
30
|
+
|
31
|
+
def ip_address(spf_entry)
|
32
|
+
spf_entry[:ip] || spf_entry[:client_ip]
|
33
|
+
end
|
34
|
+
|
35
|
+
def extract_tracing_headers(received_headers, latest_spf_entry)
|
36
|
+
start = received_headers[:received].find_index { |h| h[:sender][:ip] == ip_address(latest_spf_entry) }
|
37
|
+
received_headers[:received][start..-1]
|
38
|
+
end
|
39
|
+
|
40
|
+
def extract_origin_headers(headers)
|
41
|
+
[:from, :return_path, :message_id].inject({}) do |output, header_type|
|
42
|
+
entries = headers[header_type] || []
|
43
|
+
output.merge(header_type => entries.map { |h| h[:data] })
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/phisher_phinder.gemspec
CHANGED
@@ -27,6 +27,20 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
28
|
spec.require_paths = ["lib"]
|
29
29
|
|
30
|
+
spec.add_dependency "dotenv", "~> 2.7.5"
|
31
|
+
spec.add_dependency "maxmind-geoip2", "~> 0.4.0"
|
32
|
+
spec.add_dependency "nokogiri", "~> 1.11.0"
|
33
|
+
spec.add_dependency "sequel", "~> 5.33"
|
34
|
+
spec.add_dependency "sqlite3", "~> 1.4.2"
|
35
|
+
spec.add_dependency "terminal-table", "~> 2.0.0"
|
36
|
+
spec.add_dependency "whois", "~> 5.0.1"
|
37
|
+
spec.add_dependency "whois-parser", "~> 1.2.0"
|
38
|
+
|
39
|
+
spec.add_development_dependency "bundler-audit", "~> 0.7.0.1"
|
40
|
+
spec.add_development_dependency "rake", "~> 12.0"
|
41
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
42
|
+
spec.add_development_dependency "timecop", "~> 0.9.2"
|
43
|
+
spec.add_development_dependency 'database_cleaner-sequel', '1.8.0'
|
44
|
+
spec.add_development_dependency 'webmock', '~> 3.8.3'
|
30
45
|
spec.add_development_dependency "pry"
|
31
|
-
spec.add_development_dependency "rspec", "3.9.0"
|
32
46
|
end
|
metadata
CHANGED
@@ -1,47 +1,230 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: phisher_phinder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rory McKinley
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: dotenv
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 2.7.5
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.7.5
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: maxmind-geoip2
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.4.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.4.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: nokogiri
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.11.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.11.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: sequel
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '5.33'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '5.33'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: sqlite3
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.4.2
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.4.2
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: terminal-table
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 2.0.0
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 2.0.0
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: whois
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 5.0.1
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 5.0.1
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: whois-parser
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 1.2.0
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 1.2.0
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: bundler-audit
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 0.7.0.1
|
20
132
|
type: :development
|
21
133
|
prerelease: false
|
22
134
|
version_requirements: !ruby/object:Gem::Requirement
|
23
135
|
requirements:
|
24
|
-
- - "
|
136
|
+
- - "~>"
|
25
137
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
138
|
+
version: 0.7.0.1
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rake
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '12.0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '12.0'
|
27
153
|
- !ruby/object:Gem::Dependency
|
28
154
|
name: rspec
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '3.0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '3.0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: timecop
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - "~>"
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 0.9.2
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - "~>"
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: 0.9.2
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: database_cleaner-sequel
|
29
183
|
requirement: !ruby/object:Gem::Requirement
|
30
184
|
requirements:
|
31
185
|
- - '='
|
32
186
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
187
|
+
version: 1.8.0
|
34
188
|
type: :development
|
35
189
|
prerelease: false
|
36
190
|
version_requirements: !ruby/object:Gem::Requirement
|
37
191
|
requirements:
|
38
192
|
- - '='
|
39
193
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
194
|
+
version: 1.8.0
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: webmock
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - "~>"
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: 3.8.3
|
202
|
+
type: :development
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - "~>"
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: 3.8.3
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: pry
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - ">="
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: '0'
|
216
|
+
type: :development
|
217
|
+
prerelease: false
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - ">="
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '0'
|
41
223
|
description: A collection of tools to dissect and report on phishing emails
|
42
224
|
email:
|
43
225
|
- rorymckinley@gmail.com
|
44
|
-
executables:
|
226
|
+
executables:
|
227
|
+
- phisher_phinder
|
45
228
|
extensions: []
|
46
229
|
extra_rdoc_files: []
|
47
230
|
files:
|
@@ -61,15 +244,23 @@ files:
|
|
61
244
|
- bin/console
|
62
245
|
- bin/setup
|
63
246
|
- db/migrations/0001_create_geo_ip_cache.rb
|
247
|
+
- exe/phisher_phinder
|
64
248
|
- lib/phisher_phinder.rb
|
65
249
|
- lib/phisher_phinder/body_hyperlink.rb
|
66
250
|
- lib/phisher_phinder/cached_geoip_client.rb
|
251
|
+
- lib/phisher_phinder/command.rb
|
252
|
+
- lib/phisher_phinder/display.rb
|
67
253
|
- lib/phisher_phinder/expanded_data_processor.rb
|
68
254
|
- lib/phisher_phinder/extended_ip.rb
|
69
255
|
- lib/phisher_phinder/extended_ip_factory.rb
|
70
256
|
- lib/phisher_phinder/geoip_ip_data.rb
|
71
257
|
- lib/phisher_phinder/mail.rb
|
72
258
|
- lib/phisher_phinder/mail_parser.rb
|
259
|
+
- lib/phisher_phinder/mail_parser/authentication_headers/auth_results_parser.rb
|
260
|
+
- lib/phisher_phinder/mail_parser/authentication_headers/parser.rb
|
261
|
+
- lib/phisher_phinder/mail_parser/authentication_headers/received_spf_parser.rb
|
262
|
+
- lib/phisher_phinder/mail_parser/body/block_classifier.rb
|
263
|
+
- lib/phisher_phinder/mail_parser/body/block_parser.rb
|
73
264
|
- lib/phisher_phinder/mail_parser/body_parser.rb
|
74
265
|
- lib/phisher_phinder/mail_parser/header_value_parser.rb
|
75
266
|
- lib/phisher_phinder/mail_parser/received_headers/by_parser.rb
|
@@ -79,7 +270,11 @@ files:
|
|
79
270
|
- lib/phisher_phinder/mail_parser/received_headers/parser.rb
|
80
271
|
- lib/phisher_phinder/mail_parser/received_headers/starttls_parser.rb
|
81
272
|
- lib/phisher_phinder/mail_parser/received_headers/timestamp_parser.rb
|
273
|
+
- lib/phisher_phinder/null_lookup_client.rb
|
274
|
+
- lib/phisher_phinder/null_response.rb
|
275
|
+
- lib/phisher_phinder/sender_extractor.rb
|
82
276
|
- lib/phisher_phinder/simple_ip.rb
|
277
|
+
- lib/phisher_phinder/tracing_report.rb
|
83
278
|
- lib/phisher_phinder/version.rb
|
84
279
|
- phisher_phinder.gemspec
|
85
280
|
homepage: https://capefox.co
|
@@ -90,7 +285,7 @@ metadata:
|
|
90
285
|
homepage_uri: https://capefox.co
|
91
286
|
source_code_uri: https://github.com/rorymckinley/phisher_phinder
|
92
287
|
changelog_uri: https://github.com/rorymckinley/phisher_phinder/blob/master/CHANGELOG.md
|
93
|
-
post_install_message:
|
288
|
+
post_install_message:
|
94
289
|
rdoc_options: []
|
95
290
|
require_paths:
|
96
291
|
- lib
|
@@ -106,7 +301,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
106
301
|
version: '0'
|
107
302
|
requirements: []
|
108
303
|
rubygems_version: 3.1.2
|
109
|
-
signing_key:
|
304
|
+
signing_key:
|
110
305
|
specification_version: 4
|
111
306
|
summary: A gem for dissecting phishing emails
|
112
307
|
test_files: []
|