Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/auto_prefix_issues.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Autoprefix & Label Issues
name: Auto-prefix & Label Issues

on:
issues:
Expand Down
69 changes: 60 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,19 +1,70 @@
.PHONY : all clean build upload
.PHONY : all clean build upload test test-verbose test-coverage lint lint-fix fix

PROJECTNAME := apachetomcatscanner

all: install clean

clean:
@rm -rf `find ./ -type d -name "*__pycache__"`
@rm -rf ./build/ ./dist/ ./apachetomcatscanner.egg-info/
@rm -rf ./build/ ./dist/ ./$(PROJECTNAME).egg-info/

generate-docs:
@python3 -m pip install pdoc --break-system-packages
@echo "[$(shell date)] Generating docs ..."
@PDOC_ALLOW_EXEC=1 python3 -m pdoc -d markdown -o ./documentation/ ./$(PROJECTNAME)/
@echo "[$(shell date)] Done!"

uninstall:
pip uninstall $(PROJECTNAME) --yes --break-system-packages

install: build
pip install . --break-system-packages
python3 -m pip install . --break-system-packages

build:
python3 -m pip uninstall apachetomcatscanner --yes --break-system-packages
pip install .[build] --break-system-packages
python3 -m build --wheel
python3 -m pip uninstall $(PROJECTNAME) --yes --break-system-packages
python3 -m pip install build --break-system-packages
python3 -m build

upload: uninstall clean build
python3 -m pip install twine setuptools packaging --upgrade --break-system-packages
python3 -m twine upload dist/*.whl dist/*.tar.gz

test:
@echo "[$(shell date)] Running tests ..."
@cd $(PROJECTNAME)/tests && python3 run_tests.py
@echo "[$(shell date)] Tests completed!"

test-verbose:
@echo "[$(shell date)] Running tests with verbose output ..."
@cd $(PROJECTNAME)/tests && python3 -m unittest discover -v
@echo "[$(shell date)] Tests completed!"

test-coverage:
@echo "[$(shell date)] Installing coverage and running tests with coverage ..."
@python3 -m pip install coverage --break-system-packages
@coverage run --source=$(PROJECTNAME) $(PROJECTNAME)/tests/run_tests.py
@coverage report
@coverage html
@echo "[$(shell date)] Coverage report generated in htmlcov/"

lint:
@echo "[$(shell date)] Installing linting tools ..."
@python3 -m pip install flake8 black isort --break-system-packages
@echo "[$(shell date)] Running flake8 linting ..."
@python3 -m flake8 $(PROJECTNAME)/ --max-line-length=88 --extend-ignore=E501
@echo "[$(shell date)] Running black code formatting check ..."
@python3 -m black --check --diff $(PROJECTNAME)/
@echo "[$(shell date)] Running isort import sorting check ..."
@python3 -m isort --check-only --diff $(PROJECTNAME)/
@echo "[$(shell date)] Linting completed!"

upload: build
pip install .[twine] --break-system-packages
twine upload dist/*
lint-fix:
@echo "[$(shell date)] Installing linting tools ..."
@python3 -m pip install flake8 black isort --break-system-packages
@echo "[$(shell date)] Running black to fix formatting issues ..."
@python3 -m black $(PROJECTNAME)/
@echo "[$(shell date)] Running isort to fix import sorting ..."
@python3 -m isort $(PROJECTNAME)/
@echo "[$(shell date)] Running flake8 to check remaining issues ..."
@python3 -m flake8 $(PROJECTNAME)/ --max-line-length=88 --extend-ignore=E501
@echo "[$(shell date)] Code formatting fixes completed!"
34 changes: 22 additions & 12 deletions apachetomcatscanner/Config.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,21 @@ def debug(self, msg):

def __load_default_credentials(self):
self.credentials = {}
path_to_creds = os.path.dirname(__file__) + os.path.sep + 'data' + os.path.sep + 'credentials.json'
f = open(path_to_creds, 'r')
path_to_creds = (
os.path.dirname(__file__)
+ os.path.sep
+ "data"
+ os.path.sep
+ "credentials.json"
)
f = open(path_to_creds, "r")
self.credentials = json.loads(f.read())["credentials"]
f.close()
return None

def load_credentials_from_options(self, username, password, usernames_file, passwords_file):
def load_credentials_from_options(
self, username, password, usernames_file, passwords_file
):
usernames = []
passwords = []

Expand All @@ -69,11 +77,9 @@ def load_credentials_from_options(self, username, password, usernames_file, pass
self.credentials = []
for username in usernames:
for password in passwords:
self.credentials.append({
"username": username,
"password": password,
"description": ""
})
self.credentials.append(
{"username": username, "password": password, "description": ""}
)
return len(self.credentials)

# Get / Set functions
Expand Down Expand Up @@ -122,7 +128,7 @@ def get_debug_mode(self):
return self.debug_mode

def set_debug_mode(self, value):
if value == True:
if value:
self.verbose_mode = True
self.debug_mode = value

Expand All @@ -140,18 +146,22 @@ def set_request_proxies(self, proxy_ip, proxy_port, protocol=None):
if protocol is None:
self.request_proxies = {
"http": "%s:%d" % (proxy_ip, proxy_port),
"https": "%s:%d" % (proxy_ip, proxy_port)
"https": "%s:%d" % (proxy_ip, proxy_port),
}
else:
self.request_proxies[protocol] = "%s://%s:%d/" % (protocol, proxy_ip, proxy_port)
self.request_proxies[protocol] = "%s://%s:%d/" % (
protocol,
proxy_ip,
proxy_port,
)
return self.request_proxies

def clear_request_proxies(self):
self.request_proxies = {}

def get_no_colors(self):
return self.no_colors

def set_no_colors(self, value):
self.no_colors = value

Expand Down
95 changes: 73 additions & 22 deletions apachetomcatscanner/Reporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import os.path
import sqlite3
import traceback

import xlsxwriter


Expand All @@ -32,7 +33,11 @@ def report_result(self, computer_ip, computer_port, result, credentials_found):
finding["computer_port"] = computer_port
finding["credentials_found"] = credentials_found

finding["cves"] = self.vulns_db.get_vulnerabilities_of_version_sorted_by_criticity(finding["version"], colors=False, reverse=True)
finding["cves"] = (
self.vulns_db.get_vulnerabilities_of_version_sorted_by_criticity(
finding["version"], colors=False, reverse=True
)
)

if computer_ip not in self.data.keys():
self.data[computer_ip] = {}
Expand All @@ -49,7 +54,15 @@ def print_new_results(self):
prompt = "[>] [Apache Tomcat/%s] on %s:%s (manager: accessible) on %s "
else:
prompt = "[>] [Apache Tomcat/\x1b[1;95m%s\x1b[0m] on \x1b[1;93m%s\x1b[0m:\x1b[1;93m%s\x1b[0m (manager: \x1b[1;92maccessible\x1b[0m) on \x1b[4;94m%s\x1b[0m "
print(prompt % (finding["version"], finding["computer_ip"], finding["computer_port"], finding["manager_url"]))
print(
prompt
% (
finding["version"],
finding["computer_ip"],
finding["computer_port"],
finding["manager_url"],
)
)

if len(finding["credentials_found"]) != 0:
for statuscode, creds in finding["credentials_found"]:
Expand All @@ -58,7 +71,14 @@ def print_new_results(self):
prompt = " | Valid user: %s | password: %s | %s"
else:
prompt = " | Valid user: \x1b[1;92m%s\x1b[0m | password: \x1b[1;92m%s\x1b[0m | \x1b[94m%s\x1b[0m"
print(prompt % (creds["username"], creds["password"], creds["description"]))
print(
prompt
% (
creds["username"],
creds["password"],
creds["description"],
)
)
else:
if self.config.no_colors:
prompt = " | Valid user: %s | password: %s"
Expand All @@ -68,19 +88,35 @@ def print_new_results(self):

else:
if self.config.no_colors:
prompt = "[>] [Apache Tomcat/%s] on %s:%s (manager: not accessible)"
prompt = (
"[>] [Apache Tomcat/%s] on %s:%s (manager: not accessible)"
)
else:
prompt = "[>] [Apache Tomcat/\x1b[1;95m%s\x1b[0m] on \x1b[1;93m%s\x1b[0m:\x1b[1;93m%s\x1b[0m (manager: \x1b[1;91mnot accessible\x1b[0m)\x1b[0m "
print(prompt % (finding["version"], finding["computer_ip"], finding["computer_port"]))
print(
prompt
% (
finding["version"],
finding["computer_ip"],
finding["computer_port"],
)
)

# List of cves
if self.config.list_cves_mode == True and self.config.show_cves_descriptions_mode == False:
cve_list = self.vulns_db.get_vulnerabilities_of_version_sorted_by_criticity(finding["version"], colors=True, reverse=True)
if (
self.config.list_cves_mode
and not self.config.show_cves_descriptions_mode
):
cve_list = self.vulns_db.get_vulnerabilities_of_version_sorted_by_criticity(
finding["version"], colors=True, reverse=True
)
cve_list = [cve_colored for cve_colored, cve_content in cve_list]
if len(cve_list) != 0:
print(" | CVEs: %s" % ', '.join(cve_list))
elif self.config.show_cves_descriptions_mode == True:
cve_list = self.vulns_db.get_vulnerabilities_of_version_sorted_by_criticity(finding["version"], colors=True, reverse=True)
print(" | CVEs: %s" % ", ".join(cve_list))
elif self.config.show_cves_descriptions_mode:
cve_list = self.vulns_db.get_vulnerabilities_of_version_sorted_by_criticity(
finding["version"], colors=True, reverse=True
)
for cve_colored, cve_content in cve_list:
print(" | %s: %s" % (cve_colored, cve_content["description"]))

Expand All @@ -104,8 +140,15 @@ def export_xlsx(self, path_to_file):
workbook = xlsxwriter.Workbook(path_to_file)
worksheet = workbook.add_worksheet()

header_format = workbook.add_format({'bold': 1})
header_fields = ["Computer IP", "Port", "Apache tomcat version", "Manager accessible", "Default credentials found", "CVEs on this version"]
header_format = workbook.add_format({"bold": 1})
header_fields = [
"Computer IP",
"Port",
"Apache tomcat version",
"Manager accessible",
"Default credentials found",
"CVEs on this version",
]
for k in range(len(header_fields)):
worksheet.set_column(k, k + 1, len(header_fields[k]) + 3)
worksheet.set_row(0, 20, header_format)
Expand All @@ -115,16 +158,18 @@ def export_xlsx(self, path_to_file):
for computername in self.data.keys():
computer = self.data[computername]
for _, finding in computer.items():
cve_str = ', '.join([cve["cve"]["id"] for cve in finding["cves"]])
credentials_str = ', '.join([f"{cred[1]} ({cred[0]})" for cred in finding["credentials_found"]])
cve_str = ", ".join([cve["cve"]["id"] for cve in finding["cves"]])
credentials_str = ", ".join(
[f"{cred[1]} ({cred[0]})" for cred in finding["credentials_found"]]
)

data = [
finding["computer_ip"],
finding["computer_port"],
finding["version"],
str(finding["manager_accessible"]).upper(),
credentials_str,
cve_str
cve_str,
]
worksheet.write_row(row_id, 0, data)
row_id += 1
Expand All @@ -141,7 +186,7 @@ def export_json(self, path_to_file):
path_to_file = basepath + os.path.sep + filename
else:
path_to_file = filename
f = open(path_to_file, 'w')
f = open(path_to_file, "w")
f.write(json.dumps(self.data, indent=4))
f.close()

Expand All @@ -158,21 +203,27 @@ def export_sqlite(self, path_to_file):

conn = sqlite3.connect(path_to_file)
cursor = conn.cursor()
cursor.execute("CREATE TABLE IF NOT EXISTS results(computer_ip VARCHAR(255), computer_port INTEGER, version VARCHAR(255), manager_accessible VARCHAR(255), credentials_found VARCHAR(255), cves INTEGER);")
cursor.execute(
"CREATE TABLE IF NOT EXISTS results(computer_ip VARCHAR(255), computer_port INTEGER, version VARCHAR(255), manager_accessible VARCHAR(255), credentials_found VARCHAR(255), cves INTEGER);"
)
for computername in self.data.keys():
computer = self.data[computername]
for _, finding in computer.items():
cve_str = ', '.join([cve["cve"]["id"] for cve in finding["cves"]])
credentials_str = ', '.join([f"{cred[1]} ({cred[0]})" for cred in finding["credentials_found"]])
cve_str = ", ".join([cve["cve"]["id"] for cve in finding["cves"]])
credentials_str = ", ".join(
[f"{cred[1]} ({cred[0]})" for cred in finding["credentials_found"]]
)

cursor.execute("INSERT INTO results VALUES (?, ?, ?, ?, ?, ?)", (
cursor.execute(
"INSERT INTO results VALUES (?, ?, ?, ?, ?, ?)",
(
finding["computer_ip"],
finding["computer_port"],
finding["version"],
str(finding["manager_accessible"]).upper(),
credentials_str,
cve_str
)
cve_str,
),
)
conn.commit()
conn.close()
Loading