Parsing postfix

This commit is contained in:
geoffrey 2023-09-10 18:08:48 +02:00
parent 3cd25dce85
commit 582b85bb07
14 changed files with 281 additions and 77 deletions

@ -1,6 +1,6 @@
#!/usr/bin/env python3
def apaches_ssl() -> list:
def apache() -> list:
ssl = list()
# Check if apaches has disabled the bad SSL/TLS version

@ -3,7 +3,15 @@
def postfix() -> list:
postfix = list()
postfix.append({
'directive': "inet_interfaces",
'value': "loopback-only",
'from': 'cis',
'id': '',
'description': 'Disable the listening from all interfaces',
'flag': "inet_interfaces",
'level': 'medium',
'value': [
"127.0.0.1",
"loopback-only",
"[::1]",
]
})
return postfix

@ -6,6 +6,8 @@ system:
postfix_file: "/etc/postfix/master.cf"
sysctl:
sysctl_file: "/etc/sysctl.conf"
apache:
apache_directory: "/etc/apache2/"
# Audit application
application:

@ -11,6 +11,7 @@ LOW = "low"
AUDIT_SYSTEM = [
"sysctl",
"postfix",
"apache",
]
AUDIT_APPLICATION = [
@ -24,6 +25,8 @@ def generateConfig() -> dict:
config["system"] = dict()
config["system"]["postfix"] = dict()
config["system"]["postfix"]["postfix_file"] = "/etc/postfix/main.cf"
config["system"]["apache"] = dict()
config["system"]["apache"]["apache_directory"] = "/etc/apache2/"
config["system"]["sysctl"] = dict()
config["system"]["sysctl"]["sysctl_file"] = "/etc/sysctl.conf"
config["system"]["exclude_plugins"] = list()
@ -80,24 +83,5 @@ def parsingConfigFile(filename, configs):
# 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")

@ -8,7 +8,7 @@ class Dispatcher:
def runPlugin(self, plugin, *args) -> dict:
"""
We run the puglin. The result of this function
We run the plugin. The result of this function
is the report of the audit
"""
return self._plugins[plugin](self, *args)
@ -18,3 +18,5 @@ class Dispatcher:
cls._plugins[plugin.__name__] = plugin
return plugin
def get_plugins(self):
return self._plugins

@ -1,14 +1,13 @@
#!/usr/bin/env python
from argparse import ArgumentParser
from core.sysctl import Sysctl
from core.postfix import Postfix
from core.plugins.sysctl import Sysctl
from core.plugins.postfix import Postfix
from core.plugins.apache import Apache
from core.report import generateHtmlReport
from core.config import AUDIT_SYSTEM, AUDIT_APPLICATION, generateConfig, parsingConfigFile
from core.dispatcher import Dispatcher
from utils import getHostname, getKernelVersion, identifySystem, getCodeName, getRelease
from os import listdir
from os.path import isdir
def checkArguments():
@ -20,15 +19,14 @@ def checkArguments():
def getAllPlugins(audit):
print(f"List all plugins for {audit}")
path = str()
if audit == "system":
path = "audit/system/plugins/"
else:
path = "audit/applications/"
for directory in listdir(path):
if isdir(f"{path}/{directory}"):
print(directory)
if audit == "system":
dis = Dispatcher()
plugins = dis.get_plugins()
for plugin in plugins:
print(plugin)
elif audit == "application":
pass
def main():
args = checkArguments()
@ -91,5 +89,11 @@ def postfix(*args) -> dict:
postfix.runAudit()
return postfix.getReports()
@Dispatcher.register_plugins
def apache(*args) -> dict:
apache = Apache(args[1])
apache.runAudit()
return apache.getReports()
if __name__ == "__main__":
main()

67
core/plugins/apache.py Normal file

@ -0,0 +1,67 @@
#!/usr/bin/env python3
import re
from os import listdir
from os.path import isdir
from audit.system.plugins.apache.apache import apache
class Apache:
def __init__(self, arguments):
self._objects = apache()
self._reports = dict()
self._apache_directory = arguments["apache_directory"]
# Create the report
self._constructReports()
# Report
self._reports["directory"] = self._apache_directory
def runAudit(self):
print("Running test for Apache")
self._runParsing()
def getReports(self) -> dict:
return self._reports
def _runParsing(self):
# Check if the file exist
path = f"{self._apache_directory}/sites-available"
if isdir(self._apache_directory):
for site in listdir(path):
with open(f"{path}/{site}", 'rb') as f:
self._parseFile(f)
else:
self._reports["apache"]["test"] = "No directory found"
def _parseFile(self, fdata):
data = fdata.read()
lines = data.splitlines()
for line in lines:
line = line.decode('utf-8')
# check if SSL is enable for the VirtualHost
grSSLEngine = re.search("SSLEngine on", line)
if grSSLEngine:
print(line)
def _check_value_exist(self, line, value) -> bool:
grValue = re.search(value, line)
if grValue:
return True
return False
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['apache'] = dict()

89
core/plugins/postfix.py Normal file

@ -0,0 +1,89 @@
#!/usr/bin/env python3
import re
from audit.system.plugins.postfix.postfix import postfix
class Postfix:
def __init__(self, arguments):
self._objects = postfix()
self._reports = dict()
self._postfix_file = arguments["postfix_file"]
# Create the report
self._constructReports()
# Report
self._reports["filename"] = self._postfix_file
def runAudit(self):
print("Running test for postfix")
self._runParsing()
def getReports(self) -> dict:
return self._reports
def _runParsing(self):
# Check if the file exist
try:
with open(self._postfix_file, 'rb') as fdata:
self._parseFile(fdata)
except FileNotFoundError:
print("No postfix file found. Add into the report")
pass
def _parseFile(self, fdata):
data = fdata.read()
lines = data.splitlines()
for line in lines:
line = line.decode('utf-8')
for obj in self._objects:
grDirective = re.search(
f"^({obj['flag']})",
line
)
if grDirective:
res = False
if not isinstance(obj['value'], list):
obj['value'] = [obj['value']]
for value in obj['value']:
res = self._check_value_exist(line, value)
if res:
break
if res:
self._reports["postfix"][obj['flag']] = dict()
self._reports["postfix"][obj['flag']]["result"] = "success"
self._reports["postfix"][obj['flag']]["description"] = obj['description']
self._reports["postfix"][obj['flag']]["flagFound"] = line
else:
self._reports["postfix"][obj['flag']] = dict()
self._reports["postfix"][obj['flag']]["result"] = "failed"
self._reports["postfix"][obj["flag"]]["recommand_value"] = obj["value"]
self._reports["postfix"][obj['flag']]["description"] = obj['description']
self._reports["postfix"][obj['flag']]["flag"] = obj['flag']
def _check_value_exist(self, line, value) -> bool:
if '[' in value:
value = value.replace('[', '\[')
if ']' in value:
value = value.replace(']', '\]')
grValue = re.search(value, line)
if grValue:
return True
return False
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()

@ -1,29 +0,0 @@
#!/usr/bin/env python3
from audit.system.plugins.postfix.parsing import Parsing
from audit.system.plugins.postfix.postfix import postfix
class Postfix:
def __init__(self, arguments):
self._objects = dict()
self._reports = dict()
self._arguments = arguments
self._postfix()
self._parsing = Parsing(self._objects, arguments)
def _postfix(self):
"""
Store all data to analyze in the object variable
"""
self._objects = postfix()
def runAudit(self):
print("Running test for postfix")
self._parsing.runParsing()
self._reports = self._parsing.getResults()
def getReports(self) -> dict:
return self._reports

@ -24,8 +24,11 @@ def generateHtmlReport(data):
dataJinja2['plugins'].append(f"{plugin}.html.j2")
if 'postfix' in data['system']:
#print(data['system']['postfix'])
pass
dataJinja2['postfix'] = dict()
dataJinja2['postfix']['filename'] = data["system"]["postfix"]["filename"]
dataJinja2['postfix']['vulnerabilities'] = data['system']['postfix']['postfix']
_generateAccordion(dataJinja2['postfix']['vulnerabilities'])
if 'sysctl' in data['system']:
dataJinja2['sysctl'] = dict()
@ -33,11 +36,10 @@ def generateHtmlReport(data):
dataJinja2['sysctl']['file']['filename'] = data['system']['sysctl']['file']['filename']
dataJinja2['sysctl']['file']['sysctl'] = data['system']['sysctl']['file']['sysctl']
index = 1
for sysctl in dataJinja2['sysctl']['file']['sysctl']:
dataJinja2['sysctl']['file']['sysctl'][sysctl]['accordion-id'] = f"accordion-{index}"
index += 1
_generateAccordion(dataJinja2['sysctl']['file']['sysctl'])
if 'apache' in data['system']:
pass
dataJinja2['year'] = '2023'
dataJinja2['hostname'] = data['hostname']
@ -50,3 +52,9 @@ def generateHtmlReport(data):
print("The report is generated at this location: " \
f"reports/reports_{today}.html")
def _generateAccordion(obj):
index = 1
for entry in obj:
obj[entry]['accordion-id'] = f"accordion-{index}"
index += 1

@ -0,0 +1,43 @@
<h3 class="fs-3">Apache</h3>
{% for item in data['postfix']['vulnerabilities'] %}
<div class="accordion" id="accordionSysctl">
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#{{ data['postfix']['vulnerabilities'][item]['accordion-id'] }}" aria-expanded="true" aria-controls="{{ data['postfix']['vulnerabilities'][item]['accordion-id'] }}">
<strong>{{ item }}</strong>
{% if data['postfix']['vulnerabilities'][item]['result'] == 'failed' %}
<span class="text-bg-danger p-1" style="padding-left:10pt;padding-right:10pt;margin-left:15pt;">{{ data['postfix']['vulnerabilities'][item]['result'] }}</span>
{% elif data['postfix']['vulnerabilities'][item]['result'] == 'success' %}
<span class="text-bg-success p-1" style="padding-left:10pt;padding-right:10pt;margin-left:15pt;">{{ data['postfix']['vulnerabilities'][item]['result'] }}</span>
{% endif %}
</button>
</h2>
<div id="{{ data['postfix']['vulnerabilities'][item]['accordion-id'] }}" class="accordion-collapse collapse" data-bs-parent="#accordionPostfix">
<div class="accordion-body">
{{ data['postfix']['vulnerabilities'][item]['description'] }}. <br />
{% if data['postfix']['vulnerabilities'][item]['result'] == 'success' %}
<div class="bd-example-snippet bd-code-snippet">
<div class="highlight">
<pre tabindex="0" class="chroma"><code class="language-shell">
{{ data['postfix']['vulnerabilities'][item]['flagFound'] }}
</pre></code>
</div>
</div>
{% else %}
For resolving the issue, add this line in the <strong>{{ data['postfix']['filename'] }}</strong> vulnerabilities:
<div class="bd-example-snippet bd-code-snippet">
<div class="highlight">
<pre tabindex="0" class="chroma"><code class="language-shell">
{% for value in data['postfix']['vulnerabilities'][item]['recommand_value'] %}
{{ data['postfix']['vulnerabilities'][item]['flag'] }} = {{ value }}
{% endfor %}
</pre></code>
</div>
</div>
{% endif %}
</div>
</div>
</div>
</div>
{% endfor %}

@ -31,6 +31,7 @@
{% for plugin in data['plugins'] %}
{% include plugin %}
<div style="margin-bottom:15pt"></div>
{% endfor %}

@ -1,16 +1,41 @@
<h3 class="fs-3">Postfix</h3>
{% for item in data['postfix'] %}
<div class="accordion" id="accordionPostfix">
{% for item in data['postfix']['vulnerabilities'] %}
<div class="accordion" id="accordionSysctl">
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#{{ item['accordion-id'] }}" aria-expanded="true" aria-controls="collapseOne">
Accordion Item #1
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#{{ data['postfix']['vulnerabilities'][item]['accordion-id'] }}" aria-expanded="true" aria-controls="{{ data['postfix']['vulnerabilities'][item]['accordion-id'] }}">
<strong>{{ item }}</strong>
{% if data['postfix']['vulnerabilities'][item]['result'] == 'failed' %}
<span class="text-bg-danger p-1" style="padding-left:10pt;padding-right:10pt;margin-left:15pt;">{{ data['postfix']['vulnerabilities'][item]['result'] }}</span>
{% elif data['postfix']['vulnerabilities'][item]['result'] == 'success' %}
<span class="text-bg-success p-1" style="padding-left:10pt;padding-right:10pt;margin-left:15pt;">{{ data['postfix']['vulnerabilities'][item]['result'] }}</span>
{% endif %}
</button>
</h2>
<div id="{{ item['accordion-id'] }}" class="accordion-collapse collapse show" data-bs-parent="#accordionPostfix">
<div id="{{ data['postfix']['vulnerabilities'][item]['accordion-id'] }}" class="accordion-collapse collapse" data-bs-parent="#accordionPostfix">
<div class="accordion-body">
<strong></strong>
{{ data['postfix']['vulnerabilities'][item]['description'] }}. <br />
{% if data['postfix']['vulnerabilities'][item]['result'] == 'success' %}
<div class="bd-example-snippet bd-code-snippet">
<div class="highlight">
<pre tabindex="0" class="chroma"><code class="language-shell">
{{ data['postfix']['vulnerabilities'][item]['flagFound'] }}
</pre></code>
</div>
</div>
{% else %}
For resolving the issue, add this line in the <strong>{{ data['postfix']['filename'] }}</strong> vulnerabilities:
<div class="bd-example-snippet bd-code-snippet">
<div class="highlight">
<pre tabindex="0" class="chroma"><code class="language-shell">
{% for value in data['postfix']['vulnerabilities'][item]['recommand_value'] %}
{{ data['postfix']['vulnerabilities'][item]['flag'] }} = {{ value }}
{% endfor %}
</pre></code>
</div>
</div>
{% endif %}
</div>
</div>
</div>