Browse Source

Reorganized layers into new directory.

pull/17/head
Michael Harrity 1 year ago
parent
commit
0796312589
  1. 10
      actions/fragment.py
  2. 854
      actions/layer.py
  3. 4
      actions/sniffer.py
  4. 2
      actions/tamper.py
  5. 3
      actions/trigger.py
  6. 6
      actions/utils.py
  7. 4
      censors/censor.py
  8. 10
      censors/censor1.py
  9. 16
      censors/censor10.py
  10. 16
      censors/censor11.py
  11. 10
      censors/censor2.py
  12. 10
      censors/censor3.py
  13. 12
      censors/censor4.py
  14. 10
      censors/censor5.py
  15. 10
      censors/censor6.py
  16. 10
      censors/censor7.py
  17. 12
      censors/censor8.py
  18. 16
      censors/censor8b.py
  19. 10
      censors/censor9.py
  20. 2
      docs/api/actions/layer.rst
  21. 2
      docs/api/actions/packet.rst
  22. 10
      engine.py
  23. 3
      evolve.py
  24. 189
      layers/dns_layer.py
  25. 48
      layers/dnsqr_layer.py
  26. 103
      layers/ip_layer.py
  27. 197
      layers/layer.py
  28. 20
      layers/packet.py
  29. 10
      layers/raw_layer.py
  30. 285
      layers/tcp_layer.py
  31. 32
      layers/udp_layer.py
  32. 4
      tests/conftest.py
  33. 4
      tests/test_duplicate.py
  34. 4
      tests/test_engine.py
  35. 22
      tests/test_evolve.py
  36. 46
      tests/test_fragment.py
  37. 28
      tests/test_options.py
  38. 225
      tests/test_packet.py
  39. 3
      tests/test_population_files.py
  40. 4
      tests/test_sleep.py
  41. 15
      tests/test_strategy.py
  42. 45
      tests/test_tamper.py
  43. 6
      tests/test_trace.py
  44. 27
      tests/test_tree.py
  45. 20
      tests/test_trigger.py

10
actions/fragment.py

@ -1,6 +1,6 @@
import random
from actions.action import Action
import actions.packet
import layers.packet
from scapy.all import IP, TCP, fragment
@ -88,8 +88,8 @@ class FragmentAction(Action):
else:
# packet can be fragmented as requested
frags = self.fragment(packet.copy().packet, fragsize=self.fragsize*8)
packet1 = actions.packet.Packet(frags[0])
packet2 = actions.packet.Packet(frags[1])
packet1 = layers.packet.Packet(frags[0])
packet2 = layers.packet.Packet(frags[1])
if self.correct_order:
return packet1, packet2
else:
@ -132,8 +132,8 @@ class FragmentAction(Action):
if not pkt2.haslayer("TCP"):
pkt2 = IP(packet["IP"])/TCP(bytes(pkt2["IP"].load))
packet1 = actions.packet.Packet(pkt1)
packet2 = actions.packet.Packet(pkt2)
packet1 = layers.packet.Packet(pkt1)
packet2 = layers.packet.Packet(pkt2)
# Reset packet2's SYN number
if packet2["TCP"].seq + fragsize > MAX_UINT:

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"]

4
actions/sniffer.py

@ -1,7 +1,7 @@
import threading
import os
import actions.packet
import layers.packet
from scapy.all import sniff
from scapy.utils import PcapWriter
@ -33,7 +33,7 @@ class Sniffer():
This callback is called whenever a packet is applied.
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"]:
if(packet.haslayer(proto) and ((packet[proto].sport == self.port) or (packet[proto].dport == self.port))):
break

2
actions/tamper.py

@ -12,7 +12,7 @@ modifications (particularly header modifications). It supports the following pri
from actions.action import Action
import actions.utils
from actions.layer import DNSLayer
from layers.dns_layer import DNSLayer
import random

3
actions/trigger.py

@ -1,6 +1,7 @@
import actions.utils
import random
import re
import layers.packet
FIXED_TRIGGER = None
GAS_ENABLED = True
@ -177,7 +178,7 @@ class Trigger(object):
value = m.group(3)
# 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 = None

6
actions/utils.py

@ -12,7 +12,7 @@ import urllib.parse
import actions.action
import actions.trigger
import actions.packet
import layers.packet
import plugins.plugin_client
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:
packet = random.choice(packets)
return packet.get_random()
return actions.packet.Packet().gen_random()
return layers.packet.Packet().gen_random()
def read_packets(environment_id):
@ -327,7 +327,7 @@ def read_packets(environment_id):
parsed = []
try:
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:
print(e)
print("FAILED TO PARSE!")

4
censors/censor.py

@ -4,7 +4,7 @@ import logging
import random
import os
import actions.packet
import layers.packet
import actions.utils
# Squelch annoying scapy ::1 runtime errors
@ -104,7 +104,7 @@ class Censor(object):
Sends a packet with scapy.
"""
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)
return

10
censors/censor1.py

@ -8,7 +8,7 @@ drops all packets after a TCP forbidden keyword is detected.
"""
import logging
import actions.packet
import layers.packet
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
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.
"""
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:
self.logger.debug("Dropping all from this IP %s..." % self.drop_all_from)
return True
@ -45,20 +45,20 @@ class Censor1(Censor):
# Initial TCP synchronization
if packet["TCP"].sprintf('%TCP.flags%') == "S":
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
# If we're tracking this packet stream
if packet["TCP"].seq == self.tcb:
self.tcb += len(self.get_payload(packet))
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
# Check if any forbidden words appear in the packet payload
for keyword in self.forbidden:
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 False

16
censors/censor10.py

@ -9,7 +9,7 @@ work.
"""
import netifaces
import actions.packet
import layers.packet
from censors.censor import Censor
from scapy.all import raw, IP, TCP
@ -33,7 +33,7 @@ class Censor10(Censor):
Returns true or false.
"""
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:
self.logger.debug("Content from a flagged IP detected %s..." % packet["IP"].src)
return True
@ -65,7 +65,7 @@ class Censor10(Censor):
if not tcb:
tcb = self.get_partial_tcb(packet)
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["src"] = packet["IP"].src
@ -81,13 +81,13 @@ class Censor10(Censor):
self.tcbs.append(tcb)
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
# If connection is getting torn down
elif tcb and packet["TCP"].sprintf('%TCP.flags%') in ["R", "F"]:
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:
self.logger.debug("No TCB matches packet.")
@ -99,7 +99,7 @@ class Censor10(Censor):
# Check if any forbidden words appear in the packet payload
for keyword in self.forbidden:
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 False
@ -150,7 +150,7 @@ class Censor10(Censor):
Checks if the packet matches the stored TCB.
"""
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 \
packet["IP"].dst == tcb["dst"] and \
@ -166,7 +166,7 @@ class Censor10(Censor):
are correct.
"""
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 \
packet["IP"].dst == tcb["dst"] and \

16
censors/censor11.py

@ -9,7 +9,7 @@ work. It also resynchronizes on both S and ACK, defeating strategies that trigge
before the 3-way handshake has finished.
"""
import actions.packet
import layers.packet
import netifaces
from censors.censor import Censor
from scapy.all import raw, IP, TCP
@ -33,7 +33,7 @@ class Censor11(Censor):
Returns true or false.
"""
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:
self.logger.debug("Content from a flagged IP detected %s..." % packet["IP"].src)
return True
@ -65,7 +65,7 @@ class Censor11(Censor):
# so we can just replace that tcb with updated info
tcb = self.get_partial_tcb(packet)
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["src"] = packet["IP"].src
@ -81,13 +81,13 @@ class Censor11(Censor):
self.tcbs.append(tcb)
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
# If connection is getting torn down
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.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:
self.logger.debug("No TCB matches packet.")
@ -99,7 +99,7 @@ class Censor11(Censor):
# Check if any forbidden words appear in the packet payload
for keyword in self.forbidden:
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 False
@ -150,7 +150,7 @@ class Censor11(Censor):
Checks if the packet matches the stored TCB.
"""
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 \
packet["IP"].dst == tcb["dst"] and \
@ -166,7 +166,7 @@ class Censor11(Censor):
are correct.
"""
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 \
packet["IP"].dst == tcb["dst"] and \

10
censors/censor2.py

@ -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.
"""
import actions.packet
import layers.packet
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
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.
"""
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
if "TCP" not in packet:
@ -34,19 +34,19 @@ class Censor2(Censor):
if packet["TCP"].sprintf('%TCP.flags%') == "S":
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
if packet["TCP"].seq == self.tcb:
self.tcb += len(self.get_payload(packet))
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
for keyword in self.forbidden:
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 False

10
censors/censor3.py

@ -9,7 +9,7 @@ server AND client.
import logging
import netifaces
import actions.packet
import layers.packet
# Disable scapy ::1 warnings
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
@ -42,25 +42,25 @@ class Censor3(Censor):
self.num += 1
# 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:
return False
if packet["TCP"].sprintf('%TCP.flags%') == "S":
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
if packet["TCP"].seq == self.tcb:
self.tcb += len(self.get_payload(packet))
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
for keyword in self.forbidden:
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 False

12
censors/censor4.py

@ -4,7 +4,7 @@ Censor 4
Dropping censor that synchronizes TCB on all SYN and ACK packets.
"""
import actions.packet
import layers.packet
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import IP, TCP
@ -28,7 +28,7 @@ class Censor4(Censor):
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:
self.logger.debug("Dropping all from this IP %s..." % self.drop_all_from)
return True
@ -40,25 +40,25 @@ class Censor4(Censor):
# Initial TCP synchronization
if "S" == packet["TCP"].sprintf('%TCP.flags%'):
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
if "A" == packet["TCP"].sprintf('%TCP.flags%'):
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
# If we're tracking this packet stream
if packet["TCP"].seq == self.tcb:
self.tcb += len(self.get_payload(packet))
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
# Check if any forbidden words appear in the packet payload
for keyword in self.forbidden:
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 False

10
censors/censor5.py

@ -7,7 +7,7 @@ TCP Censor that synchronizes on first SYN only, works 100% of the time, sends 5
the server only.
"""
import actions.packet
import layers.packet
import logging
import netifaces
# Disable scapy ::1 warnings
@ -42,25 +42,25 @@ class Censor5(Censor):
self.num += 1
# 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:
return False
if packet["TCP"].sprintf('%TCP.flags%') == "S":
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
if packet["TCP"].seq == self.tcb:
self.tcb += len(self.get_payload(packet))
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
for keyword in self.forbidden:
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 False

10
censors/censor6.py

@ -4,7 +4,7 @@ FIN or RST packet.
Does not check if the ports are correct for the FIN/RST.
"""
import actions.packet
import layers.packet
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)