rogue_one 0.4.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|