First commit
This commit is contained in:
commit
96342a2b2c
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
__pycache__/
|
||||||
|
__pycache__/**
|
36
main.py
Normal file
36
main.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
from sysctl import Sysctl
|
||||||
|
|
||||||
|
|
||||||
|
def checkArguments():
|
||||||
|
args = ArgumentParser(description="Check Gitlab repositories")
|
||||||
|
args.add_argument('-a', '--audit', help="Kind of audit", choices=['system', 'application'])
|
||||||
|
return args.parse_args()
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = checkArguments()
|
||||||
|
|
||||||
|
# If audit is not specified
|
||||||
|
if args.audit is None:
|
||||||
|
print("Please, you must specify the audit type")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
# Report
|
||||||
|
report = dict()
|
||||||
|
report['system'] = None
|
||||||
|
|
||||||
|
# Audit application
|
||||||
|
if args.audit == "application":
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Audit system
|
||||||
|
if args.audit == "system":
|
||||||
|
sysctl = Sysctl()
|
||||||
|
sysctl.runAudit()
|
||||||
|
|
||||||
|
report['sysctl'] = sysctl.getReports()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
118
old_main.py
Executable file
118
old_main.py
Executable file
@ -0,0 +1,118 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
import re
|
||||||
|
from os import path
|
||||||
|
from subprocess import call, check_output, run
|
||||||
|
|
||||||
|
|
||||||
|
# 3 levels to tests: low, medium anh high
|
||||||
|
CHECKSLIST = {}
|
||||||
|
|
||||||
|
# TIPS
|
||||||
|
# https://www.process.st/server-security/
|
||||||
|
|
||||||
|
def identifySystem():
|
||||||
|
os = None
|
||||||
|
with open('/etc/issue', 'r') as f:
|
||||||
|
line = f.readline()
|
||||||
|
if re.search('Arch Linux', line):
|
||||||
|
os = 'ARCHLINUX'
|
||||||
|
elif re.search('Ubuntu', line):
|
||||||
|
os = 'UBUNTU'
|
||||||
|
elif re.search('Debian', line):
|
||||||
|
os = 'DEBIAN'
|
||||||
|
else:
|
||||||
|
os = 'UNKNOWN'
|
||||||
|
|
||||||
|
return os
|
||||||
|
|
||||||
|
def check_upgrade_packages():
|
||||||
|
pass
|
||||||
|
|
||||||
|
def check_telnet_is_open():
|
||||||
|
# check port 23 is listening
|
||||||
|
r = run(['ss', '-atn'], capture_output=True)
|
||||||
|
r = r.stdout.decode()
|
||||||
|
print(r)
|
||||||
|
|
||||||
|
def check_empty_local_passwords():
|
||||||
|
pass
|
||||||
|
|
||||||
|
def check_security_access():
|
||||||
|
# Check in /etc/security/access
|
||||||
|
pass
|
||||||
|
|
||||||
|
def check_hosts_allow():
|
||||||
|
# Check in /etc/hosts.allow
|
||||||
|
pass
|
||||||
|
|
||||||
|
def check_sshd_root():
|
||||||
|
res = False
|
||||||
|
|
||||||
|
if not path.exists("/etc/ssh/sshd_config"):
|
||||||
|
print("File sshd_config doesn't exist")
|
||||||
|
return False
|
||||||
|
|
||||||
|
with open("/etc/ssh/sshd_config", "r") as f:
|
||||||
|
for l in f.readlines():
|
||||||
|
l = l.replace('\n', '')
|
||||||
|
if re.search("PermitRootLogin.*root", l):
|
||||||
|
if not re.search("^#", l):
|
||||||
|
res = True
|
||||||
|
return res
|
||||||
|
|
||||||
|
def generateChecksList():
|
||||||
|
# LOW
|
||||||
|
CHECKSLIST['low'] = []
|
||||||
|
CHECKSLIST['low'].append({
|
||||||
|
'callback': check_sshd_root,
|
||||||
|
'name': check_sshd_root.__name__,
|
||||||
|
'resolution': 'Please, remove root auth to your server',
|
||||||
|
'score': 100
|
||||||
|
})
|
||||||
|
CHECKSLIST['low'].append({
|
||||||
|
'callback': check_upgrade_packages,
|
||||||
|
'name': check_upgrade_packages.__name__,
|
||||||
|
'resolution': 'Please, upgrade your packages',
|
||||||
|
'score': 50
|
||||||
|
})
|
||||||
|
CHECKSLIST['low'].append({
|
||||||
|
'callback': check_telnet_is_open,
|
||||||
|
'name': check_telnet_is_open.__name__,
|
||||||
|
'resolution': 'Telnet is enabled. Please, disabled this program if you could.',
|
||||||
|
'score': 50
|
||||||
|
})
|
||||||
|
# MEDIUM
|
||||||
|
CHECKSLIST['medium'] = {}
|
||||||
|
# HIGH
|
||||||
|
CHECKSLIST['high'] = {}
|
||||||
|
|
||||||
|
def getTotalScore():
|
||||||
|
score = 0
|
||||||
|
for entry in CHECKSLIST['low']:
|
||||||
|
score += entry['score']
|
||||||
|
|
||||||
|
return score
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Generate our checklist
|
||||||
|
generateChecksList()
|
||||||
|
|
||||||
|
# Get total score
|
||||||
|
totalScore = getTotalScore()
|
||||||
|
|
||||||
|
# Identify system
|
||||||
|
identifySystem()
|
||||||
|
|
||||||
|
score = totalScore
|
||||||
|
for entry in CHECKSLIST['low']:
|
||||||
|
print(f'Checking {entry["name"]}...')
|
||||||
|
res = entry['callback']()
|
||||||
|
if res:
|
||||||
|
print(entry['resolution'])
|
||||||
|
score -= entry['score']
|
||||||
|
|
||||||
|
print(f'Your total score: {score}')
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
41
parsing.py
Normal file
41
parsing.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import re
|
||||||
|
from json import dumps
|
||||||
|
|
||||||
|
class Parsing:
|
||||||
|
def __init__(self, objects, audit):
|
||||||
|
self._parsing = dict()
|
||||||
|
self._results = dict()
|
||||||
|
self._objects = objects
|
||||||
|
self._audit = audit
|
||||||
|
|
||||||
|
def runParsing(self):
|
||||||
|
for audit in self._audit:
|
||||||
|
if audit['audit'] == 'file':
|
||||||
|
with open(audit['value'], 'rb') as fdata:
|
||||||
|
self._parseFile(fdata)
|
||||||
|
|
||||||
|
def _parseFile(self, fdata):
|
||||||
|
data = fdata.read()
|
||||||
|
lines = data.splitlines()
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
self._parsingFile(line, self._objects['sysctl'])
|
||||||
|
|
||||||
|
def _parsingFile(self, line, item) -> dict:
|
||||||
|
"""
|
||||||
|
This function parse the line and try to find the item in it
|
||||||
|
"""
|
||||||
|
res = None
|
||||||
|
|
||||||
|
line = line.decode("utf-8")
|
||||||
|
for entry in item:
|
||||||
|
groupLine = re.search(entry['item'], line)
|
||||||
|
if groupLine:
|
||||||
|
sLine = line.split('=')
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
def getResults(self) -> dict:
|
||||||
|
result = dict()
|
||||||
|
|
||||||
|
return result
|
1
parsing/__init__.py
Normal file
1
parsing/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
#!/usr/bin/env python3
|
21
parsing/base.py
Normal file
21
parsing/base.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import re
|
||||||
|
from json import dumps
|
||||||
|
|
||||||
|
class ParsingBase:
|
||||||
|
def __init__(self, objects, audit):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def runParsing(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _parseFile(self, fdata):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _parsingFile(self, line, item) -> dict:
|
||||||
|
"""
|
||||||
|
This function parse the line and try to find the item in it
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def getResults(self) -> dict:
|
||||||
|
pass
|
97
parsing/sysctl.py
Normal file
97
parsing/sysctl.py
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import re
|
||||||
|
from json import dumps
|
||||||
|
from parsing.base import ParsingBase
|
||||||
|
|
||||||
|
class Parsing(ParsingBase):
|
||||||
|
def __init__(self, objects, audit):
|
||||||
|
self._parsing = dict()
|
||||||
|
self._results = dict()
|
||||||
|
self._objects = objects
|
||||||
|
self._audit = audit
|
||||||
|
|
||||||
|
def runParsing(self):
|
||||||
|
for audit in self._audit:
|
||||||
|
if audit['audit'] == 'file':
|
||||||
|
with open(audit['value'], 'rb') as fdata:
|
||||||
|
self._parseFile(fdata)
|
||||||
|
if audit['audit'] == 'process':
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _parseFile(self, fdata):
|
||||||
|
data = fdata.read()
|
||||||
|
lines = data.splitlines()
|
||||||
|
numLines = 1
|
||||||
|
|
||||||
|
self._constructResults(filename='/etc/sysctl.conf')
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
line = line.decode("utf-8")
|
||||||
|
|
||||||
|
for obj in self._objects['sysctl']:
|
||||||
|
result = self._parsingFile(line, obj)
|
||||||
|
if len(result) == 0:
|
||||||
|
pass
|
||||||
|
# If the flag is found
|
||||||
|
else:
|
||||||
|
# And if the current value is not setted corectly for the vulnerability
|
||||||
|
print(result)
|
||||||
|
|
||||||
|
self._results[obj['flag']].append({
|
||||||
|
'lineNumber': numLines,
|
||||||
|
'value': obj['value'],
|
||||||
|
'audit': 'failed' # Or success
|
||||||
|
})
|
||||||
|
|
||||||
|
if result['value'] != result['current_value']:
|
||||||
|
print(f"You must change the value to {obj['value']} for fixing the vulnerabilities")
|
||||||
|
|
||||||
|
numLines += 1
|
||||||
|
print(self._results)
|
||||||
|
|
||||||
|
def _parsingFile(self, line, obj) -> dict:
|
||||||
|
"""
|
||||||
|
This function parse the line and try to find the item in it
|
||||||
|
"""
|
||||||
|
result = dict()
|
||||||
|
|
||||||
|
groupLine = re.search(obj['flag'], line)
|
||||||
|
if groupLine:
|
||||||
|
# Avoid the comment
|
||||||
|
if not line.startswith('#'):
|
||||||
|
sLine = line.split('=')
|
||||||
|
flag = sLine[0]
|
||||||
|
value = int(sLine[1].strip(''))
|
||||||
|
#print(sLine)
|
||||||
|
|
||||||
|
result['found'] = flag
|
||||||
|
result['current_value'] = value
|
||||||
|
result['value'] = obj['value']
|
||||||
|
|
||||||
|
if value != obj['value']:
|
||||||
|
print("Need to change the value")
|
||||||
|
print(sLine)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _constructResults(self, filename):
|
||||||
|
"""
|
||||||
|
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 vulnerabilities
|
||||||
|
- level: high, medium or low
|
||||||
|
"""
|
||||||
|
self._results['filename'] = filename
|
||||||
|
|
||||||
|
for sysctl in self._objects['sysctl']:
|
||||||
|
self._results[sysctl['flag']] = list()
|
||||||
|
print(self._results)
|
||||||
|
print("")
|
||||||
|
|
||||||
|
def getResults(self) -> dict:
|
||||||
|
result = dict()
|
||||||
|
|
||||||
|
return result
|
38
report.py
Normal file
38
report.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
def generateHtmlReport(data):
|
||||||
|
today = datetime.now().isoformat()[0:10].replace("-", "_")
|
||||||
|
html = "<!doctype html>" \
|
||||||
|
"<html>" \
|
||||||
|
"<head>" \
|
||||||
|
"</head>" \
|
||||||
|
"<body>" \
|
||||||
|
f"<h1>Reports of {today}</h1>"
|
||||||
|
|
||||||
|
body = str()
|
||||||
|
for project in data['projects']:
|
||||||
|
body += f"<h2>{project['name']}</h2>"
|
||||||
|
|
||||||
|
# For python
|
||||||
|
body += f"<h3>Python</h3>"
|
||||||
|
for py in project['python']:
|
||||||
|
body += f"<h4>{py['file']}</h4>"
|
||||||
|
for vul in py['vulnerabilities']:
|
||||||
|
body += f"<h5>{vul['name']}</h5>"
|
||||||
|
body += f"<p>"
|
||||||
|
body += f"Results:<br />"
|
||||||
|
for result in vul['results']:
|
||||||
|
body += f"Line: {result['lineNumber']}<br />"
|
||||||
|
body += f"Line: {result['line']}<br />"
|
||||||
|
body += f"Level: {result['level']}<br />"
|
||||||
|
body += f"Description: {result['description']}<br /><br />"
|
||||||
|
body += f"</p>"
|
||||||
|
|
||||||
|
html += body
|
||||||
|
#print(body)
|
||||||
|
html += "</body></html>"
|
||||||
|
with open(f"reports/reports_{today}.html", "w") as f:
|
||||||
|
f.write(html)
|
||||||
|
|
39
sysctl.py
Normal file
39
sysctl.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from parsing.sysctl import Parsing
|
||||||
|
from vulnerabilities.system import system
|
||||||
|
from vulnerabilities.sysctl import sysctl
|
||||||
|
|
||||||
|
|
||||||
|
class Sysctl:
|
||||||
|
def __init__(self):
|
||||||
|
self._objects = dict()
|
||||||
|
self._reports = list()
|
||||||
|
self._audit = list()
|
||||||
|
|
||||||
|
self._audit.append({
|
||||||
|
'audit': 'file',
|
||||||
|
'value': '/etc/sysctl.conf',
|
||||||
|
})
|
||||||
|
self._audit.append({
|
||||||
|
'audit': 'process',
|
||||||
|
'value': 'sysctl -a',
|
||||||
|
})
|
||||||
|
|
||||||
|
self._sysctl()
|
||||||
|
|
||||||
|
self._parsing = Parsing(self._objects, self._audit)
|
||||||
|
|
||||||
|
def _sysctl(self):
|
||||||
|
self._objects['sysctl'] = sysctl()
|
||||||
|
|
||||||
|
def runAudit(self):
|
||||||
|
# Read /etc/sysctl.conf
|
||||||
|
self._parsing.runParsing()
|
||||||
|
self._reports.append(self._parsing.getResults())
|
||||||
|
|
||||||
|
# Run process sysctl
|
||||||
|
|
||||||
|
def getReports(self) -> list:
|
||||||
|
return self._reports
|
||||||
|
|
27
utils.py
Normal file
27
utils.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import re
|
||||||
|
from subprocess import run
|
||||||
|
|
||||||
|
|
||||||
|
def identifySystem():
|
||||||
|
os = None
|
||||||
|
with open('/etc/issue', 'r') as f:
|
||||||
|
line = f.readline()
|
||||||
|
if re.search('Arch Linux', line):
|
||||||
|
os = 'ARCHLINUX'
|
||||||
|
elif re.search('Ubuntu', line):
|
||||||
|
os = 'UBUNTU'
|
||||||
|
elif re.search('Debian', line):
|
||||||
|
os = 'DEBIAN'
|
||||||
|
else:
|
||||||
|
os = 'UNKNOWN'
|
||||||
|
|
||||||
|
return os
|
||||||
|
|
||||||
|
def getKernelVersion():
|
||||||
|
"""
|
||||||
|
This function get the kernel version Linux
|
||||||
|
"""
|
||||||
|
kernelVers = run(['/usr/bin/uname', '-r'])
|
||||||
|
return kernelVers.stdout
|
33
vulnerabilities/calls.py
Normal file
33
vulnerabilities/calls.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
def calls() -> list:
|
||||||
|
calls = list()
|
||||||
|
# https://cwe.mitre.org/data/definitions/78.html
|
||||||
|
# For commoand injections
|
||||||
|
calls.append({
|
||||||
|
"call": "exec",
|
||||||
|
"description": "",
|
||||||
|
"level": "high"
|
||||||
|
})
|
||||||
|
calls.append({
|
||||||
|
"call": "chown",
|
||||||
|
"description": "",
|
||||||
|
"level": "high"
|
||||||
|
})
|
||||||
|
calls.append({
|
||||||
|
"call": "chmod",
|
||||||
|
"description": "",
|
||||||
|
"level": "high"
|
||||||
|
})
|
||||||
|
calls.append({
|
||||||
|
"call": "rsync",
|
||||||
|
"description": "",
|
||||||
|
"level": "high"
|
||||||
|
})
|
||||||
|
calls.append({
|
||||||
|
"call": "wrap_socket",
|
||||||
|
"description": "This functions is deprecated. You must use SSLContext.wrap_context",
|
||||||
|
"level": "high"
|
||||||
|
})
|
||||||
|
return calls
|
||||||
|
|
29
vulnerabilities/sysctl.py
Normal file
29
vulnerabilities/sysctl.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
def sysctl() -> list:
|
||||||
|
sysctl = list()
|
||||||
|
|
||||||
|
# https://access.redhat.com/security/sysctl/sysctl-2023-0179
|
||||||
|
sysctl.append({
|
||||||
|
"cve": "cve-2023-0179",
|
||||||
|
"description": "",
|
||||||
|
"flag": "kernel.unprivileged_userns_clone",
|
||||||
|
"value": 0,
|
||||||
|
"level": "medium",
|
||||||
|
"affectedSystem": ({
|
||||||
|
'linux': "Debian",
|
||||||
|
'release': 'buster',
|
||||||
|
'kernel': '4.19.249-2'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
# Best practice from CIS
|
||||||
|
sysctl.append({
|
||||||
|
"cve": "",
|
||||||
|
"description": "Disable IPv4 forwarding",
|
||||||
|
"flag": "net.ipv4.conf.all.forwarding",
|
||||||
|
"value": 0,
|
||||||
|
"level": "medium"
|
||||||
|
})
|
||||||
|
|
||||||
|
return sysctl
|
6
vulnerabilities/system.py
Normal file
6
vulnerabilities/system.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
def system() -> list:
|
||||||
|
system = list()
|
||||||
|
|
||||||
|
return system
|
Loading…
Reference in New Issue
Block a user