Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ARS-480 Add hash to key ASM findings #511

Merged
merged 3 commits into from
Jul 23, 2024
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 engines/nmap/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
FROM alpine:3.16.3
LABEL Name="Nmap\ \(Patrowl engine\)" Version="1.5.1"
LABEL Name="Nmap\ \(Patrowl engine\)" Version="1.5.2"

# Set the working directory
RUN mkdir -p /opt/patrowl-engines/nmap
Expand Down
2 changes: 1 addition & 1 deletion engines/nmap/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.5.1
1.5.2
2 changes: 1 addition & 1 deletion engines/nmap/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-

__title__ = "patrowl_engine_nmap"
__version__ = "1.5.1"
__version__ = "1.5.2"
__author__ = "Nicolas MATTIOCCO"
__license__ = "AGPLv3"
__copyright__ = "Copyright (C) 2018-2024 Nicolas Mattiocco - @MaKyOtOx"
66 changes: 54 additions & 12 deletions engines/nmap/engine-nmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,16 @@
import os
import subprocess
import sys
import traceback
import psutil
import hashlib
import json
import optparse
import threading
import urllib
import time
import datetime
from collections import defaultdict
from shlex import split
from urllib.parse import urlparse
from copy import deepcopy
from flask import Flask, request, jsonify, redirect, url_for, send_from_directory
from flask import Flask, request, jsonify
import xml.etree.ElementTree as ET
import banner

Expand All @@ -25,8 +22,6 @@
from PatrowlEnginesUtils.PatrowlEngine import PatrowlEngine
from PatrowlEnginesUtils.PatrowlEngineExceptions import PatrowlEngineExceptions

from requests.packages.urllib3.exceptions import InsecureRequestWarning

app = Flask(__name__)
APP_DEBUG = os.environ.get("DEBUG", "").lower() in ["true", "1", "yes", "y", "on"]
APP_MAXSCANS = int(os.environ.get("APP_MAXSCANS", 5))
Expand Down Expand Up @@ -113,6 +108,16 @@ def status():
@app.route("/engines/nuclei/getreport/<scan_id>")
def getreport(scan_id):
"""Get report on finished scans."""
if scan_id not in engine.scans.keys():
return (
jsonify(
{
"status": "error",
"reason": f"Error 1002: scan_id '{scan_id}' not found",
}
),
503,
)
return engine.getreport(scan_id)


Expand Down Expand Up @@ -185,6 +190,16 @@ def stop():
@app.route("/engines/nmap/stop/<scan_id>")
def stop_scan(scan_id):
"""Stop scan identified by id."""
if scan_id not in engine.scans.keys():
return (
jsonify(
{
"status": "error",
"reason": f"Error 1002: scan_id '{scan_id}' not found",
}
),
503,
)
return engine.stop_scan(scan_id)


Expand Down Expand Up @@ -470,6 +485,10 @@ def _scan_thread(scan_id, thread_id):
return True


def hash_text(text):
return hashlib.sha1(text.encode("utf-8")).hexdigest()[:6]


def get_service_banner(scan_id, raw_hosts):
ts = int(time.time() * 1000)
res = []
Expand All @@ -488,13 +507,15 @@ def get_service_banner(scan_id, raw_hosts):
if port_banner == "":
continue

hash_banner = hash_text(port_banner)

res.append(
deepcopy(
_add_issue(
scan_id=scan_id,
target=target,
ts=ts,
title=f"Service banner for {host}:{port}",
title=f"Service banner for {host}:{port} (HASH: {hash_banner})",
desc=f"Service banner:\n\n{port_banner}",
type="port_banner",
raw={"banner": port_banner, "host": host, "port": port},
Expand Down Expand Up @@ -548,7 +569,6 @@ def _parse_report(filename, scan_id):
issues = []
target = {}
raw_hosts = {}
nb_vulns = {"info": 0, "low": 0, "medium": 0, "high": 0, "critical": 0}

try:
tree = ET.parse(filename)
Expand Down Expand Up @@ -670,6 +690,7 @@ def _parse_report(filename, scan_id):
openports = False
# get ports status - generate issues
if host.find("ports") is not None:
all_open_ports = []
for port in host.find("ports"):
if port.tag == "extraports":
continue
Expand All @@ -690,9 +711,10 @@ def _parse_report(filename, scan_id):
raw_hosts[t].append(portid)

# get service information if available
if port.find("service") is not None and port.find("state").get(
"state"
) not in ["filtered", "closed"]:
if port.find("service") is not None and port_state not in [
"filtered",
"closed",
]:
svc_name = port.find("service").get("name")
if svc_name == "tcpwrapped": # Classic shit with WAF and Firewalls
continue
Expand Down Expand Up @@ -781,6 +803,7 @@ def _parse_report(filename, scan_id):

if port_state not in ["filtered", "closed"]:
openports = True
all_open_ports.append(portid)
issues.append(
deepcopy(
_add_issue(
Expand Down Expand Up @@ -815,6 +838,25 @@ def _parse_report(filename, scan_id):
)
)

# Prepare and create a finding with all open ports
all_open_ports = list(set(all_open_ports))
all_open_ports.sort()
all_open_ports_str = ",".join([str(x) for x in all_open_ports])
all_open_ports_hash = hash_text(all_open_ports_str)
issues.append(
deepcopy(
_add_issue(
scan_id,
target,
ts,
f"Host has '{len(all_open_ports)}' open port(s) (HASH: {all_open_ports_hash})",
f"The scan detected following open ports: \n{all_open_ports_str}",
type="open_ports",
raw=all_open_ports,
)
)
)

# get host status
status = host.find("status").get("state")
if openports: # There are open ports so it must be up
Expand Down
2 changes: 1 addition & 1 deletion engines/nmap/nmap.json.sample
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Nmap",
"version": "1.5.1",
"version": "1.5.2",
"description": "Network Scanner",
"path": "/usr/bin/nmap",
"allowed_asset_types": ["ip", "domain", "fqdn", "url", "ip-range", "ip-subnet"],
Expand Down
2 changes: 1 addition & 1 deletion engines/owl_dns/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
FROM alpine:3.16.3
LABEL Name="Patrowl\ DNS\ \(Patrowl engine\)" Version="1.5.9"
LABEL Name="Patrowl\ DNS\ \(Patrowl engine\)" Version="1.5.10"

# Install dependencies
RUN apk add --update --no-cache \
Expand Down
2 changes: 1 addition & 1 deletion engines/owl_dns/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.5.9
1.5.10
2 changes: 1 addition & 1 deletion engines/owl_dns/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
sys.path.append(os.path.dirname(os.path.realpath(__file__)))

__title__ = "patrowl_engine_owl_dns"
__version__ = "1.5.9"
__version__ = "1.5.10"
__author__ = "Nicolas MATTIOCCO"
__license__ = "AGPLv3"
__copyright__ = "Copyright (C) 2018-2024 Nicolas Mattiocco - @MaKyOtOx"
10 changes: 8 additions & 2 deletions engines/owl_dns/engine_owl_dns.py
Original file line number Diff line number Diff line change
Expand Up @@ -1144,11 +1144,17 @@ def _get_whois(scan_id, asset):
)
if is_ip:
w = IPWhois(str(asset).strip()).lookup_rdap()
w_text = "see raw"
try:
w_text = json.dumps(w, sort_keys=True)
except Exception:
pass

res.update(
{
asset: {
"raw": {"dict": w, "text": "see raw"},
"text": "see raw",
"raw": {"dict": w, "text": w_text},
"text": w_text,
"type": "ip",
}
}
Expand Down
2 changes: 1 addition & 1 deletion engines/owl_dns/owl_dns.json.sample
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "PatrOwl - Dns module",
"version": "1.5.9",
"version": "1.5.10",
"description": "DNS Scanner",
"allowed_asset_types": ["ip", "domain", "fqdn", "keyword"],
"sublist3r_bin_path": "/opt/patrowl-engines/owl_dns/external-libs/Sublist3r",
Expand Down
Loading