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