CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/scanner/dns/dns_amp.rb
Views: 1904
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Auxiliary
7
include Msf::Auxiliary::Report
8
include Msf::Exploit::Capture
9
include Msf::Auxiliary::UDPScanner
10
include Msf::Auxiliary::DRDoS
11
12
def initialize
13
super(
14
'Name' => 'DNS Amplification Scanner',
15
'Description' => %q{
16
This module can be used to discover DNS servers which expose recursive
17
name lookups which can be used in an amplification attack against a
18
third party.
19
},
20
'Author' => [ 'xistence <xistence[at]0x90.nl>'], # Original scanner module
21
'License' => MSF_LICENSE,
22
'References' =>
23
[
24
['CVE', '2006-0987'],
25
['CVE', '2006-0988'],
26
]
27
)
28
29
register_options( [
30
Opt::RPORT(53),
31
OptString.new('DOMAINNAME', [true, 'Domain to use for the DNS request', 'isc.org' ]),
32
OptString.new('QUERYTYPE', [true, 'Query type(A, NS, SOA, MX, TXT, AAAA, RRSIG, DNSKEY, ANY)', 'ANY' ]),
33
])
34
end
35
36
def rport
37
datastore['RPORT']
38
end
39
40
def setup
41
super
42
43
# Check for DNS query types byte
44
case datastore['QUERYTYPE']
45
when 'A'
46
querypacket="\x01"
47
when 'NS'
48
querypacket="\x02"
49
when 'SOA'
50
querypacket="\x06"
51
when 'MX'
52
querypacket="\x0f"
53
when 'TXT'
54
querypacket="\x10"
55
when 'AAAA'
56
querypacket="\x1c"
57
when 'RRSIG'
58
querypacket="\x2e"
59
when 'DNSKEY'
60
querypacket="\x30"
61
when 'ANY'
62
querypacket="\xff"
63
else
64
print_error("Invalid query type!")
65
return
66
end
67
68
targdomainpacket = []
69
# Before every part of the domainname there should be the length of that part (instead of a ".")
70
# So isc.org divided is 3isc3org
71
datastore['DOMAINNAME'].split('.').each do |domainpart|
72
# The length of the domain part in hex
73
domainpartlength = "%02x" % domainpart.length
74
# Convert the name part to a hex string
75
domainpart = domainpart.each_byte.map { |b| b.to_s(16) }.join()
76
# Combine the length of the name part and the name part
77
targdomainpacket.push(domainpartlength + domainpart)
78
end
79
# Convert the targdomainpacket to a string
80
targdomainpacket = targdomainpacket.join.to_s
81
# Create a correct hex character string to be used in the packet
82
targdomainpacket = targdomainpacket.scan(/../).map { |x| x.hex.chr }.join
83
# DNS Packet including our target domain and query type
84
@msearch_probe = "\x09\x8d\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00" + targdomainpacket + "\x00\x00" + querypacket + "\x00\x01"
85
end
86
87
def scanner_prescan(batch)
88
print_status("Sending DNS probes to #{batch[0]}->#{batch[-1]} (#{batch.length} hosts)")
89
# Standard packet is 60 bytes. Add the domain size to this
90
sendpacketsize = 60 + datastore['DOMAINNAME'].length
91
print_status("Sending #{sendpacketsize} bytes to each host using the IN #{datastore['QUERYTYPE']} #{datastore['DOMAINNAME']} request")
92
@results = {}
93
end
94
95
def scan_host(ip)
96
if spoofed?
97
datastore['ScannerRecvWindow'] = 0
98
scanner_spoof_send(@msearch_probe, ip, datastore['RPORT'], datastore['SRCIP'], datastore['NUM_REQUESTS'])
99
else
100
scanner_send(@msearch_probe, ip, datastore['RPORT'])
101
end
102
end
103
104
def scanner_process(data, shost, sport)
105
106
# Check the response data for \x09\x8d and the next 2 bytes, which contain our DNS flags
107
if data =~/\x09\x8d(..)/
108
flags = $1
109
flags = flags.unpack('B*')[0].scan(/./)
110
# Query Response
111
qr = flags[0]
112
# Recursion Available
113
ra = flags[8]
114
# Response Code
115
rcode = flags[12] + flags[13] + flags[14] + flags[15]
116
117
# If these flags are set, we get a valid response
118
# don't test recursion available if correct answer received
119
# at least the case with bind and "additional-from-cache no" or version < 9.5+
120
if qr == "1" and rcode == "0000"
121
sendlength = 60 + datastore['DOMAINNAME'].length
122
receivelength = 42 + data.length
123
amp = receivelength / sendlength.to_f
124
print_good("#{shost}:#{datastore['RPORT']} - Response is #{receivelength} bytes [#{amp.round(2)}x Amplification]")
125
report_service(:host => shost, :port => datastore['RPORT'], :proto => 'udp', :name => "dns")
126
report_vuln(
127
:host => shost,
128
:port => datastore['RPORT'],
129
:proto => 'udp', :name => "DNS",
130
:info => "DNS amplification - #{data.length} bytes [#{amp.round(2)}x Amplification]",
131
:refs => self.references)
132
end
133
134
# If these flags are set, we get a valid response but recursion is not available
135
if qr == "1" and ra == "0" and rcode == "0101"
136
print_status("#{shost}:#{datastore['RPORT']} - Recursion not allowed")
137
report_service(:host => shost, :port => datastore['RPORT'], :proto => 'udp', :name => "dns")
138
end
139
end
140
end
141
end
142
143