check_sys/core/plugins/apache.py
2023-09-18 20:59:49 +02:00

287 lines
9.9 KiB
Python

#!/usr/bin/env python3
import re
from os import listdir
from os.path import isdir, isfile
from audit.system.plugins.apache import apache_protocols, apache_signature, apache_indexes
class Apache:
def __init__(self, arguments):
self._ssl_versions = apache_protocols()
self._signatures = apache_signature()
self._indexes = apache_indexes()
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")
# Check if the directory exist
path = f"{self._apache_directory}"
if isdir(path):
self._reports['audit'] = True
self._analyzingSslVersion()
self._analyzingSignature()
self._analyzingIndexes()
else:
self._reports['audit'] = False
self._reports["msg"] = "No directory found"
def getReports(self) -> dict:
return self._reports
################################################
# Analyzing SSL
################################################
def _analyzingSslVersion(self):
# Check if the file exist
path = f"{self._apache_directory}/sites-available"
if isdir(path):
self._reports['ssl']['audit'] = True
count = 0
self._reports["ssl"]["virtualhost"] = dict()
for site in listdir(path):
vh = f"{path}/{site}"
with open(vh, 'rb') as f:
self._parseFileFindingSsl(f, site)
count += 1
if count == 0:
self._reports['ssl']['audit'] = False
self._reports['ssl']['msg'] = \
f'No virtual host found in the directory {path}'
else:
self._reports['ssl']['audit'] = False
self._reports['ssl']["msg"] = f"No directory {path} found"
def _parseFileFindingSsl(self, fdata, virtualhost):
data = fdata.read()
lines = data.splitlines()
for line in lines:
line = line.decode('utf-8')
# check if SSL is enable for the VirtualHost
# (?#) -> remove commentary
# (\s) -> remove space and tabulation
grSSLEngine = re.search(
"(?#)(\s)SSLEngine on",
line,
re.IGNORECASE
)
if grSSLEngine:
report = self._check_ssl_version(lines)
self._reports["ssl"]["virtualhost"][virtualhost] = report
def _check_ssl_version(self, lines) -> dict:
report = dict()
findProtocol = False
protocolsFound = list()
for line in lines:
line = line.decode("utf-8")
grSSLProtocol = re.search(
"(?#)(\s)SSLProtocol",
line,
re.IGNORECASE
)
if grSSLProtocol:
for protocol in self._ssl_versions["protocols"]:
grProtocol = re.search(f"-{protocol}", line)
if grProtocol:
protocolsFound.append(protocol)
if len(self._ssl_versions["protocols"]) == len(protocolsFound):
report["result"] = "success"
else:
report["msg"] = list()
report["result"] = "failed"
for proto in self._ssl_versions["protocols"]:
if proto not in protocolsFound:
report["msg"].append(
f"{proto} need to be disabled"
)
report["description"] = \
self._ssl_versions["description"]
report["level"] = self._ssl_versions["level"]
report["recommand_value"] = \
self._ssl_versions["recommand_value"]
return report
################################################
# Analyzing Signature
################################################
def _analyzingSignature(self):
# Check if the apache2.conf exist
path = f"{self._apache_directory}/apache2.conf"
if isfile(path):
self._reports["signature"]["audit"] = True
with open(path, 'rb') as fdata:
self._reports["signature"]["signature"] = \
self._parsingApacheConfigForSignature(fdata)
else:
self._reports["signature"]["audit"] = False
self._reports["signature"]["audit"] = \
f"The file {path} do not exist"
def _parsingApacheConfigForSignature(self, fdata) -> dict:
report = dict()
data = fdata.read()
lines = data.splitlines()
for signature in self._signatures["signature"]:
report[signature] = dict()
for line in lines:
line = line.decode('utf-8')
for signature in self._signatures["signature"]:
grSignature = re.search(
f"(?#){signature}",
line,
re.IGNORECASE
)
if grSignature:
# It's not a comment
if '#' not in line:
report[signature]["audit"] = True
report[signature]["result"] = "success"
report[signature]["description"] = self._signatures["description"]
report[signature]["level"] = self._signatures["level"]
for signature in report:
if len(report[signature]) == 0:
report[signature]["audit"] = True
report[signature]["result"] = "failed"
report[signature]["recommand_value"] = signature
report[signature]["description"] = self._signatures["description"]
report[signature]["level"] = self._signatures["level"]
return report
################################################
# Analyzing Indexes
################################################
def _analyzingIndexes(self):
# Check if the apache2.conf exist
path = f"{self._apache_directory}/apache2.conf"
if isfile(path):
self._reports["indexes"]["audit"] = True
with open(path, 'rb') as fdata:
self._reports["indexes"]["indexes"] = \
self._parsingApacheConfig(fdata)
else:
self._reports["indexes"]["audit"] = False
self._reports["indexes"]["audit"] = \
f"The file {path} do not exist"
def _parsingApacheConfig(self, fdata) -> dict:
report = dict()
report["directories"] = dict()
data = fdata.read()
lines = data.splitlines()
# Each entry in the variable directories contains a list
# of <Directory> with all data in it
# We create another entry when a found </Directory>
directories = list()
directoryFound = False
index = 0
optsFound = list()
for line in lines:
line = line.decode('utf-8')
# Find a <Directory
if not directoryFound:
grDirectory = re.search("<Directory ", line, re.IGNORECASE)
if grDirectory:
directoryFound = True
directories.append(list())
directories[index].append(line)
else:
#directory.append(line)
directories[index].append(line)
grDirectory = re.search("</Directory>", line, re.IGNORECASE)
if grDirectory:
directoryFound = False
index += 1
# We will find if we find an indexes option
for d in directories:
for entry in d:
# We get the directory path
path = self._getDirectoryPath(entry)
report["directories"][path] = dict()
# Try to find the Option flag
grFlag = re.search(
f"{self._indexes['flag']}",
entry,
re.IGNORECASE
)
if grFlag:
for opt in self._indexes['options']:
grOption = re.search(
f"-{opt}",
entry,
re.IGNORECASE
)
if grOption:
optsFound.append(opt)
report["audit"] = True
report["options"] = dict()
if len(optsFound) == len(self._indexes['options']):
report["result"] = "success"
else:
report["result"] = "failed"
for opt in self._indexes["options"]:
if opt not in optsFound:
report["options"][opt] = f"{opt} is not removed. You should disable it"
report["description"] = self._indexes["description"]
report["level"] = self._indexes["level"]
report["recommand_value"] = self._indexes["recommand_value"]
print(report)
return report
def _getDirectoryPath(self, line) -> str:
"""
This function return the directory path
"""
path = None
grDirectory = re.search(
f"<Directory",
line,
re.IGNORECASE
)
if grDirectory:
path = line.replace("<Directory", "")
path = path.replace(">", "")
path = path.replace("\"", "")
return path
def _constructReports(self):
"""
Construct dictionary for result of the tests
Each entry contains:
Key:
- description: description of the vulnerability
- level: high, medium or low
"""
self._reports['ssl'] = dict()
self._reports['signature'] = dict()
self._reports['indexes'] = dict()