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