mirror of
https://github.com/Kkevsterrr/geneva
synced 2024-11-06 10:52:02 +01:00
Reorganized layers into new directory.
This commit is contained in:
parent
b27ea50522
commit
0796312589
@ -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
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 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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||