rogue_one 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +3 -3
- data/lib/rogue_one.rb +0 -1
- data/lib/rogue_one/cli.rb +19 -3
- data/lib/rogue_one/detector.rb +37 -10
- data/lib/rogue_one/version.rb +1 -1
- data/renovate.json +5 -0
- metadata +3 -3
- data/lib/rogue_one/resolver.rb +0 -55
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 36b1d9ea6171500c42fd1930ba0807e74d8df4908fdec5eb47f1b88b0262caf6
|
4
|
+
data.tar.gz: 3836ad7bc6a13b68e1fa07d5d584ccbe0da64c8a4c1ee31e16d8f6e5037ada7f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8659b118ceaf22a6ec4756d4f883f8bda633ddf1230aab126c2666ad967df887dd7b1fed576b2f3608ed0adefea695067030ed079b3a915af8c06b1398bd2bd0
|
7
|
+
data.tar.gz: 3c6debab123e645b9765627dda48bc5c2674ee9101f53da0c8bb967a72d54cea411213cc6b6d2354263f1034b73d75282058872779f75a1ac07ec3e5bb77a63d
|
data/README.md
CHANGED
@@ -39,16 +39,16 @@ Usage:
|
|
39
39
|
rogue_one report [DNS_SERVER]
|
40
40
|
|
41
41
|
Options:
|
42
|
+
[--custom-list=CUSTOM_LIST] # A path to a custom list of domains
|
42
43
|
[--default-list=DEFAULT_LIST] # A default list of top 100 domains (Alexa or Fortune)
|
43
44
|
# Default: alexa
|
44
|
-
[--
|
45
|
+
[--record-type=RECORD_TYPE] # A type of the DNS resource to check
|
46
|
+
# Default: A
|
45
47
|
[--threshold=N] # Threshold value for determining malicious or not
|
46
48
|
[--verbose], [--no-verbose]
|
47
49
|
|
48
50
|
Show a report of a given DNS server
|
49
51
|
|
50
|
-
Show a report of a given DNS server
|
51
|
-
|
52
52
|
$ rogue_one report 1.1.1.1
|
53
53
|
{
|
54
54
|
"verdict": "benign one",
|
data/lib/rogue_one.rb
CHANGED
data/lib/rogue_one/cli.rb
CHANGED
@@ -5,20 +5,36 @@ require "json"
|
|
5
5
|
|
6
6
|
module RogueOne
|
7
7
|
class CLI < Thor
|
8
|
+
class << self
|
9
|
+
def exit_on_failure?
|
10
|
+
true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
8
14
|
desc "report [DNS_SERVER]", "Show a report of a given DNS server"
|
9
|
-
method_option :default_list, type: :string, default: "alexa", desc: "A default list of top 100 domains (Alexa or Fortune)"
|
10
15
|
method_option :custom_list, type: :string, desc: "A path to a custom list of domains"
|
16
|
+
method_option :default_list, type: :string, default: "alexa", desc: "A default list of top 100 domains (Alexa or Fortune)"
|
17
|
+
method_option :record_type, type: :string, default: "A", desc: "A type of the DNS resource to check"
|
11
18
|
method_option :threshold, type: :numeric, desc: "Threshold value for determining malicious or not"
|
12
19
|
method_option :verbose, type: :boolean
|
13
20
|
def report(dns_server)
|
14
21
|
with_error_handling do
|
15
22
|
Ping.pong? dns_server
|
16
23
|
|
17
|
-
default_list = options["default_list"].downcase
|
18
24
|
custom_list = options["custom_list"]
|
25
|
+
default_list = options["default_list"].downcase
|
26
|
+
record_type = options["record_type"].upcase
|
19
27
|
threshold = options["threshold"]
|
20
28
|
verbose = options["verbose"]
|
21
|
-
|
29
|
+
|
30
|
+
detector = Detector.new(
|
31
|
+
custom_list: custom_list,
|
32
|
+
default_list: default_list,
|
33
|
+
record_type: record_type,
|
34
|
+
target: dns_server,
|
35
|
+
threshold: threshold,
|
36
|
+
verbose: verbose,
|
37
|
+
)
|
22
38
|
puts JSON.pretty_generate(detector.report)
|
23
39
|
end
|
24
40
|
end
|
data/lib/rogue_one/detector.rb
CHANGED
@@ -11,18 +11,26 @@ require "etc"
|
|
11
11
|
|
12
12
|
module RogueOne
|
13
13
|
class Detector
|
14
|
-
attr_reader :target
|
15
|
-
attr_reader :default_list
|
16
14
|
attr_reader :custom_list
|
17
|
-
attr_reader :
|
15
|
+
attr_reader :default_list
|
18
16
|
attr_reader :max_concurrency
|
17
|
+
attr_reader :record_type
|
18
|
+
attr_reader :target
|
19
|
+
attr_reader :verbose
|
19
20
|
|
20
21
|
GOOGLE_PUBLIC_DNS = "8.8.8.8"
|
21
22
|
|
22
|
-
def initialize(target:,
|
23
|
+
def initialize(target:,
|
24
|
+
custom_list: nil,
|
25
|
+
default_list: "alexa",
|
26
|
+
record_type: "A",
|
27
|
+
threshold: nil,
|
28
|
+
verbose: false)
|
23
29
|
@target = target
|
24
|
-
|
30
|
+
|
25
31
|
@custom_list = custom_list
|
32
|
+
@default_list = default_list
|
33
|
+
@record_type = record_type.upcase.to_sym
|
26
34
|
@threshold = threshold
|
27
35
|
@verbose = verbose
|
28
36
|
|
@@ -59,7 +67,10 @@ module RogueOne
|
|
59
67
|
def meta
|
60
68
|
return nil unless verbose
|
61
69
|
|
62
|
-
{
|
70
|
+
{
|
71
|
+
record_type: record_type,
|
72
|
+
threshold: threshold,
|
73
|
+
}
|
63
74
|
end
|
64
75
|
|
65
76
|
def landing_pages
|
@@ -89,13 +100,13 @@ module RogueOne
|
|
89
100
|
return unless @memo.empty?
|
90
101
|
|
91
102
|
# read domains outside of the async blocks
|
92
|
-
|
103
|
+
load_domains
|
93
104
|
|
94
|
-
|
105
|
+
normal_resolutions = bulk_resolve(normal_resolver, domains)
|
95
106
|
resolutions = bulk_resolve(target_resolver, domains)
|
96
107
|
|
97
108
|
results = resolutions.map do |domain, addresses|
|
98
|
-
normal_addresses =
|
109
|
+
normal_addresses = normal_resolutions.dig(domain) || []
|
99
110
|
address = (addresses || []).first
|
100
111
|
[domain, address] if address && !normal_addresses.include?(address)
|
101
112
|
end.compact.to_h
|
@@ -104,6 +115,10 @@ module RogueOne
|
|
104
115
|
@verbose_memo = results if verbose
|
105
116
|
end
|
106
117
|
|
118
|
+
def load_domains
|
119
|
+
domains
|
120
|
+
end
|
121
|
+
|
107
122
|
def domains
|
108
123
|
@domains ||= custom_list ? custom_domains : top_100_domains
|
109
124
|
end
|
@@ -131,6 +146,7 @@ module RogueOne
|
|
131
146
|
|
132
147
|
def bulk_resolve(resolver, domains)
|
133
148
|
results = []
|
149
|
+
|
134
150
|
Async do
|
135
151
|
barrier = Async::Barrier.new
|
136
152
|
semaphore = Async::Semaphore.new(max_concurrency, parent: barrier)
|
@@ -139,7 +155,7 @@ module RogueOne
|
|
139
155
|
semaphore.async do
|
140
156
|
addresses = []
|
141
157
|
begin
|
142
|
-
addresses = resolver.addresses_for(domain,
|
158
|
+
addresses = resolver.addresses_for(domain, dns_resource_by_record_type, { retries: 1 }).map(&:to_s)
|
143
159
|
rescue Async::DNS::ResolutionFailure
|
144
160
|
# do nothing
|
145
161
|
end
|
@@ -157,5 +173,16 @@ module RogueOne
|
|
157
173
|
def target_resolver
|
158
174
|
Async::DNS::Resolver.new([[:udp, target, 53], [:tcp, target, 53]])
|
159
175
|
end
|
176
|
+
|
177
|
+
def dns_resource_by_record_type
|
178
|
+
@dns_resource_by_record_type ||= dns_resources.dig(record_type)
|
179
|
+
end
|
180
|
+
|
181
|
+
def dns_resources
|
182
|
+
{
|
183
|
+
A: Resolv::DNS::Resource::IN::A,
|
184
|
+
AAAA: Resolv::DNS::Resource::IN::AAAA,
|
185
|
+
}
|
186
|
+
end
|
160
187
|
end
|
161
188
|
end
|
data/lib/rogue_one/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rogue_one
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Manabu Niseki
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-07
|
11
|
+
date: 2020-10-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -120,8 +120,8 @@ files:
|
|
120
120
|
- lib/rogue_one/detector.rb
|
121
121
|
- lib/rogue_one/domain_list.rb
|
122
122
|
- lib/rogue_one/ping.rb
|
123
|
-
- lib/rogue_one/resolver.rb
|
124
123
|
- lib/rogue_one/version.rb
|
124
|
+
- renovate.json
|
125
125
|
- rogue_one.gemspec
|
126
126
|
homepage: https://github.com/ninoseki/rogue_one
|
127
127
|
licenses:
|
data/lib/rogue_one/resolver.rb
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "resolv"
|
4
|
-
|
5
|
-
module RogueOne
|
6
|
-
class Resolver
|
7
|
-
attr_reader :nameserver
|
8
|
-
|
9
|
-
def initialize(nameserver:)
|
10
|
-
@nameserver = nameserver
|
11
|
-
end
|
12
|
-
|
13
|
-
def get_resource(domain, type)
|
14
|
-
_resolver.getresource(domain, resource_by_type(type)).address.to_s
|
15
|
-
rescue Resolv::ResolvError => _e
|
16
|
-
nil
|
17
|
-
end
|
18
|
-
|
19
|
-
def get_resources(domain, type)
|
20
|
-
_resolver.getresources(domain, resource_by_type(type)).map { |r| r.address.to_s }
|
21
|
-
rescue Resolv::ResolvError => _e
|
22
|
-
nil
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def _resolver
|
28
|
-
@_resolver ||= Resolv::DNS.new(nameserver: [nameserver])
|
29
|
-
@_resolver.timeouts = 5
|
30
|
-
@_resolver
|
31
|
-
end
|
32
|
-
|
33
|
-
def resource_by_type(type)
|
34
|
-
resources.dig(type.upcase.to_sym)
|
35
|
-
end
|
36
|
-
|
37
|
-
def resources
|
38
|
-
{
|
39
|
-
ANY: Resolv::DNS::Resource::IN::ANY,
|
40
|
-
NS: Resolv::DNS::Resource::IN::NS,
|
41
|
-
CNAME: Resolv::DNS::Resource::IN::CNAME,
|
42
|
-
SOA: Resolv::DNS::Resource::IN::SOA,
|
43
|
-
HINFO: Resolv::DNS::Resource::IN::HINFO,
|
44
|
-
MINFO: Resolv::DNS::Resource::IN::MINFO,
|
45
|
-
MX: Resolv::DNS::Resource::IN::MX,
|
46
|
-
TXT: Resolv::DNS::Resource::IN::TXT,
|
47
|
-
A: Resolv::DNS::Resource::IN::A,
|
48
|
-
WKS: Resolv::DNS::Resource::IN::WKS,
|
49
|
-
PTR: Resolv::DNS::Resource::IN::PTR,
|
50
|
-
AAAA: Resolv::DNS::Resource::IN::AAAA,
|
51
|
-
SRV: Resolv::DNS::Resource::IN::SRV,
|
52
|
-
}
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|