287 lines
9.9 KiB
Python
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()
|