-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsignature.py
132 lines (100 loc) · 4.26 KB
/
signature.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import ipaddress
import re
from helper import check_ip
class Signature:
"""
Represents a network traffic signature or rule.
"""
COMMON_LOCATION_KEYS = ["uri_raw", "http_header_content_type", "http_header", "http_client_body"]
def __init__(self, action, protocol, source_ip, destination_ip, source_port, destination_port, options):
self.action = action
self.protocol = protocol
self.source_ip = source_ip
self.destination_ip = destination_ip
self.source_port = source_port
self.destination_port = destination_port
self.options = options
@staticmethod
def parse_options(options_str):
"""
Parse the options string of a signature rule.
Args:
options_str (str): The options string to parse.
Returns:
dict: A dictionary containing the parsed options.
"""
# Initialize option dictionary
options = {}
# Split options string by semicolons outside of quotes
options_list = re.split(r';(?=(?:[^"]*"[^"]*")*[^"]*$)', options_str)
# Parse each option
for item in options_list:
if not item.strip():
continue
key_value = item.split(":", 1)
key = key_value[0].strip()
value = key_value[1].strip("'") if len(key_value) > 1 else None
if key not in Signature.COMMON_LOCATION_KEYS:
options[key] = value
else:
options["location"] = key
return options
@staticmethod
def parse_rule(rule_str: str):
"""
Parse a signature rule string into a Signature object.
Args:
rule_str (str): The signature rule string to parse.
Returns:
Signature: A Signature object representing the parsed rule.
"""
# Split the rule string into parts
parts = rule_str.split(" ")
# Extract action and protocol
action = parts[0]
protocol = parts[1]
# Extract source and destination IPs and ports
source_ip, source_port = parts[2:4]
direction = parts[4]
destination_ip, destination_port = parts[5:7]
# Extract options
options_start, options_end = rule_str.index("(") + 1, rule_str.rindex(")")
options_str = rule_str[options_start:options_end]
# Initialize option dictionary
options = Signature.parse_options(options_str)
return Signature(action, protocol, source_ip, destination_ip, source_port, destination_port, options)
def __eq__(self, other):
"""
Compare two Signature objects for equality.
Args:
other: Another Signature object.
Returns:
bool: True if the objects are equal, False otherwise.
"""
if not isinstance(other, Signature):
return False
# check for protocols
# basically not going to the rest of the checks
if not self.protocol == other.protocol:
return False
if not self.source_port == other.source_port and self.destination_port == other.destination_port:
return False
return check_ip(self.source_ip, other.source_ip) and check_ip(self.destination_ip, other.destination_ip)
def __str__(self):
return f"Signature(action='{self.action}', protocol='{self.protocol}', source_ip='{self.source_ip}', " \
f"destination_ip='{self.destination_ip}', source_port='{self.source_port}', " \
f"destination_port='{self.destination_port}', options={self.options})"
def __repr__(self):
return f"Signature(action='{self.action}', protocol='{self.protocol}', source_ip='{self.source_ip}', " \
f"destination_ip='{self.destination_ip}', source_port='{self.source_port}', " \
f"destination_port='{self.destination_port}', options={self.options})"
0
if __name__ == "__main__":
# Read signature rules from file
with open("test.rules", "r") as file:
signature_rules = file.readlines()
# Parse each signature rule and print the Signature object
for rule in signature_rules:
print(f"Rule ==> {rule}")
signature = Signature.parse_rule(rule.strip())
print(f"Signature ==> {signature} \n")