diff --git a/.gitignore b/.gitignore index 8ac3823..83e6903 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ __pycache__/ __pycache__/** **.swp +reports/ +reports/** diff --git a/issues/__init__.py b/audit/__init__.py similarity index 100% rename from issues/__init__.py rename to audit/__init__.py diff --git a/issues/calls.py b/audit/application/plugins/calls/calls.py similarity index 100% rename from issues/calls.py rename to audit/application/plugins/calls/calls.py diff --git a/audit/system/plugins/postfix/__init__.py b/audit/system/plugins/postfix/__init__.py new file mode 100644 index 0000000..e5a0d9b --- /dev/null +++ b/audit/system/plugins/postfix/__init__.py @@ -0,0 +1 @@ +#!/usr/bin/env python3 diff --git a/parsing/postfix.py b/audit/system/plugins/postfix/parsing.py similarity index 100% rename from parsing/postfix.py rename to audit/system/plugins/postfix/parsing.py diff --git a/issues/postfix.py b/audit/system/plugins/postfix/postfix.py similarity index 100% rename from issues/postfix.py rename to audit/system/plugins/postfix/postfix.py diff --git a/audit/system/plugins/sysctl/__init__.py b/audit/system/plugins/sysctl/__init__.py new file mode 100644 index 0000000..e5a0d9b --- /dev/null +++ b/audit/system/plugins/sysctl/__init__.py @@ -0,0 +1 @@ +#!/usr/bin/env python3 diff --git a/parsing/sysctl.py b/audit/system/plugins/sysctl/parsing.py similarity index 98% rename from parsing/sysctl.py rename to audit/system/plugins/sysctl/parsing.py index 0b3d7f6..3a8be2f 100644 --- a/parsing/sysctl.py +++ b/audit/system/plugins/sysctl/parsing.py @@ -78,7 +78,6 @@ class Parsing(ParsingBase): def _generateReport(self, objects): # We can generate the report for sysctl in self._reports['file']['sysctl']: - #self._reports['file']['sysctl'][sysctl] = vulnerabilityFound[sysctl] self._reports['file']['sysctl'][sysctl] = objects[sysctl] def _parsingFile(self, line, obj, vulnerabilityFound) -> bool: diff --git a/issues/sysctl.py b/audit/system/plugins/sysctl/sysctl.py similarity index 100% rename from issues/sysctl.py rename to audit/system/plugins/sysctl/sysctl.py diff --git a/config.py b/config.py deleted file mode 100644 index 656da7c..0000000 --- a/config.py +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env python3 - -# Constantes -HIGH = "high" -MEDIUM = "medium" -LOW = "low" diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..a6c5854 --- /dev/null +++ b/config.yaml @@ -0,0 +1,15 @@ +# Audit system +system: + exclude_plugins: + - "" + postfix: + postfix_file: "/etc/postfix/master.cf" + sysctl: + sysctl_file: "/etc/sysctl.conf" + +# Audit application +application: + pattern_file: + - ".py" + - ".php" + - ".c" diff --git a/core/config.py b/core/config.py new file mode 100644 index 0000000..a56327c --- /dev/null +++ b/core/config.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python3 + +import yaml +from utils import ConfigError + +# Constantes +HIGH = "high" +MEDIUM = "medium" +LOW = "low" + +AUDIT_SYSTEM = [ + "sysctl", + "postfix", +] + +AUDIT_APPLICATION = [ + 'keywords', + 'calls', +] + +def generateConfig() -> dict: + config = dict() + # System + config["system"] = dict() + config["system"]["postfix"] = dict() + config["system"]["postfix"]["postfix_file"] = "/etc/postfix/main.cf" + config["system"]["sysctl"] = dict() + config["system"]["sysctl"]["sysctl_file"] = "/etc/sysctl.conf" + config["system"]["exclude_plugins"] = list() + # Application + config["application"] = dict() + config["application"]["pattern_file"] = list() + + return config + +def _get_exclude_plugins(): + pass + +def parsingConfigFile(filename, configs): + # This function overwrite the config + try: + if not filename.endswith(".yaml"): + raise ConfigError( + "You must specified a YAML config file", + filename + ) + with open(filename, 'rb') as f: + yamlConfig = yaml.safe_load(f) + + # Mapping config file to the config dict + # TODO: recursive function + for category in yamlConfig: + if "system" in category: + for plugin in yamlConfig["system"]: + if plugin not in configs["system"]: + raise ConfigError( + f"{plugin} unknown", + filename + ) + for flag in yamlConfig["system"][plugin]: + try: + if flag is not None: + if isinstance(configs["system"][plugin], list): + configs["system"][plugin].append(flag) + else: + if flag not in configs["system"][plugin]: + raise ConfigError( + f"{flag} unknown", + filename + ) + configs["system"][plugin][flag] = yamlConfig["system"][plugin][flag] + except TypeError as e: + raise e + + #if "application" in category: + # for plugin in yamlConfig["application"]: + # for flag in yamlConfig["application"][plugin]: + # try: + # configs["application"][plugin][flag] = yamlConfig["application"][plugin][flag] + # except TypeError: + # pass + + + #fdata = f.read() + #lines = fdata.splitlines() + + #for line in lines: + # line = line.decode('utf-8') + # try: + # sLine = line.split("=") + # flag = sLine[0].strip() + # value = sLine[1].strip() + + # if flag in configs: + # if flag == "exclude_plugins": + # value = value.replace("\"", "") + # value = value.split(",") + # configs[flag] = value + # except IndexError: + # pass + + except FileNotFoundError: + print(f"Config file {filename} not found. Bypass it") diff --git a/core/dispatcher.py b/core/dispatcher.py new file mode 100644 index 0000000..75b2c6a --- /dev/null +++ b/core/dispatcher.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 + +class Dispatcher: + _plugins = dict() + + def __init__(self) -> None: + pass + + def runPlugin(self, plugin, *args) -> dict: + """ + We run the puglin. The result of this function + is the report of the audit + """ + return self._plugins[plugin](self, *args) + + @classmethod + def register_plugins(cls, plugin): + cls._plugins[plugin.__name__] = plugin + return plugin + diff --git a/core/main.py b/core/main.py new file mode 100644 index 0000000..f2be5f5 --- /dev/null +++ b/core/main.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python + +from argparse import ArgumentParser +from core.sysctl import Sysctl +from core.postfix import Postfix +from core.report import generateHtmlReport +from core.config import AUDIT_SYSTEM, AUDIT_APPLICATION, generateConfig, parsingConfigFile +from core.dispatcher import Dispatcher + + +def checkArguments(): + args = ArgumentParser(description="Check Gitlab repositories") + args.add_argument('-a', '--audit', help="Kind of audit", choices=['system', 'application']) + args.add_argument('-c', '--config', help="Config file") + return args.parse_args() + + +def main(): + args = checkArguments() + + # If audit is not specified + if args.audit is None: + print("Please, you must specify the audit type") + exit(1) + + # If config file is specified + configs = generateConfig() + if args.config is not None: + parsingConfigFile(args.config, configs) + + # Report + report = dict() + report['system'] = dict() + + # Create our dispatcher + dispatcher = Dispatcher() + + print(configs) + + if args.audit == "system": + for audit in AUDIT_SYSTEM: + if audit not in configs["system"]["exclude_plugins"]: + report["system"][audit] = dispatcher.runPlugin(audit, configs["system"][audit]) + + if args.audit == "application": + pass + + print(report) + generateHtmlReport(report) + +@Dispatcher.register_plugins +def sysctl(*args) -> dict: + sysctl = Sysctl(args[1]) + sysctl.runAudit() + return sysctl.getReports() + +@Dispatcher.register_plugins +def postfix(*args) -> dict: + arguments = args[1] + postfix = Postfix() + postfix.runAudit() + return postfix.getReports() + +if __name__ == "__main__": + main() diff --git a/core/postfix.py b/core/postfix.py index 037fa35..9cedf9d 100644 --- a/core/postfix.py +++ b/core/postfix.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 -from parsing.postfix import Parsing -from issues.postfix import postfix +from audit.system.plugins.postfix.parsing import Parsing +from audit.system.plugins.postfix.postfix import postfix class Postfix: def __init__(self): @@ -14,3 +14,9 @@ class Postfix: def _postfix(self): self._objects = postfix() + + def runAudit(self): + print("Running test for postfix") + + def getReports(self) -> dict: + return self._reports diff --git a/report.py b/core/report.py similarity index 57% rename from report.py rename to core/report.py index 66c1c5a..2b7b918 100644 --- a/report.py +++ b/core/report.py @@ -4,27 +4,24 @@ from datetime import datetime def generateHtmlReport(data): today = datetime.now().isoformat()[0:10].replace("-", "_") - html = "" \ - "" \ - "
" \ - "" \ - "" \ + html = _getHeader() + html += "" \ f""
- body += f"Results:
"
+ # # For file
+ # body += f"
"
+ # body += f"Results:
"
#for result in data['sysctl']['file']['sysctl'][vul]:
# print(result)
# body += f"Line: {result['lineNumber']}
"
@@ -39,3 +36,10 @@ def generateHtmlReport(data):
with open(f"reports/reports_{today}.html", "w") as f:
f.write(html)
+def _getHeader() -> str:
+ header = "" \
+ "" \
+ "