mirror of
https://github.com/Kkevsterrr/geneva
synced 2025-01-02 23:15:11 +01:00
133 lines
5.2 KiB
Python
133 lines
5.2 KiB
Python
"""
|
|
TamperAction
|
|
|
|
One of the four packet-level primitives supported by Geneva. Responsible for any packet-level
|
|
modifications (particularly header modifications). It supports the following primitives:
|
|
- no operation: it returns the packet given
|
|
- replace: it changes a packet field to a fixed value
|
|
- corrupt: it changes a packet field to a randomly generated value each time it is run
|
|
- add: adds a given value to the value in a field
|
|
- compress: performs DNS decompression on the packet (if applicable)
|
|
"""
|
|
|
|
from actions.action import Action
|
|
import actions.utils
|
|
from actions.layer import DNSLayer
|
|
|
|
import random
|
|
|
|
|
|
# All supported tamper primitives
|
|
SUPPORTED_PRIMITIVES = ["corrupt", "replace", "add", "compress"]
|
|
|
|
|
|
class TamperAction(Action):
|
|
"""
|
|
Defines the TamperAction for Geneva.
|
|
"""
|
|
def __init__(self, environment_id=None, field=None, tamper_type=None, tamper_value=None, tamper_proto="TCP"):
|
|
Action.__init__(self, "tamper", "both")
|
|
self.field = field
|
|
self.tamper_value = tamper_value
|
|
self.tamper_proto = actions.utils.string_to_protocol(tamper_proto)
|
|
self.tamper_proto_str = tamper_proto
|
|
self.tamper_type = tamper_type
|
|
|
|
def tamper(self, packet, logger):
|
|
"""
|
|
Edits a given packet according to the action settings.
|
|
"""
|
|
# Return packet untouched if not applicable
|
|
if not packet.haslayer(self.tamper_proto_str):
|
|
return packet
|
|
|
|
# Retrieve the old value of the field for logging purposes
|
|
old_value = packet.get(self.tamper_proto_str, self.field)
|
|
|
|
new_value = self.tamper_value
|
|
# If corrupting the packet field, generate a value for it
|
|
try:
|
|
if self.tamper_type == "corrupt":
|
|
new_value = packet.gen(self.tamper_proto_str, self.field)
|
|
elif self.tamper_type == "add":
|
|
new_value = int(self.tamper_value) + int(old_value)
|
|
elif self.tamper_type == "compress":
|
|
return packet.dns_decompress(logger)
|
|
except NotImplementedError:
|
|
# If a primitive does not support the type of packet given
|
|
return packet
|
|
except Exception:
|
|
# If an unexpected error has occurred
|
|
return packet
|
|
|
|
logger.debug(" - Tampering %s field `%s` (%s) by %s (to %s)" %
|
|
(self.tamper_proto_str, self.field, str(old_value), self.tamper_type, str(new_value)))
|
|
|
|
packet.set(self.tamper_proto_str, self.field, new_value)
|
|
|
|
return packet
|
|
|
|
def run(self, packet, logger):
|
|
"""
|
|
The tamper action runs its tamper procedure on the given packet, and
|
|
returns the edited packet down the left branch.
|
|
|
|
Nothing is returned to the right branch.
|
|
"""
|
|
return self.tamper(packet, logger), None
|
|
|
|
def __str__(self):
|
|
"""
|
|
Defines string representation for this object.
|
|
"""
|
|
s = Action.__str__(self)
|
|
if self.tamper_type == "corrupt":
|
|
s += "{%s:%s:%s}" % (self.tamper_proto_str, self.field, self.tamper_type)
|
|
elif self.tamper_type in ["replace", "add"]:
|
|
s += "{%s:%s:%s:%s}" % (self.tamper_proto_str, self.field, self.tamper_type, self.tamper_value)
|
|
elif self.tamper_type == "compress":
|
|
s += "{%s:%s:compress}" % ("DNS", "qd", )
|
|
|
|
return s
|
|
|
|
def parse(self, string, logger):
|
|
"""
|
|
Parse out a given string representation of this action and initialize
|
|
this action to those parameters.
|
|
|
|
Note that the given logger is a DIFFERENT logger than the logger passed
|
|
to the other functions, and they cannot be used interchangeably. This logger
|
|
is attached to the main GA driver, and is run outside the evaluator. When the
|
|
action is actually run, it's run within the evaluator, which by necessity must
|
|
pass in a different logger.
|
|
"""
|
|
# Different tamper actions will have different number of parameters
|
|
# Count the number of params in this given string
|
|
num_parameters = string.count(":")
|
|
|
|
# If num_parameters is greater than 3, it's not a valid tamper action
|
|
if num_parameters > 3 or num_parameters < 2:
|
|
msg = "Cannot parse tamper action %s" % string
|
|
logger.error(msg)
|
|
raise Exception(msg)
|
|
params = string.split(":")
|
|
if num_parameters == 3:
|
|
self.tamper_proto_str, self.field, self.tamper_type, self.tamper_value = params
|
|
self.tamper_proto = actions.utils.string_to_protocol(self.tamper_proto_str)
|
|
if "options" in self.field:
|
|
if not self.tamper_value:
|
|
self.tamper_value = '' # An empty string instead of an empty byte literal
|
|
|
|
# tamper_value might be parsed as a string despite being an integer in most cases.
|
|
# Try to parse it out here
|
|
try:
|
|
if "load" not in self.field:
|
|
self.tamper_value = int(self.tamper_value)
|
|
except:
|
|
pass
|
|
else:
|
|
self.tamper_proto_str, self.field, self.tamper_type = params
|
|
self.tamper_proto = actions.utils.string_to_protocol(self.tamper_proto_str)
|
|
|
|
return True
|