From 882cdf805f0215057e398e699397fd109674958a Mon Sep 17 00:00:00 2001 From: gbucchino Date: Wed, 7 Jun 2023 16:49:12 +0200 Subject: [PATCH] Parse sysctl --- core/postfix.py | 16 +++ sysctl.py => core/sysctl.py | 10 +- issues/postfix.py | 6 ++ issues/sysctl.py | 186 ++++++++++++++++++++++++++++++++ main.py | 9 +- parsing/postfix.py | 51 +++++++++ parsing/sysctl.py | 64 ++++++----- report.py | 31 +++--- reports/reports_2023_06_07.html | 1 + 9 files changed, 328 insertions(+), 46 deletions(-) create mode 100644 core/postfix.py rename sysctl.py => core/sysctl.py (76%) create mode 100644 issues/postfix.py create mode 100644 parsing/postfix.py create mode 100644 reports/reports_2023_06_07.html diff --git a/core/postfix.py b/core/postfix.py new file mode 100644 index 0000000..037fa35 --- /dev/null +++ b/core/postfix.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 + +from parsing.postfix import Parsing +from issues.postfix import postfix + +class Postfix: + def __init__(self): + self._objects = dict() + self._reports = dict() + + self._postfix() + + self._parsing = Parsing(self._objects) + + def _postfix(self): + self._objects = postfix() diff --git a/sysctl.py b/core/sysctl.py similarity index 76% rename from sysctl.py rename to core/sysctl.py index e23415c..6986862 100644 --- a/sysctl.py +++ b/core/sysctl.py @@ -1,14 +1,13 @@ #!/usr/bin/env python3 from parsing.sysctl import Parsing -from issues.system import system from issues.sysctl import sysctl class Sysctl: def __init__(self): self._objects = dict() - self._reports = list() + self._reports = dict() self._audit = list() self._audit.append({ @@ -25,15 +24,16 @@ class Sysctl: self._parsing = Parsing(self._objects, self._audit) def _sysctl(self): - self._objects['sysctl'] = sysctl() + self._objects = sysctl() def runAudit(self): # Read /etc/sysctl.conf self._parsing.runParsing() - self._reports.append(self._parsing.getResults()) + #self._reports.append(self._parsing.getResults()) + self._reports = self._parsing.getResults() # Run process sysctl - def getReports(self) -> list: + def getReports(self) -> dict: return self._reports diff --git a/issues/postfix.py b/issues/postfix.py new file mode 100644 index 0000000..324f420 --- /dev/null +++ b/issues/postfix.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 + +def postfix() -> dict: + postfix = dict() + + return postfix diff --git a/issues/sysctl.py b/issues/sysctl.py index a0c3f12..095e51d 100644 --- a/issues/sysctl.py +++ b/issues/sysctl.py @@ -6,6 +6,9 @@ def sysctl() -> list: sysctl = list() # https://access.redhat.com/security/sysctl/sysctl-2023-0179 + ##### + # CVE + ##### sysctl.append({ "from": "cve", "id": "cve-2023-0179", @@ -20,7 +23,9 @@ def sysctl() -> list: }) }) + ##### # Best practice from CIS + ##### sysctl.append({ "from": "cis", "id": "", @@ -29,5 +34,186 @@ def sysctl() -> list: "value": 0, "level": "medium", }) + sysctl.append({ + "from": "cis", + "id": "", + "description": "Disable ICMP redirects IPv4", + "flag": "net.ipv4.conf.all.accept_redirects", + "value": 0, + "level": "medium", + }) + sysctl.append({ + "from": "cis", + "id": "", + "description": "Disable Accepting Source Routed packets IPv4 for all interfaces", + "flag": "net.ipv4.conf.all.accept_source_route", + "value": 0, + "level": "medium", + }) + sysctl.append({ + "from": "cis", + "id": "", + "description": "Disable Accepting Source Routed packets IPv4 for default interface", + "flag": "net.ipv4.conf.default.accept_source_route", + "value": 0, + "level": "medium", + }) + sysctl.append({ + "from": "cis", + "id": "", + "description": "Disable ICMP Secure redirects IPv4 for all interfaces", + "flag": "net.ipv4.conf.all.secure_redirects", + "value": 0, + "level": "medium", + }) + sysctl.append({ + "from": "cis", + "id": "", + "description": "Disable ICMP Secure redirects IPv4 for default interface", + "flag": "net.ipv4.conf.default.secure_redirects", + "value": 0, + "level": "medium", + }) + sysctl.append({ + "from": "cis", + "id": "", + "description": "Enable Log martian packets IPv4 for all interfaces", + "flag": "net.ipv4.conf.all.log_martians", + "value": 1, + "level": "medium", + }) + sysctl.append({ + "from": "cis", + "id": "", + "description": "Enable Log martian packets IPv4 for default interface", + "flag": "net.ipv4.conf.default.log_martians", + "value": 1, + "level": "medium", + }) + # https://lwn.net/Articles/277146/ + sysctl.append({ + "from": "cis", + "id": "", + "description": "Enable TCP syn cookies IPv4", + "flag": "net.ipv4.tcp_syncookies", + "value": 1, + "level": "medium", + }) + sysctl.append({ + "from": "cis", + "id": "", + "description": "Disable IPv4 forwarding on all interfaces", + "flag": "net.ipv4.ip_forward", + "value": 0, + "level": "medium", + }) + sysctl.append({ + "from": "cis", + "id": "", + "description": "Disable IPv4 send redirects on all interfaces", + "flag": "net.ipv4.conf.all.send_redirects", + "value": 0, + "level": "medium", + }) + sysctl.append({ + "from": "cis", + "id": "", + "description": "Disable IPv4 send redirects on default interface", + "flag": "net.ipv4.conf.default.send_redirects", + "value": 0, + "level": "medium", + }) + sysctl.append({ + "from": "cis", + "id": "", + "description": "Enable IPv4 reverse path filtering on all interfaces", + "flag": "net.ipv4.conf.all.rp_filter", + "value": 1, + "level": "medium", + }) + sysctl.append({ + "from": "cis", + "id": "", + "description": "Enable IPv4 reverse path filtering on default interface", + "flag": "net.ipv4.conf.default.rp_filter", + "value": 1, + "level": "medium", + }) + + # For IPv6 + sysctl.append({ + "from": "cis", + "id": "", + "description": "Disable IPvi6 forwarding", + "flag": "net.ipv6.conf.all.forwarding", + "value": 0, + "level": "medium", + }) + sysctl.append({ + "from": "cis", + "id": "", + "description": "Disable ICMP redirects IPv6", + "flag": "net.ipv6.conf.all.accept_redirects", + "value": 0, + "level": "medium", + }) + sysctl.append({ + "from": "cis", + "id": "", + "description": "Disable ICMP redirects IPv6 for default interface", + "flag": "net.ipv6.conf.default.accept_redirects", + "value": 0, + "level": "medium", + }) + # https://datatracker.ietf.org/doc/html/rfc4861 + sysctl.append({ + "from": "cis", + "id": "", + "description": "Disable Route Advertisements for IPv6 for all interfaces", + "flag": "net.ipv6.conf.all.accept_ra", + "value": 0, + "level": "medium", + }) + sysctl.append({ + "from": "cis", + "id": "", + "description": "Disable Route Advertisements for IPv6 for default interface", + "flag": "net.ipv6.conf.default.accept_ra", + "value": 0, + "level": "medium", + }) + sysctl.append({ + "from": "cis", + "id": "", + "description": "Disable Accepting Source Routed for IPv6 for all interfaces", + "flag": "net.ipv6.conf.all.accept_source_route", + "value": 0, + "level": "medium", + }) + sysctl.append({ + "from": "cis", + "id": "", + "description": "Disable Accepting Source Routed for IPv6 for default interface", + "flag": "net.ipv6.conf.default.accept_source_route", + "value": 0, + "level": "medium", + }) + sysctl.append({ + "from": "cis", + "id": "", + "description": "Disable ICMP Secure redirects IPv6 for all interfaces", + "flag": "net.ipv6.conf.all.secure_redirects", + "value": 0, + "level": "medium", + }) + sysctl.append({ + "from": "cis", + "id": "", + "description": "Disable ICMP Secure redirects IPv6 for default interface", + "flag": "net.ipv6.conf.default.secure_redirects", + "value": 0, + "level": "medium", + }) + return sysctl diff --git a/main.py b/main.py index 954c955..eba5bfa 100644 --- a/main.py +++ b/main.py @@ -1,7 +1,9 @@ #!/usr/bin/env python from argparse import ArgumentParser -from sysctl import Sysctl +from core.sysctl import Sysctl +from core.postfix import Postfix +from report import generateHtmlReport def checkArguments(): @@ -30,7 +32,10 @@ def main(): sysctl = Sysctl() sysctl.runAudit() + # Getting reports report['sysctl'] = sysctl.getReports() - + + generateHtmlReport(report) + if __name__ == "__main__": main() diff --git a/parsing/postfix.py b/parsing/postfix.py new file mode 100644 index 0000000..ab43b4e --- /dev/null +++ b/parsing/postfix.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 + +import re +from json import dumps +from parsing.base import ParsingBase + + +class Parsing(ParsingBase): + def __init__(self, objects): + self._parsing = dict() + self._reports = dict() + self._objects = objects + + def runParsing(self): + # Generate report + self._constructReports() + + + print(self._reports) + + def _parseFile(self): + pass + + def _generateReport(self, objects): + # We can generate the report + for postfix in self._reports['postfix']: + self._reports['postfix'][postfix] = objects[postfix] + + def _parsingFile(self, line, obj, vulnerabilityFound) -> bool: + """ + This function parse the line and try to find the item in it + """ + result = bool() + + return result + + def _constructReports(self): + """ + Construct dictionary for result of the tests + Each entry contains: + Key: + - filename: filename of the test + - line: line of the test + - parse: Display the line where the vulnerabilites has been found + - description: description of the vulnerability + - level: high, medium or low + """ + self._reports['postfix'] = dict() + + def getResults(self) -> dict: + return self._reports diff --git a/parsing/sysctl.py b/parsing/sysctl.py index cdeb346..0b3d7f6 100644 --- a/parsing/sysctl.py +++ b/parsing/sysctl.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python3 + import re from json import dumps from parsing.base import ParsingBase @@ -10,38 +12,37 @@ class Parsing(ParsingBase): self._audit = audit def runParsing(self): + # Generate report + self._constructReports() + for audit in self._audit: if audit['audit'] == 'file': with open(audit['value'], 'rb') as fdata: self._parseFile(fdata) if audit['audit'] == 'process': - pass + self._parseProcess() def _parseFile(self, fdata): data = fdata.read() lines = data.splitlines() numLines = 1 - self._constructReports(filename='/etc/sysctl.conf') - vulnerabilityFound = dict() # I create an array which contains all flag we need to find # After that, for each data, I put the number of occurence I found. # If the array is empty, no entry found for a flag, otherwise, we check the value - for obj in self._objects['sysctl']: + for obj in self._objects: vulnerabilityFound[obj['flag']] = dict() vulnerabilityFound[obj['flag']]['recommand_value'] = obj['value'] vulnerabilityFound[obj['flag']]['occurence'] = 0 for item in obj: vulnerabilityFound[obj['flag']][item] = obj[item] - print("") - for line in lines: line = line.decode("utf-8") - for obj in self._objects['sysctl']: + for obj in self._objects: result = self._parsingFile(line, obj, vulnerabilityFound) if result: vulnerabilityFound[obj['flag']]['lineNumber'] = numLines @@ -53,26 +54,32 @@ class Parsing(ParsingBase): # And check if the flag is specified and need to put on the sysctl config for entry in vulnerabilityFound: obj = vulnerabilityFound[entry] - self._reports[entry]['result'] = dict() + vulnerabilityFound[entry]['result'] = dict() if obj['occurence'] > 0: #print(entry) #print(obj) if obj['current_value'] != obj['recommand_value']: - self._reports[entry]['result']['result'] = "failed" - #self._reports[entry]['message'] = \ - # f"You specify this value {obj['current_value']}" \ - # ", you should use this value {obj['recommand_value']}" + vulnerabilityFound[entry]['result']['result'] = "failed" else: - self._reports[entry]['result']['result'] = "failed" + vulnerabilityFound[entry]['result']['result'] = "success" else: # No find the flag, we recommand to enable it - self._reports[entry]['result']['result'] = "failed" + vulnerabilityFound[entry]['result']['result'] = "failed" + # Generate report + self._generateReport(vulnerabilityFound) + + def _parseProcess(self): + vulnerabilityFound = dict() + + # Generate report + #self._generateReport(vulnerabilityFound) + + def _generateReport(self, objects): # We can generate the report - print(self._reports) - print("") - from json import dumps - print(dumps(vulnerabilityFound, indent=4)) + 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: """ @@ -94,7 +101,7 @@ class Parsing(ParsingBase): return result - def _constructReports(self, filename): + def _constructReports(self): """ Construct dictionary for result of the tests Each entry contains: @@ -105,12 +112,19 @@ class Parsing(ParsingBase): - description: description of the vulnerability - level: high, medium or low """ - self._reports['filename'] = filename + # For file + self._reports['file'] = dict() + self._reports['file']['filename'] = self._audit[0]['value'] + self._reports['file']['sysctl'] = dict() - for sysctl in self._objects['sysctl']: - self._reports[sysctl['flag']] = dict() + # For process + self._reports['process'] = dict() + self._reports['process']['sysctl'] = dict() + + + for sysctl in self._objects: + self._reports['file']['sysctl'][sysctl['flag']] = dict() + self._reports['process']['sysctl'][sysctl['flag']] = dict() def getResults(self) -> dict: - result = dict() - - return result + return self._reports diff --git a/report.py b/report.py index fb506e6..66c1c5a 100644 --- a/report.py +++ b/report.py @@ -12,23 +12,26 @@ def generateHtmlReport(data): f"

Reports of {today}

" body = str() - for project in data['projects']: - body += f"

{project['name']}

" + # For sysctl + for entry in data['sysctl']: + body += f"

Sysctl

" - # For python - body += f"

Python

" - for py in project['python']: - body += f"

{py['file']}

" - for vul in py['vulnerabilities']: - body += f"
{vul['name']}
" + # For file + body += f"

File

" + for f in data['sysctl']['file']: + body += f"

{data['sysctl']['file']['filename']}

" + for vul in data['sysctl']['file']['sysctl']: + #print(data['sysctl']['file']['sysctl'][vul]) + body += f"
{vul}
" body += f"

" body += f"Results:
" - for result in vul['results']: - body += f"Line: {result['lineNumber']}
" - body += f"Line: {result['line']}
" - body += f"Level: {result['level']}
" - body += f"Description: {result['description']}

" - body += f"

" + #for result in data['sysctl']['file']['sysctl'][vul]: + # print(result) + # body += f"Line: {result['lineNumber']}
" + # body += f"Line: {result['line']}
" + # body += f"Level: {result['level']}
" + # body += f"Description: {result['description']}

" + #body += f"

" html += body #print(body) diff --git a/reports/reports_2023_06_07.html b/reports/reports_2023_06_07.html new file mode 100644 index 0000000..6d62042 --- /dev/null +++ b/reports/reports_2023_06_07.html @@ -0,0 +1 @@ +

Reports of 2023_06_07

Sysctl

File

/etc/sysctl.conf

kernel.unprivileged_userns_clone

Results:

net.ipv4.conf.all.forwarding

Results:

net.ipv4.conf.all.accept_redirects

Results:

net.ipv4.conf.all.accept_source_route

Results:

net.ipv4.conf.default.accept_source_route

Results:

net.ipv4.conf.all.secure_redirects

Results:

net.ipv4.conf.default.secure_redirects

Results:

net.ipv4.conf.all.log_martians

Results:

net.ipv4.conf.default.log_martians

Results:

net.ipv4.tcp_syncookies

Results:

net.ipv4.ip_forward

Results:

net.ipv4.conf.all.send_redirects

Results:

net.ipv4.conf.default.send_redirects

Results:

net.ipv4.conf.all.rp_filter

Results:

net.ipv4.conf.default.rp_filter

Results:

net.ipv6.conf.all.forwarding

Results:

net.ipv6.conf.all.accept_redirects

Results:

net.ipv6.conf.default.accept_redirects

Results:

net.ipv6.conf.all.accept_ra

Results:

net.ipv6.conf.default.accept_ra

Results:

net.ipv6.conf.all.accept_source_route

Results:

net.ipv6.conf.default.accept_source_route

Results:

net.ipv6.conf.all.secure_redirects

Results:

net.ipv6.conf.default.secure_redirects

Results:

/etc/sysctl.conf

kernel.unprivileged_userns_clone

Results:

net.ipv4.conf.all.forwarding

Results:

net.ipv4.conf.all.accept_redirects

Results:

net.ipv4.conf.all.accept_source_route

Results:

net.ipv4.conf.default.accept_source_route

Results:

net.ipv4.conf.all.secure_redirects

Results:

net.ipv4.conf.default.secure_redirects

Results:

net.ipv4.conf.all.log_martians

Results:

net.ipv4.conf.default.log_martians

Results:

net.ipv4.tcp_syncookies

Results:

net.ipv4.ip_forward

Results:

net.ipv4.conf.all.send_redirects

Results:

net.ipv4.conf.default.send_redirects

Results:

net.ipv4.conf.all.rp_filter

Results:

net.ipv4.conf.default.rp_filter

Results:

net.ipv6.conf.all.forwarding

Results:

net.ipv6.conf.all.accept_redirects

Results:

net.ipv6.conf.default.accept_redirects

Results:

net.ipv6.conf.all.accept_ra

Results:

net.ipv6.conf.default.accept_ra

Results:

net.ipv6.conf.all.accept_source_route

Results:

net.ipv6.conf.default.accept_source_route

Results:

net.ipv6.conf.all.secure_redirects

Results:

net.ipv6.conf.default.secure_redirects

Results:

Sysctl

File

/etc/sysctl.conf

kernel.unprivileged_userns_clone

Results:

net.ipv4.conf.all.forwarding

Results:

net.ipv4.conf.all.accept_redirects

Results:

net.ipv4.conf.all.accept_source_route

Results:

net.ipv4.conf.default.accept_source_route

Results:

net.ipv4.conf.all.secure_redirects

Results:

net.ipv4.conf.default.secure_redirects

Results:

net.ipv4.conf.all.log_martians

Results:

net.ipv4.conf.default.log_martians

Results:

net.ipv4.tcp_syncookies

Results:

net.ipv4.ip_forward

Results:

net.ipv4.conf.all.send_redirects

Results:

net.ipv4.conf.default.send_redirects

Results:

net.ipv4.conf.all.rp_filter

Results:

net.ipv4.conf.default.rp_filter

Results:

net.ipv6.conf.all.forwarding

Results:

net.ipv6.conf.all.accept_redirects

Results:

net.ipv6.conf.default.accept_redirects

Results:

net.ipv6.conf.all.accept_ra

Results:

net.ipv6.conf.default.accept_ra

Results:

net.ipv6.conf.all.accept_source_route

Results:

net.ipv6.conf.default.accept_source_route

Results:

net.ipv6.conf.all.secure_redirects

Results:

net.ipv6.conf.default.secure_redirects

Results:

/etc/sysctl.conf

kernel.unprivileged_userns_clone

Results:

net.ipv4.conf.all.forwarding

Results:

net.ipv4.conf.all.accept_redirects

Results:

net.ipv4.conf.all.accept_source_route

Results:

net.ipv4.conf.default.accept_source_route

Results:

net.ipv4.conf.all.secure_redirects

Results:

net.ipv4.conf.default.secure_redirects

Results:

net.ipv4.conf.all.log_martians

Results:

net.ipv4.conf.default.log_martians

Results:

net.ipv4.tcp_syncookies

Results:

net.ipv4.ip_forward

Results:

net.ipv4.conf.all.send_redirects

Results:

net.ipv4.conf.default.send_redirects

Results:

net.ipv4.conf.all.rp_filter

Results:

net.ipv4.conf.default.rp_filter

Results:

net.ipv6.conf.all.forwarding

Results:

net.ipv6.conf.all.accept_redirects

Results:

net.ipv6.conf.default.accept_redirects

Results:

net.ipv6.conf.all.accept_ra

Results:

net.ipv6.conf.default.accept_ra

Results:

net.ipv6.conf.all.accept_source_route

Results:

net.ipv6.conf.default.accept_source_route

Results:

net.ipv6.conf.all.secure_redirects

Results:

net.ipv6.conf.default.secure_redirects

Results:
\ No newline at end of file