-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrules-generator.py
executable file
·179 lines (149 loc) · 6.35 KB
/
rules-generator.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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
import argparse
import logging
import os
import pandas as pd
import requests
import sys
from lxml import etree
# Config #
# Logger
logging.basicConfig(filename="logFile.log",
format='%(asctime)s %(levelname)-10s %(message)s',
datefmt="%Y-%m-%d-%H-%M-%S",
filemode='w')
log = logging.getLogger()
log.addHandler(logging.StreamHandler(sys.stdout))
log.setLevel(logging.INFO)
# Argument parser
p = argparse.ArgumentParser()
# Mandatory parameters
# The file where the countermeasures are listed
p.add_argument('--input', type=str)
# How the countermeasure will be set: "required" or "implemented"
p.add_argument('--mode', type=str)
# Select one:
# Option 1: Access to an IriusRisk instance to get where do the countermeasures live
p.add_argument('--url', type=str, nargs="?")
p.add_argument('--token', type=str, nargs="?")
# Option 2: Get where the countermeasures live from a folder with the libraries
p.add_argument('--libs', type=str, nargs="?")
args = p.parse_args()
LIBS_FOLDER = args.libs
IRIUS_URL = args.url
IRIUS_TOKEN = args.token
INPUT_FILE = args.input
MODE = args.mode
COMPANY_NAME = "Company"
#
def read_input_file(file):
"""
Reads the input file and extracts the countermeasures
:param file: input file in several formats (csv, txt, xlsx, xlsx...)
:return: a set with the refs of the countermeasures
"""
required = set()
if file.endswith(('.csv', '.txt')):
with open(file, "r") as ff:
for element in ff.read().splitlines():
required.add(element)
if file.endswith(('.xls', '.xlsx')):
sheet_to_df_map = pd.read_excel(file, sheet_name=None)
for k, v in sheet_to_df_map.items():
ref_list = v["Ref"].to_list()
cleaned_list = [x for x in ref_list if str(x) != 'nan']
required.update(cleaned_list)
return required
def get_library_countermeasure_map(folder):
"""
If URL+Token is detected this method will query the IriusRisk API to get the information about the libraries.
If a folder path is passed in then the information will be retrieved from the XMLs.
:return: a map with the libraries and all the countermeasures that are inside each one of them
"""
lib_map = dict()
if folder:
for filename in os.listdir(str(folder)):
f = os.path.join(folder, filename)
if os.path.isfile(f) and f.endswith(".xml"):
tree = etree.parse(f)
root = tree.getroot()
lib = root.attrib["ref"]
lib_map[lib] = set()
for rp in root.find("riskPatterns").iter("riskPattern"):
for c in rp.find("countermeasures").iter("countermeasure"):
lib_map[lib].add(c.attrib["ref"])
log.info(f"Detected {len(lib_map[lib])} countermeasures in {lib}...")
else:
header = {"api-token": IRIUS_TOKEN}
response = requests.get(IRIUS_URL + "/api/v1/libraries", headers=header)
all_libraries_data = response.json()
for e in all_libraries_data:
response2 = requests.get(IRIUS_URL + "/api/v1/libraries/" + e["ref"], headers=header)
library_data = response2.json()
lib = e['ref']
lib_map[lib] = set()
for rp in library_data["riskPatterns"]:
for c in rp["countermeasures"]:
lib_map[lib].add(c["ref"])
log.info(f"Detected {len(lib_map[lib])} countermeasures in {lib}...")
return lib_map
def get_lib_for_countermeasure(ref, lib_map):
"""
Since the countermeasure can live in more than one library this method ensures that the chosen library is the one that has the most number of countermeasures
:param ref:
:param lib_map:
:return:
"""
options = set([k for k, v in lib_map.items() if ref in v])
lib_name, number = ("", 0)
if len(options) > 0:
lib_name, number = max([(k, len(v)) for k, v in lib_map.items() if k in options], key=lambda item: item[1])
return lib_name
def main():
# Getting list of countermeasures
list_of_countermeasures = read_input_file(INPUT_FILE)
if len(list_of_countermeasures) > 0:
log.info(f"Detected {len(list_of_countermeasures)} to mark as {MODE}")
else:
log.error(f"No values have been detected in {INPUT_FILE}. Exiting...")
exit(-1)
# Detecting mode
action_mode = ""
if MODE == "required":
action_mode = "APPLY_CONTROL"
if MODE == "implemented":
action_mode = "IMPLEMENT_CONTROL"
if action_mode == "":
log.error("No action has been indicated on --mode parameter. Exiting...")
exit(-1)
# Getting list of libraries for countermeasures
lib_map = {}
if IRIUS_URL and IRIUS_TOKEN:
lib_map = get_library_countermeasure_map(None)
elif LIBS_FOLDER:
lib_map = get_library_countermeasure_map(LIBS_FOLDER)
else:
log.error("No values have been indicated on --url/token or --libs. Exiting...")
exit(-1)
# Generating rules
already_added = set()
not_added = set()
with open("rules.txt", "w") as output:
for control in list_of_countermeasures:
libname = get_lib_for_countermeasure(control, lib_map)
if libname != "":
rulename = f'{COMPANY_NAME} - Mark as {MODE} - {control}'
conditions = '<condition name="CONDITION_IS_IN_TRUSTZONE" field="id" value="aaaaaaaa-bbbb-cccc-dddd-eeeeffff0000_::_trust-zone"/>'
actions = f'<action project="{libname}" value="{control}_::_false" name="{action_mode}"/>'
result = f'<rule name="{rulename}" module="component" generatedByGui="true"><conditions>{conditions}</conditions><actions>{actions}</actions></rule>'
log.info(result)
already_added.add(control)
output.write(result + "\n")
else:
not_added.add(control)
log.info(
f"Finished! Added {len(already_added)} rules. You just need to copy the output from the rules.txt file to your library.")
log.info(f"List of all countermeasures detected: {sorted(list_of_countermeasures)}")
log.info(f"List of all countermeasures added: {sorted(already_added)}")
log.info(f"List of all countermeasures not added: {sorted(not_added)}")
if __name__ == "__main__":
main()