dert 1.0.1
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 +7 -0
- data/.gitignore +24 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +39 -0
- data/Rakefile +2 -0
- data/bin/dert +73 -0
- data/dert.gemspec +25 -0
- data/lib/dert/dns.rb +278 -0
- data/lib/dert/methods/arin.rb +71 -0
- data/lib/dert/methods/axfr.rb +107 -0
- data/lib/dert/methods/brt.rb +69 -0
- data/lib/dert/methods/init.rb +9 -0
- data/lib/dert/methods/ipv6.rb +27 -0
- data/lib/dert/methods/rvl.rb +33 -0
- data/lib/dert/methods/srv.rb +44 -0
- data/lib/dert/methods/std.rb +82 -0
- data/lib/dert/methods/tld.rb +43 -0
- data/lib/dert/version.rb +3 -0
- data/lib/dert.rb +3 -0
- data/test/arin.rb +20 -0
- data/test/arin.yml +65 -0
- data/test/axfr.rb +20 -0
- data/test/axfr.yml +148 -0
- data/test/brt.rb +12 -0
- data/test/ipv6.rb +12 -0
- data/test/rvl.rb +11 -0
- data/test/srv.rb +10 -0
- data/test/std.rb +10 -0
- data/test/tdl.rb +10 -0
- data/test/wordlists/hosts.txt +2062 -0
- data/test/wordlists/ips.txt +3 -0
- data/test/wordlists/short_hosts.txt +9 -0
- data/test/wordlists/subdomains.txt +21 -0
- metadata +151 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4c1b1ce81e63f6e8a3104b069a7a856caec7c954
|
4
|
+
data.tar.gz: bcdc9478389314610cbe928e02fa0547a2c05898
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 56e24913f9651a1215325d6bc0f095b5da40eaca04053be545ea041a62b3540cfc80f1914d8171de10ede27ca3a06403639f7eb1c6a306d2747ad20ff0318667
|
7
|
+
data.tar.gz: 973bb735065cef74220a53dedfb536e54d63ba03c5cf77844e979dfe4ea4c450ec79a1f3d9d0acd5ffac9d0e243ba775b0c66dcccca8fd6e917c1ec8ed3caa76
|
data/.gitignore
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
23
|
+
test/*.txt
|
24
|
+
.idea/*
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
dert
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.1.2
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Coleton Pierson
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# Dert
|
2
|
+
|
3
|
+
Tool used to enumerate hosts and domains for reconnaissance during a penetration test.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'dert'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install dert
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
require 'dert'
|
22
|
+
|
23
|
+
Dert.run(options)
|
24
|
+
|
25
|
+
or
|
26
|
+
|
27
|
+
cd bin
|
28
|
+
|
29
|
+
chmod +x ./dert
|
30
|
+
|
31
|
+
./dert
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
1. Fork it ( https://github.com/coleton/dert/fork )
|
36
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
37
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
38
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
39
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/dert
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
###########################################################################
|
3
|
+
# Author: Coleton Pierson #
|
4
|
+
# Company: Praetorian #
|
5
|
+
# Date: August 7, 2014 #
|
6
|
+
# Project: DERT - DNS Enumeration and Reconnaissance Tool #
|
7
|
+
# Description: Small DNS Recon tool created to integrate #
|
8
|
+
# into Project Mercury. #
|
9
|
+
###########################################################################
|
10
|
+
path = File.dirname(__FILE__)
|
11
|
+
require 'optparse'
|
12
|
+
require 'dert'
|
13
|
+
|
14
|
+
if __FILE__ == $0
|
15
|
+
options = {}
|
16
|
+
|
17
|
+
optparse = OptionParser.new do|opts|
|
18
|
+
|
19
|
+
# Banner
|
20
|
+
opts.banner = "Usage: #{File.basename($0)} [options]"
|
21
|
+
|
22
|
+
# Options
|
23
|
+
the_break = "\n\t\t\t\t\t"
|
24
|
+
dns_string = ''
|
25
|
+
dns_string = dns_string + the_break + 'ARIN: "arin"'
|
26
|
+
dns_string = dns_string + the_break + 'AXFR: "zonetransfer"'
|
27
|
+
dns_string = dns_string + the_break + 'BRT: "ipv4 bruteforce (A records)"'
|
28
|
+
dns_string = dns_string + the_break + 'IPV6: "ipv6 bruteforce (AAAA records)"'
|
29
|
+
dns_string = dns_string + the_break + 'RVL: "rvl (PRT records)"'
|
30
|
+
dns_string = dns_string + the_break + 'SRV: "srv (SRV records)"'
|
31
|
+
dns_string = dns_string + the_break + 'STD: "std (SOA, A, MX, NS, TXT records)"'
|
32
|
+
dns_string = dns_string + the_break + 'TDL: "tdl (Bruteforce, A records)"'
|
33
|
+
opts.on( '-e enumeration', '--enumeration type', String, 'DNS Enumeration Types:' + dns_string) do |type|
|
34
|
+
options[:type] = type
|
35
|
+
end
|
36
|
+
|
37
|
+
opts.on( '-t thread', '--thread number', Integer, 'Number of threads') do |thread|
|
38
|
+
options[:threads] = thread
|
39
|
+
end
|
40
|
+
|
41
|
+
opts.on( '-d domain', '--domain domain', String, 'Domain to enumerate' ) do |domain|
|
42
|
+
options[:domain] = domain
|
43
|
+
end
|
44
|
+
|
45
|
+
opts.on( '-w wordlist', '--wordlist path', String, 'Wordlist for bruteforce (ipv6 and brt)' ) do |wordlist|
|
46
|
+
options[:wordlist] = wordlist
|
47
|
+
end
|
48
|
+
|
49
|
+
opts.on( '-s', '--silent', 'Do not print any output' ) do
|
50
|
+
options[:silent] = true
|
51
|
+
end
|
52
|
+
|
53
|
+
options[:logfile] = nil
|
54
|
+
opts.on( '-o', '--output file', 'Write output to a file' ) do |file|
|
55
|
+
options[:output] = file
|
56
|
+
end
|
57
|
+
|
58
|
+
# Help
|
59
|
+
opts.on( '-h', '--help', 'Display this screen' ) do
|
60
|
+
puts opts
|
61
|
+
exit
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
begin
|
66
|
+
optparse.parse!
|
67
|
+
Dert.run(options)
|
68
|
+
rescue => e
|
69
|
+
puts 'Error'
|
70
|
+
puts "Usage: #{File.basename($0)} [options]"
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
data/dert.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'dert/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'dert'
|
8
|
+
spec.version = Dert::VERSION
|
9
|
+
spec.authors = ['Coleton Pierson']
|
10
|
+
spec.email = ['coleton.pierson@gmail.com']
|
11
|
+
spec.summary = %q{DNS Enumeration and Reconnaissance Tool}
|
12
|
+
spec.description = %q{Tool used to enumerate hosts and domains for reconnaissance during a penetration test.}
|
13
|
+
spec.homepage = 'https://github.com/coleton/dert'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_development_dependency 'bundler', '~> 1.6'
|
22
|
+
spec.add_development_dependency 'rake', '~> 10'
|
23
|
+
spec.add_runtime_dependency 'dnsruby', '~> 1'
|
24
|
+
spec.add_runtime_dependency 'librex', '~> 0'
|
25
|
+
end
|
data/lib/dert/dns.rb
ADDED
@@ -0,0 +1,278 @@
|
|
1
|
+
###########################################################################
|
2
|
+
# Author: Coleton Pierson #
|
3
|
+
# Company: Praetorian #
|
4
|
+
# Date: August 7, 2014 #
|
5
|
+
# Project: Dert - DNS Enumeration and Reconnaissance Tool #
|
6
|
+
# Description: Small DNS Recon tool created to integrate #
|
7
|
+
# into Project Mercury. #
|
8
|
+
###########################################################################
|
9
|
+
require 'dnsruby'
|
10
|
+
require 'rex'
|
11
|
+
require 'resolv'
|
12
|
+
require 'socket'
|
13
|
+
require 'timeout'
|
14
|
+
require 'json'
|
15
|
+
|
16
|
+
path = File.dirname(__FILE__)
|
17
|
+
require "#{path}/methods/init"
|
18
|
+
|
19
|
+
module Dert
|
20
|
+
|
21
|
+
#############
|
22
|
+
# Constants #
|
23
|
+
#############
|
24
|
+
module CONSTANTS
|
25
|
+
ARIN = 1
|
26
|
+
AXFR = 2
|
27
|
+
BRT = 3
|
28
|
+
IPV6 = 4
|
29
|
+
RVL = 5
|
30
|
+
SRV = 6
|
31
|
+
STD = 7
|
32
|
+
TDL = 8
|
33
|
+
WILDCARD = 9
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
###########################################################################
|
38
|
+
# @method query(domain, method, list) #
|
39
|
+
# @param domain: [String] Target Domain #
|
40
|
+
# @param method: [Integer] Enum Method #
|
41
|
+
# @param list: [String] Path to Wordlist #
|
42
|
+
# @description Start DNS queries. #
|
43
|
+
###########################################################################
|
44
|
+
def self.query(domain, method, list=nil)
|
45
|
+
case method
|
46
|
+
when CONSTANTS::ARIN
|
47
|
+
return ARIN.query(domain)
|
48
|
+
when CONSTANTS::AXFR
|
49
|
+
return AXFR.query(domain)
|
50
|
+
when CONSTANTS::BRT
|
51
|
+
return BRT.query(domain, list, Dnsruby::Types.A)
|
52
|
+
when CONSTANTS::IPV6
|
53
|
+
return BRT.query(domain, list, Dnsruby::Types.AAAA)
|
54
|
+
when CONSTANTS::RVL
|
55
|
+
return RVL.query(domain)
|
56
|
+
when CONSTANTS::SRV
|
57
|
+
return SRV.query(domain)
|
58
|
+
when CONSTANTS::STD
|
59
|
+
return STD.query(domain)
|
60
|
+
when CONSTANTS::TDL
|
61
|
+
return TDL.query(domain)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
###########################################################################
|
67
|
+
# @method start(domain, method, threads, word_list, output) #
|
68
|
+
# @param domain: [String] Target Domain #
|
69
|
+
# @param method: [Integer] Enum Method #
|
70
|
+
# @param threads: [Integer] Bruteforce Threads #
|
71
|
+
# @param word_list: [String] Path to Wordlist #
|
72
|
+
# @description Threaded DNS Enumeration method. #
|
73
|
+
###########################################################################
|
74
|
+
def self.start(domain, method, threads = nil, word_list = nil, output = nil)
|
75
|
+
|
76
|
+
results = []
|
77
|
+
|
78
|
+
# Process for Brute Force DNS Enumeration
|
79
|
+
if method == CONSTANTS::BRT or method == CONSTANTS::IPV6 or method == CONSTANTS::RVL
|
80
|
+
|
81
|
+
# Count words/ips in list.
|
82
|
+
count = File.foreach(word_list).inject(0) { |c, line| c+1 }
|
83
|
+
# Words/IPs per thread
|
84
|
+
per = (count / threads) + 1
|
85
|
+
# Array of words/ips
|
86
|
+
arr = []
|
87
|
+
# Array of sets of words/ips per thread
|
88
|
+
lists_per_thread = []
|
89
|
+
|
90
|
+
thread_container = []
|
91
|
+
|
92
|
+
# Parse words/ips from word list
|
93
|
+
File.open(word_list).each_line do |x|
|
94
|
+
if method == CONSTANTS::RVL
|
95
|
+
tmp = Rex::Socket::RangeWalker.new(x.chomp.strip)
|
96
|
+
if tmp.valid?
|
97
|
+
tmp.each do |y|
|
98
|
+
arr << y
|
99
|
+
end
|
100
|
+
end
|
101
|
+
else
|
102
|
+
arr << x.chomp
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# If word list count is greater than 50, use multiple threads.
|
107
|
+
if arr.count > 50
|
108
|
+
arr.each_slice(per) { |a| lists_per_thread << a }
|
109
|
+
else
|
110
|
+
lists_per_thread = [arr]
|
111
|
+
end
|
112
|
+
|
113
|
+
# Iterate through sets of words.
|
114
|
+
lists_per_thread.each do |x|
|
115
|
+
# Create a new thread and add it to a container
|
116
|
+
thread_container << Thread.new {
|
117
|
+
# Check if RVL, else BRT or IPV
|
118
|
+
if method == CONSTANTS::RVL
|
119
|
+
# Iterate through IP addresses
|
120
|
+
ret = []
|
121
|
+
x.each do |y|
|
122
|
+
ret.concat(self.query(y, method))
|
123
|
+
end
|
124
|
+
else
|
125
|
+
# Send a single set of words to brute force
|
126
|
+
ret = self.query(domain, method, x)
|
127
|
+
end
|
128
|
+
# Grab thread output
|
129
|
+
Thread.current[:output] = ret
|
130
|
+
}
|
131
|
+
end
|
132
|
+
|
133
|
+
# Join all threads and grab their outputs
|
134
|
+
thread_container.each do |t|
|
135
|
+
t.join
|
136
|
+
results += t[:output] unless t[:output].empty?
|
137
|
+
end
|
138
|
+
|
139
|
+
# Process for Single Enumeration
|
140
|
+
else
|
141
|
+
results = self.query(domain, method)
|
142
|
+
end
|
143
|
+
|
144
|
+
# Write output to file if specified
|
145
|
+
if output
|
146
|
+
File.open(output, 'w') do |f|
|
147
|
+
f.write(JSON.pretty_generate(results))
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Return Results for Console output
|
152
|
+
results
|
153
|
+
end
|
154
|
+
|
155
|
+
###########################################################################
|
156
|
+
# @method run (options) #
|
157
|
+
# @param options: [Hash] DNS Enum Options #
|
158
|
+
# @description Main CLI Method. #
|
159
|
+
###########################################################################
|
160
|
+
def self.run(options)
|
161
|
+
type = 0
|
162
|
+
|
163
|
+
# RVL does not require a domain
|
164
|
+
unless options[:type] == 'rvl'
|
165
|
+
unless options[:domain]
|
166
|
+
puts 'Invalid command. Try --help to view options.'
|
167
|
+
exit
|
168
|
+
end
|
169
|
+
|
170
|
+
# remove http/https
|
171
|
+
options[:domain].gsub!('https://', '')
|
172
|
+
options[:domain].gsub!('http://', '')
|
173
|
+
|
174
|
+
# Validate Domain
|
175
|
+
unless options[:domain].match(/[a-zA-Z0-9\-]+\.[a-zA-z]{2,6}/)
|
176
|
+
puts 'Invalid domain.'
|
177
|
+
exit
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# Validate settings for brute force
|
182
|
+
if %w(ipv6 brt).include? options[:type]
|
183
|
+
if options[:threads] == nil or options[:domain] == nil or options[:wordlist] == nil
|
184
|
+
puts "Usage #{File.basename($0)} -e <brt|ipv6> -d <domain> -w <wordlist> -t <threads>"
|
185
|
+
exit
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# RVL requires threads and a word list
|
190
|
+
if options[:type] == 'rvl'
|
191
|
+
if options[:threads] == nil or options[:wordlist] == nil
|
192
|
+
puts "Usage #{File.basename($0)} -e rvl -w <wordlist of ips> -t <threads>"
|
193
|
+
exit
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# Validate wordlist
|
198
|
+
if options[:wordlist]
|
199
|
+
unless File.exist?(options[:wordlist])
|
200
|
+
puts 'Word List not found.'
|
201
|
+
exit
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# Validate threads
|
206
|
+
if options[:threads]
|
207
|
+
if options[:threads] > 100 or options[:threads] < 1
|
208
|
+
puts 'Thread count must be between 1 and 100'
|
209
|
+
exit
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# Validate Output
|
214
|
+
if options[:output]
|
215
|
+
unless Dir.exists?(File.dirname(options[:output]))
|
216
|
+
puts 'Output directory does not exists.'
|
217
|
+
exit
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# Convert string type to integer type
|
222
|
+
case options[:type]
|
223
|
+
when 'arin'
|
224
|
+
type = 1
|
225
|
+
when 'axfr'
|
226
|
+
type = 2
|
227
|
+
when 'brt'
|
228
|
+
type = 3
|
229
|
+
when 'ipv6'
|
230
|
+
type = 4
|
231
|
+
when 'rvl'
|
232
|
+
type = 5
|
233
|
+
when 'srv'
|
234
|
+
type = 6
|
235
|
+
when 'std'
|
236
|
+
type = 7
|
237
|
+
when 'tdl'
|
238
|
+
type = 8
|
239
|
+
else
|
240
|
+
puts 'Wrong enumeration type. Try --help to view accepted enumeration inputs.'
|
241
|
+
exit
|
242
|
+
end
|
243
|
+
|
244
|
+
# Start Enumeration
|
245
|
+
results = self.start(options[:domain], type, options[:threads], options[:wordlist])
|
246
|
+
|
247
|
+
# Save results to a file if specified
|
248
|
+
if options[:output]
|
249
|
+
File.open(options[:output], 'w') do |f|
|
250
|
+
f.write(JSON.pretty_generate(results))
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
# Print output to terminal unless silent
|
255
|
+
unless options[:silent]
|
256
|
+
puts 'Results:'
|
257
|
+
if type == 1
|
258
|
+
results.each do |x|
|
259
|
+
puts " Range: #{x[:cidr]}"
|
260
|
+
puts " Handle: #{x[:handle]}"
|
261
|
+
puts " Customer: #{x[:customer]}"
|
262
|
+
puts " Zip Code: #{x[:zip]}"
|
263
|
+
puts ''
|
264
|
+
end
|
265
|
+
else
|
266
|
+
results.each do |x|
|
267
|
+
puts " Hostname: #{x[:hostname]}"
|
268
|
+
puts " IP: #{x[:address]}"
|
269
|
+
puts " Type: #{x[:type]}"
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
# Return results as a hash
|
275
|
+
results
|
276
|
+
end
|
277
|
+
|
278
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'socket'
|
2
|
+
module Dert
|
3
|
+
class ARIN
|
4
|
+
|
5
|
+
def self.parse(data)
|
6
|
+
full_results = []
|
7
|
+
data.each do |line|
|
8
|
+
net_handle = line.match(/\(\s*(NET-\d{1,3}\-\d{1,3}\-\d{1,3}\-\d{1,3}\-\d{1,3})\s*\)/)
|
9
|
+
range = line.match(/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\s+\-\s+\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/)
|
10
|
+
if net_handle and range
|
11
|
+
customer_info = self.parse_net_handle(net_handle.to_s)
|
12
|
+
full_results.push(customer_info)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
return full_results
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.parse_net_handle(net_handle)
|
20
|
+
customer_record = {}
|
21
|
+
net_handle = net_handle.gsub('(', '')
|
22
|
+
net_handle = net_handle.gsub(')', '')
|
23
|
+
results = self.arin_results(net_handle)
|
24
|
+
results.each do |line|
|
25
|
+
ret = line.match(/(\w+):\s+(.*)\n/)
|
26
|
+
if ret
|
27
|
+
split = ret.to_s.split(':')
|
28
|
+
key = split[0].strip
|
29
|
+
value = split[1].strip
|
30
|
+
if key == 'CustName' or key == 'NetHandle' or key == 'CIDR' or key == 'PostalCode'
|
31
|
+
case key
|
32
|
+
when 'CustName'
|
33
|
+
key = :customer
|
34
|
+
when 'NetHandle'
|
35
|
+
key = :handle
|
36
|
+
when 'CIDR'
|
37
|
+
key = :cidr
|
38
|
+
when 'PostalCode'
|
39
|
+
key = :zip
|
40
|
+
end
|
41
|
+
customer_record[key] = value.to_s
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
return customer_record
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.arin_results(company)
|
50
|
+
client = TCPSocket.new('whois.arin.net', 43)
|
51
|
+
client.puts(company.to_s)
|
52
|
+
output = []
|
53
|
+
|
54
|
+
ret = client.gets
|
55
|
+
while ret != nil
|
56
|
+
output.push(ret)
|
57
|
+
ret = client.gets
|
58
|
+
end
|
59
|
+
client.close
|
60
|
+
|
61
|
+
output
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.query(domain)
|
65
|
+
company = domain.gsub(/\.\w+$/, '')
|
66
|
+
response = self.arin_results(company)
|
67
|
+
self.parse(response)
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module Dert
|
2
|
+
class AXFR
|
3
|
+
|
4
|
+
@res = Dnsruby::Resolver.new
|
5
|
+
|
6
|
+
def self.query(domain)
|
7
|
+
default_address = Resolv.getaddress(domain)
|
8
|
+
results = []
|
9
|
+
begin
|
10
|
+
ret = @res.query(domain, Dnsruby::Types.NS)
|
11
|
+
name_servers = []
|
12
|
+
ret.answer.each do |x|
|
13
|
+
name_servers << x.domainname.to_s
|
14
|
+
end
|
15
|
+
zt = Dnsruby::ZoneTransfer.new
|
16
|
+
zoneref = []
|
17
|
+
name_servers.each do |x|
|
18
|
+
begin
|
19
|
+
zt.server = x
|
20
|
+
zoneref = zt.transfer(domain)
|
21
|
+
break
|
22
|
+
rescue Dnsruby::ResolvError => e
|
23
|
+
#
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
zoneref.each do |x|
|
28
|
+
case x.type.to_s
|
29
|
+
when 'SOA'
|
30
|
+
results << {
|
31
|
+
address: default_address,
|
32
|
+
type: x.type.to_s,
|
33
|
+
hostname: x.name.to_s,
|
34
|
+
ttl: x.ttl.to_s,
|
35
|
+
klass: x.klass.to_s
|
36
|
+
}
|
37
|
+
when 'A'
|
38
|
+
results << {
|
39
|
+
address: x.address.to_s,
|
40
|
+
type: x.type.to_s,
|
41
|
+
hostname: x.name.to_s,
|
42
|
+
ttl: x.ttl.to_s,
|
43
|
+
klass: x.klass.to_s
|
44
|
+
}
|
45
|
+
when 'MX'
|
46
|
+
results << {
|
47
|
+
address: default_address,
|
48
|
+
type: x.type.to_s,
|
49
|
+
hostname: x.exchange.to_s,
|
50
|
+
ttl: x.ttl.to_s,
|
51
|
+
klass: x.klass.to_s,
|
52
|
+
preference: x.preference.to_s
|
53
|
+
}
|
54
|
+
when 'NS'
|
55
|
+
results << {
|
56
|
+
address: default_address,
|
57
|
+
type: x.type.to_s,
|
58
|
+
hostname: x.domainname.to_s,
|
59
|
+
ttl: x.ttl.to_s,
|
60
|
+
klass: x.klass.to_s
|
61
|
+
}
|
62
|
+
when 'TXT'
|
63
|
+
results << {
|
64
|
+
address: default_address,
|
65
|
+
type: x.type.to_s,
|
66
|
+
hostname: x.name.to_s,
|
67
|
+
ttl: x.ttl.to_s,
|
68
|
+
klass: x.klass.to_s
|
69
|
+
}
|
70
|
+
when 'CNAME'
|
71
|
+
results << {
|
72
|
+
address: default_address,
|
73
|
+
type: x.type.to_s,
|
74
|
+
hostname: x.name.to_s,
|
75
|
+
ttl: x.ttl.to_s,
|
76
|
+
klass: x.klass.to_s
|
77
|
+
}
|
78
|
+
when 'SRV'
|
79
|
+
results << {
|
80
|
+
address: default_address,
|
81
|
+
type: x.type.to_s,
|
82
|
+
hostname: x.name.to_s,
|
83
|
+
ttl: x.ttl.to_s,
|
84
|
+
klass: x.klass.to_s
|
85
|
+
}
|
86
|
+
when 'LOC'
|
87
|
+
results << {
|
88
|
+
address: default_address,
|
89
|
+
type: x.type.to_s,
|
90
|
+
hostname: x.name.to_s,
|
91
|
+
ttl: x.ttl.to_s,
|
92
|
+
klass: x.klass.to_s
|
93
|
+
}
|
94
|
+
else
|
95
|
+
#
|
96
|
+
end
|
97
|
+
end
|
98
|
+
rescue => e
|
99
|
+
#
|
100
|
+
end
|
101
|
+
|
102
|
+
results
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|