-
Notifications
You must be signed in to change notification settings - Fork 4
/
rsdns.rb
executable file
·268 lines (234 loc) · 7.04 KB
/
rsdns.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
#!/usr/bin/env ruby
#DNS enumeration tool for reports
require 'optimist'
require 'colorize'
require 'resolv'
require 'tty-command'
require 'logger'
require 'threadify'
require 'securerandom'
require 'csv'
class Rsdns
attr_reader :domains, :mxrecords, :nsrecords, :resolved
attr_reader :axfr_print, :axfr_file, :time
def initialize
@domains = []
@mxrecords = []
@nsrecords = []
@resolved = []
@full = []
@axfr = []
@axfr_dom = []
@axfr_print = []
@log = Logger.new('debug.log')
@cmd = TTY::Command.new(output: @log)
@time = Time.now.strftime("%d%b%Y_%H%M%S")
@axfr_file = "axfr_#{@time}.txt"
@wildcard = SecureRandom.hex
@ignoreip = []
end
def arguments
@@opts = Optimist::options do
version "rsdns 1.01b".light_blue
banner <<-EOS
BANNER GOES HERE
EOS
opt :domain, "Choose a specific domain to enumerate", :type => String
opt :domains, "List of all domains to enumerate", :type => String
opt :subdomains, "subs", :type => String
opt :dns_server, "Choose your own DNS server", :default => "8.8.8.8"
opt :axfr, "Enable Zone Transfer Checking For All Domains"
if ARGV.empty?
puts "Need Help? Try ./rsdns --help or -h"
exit
end
end
end
def domain
if @@opts[:domain]
@domains << @@opts[:domain].chomp
end
end
def domainlist
if @@opts[:domains]
domain_list = File.readlines(@@opts[:domains]).map(&:chomp &&:strip)
domain_list.each do |domain|
@domains << domain.chomp #this chomp statement should be removed
end
end
end
def mx
@domains.each do |d|
Resolv::DNS.open do |dns|
mx = dns.getresources d, Resolv::DNS::Resource::IN::MX
mx.map! { |m| [m.exchange.to_s, IPSocket::getaddress(m.exchange.to_s)] } rescue mx.map! { |m| [d, "NO MX RECORD FOR DOMAIN"] }
mx.each { |m| @mxrecords << m }
end
end
end
def ns
@domains.each do |domain|
Resolv::DNS.open do |dns|
ns = dns.getresources domain, Resolv::DNS::Resource::IN::NS
ns.map! { |m| [m.name.to_s, IPSocket::getaddress(m.name.to_s)] } rescue ns.map! { |m| "" }
ns.each { |n| @axfr_dom << [n[0], n[1], domain] }
end
end
end
def remove_domain
@axfr_dom.each { |a| @nsrecords << [a[0], a[1]] }
end
def wildcard_test
if @@opts[:subdomains]
resolver = Resolv::DNS.new(:nameserver => [@@opts[:dns_server], '8.8.4.4'])
@domains.each do |domain|
canary = "#{@wildcard}.#{domain}"
resolver.each_address(canary) { |addr| @ignoreip << addr if !addr.nil?; puts "\n#{domain} has a wildcard DNS entry, ignoring ip #{addr}".green.bold } rescue ""
end
end
end
def createsubs
if @@opts[:subdomains]
subs = File.readlines(@@opts[:subdomains]).map(&:chomp &&:strip).sort
subs.each do |sub|
@domains.each do |domain|
@full << "#{sub}.#{domain}"
end
end
end
end
def subdomains
if @@opts[:subdomains]
puts "\nSubdomain enumeration beginning at #{Time.now.strftime("%H:%M:%S")}".green.bold
resolver = Resolv::DNS.new(:nameserver => [@@opts[:dns_server], '8.8.4.4'])
@full.threadify do |name|
resolver.each_address(name) { |addr| puts "#{name}\t#{addr}" if !addr.nil? && !@ignoreip.include?(addr) ; @resolved << [name, addr] if !addr.nil? && !@ignoreip.include?(addr)} rescue [name, "NO SUBS DISCOVERED"]
end
puts "Finished subdomain enumeration at #{Time.now.strftime("%H:%M:%S")}".green.bold
end
end
def axfr
if @@opts[:axfr]
@axfr_dom.each do |dom|
out, err = @cmd.run!("dig axfr @#{dom[1]} #{dom[2]}")
if out =~ /Transfer failed|communications error to/i
@axfr_print << "Zone transfer failed on server: #{dom[1]}/#{dom[0]} for domain #{dom[2]}".upcase.white.on_green
elsif out =~ /XFR size/i
@axfr_print << "Zone transfer successful on server: #{dom[1]}/#{dom[0]} for domain #{dom[2]}".upcase.white.on_red
File.open("#{@axfr_file}", 'a+') { |f| f.puts out }
else
@axfr_print << "Unknown response on server: #{dom[1]}/#{dom[0]} for domain #{dom[2]} - Check debug.log".upcase.white.on_green
end
end
end
end
end
class Printer
def initialize(run)
@run = run
end
def printns
if !@run.nsrecords.empty?
puts "\nNS Records".blue.bold
splitns = @run.nsrecords.each_slice(2).to_a
splitns = splitns.uniq { |n| n[0] }
splitns.each do |n|
puts n
puts "#{n[0].join("\t")}\t\t#{n[1].join("\t")}" rescue puts n.join("\t")
end
else puts "\nNo Name Servers Found".red
end
end
def printdom
if @run.domains
puts "\nDomain Names".blue.bold
splitnames = @run.domains.each_slice(4).to_a
splitnames.each do |z|
puts z.join("\t\t") rescue puts z
end
end
end
def printmx
if !@run.mxrecords.empty?
puts "\nMX Records".blue.bold
splitmx = @run.mxrecords.each_slice(2).to_a
splitmx = splitmx.uniq { |m| m[0] }
splitmx.each do |m|
puts "#{m[0].join("\t")}\t\t#{m[1].join("\t")}" rescue puts m.join("\t")
end
else puts "\nNo MX Records Found".red
end
end
def printsubs
if @run.resolved and !@run.resolved.empty?
puts "\nSub-domains".blue.bold
splitsub = @run.resolved.each_slice(2).to_a
splitsub.each do |s|
puts "#{s[0].join("\t")}\t\t#{s[1].join("\t")}" rescue puts s.join("\t")
end
else puts "\nNo Subdomains Found/Searched For".red
end
end
def printaxfr
if !@run.axfr_print.empty?
puts "\nZone Transfers".blue.bold
puts @run.axfr_print
if File.exist?(@run.axfr_file)
puts "Full transfer output written to axfr_#{@run.time}.txt".upcase.white.on_blue
end
end
end
def create_file
Dir.mkdir("#{Dir.home}/Documents/rsdns_out/") unless File.exists?("#{Dir.home}/Documents/rsdns_out/")
@file = "rsdns_#{Time.now.strftime("%d%b%Y_%H%M%S")}"
@csvfile = File.new("#{Dir.home}/Documents/rsdns_out/#{@file}.csv", 'w+')
puts "Output written to #{@csvfile.path}".light_blue.bold
end
def output_data
CSV.open(@csvfile, 'w+') do |csv|
if @run.domains
csv << ["DOMAINS"]
@run.domains.each do |domain|
csv << [domain]
end
end
if !@run.nsrecords.empty?
csv << ["\nNAME SERVERS"]
@run.nsrecords.each do |ns|
csv << ns
end
end
if !@run.mxrecords.empty?
csv << ["\nMX RECORDS"]
@run.mxrecords.each do |mx|
csv << mx
end
end
if @run.resolved and !@run.resolved.empty?
csv << ["\nSUBDOMAINS"]
@run.resolved.each do |subs|
csv << subs
end
end
end
end
end
run = Rsdns.new
run.arguments
run.domain
run.domainlist
run.mx
run.ns
run.remove_domain
run.wildcard_test
run.createsubs
run.subdomains
run.axfr
printme = Printer.new(run)
printme.printdom
printme.printns
printme.printmx
printme.printsubs
printme.printaxfr
printme.create_file
printme.output_data