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