Parse sysctl

This commit is contained in:
gbucchino 2023-06-07 16:49:12 +02:00
parent 8b2e9cbd29
commit 882cdf805f
9 changed files with 328 additions and 46 deletions

16
core/postfix.py Normal file

@ -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()

@ -1,14 +1,13 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from parsing.sysctl import Parsing from parsing.sysctl import Parsing
from issues.system import system
from issues.sysctl import sysctl from issues.sysctl import sysctl
class Sysctl: class Sysctl:
def __init__(self): def __init__(self):
self._objects = dict() self._objects = dict()
self._reports = list() self._reports = dict()
self._audit = list() self._audit = list()
self._audit.append({ self._audit.append({
@ -25,15 +24,16 @@ class Sysctl:
self._parsing = Parsing(self._objects, self._audit) self._parsing = Parsing(self._objects, self._audit)
def _sysctl(self): def _sysctl(self):
self._objects['sysctl'] = sysctl() self._objects = sysctl()
def runAudit(self): def runAudit(self):
# Read /etc/sysctl.conf # Read /etc/sysctl.conf
self._parsing.runParsing() self._parsing.runParsing()
self._reports.append(self._parsing.getResults()) #self._reports.append(self._parsing.getResults())
self._reports = self._parsing.getResults()
# Run process sysctl # Run process sysctl
def getReports(self) -> list: def getReports(self) -> dict:
return self._reports return self._reports

6
issues/postfix.py Normal file

@ -0,0 +1,6 @@
#!/usr/bin/env python3
def postfix() -> dict:
postfix = dict()
return postfix

@ -6,6 +6,9 @@ def sysctl() -> list:
sysctl = list() sysctl = list()
# https://access.redhat.com/security/sysctl/sysctl-2023-0179 # https://access.redhat.com/security/sysctl/sysctl-2023-0179
#####
# CVE
#####
sysctl.append({ sysctl.append({
"from": "cve", "from": "cve",
"id": "cve-2023-0179", "id": "cve-2023-0179",
@ -20,7 +23,9 @@ def sysctl() -> list:
}) })
}) })
#####
# Best practice from CIS # Best practice from CIS
#####
sysctl.append({ sysctl.append({
"from": "cis", "from": "cis",
"id": "", "id": "",
@ -29,5 +34,186 @@ def sysctl() -> list:
"value": 0, "value": 0,
"level": "medium", "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 return sysctl

@ -1,7 +1,9 @@
#!/usr/bin/env python #!/usr/bin/env python
from argparse import ArgumentParser from argparse import ArgumentParser
from sysctl import Sysctl from core.sysctl import Sysctl
from core.postfix import Postfix
from report import generateHtmlReport
def checkArguments(): def checkArguments():
@ -30,7 +32,10 @@ def main():
sysctl = Sysctl() sysctl = Sysctl()
sysctl.runAudit() sysctl.runAudit()
# Getting reports
report['sysctl'] = sysctl.getReports() report['sysctl'] = sysctl.getReports()
generateHtmlReport(report)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

51
parsing/postfix.py Normal file

@ -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

@ -1,3 +1,5 @@
#!/usr/bin/env python3
import re import re
from json import dumps from json import dumps
from parsing.base import ParsingBase from parsing.base import ParsingBase
@ -10,38 +12,37 @@ class Parsing(ParsingBase):
self._audit = audit self._audit = audit
def runParsing(self): def runParsing(self):
# Generate report
self._constructReports()
for audit in self._audit: for audit in self._audit:
if audit['audit'] == 'file': if audit['audit'] == 'file':
with open(audit['value'], 'rb') as fdata: with open(audit['value'], 'rb') as fdata:
self._parseFile(fdata) self._parseFile(fdata)
if audit['audit'] == 'process': if audit['audit'] == 'process':
pass self._parseProcess()
def _parseFile(self, fdata): def _parseFile(self, fdata):
data = fdata.read() data = fdata.read()
lines = data.splitlines() lines = data.splitlines()
numLines = 1 numLines = 1
self._constructReports(filename='/etc/sysctl.conf')
vulnerabilityFound = dict() vulnerabilityFound = dict()
# I create an array which contains all flag we need to find # 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. # 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 # 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']] = dict()
vulnerabilityFound[obj['flag']]['recommand_value'] = obj['value'] vulnerabilityFound[obj['flag']]['recommand_value'] = obj['value']
vulnerabilityFound[obj['flag']]['occurence'] = 0 vulnerabilityFound[obj['flag']]['occurence'] = 0
for item in obj: for item in obj:
vulnerabilityFound[obj['flag']][item] = obj[item] vulnerabilityFound[obj['flag']][item] = obj[item]
print("")
for line in lines: for line in lines:
line = line.decode("utf-8") line = line.decode("utf-8")
for obj in self._objects['sysctl']: for obj in self._objects:
result = self._parsingFile(line, obj, vulnerabilityFound) result = self._parsingFile(line, obj, vulnerabilityFound)
if result: if result:
vulnerabilityFound[obj['flag']]['lineNumber'] = numLines 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 # And check if the flag is specified and need to put on the sysctl config
for entry in vulnerabilityFound: for entry in vulnerabilityFound:
obj = vulnerabilityFound[entry] obj = vulnerabilityFound[entry]
self._reports[entry]['result'] = dict() vulnerabilityFound[entry]['result'] = dict()
if obj['occurence'] > 0: if obj['occurence'] > 0:
#print(entry) #print(entry)
#print(obj) #print(obj)
if obj['current_value'] != obj['recommand_value']: if obj['current_value'] != obj['recommand_value']:
self._reports[entry]['result']['result'] = "failed" vulnerabilityFound[entry]['result']['result'] = "failed"
#self._reports[entry]['message'] = \
# f"You specify this value {obj['current_value']}" \
# ", you should use this value {obj['recommand_value']}"
else: else:
self._reports[entry]['result']['result'] = "failed" vulnerabilityFound[entry]['result']['result'] = "success"
else: else:
# No find the flag, we recommand to enable it # 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 # We can generate the report
print(self._reports) for sysctl in self._reports['file']['sysctl']:
print("") #self._reports['file']['sysctl'][sysctl] = vulnerabilityFound[sysctl]
from json import dumps self._reports['file']['sysctl'][sysctl] = objects[sysctl]
print(dumps(vulnerabilityFound, indent=4))
def _parsingFile(self, line, obj, vulnerabilityFound) -> bool: def _parsingFile(self, line, obj, vulnerabilityFound) -> bool:
""" """
@ -94,7 +101,7 @@ class Parsing(ParsingBase):
return result return result
def _constructReports(self, filename): def _constructReports(self):
""" """
Construct dictionary for result of the tests Construct dictionary for result of the tests
Each entry contains: Each entry contains:
@ -105,12 +112,19 @@ class Parsing(ParsingBase):
- description: description of the vulnerability - description: description of the vulnerability
- level: high, medium or low - 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']: # For process
self._reports[sysctl['flag']] = dict() 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: def getResults(self) -> dict:
result = dict() return self._reports
return result

@ -12,23 +12,26 @@ def generateHtmlReport(data):
f"<h1>Reports of {today}</h1>" f"<h1>Reports of {today}</h1>"
body = str() body = str()
for project in data['projects']: # For sysctl
body += f"<h2>{project['name']}</h2>" for entry in data['sysctl']:
body += f"<h2>Sysctl</h2>"
# For python # For file
body += f"<h3>Python</h3>" body += f"<h3>File</h3>"
for py in project['python']: for f in data['sysctl']['file']:
body += f"<h4>{py['file']}</h4>" body += f"<h4>{data['sysctl']['file']['filename']}</h4>"
for vul in py['vulnerabilities']: for vul in data['sysctl']['file']['sysctl']:
body += f"<h5>{vul['name']}</h5>" #print(data['sysctl']['file']['sysctl'][vul])
body += f"<h5>{vul}</h5>"
body += f"<p>" body += f"<p>"
body += f"Results:<br />" body += f"Results:<br />"
for result in vul['results']: #for result in data['sysctl']['file']['sysctl'][vul]:
body += f"Line: {result['lineNumber']}<br />" # print(result)
body += f"Line: {result['line']}<br />" # body += f"Line: {result['lineNumber']}<br />"
body += f"Level: {result['level']}<br />" # body += f"Line: {result['line']}<br />"
body += f"Description: {result['description']}<br /><br />" # body += f"Level: {result['level']}<br />"
body += f"</p>" # body += f"Description: {result['description']}<br /><br />"
#body += f"</p>"
html += body html += body
#print(body) #print(body)

File diff suppressed because one or more lines are too long