Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/scanner/discovery/ipv6_neighbor.rb
19500 views
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::Exploit::Remote::Ipv6
8
include Msf::Exploit::Remote::Capture
9
include Msf::Auxiliary::Report
10
include Msf::Auxiliary::Scanner
11
12
def initialize
13
super(
14
'Name' => 'IPv6 Local Neighbor Discovery',
15
'Description' => %q{
16
Enumerate local IPv6 hosts which respond to Neighbor Solicitations with a link-local address.
17
Note, that like ARP scanning, this usually cannot be performed beyond the local
18
broadcast network.
19
},
20
'Author' => 'belch',
21
'License' => MSF_LICENSE,
22
'Notes' => {
23
'Stability' => [CRASH_SAFE],
24
'SideEffects' => [],
25
'Reliability' => []
26
}
27
)
28
29
register_options(
30
[
31
OptString.new('SHOST', [false, 'Source IP Address']),
32
OptString.new('SMAC', [false, 'Source MAC Address']),
33
OptInt.new('TIMEOUT', [true, 'The number of seconds to wait for new data', 5]),
34
]
35
)
36
37
deregister_options('SNAPLEN', 'FILTER')
38
end
39
40
def run_batch_size
41
datastore['BATCHSIZE'] || 256
42
end
43
44
def run_batch(hosts)
45
open_pcap({ 'SNAPLEN' => 68, 'FILTER' => 'arp[6:2] == 0x0002' })
46
47
@netifaces = true
48
if !netifaces_implemented?
49
print_error('WARNING : Pcaprub is not up-to-date, some functionality will not be available')
50
@netifaces = false
51
end
52
53
print_status('Discovering IPv4 nodes via ARP...')
54
55
@interface = datastore['INTERFACE'] || Pcap.lookupdev
56
@shost = datastore['SHOST']
57
@shost ||= get_ipv4_addr(@interface) if @netifaces
58
raise 'SHOST should be defined' unless @shost
59
60
@smac = datastore['SMAC']
61
@smac ||= get_mac(@interface) if @netifaces
62
raise 'SMAC should be defined' unless @smac
63
64
addrs = []
65
66
begin
67
found = {}
68
hosts.each do |dhost|
69
probe = buildprobe(@shost, @smac, dhost)
70
capture.inject(probe)
71
while (reply = getreply)
72
next unless reply.is_arp?
73
74
next if found[reply.arp_saddr_ip]
75
76
print_good(sprintf(' %16s ALIVE', reply.arp_saddr_ip))
77
addrs << [reply.arp_saddr_ip, reply.arp_saddr_mac]
78
report_host(host: reply.arp_saddr_ip, mac: reply.arp_saddr_mac)
79
found[reply.arp_saddr_ip] = true
80
end
81
end
82
83
etime = ::Time.now.to_f + datastore['TIMEOUT']
84
85
while (::Time.now.to_f < etime)
86
while (reply = getreply)
87
next unless reply.is_arp?
88
89
next if found[reply.arp_saddr_ip]
90
91
print_good(sprintf(' %16s ALIVE', reply.arp_saddr_ip))
92
addrs << [reply.arp_saddr_ip, reply.arp_saddr_mac]
93
report_host(host: reply.arp_saddr_ip, mac: reply.arp_saddr_mac)
94
found[reply.arp_saddr_ip] = true
95
end
96
97
::IO.select(nil, nil, nil, 0.50)
98
end
99
ensure
100
close_pcap
101
end
102
103
neighbor_discovery(addrs)
104
end
105
106
def map_neighbor(nodes, adv)
107
nodes.each do |node|
108
ipv4_addr, mac_addr = node
109
next unless adv.eth_saddr == mac_addr
110
111
ipv6_addr = adv.ipv6_saddr
112
return { eth: mac_addr, ipv4: ipv4_addr, ipv6: ipv6_addr }
113
end
114
nil
115
end
116
117
def neighbor_discovery(neighs)
118
print_status('Discovering IPv6 addresses for IPv4 nodes...')
119
print_status('')
120
121
smac = @smac
122
open_pcap({ 'SNAPLEN' => 68, 'FILTER' => 'icmp6' })
123
124
begin
125
neighs.each do |neigh|
126
_, dmac = neigh
127
128
shost = ipv6_linklocaladdr(smac)
129
neigh = ipv6_linklocaladdr(dmac)
130
131
probe = buildsolicitation(smac, shost, neigh)
132
133
capture.inject(probe)
134
Kernel.select(nil, nil, nil, 0.1)
135
136
while (adv = getadvertisement)
137
next unless adv.is_ipv6?
138
139
addr = map_neighbor(neighs, adv)
140
next if !addr
141
142
print_status(format(' %<ipv4>16s maps to %<ipv6>s', ipv4: addr[:ipv4], ipv6: addr[:ipv6]))
143
report_note(
144
host: addr[:ipv4],
145
type: 'host.ipv4.ipv6.mapping',
146
data: {
147
ipv4_address: addr[:ipv4],
148
ipv6_address: addr[:ipv6],
149
matches: 'true'
150
}
151
) # with this we have the results in our database
152
153
end
154
end
155
156
etime = ::Time.now.to_f + (neighs.length * 0.5)
157
158
while (::Time.now.to_f < etime)
159
while (adv = getadvertisement)
160
next if !adv
161
162
addr = map_neighbor(neighs, adv)
163
next if !addr
164
165
print_status(format(' %<ipv4>16s maps to %<ipv6>s', ipv4: addr[:ipv4], ipv6: addr[:ipv6]))
166
end
167
::IO.select(nil, nil, nil, 0.50)
168
end
169
ensure
170
close_pcap
171
end
172
end
173
174
def buildprobe(shost, smac, dhost)
175
p = PacketFu::ARPPacket.new
176
p.eth_saddr = smac
177
p.eth_daddr = 'ff:ff:ff:ff:ff:ff'
178
p.arp_opcode = 1
179
p.arp_saddr_mac = p.eth_saddr
180
p.arp_daddr_mac = p.eth_daddr
181
p.arp_saddr_ip = shost
182
p.arp_daddr_ip = dhost
183
p.to_s
184
end
185
186
def getreply
187
pkt = capture.next
188
Kernel.select(nil, nil, nil, 0.1)
189
return if !pkt
190
191
p = PacketFu::Packet.parse(pkt)
192
return unless p.is_arp?
193
return unless p.arp_opcode == 2
194
195
p
196
end
197
198
def buildsolicitation(smac, shost, neigh)
199
dmac = ipv6_soll_mcast_mac(neigh)
200
dhost = ipv6_soll_mcast_addr6(neigh)
201
202
p = PacketFu::IPv6Packet.new
203
p.eth_saddr = smac
204
p.eth_daddr = dmac
205
p.ipv6_saddr = shost
206
p.ipv6_daddr = dhost
207
p.ipv6_next = 0x3a
208
p.ipv6_hop = 255
209
p.payload = ipv6_neighbor_solicitation(
210
IPAddr.new(neigh).to_i,
211
p.eth_src
212
)
213
p.ipv6_len = p.payload.size
214
ipv6_checksum!(p)
215
p.to_s
216
end
217
218
def getadvertisement
219
pkt = capture.next
220
Kernel.select(nil, nil, nil, 0.1)
221
return if !pkt
222
223
p = PacketFu::Packet.parse(pkt)
224
return unless p.is_ipv6?
225
return unless p.ipv6_next == 0x3a
226
return unless p.icmpv6_type == 136 && p.icmpv6_code == 0
227
228
p
229
end
230
end
231
232