mirror of https://github.com/Kkevsterrr/geneva
Reorganized layers into new directory.
This commit is contained in:
parent
b27ea50522
commit
0796312589
|
@ -1,6 +1,6 @@
|
||||||
import random
|
import random
|
||||||
from actions.action import Action
|
from actions.action import Action
|
||||||
import actions.packet
|
import layers.packet
|
||||||
|
|
||||||
from scapy.all import IP, TCP, fragment
|
from scapy.all import IP, TCP, fragment
|
||||||
|
|
||||||
|
@ -88,8 +88,8 @@ class FragmentAction(Action):
|
||||||
else:
|
else:
|
||||||
# packet can be fragmented as requested
|
# packet can be fragmented as requested
|
||||||
frags = self.fragment(packet.copy().packet, fragsize=self.fragsize*8)
|
frags = self.fragment(packet.copy().packet, fragsize=self.fragsize*8)
|
||||||
packet1 = actions.packet.Packet(frags[0])
|
packet1 = layers.packet.Packet(frags[0])
|
||||||
packet2 = actions.packet.Packet(frags[1])
|
packet2 = layers.packet.Packet(frags[1])
|
||||||
if self.correct_order:
|
if self.correct_order:
|
||||||
return packet1, packet2
|
return packet1, packet2
|
||||||
else:
|
else:
|
||||||
|
@ -132,8 +132,8 @@ class FragmentAction(Action):
|
||||||
if not pkt2.haslayer("TCP"):
|
if not pkt2.haslayer("TCP"):
|
||||||
pkt2 = IP(packet["IP"])/TCP(bytes(pkt2["IP"].load))
|
pkt2 = IP(packet["IP"])/TCP(bytes(pkt2["IP"].load))
|
||||||
|
|
||||||
packet1 = actions.packet.Packet(pkt1)
|
packet1 = layers.packet.Packet(pkt1)
|
||||||
packet2 = actions.packet.Packet(pkt2)
|
packet2 = layers.packet.Packet(pkt2)
|
||||||
|
|
||||||
# Reset packet2's SYN number
|
# Reset packet2's SYN number
|
||||||
if packet2["TCP"].seq + fragsize > MAX_UINT:
|
if packet2["TCP"].seq + fragsize > MAX_UINT:
|
||||||
|
|
854
actions/layer.py
854
actions/layer.py
|
@ -1,854 +0,0 @@
|
||||||
import binascii
|
|
||||||
import copy
|
|
||||||
import random
|
|
||||||
import string
|
|
||||||
import os
|
|
||||||
import urllib.parse
|
|
||||||
|
|
||||||
from scapy.all import IP, RandIP, UDP, DNS, DNSQR, Raw, TCP, fuzz
|
|
||||||
|
|
||||||
class Layer():
|
|
||||||
"""
|
|
||||||
Base class defining a Geneva packet layer.
|
|
||||||
"""
|
|
||||||
protocol = None
|
|
||||||
|
|
||||||
def __init__(self, layer):
|
|
||||||
"""
|
|
||||||
Initializes this layer.
|
|
||||||
"""
|
|
||||||
self.layer = layer
|
|
||||||
# No custom setter, getters, generators, or parsers are needed by default
|
|
||||||
self.setters = {}
|
|
||||||
self.getters = {}
|
|
||||||
self.generators = {}
|
|
||||||
self.parsers = {}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def reset_restrictions(cls):
|
|
||||||
"""
|
|
||||||
Resets field restrictions placed on this layer.
|
|
||||||
"""
|
|
||||||
cls.fields = cls._fields
|
|
||||||
|
|
||||||
def get_next_layer(self):
|
|
||||||
"""
|
|
||||||
Given the current layer returns the next layer beneath us.
|
|
||||||
"""
|
|
||||||
if len(self.layer.layers()) == 1:
|
|
||||||
return None
|
|
||||||
|
|
||||||
return self.layer[1]
|
|
||||||
|
|
||||||
def get_random(self):
|
|
||||||
"""
|
|
||||||
Retreives a random field and value.
|
|
||||||
"""
|
|
||||||
field = random.choice(self.fields)
|
|
||||||
return field, self.get(field)
|
|
||||||
|
|
||||||
def gen_random(self):
|
|
||||||
"""
|
|
||||||
Generates a random field and value.
|
|
||||||
"""
|
|
||||||
assert self.fields, "Layer %s doesn't have any fields" % str(self)
|
|
||||||
field = random.choice(self.fields)
|
|
||||||
return field, self.gen(field)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def name_matches(cls, name):
|
|
||||||
"""
|
|
||||||
Checks if given name matches this layer name.
|
|
||||||
"""
|
|
||||||
return name.upper() == cls.name.upper()
|
|
||||||
|
|
||||||
def get(self, field):
|
|
||||||
"""
|
|
||||||
Retrieves the value from a given field.
|
|
||||||
"""
|
|
||||||
assert field in self.fields
|
|
||||||
if field in self.getters:
|
|
||||||
return self.getters[field](field)
|
|
||||||
|
|
||||||
# Dual field accessors are fields that require two pieces of information
|
|
||||||
# to retrieve them (for example, "options-eol"). These are delimited by
|
|
||||||
# a dash "-".
|
|
||||||
base = field.split("-")[0]
|
|
||||||
if "-" in field and base in self.getters:
|
|
||||||
return self.getters[base](field)
|
|
||||||
|
|
||||||
return getattr(self.layer, field)
|
|
||||||
|
|
||||||
def set(self, packet, field, value):
|
|
||||||
"""
|
|
||||||
Sets the value for a given field.
|
|
||||||
"""
|
|
||||||
assert field in self.fields
|
|
||||||
base = field.split("-")[0]
|
|
||||||
if field in self.setters:
|
|
||||||
self.setters[field](packet, field, value)
|
|
||||||
|
|
||||||
# Dual field accessors are fields that require two pieces of information
|
|
||||||
# to retrieve them (for example, "options-eol"). These are delimited by
|
|
||||||
# a dash "-".
|
|
||||||
elif "-" in field and base in self.setters:
|
|
||||||
self.setters[base](packet, field, value)
|
|
||||||
else:
|
|
||||||
setattr(self.layer, field, value)
|
|
||||||
|
|
||||||
# Request the packet be reparsed to confirm the value is stable
|
|
||||||
# XXX Temporarily disabling the reconstitution check due to scapy bug (#2034)
|
|
||||||
#assert bytes(self.protocol(bytes(self.layer))) == bytes(self.layer)
|
|
||||||
|
|
||||||
def gen(self, field):
|
|
||||||
"""
|
|
||||||
Generates a value for this field.
|
|
||||||
"""
|
|
||||||
assert field in self.fields
|
|
||||||
if field in self.generators:
|
|
||||||
return self.generators[field](field)
|
|
||||||
|
|
||||||
# Dual field accessors are fields that require two pieces of information
|
|
||||||
# to retrieve them (for example, "options-eol"). These are delimited by
|
|
||||||
# a dash "-".
|
|
||||||
base = field.split("-")[0]
|
|
||||||
if "-" in field and base in self.generators:
|
|
||||||
return self.generators[base](field)
|
|
||||||
|
|
||||||
sample = fuzz(self.protocol())
|
|
||||||
|
|
||||||
new_value = getattr(sample, field)
|
|
||||||
if new_value == None:
|
|
||||||
new_value = 0
|
|
||||||
elif type(new_value) != int:
|
|
||||||
new_value = new_value._fix()
|
|
||||||
|
|
||||||
return new_value
|
|
||||||
|
|
||||||
def parse(self, field, value):
|
|
||||||
"""
|
|
||||||
Parses the given value for a given field. This is useful for fields whose
|
|
||||||
value cannot be represented in a string type easily - it lets us define
|
|
||||||
a common string representation for the strategy, and parse it back into
|
|
||||||
a real value here.
|
|
||||||
"""
|
|
||||||
assert field in self.fields
|
|
||||||
if field in self.parsers:
|
|
||||||
return self.parsers[field](field, value)
|
|
||||||
|
|
||||||
# Dual field accessors are fields that require two pieces of information
|
|
||||||
# to retrieve them (for example, "options-eol"). These are delimited by
|
|
||||||
# a dash "-".
|
|
||||||
base = field.split("-")[0]
|
|
||||||
if "-" in field and base in self.parsers:
|
|
||||||
return self.parsers[base](field, value)
|
|
||||||
|
|
||||||
try:
|
|
||||||
parsed = int(value)
|
|
||||||
except ValueError:
|
|
||||||
parsed = value
|
|
||||||
|
|
||||||
return parsed
|
|
||||||
|
|
||||||
def get_load(self, field):
|
|
||||||
"""
|
|
||||||
Helper method to retrieve load, as scapy doesn't recognize 'load' as
|
|
||||||
a regular field properly.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
load = self.layer.payload.load
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
load = self.layer.load
|
|
||||||
except AttributeError:
|
|
||||||
return ""
|
|
||||||
|
|
||||||
if not load:
|
|
||||||
return ""
|
|
||||||
|
|
||||||
return urllib.parse.quote(load.decode('utf-8', 'ignore'))
|
|
||||||
|
|
||||||
def set_load(self, packet, field, value):
|
|
||||||
"""
|
|
||||||
Helper method to retrieve load, as scapy doesn't recognize 'load' as
|
|
||||||
a field properly.
|
|
||||||
"""
|
|
||||||
if packet.haslayer("IP"):
|
|
||||||
del packet["IP"].len
|
|
||||||
|
|
||||||
value = urllib.parse.unquote(value)
|
|
||||||
|
|
||||||
value = value.encode('utf-8')
|
|
||||||
dns_payload = b"\x009ib\x81\x80\x00\x01\x00\x01\x00\x00\x00\x01\x08faceface\x03com\x00\x00\x01\x00\x01\xc0\x0c\x00\x01\x00\x01\x00\x00\x01+\x00\x04\xc7\xbf2I\x00\x00)\x02\x00\x00\x00\x00\x00\x00\x00"
|
|
||||||
http_payload = b"GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n"
|
|
||||||
|
|
||||||
value = value.replace(b"__DNS_REQUEST__", dns_payload)
|
|
||||||
value = value.replace(b"__HTTP_REQUEST__", http_payload)
|
|
||||||
|
|
||||||
self.layer.payload = Raw(value)
|
|
||||||
|
|
||||||
def gen_load(self, field):
|
|
||||||
"""
|
|
||||||
Helper method to generate a random load, as scapy doesn't recognize 'load'
|
|
||||||
as a field properly.
|
|
||||||
"""
|
|
||||||
load = ''.join([random.choice(string.ascii_lowercase + string.digits) for k in range(10)])
|
|
||||||
return random.choice(["", "__DNS_REQUEST__", "__HTTP_REQUEST__", urllib.parse.quote(load)])
|
|
||||||
|
|
||||||
|
|
||||||
class RawLayer(Layer):
|
|
||||||
"""
|
|
||||||
Defines an interface for the scapy Raw layer.
|
|
||||||
"""
|
|
||||||
name = "Raw"
|
|
||||||
protocol = Raw
|
|
||||||
_fields = []
|
|
||||||
fields = []
|
|
||||||
|
|
||||||
|
|
||||||
class IPLayer(Layer):
|
|
||||||
"""
|
|
||||||
Defines an interface to access IP header fields.
|
|
||||||
"""
|
|
||||||
name = "IP"
|
|
||||||
protocol = IP
|
|
||||||
_fields = [
|
|
||||||
'version',
|
|
||||||
'ihl',
|
|
||||||
'tos',
|
|
||||||
'len',
|
|
||||||
'id',
|
|
||||||
'flags',
|
|
||||||
'frag',
|
|
||||||
'ttl',
|
|
||||||
'proto',
|
|
||||||
'chksum',
|
|
||||||
'src',
|
|
||||||
'dst',
|
|
||||||
'load'
|
|
||||||
]
|
|
||||||
fields = _fields
|
|
||||||
|
|
||||||
def __init__(self, layer):
|
|
||||||
"""
|
|
||||||
Initializes the IP layer.
|
|
||||||
"""
|
|
||||||
Layer.__init__(self, layer)
|
|
||||||
self.getters = {
|
|
||||||
"flags" : self.get_flags,
|
|
||||||
"load" : self.get_load
|
|
||||||
}
|
|
||||||
self.setters = {
|
|
||||||
"flags" : self.set_flags,
|
|
||||||
"load" : self.set_load
|
|
||||||
}
|
|
||||||
self.generators = {
|
|
||||||
"src" : self.gen_ip,
|
|
||||||
"dst" : self.gen_ip,
|
|
||||||
"chksum" : self.gen_chksum,
|
|
||||||
"len" : self.gen_len,
|
|
||||||
"load" : self.gen_load,
|
|
||||||
"flags" : self.gen_flags
|
|
||||||
}
|
|
||||||
|
|
||||||
def gen_len(self, field):
|
|
||||||
"""
|
|
||||||
Generates a valid IP length. Scapy breaks if the length is set to 0, so
|
|
||||||
return a random int starting at 1.
|
|
||||||
"""
|
|
||||||
return random.randint(1, 500)
|
|
||||||
|
|
||||||
def gen_chksum(self, field):
|
|
||||||
"""
|
|
||||||
Generates a checksum.
|
|
||||||
"""
|
|
||||||
return random.randint(1, 65535)
|
|
||||||
|
|
||||||
def gen_ip(self, field):
|
|
||||||
"""
|
|
||||||
Generates an IP address.
|
|
||||||
"""
|
|
||||||
return RandIP()._fix()
|
|
||||||
|
|
||||||
def get_flags(self, field):
|
|
||||||
"""
|
|
||||||
Retrieves flags as a string.
|
|
||||||
"""
|
|
||||||
return str(self.layer.flags)
|
|
||||||
|
|
||||||
def set_flags(self, packet, field, value):
|
|
||||||
"""
|
|
||||||
Sets the flags field. There is a bug in scapy, if you retrieve an empty
|
|
||||||
flags field, it will return "", but you cannot set this value back.
|
|
||||||
To reproduce this bug:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
>>> setattr(IP(), "flags", str(IP().flags)) # raises a ValueError
|
|
||||||
|
|
||||||
To handle this case, this method converts empty string to zero so that
|
|
||||||
it can be safely stored.
|
|
||||||
"""
|
|
||||||
if value == "":
|
|
||||||
value = 0
|
|
||||||
self.layer.flags = value
|
|
||||||
|
|
||||||
def gen_flags(self, field):
|
|
||||||
"""
|
|
||||||
Generates random valid flags.
|
|
||||||
"""
|
|
||||||
sample = fuzz(self.protocol())
|
|
||||||
|
|
||||||
# Since scapy lazily evaluates fuzzing, we first must set a
|
|
||||||
# legitimate value for scapy to evaluate what combination of flags it is
|
|
||||||
sample.flags = sample.flags
|
|
||||||
|
|
||||||
return str(sample.flags)
|
|
||||||
|
|
||||||
|
|
||||||
class TCPLayer(Layer):
|
|
||||||
"""
|
|
||||||
Defines an interface to access TCP header fields.
|
|
||||||
"""
|
|
||||||
name = "TCP"
|
|
||||||
protocol = TCP
|
|
||||||
_fields = [
|
|
||||||
'sport',
|
|
||||||
'dport',
|
|
||||||
'seq',
|
|
||||||
'ack',
|
|
||||||
'dataofs',
|
|
||||||
'reserved',
|
|
||||||
'flags',
|
|
||||||
'window',
|
|
||||||
'chksum',
|
|
||||||
'urgptr',
|
|
||||||
'load',
|
|
||||||
'options-eol',
|
|
||||||
'options-nop',
|
|
||||||
'options-mss',
|
|
||||||
'options-wscale',
|
|
||||||
'options-sackok',
|
|
||||||
'options-sack',
|
|
||||||
'options-timestamp',
|
|
||||||
'options-altchksum',
|
|
||||||
'options-altchksumopt',
|
|
||||||
'options-md5header',
|
|
||||||
'options-uto'
|
|
||||||
]
|
|
||||||
fields = _fields
|
|
||||||
|
|
||||||
options_names = {
|
|
||||||
"eol": 0,
|
|
||||||
"nop": 1,
|
|
||||||
"mss": 2,
|
|
||||||
"wscale": 3,
|
|
||||||
"sackok": 4,
|
|
||||||
"sack": 5,
|
|
||||||
#"echo" : 6,
|
|
||||||
#"echo_reply" : 7,
|
|
||||||
"timestamp": 8,
|
|
||||||
"altchksum": 14,
|
|
||||||
"altchksumopt": 15,
|
|
||||||
"md5header": 19,
|
|
||||||
#"quick_start" : 27,
|
|
||||||
"uto": 28
|
|
||||||
#"authentication": 29,
|
|
||||||
#"experiment": 254
|
|
||||||
}
|
|
||||||
|
|
||||||
# Each entry is Kind: length
|
|
||||||
options_length = {
|
|
||||||
0: 0, # EOL
|
|
||||||
1: 0, # NOP
|
|
||||||
2: 2, # MSS
|
|
||||||
3: 1, # WScale
|
|
||||||
4: 0, # SAckOK
|
|
||||||
5: 0, # SAck
|
|
||||||
6: 4, # Echo
|
|
||||||
7: 4, # Echo Reply
|
|
||||||
8: 8, # Timestamp
|
|
||||||
14: 3, # AltChkSum
|
|
||||||
15: 0, # AltChkSumOpt
|
|
||||||
19: 16, # MD5header Option
|
|
||||||
27: 6, # Quick-Start response
|
|
||||||
28: 2, # User Timeout Option
|
|
||||||
29: 4, # TCP Authentication Option
|
|
||||||
254: 8, # Experiment
|
|
||||||
|
|
||||||
}
|
|
||||||
# Required by scapy
|
|
||||||
scapy_options = {
|
|
||||||
0: "EOL",
|
|
||||||
1: "NOP",
|
|
||||||
2: "MSS",
|
|
||||||
3: "WScale",
|
|
||||||
4: "SAckOK",
|
|
||||||
5: "SAck",
|
|
||||||
8: "Timestamp",
|
|
||||||
14: "AltChkSum",
|
|
||||||
15: "AltChkSumOpt",
|
|
||||||
28: "UTO",
|
|
||||||
# 254:"Experiment" # scapy has two versions of this, so it doesn't work
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, layer):
|
|
||||||
"""
|
|
||||||
Initializes the TCP layer.
|
|
||||||
"""
|
|
||||||
Layer.__init__(self, layer)
|
|
||||||
# Special methods to help access fields that cannot be accessed normally
|
|
||||||
self.getters = {
|
|
||||||
'load' : self.get_load,
|
|
||||||
'options' : self.get_options
|
|
||||||
}
|
|
||||||
self.setters = {
|
|
||||||
'load' : self.set_load,
|
|
||||||
'options' : self.set_options
|
|
||||||
}
|
|
||||||
# Special methods to help generate fields that cannot be generated normally
|
|
||||||
self.generators = {
|
|
||||||
'load' : self.gen_load,
|
|
||||||
'dataofs' : self.gen_dataofs,
|
|
||||||
'flags' : self.gen_flags,
|
|
||||||
'chksum' : self.gen_chksum,
|
|
||||||
'options' : self.gen_options,
|
|
||||||
'window' : self.gen_window
|
|
||||||
}
|
|
||||||
|
|
||||||
def gen_window(self, field):
|
|
||||||
"""
|
|
||||||
Generates a window size.
|
|
||||||
"""
|
|
||||||
return random.choice(range(10, 200, 10))
|
|
||||||
|
|
||||||
def gen_chksum(self, field):
|
|
||||||
"""
|
|
||||||
Generates a checksum.
|
|
||||||
"""
|
|
||||||
return random.randint(1, 65535)
|
|
||||||
|
|
||||||
def gen_dataofs(self, field):
|
|
||||||
"""
|
|
||||||
Generates a valid value for the data offset field.
|
|
||||||
"""
|
|
||||||
# Dataofs is a 4 bit header, so a max of 15
|
|
||||||
return random.randint(1, 15)
|
|
||||||
|
|
||||||
def gen_flags(self, field):
|
|
||||||
"""
|
|
||||||
Generates a random set of flags. 50% of the time it picks randomly from
|
|
||||||
a list of real flags, otherwise it returns fuzzed flags.
|
|
||||||
"""
|
|
||||||
if random.random() < 0.5:
|
|
||||||
return random.choice(['S', 'A', 'SA', 'PA', 'FA', 'R', 'P', 'F', 'RA', ''])
|
|
||||||
else:
|
|
||||||
sample = fuzz(self.protocol())
|
|
||||||
# Since scapy lazily evaluates fuzzing, we first must set a
|
|
||||||
# legitimate value for scapy to evaluate what combination of flags it is
|
|
||||||
sample.flags = sample.flags
|
|
||||||
return str(sample.flags)
|
|
||||||
|
|
||||||
def get_options(self, field):
|
|
||||||
"""
|
|
||||||
Helper method to retrieve options.
|
|
||||||
"""
|
|
||||||
base, req_option = field.split("-")
|
|
||||||
assert base == "options", "get_options can only be used to fetch options."
|
|
||||||
option_type = self.option_str_to_int(req_option)
|
|
||||||
i = 0
|
|
||||||
# First, check if the option is already present in the packet
|
|
||||||
for option in self.layer.options:
|
|
||||||
# Scapy may try to be helpful and return the string of the option
|
|
||||||
next_option = self.option_str_to_int(option[0])
|
|
||||||
if option_type == next_option:
|
|
||||||
_name, value = self.layer.options[i]
|
|
||||||
# Some options (timestamp, checksums, nop) store their value in a
|
|
||||||
# tuple.
|
|
||||||
if isinstance(value, tuple):
|
|
||||||
# Scapy returns values in any of these types
|
|
||||||
if value in [None, b'', ()]:
|
|
||||||
return ''
|
|
||||||
value = value[0]
|
|
||||||
if value in [None, b'', ()]:
|
|
||||||
return ''
|
|
||||||
if req_option == "md5header":
|
|
||||||
return binascii.hexlify(value).decode("utf-8")
|
|
||||||
|
|
||||||
return value
|
|
||||||
i += 1
|
|
||||||
return ''
|
|
||||||
|
|
||||||
def set_options(self, packet, field, value):
|
|
||||||
"""
|
|
||||||
Helper method to set options.
|
|
||||||
"""
|
|
||||||
base, option = field.split("-")
|
|
||||||
assert base == "options", "Must use an options field with set_options"
|
|
||||||
|
|
||||||
option_type = self.option_str_to_int(option)
|
|
||||||
if type(value) == str:
|
|
||||||
# Prepare the value for storage in the packet
|
|
||||||
value = binascii.unhexlify(value)
|
|
||||||
|
|
||||||
# Scapy requires these options to be a tuple - since evaling this
|
|
||||||
# is not yet supported, for now, SAck will always be an empty tuple
|
|
||||||
if option in ["sack"]:
|
|
||||||
value = ()
|
|
||||||
# These options must be set as integers - if they didn't exist, they can
|
|
||||||
# be added like this
|
|
||||||
if option in ["timestamp", "mss", "wscale", "altchksum", "uto"] and not value:
|
|
||||||
value = 0
|
|
||||||
i = 0
|
|
||||||
# First, check if the option is already present in the packet
|
|
||||||
for option in self.layer.options:
|
|
||||||
# Scapy may try to be helpful and return the string of the option
|
|
||||||
next_option = self.option_str_to_int(option[0])
|
|
||||||
|
|
||||||
if option_type == next_option:
|
|
||||||
packet["TCP"].options[i] = self.format_option(option_type, value)
|
|
||||||
break
|
|
||||||
i += 1
|
|
||||||
# If we didn't break, the option doesn't exist in the packet currently.
|
|
||||||
else:
|
|
||||||
old_options_array = packet["TCP"].options
|
|
||||||
old_options_array.append(self.format_option(option_type, value))
|
|
||||||
packet["TCP"].options = old_options_array
|
|
||||||
|
|
||||||
# Let scapy recalculate the required values
|
|
||||||
del self.layer.chksum
|
|
||||||
del self.layer.dataofs
|
|
||||||
if packet.haslayer("IP"):
|
|
||||||
del packet["IP"].chksum
|
|
||||||
del packet["IP"].len
|
|
||||||
return True
|
|
||||||
|
|
||||||
def gen_options(self, field):
|
|
||||||
"""
|
|
||||||
Helper method to set options.
|
|
||||||
"""
|
|
||||||
_, option = field.split("-")
|
|
||||||
option_num = self.options_names[option]
|
|
||||||
length = self.options_length[option_num]
|
|
||||||
|
|
||||||
data = b''
|
|
||||||
if length > 0:
|
|
||||||
data = os.urandom(length)
|
|
||||||
data = binascii.hexlify(data).decode()
|
|
||||||
# MSS must be a 2-byte int
|
|
||||||
if option_num == 2:
|
|
||||||
data = random.randint(0, 65535)
|
|
||||||
# WScale must be a 1-byte int
|
|
||||||
elif option_num == 3:
|
|
||||||
data = random.randint(0, 255)
|
|
||||||
# Timestamp must be an int
|
|
||||||
elif option_num == 8:
|
|
||||||
data = random.randint(0, 4294967294)
|
|
||||||
elif option_num == 14:
|
|
||||||
data = random.randint(0, 255)
|
|
||||||
elif option_num == 28:
|
|
||||||
data = random.randint(0, 255)
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
def option_str_to_int(self, option):
|
|
||||||
"""
|
|
||||||
Takes a string representation of an option and returns the option integer code.
|
|
||||||
"""
|
|
||||||
if type(option) == int:
|
|
||||||
return option
|
|
||||||
|
|
||||||
assert "-" not in option, "Must be given specific option: %s." % option
|
|
||||||
|
|
||||||
for val in self.scapy_options:
|
|
||||||
if self.scapy_options[val].lower() == option.lower():
|
|
||||||
return val
|
|
||||||
|
|
||||||
if " " in option:
|
|
||||||
option = option.replace(" ", "_").lower()
|
|
||||||
|
|
||||||
if option.lower() in self.options_names:
|
|
||||||
return self.options_names[option.lower()]
|
|
||||||
|
|
||||||
def format_option(self, options_int, value):
|
|
||||||
"""
|
|
||||||
Formats the options so they will work with scapy.
|
|
||||||
"""
|
|
||||||
# NOPs
|
|
||||||
if options_int == 1:
|
|
||||||
return (self.scapy_options[options_int], ())
|
|
||||||
elif options_int in [5]:
|
|
||||||
return (self.scapy_options[options_int], value)
|
|
||||||
# Timestamp
|
|
||||||
elif options_int in [8, 14]:
|
|
||||||
return (self.scapy_options[options_int], (value, 0))
|
|
||||||
elif options_int in self.scapy_options:
|
|
||||||
return (self.scapy_options[options_int], value)
|
|
||||||
else:
|
|
||||||
return (options_int, value)
|
|
||||||
|
|
||||||
|
|
||||||
class UDPLayer(Layer):
|
|
||||||
"""
|
|
||||||
Defines an interface to access UDP header fields.
|
|
||||||
"""
|
|
||||||
name = "UDP"
|
|
||||||
protocol = UDP
|
|
||||||
_fields = [
|
|
||||||
"sport",
|
|
||||||
"dport",
|
|
||||||
"chksum",
|
|
||||||
"len",
|
|
||||||
"load"
|
|
||||||
]
|
|
||||||
fields = _fields
|
|
||||||
|
|
||||||
def __init__(self, layer):
|
|
||||||
"""
|
|
||||||
Initializes the UDP layer.
|
|
||||||
"""
|
|
||||||
Layer.__init__(self, layer)
|
|
||||||
self.getters = {
|
|
||||||
'load' : self.get_load,
|
|
||||||
}
|
|
||||||
self.setters = {
|
|
||||||
'load' : self.set_load,
|
|
||||||
}
|
|
||||||
self.generators = {
|
|
||||||
'load' : self.gen_load,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class DNSLayer(Layer):
|
|
||||||
"""
|
|
||||||
Defines an interface to access DNS header fields.
|
|
||||||
"""
|
|
||||||
name = "DNS"
|
|
||||||
protocol = DNS
|
|
||||||
_fields = [
|
|
||||||
"id",
|
|
||||||
"qr",
|
|
||||||
"opcode",
|
|
||||||
"aa",
|
|
||||||
"tc",
|
|
||||||
"rd",
|
|
||||||
"ra",
|
|
||||||
"z",
|
|
||||||
"ad",
|
|
||||||
"cd",
|
|
||||||
"qd",
|
|
||||||
"rcode",
|
|
||||||
"qdcount",
|
|
||||||
"ancount",
|
|
||||||
"nscount",
|
|
||||||
"arcount"
|
|
||||||
]
|
|
||||||
fields = _fields
|
|
||||||
def __init__(self, layer):
|
|
||||||
"""
|
|
||||||
Initializes the DNS layer.
|
|
||||||
"""
|
|
||||||
Layer.__init__(self, layer)
|
|
||||||
|
|
||||||
self.getters = {
|
|
||||||
"qr" : self.get_bitfield,
|
|
||||||
"aa" : self.get_bitfield,
|
|
||||||
"tc" : self.get_bitfield,
|
|
||||||
"rd" : self.get_bitfield,
|
|
||||||
"ra" : self.get_bitfield,
|
|
||||||
"z" : self.get_bitfield,
|
|
||||||
"ad" : self.get_bitfield,
|
|
||||||
"cd" : self.get_bitfield
|
|
||||||
}
|
|
||||||
|
|
||||||
self.setters = {
|
|
||||||
"qr" : self.set_bitfield,
|
|
||||||
"aa" : self.set_bitfield,
|
|
||||||
"tc" : self.set_bitfield,
|
|
||||||
"rd" : self.set_bitfield,
|
|
||||||
"ra" : self.set_bitfield,
|
|
||||||
"z" : self.set_bitfield,
|
|
||||||
"ad" : self.set_bitfield,
|
|
||||||
"cd" : self.set_bitfield
|
|
||||||
}
|
|
||||||
|
|
||||||
self.generators = {
|
|
||||||
"id" : self.gen_id,
|
|
||||||
"qr" : self.gen_bitfield,
|
|
||||||
"opcode" : self.gen_opcode,
|
|
||||||
"aa" : self.gen_bitfield,
|
|
||||||
"tc" : self.gen_bitfield,
|
|
||||||
"rd" : self.gen_bitfield,
|
|
||||||
"ra" : self.gen_bitfield,
|
|
||||||
"z" : self.gen_bitfield,
|
|
||||||
"ad" : self.gen_bitfield,
|
|
||||||
"cd" : self.gen_bitfield,
|
|
||||||
"rcode" : self.gen_rcode,
|
|
||||||
"qdcount" : self.gen_count,
|
|
||||||
"ancount" : self.gen_count,
|
|
||||||
"nscount" : self.gen_count,
|
|
||||||
"arcount" : self.gen_count
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_bitfield(self, field):
|
|
||||||
""""""
|
|
||||||
return int(getattr(self.layer, field))
|
|
||||||
|
|
||||||
def set_bitfield(self, packet, field, value):
|
|
||||||
""""""
|
|
||||||
return setattr(self.layer, field, int(value))
|
|
||||||
|
|
||||||
def gen_bitfield(self, field):
|
|
||||||
""""""
|
|
||||||
return random.choice([0,1])
|
|
||||||
|
|
||||||
def gen_id(self, field):
|
|
||||||
return random.randint(0, 65535)
|
|
||||||
|
|
||||||
def gen_opcode(self, field):
|
|
||||||
return random.randint(0, 15)
|
|
||||||
|
|
||||||
def gen_rcode(self, field):
|
|
||||||
return random.randint(0, 15)
|
|
||||||
|
|
||||||
def gen_count(self, field):
|
|
||||||
return random.randint(0, 65535)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def dns_decompress(packet, logger):
|
|
||||||
"""
|
|
||||||
Performs DNS decompression on the given scapy packet, if applicable.
|
|
||||||
Note that DNS compression/decompression must be done on the boundaries
|
|
||||||
of a label, so DNS compression does not support arbitrary offsets.
|
|
||||||
"""
|
|
||||||
# If this is a TCP packet
|
|
||||||
if packet.haslayer("TCP"):
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
# Perform no action if this is not a DNS or DNSRQ packet
|
|
||||||
if not packet.haslayer("DNS") or not packet.haslayer("DNSQR"):
|
|
||||||
return packet
|
|
||||||
|
|
||||||
# Extract the query from the DNSQR layer
|
|
||||||
query = packet["DNSQR"].qname.decode()
|
|
||||||
if query[len(query) - 1] != '.':
|
|
||||||
query += '.'
|
|
||||||
|
|
||||||
# Split the query by label
|
|
||||||
labels = query.split(".")
|
|
||||||
|
|
||||||
# Collect the first and second half of the query
|
|
||||||
fhalf = labels[0]
|
|
||||||
shalf = ".".join(labels[1:])
|
|
||||||
|
|
||||||
# Build the first DNS query directly. The format of this a byte string like this:
|
|
||||||
# b'\x07minghui\xc0\x1a\x00\x01\x00\x01'
|
|
||||||
# \x07 = the length of the label in this DNSQR
|
|
||||||
# minghui = the portion of the domain we will request in the first DNSQR
|
|
||||||
# \xc0\x1a = offset into the DNS packet where the rest of the query will be. The actual offset
|
|
||||||
# here is the \x1a - DNS mandates that if compression is used, the first two bits be 11
|
|
||||||
# to differentiate them from the rest. \x1A = 26, which is the length of the DNS header
|
|
||||||
# plus the length of this DNSQR.
|
|
||||||
# \x00\x01 = type A record
|
|
||||||
# \x00\x01 = IN
|
|
||||||
length = bytes([len(fhalf)])
|
|
||||||
label = fhalf.encode()
|
|
||||||
|
|
||||||
# Since the domain will include an extra ".", add 1
|
|
||||||
# 2 * 6 is the DNS header
|
|
||||||
# 1 is the byte that determines the length of the label
|
|
||||||
# len(label) is the length of the label
|
|
||||||
# 2 is the offset pointer
|
|
||||||
# 4 - other record information (class, IN)
|
|
||||||
packet_offset = 2 * 6 + 1 + len(label) + 2 + 2 + 2
|
|
||||||
|
|
||||||
# The word must start with binary 11, so OR the offset with 0xC000.
|
|
||||||
offset = (0xc000 | packet_offset).to_bytes(2, byteorder='big')
|
|
||||||
request = b'\x00\x01\x00\x01'
|
|
||||||
|
|
||||||
dns_qr1 = length + label + offset + request
|
|
||||||
|
|
||||||
# Build the second DNS query directly. The format of the byte string is the same as above
|
|
||||||
# b'\x02ca\x00\x00\x01\x00\x01'
|
|
||||||
# \x02 = length of the remaining domain
|
|
||||||
# ca = portion of the domain in this DNSQR
|
|
||||||
# \x00 = null byte to signify the end of the query
|
|
||||||
# \x00\x01 = type A record
|
|
||||||
# \x00\x01 = IN
|
|
||||||
# Since the second half could potentially contain many labels, this is done in a list comprehension
|
|
||||||
dns_qr2 = b"".join([bytes([len(tld)]) + tld.encode() for tld in shalf.split(".")]) + b"\x00\x01\x00\x01"
|
|
||||||
|
|
||||||
# Next, we must rebuild the DNS packet itself. If we try to have scapy parse either dns_qr1 or dns_qr2, they
|
|
||||||
# will look malformed, since neither contains a complete request. Therefore, we must build the entire
|
|
||||||
# DNS packet at once. First, we must remove the original DNSQR, since this contains the original request
|
|
||||||
del packet["DNS"].qd
|
|
||||||
|
|
||||||
# Once the DNSQR is removed, scapy automatically sets the qdcount to 0. Adjust it to 2
|
|
||||||
packet["DNS"].qdcount = 2
|
|
||||||
|
|
||||||
# Extract the DNS header standalone now for building
|
|
||||||
dns_header = bytes(packet["DNS"])
|
|
||||||
|
|
||||||
dns_packet = DNS(dns_header + dns_qr1 + dns_qr2)
|
|
||||||
|
|
||||||
del packet["DNS"]
|
|
||||||
packet = packet / dns_packet
|
|
||||||
|
|
||||||
# Since the size and data of the packet have changed, force scapy to recalculate the important fields
|
|
||||||
# in below layers, if applicable
|
|
||||||
if packet.haslayer("IP"):
|
|
||||||
del packet["IP"].chksum
|
|
||||||
del packet["IP"].len
|
|
||||||
if packet.haslayer("UDP"):
|
|
||||||
del packet["UDP"].chksum
|
|
||||||
del packet["UDP"].len
|
|
||||||
|
|
||||||
return packet
|
|
||||||
|
|
||||||
|
|
||||||
class DNSQRLayer(Layer):
|
|
||||||
"""
|
|
||||||
Defines an interface to access DNSQR header fields.
|
|
||||||
"""
|
|
||||||
name = "DNSQR"
|
|
||||||
protocol = DNSQR
|
|
||||||
_fields = [
|
|
||||||
"qname",
|
|
||||||
"qtype",
|
|
||||||
"qclass"
|
|
||||||
]
|
|
||||||
fields = _fields
|
|
||||||
|
|
||||||
def __init__(self, layer):
|
|
||||||
"""
|
|
||||||
Initializes the DNS layer.
|
|
||||||
"""
|
|
||||||
Layer.__init__(self, layer)
|
|
||||||
self.getters = {
|
|
||||||
"qname" : self.get_qname
|
|
||||||
}
|
|
||||||
self.generators = {
|
|
||||||
"qname" : self.gen_qname
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_qname(self, field):
|
|
||||||
"""
|
|
||||||
Returns decoded qname from packet.
|
|
||||||
"""
|
|
||||||
return self.layer.qname.decode('utf-8')
|
|
||||||
|
|
||||||
def gen_qname(self, field):
|
|
||||||
"""
|
|
||||||
Generates domain name.
|
|
||||||
"""
|
|
||||||
return "example.com."
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def name_matches(cls, name):
|
|
||||||
"""
|
|
||||||
Scapy returns the name of DNSQR as _both_ DNSQR and "DNS Question Record",
|
|
||||||
which breaks parsing. Override the name_matches method to handle that case
|
|
||||||
here.
|
|
||||||
"""
|
|
||||||
return name.upper() in ["DNSQR", "DNS QUESTION RECORD"]
|
|
|
@ -1,7 +1,7 @@
|
||||||
import threading
|
import threading
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import actions.packet
|
import layers.packet
|
||||||
from scapy.all import sniff
|
from scapy.all import sniff
|
||||||
from scapy.utils import PcapWriter
|
from scapy.utils import PcapWriter
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ class Sniffer():
|
||||||
This callback is called whenever a packet is applied.
|
This callback is called whenever a packet is applied.
|
||||||
Returns true if it should finish, otherwise, returns false.
|
Returns true if it should finish, otherwise, returns false.
|
||||||
"""
|
"""
|
||||||
packet = actions.packet.Packet(scapy_packet)
|
packet = layers.packet.Packet(scapy_packet)
|
||||||
for proto in ["TCP", "UDP"]:
|
for proto in ["TCP", "UDP"]:
|
||||||
if(packet.haslayer(proto) and ((packet[proto].sport == self.port) or (packet[proto].dport == self.port))):
|
if(packet.haslayer(proto) and ((packet[proto].sport == self.port) or (packet[proto].dport == self.port))):
|
||||||
break
|
break
|
||||||
|
|
|
@ -12,7 +12,7 @@ modifications (particularly header modifications). It supports the following pri
|
||||||
|
|
||||||
from actions.action import Action
|
from actions.action import Action
|
||||||
import actions.utils
|
import actions.utils
|
||||||
from actions.layer import DNSLayer
|
from layers.dns_layer import DNSLayer
|
||||||
|
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import actions.utils
|
import actions.utils
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
|
import layers.packet
|
||||||
|
|
||||||
FIXED_TRIGGER = None
|
FIXED_TRIGGER = None
|
||||||
GAS_ENABLED = True
|
GAS_ENABLED = True
|
||||||
|
@ -177,7 +178,7 @@ class Trigger(object):
|
||||||
value = m.group(3)
|
value = m.group(3)
|
||||||
|
|
||||||
# Parse out the given value if necessary
|
# Parse out the given value if necessary
|
||||||
value = actions.packet.Packet.parse(proto, field, value)
|
value = layers.packet.Packet.parse(proto, field, value)
|
||||||
|
|
||||||
# Trigger gas is set to None if it is disabled
|
# Trigger gas is set to None if it is disabled
|
||||||
trigger_gas = None
|
trigger_gas = None
|
||||||
|
|
|
@ -12,7 +12,7 @@ import urllib.parse
|
||||||
|
|
||||||
import actions.action
|
import actions.action
|
||||||
import actions.trigger
|
import actions.trigger
|
||||||
import actions.packet
|
import layers.packet
|
||||||
import plugins.plugin_client
|
import plugins.plugin_client
|
||||||
import plugins.plugin_server
|
import plugins.plugin_server
|
||||||
|
|
||||||
|
@ -309,7 +309,7 @@ def get_from_fuzzed_or_real_packet(environment_id, real_packet_probability, enab
|
||||||
if packets and random.random() < real_packet_probability:
|
if packets and random.random() < real_packet_probability:
|
||||||
packet = random.choice(packets)
|
packet = random.choice(packets)
|
||||||
return packet.get_random()
|
return packet.get_random()
|
||||||
return actions.packet.Packet().gen_random()
|
return layers.packet.Packet().gen_random()
|
||||||
|
|
||||||
|
|
||||||
def read_packets(environment_id):
|
def read_packets(environment_id):
|
||||||
|
@ -327,7 +327,7 @@ def read_packets(environment_id):
|
||||||
parsed = []
|
parsed = []
|
||||||
try:
|
try:
|
||||||
packets = rdpcap(packets_path)
|
packets = rdpcap(packets_path)
|
||||||
parsed = [actions.packet.Packet(p) for p in packets]
|
parsed = [layers.packet.Packet(p) for p in packets]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
print("FAILED TO PARSE!")
|
print("FAILED TO PARSE!")
|
||||||
|
|
|
@ -4,7 +4,7 @@ import logging
|
||||||
import random
|
import random
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import actions.packet
|
import layers.packet
|
||||||
import actions.utils
|
import actions.utils
|
||||||
|
|
||||||
# Squelch annoying scapy ::1 runtime errors
|
# Squelch annoying scapy ::1 runtime errors
|
||||||
|
@ -104,7 +104,7 @@ class Censor(object):
|
||||||
Sends a packet with scapy.
|
Sends a packet with scapy.
|
||||||
"""
|
"""
|
||||||
if "TCP" in packet:
|
if "TCP" in packet:
|
||||||
self.logger.debug(actions.packet.Packet._str_packet(packet))
|
self.logger.debug(layers.packet.Packet._str_packet(packet))
|
||||||
send(packet, verbose=False)
|
send(packet, verbose=False)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ drops all packets after a TCP forbidden keyword is detected.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import actions.packet
|
import layers.packet
|
||||||
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
|
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
|
||||||
from scapy.all import IP, TCP
|
from scapy.all import IP, TCP
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ class Censor1(Censor):
|
||||||
Check if the censor should run against this packet. Returns true or false.
|
Check if the censor should run against this packet. Returns true or false.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
self.logger.debug("Inbound packet to censor: " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Inbound packet to censor: " + layers.packet.Packet._str_packet(packet))
|
||||||
if self.drop_all_from == packet["IP"].src:
|
if self.drop_all_from == packet["IP"].src:
|
||||||
self.logger.debug("Dropping all from this IP %s..." % self.drop_all_from)
|
self.logger.debug("Dropping all from this IP %s..." % self.drop_all_from)
|
||||||
return True
|
return True
|
||||||
|
@ -45,20 +45,20 @@ class Censor1(Censor):
|
||||||
# Initial TCP synchronization
|
# Initial TCP synchronization
|
||||||
if packet["TCP"].sprintf('%TCP.flags%') == "S":
|
if packet["TCP"].sprintf('%TCP.flags%') == "S":
|
||||||
self.tcb = packet["TCP"].seq + 1
|
self.tcb = packet["TCP"].seq + 1
|
||||||
self.logger.debug(("Synchronizing TCB (%d) on packet " + actions.packet.Packet._str_packet(packet)) % self.tcb)
|
self.logger.debug(("Synchronizing TCB (%d) on packet " + layers.packet.Packet._str_packet(packet)) % self.tcb)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# If we're tracking this packet stream
|
# If we're tracking this packet stream
|
||||||
if packet["TCP"].seq == self.tcb:
|
if packet["TCP"].seq == self.tcb:
|
||||||
self.tcb += len(self.get_payload(packet))
|
self.tcb += len(self.get_payload(packet))
|
||||||
else:
|
else:
|
||||||
self.logger.debug("Ignoring packet: " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Ignoring packet: " + layers.packet.Packet._str_packet(packet))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Check if any forbidden words appear in the packet payload
|
# Check if any forbidden words appear in the packet payload
|
||||||
for keyword in self.forbidden:
|
for keyword in self.forbidden:
|
||||||
if keyword in self.get_payload(packet):
|
if keyword in self.get_payload(packet):
|
||||||
self.logger.debug("Packet triggered censor: " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Packet triggered censor: " + layers.packet.Packet._str_packet(packet))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -9,7 +9,7 @@ work.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import netifaces
|
import netifaces
|
||||||
import actions.packet
|
import layers.packet
|
||||||
from censors.censor import Censor
|
from censors.censor import Censor
|
||||||
from scapy.all import raw, IP, TCP
|
from scapy.all import raw, IP, TCP
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ class Censor10(Censor):
|
||||||
Returns true or false.
|
Returns true or false.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
self.logger.debug("Inbound packet to censor: %s" % actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Inbound packet to censor: %s" % layers.packet.Packet._str_packet(packet))
|
||||||
if packet["IP"].src in self.flagged_ips:
|
if packet["IP"].src in self.flagged_ips:
|
||||||
self.logger.debug("Content from a flagged IP detected %s..." % packet["IP"].src)
|
self.logger.debug("Content from a flagged IP detected %s..." % packet["IP"].src)
|
||||||
return True
|
return True
|
||||||
|
@ -65,7 +65,7 @@ class Censor10(Censor):
|
||||||
if not tcb:
|
if not tcb:
|
||||||
tcb = self.get_partial_tcb(packet)
|
tcb = self.get_partial_tcb(packet)
|
||||||
if tcb is None:
|
if tcb is None:
|
||||||
self.logger.debug("Making a new TCB for packet %s" % actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Making a new TCB for packet %s" % layers.packet.Packet._str_packet(packet))
|
||||||
tcb = {}
|
tcb = {}
|
||||||
|
|
||||||
tcb["src"] = packet["IP"].src
|
tcb["src"] = packet["IP"].src
|
||||||
|
@ -81,13 +81,13 @@ class Censor10(Censor):
|
||||||
|
|
||||||
self.tcbs.append(tcb)
|
self.tcbs.append(tcb)
|
||||||
self.resynchronize[(tcb["src"], tcb["dst"], tcb["sport"], tcb["dport"])] = False
|
self.resynchronize[(tcb["src"], tcb["dst"], tcb["sport"], tcb["dport"])] = False
|
||||||
self.logger.debug("Synchronizing a TCB (%s) on packet %s " % (str(tcb), actions.packet.Packet._str_packet(packet)))
|
self.logger.debug("Synchronizing a TCB (%s) on packet %s " % (str(tcb), layers.packet.Packet._str_packet(packet)))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# If connection is getting torn down
|
# If connection is getting torn down
|
||||||
elif tcb and packet["TCP"].sprintf('%TCP.flags%') in ["R", "F"]:
|
elif tcb and packet["TCP"].sprintf('%TCP.flags%') in ["R", "F"]:
|
||||||
self.resynchronize[(tcb["src"], tcb["dst"], tcb["sport"], tcb["dport"])] = True
|
self.resynchronize[(tcb["src"], tcb["dst"], tcb["sport"], tcb["dport"])] = True
|
||||||
self.logger.debug(("Entering resynchronization state on packet %s" % actions.packet.Packet._str_packet(packet)))
|
self.logger.debug(("Entering resynchronization state on packet %s" % layers.packet.Packet._str_packet(packet)))
|
||||||
|
|
||||||
if not tcb:
|
if not tcb:
|
||||||
self.logger.debug("No TCB matches packet.")
|
self.logger.debug("No TCB matches packet.")
|
||||||
|
@ -99,7 +99,7 @@ class Censor10(Censor):
|
||||||
# Check if any forbidden words appear in the packet payload
|
# Check if any forbidden words appear in the packet payload
|
||||||
for keyword in self.forbidden:
|
for keyword in self.forbidden:
|
||||||
if keyword in self.get_payload(packet):
|
if keyword in self.get_payload(packet):
|
||||||
self.logger.debug("Packet triggered censor: %s" % actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Packet triggered censor: %s" % layers.packet.Packet._str_packet(packet))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
@ -150,7 +150,7 @@ class Censor10(Censor):
|
||||||
Checks if the packet matches the stored TCB.
|
Checks if the packet matches the stored TCB.
|
||||||
"""
|
"""
|
||||||
for tcb in self.tcbs:
|
for tcb in self.tcbs:
|
||||||
self.logger.debug("Checking %s against packet %s" % (str(tcb), actions.packet.Packet._str_packet(packet)))
|
self.logger.debug("Checking %s against packet %s" % (str(tcb), layers.packet.Packet._str_packet(packet)))
|
||||||
|
|
||||||
if (packet["IP"].src == tcb["src"] and \
|
if (packet["IP"].src == tcb["src"] and \
|
||||||
packet["IP"].dst == tcb["dst"] and \
|
packet["IP"].dst == tcb["dst"] and \
|
||||||
|
@ -166,7 +166,7 @@ class Censor10(Censor):
|
||||||
are correct.
|
are correct.
|
||||||
"""
|
"""
|
||||||
for tcb in self.tcbs:
|
for tcb in self.tcbs:
|
||||||
self.logger.debug("Checking %s against packet %s for partial match" % (str(tcb), actions.packet.Packet._str_packet(packet)))
|
self.logger.debug("Checking %s against packet %s for partial match" % (str(tcb), layers.packet.Packet._str_packet(packet)))
|
||||||
|
|
||||||
if (packet["IP"].src == tcb["src"] and \
|
if (packet["IP"].src == tcb["src"] and \
|
||||||
packet["IP"].dst == tcb["dst"] and \
|
packet["IP"].dst == tcb["dst"] and \
|
||||||
|
|
|
@ -9,7 +9,7 @@ work. It also resynchronizes on both S and ACK, defeating strategies that trigge
|
||||||
before the 3-way handshake has finished.
|
before the 3-way handshake has finished.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import actions.packet
|
import layers.packet
|
||||||
import netifaces
|
import netifaces
|
||||||
from censors.censor import Censor
|
from censors.censor import Censor
|
||||||
from scapy.all import raw, IP, TCP
|
from scapy.all import raw, IP, TCP
|
||||||
|
@ -33,7 +33,7 @@ class Censor11(Censor):
|
||||||
Returns true or false.
|
Returns true or false.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
self.logger.debug("Inbound packet to censor: %s" % actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Inbound packet to censor: %s" % layers.packet.Packet._str_packet(packet))
|
||||||
if packet["IP"].src in self.flagged_ips:
|
if packet["IP"].src in self.flagged_ips:
|
||||||
self.logger.debug("Content from a flagged IP detected %s..." % packet["IP"].src)
|
self.logger.debug("Content from a flagged IP detected %s..." % packet["IP"].src)
|
||||||
return True
|
return True
|
||||||
|
@ -65,7 +65,7 @@ class Censor11(Censor):
|
||||||
# so we can just replace that tcb with updated info
|
# so we can just replace that tcb with updated info
|
||||||
tcb = self.get_partial_tcb(packet)
|
tcb = self.get_partial_tcb(packet)
|
||||||
if tcb is None:
|
if tcb is None:
|
||||||
self.logger.debug("Making a new TCB for packet %s" % actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Making a new TCB for packet %s" % layers.packet.Packet._str_packet(packet))
|
||||||
tcb = {}
|
tcb = {}
|
||||||
|
|
||||||
tcb["src"] = packet["IP"].src
|
tcb["src"] = packet["IP"].src
|
||||||
|
@ -81,13 +81,13 @@ class Censor11(Censor):
|
||||||
|
|
||||||
self.tcbs.append(tcb)
|
self.tcbs.append(tcb)
|
||||||
self.resynchronize[(tcb["src"], tcb["dst"], tcb["sport"], tcb["dport"])] = False
|
self.resynchronize[(tcb["src"], tcb["dst"], tcb["sport"], tcb["dport"])] = False
|
||||||
self.logger.debug("Synchronizing a TCB (%s) on packet %s " % (str(tcb), actions.packet.Packet._str_packet(packet)))
|
self.logger.debug("Synchronizing a TCB (%s) on packet %s " % (str(tcb), layers.packet.Packet._str_packet(packet)))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# If connection is getting torn down
|
# If connection is getting torn down
|
||||||
elif tcb and packet["TCP"].sprintf('%TCP.flags%') in ["R", "F", "RA", "FA"]:
|
elif tcb and packet["TCP"].sprintf('%TCP.flags%') in ["R", "F", "RA", "FA"]:
|
||||||
self.resynchronize[(tcb["src"], tcb["dst"], tcb["sport"], tcb["dport"])] = True
|
self.resynchronize[(tcb["src"], tcb["dst"], tcb["sport"], tcb["dport"])] = True
|
||||||
self.logger.debug(("Entering resynchronization state on packet %s" % actions.packet.Packet._str_packet(packet)))
|
self.logger.debug(("Entering resynchronization state on packet %s" % layers.packet.Packet._str_packet(packet)))
|
||||||
|
|
||||||
if not tcb:
|
if not tcb:
|
||||||
self.logger.debug("No TCB matches packet.")
|
self.logger.debug("No TCB matches packet.")
|
||||||
|
@ -99,7 +99,7 @@ class Censor11(Censor):
|
||||||
# Check if any forbidden words appear in the packet payload
|
# Check if any forbidden words appear in the packet payload
|
||||||
for keyword in self.forbidden:
|
for keyword in self.forbidden:
|
||||||
if keyword in self.get_payload(packet):
|
if keyword in self.get_payload(packet):
|
||||||
self.logger.debug("Packet triggered censor: %s" % actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Packet triggered censor: %s" % layers.packet.Packet._str_packet(packet))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
@ -150,7 +150,7 @@ class Censor11(Censor):
|
||||||
Checks if the packet matches the stored TCB.
|
Checks if the packet matches the stored TCB.
|
||||||
"""
|
"""
|
||||||
for tcb in self.tcbs:
|
for tcb in self.tcbs:
|
||||||
self.logger.debug("Checking %s against packet %s" % (str(tcb), actions.packet.Packet._str_packet(packet)))
|
self.logger.debug("Checking %s against packet %s" % (str(tcb), layers.packet.Packet._str_packet(packet)))
|
||||||
|
|
||||||
if (packet["IP"].src == tcb["src"] and \
|
if (packet["IP"].src == tcb["src"] and \
|
||||||
packet["IP"].dst == tcb["dst"] and \
|
packet["IP"].dst == tcb["dst"] and \
|
||||||
|
@ -166,7 +166,7 @@ class Censor11(Censor):
|
||||||
are correct.
|
are correct.
|
||||||
"""
|
"""
|
||||||
for tcb in self.tcbs:
|
for tcb in self.tcbs:
|
||||||
self.logger.debug("Checking %s against packet %s for partial match" % (str(tcb), actions.packet.Packet._str_packet(packet)))
|
self.logger.debug("Checking %s against packet %s for partial match" % (str(tcb), layers.packet.Packet._str_packet(packet)))
|
||||||
|
|
||||||
if (packet["IP"].src == tcb["src"] and \
|
if (packet["IP"].src == tcb["src"] and \
|
||||||
packet["IP"].dst == tcb["dst"] and \
|
packet["IP"].dst == tcb["dst"] and \
|
||||||
|
|
|
@ -6,7 +6,7 @@ Designed to be run by the evaluator.
|
||||||
TCP Censor that synchronizes on first SYN only, works 100% of the time, sends 5 RSTs to client.
|
TCP Censor that synchronizes on first SYN only, works 100% of the time, sends 5 RSTs to client.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import actions.packet
|
import layers.packet
|
||||||
import logging
|
import logging
|
||||||
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
|
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
|
||||||
from scapy.all import IP, TCP
|
from scapy.all import IP, TCP
|
||||||
|
@ -26,7 +26,7 @@ class Censor2(Censor):
|
||||||
Check if the censor should run against this packet. Returns true or false.
|
Check if the censor should run against this packet. Returns true or false.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
self.logger.debug("Inbound packet to censor: %s", actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Inbound packet to censor: %s", layers.packet.Packet._str_packet(packet))
|
||||||
|
|
||||||
# Only censor TCP packets for now
|
# Only censor TCP packets for now
|
||||||
if "TCP" not in packet:
|
if "TCP" not in packet:
|
||||||
|
@ -34,19 +34,19 @@ class Censor2(Censor):
|
||||||
|
|
||||||
if packet["TCP"].sprintf('%TCP.flags%') == "S":
|
if packet["TCP"].sprintf('%TCP.flags%') == "S":
|
||||||
self.tcb = packet["TCP"].seq + 1
|
self.tcb = packet["TCP"].seq + 1
|
||||||
self.logger.debug("Synchronizing TCB on packet: %s", actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Synchronizing TCB on packet: %s", layers.packet.Packet._str_packet(packet))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if packet["TCP"].seq == self.tcb:
|
if packet["TCP"].seq == self.tcb:
|
||||||
self.tcb += len(self.get_payload(packet))
|
self.tcb += len(self.get_payload(packet))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.logger.debug("Ignoring packet: %s", actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Ignoring packet: %s", layers.packet.Packet._str_packet(packet))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
for keyword in self.forbidden:
|
for keyword in self.forbidden:
|
||||||
if keyword in self.get_payload(packet):
|
if keyword in self.get_payload(packet):
|
||||||
self.logger.debug("Packet triggered censor: %s", actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Packet triggered censor: %s", layers.packet.Packet._str_packet(packet))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -9,7 +9,7 @@ server AND client.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import netifaces
|
import netifaces
|
||||||
import actions.packet
|
import layers.packet
|
||||||
# Disable scapy ::1 warnings
|
# Disable scapy ::1 warnings
|
||||||
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
|
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
|
||||||
|
|
||||||
|
@ -42,25 +42,25 @@ class Censor3(Censor):
|
||||||
self.num += 1
|
self.num += 1
|
||||||
|
|
||||||
# Only censor TCP packets for now
|
# Only censor TCP packets for now
|
||||||
self.logger.debug("Inbound packet to censor: " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Inbound packet to censor: " + layers.packet.Packet._str_packet(packet))
|
||||||
if "TCP" not in packet:
|
if "TCP" not in packet:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if packet["TCP"].sprintf('%TCP.flags%') == "S":
|
if packet["TCP"].sprintf('%TCP.flags%') == "S":
|
||||||
self.tcb = packet["TCP"].seq + 1
|
self.tcb = packet["TCP"].seq + 1
|
||||||
self.logger.debug("Synchronizing TCB on packet " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Synchronizing TCB on packet " + layers.packet.Packet._str_packet(packet))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if packet["TCP"].seq == self.tcb:
|
if packet["TCP"].seq == self.tcb:
|
||||||
self.tcb += len(self.get_payload(packet))
|
self.tcb += len(self.get_payload(packet))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.logger.debug("Ignoring packet: " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Ignoring packet: " + layers.packet.Packet._str_packet(packet))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
for keyword in self.forbidden:
|
for keyword in self.forbidden:
|
||||||
if keyword in self.get_payload(packet):
|
if keyword in self.get_payload(packet):
|
||||||
self.logger.debug("Packet triggered censor: " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Packet triggered censor: " + layers.packet.Packet._str_packet(packet))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -4,7 +4,7 @@ Censor 4
|
||||||
Dropping censor that synchronizes TCB on all SYN and ACK packets.
|
Dropping censor that synchronizes TCB on all SYN and ACK packets.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import actions.packet
|
import layers.packet
|
||||||
import logging
|
import logging
|
||||||
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
|
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
|
||||||
from scapy.all import IP, TCP
|
from scapy.all import IP, TCP
|
||||||
|
@ -28,7 +28,7 @@ class Censor4(Censor):
|
||||||
self.num += 1
|
self.num += 1
|
||||||
|
|
||||||
|
|
||||||
self.logger.debug("Inbound packet to censor: " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Inbound packet to censor: " + layers.packet.Packet._str_packet(packet))
|
||||||
if self.drop_all_from == packet["IP"].src:
|
if self.drop_all_from == packet["IP"].src:
|
||||||
self.logger.debug("Dropping all from this IP %s..." % self.drop_all_from)
|
self.logger.debug("Dropping all from this IP %s..." % self.drop_all_from)
|
||||||
return True
|
return True
|
||||||
|
@ -40,25 +40,25 @@ class Censor4(Censor):
|
||||||
# Initial TCP synchronization
|
# Initial TCP synchronization
|
||||||
if "S" == packet["TCP"].sprintf('%TCP.flags%'):
|
if "S" == packet["TCP"].sprintf('%TCP.flags%'):
|
||||||
self.tcb = packet["TCP"].seq + 1
|
self.tcb = packet["TCP"].seq + 1
|
||||||
self.logger.debug(("Synchronizing TCB (%d) on S packet " + actions.packet.Packet._str_packet(packet)) % self.tcb)
|
self.logger.debug(("Synchronizing TCB (%d) on S packet " + layers.packet.Packet._str_packet(packet)) % self.tcb)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if "A" == packet["TCP"].sprintf('%TCP.flags%'):
|
if "A" == packet["TCP"].sprintf('%TCP.flags%'):
|
||||||
self.tcb = packet["TCP"].seq
|
self.tcb = packet["TCP"].seq
|
||||||
self.logger.debug(("Synchronizing TCB (%d) on A packet " + actions.packet.Packet._str_packet(packet)) % self.tcb)
|
self.logger.debug(("Synchronizing TCB (%d) on A packet " + layers.packet.Packet._str_packet(packet)) % self.tcb)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# If we're tracking this packet stream
|
# If we're tracking this packet stream
|
||||||
if packet["TCP"].seq == self.tcb:
|
if packet["TCP"].seq == self.tcb:
|
||||||
self.tcb += len(self.get_payload(packet))
|
self.tcb += len(self.get_payload(packet))
|
||||||
else:
|
else:
|
||||||
self.logger.debug("Ignoring packet: " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Ignoring packet: " + layers.packet.Packet._str_packet(packet))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Check if any forbidden words appear in the packet payload
|
# Check if any forbidden words appear in the packet payload
|
||||||
for keyword in self.forbidden:
|
for keyword in self.forbidden:
|
||||||
if keyword in self.get_payload(packet):
|
if keyword in self.get_payload(packet):
|
||||||
self.logger.debug("Packet triggered censor: " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Packet triggered censor: " + layers.packet.Packet._str_packet(packet))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -7,7 +7,7 @@ TCP Censor that synchronizes on first SYN only, works 100% of the time, sends 5
|
||||||
the server only.
|
the server only.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import actions.packet
|
import layers.packet
|
||||||
import logging
|
import logging
|
||||||
import netifaces
|
import netifaces
|
||||||
# Disable scapy ::1 warnings
|
# Disable scapy ::1 warnings
|
||||||
|
@ -42,25 +42,25 @@ class Censor5(Censor):
|
||||||
self.num += 1
|
self.num += 1
|
||||||
|
|
||||||
# Only censor TCP packets for now
|
# Only censor TCP packets for now
|
||||||
self.logger.debug("Inbound packet to censor: " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Inbound packet to censor: " + layers.packet.Packet._str_packet(packet))
|
||||||
if "TCP" not in packet:
|
if "TCP" not in packet:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if packet["TCP"].sprintf('%TCP.flags%') == "S":
|
if packet["TCP"].sprintf('%TCP.flags%') == "S":
|
||||||
self.tcb = packet["TCP"].seq + 1
|
self.tcb = packet["TCP"].seq + 1
|
||||||
self.logger.debug("Synchronizing TCB on packet " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Synchronizing TCB on packet " + layers.packet.Packet._str_packet(packet))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if packet["TCP"].seq == self.tcb:
|
if packet["TCP"].seq == self.tcb:
|
||||||
self.tcb += len(self.get_payload(packet))
|
self.tcb += len(self.get_payload(packet))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.logger.debug("Ignoring packet: " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Ignoring packet: " + layers.packet.Packet._str_packet(packet))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
for keyword in self.forbidden:
|
for keyword in self.forbidden:
|
||||||
if keyword in self.get_payload(packet):
|
if keyword in self.get_payload(packet):
|
||||||
self.logger.debug("Packet triggered censor: " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Packet triggered censor: " + layers.packet.Packet._str_packet(packet))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -4,7 +4,7 @@ FIN or RST packet.
|
||||||
Does not check if the ports are correct for the FIN/RST.
|
Does not check if the ports are correct for the FIN/RST.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import actions.packet
|
import layers.packet
|
||||||
import logging
|
import logging
|
||||||
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
|
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
|
||||||
from scapy.all import IP, TCP
|
from scapy.all import IP, TCP
|
||||||
|
@ -24,7 +24,7 @@ class Censor6(Censor):
|
||||||
Check if the censor should run against this packet. Returns true or false.
|
Check if the censor should run against this packet. Returns true or false.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
self.logger.debug("Inbound packet to censor: " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Inbound packet to censor: " + layers.packet.Packet._str_packet(packet))
|
||||||
if self.drop_all_from == packet["IP"].src:
|
if self.drop_all_from == packet["IP"].src:
|
||||||
self.logger.debug("Dropping all from this IP %s..." % self.drop_all_from)
|
self.logger.debug("Dropping all from this IP %s..." % self.drop_all_from)
|
||||||
return True
|
return True
|
||||||
|
@ -36,17 +36,17 @@ class Censor6(Censor):
|
||||||
# Some stacks send RA to tear down a connection
|
# Some stacks send RA to tear down a connection
|
||||||
if packet["TCP"].sprintf('%TCP.flags%') in ["R", "RA", "F"]:
|
if packet["TCP"].sprintf('%TCP.flags%') in ["R", "RA", "F"]:
|
||||||
self.tcb = None
|
self.tcb = None
|
||||||
self.logger.debug(("Tearing down TCB on packet " + actions.packet.Packet._str_packet(packet)))
|
self.logger.debug(("Tearing down TCB on packet " + layers.packet.Packet._str_packet(packet)))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if self.tcb is None:
|
if self.tcb is None:
|
||||||
self.logger.debug("Ignoring packet: " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Ignoring packet: " + layers.packet.Packet._str_packet(packet))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Check if any forbidden words appear in the packet payload
|
# Check if any forbidden words appear in the packet payload
|
||||||
for keyword in self.forbidden:
|
for keyword in self.forbidden:
|
||||||
if keyword in self.get_payload(packet):
|
if keyword in self.get_payload(packet):
|
||||||
self.logger.debug("Packet triggered censor: " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Packet triggered censor: " + layers.packet.Packet._str_packet(packet))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -5,7 +5,7 @@ Does not check if the SEQ/ACK are in window for the FIN/RST.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import actions.packet
|
import layers.packet
|
||||||
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
|
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
|
||||||
from scapy.all import IP, TCP
|
from scapy.all import IP, TCP
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ class Censor7(Censor):
|
||||||
Check if the censor should run against this packet. Returns true or false.
|
Check if the censor should run against this packet. Returns true or false.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
self.logger.debug("Inbound packet to censor: " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Inbound packet to censor: " + layers.packet.Packet._str_packet(packet))
|
||||||
if self.drop_all_from == packet["IP"].src:
|
if self.drop_all_from == packet["IP"].src:
|
||||||
self.logger.debug("Dropping all from this IP %s..." % self.drop_all_from)
|
self.logger.debug("Dropping all from this IP %s..." % self.drop_all_from)
|
||||||
return True
|
return True
|
||||||
|
@ -43,7 +43,7 @@ class Censor7(Censor):
|
||||||
packet["TCP"].sport in self.tcb["ports"]:
|
packet["TCP"].sport in self.tcb["ports"]:
|
||||||
|
|
||||||
self.tcb = None
|
self.tcb = None
|
||||||
self.logger.debug(("Tearing down TCB on packet " + actions.packet.Packet._str_packet(packet)))
|
self.logger.debug(("Tearing down TCB on packet " + layers.packet.Packet._str_packet(packet)))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
elif not self.tcb and self.tcb is not None:
|
elif not self.tcb and self.tcb is not None:
|
||||||
|
@ -51,13 +51,13 @@ class Censor7(Censor):
|
||||||
self.tcb["ports"] = [packet["TCP"].sport, packet["TCP"].dport]
|
self.tcb["ports"] = [packet["TCP"].sport, packet["TCP"].dport]
|
||||||
|
|
||||||
if self.tcb is None:
|
if self.tcb is None:
|
||||||
self.logger.debug("Ignoring packet: " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Ignoring packet: " + layers.packet.Packet._str_packet(packet))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Check if any forbidden words appear in the packet payload
|
# Check if any forbidden words appear in the packet payload
|
||||||
for keyword in self.forbidden:
|
for keyword in self.forbidden:
|
||||||
if keyword in self.get_payload(packet):
|
if keyword in self.get_payload(packet):
|
||||||
self.logger.debug("Packet triggered censor: " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Packet triggered censor: " + layers.packet.Packet._str_packet(packet))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -4,7 +4,7 @@ if the full tuple of the TCB matches (src, dst, sport, dport, seq).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import actions.packet
|
import layers.packet
|
||||||
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
|
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
|
||||||
from scapy.all import IP, TCP
|
from scapy.all import IP, TCP
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ class Censor8(Censor):
|
||||||
Check if the censor should run against this packet. Returns true or false.
|
Check if the censor should run against this packet. Returns true or false.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
self.logger.debug("Inbound packet to censor: " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Inbound packet to censor: " + layers.packet.Packet._str_packet(packet))
|
||||||
if self.drop_all_from == packet["IP"].src:
|
if self.drop_all_from == packet["IP"].src:
|
||||||
self.logger.debug("Dropping all from this IP %s..." % self.drop_all_from)
|
self.logger.debug("Dropping all from this IP %s..." % self.drop_all_from)
|
||||||
return True
|
return True
|
||||||
|
@ -36,7 +36,7 @@ class Censor8(Censor):
|
||||||
self.tcb["ips"] = [packet["IP"].src, packet["IP"].dst]
|
self.tcb["ips"] = [packet["IP"].src, packet["IP"].dst]
|
||||||
self.tcb["ports"] = [packet["TCP"].sport, packet["TCP"].dport]
|
self.tcb["ports"] = [packet["TCP"].sport, packet["TCP"].dport]
|
||||||
self.tcb["seq"] = packet["TCP"].seq + 1
|
self.tcb["seq"] = packet["TCP"].seq + 1
|
||||||
self.logger.debug("Synchronizing TCB on packet " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Synchronizing TCB on packet " + layers.packet.Packet._str_packet(packet))
|
||||||
return False
|
return False
|
||||||
# TCB teardown
|
# TCB teardown
|
||||||
elif packet["TCP"].sprintf('%TCP.flags%') == "R" or packet["TCP"].sprintf('%TCP.flags%') == "F":
|
elif packet["TCP"].sprintf('%TCP.flags%') == "R" or packet["TCP"].sprintf('%TCP.flags%') == "F":
|
||||||
|
@ -49,11 +49,11 @@ class Censor8(Censor):
|
||||||
packet["TCP"].seq == self.tcb["seq"]:
|
packet["TCP"].seq == self.tcb["seq"]:
|
||||||
|
|
||||||
self.tcb = None
|
self.tcb = None
|
||||||
self.logger.debug(("Tearing down TCB on packet " + actions.packet.Packet._str_packet(packet)))
|
self.logger.debug(("Tearing down TCB on packet " + layers.packet.Packet._str_packet(packet)))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if self.tcb is None:
|
if self.tcb is None:
|
||||||
self.logger.debug("Ignoring packet: " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Ignoring packet: " + layers.packet.Packet._str_packet(packet))
|
||||||
return False
|
return False
|
||||||
elif "seq" in self.tcb and packet["TCP"].seq == self.tcb["seq"]:
|
elif "seq" in self.tcb and packet["TCP"].seq == self.tcb["seq"]:
|
||||||
self.tcb["seq"] += len(self.get_payload(packet))
|
self.tcb["seq"] += len(self.get_payload(packet))
|
||||||
|
@ -61,7 +61,7 @@ class Censor8(Censor):
|
||||||
# Check if any forbidden words appear in the packet payload
|
# Check if any forbidden words appear in the packet payload
|
||||||
for keyword in self.forbidden:
|
for keyword in self.forbidden:
|
||||||
if keyword in self.get_payload(packet):
|
if keyword in self.get_payload(packet):
|
||||||
self.logger.debug("Packet triggered censor: " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Packet triggered censor: " + layers.packet.Packet._str_packet(packet))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -5,7 +5,7 @@ state if a RST or FIN, it simply tears down. It creates new TCBs for connections
|
||||||
yet aware of, but does not check the checksums of incoming packets.
|
yet aware of, but does not check the checksums of incoming packets.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import actions.packet
|
import layers.packet
|
||||||
import netifaces
|
import netifaces
|
||||||
from censors.censor import Censor
|
from censors.censor import Censor
|
||||||
from scapy.all import IP, TCP
|
from scapy.all import IP, TCP
|
||||||
|
@ -28,7 +28,7 @@ class Censor8b(Censor):
|
||||||
Returns true or false.
|
Returns true or false.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
self.logger.debug("Inbound packet to censor: %s" % actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Inbound packet to censor: %s" % layers.packet.Packet._str_packet(packet))
|
||||||
if packet["IP"].src in self.flagged_ips:
|
if packet["IP"].src in self.flagged_ips:
|
||||||
self.logger.debug("Content from a flagged IP detected %s..." % packet["IP"].src)
|
self.logger.debug("Content from a flagged IP detected %s..." % packet["IP"].src)
|
||||||
return True
|
return True
|
||||||
|
@ -49,7 +49,7 @@ class Censor8b(Censor):
|
||||||
# so we can just replace that tcb with updated info
|
# so we can just replace that tcb with updated info
|
||||||
tcb = self.get_partial_tcb(packet)
|
tcb = self.get_partial_tcb(packet)
|
||||||
if tcb is None:
|
if tcb is None:
|
||||||
self.logger.debug("Making a new TCB for packet %s" % actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Making a new TCB for packet %s" % layers.packet.Packet._str_packet(packet))
|
||||||
tcb = {}
|
tcb = {}
|
||||||
|
|
||||||
tcb["src"] = packet["IP"].src
|
tcb["src"] = packet["IP"].src
|
||||||
|
@ -64,12 +64,12 @@ class Censor8b(Censor):
|
||||||
tcb["seq"] += len(self.get_payload(packet))
|
tcb["seq"] += len(self.get_payload(packet))
|
||||||
|
|
||||||
self.tcbs.append(tcb)
|
self.tcbs.append(tcb)
|
||||||
self.logger.debug("Synchronizing a TCB (%s) on packet %s " % (str(tcb), actions.packet.Packet._str_packet(packet)))
|
self.logger.debug("Synchronizing a TCB (%s) on packet %s " % (str(tcb), layers.packet.Packet._str_packet(packet)))
|
||||||
return False
|
return False
|
||||||
# If connection is getting torn down
|
# If connection is getting torn down
|
||||||
elif tcb and packet["TCP"].sprintf('%TCP.flags%') in ["R", "RA"]:
|
elif tcb and packet["TCP"].sprintf('%TCP.flags%') in ["R", "RA"]:
|
||||||
self.tcbs.remove(tcb)
|
self.tcbs.remove(tcb)
|
||||||
self.logger.debug(("Deleting TCB for packet %s" % actions.packet.Packet._str_packet(packet)))
|
self.logger.debug(("Deleting TCB for packet %s" % layers.packet.Packet._str_packet(packet)))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if not tcb:
|
if not tcb:
|
||||||
|
@ -82,7 +82,7 @@ class Censor8b(Censor):
|
||||||
# Check if any forbidden words appear in the packet payload
|
# Check if any forbidden words appear in the packet payload
|
||||||
for keyword in self.forbidden:
|
for keyword in self.forbidden:
|
||||||
if keyword in self.get_payload(packet):
|
if keyword in self.get_payload(packet):
|
||||||
self.logger.debug("Packet triggered censor: %s" % actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Packet triggered censor: %s" % layers.packet.Packet._str_packet(packet))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
@ -133,7 +133,7 @@ class Censor8b(Censor):
|
||||||
Checks if the packet matches the stored TCB.
|
Checks if the packet matches the stored TCB.
|
||||||
"""
|
"""
|
||||||
for tcb in self.tcbs:
|
for tcb in self.tcbs:
|
||||||
self.logger.debug("Checking %s against packet %s" % (str(tcb), actions.packet.Packet._str_packet(packet)))
|
self.logger.debug("Checking %s against packet %s" % (str(tcb), layers.packet.Packet._str_packet(packet)))
|
||||||
|
|
||||||
if (packet["IP"].src == tcb["src"] and \
|
if (packet["IP"].src == tcb["src"] and \
|
||||||
packet["IP"].dst == tcb["dst"] and \
|
packet["IP"].dst == tcb["dst"] and \
|
||||||
|
@ -149,7 +149,7 @@ class Censor8b(Censor):
|
||||||
are correct.
|
are correct.
|
||||||
"""
|
"""
|
||||||
for tcb in self.tcbs:
|
for tcb in self.tcbs:
|
||||||
self.logger.debug("Checking %s against packet %s for partial match" % (str(tcb), actions.packet.Packet._str_packet(packet)))
|
self.logger.debug("Checking %s against packet %s for partial match" % (str(tcb), layers.packet.Packet._str_packet(packet)))
|
||||||
|
|
||||||
if (packet["IP"].src == tcb["src"] and \
|
if (packet["IP"].src == tcb["src"] and \
|
||||||
packet["IP"].dst == tcb["dst"] and \
|
packet["IP"].dst == tcb["dst"] and \
|
||||||
|
|
|
@ -7,7 +7,7 @@ More closely mimics GFW behavior.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import actions.packet
|
import layers.packet
|
||||||
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
|
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
|
||||||
from scapy.all import IP, TCP
|
from scapy.all import IP, TCP
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ class Censor9(Censor):
|
||||||
Check if the censor should run against this packet. Returns true or false.
|
Check if the censor should run against this packet. Returns true or false.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
self.logger.debug("Inbound packet to censor: " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Inbound packet to censor: " + layers.packet.Packet._str_packet(packet))
|
||||||
if self.drop_all_from == packet["IP"].src:
|
if self.drop_all_from == packet["IP"].src:
|
||||||
self.logger.debug("Dropping all from this IP %s..." % self.drop_all_from)
|
self.logger.debug("Dropping all from this IP %s..." % self.drop_all_from)
|
||||||
return True
|
return True
|
||||||
|
@ -51,7 +51,7 @@ class Censor9(Censor):
|
||||||
self.tcb["seq"] += len(self.get_payload(packet))
|
self.tcb["seq"] += len(self.get_payload(packet))
|
||||||
|
|
||||||
self.resynchronize = False
|
self.resynchronize = False
|
||||||
self.logger.debug("Synchronizing TCB on packet " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Synchronizing TCB on packet " + layers.packet.Packet._str_packet(packet))
|
||||||
return self.check_forbidden(packet)
|
return self.check_forbidden(packet)
|
||||||
|
|
||||||
# If connection is getting torn down
|
# If connection is getting torn down
|
||||||
|
@ -59,7 +59,7 @@ class Censor9(Censor):
|
||||||
(packet["TCP"].sprintf('%TCP.flags%') == "R" or \
|
(packet["TCP"].sprintf('%TCP.flags%') == "R" or \
|
||||||
packet["TCP"].sprintf('%TCP.flags%') == "F"):
|
packet["TCP"].sprintf('%TCP.flags%') == "F"):
|
||||||
self.resynchronize = True
|
self.resynchronize = True
|
||||||
self.logger.debug(("Entering resynchronization state on packet " + actions.packet.Packet._str_packet(packet)))
|
self.logger.debug(("Entering resynchronization state on packet " + layers.packet.Packet._str_packet(packet)))
|
||||||
|
|
||||||
if not self.tcb_matches(packet):
|
if not self.tcb_matches(packet):
|
||||||
self.logger.debug("TCB does not match packet.")
|
self.logger.debug("TCB does not match packet.")
|
||||||
|
@ -89,7 +89,7 @@ class Censor9(Censor):
|
||||||
# Check if any forbidden words appear in the packet payload
|
# Check if any forbidden words appear in the packet payload
|
||||||
for keyword in self.forbidden:
|
for keyword in self.forbidden:
|
||||||
if keyword in self.get_payload(packet):
|
if keyword in self.get_payload(packet):
|
||||||
self.logger.debug("Packet triggered censor: " + actions.packet.Packet._str_packet(packet))
|
self.logger.debug("Packet triggered censor: " + layers.packet.Packet._str_packet(packet))
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
geneva.actions.layer
|
geneva.layers.layer
|
||||||
====================
|
====================
|
||||||
|
|
||||||
.. automodule:: layer
|
.. automodule:: layer
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
geneva.actions.packet
|
geneva.layers.packet
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
.. automodule:: packet
|
.. automodule:: packet
|
||||||
|
|
10
engine.py
10
engine.py
|
@ -25,7 +25,7 @@ from scapy.config import conf
|
||||||
|
|
||||||
socket.setdefaulttimeout(1)
|
socket.setdefaulttimeout(1)
|
||||||
|
|
||||||
import actions.packet
|
import layers.packet
|
||||||
import actions.strategy
|
import actions.strategy
|
||||||
import actions.utils
|
import actions.utils
|
||||||
|
|
||||||
|
@ -141,10 +141,10 @@ class Engine():
|
||||||
configured route, and clears the checksums for recalculating
|
configured route, and clears the checksums for recalculating
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
packet (Actions.packet.Packet): packet to modify before sending
|
packet (layers.packet.Packet): packet to modify before sending
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Actions.packet.Packet: the modified packet
|
layers.packet.Packet: the modified packet
|
||||||
"""
|
"""
|
||||||
if packet["IP"].src == self.sender_ip:
|
if packet["IP"].src == self.sender_ip:
|
||||||
packet["IP"].dst = self.forward_ip
|
packet["IP"].dst = self.forward_ip
|
||||||
|
@ -329,7 +329,7 @@ class Engine():
|
||||||
if not self.running_nfqueue:
|
if not self.running_nfqueue:
|
||||||
return
|
return
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(nfpacket.get_payload()))
|
packet = layers.packet.Packet(IP(nfpacket.get_payload()))
|
||||||
self.logger.debug("Received outbound packet %s", str(packet))
|
self.logger.debug("Received outbound packet %s", str(packet))
|
||||||
|
|
||||||
# Record this packet for a .pacp later
|
# Record this packet for a .pacp later
|
||||||
|
@ -365,7 +365,7 @@ class Engine():
|
||||||
"""
|
"""
|
||||||
if not self.running_nfqueue:
|
if not self.running_nfqueue:
|
||||||
return
|
return
|
||||||
packet = actions.packet.Packet(IP(nfpacket.get_payload()))
|
packet = layers.packet.Packet(IP(nfpacket.get_payload()))
|
||||||
|
|
||||||
if self.save_seen_packets:
|
if self.save_seen_packets:
|
||||||
self.seen_packets.append(packet)
|
self.seen_packets.append(packet)
|
||||||
|
|
|
@ -16,6 +16,7 @@ import actions.strategy
|
||||||
import actions.tree
|
import actions.tree
|
||||||
import actions.trigger
|
import actions.trigger
|
||||||
import evaluator
|
import evaluator
|
||||||
|
import layers.packet
|
||||||
|
|
||||||
# Grab the terminal size for printing
|
# Grab the terminal size for printing
|
||||||
try:
|
try:
|
||||||
|
@ -715,7 +716,7 @@ def restrict_headers(logger, protos, filter_fields, disabled_fields):
|
||||||
if disabled_fields:
|
if disabled_fields:
|
||||||
disabled_fields = disabled_fields.split(",")
|
disabled_fields = disabled_fields.split(",")
|
||||||
|
|
||||||
actions.packet.Packet.restrict_fields(logger, protos, filter_fields, disabled_fields)
|
layers.packet.Packet.restrict_fields(logger, protos, filter_fields, disabled_fields)
|
||||||
|
|
||||||
|
|
||||||
def driver(cmd):
|
def driver(cmd):
|
||||||
|
|
|
@ -0,0 +1,189 @@
|
||||||
|
import random
|
||||||
|
from layers.layer import Layer
|
||||||
|
from scapy.all import DNS
|
||||||
|
|
||||||
|
class DNSLayer(Layer):
|
||||||
|
"""
|
||||||
|
Defines an interface to access DNS header fields.
|
||||||
|
"""
|
||||||
|
name = "DNS"
|
||||||
|
protocol = DNS
|
||||||
|
_fields = [
|
||||||
|
"id",
|
||||||
|
"qr",
|
||||||
|
"opcode",
|
||||||
|
"aa",
|
||||||
|
"tc",
|
||||||
|
"rd",
|
||||||
|
"ra",
|
||||||
|
"z",
|
||||||
|
"ad",
|
||||||
|
"cd",
|
||||||
|
"qd",
|
||||||
|
"rcode",
|
||||||
|
"qdcount",
|
||||||
|
"ancount",
|
||||||
|
"nscount",
|
||||||
|
"arcount"
|
||||||
|
]
|
||||||
|
fields = _fields
|
||||||
|
def __init__(self, layer):
|
||||||
|
"""
|
||||||
|
Initializes the DNS layer.
|
||||||
|
"""
|
||||||
|
Layer.__init__(self, layer)
|
||||||
|
|
||||||
|
self.getters = {
|
||||||
|
"qr" : self.get_bitfield,
|
||||||
|
"aa" : self.get_bitfield,
|
||||||
|
"tc" : self.get_bitfield,
|
||||||
|
"rd" : self.get_bitfield,
|
||||||
|
"ra" : self.get_bitfield,
|
||||||
|
"z" : self.get_bitfield,
|
||||||
|
"ad" : self.get_bitfield,
|
||||||
|
"cd" : self.get_bitfield
|
||||||
|
}
|
||||||
|
|
||||||
|
self.setters = {
|
||||||
|
"qr" : self.set_bitfield,
|
||||||
|
"aa" : self.set_bitfield,
|
||||||
|
"tc" : self.set_bitfield,
|
||||||
|
"rd" : self.set_bitfield,
|
||||||
|
"ra" : self.set_bitfield,
|
||||||
|
"z" : self.set_bitfield,
|
||||||
|
"ad" : self.set_bitfield,
|
||||||
|
"cd" : self.set_bitfield
|
||||||
|
}
|
||||||
|
|
||||||
|
self.generators = {
|
||||||
|
"id" : self.gen_id,
|
||||||
|
"qr" : self.gen_bitfield,
|
||||||
|
"opcode" : self.gen_opcode,
|
||||||
|
"aa" : self.gen_bitfield,
|
||||||
|
"tc" : self.gen_bitfield,
|
||||||
|
"rd" : self.gen_bitfield,
|
||||||
|
"ra" : self.gen_bitfield,
|
||||||
|
"z" : self.gen_bitfield,
|
||||||
|
"ad" : self.gen_bitfield,
|
||||||
|
"cd" : self.gen_bitfield,
|
||||||
|
"rcode" : self.gen_rcode,
|
||||||
|
"qdcount" : self.gen_count,
|
||||||
|
"ancount" : self.gen_count,
|
||||||
|
"nscount" : self.gen_count,
|
||||||
|
"arcount" : self.gen_count
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_bitfield(self, field):
|
||||||
|
""""""
|
||||||
|
return int(getattr(self.layer, field))
|
||||||
|
|
||||||
|
def set_bitfield(self, packet, field, value):
|
||||||
|
""""""
|
||||||
|
return setattr(self.layer, field, int(value))
|
||||||
|
|
||||||
|
def gen_bitfield(self, field):
|
||||||
|
""""""
|
||||||
|
return random.choice([0,1])
|
||||||
|
|
||||||
|
def gen_id(self, field):
|
||||||
|
return random.randint(0, 65535)
|
||||||
|
|
||||||
|
def gen_opcode(self, field):
|
||||||
|
return random.randint(0, 15)
|
||||||
|
|
||||||
|
def gen_rcode(self, field):
|
||||||
|
return random.randint(0, 15)
|
||||||
|
|
||||||
|
def gen_count(self, field):
|
||||||
|
return random.randint(0, 65535)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def dns_decompress(packet, logger):
|
||||||
|
"""
|
||||||
|
Performs DNS decompression on the given scapy packet, if applicable.
|
||||||
|
Note that DNS compression/decompression must be done on the boundaries
|
||||||
|
of a label, so DNS compression does not support arbitrary offsets.
|
||||||
|
"""
|
||||||
|
# If this is a TCP packet
|
||||||
|
if packet.haslayer("TCP"):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
# Perform no action if this is not a DNS or DNSRQ packet
|
||||||
|
if not packet.haslayer("DNS") or not packet.haslayer("DNSQR"):
|
||||||
|
return packet
|
||||||
|
|
||||||
|
# Extract the query from the DNSQR layer
|
||||||
|
query = packet["DNSQR"].qname.decode()
|
||||||
|
if query[len(query) - 1] != '.':
|
||||||
|
query += '.'
|
||||||
|
|
||||||
|
# Split the query by label
|
||||||
|
labels = query.split(".")
|
||||||
|
|
||||||
|
# Collect the first and second half of the query
|
||||||
|
fhalf = labels[0]
|
||||||
|
shalf = ".".join(labels[1:])
|
||||||
|
|
||||||
|
# Build the first DNS query directly. The format of this a byte string like this:
|
||||||
|
# b'\x07minghui\xc0\x1a\x00\x01\x00\x01'
|
||||||
|
# \x07 = the length of the label in this DNSQR
|
||||||
|
# minghui = the portion of the domain we will request in the first DNSQR
|
||||||
|
# \xc0\x1a = offset into the DNS packet where the rest of the query will be. The actual offset
|
||||||
|
# here is the \x1a - DNS mandates that if compression is used, the first two bits be 11
|
||||||
|
# to differentiate them from the rest. \x1A = 26, which is the length of the DNS header
|
||||||
|
# plus the length of this DNSQR.
|
||||||
|
# \x00\x01 = type A record
|
||||||
|
# \x00\x01 = IN
|
||||||
|
length = bytes([len(fhalf)])
|
||||||
|
label = fhalf.encode()
|
||||||
|
|
||||||
|
# Since the domain will include an extra ".", add 1
|
||||||
|
# 2 * 6 is the DNS header
|
||||||
|
# 1 is the byte that determines the length of the label
|
||||||
|
# len(label) is the length of the label
|
||||||
|
# 2 is the offset pointer
|
||||||
|
# 4 - other record information (class, IN)
|
||||||
|
packet_offset = 2 * 6 + 1 + len(label) + 2 + 2 + 2
|
||||||
|
|
||||||
|
# The word must start with binary 11, so OR the offset with 0xC000.
|
||||||
|
offset = (0xc000 | packet_offset).to_bytes(2, byteorder='big')
|
||||||
|
request = b'\x00\x01\x00\x01'
|
||||||
|
|
||||||
|
dns_qr1 = length + label + offset + request
|
||||||
|
|
||||||
|
# Build the second DNS query directly. The format of the byte string is the same as above
|
||||||
|
# b'\x02ca\x00\x00\x01\x00\x01'
|
||||||
|
# \x02 = length of the remaining domain
|
||||||
|
# ca = portion of the domain in this DNSQR
|
||||||
|
# \x00 = null byte to signify the end of the query
|
||||||
|
# \x00\x01 = type A record
|
||||||
|
# \x00\x01 = IN
|
||||||
|
# Since the second half could potentially contain many labels, this is done in a list comprehension
|
||||||
|
dns_qr2 = b"".join([bytes([len(tld)]) + tld.encode() for tld in shalf.split(".")]) + b"\x00\x01\x00\x01"
|
||||||
|
|
||||||
|
# Next, we must rebuild the DNS packet itself. If we try to have scapy parse either dns_qr1 or dns_qr2, they
|
||||||
|
# will look malformed, since neither contains a complete request. Therefore, we must build the entire
|
||||||
|
# DNS packet at once. First, we must remove the original DNSQR, since this contains the original request
|
||||||
|
del packet["DNS"].qd
|
||||||
|
|
||||||
|
# Once the DNSQR is removed, scapy automatically sets the qdcount to 0. Adjust it to 2
|
||||||
|
packet["DNS"].qdcount = 2
|
||||||
|
|
||||||
|
# Extract the DNS header standalone now for building
|
||||||
|
dns_header = bytes(packet["DNS"])
|
||||||
|
|
||||||
|
dns_packet = DNS(dns_header + dns_qr1 + dns_qr2)
|
||||||
|
|
||||||
|
del packet["DNS"]
|
||||||
|
packet = packet / dns_packet
|
||||||
|
|
||||||
|
# Since the size and data of the packet have changed, force scapy to recalculate the important fields
|
||||||
|
# in below layers, if applicable
|
||||||
|
if packet.haslayer("IP"):
|
||||||
|
del packet["IP"].chksum
|
||||||
|
del packet["IP"].len
|
||||||
|
if packet.haslayer("UDP"):
|
||||||
|
del packet["UDP"].chksum
|
||||||
|
del packet["UDP"].len
|
||||||
|
|
||||||
|
return packet
|
|
@ -0,0 +1,48 @@
|
||||||
|
from layers.layer import Layer
|
||||||
|
from scapy.all import DNSQR
|
||||||
|
|
||||||
|
class DNSQRLayer(Layer):
|
||||||
|
"""
|
||||||
|
Defines an interface to access DNSQR header fields.
|
||||||
|
"""
|
||||||
|
name = "DNSQR"
|
||||||
|
protocol = DNSQR
|
||||||
|
_fields = [
|
||||||
|
"qname",
|
||||||
|
"qtype",
|
||||||
|
"qclass"
|
||||||
|
]
|
||||||
|
fields = _fields
|
||||||
|
|
||||||
|
def __init__(self, layer):
|
||||||
|
"""
|
||||||
|
Initializes the DNS layer.
|
||||||
|
"""
|
||||||
|
Layer.__init__(self, layer)
|
||||||
|
self.getters = {
|
||||||
|
"qname" : self.get_qname
|
||||||
|
}
|
||||||
|
self.generators = {
|
||||||
|
"qname" : self.gen_qname
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_qname(self, field):
|
||||||
|
"""
|
||||||
|
Returns decoded qname from packet.
|
||||||
|
"""
|
||||||
|
return self.layer.qname.decode('utf-8')
|
||||||
|
|
||||||
|
def gen_qname(self, field):
|
||||||
|
"""
|
||||||
|
Generates domain name.
|
||||||
|
"""
|
||||||
|
return "example.com."
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def name_matches(cls, name):
|
||||||
|
"""
|
||||||
|
Scapy returns the name of DNSQR as _both_ DNSQR and "DNS Question Record",
|
||||||
|
which breaks parsing. Override the name_matches method to handle that case
|
||||||
|
here.
|
||||||
|
"""
|
||||||
|
return name.upper() in ["DNSQR", "DNS QUESTION RECORD"]
|
|
@ -0,0 +1,103 @@
|
||||||
|
import random
|
||||||
|
|
||||||
|
from layers.layer import Layer
|
||||||
|
from scapy.all import IP, fuzz, RandIP
|
||||||
|
|
||||||
|
class IPLayer(Layer):
|
||||||
|
"""
|
||||||
|
Defines an interface to access IP header fields.
|
||||||
|
"""
|
||||||
|
name = "IP"
|
||||||
|
protocol = IP
|
||||||
|
_fields = [
|
||||||
|
'version',
|
||||||
|
'ihl',
|
||||||
|
'tos',
|
||||||
|
'len',
|
||||||
|
'id',
|
||||||
|
'flags',
|
||||||
|
'frag',
|
||||||
|
'ttl',
|
||||||
|
'proto',
|
||||||
|
'chksum',
|
||||||
|
'src',
|
||||||
|
'dst',
|
||||||
|
'load'
|
||||||
|
]
|
||||||
|
fields = _fields
|
||||||
|
|
||||||
|
def __init__(self, layer):
|
||||||
|
"""
|
||||||
|
Initializes the IP layer.
|
||||||
|
"""
|
||||||
|
Layer.__init__(self, layer)
|
||||||
|
self.getters = {
|
||||||
|
"flags" : self.get_flags,
|
||||||
|
"load" : self.get_load
|
||||||
|
}
|
||||||
|
self.setters = {
|
||||||
|
"flags" : self.set_flags,
|
||||||
|
"load" : self.set_load
|
||||||
|
}
|
||||||
|
self.generators = {
|
||||||
|
"src" : self.gen_ip,
|
||||||
|
"dst" : self.gen_ip,
|
||||||
|
"chksum" : self.gen_chksum,
|
||||||
|
"len" : self.gen_len,
|
||||||
|
"load" : self.gen_load,
|
||||||
|
"flags" : self.gen_flags
|
||||||
|
}
|
||||||
|
|
||||||
|
def gen_len(self, field):
|
||||||
|
"""
|
||||||
|
Generates a valid IP length. Scapy breaks if the length is set to 0, so
|
||||||
|
return a random int starting at 1.
|
||||||
|
"""
|
||||||
|
return random.randint(1, 500)
|
||||||
|
|
||||||
|
def gen_chksum(self, field):
|
||||||
|
"""
|
||||||
|
Generates a checksum.
|
||||||
|
"""
|
||||||
|
return random.randint(1, 65535)
|
||||||
|
|
||||||
|
def gen_ip(self, field):
|
||||||
|
"""
|
||||||
|
Generates an IP address.
|
||||||
|
"""
|
||||||
|
return RandIP()._fix()
|
||||||
|
|
||||||
|
def get_flags(self, field):
|
||||||
|
"""
|
||||||
|
Retrieves flags as a string.
|
||||||
|
"""
|
||||||
|
return str(self.layer.flags)
|
||||||
|
|
||||||
|
def set_flags(self, packet, field, value):
|
||||||
|
"""
|
||||||
|
Sets the flags field. There is a bug in scapy, if you retrieve an empty
|
||||||
|
flags field, it will return "", but you cannot set this value back.
|
||||||
|
To reproduce this bug:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> setattr(IP(), "flags", str(IP().flags)) # raises a ValueError
|
||||||
|
|
||||||
|
To handle this case, this method converts empty string to zero so that
|
||||||
|
it can be safely stored.
|
||||||
|
"""
|
||||||
|
if value == "":
|
||||||
|
value = 0
|
||||||
|
self.layer.flags = value
|
||||||
|
|
||||||
|
def gen_flags(self, field):
|
||||||
|
"""
|
||||||
|
Generates random valid flags.
|
||||||
|
"""
|
||||||
|
sample = fuzz(self.protocol())
|
||||||
|
|
||||||
|
# Since scapy lazily evaluates fuzzing, we first must set a
|
||||||
|
# legitimate value for scapy to evaluate what combination of flags it is
|
||||||
|
sample.flags = sample.flags
|
||||||
|
|
||||||
|
return str(sample.flags)
|
|
@ -0,0 +1,197 @@
|
||||||
|
import binascii
|
||||||
|
import copy
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
import os
|
||||||
|
import urllib.parse
|
||||||
|
|
||||||
|
from scapy.all import IP, RandIP, UDP, DNS, DNSQR, Raw, TCP, fuzz
|
||||||
|
|
||||||
|
class Layer():
|
||||||
|
"""
|
||||||
|
Base class defining a Geneva packet layer.
|
||||||
|
"""
|
||||||
|
protocol = None
|
||||||
|
|
||||||
|
def __init__(self, layer):
|
||||||
|
"""
|
||||||
|
Initializes this layer.
|
||||||
|
"""
|
||||||
|
self.layer = layer
|
||||||
|
# No custom setter, getters, generators, or parsers are needed by default
|
||||||
|
self.setters = {}
|
||||||
|
self.getters = {}
|
||||||
|
self.generators = {}
|
||||||
|
self.parsers = {}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def reset_restrictions(cls):
|
||||||
|
"""
|
||||||
|
Resets field restrictions placed on this layer.
|
||||||
|
"""
|
||||||
|
cls.fields = cls._fields
|
||||||
|
|
||||||
|
def get_next_layer(self):
|
||||||
|
"""
|
||||||
|
Given the current layer returns the next layer beneath us.
|
||||||
|
"""
|
||||||
|
if len(self.layer.layers()) == 1:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return self.layer[1]
|
||||||
|
|
||||||
|
def get_random(self):
|
||||||
|
"""
|
||||||
|
Retreives a random field and value.
|
||||||
|
"""
|
||||||
|
field = random.choice(self.fields)
|
||||||
|
return field, self.get(field)
|
||||||
|
|
||||||
|
def gen_random(self):
|
||||||
|
"""
|
||||||
|
Generates a random field and value.
|
||||||
|
"""
|
||||||
|
assert self.fields, "Layer %s doesn't have any fields" % str(self)
|
||||||
|
field = random.choice(self.fields)
|
||||||
|
return field, self.gen(field)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def name_matches(cls, name):
|
||||||
|
"""
|
||||||
|
Checks if given name matches this layer name.
|
||||||
|
"""
|
||||||
|
return name.upper() == cls.name.upper()
|
||||||
|
|
||||||
|
def get(self, field):
|
||||||
|
"""
|
||||||
|
Retrieves the value from a given field.
|
||||||
|
"""
|
||||||
|
assert field in self.fields
|
||||||
|
if field in self.getters:
|
||||||
|
return self.getters[field](field)
|
||||||
|
|
||||||
|
# Dual field accessors are fields that require two pieces of information
|
||||||
|
# to retrieve them (for example, "options-eol"). These are delimited by
|
||||||
|
# a dash "-".
|
||||||
|
base = field.split("-")[0]
|
||||||
|
if "-" in field and base in self.getters:
|
||||||
|
return self.getters[base](field)
|
||||||
|
|
||||||
|
return getattr(self.layer, field)
|
||||||
|
|
||||||
|
def set(self, packet, field, value):
|
||||||
|
"""
|
||||||
|
Sets the value for a given field.
|
||||||
|
"""
|
||||||
|
assert field in self.fields
|
||||||
|
base = field.split("-")[0]
|
||||||
|
if field in self.setters:
|
||||||
|
self.setters[field](packet, field, value)
|
||||||
|
|
||||||
|
# Dual field accessors are fields that require two pieces of information
|
||||||
|
# to retrieve them (for example, "options-eol"). These are delimited by
|
||||||
|
# a dash "-".
|
||||||
|
elif "-" in field and base in self.setters:
|
||||||
|
self.setters[base](packet, field, value)
|
||||||
|
else:
|
||||||
|
setattr(self.layer, field, value)
|
||||||
|
|
||||||
|
# Request the packet be reparsed to confirm the value is stable
|
||||||
|
# XXX Temporarily disabling the reconstitution check due to scapy bug (#2034)
|
||||||
|
#assert bytes(self.protocol(bytes(self.layer))) == bytes(self.layer)
|
||||||
|
|
||||||
|
def gen(self, field):
|
||||||
|
"""
|
||||||
|
Generates a value for this field.
|
||||||
|
"""
|
||||||
|
assert field in self.fields
|
||||||
|
if field in self.generators:
|
||||||
|
return self.generators[field](field)
|
||||||
|
|
||||||
|
# Dual field accessors are fields that require two pieces of information
|
||||||
|
# to retrieve them (for example, "options-eol"). These are delimited by
|
||||||
|
# a dash "-".
|
||||||
|
base = field.split("-")[0]
|
||||||
|
if "-" in field and base in self.generators:
|
||||||
|
return self.generators[base](field)
|
||||||
|
|
||||||
|
sample = fuzz(self.protocol())
|
||||||
|
|
||||||
|
new_value = getattr(sample, field)
|
||||||
|
if new_value == None:
|
||||||
|
new_value = 0
|
||||||
|
elif type(new_value) != int:
|
||||||
|
new_value = new_value._fix()
|
||||||
|
|
||||||
|
return new_value
|
||||||
|
|
||||||
|
def parse(self, field, value):
|
||||||
|
"""
|
||||||
|
Parses the given value for a given field. This is useful for fields whose
|
||||||
|
value cannot be represented in a string type easily - it lets us define
|
||||||
|
a common string representation for the strategy, and parse it back into
|
||||||
|
a real value here.
|
||||||
|
"""
|
||||||
|
assert field in self.fields
|
||||||
|
if field in self.parsers:
|
||||||
|
return self.parsers[field](field, value)
|
||||||
|
|
||||||
|
# Dual field accessors are fields that require two pieces of information
|
||||||
|
# to retrieve them (for example, "options-eol"). These are delimited by
|
||||||
|
# a dash "-".
|
||||||
|
base = field.split("-")[0]
|
||||||
|
if "-" in field and base in self.parsers:
|
||||||
|
return self.parsers[base](field, value)
|
||||||
|
|
||||||
|
try:
|
||||||
|
parsed = int(value)
|
||||||
|
except ValueError:
|
||||||
|
parsed = value
|
||||||
|
|
||||||
|
return parsed
|
||||||
|
|
||||||
|
def get_load(self, field):
|
||||||
|
"""
|
||||||
|
Helper method to retrieve load, as scapy doesn't recognize 'load' as
|
||||||
|
a regular field properly.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
load = self.layer.payload.load
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
load = self.layer.load
|
||||||
|
except AttributeError:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
if not load:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
return urllib.parse.quote(load.decode('utf-8', 'ignore'))
|
||||||
|
|
||||||
|
def set_load(self, packet, field, value):
|
||||||
|
"""
|
||||||
|
Helper method to retrieve load, as scapy doesn't recognize 'load' as
|
||||||
|
a field properly.
|
||||||
|
"""
|
||||||
|
if packet.haslayer("IP"):
|
||||||
|
del packet["IP"].len
|
||||||
|
|
||||||
|
value = urllib.parse.unquote(value)
|
||||||
|
|
||||||
|
value = value.encode('utf-8')
|
||||||
|
dns_payload = b"\x009ib\x81\x80\x00\x01\x00\x01\x00\x00\x00\x01\x08faceface\x03com\x00\x00\x01\x00\x01\xc0\x0c\x00\x01\x00\x01\x00\x00\x01+\x00\x04\xc7\xbf2I\x00\x00)\x02\x00\x00\x00\x00\x00\x00\x00"
|
||||||
|
http_payload = b"GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n"
|
||||||
|
|
||||||
|
value = value.replace(b"__DNS_REQUEST__", dns_payload)
|
||||||
|
value = value.replace(b"__HTTP_REQUEST__", http_payload)
|
||||||
|
|
||||||
|
self.layer.payload = Raw(value)
|
||||||
|
|
||||||
|
def gen_load(self, field):
|
||||||
|
"""
|
||||||
|
Helper method to generate a random load, as scapy doesn't recognize 'load'
|
||||||
|
as a field properly.
|
||||||
|
"""
|
||||||
|
load = ''.join([random.choice(string.ascii_lowercase + string.digits) for k in range(10)])
|
||||||
|
return random.choice(["", "__DNS_REQUEST__", "__HTTP_REQUEST__", urllib.parse.quote(load)])
|
|
@ -1,15 +1,19 @@
|
||||||
import copy
|
import copy
|
||||||
import random
|
import random
|
||||||
|
|
||||||
import actions.layer
|
import layers.layer
|
||||||
|
import layers.ip_layer
|
||||||
|
import layers.tcp_layer
|
||||||
|
import layers.udp_layer
|
||||||
|
import layers.dns_layer
|
||||||
|
import layers.dnsqr_layer
|
||||||
|
|
||||||
_SUPPORTED_LAYERS = [
|
_SUPPORTED_LAYERS = [
|
||||||
actions.layer.IPLayer,
|
layers.ip_layer.IPLayer,
|
||||||
actions.layer.TCPLayer,
|
layers.tcp_layer.TCPLayer,
|
||||||
actions.layer.UDPLayer,
|
layers.udp_layer.UDPLayer,
|
||||||
actions.layer.DNSLayer,
|
layers.dns_layer.DNSLayer,
|
||||||
actions.layer.DNSQRLayer
|
layers.dnsqr_layer.DNSQRLayer
|
||||||
]
|
]
|
||||||
SUPPORTED_LAYERS = _SUPPORTED_LAYERS
|
SUPPORTED_LAYERS = _SUPPORTED_LAYERS
|
||||||
|
|
||||||
|
@ -326,6 +330,6 @@ class Packet():
|
||||||
"""
|
"""
|
||||||
Performs DNS decompression, if applicable. Returns a new packet.
|
Performs DNS decompression, if applicable. Returns a new packet.
|
||||||
"""
|
"""
|
||||||
self.packet = actions.layer.DNSLayer.dns_decompress(self.packet, logger)
|
self.packet = layers.dns_layer.DNSLayer.dns_decompress(self.packet, logger)
|
||||||
self.layers = self.setup_layers()
|
self.layers = self.setup_layers()
|
||||||
return self
|
return self
|
|
@ -0,0 +1,10 @@
|
||||||
|
from layers.layer import Layer
|
||||||
|
|
||||||
|
class RawLayer(Layer):
|
||||||
|
"""
|
||||||
|
Defines an interface for the scapy Raw layer.
|
||||||
|
"""
|
||||||
|
name = "Raw"
|
||||||
|
protocol = Raw
|
||||||
|
_fields = []
|
||||||
|
fields = []
|
|
@ -0,0 +1,285 @@
|
||||||
|
import random
|
||||||
|
import binascii
|
||||||
|
from layers.layer import Layer
|
||||||
|
from scapy.all import TCP, fuzz
|
||||||
|
|
||||||
|
class TCPLayer(Layer):
|
||||||
|
"""
|
||||||
|
Defines an interface to access TCP header fields.
|
||||||
|
"""
|
||||||
|
name = "TCP"
|
||||||
|
protocol = TCP
|
||||||
|
_fields = [
|
||||||
|
'sport',
|
||||||
|
'dport',
|
||||||
|
'seq',
|
||||||
|
'ack',
|
||||||
|
'dataofs',
|
||||||
|
'reserved',
|
||||||
|
'flags',
|
||||||
|
'window',
|
||||||
|
'chksum',
|
||||||
|
'urgptr',
|
||||||
|
'load',
|
||||||
|
'options-eol',
|
||||||
|
'options-nop',
|
||||||
|
'options-mss',
|
||||||
|
'options-wscale',
|
||||||
|
'options-sackok',
|
||||||
|
'options-sack',
|
||||||
|
'options-timestamp',
|
||||||
|
'options-altchksum',
|
||||||
|
'options-altchksumopt',
|
||||||
|
'options-md5header',
|
||||||
|
'options-uto'
|
||||||
|
]
|
||||||
|
fields = _fields
|
||||||
|
|
||||||
|
options_names = {
|
||||||
|
"eol": 0,
|
||||||
|
"nop": 1,
|
||||||
|
"mss": 2,
|
||||||
|
"wscale": 3,
|
||||||
|
"sackok": 4,
|
||||||
|
"sack": 5,
|
||||||
|
#"echo" : 6,
|
||||||
|
#"echo_reply" : 7,
|
||||||
|
"timestamp": 8,
|
||||||
|
"altchksum": 14,
|
||||||
|
"altchksumopt": 15,
|
||||||
|
"md5header": 19,
|
||||||
|
#"quick_start" : 27,
|
||||||
|
"uto": 28
|
||||||
|
#"authentication": 29,
|
||||||
|
#"experiment": 254
|
||||||
|
}
|
||||||
|
|
||||||
|
# Each entry is Kind: length
|
||||||
|
options_length = {
|
||||||
|
0: 0, # EOL
|
||||||
|
1: 0, # NOP
|
||||||
|
2: 2, # MSS
|
||||||
|
3: 1, # WScale
|
||||||
|
4: 0, # SAckOK
|
||||||
|
5: 0, # SAck
|
||||||
|
6: 4, # Echo
|
||||||
|
7: 4, # Echo Reply
|
||||||
|
8: 8, # Timestamp
|
||||||
|
14: 3, # AltChkSum
|
||||||
|
15: 0, # AltChkSumOpt
|
||||||
|
19: 16, # MD5header Option
|
||||||
|
27: 6, # Quick-Start response
|
||||||
|
28: 2, # User Timeout Option
|
||||||
|
29: 4, # TCP Authentication Option
|
||||||
|
254: 8, # Experiment
|
||||||
|
|
||||||
|
}
|
||||||
|
# Required by scapy
|
||||||
|
scapy_options = {
|
||||||
|
0: "EOL",
|
||||||
|
1: "NOP",
|
||||||
|
2: "MSS",
|
||||||
|
3: "WScale",
|
||||||
|
4: "SAckOK",
|
||||||
|
5: "SAck",
|
||||||
|
8: "Timestamp",
|
||||||
|
14: "AltChkSum",
|
||||||
|
15: "AltChkSumOpt",
|
||||||
|
28: "UTO",
|
||||||
|
# 254:"Experiment" # scapy has two versions of this, so it doesn't work
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, layer):
|
||||||
|
"""
|
||||||
|
Initializes the TCP layer.
|
||||||
|
"""
|
||||||
|
Layer.__init__(self, layer)
|
||||||
|
# Special methods to help access fields that cannot be accessed normally
|
||||||
|
self.getters = {
|
||||||
|
'load' : self.get_load,
|
||||||
|
'options' : self.get_options
|
||||||
|
}
|
||||||
|
self.setters = {
|
||||||
|
'load' : self.set_load,
|
||||||
|
'options' : self.set_options
|
||||||
|
}
|
||||||
|
# Special methods to help generate fields that cannot be generated normally
|
||||||
|
self.generators = {
|
||||||
|
'load' : self.gen_load,
|
||||||
|
'dataofs' : self.gen_dataofs,
|
||||||
|
'flags' : self.gen_flags,
|
||||||
|
'chksum' : self.gen_chksum,
|
||||||
|
'options' : self.gen_options,
|
||||||
|
'window' : self.gen_window
|
||||||
|
}
|
||||||
|
|
||||||
|
def gen_window(self, field):
|
||||||
|
"""
|
||||||
|
Generates a window size.
|
||||||
|
"""
|
||||||
|
return random.choice(range(10, 200, 10))
|
||||||
|
|
||||||
|
def gen_chksum(self, field):
|
||||||
|
"""
|
||||||
|
Generates a checksum.
|
||||||
|
"""
|
||||||
|
return random.randint(1, 65535)
|
||||||
|
|
||||||
|
def gen_dataofs(self, field):
|
||||||
|
"""
|
||||||
|
Generates a valid value for the data offset field.
|
||||||
|
"""
|
||||||
|
# Dataofs is a 4 bit header, so a max of 15
|
||||||
|
return random.randint(1, 15)
|
||||||
|
|
||||||
|
def gen_flags(self, field):
|
||||||
|
"""
|
||||||
|
Generates a random set of flags. 50% of the time it picks randomly from
|
||||||
|
a list of real flags, otherwise it returns fuzzed flags.
|
||||||
|
"""
|
||||||
|
if random.random() < 0.5:
|
||||||
|
return random.choice(['S', 'A', 'SA', 'PA', 'FA', 'R', 'P', 'F', 'RA', ''])
|
||||||
|
else:
|
||||||
|
sample = fuzz(self.protocol())
|
||||||
|
# Since scapy lazily evaluates fuzzing, we first must set a
|
||||||
|
# legitimate value for scapy to evaluate what combination of flags it is
|
||||||
|
sample.flags = sample.flags
|
||||||
|
return str(sample.flags)
|
||||||
|
|
||||||
|
def get_options(self, field):
|
||||||
|
"""
|
||||||
|
Helper method to retrieve options.
|
||||||
|
"""
|
||||||
|
base, req_option = field.split("-")
|
||||||
|
assert base == "options", "get_options can only be used to fetch options."
|
||||||
|
option_type = self.option_str_to_int(req_option)
|
||||||
|
i = 0
|
||||||
|
# First, check if the option is already present in the packet
|
||||||
|
for option in self.layer.options:
|
||||||
|
# Scapy may try to be helpful and return the string of the option
|
||||||
|
next_option = self.option_str_to_int(option[0])
|
||||||
|
if option_type == next_option:
|
||||||
|
_name, value = self.layer.options[i]
|
||||||
|
# Some options (timestamp, checksums, nop) store their value in a
|
||||||
|
# tuple.
|
||||||
|
if isinstance(value, tuple):
|
||||||
|
# Scapy returns values in any of these types
|
||||||
|
if value in [None, b'', ()]:
|
||||||
|
return ''
|
||||||
|
value = value[0]
|
||||||
|
if value in [None, b'', ()]:
|
||||||
|
return ''
|
||||||
|
if req_option == "md5header":
|
||||||
|
return binascii.hexlify(value).decode("utf-8")
|
||||||
|
|
||||||
|
return value
|
||||||
|
i += 1
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def set_options(self, packet, field, value):
|
||||||
|
"""
|
||||||
|
Helper method to set options.
|
||||||
|
"""
|
||||||
|
base, option = field.split("-")
|
||||||
|
assert base == "options", "Must use an options field with set_options"
|
||||||
|
|
||||||
|
option_type = self.option_str_to_int(option)
|
||||||
|
if type(value) == str:
|
||||||
|
# Prepare the value for storage in the packet
|
||||||
|
value = binascii.unhexlify(value)
|
||||||
|
|
||||||
|
# Scapy requires these options to be a tuple - since evaling this
|
||||||
|
# is not yet supported, for now, SAck will always be an empty tuple
|
||||||
|
if option in ["sack"]:
|
||||||
|
value = ()
|
||||||
|
# These options must be set as integers - if they didn't exist, they can
|
||||||
|
# be added like this
|
||||||
|
if option in ["timestamp", "mss", "wscale", "altchksum", "uto"] and not value:
|
||||||
|
value = 0
|
||||||
|
i = 0
|
||||||
|
# First, check if the option is already present in the packet
|
||||||
|
for option in self.layer.options:
|
||||||
|
# Scapy may try to be helpful and return the string of the option
|
||||||
|
next_option = self.option_str_to_int(option[0])
|
||||||
|
|
||||||
|
if option_type == next_option:
|
||||||
|
packet["TCP"].options[i] = self.format_option(option_type, value)
|
||||||
|
break
|
||||||
|
i += 1
|
||||||
|
# If we didn't break, the option doesn't exist in the packet currently.
|
||||||
|
else:
|
||||||
|
old_options_array = packet["TCP"].options
|
||||||
|
old_options_array.append(self.format_option(option_type, value))
|
||||||
|
packet["TCP"].options = old_options_array
|
||||||
|
|
||||||
|
# Let scapy recalculate the required values
|
||||||
|
del self.layer.chksum
|
||||||
|
del self.layer.dataofs
|
||||||
|
if packet.haslayer("IP"):
|
||||||
|
del packet["IP"].chksum
|
||||||
|
del packet["IP"].len
|
||||||
|
return True
|
||||||
|
|
||||||
|
def gen_options(self, field):
|
||||||
|
"""
|
||||||
|
Helper method to set options.
|
||||||
|
"""
|
||||||
|
_, option = field.split("-")
|
||||||
|
option_num = self.options_names[option]
|
||||||
|
length = self.options_length[option_num]
|
||||||
|
|
||||||
|
data = b''
|
||||||
|
if length > 0:
|
||||||
|
data = os.urandom(length)
|
||||||
|
data = binascii.hexlify(data).decode()
|
||||||
|
# MSS must be a 2-byte int
|
||||||
|
if option_num == 2:
|
||||||
|
data = random.randint(0, 65535)
|
||||||
|
# WScale must be a 1-byte int
|
||||||
|
elif option_num == 3:
|
||||||
|
data = random.randint(0, 255)
|
||||||
|
# Timestamp must be an int
|
||||||
|
elif option_num == 8:
|
||||||
|
data = random.randint(0, 4294967294)
|
||||||
|
elif option_num == 14:
|
||||||
|
data = random.randint(0, 255)
|
||||||
|
elif option_num == 28:
|
||||||
|
data = random.randint(0, 255)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def option_str_to_int(self, option):
|
||||||
|
"""
|
||||||
|
Takes a string representation of an option and returns the option integer code.
|
||||||
|
"""
|
||||||
|
if type(option) == int:
|
||||||
|
return option
|
||||||
|
|
||||||
|
assert "-" not in option, "Must be given specific option: %s." % option
|
||||||
|
|
||||||
|
for val in self.scapy_options:
|
||||||
|
if self.scapy_options[val].lower() == option.lower():
|
||||||
|
return val
|
||||||
|
|
||||||
|
if " " in option:
|
||||||
|
option = option.replace(" ", "_").lower()
|
||||||
|
|
||||||
|
if option.lower() in self.options_names:
|
||||||
|
return self.options_names[option.lower()]
|
||||||
|
|
||||||
|
def format_option(self, options_int, value):
|
||||||
|
"""
|
||||||
|
Formats the options so they will work with scapy.
|
||||||
|
"""
|
||||||
|
# NOPs
|
||||||
|
if options_int == 1:
|
||||||
|
return (self.scapy_options[options_int], ())
|
||||||
|
elif options_int in [5]:
|
||||||
|
return (self.scapy_options[options_int], value)
|
||||||
|
# Timestamp
|
||||||
|
elif options_int in [8, 14]:
|
||||||
|
return (self.scapy_options[options_int], (value, 0))
|
||||||
|
elif options_int in self.scapy_options:
|
||||||
|
return (self.scapy_options[options_int], value)
|
||||||
|
else:
|
||||||
|
return (options_int, value)
|
|
@ -0,0 +1,32 @@
|
||||||
|
from layers.layer import Layer
|
||||||
|
from scapy.all import UDP
|
||||||
|
|
||||||
|
class UDPLayer(Layer):
|
||||||
|
"""
|
||||||
|
Defines an interface to access UDP header fields.
|
||||||
|
"""
|
||||||
|
name = "UDP"
|
||||||
|
protocol = UDP
|
||||||
|
_fields = [
|
||||||
|
"sport",
|
||||||
|
"dport",
|
||||||
|
"chksum",
|
||||||
|
"len",
|
||||||
|
"load"
|
||||||
|
]
|
||||||
|
fields = _fields
|
||||||
|
|
||||||
|
def __init__(self, layer):
|
||||||
|
"""
|
||||||
|
Initializes the UDP layer.
|
||||||
|
"""
|
||||||
|
Layer.__init__(self, layer)
|
||||||
|
self.getters = {
|
||||||
|
'load' : self.get_load,
|
||||||
|
}
|
||||||
|
self.setters = {
|
||||||
|
'load' : self.set_load,
|
||||||
|
}
|
||||||
|
self.generators = {
|
||||||
|
'load' : self.gen_load,
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ import os
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
import evolve
|
import evolve
|
||||||
import actions.packet
|
import layers.packet
|
||||||
|
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
|
@ -39,7 +39,7 @@ def reset_packet_restrictions():
|
||||||
"""
|
"""
|
||||||
Autouse feature to make sure tests have a clean slate for processing.
|
Autouse feature to make sure tests have a clean slate for processing.
|
||||||
"""
|
"""
|
||||||
actions.packet.Packet.reset_restrictions()
|
layers.packet.Packet.reset_restrictions()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.tryfirst
|
@pytest.mark.tryfirst
|
||||||
|
|
|
@ -3,7 +3,7 @@ import sys
|
||||||
sys.path.append("..")
|
sys.path.append("..")
|
||||||
|
|
||||||
import actions.duplicate
|
import actions.duplicate
|
||||||
import actions.packet
|
import layers.packet
|
||||||
import actions.strategy
|
import actions.strategy
|
||||||
import actions.utils
|
import actions.utils
|
||||||
import evolve
|
import evolve
|
||||||
|
@ -18,7 +18,7 @@ def test_duplicate(logger):
|
||||||
duplicate = actions.duplicate.DuplicateAction()
|
duplicate = actions.duplicate.DuplicateAction()
|
||||||
assert str(duplicate) == "duplicate", "Duplicate returned incorrect string representation: %s" % str(duplicate)
|
assert str(duplicate) == "duplicate", "Duplicate returned incorrect string representation: %s" % str(duplicate)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
||||||
packet1, packet2 = duplicate.run(packet, logger)
|
packet1, packet2 = duplicate.run(packet, logger)
|
||||||
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
||||||
duplicate.mutate()
|
duplicate.mutate()
|
||||||
|
|
|
@ -8,7 +8,7 @@ from scapy.all import *
|
||||||
BASEPATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
BASEPATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
sys.path.append(BASEPATH)
|
sys.path.append(BASEPATH)
|
||||||
|
|
||||||
import actions.packet
|
import layers.packet
|
||||||
import engine
|
import engine
|
||||||
|
|
||||||
def test_engine():
|
def test_engine():
|
||||||
|
@ -55,7 +55,7 @@ def test_nat_unit():
|
||||||
"forward_ip": "3.3.3.3"
|
"forward_ip": "3.3.3.3"
|
||||||
}
|
}
|
||||||
pkt = IP(src="1.1.1.1", dst="2.2.2.2")/TCP()/Raw("test")
|
pkt = IP(src="1.1.1.1", dst="2.2.2.2")/TCP()/Raw("test")
|
||||||
packet = actions.packet.Packet(pkt)
|
packet = layers.packet.Packet(pkt)
|
||||||
eng = engine.Engine(80, "", forwarder=forwarder)
|
eng = engine.Engine(80, "", forwarder=forwarder)
|
||||||
eng.do_nat(packet)
|
eng.do_nat(packet)
|
||||||
packet[IP].src == "2.2.2.2"
|
packet[IP].src == "2.2.2.2"
|
||||||
|
|
|
@ -12,7 +12,7 @@ import common
|
||||||
import evolve
|
import evolve
|
||||||
import evaluator
|
import evaluator
|
||||||
import actions.utils
|
import actions.utils
|
||||||
import actions.packet
|
import layers.packet
|
||||||
from actions.tamper import TamperAction
|
from actions.tamper import TamperAction
|
||||||
from scapy.all import IP, TCP, UDP
|
from scapy.all import IP, TCP, UDP
|
||||||
import random
|
import random
|
||||||
|
@ -50,7 +50,7 @@ def test_disable_single_action(logger):
|
||||||
"""
|
"""
|
||||||
Tests disabling a single action
|
Tests disabling a single action
|
||||||
"""
|
"""
|
||||||
actions.packet.Packet.reset_restrictions()
|
layers.packet.Packet.reset_restrictions()
|
||||||
try:
|
try:
|
||||||
logger.setLevel("ERROR")
|
logger.setLevel("ERROR")
|
||||||
actions.action.ACTION_CACHE={}
|
actions.action.ACTION_CACHE={}
|
||||||
|
@ -66,14 +66,14 @@ def test_disable_single_action(logger):
|
||||||
actions.action.ACTION_CACHE["in"] = {}
|
actions.action.ACTION_CACHE["in"] = {}
|
||||||
actions.action.ACTION_CACHE["out"] = {}
|
actions.action.ACTION_CACHE["out"] = {}
|
||||||
finally:
|
finally:
|
||||||
actions.packet.Packet.reset_restrictions()
|
layers.packet.Packet.reset_restrictions()
|
||||||
|
|
||||||
|
|
||||||
def test_disable_multiple_actions(logger):
|
def test_disable_multiple_actions(logger):
|
||||||
"""
|
"""
|
||||||
Tests disabling multiple actions
|
Tests disabling multiple actions
|
||||||
"""
|
"""
|
||||||
actions.packet.Packet.reset_restrictions()
|
layers.packet.Packet.reset_restrictions()
|
||||||
try:
|
try:
|
||||||
logger.setLevel("ERROR")
|
logger.setLevel("ERROR")
|
||||||
actions.action.ACTION_CACHE={}
|
actions.action.ACTION_CACHE={}
|
||||||
|
@ -95,7 +95,7 @@ def test_disable_multiple_actions(logger):
|
||||||
actions.action.ACTION_CACHE["in"] = {}
|
actions.action.ACTION_CACHE["in"] = {}
|
||||||
actions.action.ACTION_CACHE["out"] = {}
|
actions.action.ACTION_CACHE["out"] = {}
|
||||||
finally:
|
finally:
|
||||||
actions.packet.Packet.reset_restrictions()
|
layers.packet.Packet.reset_restrictions()
|
||||||
|
|
||||||
|
|
||||||
def assert_only(ind, field):
|
def assert_only(ind, field):
|
||||||
|
@ -160,7 +160,7 @@ def test_disable_fields(logger, use_canary):
|
||||||
p.mutate(logger)
|
p.mutate(logger)
|
||||||
assert_only(p, "ack")
|
assert_only(p, "ack")
|
||||||
|
|
||||||
actions.packet.Packet.reset_restrictions()
|
layers.packet.Packet.reset_restrictions()
|
||||||
|
|
||||||
# Restrict evolve to using NOT the dataofs or chksum field in the TCP header
|
# Restrict evolve to using NOT the dataofs or chksum field in the TCP header
|
||||||
evolve.restrict_headers(logger, "TCP,UDP", "", "dataofs,chksum",)
|
evolve.restrict_headers(logger, "TCP,UDP", "", "dataofs,chksum",)
|
||||||
|
@ -194,7 +194,7 @@ def test_disable_fields(logger, use_canary):
|
||||||
assert_not(p, ["dataofs", "chksum"])
|
assert_not(p, ["dataofs", "chksum"])
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
actions.packet.Packet.reset_restrictions()
|
layers.packet.Packet.reset_restrictions()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("use_canary", [True, False], ids=["with_canary", "without_canary"])
|
@pytest.mark.parametrize("use_canary", [True, False], ids=["with_canary", "without_canary"])
|
||||||
|
@ -220,7 +220,7 @@ def test_population_pool(logger, use_canary):
|
||||||
tester = evaluator.Evaluator(cmd, logger)
|
tester = evaluator.Evaluator(cmd, logger)
|
||||||
canary_id = evolve.run_collection_phase(logger, tester)
|
canary_id = evolve.run_collection_phase(logger, tester)
|
||||||
|
|
||||||
actions.packet.Packet.reset_restrictions()
|
layers.packet.Packet.reset_restrictions()
|
||||||
population = []
|
population = []
|
||||||
print("Generating population pool")
|
print("Generating population pool")
|
||||||
# Generate random strategies to initialize the population
|
# Generate random strategies to initialize the population
|
||||||
|
@ -237,7 +237,7 @@ def test_population_pool(logger, use_canary):
|
||||||
IP(src="127.0.0.1", dst="127.0.0.1")/UDP(sport=2222, dport=3333, chksum=0x4444),
|
IP(src="127.0.0.1", dst="127.0.0.1")/UDP(sport=2222, dport=3333, chksum=0x4444),
|
||||||
IP(src="127.0.0.1", dst="127.0.0.1")/UDP(sport=2222, dport=3333, chksum=0x8888)
|
IP(src="127.0.0.1", dst="127.0.0.1")/UDP(sport=2222, dport=3333, chksum=0x8888)
|
||||||
]
|
]
|
||||||
packets = [actions.packet.Packet(packet) for packet in packets]
|
packets = [layers.packet.Packet(packet) for packet in packets]
|
||||||
for generation in range(0, 20):
|
for generation in range(0, 20):
|
||||||
print("Starting fake generation %d" % generation)
|
print("Starting fake generation %d" % generation)
|
||||||
for ind in population:
|
for ind in population:
|
||||||
|
@ -249,7 +249,7 @@ def test_population_pool(logger, use_canary):
|
||||||
print(str(ind))
|
print(str(ind))
|
||||||
print(packet)
|
print(packet)
|
||||||
packet.show()
|
packet.show()
|
||||||
print(actions.packet.SUPPORTED_LAYERS)
|
print(layers.packet.SUPPORTED_LAYERS)
|
||||||
raise
|
raise
|
||||||
for p in population:
|
for p in population:
|
||||||
try:
|
try:
|
||||||
|
@ -305,7 +305,7 @@ def test_mutation(logger):
|
||||||
Tests mutation.
|
Tests mutation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
actions.packet.Packet.reset_restrictions()
|
layers.packet.Packet.reset_restrictions()
|
||||||
population = [actions.utils.parse("[TCP:flags:PA]-| \/", logger)]
|
population = [actions.utils.parse("[TCP:flags:PA]-| \/", logger)]
|
||||||
population[0].in_enabled = False
|
population[0].in_enabled = False
|
||||||
assert population
|
assert population
|
||||||
|
|
|
@ -5,7 +5,7 @@ import sys
|
||||||
sys.path.append("..")
|
sys.path.append("..")
|
||||||
|
|
||||||
import actions.fragment
|
import actions.fragment
|
||||||
import actions.packet
|
import layers.packet
|
||||||
import actions.strategy
|
import actions.strategy
|
||||||
import actions.utils
|
import actions.utils
|
||||||
import evolve
|
import evolve
|
||||||
|
@ -22,7 +22,7 @@ def test_segment(logger):
|
||||||
fragment = actions.fragment.FragmentAction(correct_order=True)
|
fragment = actions.fragment.FragmentAction(correct_order=True)
|
||||||
assert str(fragment) == "fragment{tcp:-1:True}", "Fragment returned incorrect string representation: %s" % str(fragment)
|
assert str(fragment) == "fragment{tcp:-1:True}", "Fragment returned incorrect string representation: %s" % str(fragment)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP()/("data"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP()/("data"))
|
||||||
packet1, packet2 = fragment.run(packet, logger)
|
packet1, packet2 = fragment.run(packet, logger)
|
||||||
|
|
||||||
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
||||||
|
@ -38,7 +38,7 @@ def test_segment_wrap(logger):
|
||||||
fragment = actions.fragment.FragmentAction(correct_order=True)
|
fragment = actions.fragment.FragmentAction(correct_order=True)
|
||||||
assert str(fragment) == "fragment{tcp:-1:True}", "Fragment returned incorrect string representation: %s" % str(fragment)
|
assert str(fragment) == "fragment{tcp:-1:True}", "Fragment returned incorrect string representation: %s" % str(fragment)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP()/("data"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP()/("data"))
|
||||||
packet["TCP"].seq = MAX_UINT-1
|
packet["TCP"].seq = MAX_UINT-1
|
||||||
packet1, packet2 = fragment.run(packet, logger)
|
packet1, packet2 = fragment.run(packet, logger)
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ def test_segment_wrap2(logger):
|
||||||
fragment = actions.fragment.FragmentAction(correct_order=True)
|
fragment = actions.fragment.FragmentAction(correct_order=True)
|
||||||
assert str(fragment) == "fragment{tcp:-1:True}", "Fragment returned incorrect string representation: %s" % str(fragment)
|
assert str(fragment) == "fragment{tcp:-1:True}", "Fragment returned incorrect string representation: %s" % str(fragment)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP()/("data"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP()/("data"))
|
||||||
packet["TCP"].seq = MAX_UINT
|
packet["TCP"].seq = MAX_UINT
|
||||||
packet1, packet2 = fragment.run(packet, logger)
|
packet1, packet2 = fragment.run(packet, logger)
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ def test_segment_wrap3(logger):
|
||||||
fragment = actions.fragment.FragmentAction(correct_order=True)
|
fragment = actions.fragment.FragmentAction(correct_order=True)
|
||||||
assert str(fragment) == "fragment{tcp:-1:True}", "Fragment returned incorrect string representation: %s" % str(fragment)
|
assert str(fragment) == "fragment{tcp:-1:True}", "Fragment returned incorrect string representation: %s" % str(fragment)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP()/("data"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP()/("data"))
|
||||||
packet["TCP"].seq = MAX_UINT-2
|
packet["TCP"].seq = MAX_UINT-2
|
||||||
packet1, packet2 = fragment.run(packet, logger)
|
packet1, packet2 = fragment.run(packet, logger)
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ def test_segment_reverse(logger):
|
||||||
fragment = actions.fragment.FragmentAction(correct_order=False)
|
fragment = actions.fragment.FragmentAction(correct_order=False)
|
||||||
assert str(fragment) == "fragment{tcp:-1:False}", "Fragment returned incorrect string representation: %s" % str(fragment)
|
assert str(fragment) == "fragment{tcp:-1:False}", "Fragment returned incorrect string representation: %s" % str(fragment)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP()/("data"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP()/("data"))
|
||||||
packet1, packet2 = fragment.run(packet, logger)
|
packet1, packet2 = fragment.run(packet, logger)
|
||||||
|
|
||||||
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
||||||
|
@ -114,7 +114,7 @@ def test_odd_fragment(logger):
|
||||||
fragment = actions.fragment.FragmentAction(correct_order=True, segment=False)
|
fragment = actions.fragment.FragmentAction(correct_order=True, segment=False)
|
||||||
assert str(fragment) == "fragment{ip:-1:True}", "Fragment returned incorrect string representation: %s" % str(fragment)
|
assert str(fragment) == "fragment{ip:-1:True}", "Fragment returned incorrect string representation: %s" % str(fragment)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1", proto=0x06)/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("dataisodd"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1", proto=0x06)/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("dataisodd"))
|
||||||
packet1, packet2 = fragment.run(packet, logger)
|
packet1, packet2 = fragment.run(packet, logger)
|
||||||
|
|
||||||
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
||||||
|
@ -132,7 +132,7 @@ def test_custom_fragment(logger):
|
||||||
fragment = actions.fragment.FragmentAction(correct_order=True, fragsize=3, segment=False)
|
fragment = actions.fragment.FragmentAction(correct_order=True, fragsize=3, segment=False)
|
||||||
assert str(fragment) == "fragment{ip:3:True}", "Fragment returned incorrect string representation: %s" % str(fragment)
|
assert str(fragment) == "fragment{ip:3:True}", "Fragment returned incorrect string representation: %s" % str(fragment)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1", proto=0x06)/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("thisissomedata"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1", proto=0x06)/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("thisissomedata"))
|
||||||
packet1, packet2 = fragment.run(packet, logger)
|
packet1, packet2 = fragment.run(packet, logger)
|
||||||
|
|
||||||
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
||||||
|
@ -149,7 +149,7 @@ def test_reverse_fragment(logger):
|
||||||
fragment = actions.fragment.FragmentAction(correct_order=False, fragsize=3, segment=False)
|
fragment = actions.fragment.FragmentAction(correct_order=False, fragsize=3, segment=False)
|
||||||
assert str(fragment) == "fragment{ip:3:False}", "Fragment returned incorrect string representation: %s" % str(fragment)
|
assert str(fragment) == "fragment{ip:3:False}", "Fragment returned incorrect string representation: %s" % str(fragment)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1", proto=0x06)/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("thisissomedata"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1", proto=0x06)/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("thisissomedata"))
|
||||||
packet1, packet2 = fragment.run(packet, logger)
|
packet1, packet2 = fragment.run(packet, logger)
|
||||||
|
|
||||||
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
||||||
|
@ -166,7 +166,7 @@ def test_udp_fragment(logger):
|
||||||
fragment = actions.fragment.FragmentAction(correct_order=False, fragsize=2, segment=False)
|
fragment = actions.fragment.FragmentAction(correct_order=False, fragsize=2, segment=False)
|
||||||
assert str(fragment) == "fragment{ip:2:False}", "Fragment returned incorrect string representation: %s" % str(fragment)
|
assert str(fragment) == "fragment{ip:2:False}", "Fragment returned incorrect string representation: %s" % str(fragment)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1", proto=0x06)/UDP(sport=2222, dport=3333, chksum=0x4444)/("thisissomedata"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1", proto=0x06)/UDP(sport=2222, dport=3333, chksum=0x4444)/("thisissomedata"))
|
||||||
packet1, packet2 = fragment.run(packet, logger)
|
packet1, packet2 = fragment.run(packet, logger)
|
||||||
|
|
||||||
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
||||||
|
@ -183,7 +183,7 @@ def test_mutate(logger):
|
||||||
for _ in range(0, 200):
|
for _ in range(0, 200):
|
||||||
fragment.mutate()
|
fragment.mutate()
|
||||||
fragment.parse(str(fragment), logger)
|
fragment.parse(str(fragment), logger)
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1", proto=0x06)/TCP(sport=2222, dport=3333, chksum=0x4444)/("thisissomedata"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1", proto=0x06)/TCP(sport=2222, dport=3333, chksum=0x4444)/("thisissomedata"))
|
||||||
packet1, packet2 = fragment.run(packet, logger)
|
packet1, packet2 = fragment.run(packet, logger)
|
||||||
|
|
||||||
|
|
||||||
|
@ -211,16 +211,16 @@ def test_parse(logger):
|
||||||
|
|
||||||
fragment = actions.fragment.FragmentAction()
|
fragment = actions.fragment.FragmentAction()
|
||||||
assert fragment.correct_order in [True, False]
|
assert fragment.correct_order in [True, False]
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
||||||
|
|
||||||
strat = actions.utils.parse("[IP:proto:6:0]-tamper{IP:proto:replace:6}(fragment{ip:-1:True}(tamper{TCP:dataofs:replace:8}(duplicate,),tamper{IP:frag:replace:0}),)-| [IP:tos:0:0]-duplicate-| \/", logger)
|
strat = actions.utils.parse("[IP:proto:6:0]-tamper{IP:proto:replace:6}(fragment{ip:-1:True}(tamper{TCP:dataofs:replace:8}(duplicate,),tamper{IP:frag:replace:0}),)-| [IP:tos:0:0]-duplicate-| \/", logger)
|
||||||
strat.act_on_packet(packet, logger)
|
strat.act_on_packet(packet, logger)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/UDP(sport=2222, dport=3333, chksum=0x4444))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/UDP(sport=2222, dport=3333, chksum=0x4444))
|
||||||
strat = actions.utils.parse("[IP:proto:6:0]-tamper{IP:proto:replace:6}(fragment{ip:-1:True}(tamper{TCP:dataofs:replace:8}(duplicate,),tamper{IP:frag:replace:0}),)-| [IP:tos:0:0]-duplicate-| \/", logger)
|
strat = actions.utils.parse("[IP:proto:6:0]-tamper{IP:proto:replace:6}(fragment{ip:-1:True}(tamper{TCP:dataofs:replace:8}(duplicate,),tamper{IP:frag:replace:0}),)-| [IP:tos:0:0]-duplicate-| \/", logger)
|
||||||
strat.act_on_packet(packet, logger)
|
strat.act_on_packet(packet, logger)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, chksum=0x4444))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, chksum=0x4444))
|
||||||
strat = actions.utils.parse("[TCP:urgptr:0]-tamper{TCP:options-altchksumopt:corrupt}(fragment{tcp:-1:True}(tamper{IP:proto:corrupt},tamper{TCP:seq:replace:654077552}),)-| \/", logger)
|
strat = actions.utils.parse("[TCP:urgptr:0]-tamper{TCP:options-altchksumopt:corrupt}(fragment{tcp:-1:True}(tamper{IP:proto:corrupt},tamper{TCP:seq:replace:654077552}),)-| \/", logger)
|
||||||
strat.act_on_packet(packet, logger)
|
strat.act_on_packet(packet, logger)
|
||||||
|
|
||||||
|
@ -245,25 +245,25 @@ def test_fallback(logger):
|
||||||
assert str(fragment) == "fragment{ip:2:False}", "Fragment returned incorrect string representation: %s" % str(fragment)
|
assert str(fragment) == "fragment{ip:2:False}", "Fragment returned incorrect string representation: %s" % str(fragment)
|
||||||
|
|
||||||
fragment.parse("fragment{ip:0:False}", logger)
|
fragment.parse("fragment{ip:0:False}", logger)
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1", proto=0x06)/UDP(sport=2222, dport=3333, chksum=0x4444)/("thisissomedata"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1", proto=0x06)/UDP(sport=2222, dport=3333, chksum=0x4444)/("thisissomedata"))
|
||||||
packet1, packet2 = fragment.run(packet, logger)
|
packet1, packet2 = fragment.run(packet, logger)
|
||||||
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
||||||
assert str(packet1) == str(packet2)
|
assert str(packet1) == str(packet2)
|
||||||
|
|
||||||
fragment.parse("fragment{tcp:-1:False}", logger)
|
fragment.parse("fragment{tcp:-1:False}", logger)
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1", proto=0x06)/UDP(sport=2222, dport=3333, chksum=0x4444)/("thisissomedata"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1", proto=0x06)/UDP(sport=2222, dport=3333, chksum=0x4444)/("thisissomedata"))
|
||||||
packet1, packet2 = fragment.run(packet, logger)
|
packet1, packet2 = fragment.run(packet, logger)
|
||||||
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
||||||
assert str(packet1) == str(packet2)
|
assert str(packet1) == str(packet2)
|
||||||
|
|
||||||
fragment.parse("fragment{tcp:-1:False}", logger)
|
fragment.parse("fragment{tcp:-1:False}", logger)
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1", proto=0x06)/TCP(sport=2222, dport=3333, chksum=0x4444))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1", proto=0x06)/TCP(sport=2222, dport=3333, chksum=0x4444))
|
||||||
packet1, packet2 = fragment.run(packet, logger)
|
packet1, packet2 = fragment.run(packet, logger)
|
||||||
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
||||||
assert str(packet1) == str(packet2)
|
assert str(packet1) == str(packet2)
|
||||||
|
|
||||||
fragment.parse("fragment{ip:-1:False}", logger)
|
fragment.parse("fragment{ip:-1:False}", logger)
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1", proto=0x06))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1", proto=0x06))
|
||||||
packet1, packet2 = fragment.run(packet, logger)
|
packet1, packet2 = fragment.run(packet, logger)
|
||||||
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
||||||
assert str(packet1) == str(packet2)
|
assert str(packet1) == str(packet2)
|
||||||
|
@ -276,7 +276,7 @@ def test_ip_only_fragment(logger):
|
||||||
fragment = actions.fragment.FragmentAction(correct_order=True)
|
fragment = actions.fragment.FragmentAction(correct_order=True)
|
||||||
fragment.parse("fragment{ip:-1:True}", logger)
|
fragment.parse("fragment{ip:-1:True}", logger)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/("datadata11datadata"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/("datadata11datadata"))
|
||||||
packet1, packet2 = fragment.run(packet, logger)
|
packet1, packet2 = fragment.run(packet, logger)
|
||||||
|
|
||||||
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
||||||
|
@ -293,7 +293,7 @@ def test_overlapping_segment():
|
||||||
fragment = actions.fragment.FragmentAction(correct_order=True)
|
fragment = actions.fragment.FragmentAction(correct_order=True)
|
||||||
fragment.parse("fragment{tcp:-1:True:4}", logger)
|
fragment.parse("fragment{tcp:-1:True:4}", logger)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(seq=100)/("datadata11datadata"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(seq=100)/("datadata11datadata"))
|
||||||
packet1, packet2 = fragment.run(packet, logger)
|
packet1, packet2 = fragment.run(packet, logger)
|
||||||
|
|
||||||
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
||||||
|
@ -312,7 +312,7 @@ def test_overlapping_segment_no_overlap():
|
||||||
fragment = actions.fragment.FragmentAction(correct_order=True)
|
fragment = actions.fragment.FragmentAction(correct_order=True)
|
||||||
fragment.parse("fragment{tcp:-1:True:0}", logger)
|
fragment.parse("fragment{tcp:-1:True:0}", logger)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(seq=100)/("datadata11datadata"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(seq=100)/("datadata11datadata"))
|
||||||
packet1, packet2 = fragment.run(packet, logger)
|
packet1, packet2 = fragment.run(packet, logger)
|
||||||
|
|
||||||
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
||||||
|
@ -331,7 +331,7 @@ def test_overlapping_segment_entire_packet():
|
||||||
fragment = actions.fragment.FragmentAction(correct_order=True)
|
fragment = actions.fragment.FragmentAction(correct_order=True)
|
||||||
fragment.parse("fragment{tcp:-1:True:9}", logger)
|
fragment.parse("fragment{tcp:-1:True:9}", logger)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(seq=100)/("datadata11datadata"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(seq=100)/("datadata11datadata"))
|
||||||
packet1, packet2 = fragment.run(packet, logger)
|
packet1, packet2 = fragment.run(packet, logger)
|
||||||
|
|
||||||
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
||||||
|
@ -350,7 +350,7 @@ def test_overlapping_segment_out_of_bounds():
|
||||||
fragment = actions.fragment.FragmentAction(correct_order=True)
|
fragment = actions.fragment.FragmentAction(correct_order=True)
|
||||||
fragment.parse("fragment{tcp:-1:True:20}", logger)
|
fragment.parse("fragment{tcp:-1:True:20}", logger)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(seq=100)/("datadata11datadata"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(seq=100)/("datadata11datadata"))
|
||||||
packet1, packet2 = fragment.run(packet, logger)
|
packet1, packet2 = fragment.run(packet, logger)
|
||||||
|
|
||||||
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
assert id(packet1) != id(packet2), "Duplicate aliased packet objects"
|
||||||
|
|
|
@ -7,6 +7,8 @@ sys.path.append("..")
|
||||||
import actions.strategy
|
import actions.strategy
|
||||||
import actions.utils
|
import actions.utils
|
||||||
import actions.tamper
|
import actions.tamper
|
||||||
|
import layers.layer
|
||||||
|
import layers.tcp_layer
|
||||||
|
|
||||||
from scapy.all import IP, TCP, Raw, send
|
from scapy.all import IP, TCP, Raw, send
|
||||||
|
|
||||||
|
@ -15,7 +17,7 @@ def test_append_options(logger):
|
||||||
"""
|
"""
|
||||||
Tests appending a given option
|
Tests appending a given option
|
||||||
"""
|
"""
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
||||||
tamper = actions.tamper.TamperAction(tamper_proto="TCP", field="options-wscale", tamper_value=50, tamper_type="replace")
|
tamper = actions.tamper.TamperAction(tamper_proto="TCP", field="options-wscale", tamper_value=50, tamper_type="replace")
|
||||||
lpacket, rpacket = tamper.run(packet, logger)
|
lpacket, rpacket = tamper.run(packet, logger)
|
||||||
lpacket.show()
|
lpacket.show()
|
||||||
|
@ -26,7 +28,7 @@ def test_append_random_options(logger):
|
||||||
"""
|
"""
|
||||||
Tests appending a given option with a random value
|
Tests appending a given option with a random value
|
||||||
"""
|
"""
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
||||||
tamper = actions.tamper.TamperAction(None, field="options-mss", tamper_type="corrupt")
|
tamper = actions.tamper.TamperAction(None, field="options-mss", tamper_type="corrupt")
|
||||||
lpacket, rpacket = tamper.run(packet, logger)
|
lpacket, rpacket = tamper.run(packet, logger)
|
||||||
assert lpacket["TCP"].options[0][0] == 'MSS'
|
assert lpacket["TCP"].options[0][0] == 'MSS'
|
||||||
|
@ -36,7 +38,7 @@ def test_tamper_options(logger):
|
||||||
"""
|
"""
|
||||||
Tests tampering a given option with a given value
|
Tests tampering a given option with a given value
|
||||||
"""
|
"""
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
||||||
tamper = actions.tamper.TamperAction(None, field="options-timestamp", tamper_type="replace", tamper_value=3433)
|
tamper = actions.tamper.TamperAction(None, field="options-timestamp", tamper_type="replace", tamper_value=3433)
|
||||||
lpacket, rpacket = tamper.run(packet, logger)
|
lpacket, rpacket = tamper.run(packet, logger)
|
||||||
assert lpacket["TCP"].options[0][0] == "Timestamp"
|
assert lpacket["TCP"].options[0][0] == "Timestamp"
|
||||||
|
@ -46,7 +48,7 @@ def test_random_tamper_options(logger):
|
||||||
"""
|
"""
|
||||||
Tests tampering a given option with a random value (corrupt)
|
Tests tampering a given option with a random value (corrupt)
|
||||||
"""
|
"""
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
||||||
tamper = actions.tamper.TamperAction(None, field="options-mss", tamper_type="corrupt")
|
tamper = actions.tamper.TamperAction(None, field="options-mss", tamper_type="corrupt")
|
||||||
lpacket, rpacket = tamper.run(packet, logger)
|
lpacket, rpacket = tamper.run(packet, logger)
|
||||||
assert lpacket["TCP"].options[0][0] == "MSS"
|
assert lpacket["TCP"].options[0][0] == "MSS"
|
||||||
|
@ -59,9 +61,9 @@ def test_correct_assignment(logger):
|
||||||
"""
|
"""
|
||||||
Tests that all options can be assigned
|
Tests that all options can be assigned
|
||||||
"""
|
"""
|
||||||
for option in actions.layer.TCPLayer.scapy_options.values():
|
for option in layers.tcp_layer.TCPLayer.scapy_options.values():
|
||||||
print(option)
|
print(option)
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
||||||
tamper = actions.tamper.TamperAction(None, field="options-" + str(option.lower()), tamper_type="corrupt")
|
tamper = actions.tamper.TamperAction(None, field="options-" + str(option.lower()), tamper_type="corrupt")
|
||||||
lpacket, rpacket = tamper.run(packet, logger)
|
lpacket, rpacket = tamper.run(packet, logger)
|
||||||
assert lpacket["TCP"].options[0][0] == option
|
assert lpacket["TCP"].options[0][0] == option
|
||||||
|
@ -70,7 +72,7 @@ def test_str(logger):
|
||||||
"""
|
"""
|
||||||
Tests the string representation of each
|
Tests the string representation of each
|
||||||
"""
|
"""
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
||||||
|
|
||||||
tamper = actions.tamper.TamperAction(None, field="options-mss", tamper_value=39584, tamper_type="replace")
|
tamper = actions.tamper.TamperAction(None, field="options-mss", tamper_value=39584, tamper_type="replace")
|
||||||
assert str(tamper) == "tamper{TCP:options-mss:replace:39584}"
|
assert str(tamper) == "tamper{TCP:options-mss:replace:39584}"
|
||||||
|
@ -79,7 +81,7 @@ def test_parse(logger):
|
||||||
"""
|
"""
|
||||||
Tests the ability to parse
|
Tests the ability to parse
|
||||||
"""
|
"""
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
||||||
tamper = actions.tamper.TamperAction(None, field="options-mss")
|
tamper = actions.tamper.TamperAction(None, field="options-mss")
|
||||||
assert tamper.parse("TCP:options-mss:corrupt", logger)
|
assert tamper.parse("TCP:options-mss:corrupt", logger)
|
||||||
assert str(tamper) == "tamper{TCP:options-mss:corrupt}"
|
assert str(tamper) == "tamper{TCP:options-mss:corrupt}"
|
||||||
|
@ -88,7 +90,7 @@ def test_parse_run(logger):
|
||||||
"""
|
"""
|
||||||
Tests the ability to parse
|
Tests the ability to parse
|
||||||
"""
|
"""
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
||||||
tamper = actions.tamper.TamperAction(None)
|
tamper = actions.tamper.TamperAction(None)
|
||||||
assert tamper.parse("TCP:options-mss:corrupt", logger)
|
assert tamper.parse("TCP:options-mss:corrupt", logger)
|
||||||
|
|
||||||
|
@ -99,7 +101,7 @@ def test_parse_num(logger):
|
||||||
"""
|
"""
|
||||||
Tests parsing integers
|
Tests parsing integers
|
||||||
"""
|
"""
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
||||||
tamper = actions.tamper.TamperAction(None, tamper_type="options")
|
tamper = actions.tamper.TamperAction(None, tamper_type="options")
|
||||||
assert tamper.parse("TCP:options-mss:replace:1440", logger)
|
assert tamper.parse("TCP:options-mss:replace:1440", logger)
|
||||||
|
|
||||||
|
@ -110,7 +112,7 @@ def test_option_8(logger):
|
||||||
"""
|
"""
|
||||||
Tests options 7
|
Tests options 7
|
||||||
"""
|
"""
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
||||||
tamper = actions.tamper.TamperAction(None)
|
tamper = actions.tamper.TamperAction(None)
|
||||||
assert tamper.parse("TCP:options-timestamp:replace:40000", logger)
|
assert tamper.parse("TCP:options-timestamp:replace:40000", logger)
|
||||||
|
|
||||||
|
@ -121,7 +123,7 @@ def test_option_1(logger):
|
||||||
"""
|
"""
|
||||||
Tests option 1
|
Tests option 1
|
||||||
"""
|
"""
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
||||||
tamper = actions.tamper.TamperAction(None, tamper_type="options")
|
tamper = actions.tamper.TamperAction(None, tamper_type="options")
|
||||||
assert tamper.parse("TCP:options-nop:corrupt", logger)
|
assert tamper.parse("TCP:options-nop:corrupt", logger)
|
||||||
|
|
||||||
|
@ -132,7 +134,7 @@ def test_md5options(logger):
|
||||||
"""
|
"""
|
||||||
Tests appending a given option - the md5header
|
Tests appending a given option - the md5header
|
||||||
"""
|
"""
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/("data"))
|
||||||
tamper = actions.tamper.TamperAction(None, field="options-md5header", tamper_value=b'\xee\xee\xee\xee\xee\xee\xee\xee', tamper_type="replace")
|
tamper = actions.tamper.TamperAction(None, field="options-md5header", tamper_value=b'\xee\xee\xee\xee\xee\xee\xee\xee', tamper_type="replace")
|
||||||
lpacket, rpacket = tamper.run(packet, logger)
|
lpacket, rpacket = tamper.run(packet, logger)
|
||||||
assert lpacket["TCP"].options == [(19, b'\xee\xee\xee\xee\xee\xee\xee\xee')]
|
assert lpacket["TCP"].options == [(19, b'\xee\xee\xee\xee\xee\xee\xee\xee')]
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import actions.packet
|
import actions.utils
|
||||||
import actions.layer
|
import actions.trigger
|
||||||
|
import layers.packet
|
||||||
|
import layers.layer
|
||||||
|
import layers.tcp_layer
|
||||||
|
import layers.dns_layer
|
||||||
|
import layers.dnsqr_layer
|
||||||
|
import layers.udp_layer
|
||||||
|
import layers.ip_layer
|
||||||
import evolve
|
import evolve
|
||||||
|
|
||||||
from scapy.all import IP, TCP, UDP, DNS, DNSQR, Raw, DNSRR
|
from scapy.all import IP, TCP, UDP, DNS, DNSQR, Raw, DNSRR
|
||||||
|
@ -12,10 +19,10 @@ def test_parse_layers():
|
||||||
Tests layer parsing.
|
Tests layer parsing.
|
||||||
"""
|
"""
|
||||||
pkt = IP()/TCP()/Raw("")
|
pkt = IP()/TCP()/Raw("")
|
||||||
packet = actions.packet.Packet(pkt)
|
packet = layers.packet.Packet(pkt)
|
||||||
layers = list(packet.read_layers())
|
layers_l = list(packet.read_layers())
|
||||||
assert layers[0].name == "IP"
|
assert layers_l[0].name == "IP"
|
||||||
assert layers[1].name == "TCP"
|
assert layers_l[1].name == "TCP"
|
||||||
|
|
||||||
layers_dict = packet.setup_layers()
|
layers_dict = packet.setup_layers()
|
||||||
assert layers_dict["IP"]
|
assert layers_dict["IP"]
|
||||||
|
@ -27,9 +34,9 @@ def test_get_random():
|
||||||
Tests get random
|
Tests get random
|
||||||
"""
|
"""
|
||||||
|
|
||||||
tcplayer = actions.layer.TCPLayer(TCP())
|
tcplayer = layers.tcp_layer.TCPLayer(TCP())
|
||||||
field, value = tcplayer.get_random()
|
field, value = tcplayer.get_random()
|
||||||
assert field in actions.layer.TCPLayer.fields
|
assert field in layers.tcp_layer.TCPLayer.fields
|
||||||
|
|
||||||
|
|
||||||
def test_gen_random():
|
def test_gen_random():
|
||||||
|
@ -37,7 +44,7 @@ def test_gen_random():
|
||||||
Tests gen random
|
Tests gen random
|
||||||
"""
|
"""
|
||||||
for i in range(0, 2000):
|
for i in range(0, 2000):
|
||||||
layer, field, value = actions.packet.Packet().gen_random()
|
layer, field, value = layers.packet.Packet().gen_random()
|
||||||
assert layer in [DNS, TCP, UDP, IP, DNSQR]
|
assert layer in [DNS, TCP, UDP, IP, DNSQR]
|
||||||
|
|
||||||
|
|
||||||
|
@ -47,14 +54,14 @@ def test_dnsqr():
|
||||||
"""
|
"""
|
||||||
pkt = UDP()/DNS(ancount=1)/DNSQR()
|
pkt = UDP()/DNS(ancount=1)/DNSQR()
|
||||||
pkt.show()
|
pkt.show()
|
||||||
packet = actions.packet.Packet(pkt)
|
packet = layers.packet.Packet(pkt)
|
||||||
packet.show()
|
packet.show()
|
||||||
assert len(packet.layers) == 3
|
assert len(packet.layers) == 3
|
||||||
assert "UDP" in packet.layers
|
assert "UDP" in packet.layers
|
||||||
assert "DNS" in packet.layers
|
assert "DNS" in packet.layers
|
||||||
assert "DNSQR" in packet.layers
|
assert "DNSQR" in packet.layers
|
||||||
pkt = IP()/UDP()/DNS()/DNSQR()
|
pkt = IP()/UDP()/DNS()/DNSQR()
|
||||||
packet = actions.packet.Packet(pkt)
|
packet = layers.packet.Packet(pkt)
|
||||||
assert str(packet)
|
assert str(packet)
|
||||||
|
|
||||||
|
|
||||||
|
@ -62,12 +69,12 @@ def test_load():
|
||||||
"""
|
"""
|
||||||
Tests loads.
|
Tests loads.
|
||||||
"""
|
"""
|
||||||
tcp = actions.layer.TCPLayer(TCP())
|
tcp = layers.tcp_layer.TCPLayer(TCP())
|
||||||
load = tcp.gen("load")
|
load = tcp.gen("load")
|
||||||
pkt = IP()/"datadata"
|
pkt = IP()/"datadata"
|
||||||
p = actions.packet.Packet(pkt)
|
p = layers.packet.Packet(pkt)
|
||||||
assert p.get("IP", "load") == "datadata"
|
assert p.get("IP", "load") == "datadata"
|
||||||
p2 = actions.packet.Packet(IP(bytes(p)))
|
p2 = layers.packet.Packet(IP(bytes(p)))
|
||||||
assert p2.get("IP", "load") == "datadata"
|
assert p2.get("IP", "load") == "datadata"
|
||||||
p2.set("IP", "load", "data2")
|
p2.set("IP", "load", "data2")
|
||||||
# Check p is unchanged
|
# Check p is unchanged
|
||||||
|
@ -81,9 +88,9 @@ def test_load():
|
||||||
assert p2.get("IP", "chksum") == None
|
assert p2.get("IP", "chksum") == None
|
||||||
|
|
||||||
pkt = IP()/TCP()/"datadata"
|
pkt = IP()/TCP()/"datadata"
|
||||||
p = actions.packet.Packet(pkt)
|
p = layers.packet.Packet(pkt)
|
||||||
assert p.get("TCP", "load") == "datadata"
|
assert p.get("TCP", "load") == "datadata"
|
||||||
p2 = actions.packet.Packet(IP(bytes(p)))
|
p2 = layers.packet.Packet(IP(bytes(p)))
|
||||||
assert p2.get("TCP", "load") == "datadata"
|
assert p2.get("TCP", "load") == "datadata"
|
||||||
p2.set("TCP", "load", "data2")
|
p2.set("TCP", "load", "data2")
|
||||||
# Check p is unchanged
|
# Check p is unchanged
|
||||||
|
@ -97,7 +104,7 @@ def test_parse_load(logger):
|
||||||
"""
|
"""
|
||||||
Tests load parsing.
|
Tests load parsing.
|
||||||
"""
|
"""
|
||||||
pkt = actions.packet.Packet(IP()/TCP()/"TYPE A\r\n")
|
pkt = layers.packet.Packet(IP()/TCP()/"TYPE A\r\n")
|
||||||
print("Parsed: %s" % pkt.get("TCP", "load"))
|
print("Parsed: %s" % pkt.get("TCP", "load"))
|
||||||
|
|
||||||
strat = actions.utils.parse("[TCP:load:TYPE%20A%0D%0A]-drop-| \/", logger)
|
strat = actions.utils.parse("[TCP:load:TYPE%20A%0D%0A]-drop-| \/", logger)
|
||||||
|
@ -113,12 +120,12 @@ def test_dns():
|
||||||
"""
|
"""
|
||||||
Tests DNS layer.
|
Tests DNS layer.
|
||||||
"""
|
"""
|
||||||
dns = actions.layer.DNSLayer(DNS())
|
dns = layers.dns_layer.DNSLayer(DNS())
|
||||||
print(dns.gen("id"))
|
print(dns.gen("id"))
|
||||||
assert dns.gen("id")
|
assert dns.gen("id")
|
||||||
|
|
||||||
p = actions.packet.Packet(DNS(id=0xabcd))
|
p = layers.packet.Packet(DNS(id=0xabcd))
|
||||||
p2 = actions.packet.Packet(DNS(bytes(p)))
|
p2 = layers.packet.Packet(DNS(bytes(p)))
|
||||||
assert p.get("DNS", "id") == 0xabcd
|
assert p.get("DNS", "id") == 0xabcd
|
||||||
assert p2.get("DNS", "id") == 0xabcd
|
assert p2.get("DNS", "id") == 0xabcd
|
||||||
|
|
||||||
|
@ -126,13 +133,13 @@ def test_dns():
|
||||||
assert p.get("DNS", "id") == 0xabcd # Check p is unchanged
|
assert p.get("DNS", "id") == 0xabcd # Check p is unchanged
|
||||||
assert p2.get("DNS", "id") == 0x4321
|
assert p2.get("DNS", "id") == 0x4321
|
||||||
|
|
||||||
dns = actions.packet.Packet(DNS(aa=1))
|
dns = layers.packet.Packet(DNS(aa=1))
|
||||||
assert dns.get("DNS", "aa") == 1
|
assert dns.get("DNS", "aa") == 1
|
||||||
aa = dns.gen("DNS", "aa")
|
aa = dns.gen("DNS", "aa")
|
||||||
assert aa == 0 or aa == 1
|
assert aa == 0 or aa == 1
|
||||||
assert dns.get("DNS", "aa") == 1 # Original value unchanged
|
assert dns.get("DNS", "aa") == 1 # Original value unchanged
|
||||||
|
|
||||||
dns = actions.packet.Packet(DNS(opcode=15))
|
dns = layers.packet.Packet(DNS(opcode=15))
|
||||||
assert dns.get("DNS", "opcode") == 15
|
assert dns.get("DNS", "opcode") == 15
|
||||||
opcode = dns.gen("DNS", "opcode")
|
opcode = dns.gen("DNS", "opcode")
|
||||||
assert opcode >= 0 and opcode <= 15
|
assert opcode >= 0 and opcode <= 15
|
||||||
|
@ -141,7 +148,7 @@ def test_dns():
|
||||||
dns.set("DNS", "opcode", 3)
|
dns.set("DNS", "opcode", 3)
|
||||||
assert dns.get("DNS", "opcode") == 3
|
assert dns.get("DNS", "opcode") == 3
|
||||||
|
|
||||||
dns = actions.packet.Packet(DNS(qr=0))
|
dns = layers.packet.Packet(DNS(qr=0))
|
||||||
assert dns.get("DNS", "qr") == 0
|
assert dns.get("DNS", "qr") == 0
|
||||||
qr = dns.gen("DNS", "qr")
|
qr = dns.gen("DNS", "qr")
|
||||||
assert qr == 0 or qr == 1
|
assert qr == 0 or qr == 1
|
||||||
|
@ -150,7 +157,7 @@ def test_dns():
|
||||||
dns.set("DNS", "qr", 1)
|
dns.set("DNS", "qr", 1)
|
||||||
assert dns.get("DNS", "qr") == 1
|
assert dns.get("DNS", "qr") == 1
|
||||||
|
|
||||||
dns = actions.packet.Packet(DNS(arcount=0xAABB))
|
dns = layers.packet.Packet(DNS(arcount=0xAABB))
|
||||||
assert dns.get("DNS", "arcount") == 0xAABB
|
assert dns.get("DNS", "arcount") == 0xAABB
|
||||||
arcount = dns.gen("DNS", "arcount")
|
arcount = dns.gen("DNS", "arcount")
|
||||||
assert arcount >= 0 and arcount <= 0xffff
|
assert arcount >= 0 and arcount <= 0xffff
|
||||||
|
@ -159,13 +166,13 @@ def test_dns():
|
||||||
dns.set("DNS", "arcount", 65432)
|
dns.set("DNS", "arcount", 65432)
|
||||||
assert dns.get("DNS", "arcount") == 65432
|
assert dns.get("DNS", "arcount") == 65432
|
||||||
|
|
||||||
dns = actions.layer.DNSLayer(DNS()/DNSQR(qname="example.com"))
|
dns = layers.dns_layer.DNSLayer(DNS()/DNSQR(qname="example.com"))
|
||||||
assert isinstance(dns.get_next_layer(), DNSQR)
|
assert isinstance(dns.get_next_layer(), DNSQR)
|
||||||
print(dns.gen("id"))
|
print(dns.gen("id"))
|
||||||
assert dns.gen("id")
|
assert dns.gen("id")
|
||||||
|
|
||||||
p = actions.packet.Packet(DNS(id=0xabcd))
|
p = layers.packet.Packet(DNS(id=0xabcd))
|
||||||
p2 = actions.packet.Packet(DNS(bytes(p)))
|
p2 = layers.packet.Packet(DNS(bytes(p)))
|
||||||
assert p.get("DNS", "id") == 0xabcd
|
assert p.get("DNS", "id") == 0xabcd
|
||||||
assert p2.get("DNS", "id") == 0xabcd
|
assert p2.get("DNS", "id") == 0xabcd
|
||||||
|
|
||||||
|
@ -175,27 +182,27 @@ def test_read_layers():
|
||||||
Tests the ability to read each layer
|
Tests the ability to read each layer
|
||||||
"""
|
"""
|
||||||
packet = IP() / UDP() / TCP() / DNS() / DNSQR(qname="example.com") / DNSQR(qname="example2.com") / DNSQR(qname="example3.com")
|
packet = IP() / UDP() / TCP() / DNS() / DNSQR(qname="example.com") / DNSQR(qname="example2.com") / DNSQR(qname="example3.com")
|
||||||
packet_geneva = actions.packet.Packet(packet)
|
packet_geneva = layers.packet.Packet(packet)
|
||||||
packet_geneva.setup_layers()
|
packet_geneva.setup_layers()
|
||||||
|
|
||||||
i = 0
|
i = 0
|
||||||
for layer in packet_geneva.read_layers():
|
for layer in packet_geneva.read_layers():
|
||||||
if i == 0:
|
if i == 0:
|
||||||
assert isinstance(layer, actions.layer.IPLayer)
|
assert isinstance(layer, layers.ip_layer.IPLayer)
|
||||||
elif i == 1:
|
elif i == 1:
|
||||||
assert isinstance(layer, actions.layer.UDPLayer)
|
assert isinstance(layer, layers.udp_layer.UDPLayer)
|
||||||
elif i == 2:
|
elif i == 2:
|
||||||
assert isinstance(layer, actions.layer.TCPLayer)
|
assert isinstance(layer, layers.tcp_layer.TCPLayer)
|
||||||
elif i == 3:
|
elif i == 3:
|
||||||
assert isinstance(layer, actions.layer.DNSLayer)
|
assert isinstance(layer, layers.dns_layer.DNSLayer)
|
||||||
elif i == 4:
|
elif i == 4:
|
||||||
assert isinstance(layer, actions.layer.DNSQRLayer)
|
assert isinstance(layer, layers.dnsqr_layer.DNSQRLayer)
|
||||||
assert layer.layer.qname == b"example.com"
|
assert layer.layer.qname == b"example.com"
|
||||||
elif i == 5:
|
elif i == 5:
|
||||||
assert isinstance(layer, actions.layer.DNSQRLayer)
|
assert isinstance(layer, layers.dnsqr_layer.DNSQRLayer)
|
||||||
assert layer.layer.qname == b"example2.com"
|
assert layer.layer.qname == b"example2.com"
|
||||||
elif i == 6:
|
elif i == 6:
|
||||||
assert isinstance(layer, actions.layer.DNSQRLayer)
|
assert isinstance(layer, layers.dnsqr_layer.DNSQRLayer)
|
||||||
assert layer.layer.qname == b"example3.com"
|
assert layer.layer.qname == b"example3.com"
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
|
@ -204,7 +211,7 @@ def test_multi_opts():
|
||||||
Tests various option getting/setting.
|
Tests various option getting/setting.
|
||||||
"""
|
"""
|
||||||
pkt = IP()/TCP(options=[('MSS', 1460), ('SAckOK', b''), ('Timestamp', (4154603075, 0)), ('NOP', None), ('WScale', 7), ('md5header', b'abcd' * 8)])
|
pkt = IP()/TCP(options=[('MSS', 1460), ('SAckOK', b''), ('Timestamp', (4154603075, 0)), ('NOP', None), ('WScale', 7), ('md5header', b'abcd' * 8)])
|
||||||
packet = actions.packet.Packet(pkt)
|
packet = layers.packet.Packet(pkt)
|
||||||
assert packet.get("TCP", "options-sackok") == ''
|
assert packet.get("TCP", "options-sackok") == ''
|
||||||
assert packet.get("TCP", "options-mss") == 1460
|
assert packet.get("TCP", "options-mss") == 1460
|
||||||
assert packet.get("TCP", "options-timestamp") == 4154603075
|
assert packet.get("TCP", "options-timestamp") == 4154603075
|
||||||
|
@ -215,7 +222,7 @@ def test_multi_opts():
|
||||||
assert packet.get("TCP", "options-timestamp") == 400000000
|
assert packet.get("TCP", "options-timestamp") == 400000000
|
||||||
assert packet.get("TCP", "options-wscale") == 7
|
assert packet.get("TCP", "options-wscale") == 7
|
||||||
pkt = IP()/TCP(options=[('SAckOK', b''), ('Timestamp', (4154603075, 0)), ('NOP', None), ('WScale', 7)])
|
pkt = IP()/TCP(options=[('SAckOK', b''), ('Timestamp', (4154603075, 0)), ('NOP', None), ('WScale', 7)])
|
||||||
packet = actions.packet.Packet(pkt)
|
packet = layers.packet.Packet(pkt)
|
||||||
# If the option isn't present, it will be returned as an empty string
|
# If the option isn't present, it will be returned as an empty string
|
||||||
assert packet.get("TCP", "options-mss") == ''
|
assert packet.get("TCP", "options-mss") == ''
|
||||||
packet.set("TCP", "options-mss", "")
|
packet.set("TCP", "options-mss", "")
|
||||||
|
@ -227,11 +234,11 @@ def test_options_eol():
|
||||||
Tests options-eol.
|
Tests options-eol.
|
||||||
"""
|
"""
|
||||||
pkt = TCP(options=[("EOL", None)])
|
pkt = TCP(options=[("EOL", None)])
|
||||||
p = actions.packet.Packet(pkt)
|
p = layers.packet.Packet(pkt)
|
||||||
assert p.get("TCP", "options-eol") == ""
|
assert p.get("TCP", "options-eol") == ""
|
||||||
p2 = actions.packet.Packet(TCP(bytes(p)))
|
p2 = layers.packet.Packet(TCP(bytes(p)))
|
||||||
assert p2.get("TCP", "options-eol") == ""
|
assert p2.get("TCP", "options-eol") == ""
|
||||||
p = actions.packet.Packet(IP()/TCP(options=[]))
|
p = layers.packet.Packet(IP()/TCP(options=[]))
|
||||||
assert p.get("TCP", "options-eol") == ""
|
assert p.get("TCP", "options-eol") == ""
|
||||||
p.set("TCP", "options-eol", "")
|
p.set("TCP", "options-eol", "")
|
||||||
p.show()
|
p.show()
|
||||||
|
@ -249,8 +256,8 @@ def test_compression_fallback(logger):
|
||||||
Test that compression does not touch a packet without DNS in it packet
|
Test that compression does not touch a packet without DNS in it packet
|
||||||
"""
|
"""
|
||||||
pkt = UDP()
|
pkt = UDP()
|
||||||
p = actions.packet.Packet(pkt)
|
p = layers.packet.Packet(pkt)
|
||||||
p2 = actions.layer.DNSLayer.dns_decompress(p, logger)
|
p2 = layers.dns_layer.DNSLayer.dns_decompress(p, logger)
|
||||||
assert p2 == p, "dns_decompress changed a non DNS packet"
|
assert p2 == p, "dns_decompress changed a non DNS packet"
|
||||||
|
|
||||||
|
|
||||||
|
@ -259,11 +266,11 @@ def test_options_mss():
|
||||||
Tests options-eol.
|
Tests options-eol.
|
||||||
"""
|
"""
|
||||||
pkt = TCP(options=[("MSS", 1440)])
|
pkt = TCP(options=[("MSS", 1440)])
|
||||||
p = actions.packet.Packet(pkt)
|
p = layers.packet.Packet(pkt)
|
||||||
assert p.get("TCP", "options-mss") == 1440
|
assert p.get("TCP", "options-mss") == 1440
|
||||||
p2 = actions.packet.Packet(TCP(bytes(p)))
|
p2 = layers.packet.Packet(TCP(bytes(p)))
|
||||||
assert p2.get("TCP", "options-mss") == 1440
|
assert p2.get("TCP", "options-mss") == 1440
|
||||||
p = actions.packet.Packet(TCP(options=[]))
|
p = layers.packet.Packet(TCP(options=[]))
|
||||||
assert p.get("TCP", "options-mss") == ""
|
assert p.get("TCP", "options-mss") == ""
|
||||||
p.set("TCP", "options-mss", 2880)
|
p.set("TCP", "options-mss", 2880)
|
||||||
p.show()
|
p.show()
|
||||||
|
@ -281,7 +288,7 @@ def check_get(protocol, field, value):
|
||||||
"""
|
"""
|
||||||
pkt = protocol()
|
pkt = protocol()
|
||||||
setattr(pkt, field, value)
|
setattr(pkt, field, value)
|
||||||
packet = actions.packet.Packet(pkt)
|
packet = layers.packet.Packet(pkt)
|
||||||
assert packet.get(protocol.__name__, field) == value
|
assert packet.get(protocol.__name__, field) == value
|
||||||
|
|
||||||
|
|
||||||
|
@ -374,11 +381,11 @@ def check_set_get(protocol, field, value):
|
||||||
"""
|
"""
|
||||||
Checks if the get method worked for this protocol, field, and value.
|
Checks if the get method worked for this protocol, field, and value.
|
||||||
"""
|
"""
|
||||||
pkt = actions.packet.Packet(protocol())
|
pkt = layers.packet.Packet(protocol())
|
||||||
pkt.set(protocol.__name__, field, value)
|
pkt.set(protocol.__name__, field, value)
|
||||||
assert pkt.get(protocol.__name__, field) == value
|
assert pkt.get(protocol.__name__, field) == value
|
||||||
# Rebuild the packet to confirm the type survived
|
# Rebuild the packet to confirm the type survived
|
||||||
pkt2 = actions.packet.Packet(protocol(bytes(pkt)))
|
pkt2 = layers.packet.Packet(protocol(bytes(pkt)))
|
||||||
assert pkt2.get(protocol.__name__, field) == value, "Value %s for header %s didn't survive packet parsing." % (value, field)
|
assert pkt2.get(protocol.__name__, field) == value, "Value %s for header %s didn't survive packet parsing." % (value, field)
|
||||||
|
|
||||||
|
|
||||||
|
@ -396,12 +403,12 @@ def check_gen_set_get(protocol, field):
|
||||||
"""
|
"""
|
||||||
Checks if the get method worked for this protocol, field, and value.
|
Checks if the get method worked for this protocol, field, and value.
|
||||||
"""
|
"""
|
||||||
pkt = actions.packet.Packet(protocol())
|
pkt = layers.packet.Packet(protocol())
|
||||||
new_value = pkt.gen(protocol.__name__, field)
|
new_value = pkt.gen(protocol.__name__, field)
|
||||||
pkt.set(protocol.__name__, field, new_value)
|
pkt.set(protocol.__name__, field, new_value)
|
||||||
assert pkt.get(protocol.__name__, field) == new_value
|
assert pkt.get(protocol.__name__, field) == new_value
|
||||||
# Rebuild the packet to confirm the type survived
|
# Rebuild the packet to confirm the type survived
|
||||||
pkt2 = actions.packet.Packet(protocol(bytes(pkt)))
|
pkt2 = layers.packet.Packet(protocol(bytes(pkt)))
|
||||||
assert pkt2.get(protocol.__name__, field) == new_value
|
assert pkt2.get(protocol.__name__, field) == new_value
|
||||||
|
|
||||||
|
|
||||||
|
@ -422,7 +429,7 @@ def test_custom_get():
|
||||||
Tests value retrieval for custom getters.
|
Tests value retrieval for custom getters.
|
||||||
"""
|
"""
|
||||||
pkt = IP()/TCP()/Raw(load="AAAA")
|
pkt = IP()/TCP()/Raw(load="AAAA")
|
||||||
tcp = actions.packet.Packet(pkt)
|
tcp = layers.packet.Packet(pkt)
|
||||||
assert tcp.get("TCP", "load") == "AAAA"
|
assert tcp.get("TCP", "load") == "AAAA"
|
||||||
|
|
||||||
|
|
||||||
|
@ -430,51 +437,51 @@ def test_restrict_fields(logger):
|
||||||
"""
|
"""
|
||||||
Tests packet field restriction.
|
Tests packet field restriction.
|
||||||
"""
|
"""
|
||||||
actions.packet.SUPPORTED_LAYERS = [
|
layers.packet.SUPPORTED_LAYERS = [
|
||||||
actions.layer.IPLayer,
|
layers.ip_layer.IPLayer,
|
||||||
actions.layer.TCPLayer,
|
layers.tcp_layer.TCPLayer,
|
||||||
actions.layer.UDPLayer
|
layers.udp_layer.UDPLayer
|
||||||
]
|
]
|
||||||
tcpfields = actions.layer.TCPLayer.fields
|
tcpfields = layers.tcp_layer.TCPLayer.fields
|
||||||
udpfields = actions.layer.UDPLayer.fields
|
udpfields = layers.udp_layer.UDPLayer.fields
|
||||||
ipfields = actions.layer.IPLayer.fields
|
ipfields = layers.ip_layer.IPLayer.fields
|
||||||
|
|
||||||
actions.packet.Packet.restrict_fields(logger, ["TCP", "UDP"], [], [])
|
layers.packet.Packet.restrict_fields(logger, ["TCP", "UDP"], [], [])
|
||||||
assert len(actions.packet.SUPPORTED_LAYERS) == 2
|
assert len(layers.packet.SUPPORTED_LAYERS) == 2
|
||||||
assert actions.layer.TCPLayer in actions.packet.SUPPORTED_LAYERS
|
assert layers.tcp_layer.TCPLayer in layers.packet.SUPPORTED_LAYERS
|
||||||
assert actions.layer.UDPLayer in actions.packet.SUPPORTED_LAYERS
|
assert layers.udp_layer.UDPLayer in layers.packet.SUPPORTED_LAYERS
|
||||||
assert not actions.layer.IPLayer in actions.packet.SUPPORTED_LAYERS
|
assert not layers.ip_layer.IPLayer in layers.packet.SUPPORTED_LAYERS
|
||||||
|
|
||||||
pkt = IP()/TCP()
|
pkt = IP()/TCP()
|
||||||
packet = actions.packet.Packet(pkt)
|
packet = layers.packet.Packet(pkt)
|
||||||
assert "TCP" in packet.layers
|
assert "TCP" in packet.layers
|
||||||
assert not "IP" in packet.layers
|
assert not "IP" in packet.layers
|
||||||
assert len(packet.layers) == 1
|
assert len(packet.layers) == 1
|
||||||
|
|
||||||
for i in range(0, 2000):
|
for i in range(0, 2000):
|
||||||
layer, proto, field = actions.packet.Packet().gen_random()
|
layer, proto, field = layers.packet.Packet().gen_random()
|
||||||
assert layer in [TCP, UDP]
|
assert layer in [TCP, UDP]
|
||||||
|
|
||||||
# Check we can't retrieve any IP fields
|
# Check we can't retrieve any IP fields
|
||||||
for field in actions.layer.IPLayer.fields:
|
for field in layers.ip_layer.IPLayer.fields:
|
||||||
with pytest.raises(AssertionError):
|
with pytest.raises(AssertionError):
|
||||||
packet.get("IP", field)
|
packet.get("IP", field)
|
||||||
|
|
||||||
# Check we can get all the TCP fields
|
# Check we can get all the TCP fields
|
||||||
for field in actions.layer.TCPLayer.fields:
|
for field in layers.tcp_layer.TCPLayer.fields:
|
||||||
packet.get("TCP", field)
|
packet.get("TCP", field)
|
||||||
|
|
||||||
actions.packet.Packet.restrict_fields(logger, ["TCP", "UDP"], ["flags"], [])
|
layers.packet.Packet.restrict_fields(logger, ["TCP", "UDP"], ["flags"], [])
|
||||||
packet = actions.packet.Packet(pkt)
|
packet = layers.packet.Packet(pkt)
|
||||||
assert len(actions.packet.SUPPORTED_LAYERS) == 1
|
assert len(layers.packet.SUPPORTED_LAYERS) == 1
|
||||||
assert actions.layer.TCPLayer in actions.packet.SUPPORTED_LAYERS
|
assert layers.tcp_layer.TCPLayer in layers.packet.SUPPORTED_LAYERS
|
||||||
assert not actions.layer.UDPLayer in actions.packet.SUPPORTED_LAYERS
|
assert not layers.udp_layer.UDPLayer in layers.packet.SUPPORTED_LAYERS
|
||||||
assert not actions.layer.IPLayer in actions.packet.SUPPORTED_LAYERS
|
assert not layers.ip_layer.IPLayer in layers.packet.SUPPORTED_LAYERS
|
||||||
assert actions.layer.TCPLayer.fields == ["flags"]
|
assert layers.tcp_layer.TCPLayer.fields == ["flags"]
|
||||||
assert not actions.layer.UDPLayer.fields
|
assert not layers.udp_layer.UDPLayer.fields
|
||||||
|
|
||||||
# Check we can't retrieve any IP fields
|
# Check we can't retrieve any IP fields
|
||||||
for field in actions.layer.IPLayer.fields:
|
for field in layers.ip_layer.IPLayer.fields:
|
||||||
with pytest.raises(AssertionError):
|
with pytest.raises(AssertionError):
|
||||||
packet.get("IP", field)
|
packet.get("IP", field)
|
||||||
|
|
||||||
|
@ -487,37 +494,37 @@ def test_restrict_fields(logger):
|
||||||
packet.get("TCP", field)
|
packet.get("TCP", field)
|
||||||
|
|
||||||
for i in range(0, 2000):
|
for i in range(0, 2000):
|
||||||
layer, field, value = actions.packet.Packet().gen_random()
|
layer, field, value = layers.packet.Packet().gen_random()
|
||||||
assert layer == TCP
|
assert layer == TCP
|
||||||
assert field == "flags"
|
assert field == "flags"
|
||||||
|
|
||||||
_, proto, field, value, _ = actions.trigger.Trigger.get_rand_trigger(None, 0)
|
_, proto, field, value, _ = actions.trigger.Trigger.get_rand_trigger(None, 0)
|
||||||
assert proto == 'TCP'
|
assert proto == 'TCP'
|
||||||
assert field == "flags"
|
assert field == "flags"
|
||||||
actions.packet.Packet.reset_restrictions()
|
layers.packet.Packet.reset_restrictions()
|
||||||
actions.packet.SUPPORTED_LAYERS = [
|
layers.packet.SUPPORTED_LAYERS = [
|
||||||
actions.layer.IPLayer,
|
layers.ip_layer.IPLayer,
|
||||||
actions.layer.TCPLayer,
|
layers.tcp_layer.TCPLayer,
|
||||||
actions.layer.UDPLayer
|
layers.udp_layer.UDPLayer
|
||||||
]
|
]
|
||||||
|
|
||||||
with pytest.raises(AssertionError):
|
with pytest.raises(AssertionError):
|
||||||
actions.packet.Packet.restrict_fields(logger, ["TCP", "IP"], ["notathing"], ["notathing"])
|
layers.packet.Packet.restrict_fields(logger, ["TCP", "IP"], ["notathing"], ["notathing"])
|
||||||
actions.packet.Packet.reset_restrictions()
|
layers.packet.Packet.reset_restrictions()
|
||||||
|
|
||||||
actions.packet.Packet.restrict_fields(logger, ["TCP", "IP"], [], ["sport", "dport", "seq", "src"])
|
layers.packet.Packet.restrict_fields(logger, ["TCP", "IP"], [], ["sport", "dport", "seq", "src"])
|
||||||
packet = actions.packet.Packet(pkt)
|
packet = layers.packet.Packet(pkt)
|
||||||
packet = packet.copy()
|
packet = packet.copy()
|
||||||
assert packet.has_supported_layers()
|
assert packet.has_supported_layers()
|
||||||
assert len(actions.packet.SUPPORTED_LAYERS) == 2
|
assert len(layers.packet.SUPPORTED_LAYERS) == 2
|
||||||
assert actions.layer.TCPLayer in actions.packet.SUPPORTED_LAYERS
|
assert layers.tcp_layer.TCPLayer in layers.packet.SUPPORTED_LAYERS
|
||||||
assert not actions.layer.UDPLayer in actions.packet.SUPPORTED_LAYERS
|
assert not layers.udp_layer.UDPLayer in layers.packet.SUPPORTED_LAYERS
|
||||||
assert actions.layer.IPLayer in actions.packet.SUPPORTED_LAYERS
|
assert layers.ip_layer.IPLayer in layers.packet.SUPPORTED_LAYERS
|
||||||
assert set(actions.layer.TCPLayer.fields) == set([f for f in tcpfields if f not in ["sport", "dport", "seq"]])
|
assert set(layers.tcp_layer.TCPLayer.fields) == set([f for f in tcpfields if f not in ["sport", "dport", "seq"]])
|
||||||
assert set(actions.layer.IPLayer.fields) == set([f for f in ipfields if f not in ["src"]])
|
assert set(layers.ip_layer.IPLayer.fields) == set([f for f in ipfields if f not in ["src"]])
|
||||||
|
|
||||||
# Check we can't retrieve any IP fields
|
# Check we can't retrieve any IP fields
|
||||||
for field in actions.layer.IPLayer.fields:
|
for field in layers.ip_layer.IPLayer.fields:
|
||||||
if field == "src":
|
if field == "src":
|
||||||
with pytest.raises(AssertionError):
|
with pytest.raises(AssertionError):
|
||||||
packet.get("IP", field)
|
packet.get("IP", field)
|
||||||
|
@ -533,7 +540,7 @@ def test_restrict_fields(logger):
|
||||||
packet.get("TCP", field)
|
packet.get("TCP", field)
|
||||||
|
|
||||||
for i in range(0, 2000):
|
for i in range(0, 2000):
|
||||||
layer, field, value = actions.packet.Packet().gen_random()
|
layer, field, value = layers.packet.Packet().gen_random()
|
||||||
assert layer in [TCP, IP]
|
assert layer in [TCP, IP]
|
||||||
assert field not in ["sport", "dport", "seq", "src"]
|
assert field not in ["sport", "dport", "seq", "src"]
|
||||||
|
|
||||||
|
@ -541,24 +548,24 @@ def test_restrict_fields(logger):
|
||||||
assert proto in ['TCP', 'IP']
|
assert proto in ['TCP', 'IP']
|
||||||
assert field not in ["sport", "dport", "seq", "src"]
|
assert field not in ["sport", "dport", "seq", "src"]
|
||||||
|
|
||||||
actions.packet.Packet.reset_restrictions()
|
layers.packet.Packet.reset_restrictions()
|
||||||
actions.packet.SUPPORTED_LAYERS = [
|
layers.packet.SUPPORTED_LAYERS = [
|
||||||
actions.layer.IPLayer,
|
layers.ip_layer.IPLayer,
|
||||||
actions.layer.TCPLayer,
|
layers.tcp_layer.TCPLayer,
|
||||||
actions.layer.UDPLayer
|
layers.udp_layer.UDPLayer
|
||||||
]
|
]
|
||||||
|
|
||||||
evolve.restrict_headers(logger, "ip,udp,dns", "", "version")
|
evolve.restrict_headers(logger, "ip,udp,dns", "", "version")
|
||||||
packet = actions.packet.Packet(pkt)
|
packet = layers.packet.Packet(pkt)
|
||||||
proto, field, value = packet.get_random()
|
proto, field, value = packet.get_random()
|
||||||
assert proto.__name__ in ["IP", "UDP"]
|
assert proto.__name__ in ["IP", "UDP"]
|
||||||
assert len(actions.packet.SUPPORTED_LAYERS) == 2
|
assert len(layers.packet.SUPPORTED_LAYERS) == 2
|
||||||
assert not actions.layer.TCPLayer in actions.packet.SUPPORTED_LAYERS
|
assert not layers.tcp_layer.TCPLayer in layers.packet.SUPPORTED_LAYERS
|
||||||
assert actions.layer.UDPLayer in actions.packet.SUPPORTED_LAYERS
|
assert layers.udp_layer.UDPLayer in layers.packet.SUPPORTED_LAYERS
|
||||||
assert actions.layer.IPLayer in actions.packet.SUPPORTED_LAYERS
|
assert layers.ip_layer.IPLayer in layers.packet.SUPPORTED_LAYERS
|
||||||
assert set(actions.layer.IPLayer.fields) == set([f for f in ipfields if f not in ["version"]])
|
assert set(layers.ip_layer.IPLayer.fields) == set([f for f in ipfields if f not in ["version"]])
|
||||||
assert set(actions.layer.UDPLayer.fields) == set(udpfields)
|
assert set(layers.udp_layer.UDPLayer.fields) == set(udpfields)
|
||||||
|
|
||||||
actions.packet.Packet.reset_restrictions()
|
layers.packet.Packet.reset_restrictions()
|
||||||
for layer in actions.packet.SUPPORTED_LAYERS:
|
for layer in layers.packet.SUPPORTED_LAYERS:
|
||||||
assert layer.fields, '%s has no fields - reset failed!' % str(layer)
|
assert layer.fields, '%s has no fields - reset failed!' % str(layer)
|
||||||
|
|
|
@ -4,6 +4,7 @@ sys.path.append("..") # Include the root of the project
|
||||||
import evolve
|
import evolve
|
||||||
import os
|
import os
|
||||||
import actions.utils
|
import actions.utils
|
||||||
|
import layers.layer
|
||||||
|
|
||||||
# Test Files Directory Setup
|
# Test Files Directory Setup
|
||||||
test_files_directory = os.path.join("test_files")
|
test_files_directory = os.path.join("test_files")
|
||||||
|
@ -97,7 +98,7 @@ def test_evolve_load_generation(logger):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
generations = 2
|
generations = 2
|
||||||
actions.packet.Packet.reset_restrictions()
|
layers.packet.Packet.reset_restrictions()
|
||||||
|
|
||||||
options = {}
|
options = {}
|
||||||
options["population_size"] = 2
|
options["population_size"] = 2
|
||||||
|
|
|
@ -2,7 +2,7 @@ from scapy.all import IP, TCP
|
||||||
import evolve
|
import evolve
|
||||||
import actions.utils
|
import actions.utils
|
||||||
import actions.strategy
|
import actions.strategy
|
||||||
import actions.packet
|
import layers.packet
|
||||||
import actions.sleep
|
import actions.sleep
|
||||||
import sys
|
import sys
|
||||||
# Include the root of the project
|
# Include the root of the project
|
||||||
|
@ -16,7 +16,7 @@ def test_basic_sleep(logger):
|
||||||
sleep = actions.sleep.SleepAction(.5)
|
sleep = actions.sleep.SleepAction(.5)
|
||||||
assert str(sleep) == "sleep{0.5}", "Sleep returned incorrect string representation: %s" % str(sleep)
|
assert str(sleep) == "sleep{0.5}", "Sleep returned incorrect string representation: %s" % str(sleep)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP()/("data"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP()/("data"))
|
||||||
packet1, packet2 = sleep.run(packet, logger)
|
packet1, packet2 = sleep.run(packet, logger)
|
||||||
|
|
||||||
assert packet1.sleep == .5, "Packet had wrong sleep value"
|
assert packet1.sleep == .5, "Packet had wrong sleep value"
|
||||||
|
|
|
@ -10,6 +10,7 @@ import actions.utils
|
||||||
import actions.strategy
|
import actions.strategy
|
||||||
import evaluator
|
import evaluator
|
||||||
import evolve
|
import evolve
|
||||||
|
import layers.layer
|
||||||
|
|
||||||
from scapy.all import IP, TCP, Raw
|
from scapy.all import IP, TCP, Raw
|
||||||
|
|
||||||
|
@ -67,24 +68,24 @@ def test_run(logger):
|
||||||
strat3 = actions.utils.parse("[TCP:flags:A]-duplicate(tamper{TCP:dataofs:replace:0},)-| \/", logger)
|
strat3 = actions.utils.parse("[TCP:flags:A]-duplicate(tamper{TCP:dataofs:replace:0},)-| \/", logger)
|
||||||
strat4 = actions.utils.parse("[TCP:flags:A]-duplicate(tamper{TCP:flags:replace:R}(tamper{TCP:chksum:replace:15239},),duplicate(tamper{TCP:flags:replace:S}(tamper{TCP:chksum:replace:14539}(tamper{TCP:seq:corrupt},),),))-| \/", logger)
|
strat4 = actions.utils.parse("[TCP:flags:A]-duplicate(tamper{TCP:flags:replace:R}(tamper{TCP:chksum:replace:15239},),duplicate(tamper{TCP:flags:replace:S}(tamper{TCP:chksum:replace:14539}(tamper{TCP:seq:corrupt},),),))-| \/", logger)
|
||||||
|
|
||||||
p1 = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
p1 = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
||||||
packets = strat1.act_on_packet(p1, logger, direction="out")
|
packets = strat1.act_on_packet(p1, logger, direction="out")
|
||||||
assert packets, "Strategy dropped SYN packets"
|
assert packets, "Strategy dropped SYN packets"
|
||||||
assert len(packets) == 1
|
assert len(packets) == 1
|
||||||
assert packets[0]["TCP"].flags == "S"
|
assert packets[0]["TCP"].flags == "S"
|
||||||
|
|
||||||
p1 = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
p1 = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
||||||
packets = strat2.act_on_packet(p1, logger, direction="out")
|
packets = strat2.act_on_packet(p1, logger, direction="out")
|
||||||
assert not packets, "Strategy failed to drop SYN packets"
|
assert not packets, "Strategy failed to drop SYN packets"
|
||||||
|
|
||||||
p1 = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="A", dataofs=5))
|
p1 = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="A", dataofs=5))
|
||||||
packets = strat3.act_on_packet(p1, logger, direction="out")
|
packets = strat3.act_on_packet(p1, logger, direction="out")
|
||||||
assert packets, "Strategy dropped packets"
|
assert packets, "Strategy dropped packets"
|
||||||
assert len(packets) == 2, "Incorrect number of packets emerged from forest"
|
assert len(packets) == 2, "Incorrect number of packets emerged from forest"
|
||||||
assert packets[0]["TCP"].dataofs == 0, "Packet tamper failed"
|
assert packets[0]["TCP"].dataofs == 0, "Packet tamper failed"
|
||||||
assert packets[1]["TCP"].dataofs == 5, "Duplicate packet was tampered"
|
assert packets[1]["TCP"].dataofs == 5, "Duplicate packet was tampered"
|
||||||
|
|
||||||
p1 = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="A", dataofs=5, chksum=100))
|
p1 = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="A", dataofs=5, chksum=100))
|
||||||
packets = strat4.act_on_packet(p1, logger, direction="out")
|
packets = strat4.act_on_packet(p1, logger, direction="out")
|
||||||
assert packets, "Strategy dropped packets"
|
assert packets, "Strategy dropped packets"
|
||||||
assert len(packets) == 3, "Incorrect number of packets emerged from forest"
|
assert len(packets) == 3, "Incorrect number of packets emerged from forest"
|
||||||
|
@ -96,12 +97,12 @@ def test_run(logger):
|
||||||
assert packets[2]["TCP"].flags == "A", "Duplicate failed"
|
assert packets[2]["TCP"].flags == "A", "Duplicate failed"
|
||||||
|
|
||||||
strat4 = actions.utils.parse("[TCP:load:]-tamper{TCP:load:replace:mhe76jm0bd}(fragment{ip:-1:True}(tamper{IP:load:corrupt},drop),)-| \/ ", logger)
|
strat4 = actions.utils.parse("[TCP:load:]-tamper{TCP:load:replace:mhe76jm0bd}(fragment{ip:-1:True}(tamper{IP:load:corrupt},drop),)-| \/ ", logger)
|
||||||
p1 = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
p1 = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
||||||
packets = strat4.act_on_packet(p1, logger)
|
packets = strat4.act_on_packet(p1, logger)
|
||||||
|
|
||||||
# Will fail with scapy 2.4.2 if packet is reparsed
|
# Will fail with scapy 2.4.2 if packet is reparsed
|
||||||
strat5 = actions.utils.parse("[TCP:options-eol:]-tamper{TCP:load:replace:o}(tamper{TCP:dataofs:replace:11},)-| \/", logger)
|
strat5 = actions.utils.parse("[TCP:options-eol:]-tamper{TCP:load:replace:o}(tamper{TCP:dataofs:replace:11},)-| \/", logger)
|
||||||
p1 = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
p1 = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
||||||
packets = strat5.act_on_packet(p1, logger)
|
packets = strat5.act_on_packet(p1, logger)
|
||||||
|
|
||||||
|
|
||||||
|
@ -205,5 +206,5 @@ def test_fail_cases(logger):
|
||||||
s = "[IP:proto:6]-tamper{IP:proto:replace:125}(fragment{tcp:48:True:26}(tamper{TCP:options-md5header:replace:37f0e737da65224ea03d46c713ed6fd2},),)-| \/ "
|
s = "[IP:proto:6]-tamper{IP:proto:replace:125}(fragment{tcp:48:True:26}(tamper{TCP:options-md5header:replace:37f0e737da65224ea03d46c713ed6fd2},),)-| \/ "
|
||||||
s = actions.utils.parse(s, logger)
|
s = actions.utils.parse(s, logger)
|
||||||
|
|
||||||
p = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/Raw("aaaaaaaaaa"))
|
p = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S")/Raw("aaaaaaaaaa"))
|
||||||
s.act_on_packet(p, logger)
|
s.act_on_packet(p, logger)
|
||||||
|
|
|
@ -8,10 +8,11 @@ sys.path.append("..")
|
||||||
import evolve
|
import evolve
|
||||||
import evaluator
|
import evaluator
|
||||||
import actions.strategy
|
import actions.strategy
|
||||||
import actions.packet
|
import layers.packet
|
||||||
import actions.utils
|
import actions.utils
|
||||||
import actions.tamper
|
import actions.tamper
|
||||||
import actions.layer
|
import layers.layer
|
||||||
|
import layers.ip_layer
|
||||||
|
|
||||||
from scapy.all import IP, TCP, UDP, DNS, DNSQR, sr1
|
from scapy.all import IP, TCP, UDP, DNS, DNSQR, sr1
|
||||||
|
|
||||||
|
@ -20,7 +21,7 @@ def test_tamper(logger):
|
||||||
"""
|
"""
|
||||||
Tests tampering with replace
|
Tests tampering with replace
|
||||||
"""
|
"""
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
||||||
original = copy.deepcopy(packet)
|
original = copy.deepcopy(packet)
|
||||||
tamper = actions.tamper.TamperAction(None, field="flags", tamper_type="replace", tamper_value="R")
|
tamper = actions.tamper.TamperAction(None, field="flags", tamper_type="replace", tamper_value="R")
|
||||||
lpacket, rpacket = tamper.run(packet, logger)
|
lpacket, rpacket = tamper.run(packet, logger)
|
||||||
|
@ -48,7 +49,7 @@ def test_tamper_ip(logger):
|
||||||
"""
|
"""
|
||||||
Tests tampering with IP
|
Tests tampering with IP
|
||||||
"""
|
"""
|
||||||
packet = actions.packet.Packet(IP(src='127.0.0.1', dst='127.0.0.1')/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
packet = layers.packet.Packet(IP(src='127.0.0.1', dst='127.0.0.1')/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
||||||
original = copy.deepcopy(packet)
|
original = copy.deepcopy(packet)
|
||||||
tamper = actions.tamper.TamperAction(None, field="src", tamper_type="replace", tamper_value="192.168.1.1", tamper_proto="IP")
|
tamper = actions.tamper.TamperAction(None, field="src", tamper_type="replace", tamper_value="192.168.1.1", tamper_proto="IP")
|
||||||
lpacket, rpacket = tamper.run(packet, logger)
|
lpacket, rpacket = tamper.run(packet, logger)
|
||||||
|
@ -70,7 +71,7 @@ def test_tamper_udp(logger):
|
||||||
"""
|
"""
|
||||||
Tests tampering with UDP
|
Tests tampering with UDP
|
||||||
"""
|
"""
|
||||||
packet = actions.packet.Packet(IP(src='127.0.0.1', dst='127.0.0.1')/UDP(sport=2222, dport=53))
|
packet = layers.packet.Packet(IP(src='127.0.0.1', dst='127.0.0.1')/UDP(sport=2222, dport=53))
|
||||||
original = copy.deepcopy(packet)
|
original = copy.deepcopy(packet)
|
||||||
tamper = actions.tamper.TamperAction(None, field="chksum", tamper_type="replace", tamper_value=4444, tamper_proto="UDP")
|
tamper = actions.tamper.TamperAction(None, field="chksum", tamper_type="replace", tamper_value=4444, tamper_proto="UDP")
|
||||||
lpacket, rpacket = tamper.run(packet, logger)
|
lpacket, rpacket = tamper.run(packet, logger)
|
||||||
|
@ -93,7 +94,7 @@ def test_tamper_ip_ident(logger):
|
||||||
Tests tampering with IP and that the checksum is correctly changed
|
Tests tampering with IP and that the checksum is correctly changed
|
||||||
"""
|
"""
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src='127.0.0.1', dst='127.0.0.1')/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
packet = layers.packet.Packet(IP(src='127.0.0.1', dst='127.0.0.1')/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
||||||
original = copy.deepcopy(packet)
|
original = copy.deepcopy(packet)
|
||||||
tamper = actions.tamper.TamperAction(None, field='id', tamper_type='replace', tamper_value=3333, tamper_proto="IP")
|
tamper = actions.tamper.TamperAction(None, field='id', tamper_type='replace', tamper_value=3333, tamper_proto="IP")
|
||||||
lpacket, rpacket = tamper.run(packet, logger)
|
lpacket, rpacket = tamper.run(packet, logger)
|
||||||
|
@ -161,9 +162,9 @@ def test_mutate(logger, use_canary):
|
||||||
assert tamper.tamper_value == val, "Tamper value is not stable."
|
assert tamper.tamper_value == val, "Tamper value is not stable."
|
||||||
# Create a test packet to ensure the field/proto choice was safe
|
# Create a test packet to ensure the field/proto choice was safe
|
||||||
if random.random() < 0.5:
|
if random.random() < 0.5:
|
||||||
test_packet = actions.packet.Packet(IP()/TCP())
|
test_packet = layers.packet.Packet(IP()/TCP())
|
||||||
else:
|
else:
|
||||||
test_packet = actions.packet.Packet(IP()/UDP())
|
test_packet = layers.packet.Packet(IP()/UDP())
|
||||||
|
|
||||||
# Check that tamper can run safely after mutation
|
# Check that tamper can run safely after mutation
|
||||||
try:
|
try:
|
||||||
|
@ -199,7 +200,7 @@ def test_corrupt(logger):
|
||||||
assert tamper.tamper_type == "corrupt", "Tamper action changed types."
|
assert tamper.tamper_type == "corrupt", "Tamper action changed types."
|
||||||
assert str(tamper) == "tamper{TCP:flags:corrupt}", "Tamper returned incorrect string representation: %s" % str(tamper)
|
assert str(tamper) == "tamper{TCP:flags:corrupt}", "Tamper returned incorrect string representation: %s" % str(tamper)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
||||||
original = copy.deepcopy(packet)
|
original = copy.deepcopy(packet)
|
||||||
tamper.tamper(packet, logger)
|
tamper.tamper(packet, logger)
|
||||||
|
|
||||||
|
@ -226,7 +227,7 @@ def test_add(logger):
|
||||||
assert tamper.tamper_type == "add", "Tamper action changed types."
|
assert tamper.tamper_type == "add", "Tamper action changed types."
|
||||||
assert str(tamper) == "tamper{TCP:seq:add:10}", "Tamper returned incorrect string representation: %s" % str(tamper)
|
assert str(tamper) == "tamper{TCP:seq:add:10}", "Tamper returned incorrect string representation: %s" % str(tamper)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
||||||
original = copy.deepcopy(packet)
|
original = copy.deepcopy(packet)
|
||||||
tamper.tamper(packet, logger)
|
tamper.tamper(packet, logger)
|
||||||
|
|
||||||
|
@ -254,7 +255,7 @@ def test_decompress(logger):
|
||||||
assert tamper.tamper_type == "compress", "Tamper action changed types."
|
assert tamper.tamper_type == "compress", "Tamper action changed types."
|
||||||
assert str(tamper) == "tamper{DNS:qd:compress}", "Tamper returned incorrect string representation: %s" % str(tamper)
|
assert str(tamper) == "tamper{DNS:qd:compress}", "Tamper returned incorrect string representation: %s" % str(tamper)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(dst="8.8.8.8")/UDP(dport=53)/DNS(qd=DNSQR(qname="minghui.ca.")))
|
packet = layers.packet.Packet(IP(dst="8.8.8.8")/UDP(dport=53)/DNS(qd=DNSQR(qname="minghui.ca.")))
|
||||||
original = packet.copy()
|
original = packet.copy()
|
||||||
tamper.tamper(packet, logger)
|
tamper.tamper(packet, logger)
|
||||||
assert bytes(packet["DNS"]) == b'\x00\x00\x01\x00\x00\x02\x00\x00\x00\x00\x00\x00\x07minghui\xc0\x1a\x00\x01\x00\x01\x02ca\x00\x00\x01\x00\x01'
|
assert bytes(packet["DNS"]) == b'\x00\x00\x01\x00\x00\x02\x00\x00\x00\x00\x00\x00\x07minghui\xc0\x1a\x00\x01\x00\x01\x02ca\x00\x00\x01\x00\x01'
|
||||||
|
@ -266,7 +267,7 @@ def test_decompress(logger):
|
||||||
assert confirm_unchanged(packet, original, IP, ["len"])
|
assert confirm_unchanged(packet, original, IP, ["len"])
|
||||||
print(resp.summary())
|
print(resp.summary())
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(dst="8.8.8.8")/UDP(dport=53)/DNS(qd=DNSQR(qname="maps.google.com")))
|
packet = layers.packet.Packet(IP(dst="8.8.8.8")/UDP(dport=53)/DNS(qd=DNSQR(qname="maps.google.com")))
|
||||||
original = packet.copy()
|
original = packet.copy()
|
||||||
tamper.tamper(packet, logger)
|
tamper.tamper(packet, logger)
|
||||||
assert bytes(packet["DNS"]) == b'\x00\x00\x01\x00\x00\x02\x00\x00\x00\x00\x00\x00\x04maps\xc0\x17\x00\x01\x00\x01\x06google\x03com\x00\x00\x01\x00\x01'
|
assert bytes(packet["DNS"]) == b'\x00\x00\x01\x00\x00\x02\x00\x00\x00\x00\x00\x00\x04maps\xc0\x17\x00\x01\x00\x01\x06google\x03com\x00\x00\x01\x00\x01'
|
||||||
|
@ -279,7 +280,7 @@ def test_decompress(logger):
|
||||||
print(resp.summary())
|
print(resp.summary())
|
||||||
|
|
||||||
# Confirm this is a NOP on normal packets
|
# Confirm this is a NOP on normal packets
|
||||||
packet = actions.packet.Packet(IP()/UDP())
|
packet = layers.packet.Packet(IP()/UDP())
|
||||||
original = packet.copy()
|
original = packet.copy()
|
||||||
tamper.tamper(packet, logger)
|
tamper.tamper(packet, logger)
|
||||||
assert packet.packet.summary() == original.packet.summary()
|
assert packet.packet.summary() == original.packet.summary()
|
||||||
|
@ -302,7 +303,7 @@ def test_corrupt_chksum(logger):
|
||||||
assert tamper.tamper_type == "corrupt", "Tamper action changed types."
|
assert tamper.tamper_type == "corrupt", "Tamper action changed types."
|
||||||
assert str(tamper) == "tamper{TCP:chksum:corrupt}", "Tamper returned incorrect string representation: %s" % str(tamper)
|
assert str(tamper) == "tamper{TCP:chksum:corrupt}", "Tamper returned incorrect string representation: %s" % str(tamper)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
||||||
original = copy.deepcopy(packet)
|
original = copy.deepcopy(packet)
|
||||||
tamper.tamper(packet, logger)
|
tamper.tamper(packet, logger)
|
||||||
|
|
||||||
|
@ -326,7 +327,7 @@ def test_corrupt_dataofs(logger):
|
||||||
"""
|
"""
|
||||||
Tests the tamper 'replace' primitive.
|
Tests the tamper 'replace' primitive.
|
||||||
"""
|
"""
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S", dataofs="6L"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S", dataofs="6L"))
|
||||||
original = copy.deepcopy(packet)
|
original = copy.deepcopy(packet)
|
||||||
tamper = actions.tamper.TamperAction(None, field="dataofs", tamper_type="corrupt")
|
tamper = actions.tamper.TamperAction(None, field="dataofs", tamper_type="corrupt")
|
||||||
|
|
||||||
|
@ -357,7 +358,7 @@ def test_replace(logger):
|
||||||
assert tamper.field == "flags", "Tamper action changed fields."
|
assert tamper.field == "flags", "Tamper action changed fields."
|
||||||
assert tamper.tamper_type == "replace", "Tamper action changed types."
|
assert tamper.tamper_type == "replace", "Tamper action changed types."
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
||||||
original = copy.deepcopy(packet)
|
original = copy.deepcopy(packet)
|
||||||
tamper.tamper(packet, logger)
|
tamper.tamper(packet, logger)
|
||||||
|
|
||||||
|
@ -400,7 +401,7 @@ def test_parse_flags(logger):
|
||||||
assert tamper.tamper_type == "replace", "Tamper action changed types."
|
assert tamper.tamper_type == "replace", "Tamper action changed types."
|
||||||
assert str(tamper) == "tamper{TCP:flags:replace:FRAPUN}", "Tamper returned incorrect string representation: %s" % str(tamper)
|
assert str(tamper) == "tamper{TCP:flags:replace:FRAPUN}", "Tamper returned incorrect string representation: %s" % str(tamper)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
||||||
tamper.tamper(packet, logger)
|
tamper.tamper(packet, logger)
|
||||||
assert packet[TCP].flags == "FRAPUN", "Tamper failed to change flags."
|
assert packet[TCP].flags == "FRAPUN", "Tamper failed to change flags."
|
||||||
|
|
||||||
|
@ -417,21 +418,21 @@ def test_options(logger, value, test_type):
|
||||||
tamper = actions.tamper.TamperAction(None)
|
tamper = actions.tamper.TamperAction(None)
|
||||||
assert tamper.parse("TCP:options-%s:corrupt" % value.lower(), logger)
|
assert tamper.parse("TCP:options-%s:corrupt" % value.lower(), logger)
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
||||||
tamper.run(packet, logger)
|
tamper.run(packet, logger)
|
||||||
opts_dict_lookup = value.lower().replace(" ", "_")
|
opts_dict_lookup = value.lower().replace(" ", "_")
|
||||||
|
|
||||||
for optname, optval in packet["TCP"].options:
|
for optname, optval in packet["TCP"].options:
|
||||||
if optname == value:
|
if optname == value:
|
||||||
break
|
break
|
||||||
elif optname == actions.layer.TCPLayer.options_names[opts_dict_lookup]:
|
elif optname == layers.ip_layer.TCPLayer.options_names[opts_dict_lookup]:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
pytest.fail("Failed to find %s in options" % value)
|
pytest.fail("Failed to find %s in options" % value)
|
||||||
assert len(packet["TCP"].options) == 1
|
assert len(packet["TCP"].options) == 1
|
||||||
raw_p = bytes(packet)
|
raw_p = bytes(packet)
|
||||||
assert raw_p, "options broke scapy bytes"
|
assert raw_p, "options broke scapy bytes"
|
||||||
p2 = actions.packet.Packet(IP(bytes(raw_p)))
|
p2 = layers.packet.Packet(IP(bytes(raw_p)))
|
||||||
assert p2.haslayer("IP")
|
assert p2.haslayer("IP")
|
||||||
assert p2.haslayer("TCP")
|
assert p2.haslayer("TCP")
|
||||||
# EOLs might be added for padding, so just check >= 1
|
# EOLs might be added for padding, so just check >= 1
|
||||||
|
@ -439,7 +440,7 @@ def test_options(logger, value, test_type):
|
||||||
for optname, optval in p2["TCP"].options:
|
for optname, optval in p2["TCP"].options:
|
||||||
if optname == value:
|
if optname == value:
|
||||||
break
|
break
|
||||||
elif optname == actions.layer.TCPLayer.options_names[opts_dict_lookup]:
|
elif optname == layers.ip_layer.TCPLayer.options_names[opts_dict_lookup]:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
pytest.fail("Failed to find %s in options" % value)
|
pytest.fail("Failed to find %s in options" % value)
|
||||||
|
@ -458,7 +459,7 @@ def test_tamper_mutate_compress(logger):
|
||||||
assert tamper.tamper_type == "compress"
|
assert tamper.tamper_type == "compress"
|
||||||
assert tamper.tamper_proto_str == "DNS"
|
assert tamper.tamper_proto_str == "DNS"
|
||||||
assert tamper.field == "qd"
|
assert tamper.field == "qd"
|
||||||
packet = actions.packet.Packet(IP()/TCP()/DNS()/DNSQR())
|
packet = layers.packet.Packet(IP()/TCP()/DNS()/DNSQR())
|
||||||
packet2 = tamper.tamper(packet, logger)
|
packet2 = tamper.tamper(packet, logger)
|
||||||
assert packet2 == packet
|
assert packet2 == packet
|
||||||
finally:
|
finally:
|
||||||
|
|
|
@ -4,7 +4,7 @@ import pytest
|
||||||
sys.path.append("..")
|
sys.path.append("..")
|
||||||
|
|
||||||
import actions.trace
|
import actions.trace
|
||||||
import actions.packet
|
import layers.packet
|
||||||
import actions.strategy
|
import actions.strategy
|
||||||
import actions.utils
|
import actions.utils
|
||||||
import evolve
|
import evolve
|
||||||
|
@ -19,14 +19,14 @@ def test_trace(logger):
|
||||||
trace = actions.trace.TraceAction(start_ttl=1, end_ttl=3)
|
trace = actions.trace.TraceAction(start_ttl=1, end_ttl=3)
|
||||||
|
|
||||||
assert str(trace) == "trace{1:3}", "Trace returned incorrect string representation: %s" % str(trace)
|
assert str(trace) == "trace{1:3}", "Trace returned incorrect string representation: %s" % str(trace)
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
||||||
trace.run(packet, logger)
|
trace.run(packet, logger)
|
||||||
|
|
||||||
print("Testing that trace will not run twice:")
|
print("Testing that trace will not run twice:")
|
||||||
assert trace.run(packet, logger) == (None, None)
|
assert trace.run(packet, logger) == (None, None)
|
||||||
|
|
||||||
trace = actions.trace.TraceAction(start_ttl=1, end_ttl=3)
|
trace = actions.trace.TraceAction(start_ttl=1, end_ttl=3)
|
||||||
packet = actions.packet.Packet(TCP())
|
packet = layers.packet.Packet(TCP())
|
||||||
assert trace.run(packet, logger) == (packet, None)
|
assert trace.run(packet, logger) == (packet, None)
|
||||||
|
|
||||||
s = "[TCP:flags:PA]-trace{1:3}-| \/ "
|
s = "[TCP:flags:PA]-trace{1:3}-| \/ "
|
||||||
|
|
|
@ -7,6 +7,7 @@ import actions.drop
|
||||||
import actions.tamper
|
import actions.tamper
|
||||||
import actions.duplicate
|
import actions.duplicate
|
||||||
import actions.utils
|
import actions.utils
|
||||||
|
import layers.packet
|
||||||
|
|
||||||
|
|
||||||
def test_init():
|
def test_init():
|
||||||
|
@ -46,9 +47,9 @@ def test_check():
|
||||||
a = actions.tree.ActionTree("out")
|
a = actions.tree.ActionTree("out")
|
||||||
logger = logging.getLogger("test")
|
logger = logging.getLogger("test")
|
||||||
a.parse("[TCP:flags:RA]-tamper{TCP:flags:replace:S}-|", logger)
|
a.parse("[TCP:flags:RA]-tamper{TCP:flags:replace:S}-|", logger)
|
||||||
p = actions.packet.Packet(IP()/TCP(flags="A"))
|
p = layers.packet.Packet(IP()/TCP(flags="A"))
|
||||||
assert not a.check(p, logger)
|
assert not a.check(p, logger)
|
||||||
p = actions.packet.Packet(IP(ttl=64)/TCP(flags="RA"))
|
p = layers.packet.Packet(IP(ttl=64)/TCP(flags="RA"))
|
||||||
assert a.check(p, logger)
|
assert a.check(p, logger)
|
||||||
assert a.remove_one()
|
assert a.remove_one()
|
||||||
assert a.check(p, logger)
|
assert a.check(p, logger)
|
||||||
|
@ -56,7 +57,7 @@ def test_check():
|
||||||
assert a.check(p, logger)
|
assert a.check(p, logger)
|
||||||
a.parse("[IP:ttl:64]-tamper{TCP:flags:replace:S}-|", logger)
|
a.parse("[IP:ttl:64]-tamper{TCP:flags:replace:S}-|", logger)
|
||||||
assert a.check(p, logger)
|
assert a.check(p, logger)
|
||||||
p = actions.packet.Packet(IP(ttl=15)/TCP(flags="RA"))
|
p = layers.packet.Packet(IP(ttl=15)/TCP(flags="RA"))
|
||||||
assert not a.check(p, logger)
|
assert not a.check(p, logger)
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,11 +68,11 @@ def test_scapy():
|
||||||
a = actions.tree.ActionTree("out")
|
a = actions.tree.ActionTree("out")
|
||||||
logger = logging.getLogger("test")
|
logger = logging.getLogger("test")
|
||||||
a.parse("[TCP:reserved:0]-tamper{TCP:flags:replace:S}-|", logger)
|
a.parse("[TCP:reserved:0]-tamper{TCP:flags:replace:S}-|", logger)
|
||||||
p = actions.packet.Packet(IP()/TCP(flags="A"))
|
p = layers.packet.Packet(IP()/TCP(flags="A"))
|
||||||
assert a.check(p, logger)
|
assert a.check(p, logger)
|
||||||
packets = a.run(p, logger)
|
packets = a.run(p, logger)
|
||||||
assert packets[0][TCP].flags == "S"
|
assert packets[0][TCP].flags == "S"
|
||||||
p = actions.packet.Packet(IP()/TCP(flags="A"))
|
p = layers.packet.Packet(IP()/TCP(flags="A"))
|
||||||
assert a.check(p, logger)
|
assert a.check(p, logger)
|
||||||
a.parse("[TCP:reserved:0]-tamper{TCP:chksum:corrupt}-|", logger)
|
a.parse("[TCP:reserved:0]-tamper{TCP:chksum:corrupt}-|", logger)
|
||||||
packets = a.run(p, logger)
|
packets = a.run(p, logger)
|
||||||
|
@ -424,7 +425,7 @@ def test_run():
|
||||||
duplicate2 = actions.duplicate.DuplicateAction()
|
duplicate2 = actions.duplicate.DuplicateAction()
|
||||||
drop = actions.drop.DropAction()
|
drop = actions.drop.DropAction()
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP()/TCP())
|
packet = layers.packet.Packet(IP()/TCP())
|
||||||
a.add_action(tamper)
|
a.add_action(tamper)
|
||||||
packets = a.run(packet, logging.getLogger("test"))
|
packets = a.run(packet, logging.getLogger("test"))
|
||||||
assert len(packets) == 1
|
assert len(packets) == 1
|
||||||
|
@ -433,7 +434,7 @@ def test_run():
|
||||||
a.add_action(tamper2)
|
a.add_action(tamper2)
|
||||||
print(str(a))
|
print(str(a))
|
||||||
|
|
||||||
packet = actions.packet.Packet(IP()/TCP())
|
packet = layers.packet.Packet(IP()/TCP())
|
||||||
assert not a.add_action(tamper), "tree added duplicate action"
|
assert not a.add_action(tamper), "tree added duplicate action"
|
||||||
packets = a.run(packet, logging.getLogger("test"))
|
packets = a.run(packet, logging.getLogger("test"))
|
||||||
assert len(packets) == 1
|
assert len(packets) == 1
|
||||||
|
@ -444,7 +445,7 @@ def test_run():
|
||||||
a.remove_action(tamper2)
|
a.remove_action(tamper2)
|
||||||
a.remove_action(tamper)
|
a.remove_action(tamper)
|
||||||
a.add_action(duplicate)
|
a.add_action(duplicate)
|
||||||
packet = actions.packet.Packet(IP()/TCP(flags="RA"))
|
packet = layers.packet.Packet(IP()/TCP(flags="RA"))
|
||||||
packets = a.run(packet, logging.getLogger("test"))
|
packets = a.run(packet, logging.getLogger("test"))
|
||||||
assert len(packets) == 2
|
assert len(packets) == 2
|
||||||
assert None not in packets
|
assert None not in packets
|
||||||
|
@ -454,7 +455,7 @@ def test_run():
|
||||||
|
|
||||||
duplicate.left = tamper
|
duplicate.left = tamper
|
||||||
duplicate.right = tamper2
|
duplicate.right = tamper2
|
||||||
packet = actions.packet.Packet(IP()/TCP(flags="RA"))
|
packet = layers.packet.Packet(IP()/TCP(flags="RA"))
|
||||||
print("ABUT TO RUN")
|
print("ABUT TO RUN")
|
||||||
packets = a.run(packet, logging.getLogger("test"))
|
packets = a.run(packet, logging.getLogger("test"))
|
||||||
assert len(packets) == 2
|
assert len(packets) == 2
|
||||||
|
@ -467,7 +468,7 @@ def test_run():
|
||||||
print(str(a))
|
print(str(a))
|
||||||
|
|
||||||
tamper.left = duplicate2
|
tamper.left = duplicate2
|
||||||
packet = actions.packet.Packet(IP()/TCP(flags="RA"))
|
packet = layers.packet.Packet(IP()/TCP(flags="RA"))
|
||||||
packets = a.run(packet, logging.getLogger("test"))
|
packets = a.run(packet, logging.getLogger("test"))
|
||||||
assert len(packets) == 3
|
assert len(packets) == 3
|
||||||
assert None not in packets
|
assert None not in packets
|
||||||
|
@ -477,7 +478,7 @@ def test_run():
|
||||||
print(str(a))
|
print(str(a))
|
||||||
|
|
||||||
tamper2.left = drop
|
tamper2.left = drop
|
||||||
packet = actions.packet.Packet(IP()/TCP(flags="RA"))
|
packet = layers.packet.Packet(IP()/TCP(flags="RA"))
|
||||||
packets = a.run(packet, logging.getLogger("test"))
|
packets = a.run(packet, logging.getLogger("test"))
|
||||||
assert len(packets) == 2
|
assert len(packets) == 2
|
||||||
assert None not in packets
|
assert None not in packets
|
||||||
|
@ -487,13 +488,13 @@ def test_run():
|
||||||
|
|
||||||
assert a.remove_action(duplicate2)
|
assert a.remove_action(duplicate2)
|
||||||
tamper.left = actions.drop.DropAction()
|
tamper.left = actions.drop.DropAction()
|
||||||
packet = actions.packet.Packet(IP()/TCP(flags="RA"))
|
packet = layers.packet.Packet(IP()/TCP(flags="RA"))
|
||||||
packets = a.run(packet, logger )
|
packets = a.run(packet, logger )
|
||||||
assert len(packets) == 0
|
assert len(packets) == 0
|
||||||
print(str(a))
|
print(str(a))
|
||||||
|
|
||||||
a.parse("[TCP:flags:A]-duplicate(tamper{TCP:flags:replace:R}(tamper{TCP:chksum:replace:14239},),duplicate(tamper{TCP:flags:replace:S},))-|", logger)
|
a.parse("[TCP:flags:A]-duplicate(tamper{TCP:flags:replace:R}(tamper{TCP:chksum:replace:14239},),duplicate(tamper{TCP:flags:replace:S},))-|", logger)
|
||||||
packet = actions.packet.Packet(IP()/TCP(flags="A"))
|
packet = layers.packet.Packet(IP()/TCP(flags="A"))
|
||||||
assert a.check(packet, logger)
|
assert a.check(packet, logger)
|
||||||
packets = a.run(packet, logger)
|
packets = a.run(packet, logger)
|
||||||
assert len(packets) == 3
|
assert len(packets) == 3
|
||||||
|
|
|
@ -2,7 +2,7 @@ import sys
|
||||||
# Include the root of the project
|
# Include the root of the project
|
||||||
sys.path.append("..")
|
sys.path.append("..")
|
||||||
|
|
||||||
import actions.packet
|
import layers.packet
|
||||||
import actions.strategy
|
import actions.strategy
|
||||||
import actions.tamper
|
import actions.tamper
|
||||||
import actions.utils
|
import actions.utils
|
||||||
|
@ -23,7 +23,7 @@ def test_init(logger):
|
||||||
"""
|
"""
|
||||||
Tests initialization.
|
Tests initialization.
|
||||||
"""
|
"""
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="S"))
|
||||||
trigger = actions.trigger.Trigger(None, None, None)
|
trigger = actions.trigger.Trigger(None, None, None)
|
||||||
trigger.is_applicable(packet, logger)
|
trigger.is_applicable(packet, logger)
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ def test_trigger_gas(logger):
|
||||||
"""
|
"""
|
||||||
Tests triggers having gas, including changing that gas while in use
|
Tests triggers having gas, including changing that gas while in use
|
||||||
"""
|
"""
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="SA"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="SA"))
|
||||||
trigger = actions.trigger.Trigger("field", "flags", "TCP", trigger_value="SA", gas=1)
|
trigger = actions.trigger.Trigger("field", "flags", "TCP", trigger_value="SA", gas=1)
|
||||||
print(trigger)
|
print(trigger)
|
||||||
assert trigger.is_applicable(packet, logger)
|
assert trigger.is_applicable(packet, logger)
|
||||||
|
@ -66,7 +66,7 @@ def test_bomb_trigger_gas(logger):
|
||||||
"""
|
"""
|
||||||
Tests triggers having bomb gas, including changing that gas while in use
|
Tests triggers having bomb gas, including changing that gas while in use
|
||||||
"""
|
"""
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="SA"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="SA"))
|
||||||
trigger = actions.trigger.Trigger("field", "flags", "TCP", trigger_value="SA", gas=-1)
|
trigger = actions.trigger.Trigger("field", "flags", "TCP", trigger_value="SA", gas=-1)
|
||||||
print(trigger)
|
print(trigger)
|
||||||
assert not trigger.is_applicable(packet, logger), "trigger should not fire on first run"
|
assert not trigger.is_applicable(packet, logger), "trigger should not fire on first run"
|
||||||
|
@ -98,7 +98,7 @@ def test_trigger_parse_gas(logger):
|
||||||
"""
|
"""
|
||||||
Tests triggers having gas, including changing that gas while in use
|
Tests triggers having gas, including changing that gas while in use
|
||||||
"""
|
"""
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="SA"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="SA"))
|
||||||
|
|
||||||
|
|
||||||
# parse a trigger with 1 gas
|
# parse a trigger with 1 gas
|
||||||
|
@ -132,7 +132,7 @@ def test_bomb_trigger_parse_gas(logger):
|
||||||
"""
|
"""
|
||||||
Tests bomb triggers having gas, including changing that gas while in use
|
Tests bomb triggers having gas, including changing that gas while in use
|
||||||
"""
|
"""
|
||||||
packet = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="SA"))
|
packet = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="SA"))
|
||||||
|
|
||||||
# parse a bomb trigger with 1 gas
|
# parse a bomb trigger with 1 gas
|
||||||
trigger = actions.trigger.Trigger.parse("TCP:flags:SA:-1")
|
trigger = actions.trigger.Trigger.parse("TCP:flags:SA:-1")
|
||||||
|
@ -168,10 +168,10 @@ def test_wildcard(logger):
|
||||||
"""
|
"""
|
||||||
Test wildcard trigger value
|
Test wildcard trigger value
|
||||||
"""
|
"""
|
||||||
packet_1 = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="A"))
|
packet_1 = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="A"))
|
||||||
packet_2 = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="SA"))
|
packet_2 = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="SA"))
|
||||||
packet_3 = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="RA"))
|
packet_3 = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="RA"))
|
||||||
packet_4 = actions.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="P"))
|
packet_4 = layers.packet.Packet(IP(src="127.0.0.1", dst="127.0.0.1")/TCP(sport=2222, dport=3333, seq=100, ack=100, flags="P"))
|
||||||
trigger = actions.trigger.Trigger("field", "flags", "TCP", trigger_value="A*", gas=None)
|
trigger = actions.trigger.Trigger("field", "flags", "TCP", trigger_value="A*", gas=None)
|
||||||
assert trigger.is_applicable(packet_1, logger)
|
assert trigger.is_applicable(packet_1, logger)
|
||||||
assert trigger.is_applicable(packet_2, logger)
|
assert trigger.is_applicable(packet_2, logger)
|
||||||
|
|
Loading…
Reference in New Issue