dert 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dert.gemspec
4
+ gemspec
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
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
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