diff --git a/atomics/T1055/T1055.yaml b/atomics/T1055/T1055.yaml index 6de0d7d9..fa94cb2c 100644 --- a/atomics/T1055/T1055.yaml +++ b/atomics/T1055/T1055.yaml @@ -130,7 +130,6 @@ atomic_tests: name: powershell elevation_required: false - name: Read-Write-Execute process Injection - auto_generated_guid: 49543237-25db-497b-90df-d0a0a6e8fe2c description: | This test exploited the vulnerability in legitimate PE formats where sections have RWX permission and enough space for shellcode. The RWX injection avoided the use of VirtualAlloc, WriteVirtualMemory, and ProtectVirtualMemory, thus evading detection mechanisms diff --git a/bin/validate/validate.py b/bin/validate/validate.py index 927f9e22..c1f3c447 100644 --- a/bin/validate/validate.py +++ b/bin/validate/validate.py @@ -23,6 +23,19 @@ class InvalidFileName(BaseError): return f"Invalid filename. Rename file from .yml to .yaml" +class ReusedGuid(BaseError): + def __init__(self, path, guid, test_number): + super().__init__(path) + self.guid = guid + self.test_number = test_number + + def __str__(self): + return ( + f"GUID {self.guid} reused for test {self.test_number}. GUIDs are auto generated." + f"You can remove atomic_tests[{self.test_number}].auto_generated_guid" + ) + + class UnusedArgument(BaseError): def __init__(self, path, argument, test_number): super().__init__(path) @@ -37,8 +50,13 @@ class Validator: errors = defaultdict(list) def __init__(self): - with open(f"{os.path.dirname(os.path.abspath(__file__))}/atomic-red-team.schema.yaml", "r") as f: + schema_path = f"{os.path.dirname(os.path.abspath(__file__))}/atomic-red-team.schema.yaml" + used_guids_path = "./atomics/used_guids.txt" + with open(used_guids_path, "r") as f: + self.used_guids = [x.strip() for x in f.readlines()] + with open(schema_path, "r") as f: self.schema = yaml.safe_load(f) + self.guids = [] def validate(self, obj: DirEntry): if obj.is_file(): @@ -50,14 +68,21 @@ class Validator: def validate_file(self, file: DirEntry): """Performs file validation""" self.validate_yaml_extension(file) - self.validate_input_args(file) + self.validate_atomic(file) self.validate_json_schema(file) - def validate_input_args(self, file: DirEntry): + def validate_atomic(self, file: DirEntry): """Validates whether the defined input args are used.""" with open(file.path, "r") as f: atomic = yaml.safe_load(f) for index, t in enumerate(atomic["atomic_tests"]): + if t.get("auto_generated_guid"): + if t["auto_generated_guid"] not in self.guids: + self.guids.append(t["auto_generated_guid"]) + else: + self.errors[file.path].append( + ReusedGuid(file.path, t["auto_generated_guid"], index + 1) + ) if args := t.get("input_arguments"): for k in list(args.keys()): variable = f"#{{{k}}}" @@ -65,7 +90,11 @@ class Validator: deps = t.get("dependencies", []) if executor: - commands = [executor.get("command"), executor.get("cleanup_command"), executor.get("steps")] + commands = [ + executor.get("command"), + executor.get("cleanup_command"), + executor.get("steps"), + ] if deps: commands += [d.get("get_prereq_command") for d in deps] commands += [d.get("prereq_command") for d in deps] @@ -96,7 +125,7 @@ class Validator: self.validate_directory_path(directory) def validate_directory_path(self, directory: DirEntry): - """Validated whether the directory is a allowed directory name (`src` or `bin`) """ + """Validated whether the directory is a allowed directory name (`src` or `bin`)""" if directory.name not in ["src", "bin"]: self.errors[directory.path].append(InvalidPath(directory.path))