From aa53517676d6e62f3397cdc95288023f769c6064 Mon Sep 17 00:00:00 2001 From: dolevf Date: Thu, 1 Oct 2020 11:59:16 -0400 Subject: [PATCH] Ability to close alerts, better descriptions, bug fixes --- core/redis.py | 6 + main.py | 2 + rules/bruteforce/rule_basicauth-bf.py | 13 +- rules/bruteforce/rule_ftp-bf.py | 13 +- rules/bruteforce/rule_mongodb-bf.py | 13 +- rules/bruteforce/rule_mysql-bf.py | 12 +- rules/bruteforce/rule_psql-bf.py | 12 +- rules/bruteforce/rule_redis-bf.py | 10 +- rules/bruteforce/rule_ssh-bf.py | 12 +- rules/configuration/rule_actuator.py | 20 ++-- rules/configuration/rule_apache.py | 17 ++- rules/configuration/rule_basic-auth.py | 16 ++- .../configuration/rule_cors-custom-origin.py | 15 +-- rules/configuration/rule_cors-wildcard.py | 18 ++- rules/configuration/rule_default-webpages.py | 14 +-- rules/configuration/rule_laravel.py | 17 ++- rules/configuration/rule_nginx-status.py | 13 +- rules/configuration/rule_nodejs.py | 13 +- rules/configuration/rule_openapi.py | 17 ++- rules/configuration/rule_php-info.py | 17 ++- rules/configuration/rule_powered-by.py | 20 ++-- rules/configuration/rule_ssh-auth-check.py | 16 +-- rules/configuration/rule_wordpress.py | 17 ++- rules/configuration/rule_wp-xmlrpc.py | 16 +-- rules/cves/rule_f5-cve-2020-5902.py | 37 +++--- rules/cves/rule_fortinet-cve-2018-13379.py | 38 +++--- rules/cves/rule_nginx-cve-2017-7529.py | 35 +++--- rules/discovery/rule_adminer.py | 31 +++-- rules/discovery/rule_artifactory.py | 13 +- rules/discovery/rule_aspconfig.py | 31 +++-- rules/discovery/rule_cisco-asa.py | 31 +++-- rules/discovery/rule_clockwork.py | 31 +++-- rules/discovery/rule_composer.py | 31 +++-- rules/discovery/rule_consul.py | 31 +++-- rules/discovery/rule_django-rest.py | 31 +++-- rules/discovery/rule_docker-registry.py | 31 +++-- rules/discovery/rule_elmah.py | 13 +- rules/discovery/rule_flask-console.py | 13 +- rules/discovery/rule_flyway.py | 15 +-- rules/discovery/rule_gitlab.py | 31 +++-- rules/discovery/rule_globalprotect.py | 31 +++-- rules/discovery/rule_hadoop.py | 31 +++-- rules/discovery/rule_jenkins.py | 31 +++-- rules/discovery/rule_jmx-console.py | 31 +++-- rules/discovery/rule_jolokia.py | 35 +++--- rules/discovery/rule_known-platforms-body.py | 20 ++-- .../discovery/rule_known-platforms-headers.py | 32 +++-- rules/discovery/rule_liferay.py | 31 +++-- rules/discovery/rule_moadmin.py | 13 +- rules/discovery/rule_phpmyadmin.py | 31 +++-- rules/discovery/rule_pprof.py | 31 +++-- rules/discovery/rule_prometheus.py | 31 +++-- rules/discovery/rule_redash.py | 31 +++-- rules/discovery/rule_selenium-grid.py | 31 +++-- rules/discovery/rule_snoopjsp.py | 31 +++-- rules/discovery/rule_solr.py | 31 +++-- rules/discovery/rule_struts-console.py | 31 +++-- rules/discovery/rule_webmin.py | 31 +++-- rules/discovery/rule_zabbix.py | 31 +++-- rules/services/rule_admin-ports.py | 37 +++--- rules/services/rule_db-ports.py | 19 +-- rules/services/rule_ftp-ports.py | 34 +++--- rules/services/rule_http-ports.py | 35 +++--- rules/services/rule_ldap-ports.py | 35 +++--- rules/services/rule_obfuscated-ssh.py | 37 +++--- rules/services/rule_rare-ports.py | 33 +++-- rules/services/rule_smb-ports.py | 36 +++--- rules/services/rule_svc-ports.py | 34 +++--- rules/services/rule_vpn-ports.py | 33 +++-- .../rule_beanstalk-takeover.py | 15 +-- rules/vulnerabilities/rule_crlf-injection.py | 15 ++- rules/vulnerabilities/rule_cve-check.py | 10 +- rules/vulnerabilities/rule_dir-index.py | 13 +- rules/vulnerabilities/rule_ds-store.py | 14 +-- rules/vulnerabilities/rule_elasticsearch.py | 31 +++-- rules/vulnerabilities/rule_error-detect.py | 13 +- rules/vulnerabilities/rule_front-page.py | 13 +- rules/vulnerabilities/rule_ftp-anon-access.py | 31 ++--- rules/vulnerabilities/rule_git-repo.py | 32 +++-- rules/vulnerabilities/rule_graphql.py | 12 +- rules/vulnerabilities/rule_host-inject.py | 20 ++-- rules/vulnerabilities/rule_intellij-idea.py | 12 +- rules/vulnerabilities/rule_redis-dump-keys.py | 14 +-- rules/vulnerabilities/rule_s3-takeover.py | 33 +++-- rules/vulnerabilities/rule_shellshock.py | 16 ++- .../rule_ssh_filedisclosure.py | 16 +-- rules/vulnerabilities/rule_svn-repo.py | 14 +-- .../vulnerabilities/rule_unencrypted_login.py | 37 +++--- .../vulnerabilities/rule_wordpress-listing.py | 13 +- rules/vulnerabilities/rule_xfh-injection.py | 19 ++- rules/vulnerabilities/rule_xmlrpc.py | 47 -------- static/css/nerve.css | 2 +- templates/alert.html | 113 ++++++++++++++++++ templates/assessment.html | 23 ++-- templates/assets.html | 34 +++--- templates/console.html | 20 ++-- templates/dashboard.html | 27 ++--- templates/documentation.html | 21 ++-- templates/login.html | 17 +-- templates/quickstart.html | 21 ++-- templates/reports.html | 21 ++-- templates/settings.html | 22 ++-- templates/sidebar.html | 3 +- templates/topology.html | 28 ++--- templates/vulnerabilities.html | 42 ++++--- templates/welcome.html | 20 ++-- version.py | 2 +- views/view_alert.py | 34 ++++++ views/view_vulns.py | 4 + 109 files changed, 1210 insertions(+), 1364 deletions(-) delete mode 100644 rules/vulnerabilities/rule_xmlrpc.py create mode 100644 templates/alert.html create mode 100644 views/view_alert.py diff --git a/core/redis.py b/core/redis.py index 0555408..76c7dcc 100644 --- a/core/redis.py +++ b/core/redis.py @@ -123,6 +123,12 @@ def get_vuln_data(self): logger.error('Error retrieving key') return kv + + def get_vuln_by_id(self, alert_id): + vuln = self.r.get(alert_id) + if vuln: + return pickle.loads(vuln) + return None def get_inventory_data(self): kv = {} diff --git a/main.py b/main.py index 9c88e15..a83efda 100644 --- a/main.py +++ b/main.py @@ -26,6 +26,7 @@ from views.view_settings import settings from views.view_scan import scan from views.view_vulns import vulns +from views.view_alert import alert from views.view_startover import startover # Import REST API Endpoints @@ -52,6 +53,7 @@ app.register_blueprint(vulns) app.register_blueprint(settings) app.register_blueprint(scan) +app.register_blueprint(alert) app.register_blueprint(startover) app.config.update( diff --git a/rules/bruteforce/rule_basicauth-bf.py b/rules/bruteforce/rule_basicauth-bf.py index d156396..c21e9ba 100644 --- a/rules/bruteforce/rule_basicauth-bf.py +++ b/rules/bruteforce/rule_basicauth-bf.py @@ -12,11 +12,11 @@ class Rule: def __init__(self): self.rule = 'BRF_42FE' self.rule_severity = 4 - self.rule_description = 'Checks if Basic Authentication is using weak credentials' + self.rule_description = 'This rule checks if a Web Server is configured with Basic Authentication using weak credentials' self.rule_confirm = 'Basic Authentication with Weak Credentials' self.rule_details = '' self.rule_mitigation = '''Basic Authentication is configured on the remote server with weak credentials. -Change to a stronger password or alternatively use Single Sign On solution, such as Google.''' +Change to a stronger password or alternatively use a Single Sign On solution.''' self.rule_doc_roots = COMMON_LOGIN_PATHS self.intensity = 3 @@ -46,9 +46,8 @@ def check_rule(self, ip, port, values, conf): for password in passwords: auth_attempt = requests.get(resp.url, auth = HTTPBasicAuth(username, password)) if auth_attempt is not None and auth_attempt.status_code == 200: - - self.rule_details = 'Credentials are set to {}:{} at {}'.format(username, password, uri) - js_data = { + self.rule_details = 'Basic Authentication Credentials are set to {}:{} at {}'.format(username, password, uri) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -58,8 +57,6 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - - rds.store_vuln(js_data) + }) return diff --git a/rules/bruteforce/rule_ftp-bf.py b/rules/bruteforce/rule_ftp-bf.py index 0595a3d..978e761 100644 --- a/rules/bruteforce/rule_ftp-bf.py +++ b/rules/bruteforce/rule_ftp-bf.py @@ -10,11 +10,11 @@ class Rule: def __init__(self): self.rule = 'BRF_AZZ0' self.rule_severity = 4 - self.rule_description = 'Checks if FTP is configured with weak credentials' + self.rule_description = 'This rule checks if an FTP server is configured to accept remote connections using weak credentials' self.rule_confirm = 'Remote Server with weak FTP credentials' self.rule_details = '' - self.rule_mitigation = '''FTP Server Allows connections with a weak password. -FTP must not be listening on an external interface, and if required, it must allow only specific source IP addresses, in addition to a strong password authentication.''' + self.rule_mitigation = '''FTP Server allows remote connections be accepted using a weak password. +FTP should not be listening on an external interface. If required, it is recommended to allow only specific source IP addresses, in addition to a strong password authentication.''' self.intensity = 3 def ftp_attack(self, ip, username, password): @@ -51,8 +51,8 @@ def check_rule(self, ip, port, values, conf): for username in usernames: for password in passwords: if self.ftp_attack(ip, username, password): - self.rule_details = 'Credentials are set to: {}:{}'.format(username, password) - js_data = { + self.rule_details = 'FTP Server Credentials are set to: {}:{}'.format(username, password) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -62,8 +62,7 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) return diff --git a/rules/bruteforce/rule_mongodb-bf.py b/rules/bruteforce/rule_mongodb-bf.py index 0d0b868..8d93254 100644 --- a/rules/bruteforce/rule_mongodb-bf.py +++ b/rules/bruteforce/rule_mongodb-bf.py @@ -10,11 +10,13 @@ class Rule: def __init__(self): self.rule = 'BRF_H7J5' self.rule_severity = 4 - self.rule_description = 'Checks if MongoDB is configured with weak credentials' + self.rule_description = 'This rule checks if MongoDB server is configured to accept remote connections using weak credentials' self.rule_confirm = 'Remote Server with weak MongoDB credentials' self.rule_details = '' - self.rule_mitigation = '''MongoDB Server Allows connections with a weak password. -MongoDB must not be listening on an external interface, and if required, it must allow only specific source IP addresses, in addition to a strong password authentication.''' + self.rule_mitigation = '''MongoDB Server allows cremote onnections with a weak password. +MongoDB must not be listening on an external interface, and if required, it must allow only specific source IP addresses, in addition to a strong password authentication. +Refer to the MongoDB hardening guide for more information: https://docs.mongodb.com/manual/administration/security-checklist/ +''' self.intensity = 3 def mongodb_attack(self, ip, port, username, password): @@ -55,7 +57,7 @@ def check_rule(self, ip, port, values, conf): # Check if MongoDB is configured with or without authentication if self.mongodb_attack(ip, port, None, None): - js_data = { + rds.store_vuln({ 'ip': ip, 'port': port, 'domain': domain, @@ -65,8 +67,7 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm': 'Remote server with no authentication on MongoDB', 'rule_details': 'MongoDB is configured with no authentication', 'rule_mitigation': self.rule_mitigation - } - rds.store_vuln(js_data) + }) return if not c.get_cfg_allow_bf(): diff --git a/rules/bruteforce/rule_mysql-bf.py b/rules/bruteforce/rule_mysql-bf.py index 24647b4..5de54af 100644 --- a/rules/bruteforce/rule_mysql-bf.py +++ b/rules/bruteforce/rule_mysql-bf.py @@ -10,11 +10,12 @@ class Rule: def __init__(self): self.rule = 'BRF_4F74' self.rule_severity = 4 - self.rule_description = 'Checks if MySQL is configured with weak credentials' + self.rule_description = 'This rule checks if MySQL is configured to accept remote connections using weak credentials' self.rule_confirm = 'Remote Server with weak MySQL credentials' self.rule_details = '' self.rule_mitigation = '''MySQL Allows connections with a weak password. -MySQL must not be listening on an external interface, and if required, it must allow only specific source IP addresses, in addition to a strong password authentication.''' +MySQL must not be listening on an external interface, and if required, it must allow only specific source IP addresses, in addition to a strong password authentication. +Refer to the MySQL Hardening Guideline for more information: https://dev.mysql.com/doc/refman/8.0/en/security-guidelines.html''' self.intensity = 3 def mysql_attack(self, ip, username, password): @@ -48,8 +49,8 @@ def check_rule(self, ip, port, values, conf): for username in usernames: for password in passwords: if self.mysql_attack(ip, username, password): - self.rule_details = 'Credentials are set to: {}'.format(result) - js_data = { + self.rule_details = 'MySQL Credentials are set to: {}:{}'.format(username, password) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -59,8 +60,7 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) return diff --git a/rules/bruteforce/rule_psql-bf.py b/rules/bruteforce/rule_psql-bf.py index 254b61c..d17e37c 100644 --- a/rules/bruteforce/rule_psql-bf.py +++ b/rules/bruteforce/rule_psql-bf.py @@ -9,11 +9,12 @@ class Rule: def __init__(self): self.rule = 'BRF_DC78' self.rule_severity = 4 - self.rule_description = 'Checks if PostgreSQL is configured with weak credentials' + self.rule_description = 'This rule checks if PostgreSQL is configured to accept remote connections using weak credentials' self.rule_confirm = 'Remote Server with weak PostgreSQL credentials' self.rule_details = '' self.rule_mitigation = '''PostgreSQL Allows connections with a weak password. -PostgreSQL must not be listening on an external interface, and if required, it must allow only specific source IP addresses, in addition to a strong password authentication.''' +PostgreSQL must not be listening on an external interface, and if required, it must allow only specific source IP addresses, in addition to a strong password authentication. +Refer to the PostgreSQL Hardening Guideline for more information: https://www.postgresql.org/docs/7.0/security.htm''' self.intensity = 3 def psql_attack(self, ip, username, password): @@ -48,8 +49,8 @@ def check_rule(self, ip, port, values, conf): for username in usernames: for password in passwords: if self.psql_attack(ip, username, password): - self.rule_details = 'Credentials are set to {}:{}'.format(username, password) - js_data = { + self.rule_details = 'PostgreSQL Credentials are set to {}:{}'.format(username, password) + rds.store_vuln({ 'ip': ip, 'port': port, 'domain': domain, @@ -59,8 +60,7 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm': self.rule_confirm, 'rule_details': self.rule_details, 'rule_mitigation': self.rule_mitigation - } - rds.store_vuln(js_data) + }) return return diff --git a/rules/bruteforce/rule_redis-bf.py b/rules/bruteforce/rule_redis-bf.py index 80932dc..76f5371 100644 --- a/rules/bruteforce/rule_redis-bf.py +++ b/rules/bruteforce/rule_redis-bf.py @@ -9,11 +9,12 @@ class Rule: def __init__(self): self.rule = 'BRF_DD00' self.rule_severity = 4 - self.rule_description = 'Checks if Redis is configured with weak credentials' + self.rule_description = 'This rule checks if Redis is configured to accept remote connections using weak credentials' self.rule_confirm = 'Remote Server with weak Redis credentials' self.rule_details = '' self.rule_mitigation = '''Redis Server Allows connections with a weak password. -Redis must not be listening on an external interface, and if required, it must allow only specific source IP addresses, in addition to a strong password authentication.''' +Redis must not be listening on an external interface, and if required, it must allow only specific source IP addresses, in addition to a strong password authentication. +Refer to the Redis Hardening Guidelines for more information: https://redis.io/topics/security''' self.intensity = 3 def redis_attack(self, ip, port, password): @@ -58,7 +59,7 @@ def check_rule(self, ip, port, values, conf): for password in passwords: if self.redis_attack(ip, port, password): self.rule_details = 'Redis Credentials are set to: {}'.format(password) - js_data = { + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -68,8 +69,7 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) return except: return diff --git a/rules/bruteforce/rule_ssh-bf.py b/rules/bruteforce/rule_ssh-bf.py index ad44dd0..869307f 100644 --- a/rules/bruteforce/rule_ssh-bf.py +++ b/rules/bruteforce/rule_ssh-bf.py @@ -12,12 +12,13 @@ class Rule: def __init__(self): self.rule = 'BRF_A953' self.rule_severity = 4 - self.rule_description = 'Checks if SSH is set with a weak password' + self.rule_description = 'This rule checks if an SSH Server is configured to accept remote connections using weak credentials' self.rule_confirm = 'Remote server with weak credentials' self.rule_details = '' self.rule_mitigation = '''SSH Allows connections with a weak password. SSH must allow only trusted sources remote access, such as specific IP addresses, and use stronger authentication such as \ -Public Key Authentication, in addition to a strong password authentication.''' +Public Key Authentication, in addition to a strong password authentication. +Refer to an OpenSSH Hardening Guidelines for more information: https://linux-audit.com/audit-and-harden-your-ssh-configuration/''' self.intensity = 3 def ssh_attack(self, ip, port, username, password): @@ -57,8 +58,8 @@ def check_rule(self, ip, port, values, conf): for username in usernames: for password in passwords: if self.ssh_attack(ip, port, username, password): - self.rule_details = 'Credentials are set to {}:{}'.format(username, password) - js_data = { + self.rule_details = 'SSH Server Credentials are set to {}:{}'.format(username, password) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -68,7 +69,6 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) return diff --git a/rules/configuration/rule_actuator.py b/rules/configuration/rule_actuator.py index 2566522..30875dc 100644 --- a/rules/configuration/rule_actuator.py +++ b/rules/configuration/rule_actuator.py @@ -1,16 +1,17 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'CFG_9B88' self.rule_severity = 3 - self.rule_description = 'Actuator Misconfiguration' - self.rule_confirm = 'Remote Server Actuator is misconfigured' + self.rule_description = 'This rule checks for misconfigurations in Spring Boot Actuator' + self.rule_confirm = 'Spring Boot Actuator is misconfigured' self.rule_details = '' self.rule_mitigation = '''Server has a misconfigured Actuator, which is potentially leaking out sensitive data. \ -Restrict access to the endpoint to trusted sources only.''' +Restrict access to the endpoint to trusted sources only. +Refer to the following Spring Boot Actuator Hardening Guideline for more information: https://www.devglan.com/spring-security/securing-spring-boot-actuator-endpoints-with-spring-security''' self.rule_match_string = { '/admin/dump':{ 'app':'SPRING_BOOT_ACTUATOR_DUMP', @@ -57,7 +58,6 @@ def __init__(self): def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -68,7 +68,6 @@ def check_rule(self, ip, port, values, conf): return for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -76,9 +75,8 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - - js_data = { + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -88,8 +86,6 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - - rds.store_vuln(js_data) + }) return diff --git a/rules/configuration/rule_apache.py b/rules/configuration/rule_apache.py index c078384..730f227 100644 --- a/rules/configuration/rule_apache.py +++ b/rules/configuration/rule_apache.py @@ -1,16 +1,17 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'CFG_91Z0' self.rule_severity = 1 - self.rule_description = 'Checks for Apache Misconfigurations' - self.rule_confirm = 'Apache Server Misconfiguration' + self.rule_description = 'This rule checks for Apache Web Server Misconfigurations' + self.rule_confirm = 'Misconfigured Apache Server' self.rule_details = '' self.rule_mitigation = '''Apache Web Server is misconfigured and exposes one or more files \ -related to configuration, statistics or example servlets.''' +related to configuration, statistics or example servlets. +Refer to an Apache Hardening Guideline for more information: https://geekflare.com/apache-web-server-hardening-security/''' self.rule_match_string = { '/server-status':{ 'app':'APACHE_SERVER_STATUS', @@ -37,7 +38,6 @@ def __init__(self): def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -55,8 +55,8 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Apache misconfiguration - {} at {}'.format(app_title, uri) - js_data = { + self.rule_details = 'Apache misconfiguration - {} at {}'.format(app_title, resp.url) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -66,6 +66,5 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) return diff --git a/rules/configuration/rule_basic-auth.py b/rules/configuration/rule_basic-auth.py index f50a016..fc310bd 100644 --- a/rules/configuration/rule_basic-auth.py +++ b/rules/configuration/rule_basic-auth.py @@ -1,24 +1,23 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser from db.db_paths import COMMON_LOGIN_PATHS class Rule: def __init__(self): self.rule = 'CFG_D2A9' self.rule_severity = 2 - self.rule_description = 'Checks if Basic Auth is enabled' + self.rule_description = 'This rule checks if a Web Server has Basic Authentication enabled' self.rule_confirm = 'Basic Authentication is Configured' self.rule_details = '' self.rule_mitigation = '''Basic authentication is a simple authentication scheme built into the HTTP protocol. The client sends HTTP requests with the Authorization header that contains the word Basic word followed by a \ space and a base64-encoded string username:password -Change to a stronger password or alternatively use Single Sign On solution, such as Google.''' +Basic Authentication does not have brute force protection mechanisms, and may potentially be a target for attackers''' self.rule_doc_roots = COMMON_LOGIN_PATHS - self.intensity = 1 + self.intensity = 2 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -36,8 +35,8 @@ def check_rule(self, ip, port, values, conf): if 'WWW-Authenticate' in resp.headers: header = resp.headers['WWW-Authenticate'] if header.startswith('Basic'): - self.rule_details = '{} at {}'.format(self.rule_confirm, uri) - js_data = { + self.rule_details = '{} at {}'.format(self.rule_confirm, resp.url) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -47,7 +46,6 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) return diff --git a/rules/configuration/rule_cors-custom-origin.py b/rules/configuration/rule_cors-custom-origin.py index 56575c9..cd976e0 100644 --- a/rules/configuration/rule_cors-custom-origin.py +++ b/rules/configuration/rule_cors-custom-origin.py @@ -3,16 +3,16 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'CFG_DZ19' self.rule_severity = 1 - self.rule_description = 'Checks if CORS Allows Arbitrary Origin Trust' + self.rule_description = 'This rule checks if Cross Origin Resource Sharing policy trusts arbitrary origins' self.rule_confirm = 'CORS Allows Arbitrary Origins' self.rule_details = '' - self.rule_mitigation = '''Consider hardening your CORS Policy to define specific Origins \ + self.rule_mitigation = '''Consider hardening your Cross Origin Resource Sharing Policy to define specific Origins \ https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS''' self.intensity = 1 @@ -21,13 +21,11 @@ def randomize_origin(self): return 'https://{}.com'.format(rand_str) def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) domain = p.get_domain() module = p.get_module() - product = p.get_product() if 'http' not in module: return @@ -44,8 +42,8 @@ def check_rule(self, ip, port, values, conf): return if 'Access-Control-Allow-Origin' in resp.headers and resp.headers['Access-Control-Allow-Origin'] == random_origin: - self.rule_details = 'Header used: "Origin: {}"'.format(random_origin) - js_data = { + self.rule_details = 'Remote Server accepted a custom origin. Header used: "Origin: {}"'.format(random_origin) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -55,7 +53,6 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) return \ No newline at end of file diff --git a/rules/configuration/rule_cors-wildcard.py b/rules/configuration/rule_cors-wildcard.py index 6cb9202..23f9538 100644 --- a/rules/configuration/rule_cors-wildcard.py +++ b/rules/configuration/rule_cors-wildcard.py @@ -1,27 +1,24 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'CFG_DFFF' self.rule_severity = 1 - self.rule_description = 'Checks if CORS Headers support Wildcard Origins' + self.rule_description = 'This rule checks if Cross Origin Resource Sharing Headers support Wildcard Origins' self.rule_confirm = 'Webserver is allowing all domains in CORS' self.rule_details = '' - self.rule_mitigation = '''Consider hardening your CORS Policy to define specific Origins \ -https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS -''' + self.rule_mitigation = '''Consider hardening your Cross Origin Resource Sharing Policy to define specific Origins \ +https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS''' self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) domain = p.get_domain() module = p.get_module() - product = p.get_product() if 'http' not in module: return @@ -38,8 +35,8 @@ def check_rule(self, ip, port, values, conf): for header, value in resp.headers.items(): if header.lower() == 'access-control-allow-origin' and value == '*': - self.rule_details = 'Access-Control-Allow-Origin is set to: *' - js_data = { + self.rule_details = 'Server responded with an HTTP Response Header of Access-Control-Allow-Origin: *' + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -49,8 +46,7 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) return return \ No newline at end of file diff --git a/rules/configuration/rule_default-webpages.py b/rules/configuration/rule_default-webpages.py index 7fb14a5..6cd37e8 100644 --- a/rules/configuration/rule_default-webpages.py +++ b/rules/configuration/rule_default-webpages.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'CFG_E9AF' self.rule_severity = 0 - self.rule_description = 'Checks if a Default Page is Served' + self.rule_description = 'This rule checks if a Default Page is Served by a Web Server' self.rule_confirm = 'Unmaintained Webserver' self.rule_details = '' self.rule_mitigation = '''Server is configured with the default web server page. @@ -86,7 +86,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -102,14 +101,12 @@ def check_rule(self, ip, port, values, conf): return for app, val in self.rule_match_string.items(): - app_name = val['app'] app_title = val['title'] - for match in val['match']: if match in resp.text: - self.rule_details = '{} Indicator: "{}" ({})'.format(app, match, app_title) - js_data = { + self.rule_details = 'Identified a default page: {} Indicator: "{}" ({})'.format(resp.url, match, app_title) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -119,7 +116,6 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) return diff --git a/rules/configuration/rule_laravel.py b/rules/configuration/rule_laravel.py index 8586a5a..0ef76d2 100644 --- a/rules/configuration/rule_laravel.py +++ b/rules/configuration/rule_laravel.py @@ -1,16 +1,15 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'CFG_823E' self.rule_severity = 3 - self.rule_description = 'Laravel Misconfiguration' + self.rule_description = 'This rule checks for misconfigurations in Laravel' self.rule_confirm = 'Remote Server Misconfigured Laravel' self.rule_mitigation = '''Laravel has been misconfigured and may leak environment or log data. \ -Use the laravel guide for hardening best practices: https://laravel.com/docs/7.x/configuration -''' +Use the Laravel Hardening Guidelines for reference: https://laravel.com/docs/7.x/configuration''' self.rule_details = '' self.rule_match_string = { '/storage/logs/laravel.log':{ @@ -29,11 +28,10 @@ def __init__(self): def check_rule(self, ip, port, values, conf): - c = ConfParser t = Triage() p = ScanParser(port, values) - module = p.get_module() + module = p.get_module() domain = p.get_domain() if 'http' not in module: @@ -47,8 +45,8 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Laravel Misconfiguration - {} at {}'.format(app_title, uri) - js_data = { + self.rule_details = 'Laravel Misconfiguration - {} at {}'.format(app_title, resp.url) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -58,6 +56,5 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) return \ No newline at end of file diff --git a/rules/configuration/rule_nginx-status.py b/rules/configuration/rule_nginx-status.py index 6319c4f..c7fd6c6 100644 --- a/rules/configuration/rule_nginx-status.py +++ b/rules/configuration/rule_nginx-status.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'CFG_ECC8' self.rule_severity = 1 - self.rule_description = 'Nginx Misconfiguration' + self.rule_description = 'This rule checks for misconfigurations in Nginx' self.rule_details = '' self.rule_confirm = 'Nginx Server is misconfigured' self.rule_mitigation = '''Nginx is configured with default configurations, which exposes one or more status endpoints. @@ -32,7 +32,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -50,8 +49,8 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Nginx Misconfiguration - {} at {}'.format(app_title, uri) - js_data = { + self.rule_details = 'Nginx Misconfiguration - {} at {}'.format(app_title, resp.url) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -61,8 +60,6 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - - rds.store_vuln(js_data) + }) return \ No newline at end of file diff --git a/rules/configuration/rule_nodejs.py b/rules/configuration/rule_nodejs.py index 2ca790c..beb6cfb 100644 --- a/rules/configuration/rule_nodejs.py +++ b/rules/configuration/rule_nodejs.py @@ -2,13 +2,13 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'CFG_ESTR' self.rule_severity = 4 - self.rule_description = 'Checks for NodeJS Server.js exposures' + self.rule_description = 'Thisr ule checks for NodeJS Server.js file exposures' self.rule_confirm = 'Remote NodeJS Server is leaking server.js' self.rule_details = '' self.rule_mitigation = '''NodeJS has been configured to serve server.js which may allow attackers access to backend code.''' @@ -21,7 +21,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -36,8 +35,8 @@ def check_rule(self, ip, port, values, conf): for i in self.rule_match_string: if i in resp.text: - self.rule_details = 'Identified a NodeJS Leakage Indicator: {}'.format(i) - js_data = { + self.rule_details = 'Identified a NodeJS Leakage at {} Indicator: {}'.format(resp.url, i) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -47,7 +46,5 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - - rds.store_vuln(js_data) + }) return diff --git a/rules/configuration/rule_openapi.py b/rules/configuration/rule_openapi.py index 132e480..1a53725 100644 --- a/rules/configuration/rule_openapi.py +++ b/rules/configuration/rule_openapi.py @@ -1,16 +1,16 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'CFG_ZEGE' self.rule_severity = 2 - self.rule_description = 'Finds Open API Docs' + self.rule_description = 'This rule checks for accessible Open API (Swagger) Documentation' self.rule_confirm = 'Remote Server is exposing Swagger API' self.rule_details = '' - self.rule_mitigation = '''Swagger API may have been incorrectly configured to allow access to untrusted clients Check whether this can be restricted, as it may \ -lead to attackers identifying your application endpoints.''' + self.rule_mitigation = '''Swagger API may have been incorrectly configured to allow access to untrusted clients. \ +Check whether this can be restricted, as it may lead to attackers identifying your application endpoints.''' self.rule_match_string = { '/v2/api-docs':{ 'app':'SWAGGER', @@ -62,7 +62,6 @@ def __init__(self): def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -73,7 +72,6 @@ def check_rule(self, ip, port, values, conf): return for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -81,8 +79,8 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { + self.rule_details = 'Identified an exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -92,6 +90,5 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) return diff --git a/rules/configuration/rule_php-info.py b/rules/configuration/rule_php-info.py index ab62c5e..7b483c1 100644 --- a/rules/configuration/rule_php-info.py +++ b/rules/configuration/rule_php-info.py @@ -1,15 +1,15 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'CFG_BS3R' self.rule_severity = 2 - self.rule_description = 'PHP Misconfiguration' - self.rule_confirm = 'PHP is leaking information' + self.rule_description = 'This rule checks for misconfigurations in PHP' + self.rule_confirm = 'PHP Information Leakage' self.rule_details = '' - self.rule_mitigation = '''Server's PHP is leaking out environment information, which may under \ + self.rule_mitigation = '''The Remote Server's PHP is leaking out environment information, which may under \ certain situations reveal sensitive data such as environment variables, modules installed, etc. Disable PHP info by either adding `disable_functions = phpinfo` @@ -69,7 +69,6 @@ def __init__(self): def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -87,8 +86,8 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'PHP Misconfiguration - {} at {}'.format(app_title, uri) - js_data = { + self.rule_details = 'PHP Misconfiguration - {} at {}'.format(app_title, resp.url) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -98,7 +97,5 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - - rds.store_vuln(js_data) + }) return \ No newline at end of file diff --git a/rules/configuration/rule_powered-by.py b/rules/configuration/rule_powered-by.py index 816ce59..56e681f 100644 --- a/rules/configuration/rule_powered-by.py +++ b/rules/configuration/rule_powered-by.py @@ -1,28 +1,25 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'CFG_BZLS' self.rule_severity = 0 - self.rule_description = 'Checks if Banner Reveals Platform Version' + self.rule_description = 'This rule checks if the Server\'s Response Headers Reveals Platform Version' self.rule_confirm = 'Identified Powered By Headers' self.rule_details = '' - self.rule_mitigation = '''Disable Version Advertisement in the Web Server Configuration. \n -in IIS: https://stackoverflow.com/questions/3374831/in-iis-can-i-safely-remove-the-x-powered-by-asp-net-header \n -in ASP.NET: https://doc.sitecore.com/developers/90/platform-administration-and-architecture/en/remove-header-information-from-responses-sent-by-your-website.html -''' + self.rule_mitigation = '''Disable Version Advertisement in the Web Server Configuration. +in IIS: https://stackoverflow.com/questions/3374831/in-iis-can-i-safely-remove-the-x-powered-by-asp-net-header +in ASP.NET: https://doc.sitecore.com/developers/90/platform-administration-and-architecture/en/remove-header-information-from-responses-sent-by-your-website.html''' self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) domain = p.get_domain() module = p.get_module() - product = p.get_product() if 'http' not in module: return @@ -36,8 +33,8 @@ def check_rule(self, ip, port, values, conf): for poweredby_header in powered_by_headers: result = t.string_in_headers(resp, poweredby_header) if result: - self.rule_details = '{}:{}'.format(poweredby_header, resp.headers.get(poweredby_header, None)) - js_data = { + self.rule_details = 'Server is set with "{}" Headers'.format(poweredby_header) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -47,7 +44,6 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) return \ No newline at end of file diff --git a/rules/configuration/rule_ssh-auth-check.py b/rules/configuration/rule_ssh-auth-check.py index 8feb0cf..503308d 100644 --- a/rules/configuration/rule_ssh-auth-check.py +++ b/rules/configuration/rule_ssh-auth-check.py @@ -1,21 +1,20 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser from db.db_ports import ssh_ports class Rule: def __init__(self): self.rule = 'CFG_FOQW' self.rule_severity = 3 - self.rule_description = 'Checks if SSH password authentication is supported' + self.rule_description = 'This rule checks if OpenSSH allows passwords as an accepted authentication mechanism' self.rule_confirm = 'Remote Server Supports SSH Passwords' self.rule_details = '' - self.rule_mitigation = '''SSH Allows Password authentication, this is considered bad security practice. + self.rule_mitigation = '''OpenSSH allows password authentication, this is considered bad security practice. SSH Key based authentication should be enabled on the server, and passwords should be disabled.''' self.intensity = 0 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -24,9 +23,8 @@ def check_rule(self, ip, port, values, conf): if port in ssh_ports and t.is_ssh(ip, port): output = t.run_cmd('ssh -o PreferredAuthentications=none -o ConnectTimeout=5 -o StrictHostKeyChecking=no -o NoHostAuthenticationForLocalhost=yes user@"{}" -p "{}"'.format(ip, port)) if output and 'password' in str(output): - self.rule_details = p.get_product() - - js_data = { + self.rule_details = 'Server accepts passwords as an authentication option' + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -36,8 +34,6 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - - rds.store_vuln(js_data) + }) return diff --git a/rules/configuration/rule_wordpress.py b/rules/configuration/rule_wordpress.py index 12e225d..a8cf0e8 100644 --- a/rules/configuration/rule_wordpress.py +++ b/rules/configuration/rule_wordpress.py @@ -1,16 +1,16 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'CFG_8BA9' self.rule_severity = 3 - self.rule_description = 'Wordpress Misconfiguration' + self.rule_description = 'This rule checks for misconfigurations in the blog platform Wordpress.' self.rule_confirm = 'Remote Server Wordpress is Misconfigured' self.rule_details = '' - self.rule_mitigation = '''Wordpress may have been misconfigured and may had leaked application data. -Remove any unnecessary files from the webserver which could potentially leak environment details of your wordpress instance''' + self.rule_mitigation = '''Wordpress may have been misconfigured and potentially leaks application data. +Remove any unnecessary files from the webserver which could potentially leak environment details of your Wordpress instance''' self.rule_match_string = { '/wp-config.old':{ 'app':'WORDPRESS', @@ -51,7 +51,6 @@ def __init__(self): self.intensity = 2 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -68,9 +67,8 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Wordpress Misconfiguration - {} at {}'.format(app_title, uri) - - js_data = { + self.rule_details = 'Wordpress Misconfiguration - {} at {}'.format(app_title, resp.url) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -80,6 +78,5 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) return \ No newline at end of file diff --git a/rules/configuration/rule_wp-xmlrpc.py b/rules/configuration/rule_wp-xmlrpc.py index d4455b7..1829756 100644 --- a/rules/configuration/rule_wp-xmlrpc.py +++ b/rules/configuration/rule_wp-xmlrpc.py @@ -1,20 +1,21 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'CFG_B3AB' self.rule_severity = 1 - self.rule_description = 'Wordpress XML-RPC' + self.rule_description = 'This rule checks for XML-RPC Enabled interfaces in Wordpress' self.rule_confirm = 'Remote Server supports XML-RPC' - self.rule_mitigation = '''Wordpress is configured with XML-RPC. XML-RPC can be used to cause Denial of Service and User Enumeration on a wordpress server.''' + self.rule_mitigation = '''Wordpress is configured with XML-RPC. XML-RPC can be used to cause Denial of Service and User Enumeration on a Wordpress server. +It is recommended to disable this interface if it is not utilized. +Refer to the following article for more information on XML RPC Attacks: https://kinsta.com/blog/xmlrpc-php/''' self.rule_details = '' self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser t = Triage() p = ScanParser(port, values) @@ -26,8 +27,8 @@ def check_rule(self, ip, port, values, conf): resp = t.http_request(ip, port, uri='/xmlrpc.php') if resp is not None and resp.status_code == 405: - self.rule_details = 'GET /xmlrpc.php responded with code:405' - js_data = { + self.rule_details = 'Server responded to a GET request at /xmlrpc.php with status code: 405' + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -37,7 +38,6 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) return \ No newline at end of file diff --git a/rules/cves/rule_f5-cve-2020-5902.py b/rules/cves/rule_f5-cve-2020-5902.py index 3bb47b8..d163e12 100644 --- a/rules/cves/rule_f5-cve-2020-5902.py +++ b/rules/cves/rule_f5-cve-2020-5902.py @@ -1,26 +1,23 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'CVE_72D3' self.rule_severity = 4 - self.rule_description = 'Checks for F5 BIG IP Vulnerability (CVE-2020-5902)' + self.rule_description = 'This rule checks for F5 BIG IP Vulnerability (CVE-2020-5902)' self.rule_confirm = 'F5 Networks BIG IP Vulnerability' self.rule_details = '' - self.rule_mitigation = ''' -Patch F5 BIGIP to the latest version available. -''' + self.rule_mitigation = '''Patch F5 BIGIP to the latest version available +Refer to the following AskF5 Article for more information on mitigation: https://support.f5.com/csp/article/K52145254.''' self.intensity = 1 def check_rule(self, ip, port, values, conf): t = Triage() - c = ConfParser(conf) p = ScanParser(port, values) domain = p.get_domain() - module = p.get_module() product = p.get_product() if not 'F5 BIG-IP' in product or not 'BigIP' in product: @@ -32,19 +29,17 @@ def check_rule(self, ip, port, values, conf): return if 'root:x:0:0' in resp.text: - self.rule_details = 'F5 BIGIP Vulnerability - CVE-2020-5902' - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - - rds.store_vuln(js_data) + self.rule_details = 'F5 BIGIP Vulnerability - CVE-2020-5902 at {}'.format(resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) return diff --git a/rules/cves/rule_fortinet-cve-2018-13379.py b/rules/cves/rule_fortinet-cve-2018-13379.py index bdfeae4..2ca251e 100644 --- a/rules/cves/rule_fortinet-cve-2018-13379.py +++ b/rules/cves/rule_fortinet-cve-2018-13379.py @@ -1,27 +1,23 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'CVE_72D3' self.rule_severity = 4 - self.rule_description = 'Checks for Fortinet SSL VPN Vulnerability (CVE-2018-13379)' + self.rule_description = 'This rule checks for Fortinet SSL VPN Vulnerability (CVE-2018-13379)' self.rule_confirm = 'Fortigate SSL VPN Vulnerability' self.rule_details = '' - self.rule_mitigation = ''' -Patch Fortinet Firewall to the latest version -''' + self.rule_mitigation = '''Patch Fortinet Firewall to the latest version. +Refer to the Fortiguard Labs article for more information: https://www.fortiguard.com/psirt/FG-IR-18-384''' self.intensity = 1 def check_rule(self, ip, port, values, conf): t = Triage() - c = ConfParser(conf) p = ScanParser(port, values) domain = p.get_domain() - module = p.get_module() - product = p.get_product() if port != 10043: return @@ -32,19 +28,17 @@ def check_rule(self, ip, port, values, conf): return if 'var fgt_lang =' in resp.text: - self.rule_details = 'Fortinet SSL VPN ({})'.format(port) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - - rds.store_vuln(js_data) + self.rule_details = 'Fortinet SSL VPN CVE-2018-13379 Vulnerability at {}'.format(resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) return diff --git a/rules/cves/rule_nginx-cve-2017-7529.py b/rules/cves/rule_nginx-cve-2017-7529.py index 241ab1c..ff6bd9e 100644 --- a/rules/cves/rule_nginx-cve-2017-7529.py +++ b/rules/cves/rule_nginx-cve-2017-7529.py @@ -1,27 +1,24 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'CVE_C2CF' self.rule_severity = 2 - self.rule_description = 'Checks for Nginx Vulnerability (CVE-2017-7529)' + self.rule_description = 'This rule checks for Nginx Vulnerability (CVE-2017-7529)' self.rule_confirm = 'Nginx Integer Overflow Vulnerability' self.rule_details = '' - self.rule_mitigation = ''' -Patch Nginx to the latest version. -''' + self.rule_mitigation = '''Patch Nginx to the latest version. +Refer to the following CVE advisory for more information: https://nvd.nist.gov/vuln/detail/CVE-2017-7529''' self.intensity = 1 def check_rule(self, ip, port, values, conf): t = Triage() - c = ConfParser(conf) p = ScanParser(port, values) domain = p.get_domain() module = p.get_module() - product = p.get_product() if 'http' not in module: return @@ -45,18 +42,16 @@ def check_rule(self, ip, port, values, conf): return if resp.status_code == 206 and 'Content-Range' in resp.text: - self.rule_details = 'Nginx Integer Overflow' - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - - rds.store_vuln(js_data) + self.rule_details = 'Identified Nginx Integer Overflow (CVE-2017-7529) via Content-Range headers' + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) return \ No newline at end of file diff --git a/rules/discovery/rule_adminer.py b/rules/discovery/rule_adminer.py index 377af09..36008d8 100644 --- a/rules/discovery/rule_adminer.py +++ b/rules/discovery/rule_adminer.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_GEAZ' self.rule_severity = 1 - self.rule_description = 'Checks for Adminer Panel' + self.rule_description = 'This rule checks for the exposure of Adminer Panel' self.rule_confirm = 'Identified an Adminer Panel' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed the network.''' @@ -20,7 +20,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -29,7 +28,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -37,19 +35,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_artifactory.py b/rules/discovery/rule_artifactory.py index 091d6a7..75c1e67 100644 --- a/rules/discovery/rule_artifactory.py +++ b/rules/discovery/rule_artifactory.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_SSB9' self.rule_severity = 2 - self.rule_description = 'Checks for Artifactory Panels' + self.rule_description = 'This rule checks for the exposure of Artifactory Panels' self.rule_confirm = 'Identified an Artifactory Panel' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -25,7 +25,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -34,7 +33,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -42,8 +40,8 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -53,8 +51,7 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) break return diff --git a/rules/discovery/rule_aspconfig.py b/rules/discovery/rule_aspconfig.py index e618558..d18d637 100644 --- a/rules/discovery/rule_aspconfig.py +++ b/rules/discovery/rule_aspconfig.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_GEG2' self.rule_severity = 2 - self.rule_description = 'Checks for ASP.NET Configs' + self.rule_description = 'This rule checks for the exposure of ASP.NET configurations' self.rule_confirm = 'Identified an ASP.NET Config' self.rule_details = '' self.rule_mitigation = '''Identify whether the configuration file is supposed to be exposed to the network.''' @@ -20,7 +20,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -29,7 +28,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -37,19 +35,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_cisco-asa.py b/rules/discovery/rule_cisco-asa.py index 2ec68c1..d03b508 100644 --- a/rules/discovery/rule_cisco-asa.py +++ b/rules/discovery/rule_cisco-asa.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_FFEE' self.rule_severity = 1 - self.rule_description = 'Checks for Cisco ASA Panels' + self.rule_description = 'This rule checks for the exposure of Cisco ASA Panels' self.rule_confirm = 'Identified a Cisco ASA Panel' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -20,7 +20,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -29,7 +28,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -37,19 +35,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_clockwork.py b/rules/discovery/rule_clockwork.py index 6ead9cf..c4c6a06 100644 --- a/rules/discovery/rule_clockwork.py +++ b/rules/discovery/rule_clockwork.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_38A9' self.rule_severity = 1 - self.rule_description = 'Checks for Clockwork Panel' + self.rule_description = 'This rule checks for the exposure of Clockwork Panels' self.rule_confirm = 'Identified a Clockwork Panel' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -20,7 +20,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -29,7 +28,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -37,19 +35,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_composer.py b/rules/discovery/rule_composer.py index 155720b..af1bc0b 100644 --- a/rules/discovery/rule_composer.py +++ b/rules/discovery/rule_composer.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_38A9' self.rule_severity = 2 - self.rule_description = 'Checks for Composer JSON' + self.rule_description = 'This rule checks for the exposure of Composer JSON' self.rule_confirm = 'Identified a Composer JSON' self.rule_details = '' self.rule_mitigation = '''Identify whether the file in question is supposed to be exposed to the network.''' @@ -20,7 +20,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -29,7 +28,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -37,19 +35,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_consul.py b/rules/discovery/rule_consul.py index c70df4c..fc745db 100644 --- a/rules/discovery/rule_consul.py +++ b/rules/discovery/rule_consul.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_2435' self.rule_severity = 1 - self.rule_description = 'Checks for Hashicorp Consul Panels' + self.rule_description = 'This rule checks for the exposure of Hashicorp Consul Panels' self.rule_confirm = 'Identified a Hashicorp Consul Panel' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -20,7 +20,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -29,7 +28,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -37,19 +35,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln( { + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_django-rest.py b/rules/discovery/rule_django-rest.py index 98161f1..0876c48 100644 --- a/rules/discovery/rule_django-rest.py +++ b/rules/discovery/rule_django-rest.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_BSZ2' self.rule_severity = 2 - self.rule_description = 'Checks for Django API Endpoints' + self.rule_description = 'This rule checks for the exposure of Django Users API Endpoints' self.rule_confirm = 'Identified a Django API Endpoint' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -20,7 +20,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -29,7 +28,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -37,19 +35,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_docker-registry.py b/rules/discovery/rule_docker-registry.py index 57f53dc..f683538 100644 --- a/rules/discovery/rule_docker-registry.py +++ b/rules/discovery/rule_docker-registry.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_55A9' self.rule_severity = 3 - self.rule_description = 'Checks for Docker Registry Endpoints' + self.rule_description = 'This rule checks for the exposure of Docker Registry Endpoints' self.rule_confirm = 'Identified a Docker Registry Endpoint' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -20,7 +20,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -29,7 +28,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -37,19 +35,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_elmah.py b/rules/discovery/rule_elmah.py index e1a94c6..5e39db9 100644 --- a/rules/discovery/rule_elmah.py +++ b/rules/discovery/rule_elmah.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_3E39' self.rule_severity = 1 - self.rule_description = 'Checks for Elmah Panel' + self.rule_description = 'This rule checks for the exposure of Elmah Panels' self.rule_confirm = 'Identified an Elmah Panel' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -20,7 +20,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -29,7 +28,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -37,8 +35,8 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -48,8 +46,7 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) break return diff --git a/rules/discovery/rule_flask-console.py b/rules/discovery/rule_flask-console.py index 009d447..cecdd28 100644 --- a/rules/discovery/rule_flask-console.py +++ b/rules/discovery/rule_flask-console.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_38A9' self.rule_severity = 1 - self.rule_description = 'Checks for Flask Consoles' + self.rule_description = 'This rule checks for the exposure of Flask Consoles' self.rule_confirm = 'Identified a Flask Console' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -20,7 +20,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -29,7 +28,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -37,8 +35,8 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -48,8 +46,7 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) break return diff --git a/rules/discovery/rule_flyway.py b/rules/discovery/rule_flyway.py index 5c41dec..0b177ed 100644 --- a/rules/discovery/rule_flyway.py +++ b/rules/discovery/rule_flyway.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_3GGB' self.rule_severity = 1 - self.rule_description = 'Checks for Flyway App' + self.rule_description = 'This rule checks for the exposure of Flyway' self.rule_confirm = 'Identified a Flyway App' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -20,7 +20,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -29,16 +28,15 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] - + resp = t.http_request(ip, port, uri=uri) if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -48,8 +46,7 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) break return diff --git a/rules/discovery/rule_gitlab.py b/rules/discovery/rule_gitlab.py index 43d315a..1e07653 100644 --- a/rules/discovery/rule_gitlab.py +++ b/rules/discovery/rule_gitlab.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_OR39' self.rule_severity = 1 - self.rule_description = 'Checks for GitLab Panels' + self.rule_description = 'This rule checks for the exposure of GitLab Panels' self.rule_confirm = 'Identified a GitLab Panel' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -30,7 +30,6 @@ def __init__(self): self.intensity = 2 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -39,7 +38,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -47,19 +45,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_globalprotect.py b/rules/discovery/rule_globalprotect.py index 2d602bc..88470ce 100644 --- a/rules/discovery/rule_globalprotect.py +++ b/rules/discovery/rule_globalprotect.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_100F' self.rule_severity = 1 - self.rule_description = 'Checks for Global Protect Panels' + self.rule_description = 'This rule checks for the exposure of Palo Alto Global Protect Panels' self.rule_confirm = 'Identified a Global Protect Panel' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -25,7 +25,6 @@ def __init__(self): self.intensity = 2 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -34,7 +33,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -42,19 +40,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_hadoop.py b/rules/discovery/rule_hadoop.py index e8fc620..50b00f0 100644 --- a/rules/discovery/rule_hadoop.py +++ b/rules/discovery/rule_hadoop.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_3561' self.rule_severity = 1 - self.rule_description = 'Checks for Hadoop RM Panels' + self.rule_description = 'This rule checks for the exposure of Hadoop Resource Manager Panels' self.rule_confirm = 'Identified a Hadoop RM Panel' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -20,7 +20,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -29,7 +28,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -37,19 +35,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_jenkins.py b/rules/discovery/rule_jenkins.py index 43d78e8..c540dd7 100644 --- a/rules/discovery/rule_jenkins.py +++ b/rules/discovery/rule_jenkins.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_TGGS' self.rule_severity = 1 - self.rule_description = 'Checks for Jenkins' + self.rule_description = 'This rule checks for the exposure of Jenkins' self.rule_confirm = 'Identified a Jenkins Instance' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -20,7 +20,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -29,7 +28,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -37,19 +35,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_jmx-console.py b/rules/discovery/rule_jmx-console.py index c61067b..674ed62 100644 --- a/rules/discovery/rule_jmx-console.py +++ b/rules/discovery/rule_jmx-console.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_11A9' self.rule_severity = 1 - self.rule_description = 'Checks for JMX Consoles' + self.rule_description = 'This rule checks for the exposure of JMX Consoles' self.rule_confirm = 'Identified a JMX Console' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -20,7 +20,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -29,7 +28,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -37,19 +35,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_jolokia.py b/rules/discovery/rule_jolokia.py index 07d9209..a002392 100644 --- a/rules/discovery/rule_jolokia.py +++ b/rules/discovery/rule_jolokia.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_3TE9' self.rule_severity = 1 - self.rule_description = 'Checks for Jolokia Panels' + self.rule_description = 'This rule checks for the exposure of Jolokia Panels' self.rule_confirm = 'Identified a Jolokia Panel' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -26,7 +26,6 @@ def __init__(self): self.intensity = 2 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -35,27 +34,25 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] - - resp = t.http_request(ip, port, uri=uri) + resp = t.http_request(ip, port, uri=uri) + if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_known-platforms-body.py b/rules/discovery/rule_known-platforms-body.py index 881c9eb..a455c85 100644 --- a/rules/discovery/rule_known-platforms-body.py +++ b/rules/discovery/rule_known-platforms-body.py @@ -1,19 +1,19 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser from db.db_paths import COMMON_LOGIN_PATHS class Rule: def __init__(self): self.rule = 'DSC_A4F1' self.rule_severity = 1 - self.rule_description = 'Checks if a Web Panel is exposed' + self.rule_description = 'This rule checks for the exposure of Web Panels' self.rule_confirm = 'Identified a Known Web Panel' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' self.rule_doc_roots = COMMON_LOGIN_PATHS self.rule_match_string = { - 'Generic':{ + 'Generic Panel':{ 'app':'GENERIC', 'match':['Sign In', 'Login', 'Forgot Password', 'Authenticate', 'input type="password"'], 'title':'Login Page' @@ -234,7 +234,7 @@ def __init__(self): 'title':'Adobe AEM' }, 'Github':{ - 'app':'Github', + 'app':'GITHUB', 'match':['GitHub · Enterprise'], 'title':'GitHub Enterprise' } @@ -243,7 +243,6 @@ def __init__(self): self.intensity = 3 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -256,15 +255,13 @@ def check_rule(self, ip, port, values, conf): for uri in self.rule_doc_roots: resp = t.http_request(ip, port, uri=uri) - for app, val in self.rule_match_string.items(): - app_name = val['app'] + for _, val in self.rule_match_string.items(): app_title = val['title'] - if resp: for i in val['match']: if i in resp.text: - self.rule_details = '{} - ({})'.format(app, app_title) - js_data = { + self.rule_details = '{} Exposed at {}'.format(app_title, resp.url) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -274,8 +271,7 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) break return diff --git a/rules/discovery/rule_known-platforms-headers.py b/rules/discovery/rule_known-platforms-headers.py index 3057b29..8f2752e 100644 --- a/rules/discovery/rule_known-platforms-headers.py +++ b/rules/discovery/rule_known-platforms-headers.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_FB18' self.rule_severity = 1 - self.rule_description = 'Checks if a Known Platform is exposed' + self.rule_description = 'This rule checks for the exposure of Known Platform based on response header signatures' self.rule_confirm = 'Identified a Known Platform via its Headers' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -130,7 +130,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) p = ScanParser(port, values) t = Triage() @@ -142,24 +141,23 @@ def check_rule(self, ip, port, values, conf): resp = t.http_request(ip, port) - for app, val in self.rule_match_string.items(): - app_name = val['app'] + for _, val in self.rule_match_string.items(): app_title = val['title'] for match in val['match']: if resp and t.string_in_headers(resp, match): - self.rule_details = '{} ({})'.format(app, app_title) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) + break return diff --git a/rules/discovery/rule_liferay.py b/rules/discovery/rule_liferay.py index 36cce4c..82b14ff 100644 --- a/rules/discovery/rule_liferay.py +++ b/rules/discovery/rule_liferay.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_GQW9' self.rule_severity = 1 - self.rule_description = 'Checks for LifeRay Panels' + self.rule_description = 'This rule checks for the exposure of LifeRay Panels' self.rule_confirm = 'Identified a LifeRay Panel' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -20,7 +20,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -29,7 +28,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -37,19 +35,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_moadmin.py b/rules/discovery/rule_moadmin.py index 1d29cc2..d293cae 100644 --- a/rules/discovery/rule_moadmin.py +++ b/rules/discovery/rule_moadmin.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_3TGT' self.rule_severity = 1 - self.rule_description = 'Checks for MongoAdmin Panel' + self.rule_description = 'This rule checks for the exposure of MongoAdmin Panel' self.rule_confirm = 'Identified a MongoAdmin Web Panel' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -25,7 +25,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -34,7 +33,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -42,8 +40,8 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -53,8 +51,7 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) break return diff --git a/rules/discovery/rule_phpmyadmin.py b/rules/discovery/rule_phpmyadmin.py index 2b55413..77aaf15 100644 --- a/rules/discovery/rule_phpmyadmin.py +++ b/rules/discovery/rule_phpmyadmin.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_3GG3' self.rule_severity = 1 - self.rule_description = 'Checks for PHPMyAdmin Panels' + self.rule_description = 'This rule checks for the exposure of PHPMyAdmin Panels' self.rule_confirm = 'Identified a PHPMyAdmin Web Panel' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -25,7 +25,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -34,7 +33,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -42,19 +40,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_pprof.py b/rules/discovery/rule_pprof.py index f1cf65b..c63b7de 100644 --- a/rules/discovery/rule_pprof.py +++ b/rules/discovery/rule_pprof.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_EEF1' self.rule_severity = 1 - self.rule_description = 'Checks for PProf' + self.rule_description = 'This rule checks for the exposure of PProf' self.rule_confirm = 'Identified PProf' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -20,7 +20,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -29,7 +28,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -37,19 +35,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_prometheus.py b/rules/discovery/rule_prometheus.py index a6e462d..78cc129 100644 --- a/rules/discovery/rule_prometheus.py +++ b/rules/discovery/rule_prometheus.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_FOR3' self.rule_severity = 1 - self.rule_description = 'Checks for Prometheus Panels' + self.rule_description = 'This rule checks for the exposure of Prometheus Panels' self.rule_confirm = 'Identified a Prometheus Panel' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -25,7 +25,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -34,7 +33,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -42,19 +40,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_redash.py b/rules/discovery/rule_redash.py index b03217c..2fab1da 100644 --- a/rules/discovery/rule_redash.py +++ b/rules/discovery/rule_redash.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_KKW9' self.rule_severity = 1 - self.rule_description = 'Checks for Redash Panels' + self.rule_description = 'This rule checks for the exposure of Redash Panels' self.rule_confirm = 'Identified a Redash Panel' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -20,7 +20,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -29,7 +28,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -37,19 +35,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_selenium-grid.py b/rules/discovery/rule_selenium-grid.py index 6e7b6bb..ba21045 100644 --- a/rules/discovery/rule_selenium-grid.py +++ b/rules/discovery/rule_selenium-grid.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_TOOA' self.rule_severity = 1 - self.rule_description = 'Checks for Selenium Grid' + self.rule_description = 'This rule checks for the exposure of Selenium Grid Panels' self.rule_confirm = 'Identified a Selenium Grid Instance' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -20,7 +20,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -29,7 +28,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -37,19 +35,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_snoopjsp.py b/rules/discovery/rule_snoopjsp.py index bd8df2b..03c3466 100644 --- a/rules/discovery/rule_snoopjsp.py +++ b/rules/discovery/rule_snoopjsp.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_0119' self.rule_severity = 1 - self.rule_description = 'Checks for Snoop JSP' + self.rule_description = 'This rule checks for the exposure of Snoop JSP' self.rule_confirm = 'Identified a Snoop JSP' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -20,7 +20,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -29,7 +28,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -37,19 +35,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_solr.py b/rules/discovery/rule_solr.py index d096b0a..49f6a16 100644 --- a/rules/discovery/rule_solr.py +++ b/rules/discovery/rule_solr.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_2200' self.rule_severity = 1 - self.rule_description = 'Checks for Apache Solr Panels' + self.rule_description = 'This rule checks for the exposure of Apache Solr Panels' self.rule_confirm = 'Identified an Apache Solr Panel' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -20,7 +20,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -29,7 +28,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -37,19 +35,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_struts-console.py b/rules/discovery/rule_struts-console.py index e919403..0f9ba95 100644 --- a/rules/discovery/rule_struts-console.py +++ b/rules/discovery/rule_struts-console.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_BFL9' self.rule_severity = 1 - self.rule_description = 'Checks for Struts Consoles' + self.rule_description = 'This rule checks for the exposure of Struts Consoles' self.rule_confirm = 'Identified a Struts Console' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -20,7 +20,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -29,7 +28,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -37,19 +35,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_webmin.py b/rules/discovery/rule_webmin.py index affe356..d194be7 100644 --- a/rules/discovery/rule_webmin.py +++ b/rules/discovery/rule_webmin.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_OWA9' self.rule_severity = 1 - self.rule_description = 'Checks for Webmin Panels' + self.rule_description = 'This rule checks for the exposure of Webmin Panels' self.rule_confirm = 'Identified a Webmin Panel' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -20,7 +20,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -29,7 +28,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -37,19 +35,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/discovery/rule_zabbix.py b/rules/discovery/rule_zabbix.py index 16e8ed4..df61894 100644 --- a/rules/discovery/rule_zabbix.py +++ b/rules/discovery/rule_zabbix.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'DSC_3GGB' self.rule_severity = 1 - self.rule_description = 'Checks for Zabbix' + self.rule_description = 'This rule checks for the exposure of Zabbix Monitoring Panel' self.rule_confirm = 'Identified a Zabbix Instance' self.rule_details = '' self.rule_mitigation = '''Identify whether the application in question is supposed to be exposed to the network.''' @@ -20,7 +20,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -29,7 +28,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -37,19 +35,18 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) break return diff --git a/rules/services/rule_admin-ports.py b/rules/services/rule_admin-ports.py index b6c6604..3556e72 100644 --- a/rules/services/rule_admin-ports.py +++ b/rules/services/rule_admin-ports.py @@ -1,41 +1,34 @@ from core.redis import rds -from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser from db.db_ports import admin_ports class Rule: def __init__(self): self.rule = 'SVC_6509' self.rule_severity = 3 - self.rule_description = 'Checks for Remote Management Ports' + self.rule_description = 'This rule checks for open Remote Management Ports' self.rule_mitigation = '''Bind all possible services to localhost, and confirm only those which require remote clients are allowed remotely.''' self.rule_confirm = 'Remote Server Exposes Administration Port(s)' self.rule_details = '' self.intensity = 0 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) - t = Triage() p = ScanParser(port, values) domain = p.get_domain() if port in admin_ports: - - self.rule_details = 'Open Port: {} ({})'.format(port, admin_ports[port]) - - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - - rds.store_vuln(js_data) - + self.rule_details = 'Server is listening on remote port: {} ({})'.format(port, admin_ports[port]) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) + return diff --git a/rules/services/rule_db-ports.py b/rules/services/rule_db-ports.py index e3e02e3..f5abb64 100644 --- a/rules/services/rule_db-ports.py +++ b/rules/services/rule_db-ports.py @@ -1,13 +1,12 @@ from core.redis import rds -from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser from db.db_ports import database_ports class Rule: def __init__(self): self.rule = 'SVC_0C15' self.rule_severity = 3 - self.rule_description = 'Checks for Database Ports' + self.rule_description = 'This rule checks for open Database Ports' self.rule_confirm = 'Remote Server Exposes Database Port(s)' self.rule_details = '' self.rule_mitigation = '''Bind all possible database interfaces to localhost. @@ -15,18 +14,14 @@ def __init__(self): self.intensity = 0 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) - t = Triage() p = ScanParser(port, values) domain = p.get_domain() - for db_port, service in database_ports.items(): + for db_port, _ in database_ports.items(): if port == db_port: - - self.rule_details = 'Open Port: {} ({})'.format(port, database_ports[port]) - - js_data = { + self.rule_details = 'Server is listening on remote port: {} ({})'.format(port, database_ports[port]) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -36,9 +31,7 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - - rds.store_vuln(js_data) + }) return diff --git a/rules/services/rule_ftp-ports.py b/rules/services/rule_ftp-ports.py index 20ab507..4addb16 100644 --- a/rules/services/rule_ftp-ports.py +++ b/rules/services/rule_ftp-ports.py @@ -1,13 +1,12 @@ from core.redis import rds -from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser from db.db_ports import ftp_ports class Rule: def __init__(self): self.rule = 'SVC_C74A' self.rule_severity = 3 - self.rule_description = 'Checks for FTP Ports' + self.rule_description = 'This rule checks for open FTP Ports' self.rule_confirm = 'Remote Server Exposes FTP Port(s)' self.rule_details = '' self.rule_mitigation = '''Ensure at the bare minimum FTP is over SSL, and only allow trusted clients to connect to it over the network.''' @@ -15,28 +14,23 @@ def __init__(self): self.intensity = 0 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) - t = Triage() p = ScanParser(port, values) domain = p.get_domain() if port in ftp_ports: - self.rule_details = 'Open Port: {} ({})'.format(port, ftp_ports[port]) - - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - - rds.store_vuln(js_data) + self.rule_details = 'Server is listening on remote port:{} ({})'.format(port, ftp_ports[port]) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) return \ No newline at end of file diff --git a/rules/services/rule_http-ports.py b/rules/services/rule_http-ports.py index 3aa274c..1a05409 100644 --- a/rules/services/rule_http-ports.py +++ b/rules/services/rule_http-ports.py @@ -1,6 +1,6 @@ import time from core.redis import rds -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser from core.triage import Triage from db.db_ports import http_ports, https_ports @@ -8,34 +8,29 @@ class Rule: def __init__(self): self.rule = 'SVC_ZGZA' self.rule_severity = 1 - self.rule_description = 'Checks for HTTP Ports' + self.rule_description = 'This rule checks for open HTTP Ports' self.rule_confirm = 'Remote Server Exposes HTTP Port(s)' self.rule_details = '' self.rule_mitigation = '''Bind all possible network services to localhost, and configure only those which require remote clients on an external interface.''' self.intensity = 0 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) - t = Triage() p = ScanParser(port, values) domain = p.get_domain() if port in http_ports or port in https_ports: - self.rule_details = 'Open Port: {} (HTTP)'.format(port) - - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - - rds.store_vuln(js_data) - + self.rule_details = 'Server is listening on remote port: {} (HTTP)'.format(port) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) + return diff --git a/rules/services/rule_ldap-ports.py b/rules/services/rule_ldap-ports.py index f86821d..a501cb4 100644 --- a/rules/services/rule_ldap-ports.py +++ b/rules/services/rule_ldap-ports.py @@ -1,13 +1,12 @@ from core.redis import rds -from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser from db.db_ports import ldap_ports class Rule: def __init__(self): self.rule = 'SVC_222E' self.rule_severity = 3 - self.rule_description = 'Checks for LDAP Ports' + self.rule_description = 'This rule checks for open LDAP Ports' self.rule_confirm = 'Remote Server Exposes LDAP Port(s)' self.rule_details = '' self.rule_mitigation = '''Bind all possible network services to localhost, and allow those which require remote clients to connect. @@ -15,28 +14,22 @@ def __init__(self): self.intensity = 0 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) - t = Triage() p = ScanParser(port, values) domain = p.get_domain() if port in ldap_ports: + self.rule_details = 'Server is listening on remote port: {} ({})'.format(port, ldap_ports[port]) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) - self.rule_details = 'Open Port: {} ({})'.format(port, ldap_ports[port]) - - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - - rds.store_vuln(js_data) - return diff --git a/rules/services/rule_obfuscated-ssh.py b/rules/services/rule_obfuscated-ssh.py index 0b8f849..94fdc87 100644 --- a/rules/services/rule_obfuscated-ssh.py +++ b/rules/services/rule_obfuscated-ssh.py @@ -1,12 +1,11 @@ from core.redis import rds -from core.triage import Triage -from core.parser import ScanParser, ConfParser -from core.logging import logger +from core.parser import ScanParser + class Rule: def __init__(self): self.rule = 'SVC_21BV' self.rule_severity = 1 - self.rule_description = 'Checks for Obfuscated SSH Ports' + self.rule_description = 'This rule checks for SSH services on obfuscated ports' self.rule_mitigation = '''SSH Running on non-standard ports is easy for attackers to find. While it doesn't do harm changing the standard port from (default) 22, ensure the server only accepts keys, and only allows SSH access from trusted IP sources. ''' @@ -15,8 +14,6 @@ def __init__(self): self.intensity = 0 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) - t = Triage() p = ScanParser(port, values) module = p.get_module() @@ -25,19 +22,17 @@ def check_rule(self, ip, port, values, conf): if 'ssh' in module or 'ssh' in product.lower(): if port != 22: - self.rule_details = 'SSH is hidden behind port {}'.format(port) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - - rds.store_vuln(js_data) - + self.rule_details = 'Server is hiding SSH behind remote port: {}'.format(port) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) + return diff --git a/rules/services/rule_rare-ports.py b/rules/services/rule_rare-ports.py index 10055b1..e134828 100644 --- a/rules/services/rule_rare-ports.py +++ b/rules/services/rule_rare-ports.py @@ -1,21 +1,18 @@ from core.redis import rds -from core.parser import ScanParser, Helper, ConfParser -from core.triage import Triage +from core.parser import ScanParser, Helper from db.db_ports import known_ports class Rule: def __init__(self): self.rule = 'SVC_0C1Z' self.rule_severity = 2 - self.rule_description = 'Checks for Rare Ports' + self.rule_description = 'This rule checks for open Rare Ports' self.rule_confirm = 'Remote Server Exposes Rare Port(s)' self.rule_details = '' self.rule_mitigation = '''Bind all possible network services to localhost, and configure only those which require remote clients on an external interface.''' self.intensity = 0 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) - t = Triage() h = Helper() p = ScanParser(port, values) @@ -28,19 +25,17 @@ def check_rule(self, ip, port, values, conf): known = True if not known: - self.rule_details = 'Open Port: {} ({})'.format(port, h.portTranslate(port)) - - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Server is listening on remote port: {} ({})'.format(port, h.portTranslate(port)) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) return diff --git a/rules/services/rule_smb-ports.py b/rules/services/rule_smb-ports.py index 8a2275d..7f47321 100644 --- a/rules/services/rule_smb-ports.py +++ b/rules/services/rule_smb-ports.py @@ -1,40 +1,34 @@ from core.redis import rds -from core.parser import ScanParser, ConfParser -from core.triage import Triage +from core.parser import ScanParser from db.db_ports import smb_ports class Rule: def __init__(self): self.rule = 'SVC_Z115' self.rule_severity = 3 - self.rule_description = 'Checks for SMB Ports' + self.rule_description = 'This rule checks for open SMB Ports' self.rule_confirm = 'Remote Server Exposes SMB Port(s)' self.rule_details = '' self.rule_mitigation = '''Bind all possible network services to localhost, and configure only those which require remote clients on an external interface.''' self.intensity = 0 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) - t = Triage() p = ScanParser(port, values) domain = p.get_domain() if port in smb_ports: - self.rule_details = 'Open Port: {} ({})'.format(port, smb_ports[port]) - - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - - rds.store_vuln(js_data) - + self.rule_details = 'Server is listening on remote port: {} ({})'.format(port, smb_ports[port]) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) + return diff --git a/rules/services/rule_svc-ports.py b/rules/services/rule_svc-ports.py index 6212a07..528b8e9 100644 --- a/rules/services/rule_svc-ports.py +++ b/rules/services/rule_svc-ports.py @@ -1,40 +1,34 @@ from core.redis import rds -from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser from db.db_ports import svc_ports class Rule: def __init__(self): self.rule = 'SVC_F88A' self.rule_severity = 3 - self.rule_description = 'Checks for Known Service Ports' + self.rule_description = 'This rule checks for open Service Ports' self.rule_confirm = 'Exposed Service Port' self.rule_details = '' self.rule_mitigation = '''Bind all possible network services to localhost, and configure only those which require remote clients on an external interface.''' self.intensity = 0 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) - t = Triage() p = ScanParser(port, values) domain = p.get_domain() - module = p.get_module() if port in svc_ports: - self.rule_details = 'Open Port: {} ({})'.format(port, svc_ports[port]) - - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Server is listening on remote port: {} ({})'.format(port, svc_ports[port]) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) return diff --git a/rules/services/rule_vpn-ports.py b/rules/services/rule_vpn-ports.py index 47f4ecc..3c54e5a 100644 --- a/rules/services/rule_vpn-ports.py +++ b/rules/services/rule_vpn-ports.py @@ -1,13 +1,12 @@ from core.redis import rds -from core.parser import ScanParser, ConfParser -from core.triage import Triage +from core.parser import ScanParser from db.db_ports import vpn_ports class Rule: def __init__(self): self.rule = 'SVC_ZII2' self.rule_severity = 2 - self.rule_description = 'Checks for VPN Ports' + self.rule_description = 'This rule checks for open VPN Ports' self.rule_confirm = 'Exposed VPN Port' self.rule_details = '' self.rule_mitigation = '''Bind all possible network services to localhost, and configure only those which require remote clients on an external interface.''' @@ -15,25 +14,21 @@ def __init__(self): self.intensity = 0 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) - t = Triage() p = ScanParser(port, values) domain = p.get_domain() if port in vpn_ports: - - self.rule_details = 'Open Port: {} ({})'.format(port, vpn_ports[port]) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Server is listening on remote port: {} ({})'.format(port, vpn_ports[port]) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) return diff --git a/rules/vulnerabilities/rule_beanstalk-takeover.py b/rules/vulnerabilities/rule_beanstalk-takeover.py index 6366317..10f3e83 100644 --- a/rules/vulnerabilities/rule_beanstalk-takeover.py +++ b/rules/vulnerabilities/rule_beanstalk-takeover.py @@ -1,22 +1,19 @@ import dns.resolver from core.redis import rds -from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'VLN_ZZ13' self.rule_severity = 3 - self.rule_description = 'Checks for Beanstalk Takeovers' + self.rule_description = 'This rule checks for Beanstalk DNS Takeovers' self.rule_confirm = 'DNS Entry allows takeover of Beanstalk server' self.rule_details = '' self.rule_mitigation = '''Verify the DNS is in use, remove the record if unnecessary.''' self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) - t = Triage() p = ScanParser(port, values) domain = p.get_domain() @@ -31,9 +28,8 @@ def check_rule(self, ip, port, values, conf): try: dns.resolver.query(resolved) except dns.resolver.NXDOMAIN: - info = 'Beanstalk Takeover' - self.rule_details = 'Beanstalk Takeover at {} ({})'.format(domain, resolved) - js_data = { + self.rule_details = 'Beanstalk DNS Takeover at {} ({})'.format(domain, resolved) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -43,8 +39,7 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) return except: continue diff --git a/rules/vulnerabilities/rule_crlf-injection.py b/rules/vulnerabilities/rule_crlf-injection.py index 5682a29..a7ecacc 100644 --- a/rules/vulnerabilities/rule_crlf-injection.py +++ b/rules/vulnerabilities/rule_crlf-injection.py @@ -1,19 +1,19 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'VLN_ZPZB' self.rule_severity = 2 - self.rule_description = 'Checks for CRLF Injection' + self.rule_description = 'This rule checks for Carriage Return Line Feed Injections' self.rule_confirm = 'Remote Server suffers from CRLF Injection / HTTP Response Splitting' self.rule_details = '' - self.rule_mitigation = '''Do not use CRLF characters in URL as HTTP stream''' + self.rule_mitigation = '''Do not use CRLF characters in URL as HTTP stream +Refer to the OWASP CRLF Injection article for more information: https://owasp.org/www-community/vulnerabilities/CRLF_Injection#:~:text=The%20term%20CRLF%20refers%20to,in%20today's%20popular%20Operating%20Systems.''' self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -30,8 +30,8 @@ def check_rule(self, ip, port, values, conf): return if 'set-cookie' in resp.headers and 'inserted_by_nerve' in resp.headers['set-cookie']: - self.rule_details = 'CRLF Injection' - js_data = { + self.rule_details = 'Identified CRLF Injection by inserting a Set-Cookie header' + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -41,7 +41,6 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) return diff --git a/rules/vulnerabilities/rule_cve-check.py b/rules/vulnerabilities/rule_cve-check.py index 00ca62a..268d43a 100644 --- a/rules/vulnerabilities/rule_cve-check.py +++ b/rules/vulnerabilities/rule_cve-check.py @@ -8,12 +8,11 @@ class Rule: def __init__(self): self.rule = 'VLN_2451' self.rule_severity = 3 - self.rule_description = 'Checks for Software Vulnerabilities' + self.rule_description = 'This rule checks for known Software Vulnerabilities' self.rule_confirm = 'Critical Vulnerabilities Found' self.rule_details = '' self.rule_mitigation = '''Server has 1 or more Critical (10.0) CVEs associated with its version. -Update the software to the latest version -''' +Update the software to the latest version''' self.intensity = 0 def check_rule(self, ip, port, values, conf): @@ -36,7 +35,7 @@ def check_rule(self, ip, port, values, conf): if t.has_cves(cpe): self.rule_details = 'List of Vulnerabilities for this version: https://nvd.nist.gov/vuln/search/results?cpe_version={}'.format(cpe) - js_data = { + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -46,7 +45,6 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) return diff --git a/rules/vulnerabilities/rule_dir-index.py b/rules/vulnerabilities/rule_dir-index.py index 0fa7b2e..f8ac5fd 100644 --- a/rules/vulnerabilities/rule_dir-index.py +++ b/rules/vulnerabilities/rule_dir-index.py @@ -1,13 +1,13 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser from db.db_paths import COMMON_WEB_PATHS class Rule: def __init__(self): self.rule = 'VLN_Z013' self.rule_severity = 4 - self.rule_description = 'Checks for Open Directories' + self.rule_description = 'This rule checks for Open Directories via Directory Indexing' self.rule_confirm = 'Remote Server has Directory Indexing Enabled' self.rule_details = '' self.rule_mitigation = '''Disable Directory Indexing on the server. Directory Indexing can allow access to files on the server to untrusted sources.''' @@ -15,7 +15,6 @@ def __init__(self): self.intensity = 3 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -24,6 +23,7 @@ def check_rule(self, ip, port, values, conf): if 'http' not in module: return + resp = None for uri in self.uris: @@ -31,8 +31,8 @@ def check_rule(self, ip, port, values, conf): if resp: for match in ('C=N;O=D', 'Index of /'): if match in resp.text: - self.rule_details = 'Found Open Directory at {}'.format(uri) - js_data = { + self.rule_details = 'Identified an Open Directory at {}'.format(resp.url) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -42,8 +42,7 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) break return diff --git a/rules/vulnerabilities/rule_ds-store.py b/rules/vulnerabilities/rule_ds-store.py index bf14a9a..77f58cd 100644 --- a/rules/vulnerabilities/rule_ds-store.py +++ b/rules/vulnerabilities/rule_ds-store.py @@ -5,14 +5,14 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser from db.db_paths import COMMON_WEB_PATHS class Rule: def __init__(self): self.rule = 'VLN_AS91' self.rule_severity = 1 - self.rule_description = 'Checks for .DS_Store files' + self.rule_description = 'This rule checks for forgotten .DS_Store files' self.rule_confirm = '.DS_Store File Found' self.rule_details = '' self.rule_mitigation = '''A .DS_Store file is a special MacOSX file which reveals the files within the same folder where it lives. and may indicate what other files exists on the webserver. @@ -45,7 +45,6 @@ def generate_filename(self): return ''.join(random.choices(string.ascii_letters + string.digits, k=8)) def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -54,8 +53,8 @@ def check_rule(self, ip, port, values, conf): if 'http' not in module: return + for uri in self.uris: - filename = self.generate_filename() resp = t.http_request(ip, port, uri=uri + '/.DS_Store') @@ -69,8 +68,8 @@ def check_rule(self, ip, port, values, conf): with open(filename, 'rb') as f: if self.is_file_ds_store(f.read()): - self.rule_details = 'Found .DS_Store file at {}'.format(uri) - js_data = { + self.rule_details = 'Identified .DS_Store file at {}'.format(resp.url) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -80,8 +79,7 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) os.remove(filename) return diff --git a/rules/vulnerabilities/rule_elasticsearch.py b/rules/vulnerabilities/rule_elasticsearch.py index c3eed8d..249336b 100644 --- a/rules/vulnerabilities/rule_elasticsearch.py +++ b/rules/vulnerabilities/rule_elasticsearch.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'VLN_77D7' self.rule_severity = 2 - self.rule_description = 'Checks for Open Elasticsearch instances' + self.rule_description = 'This rule checks for Open Elasticsearch instances' self.rule_confirm = 'Identified an open Elasticsearch' self.rule_details = '' self.rule_mitigation = '''Identify whether ElasticSearch should allow access to untrusted clients.\ @@ -27,7 +27,6 @@ def __init__(self): self.intensity = 3 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -39,7 +38,6 @@ def check_rule(self, ip, port, values, conf): if 'http' in module: for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -47,18 +45,17 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Exposed {} at {}'.format(app_title, uri) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + self.rule_details = 'Exposed {} at {}'.format(app_title, resp.url) + rds.store_vuln( { + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) return return diff --git a/rules/vulnerabilities/rule_error-detect.py b/rules/vulnerabilities/rule_error-detect.py index 43b7654..07bbce9 100644 --- a/rules/vulnerabilities/rule_error-detect.py +++ b/rules/vulnerabilities/rule_error-detect.py @@ -3,13 +3,13 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'VLN_AB1D' self.rule_severity = 2 - self.rule_description = 'Checks for Information Revealing Errors' + self.rule_description = 'This rule checks for Information Revealing Errors' self.rule_confirm = 'Application is Leaking Information' self.rule_details = '' self.rule_mitigation = '''Server is configured with one or more frameworks which are incorrectly configured. @@ -65,7 +65,6 @@ def generate_str(self): return '/' + ''.join(random.choices(string.ascii_letters + string.digits, k=8)) def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -78,7 +77,6 @@ def check_rule(self, ip, port, values, conf): resp = None for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -86,8 +84,8 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = 'Info Leakage - {}, Path: {}'.format(app_title, uri) - js_data = { + self.rule_details = 'Information Leakage via {} at {}'.format(app_title, resp.url) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -97,6 +95,5 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) return diff --git a/rules/vulnerabilities/rule_front-page.py b/rules/vulnerabilities/rule_front-page.py index 1dad8f6..b3cefb9 100644 --- a/rules/vulnerabilities/rule_front-page.py +++ b/rules/vulnerabilities/rule_front-page.py @@ -1,20 +1,19 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'VLN_65C8' self.rule_severity = 2 - self.rule_description = 'FrontPage configuration information disclosure' + self.rule_description = 'This rule checks for FrontPage configuration information disclosure' self.rule_confirm = 'FrontPage misconfiguration' self.rule_details = '' self.rule_mitigation = '''Ensure SharePoint is not anonymously accessible''' self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -30,8 +29,8 @@ def check_rule(self, ip, port, values, conf): return if 'Content-Length' in resp.headers and resp.headers['Content-Length'] == '247': - self.rule_details = 'Exposed FrontPage at /_vti_inf.html' - js_data = { + self.rule_details = 'Exposed FrontPage at {}'.format(resp.url) + rds.store_vuln({ 'ip': ip, 'port': port, 'domain': domain, @@ -41,8 +40,6 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm': self.rule_confirm, 'rule_details': self.rule_details, 'rule_mitigation': self.rule_mitigation - } - - rds.store_vuln(js_data) + }) return diff --git a/rules/vulnerabilities/rule_ftp-anon-access.py b/rules/vulnerabilities/rule_ftp-anon-access.py index 64887a0..4eb5df1 100644 --- a/rules/vulnerabilities/rule_ftp-anon-access.py +++ b/rules/vulnerabilities/rule_ftp-anon-access.py @@ -2,14 +2,14 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser from db.db_ports import ftp_ports class Rule: def __init__(self): self.rule = 'VLN_242C' self.rule_severity = 4 - self.rule_description = 'Checks if FTP allows Anonymous Access' + self.rule_description = 'This rule checks if FTP Server allows Anonymous Access' self.rule_details = '' self.rule_confirm = 'FTP Anonymous Access Allowed' self.rule_mitigation = '''FTP allows anonymous users access. Disable Anonymous FTP access if this is not a business requirement.''' @@ -17,13 +17,9 @@ def __init__(self): self.intensity = 0 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) - t = Triage() p = ScanParser(port, values) domain = p.get_domain() - module = p.get_module() - product = p.get_product() if port in self.rule_match_port: try: @@ -32,18 +28,17 @@ def check_rule(self, ip, port, values, conf): if res: if '230' in res or 'user logged in' in res or 'successful' in res: self.rule_details = 'FTP with Anonymous Access Enabled' - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) except: pass diff --git a/rules/vulnerabilities/rule_git-repo.py b/rules/vulnerabilities/rule_git-repo.py index f318e56..5f2431c 100644 --- a/rules/vulnerabilities/rule_git-repo.py +++ b/rules/vulnerabilities/rule_git-repo.py @@ -1,6 +1,6 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser from db.db_paths import COMMON_WEB_PATHS from core.logging import logger @@ -8,7 +8,7 @@ class Rule: def __init__(self): self.rule = 'VLN_92F9' self.rule_severity = 4 - self.rule_description = 'Checks for Git Repositories' + self.rule_description = 'This rule checks for open Git Repositories' self.rule_confirm = 'Remote Server Exposes Git Repository' self.rule_details = '' self.rule_mitigation = '''Git repository was found to be accessible. \ @@ -17,7 +17,6 @@ def __init__(self): self.uris = COMMON_WEB_PATHS def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -33,20 +32,17 @@ def check_rule(self, ip, port, values, conf): resp = t.http_request(ip, port, uri=uri + '/.git/HEAD') if resp and resp.text.startswith('ref:'): - self.rule_details = 'Git Path: {}'.format(uri) - - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - - rds.store_vuln(js_data) + self.rule_details = 'Identified a git repository at {}'.format(resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) return diff --git a/rules/vulnerabilities/rule_graphql.py b/rules/vulnerabilities/rule_graphql.py index 4cbaca2..8a41168 100644 --- a/rules/vulnerabilities/rule_graphql.py +++ b/rules/vulnerabilities/rule_graphql.py @@ -1,12 +1,12 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'VLN_FBQP' self.rule_severity = 2 - self.rule_description = 'Checks for GraphQL Interfaces' + self.rule_description = 'This rule checks for open GraphQL Interfaces' self.rule_confirm = 'Exposed GraphQL Interface' self.rule_details = '' self.rule_mitigation = '''Restrict access to the GraphQL Interface to trusted sources \ @@ -14,7 +14,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -34,8 +33,8 @@ def check_rule(self, ip, port, values, conf): return if resp.status_code == 400 and 'GET query missing.' in resp.text: - self.rule_details = 'GraphQL Enabled on the Server' - js_data = { + self.rule_details = 'GraphQL Enabled on the Server at {}'.format(resp.url) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -45,8 +44,7 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) return return diff --git a/rules/vulnerabilities/rule_host-inject.py b/rules/vulnerabilities/rule_host-inject.py index a859f49..f44b83a 100644 --- a/rules/vulnerabilities/rule_host-inject.py +++ b/rules/vulnerabilities/rule_host-inject.py @@ -1,22 +1,21 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'VLN_4SD5' self.rule_severity = 2 - self.rule_description = 'Checks for Host Header Injections' + self.rule_description = 'This rule checks for possible Host Header Injections' self.rule_confirm = 'Identified Host Header Injection' self.rule_details = '' - self.rule_mitigation = '''Redirect only to allowed hosts, otherwise ignore the Host Header.\ -This may not indicate an immediate problem, but could potentially become an issue if any URLS are being constructed using the Host header.\ -https://www.acunetix.com/blog/articles/automated-detection-of-host-header-attacks''' + self.rule_mitigation = '''Redirect only to allowed hosts, otherwise ignore the Host Header. +This may not indicate an immediate problem, but could potentially become an issue if any URLs are being constructed using the Host header. +Refer to the following Acunetix article for more information on Host Header Injections: https://www.acunetix.com/blog/articles/automated-detection-of-host-header-attacks''' self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -32,9 +31,8 @@ def check_rule(self, ip, port, values, conf): if resp: if 'Location' in resp.headers and '112000as0az7s62s9d7.com' in resp.headers['Location']: - self.rule_details = 'Host header injection' - - js_data = { + self.rule_details = 'Host header injection was possible via headers: X-Forwarded-Host: 112000as0az7s62s9d7.com and Host: 112000as0az7s62s9d7.com' + rds.store_vuln({ 'ip': ip, 'port': port, 'domain': domain, @@ -44,8 +42,6 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm': self.rule_confirm, 'rule_details': self.rule_details, 'rule_mitigation': self.rule_mitigation - } - - rds.store_vuln(js_data) + }) return diff --git a/rules/vulnerabilities/rule_intellij-idea.py b/rules/vulnerabilities/rule_intellij-idea.py index d43eac7..b52f8ce 100644 --- a/rules/vulnerabilities/rule_intellij-idea.py +++ b/rules/vulnerabilities/rule_intellij-idea.py @@ -1,13 +1,13 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser from db.db_paths import COMMON_WEB_PATHS from core.logging import logger class Rule: def __init__(self): self.rule = 'VLN_ZBKK' self.rule_severity = 1 - self.rule_description = 'Checks for Intellij IDEA files' + self.rule_description = 'This rule checks for forgotten Intellij IDEA files' self.rule_confirm = 'Remote Server contains IDE related files' self.rule_details = '' self.rule_mitigation = '''Add the files to gitignore to prevent them from getting pushed.''' @@ -16,7 +16,6 @@ def __init__(self): self.intensity = 3 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -33,8 +32,8 @@ def check_rule(self, ip, port, values, conf): if resp: for match in self.rule_match_string: if match in resp.text: - self.rule_details = 'Found Intelli IDEA files at {}/.idea/workspace.xml'.format(uri) - js_data = { + self.rule_details = 'Found Intelli IDEA files at {}'.format(resp.url) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -44,6 +43,5 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) return diff --git a/rules/vulnerabilities/rule_redis-dump-keys.py b/rules/vulnerabilities/rule_redis-dump-keys.py index c826df7..3370257 100644 --- a/rules/vulnerabilities/rule_redis-dump-keys.py +++ b/rules/vulnerabilities/rule_redis-dump-keys.py @@ -2,22 +2,20 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser from db.db_ports import database_ports class Rule: def __init__(self): self.rule = 'VLN_E034' self.rule_severity = 3 - self.rule_description = 'Checks for Open Redis Instances' + self.rule_description = 'This rule checks for Open Redis Instances' self.rule_confirm = 'Remote Server Exposes Redis Keys' self.rule_details = '' self.rule_mitigation = '''Bind redis to the local network, and add authentication using --require-auth config parameter.''' self.intensity = 0 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) - t = Triage() p = ScanParser(port, values) domain = p.get_domain() @@ -33,8 +31,8 @@ def check_rule(self, ip, port, values, conf): data = s.recv(1024) if data and 'redis_version' in str(data): - self.rule_details = 'Redis version: ..snip.. {} ..snip..'.format(str(data)[0:100]) - js_data = { + self.rule_details = 'Redis is open and exposes the following: ..snip.. {} ..snip..'.format(str(data)[0:100]) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -44,9 +42,7 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - - rds.store_vuln(js_data) + }) return except: pass diff --git a/rules/vulnerabilities/rule_s3-takeover.py b/rules/vulnerabilities/rule_s3-takeover.py index 483c344..dff7a2a 100644 --- a/rules/vulnerabilities/rule_s3-takeover.py +++ b/rules/vulnerabilities/rule_s3-takeover.py @@ -2,13 +2,13 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'VLN_ZZ13' self.rule_severity = 3 - self.rule_description = 'Checks for Beanstalk Takeovers' + self.rule_description = 'This rule checks for possible AWS S3 DNS takeovers' self.rule_confirm = 'DNS Entry allows takeover of Beanstalk server' self.rule_details = '' self.rule_mitigation = '''Verify the DNS is in use, remove if unnecessary.\ @@ -16,7 +16,6 @@ def __init__(self): self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -31,18 +30,18 @@ def check_rule(self, ip, port, values, conf): return if resp.status_code == 404 and 'NoSuchBucket' in resp.text: - self.rule_details = 'S3 Takeover at {}'.format(domain) - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) - + self.rule_details = 'AWS S3 Subdomain takeover is possible at {}'.format(domain) + + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) + return diff --git a/rules/vulnerabilities/rule_shellshock.py b/rules/vulnerabilities/rule_shellshock.py index 7d558c7..5ca1207 100644 --- a/rules/vulnerabilities/rule_shellshock.py +++ b/rules/vulnerabilities/rule_shellshock.py @@ -2,21 +2,21 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser from db.db_paths import COMMON_CGI_PATHS class Rule: def __init__(self): self.rule = 'VLN_88GV' self.rule_severity = 4 - self.rule_description = 'Remote Code Execution Via User-Agent shellshock' + self.rule_description = 'This rule checks for Remote Code Execution Via User-Agent shellshock (CVE-2014-6271)' self.rule_confirm = 'Shellshock RCE' self.rule_details = '' - self.rule_mitigation = '''Patch the vulnerable system's kernel to a non-vulnerable version.''' + self.rule_mitigation = '''Patch the vulnerable system's kernel to a non-vulnerable version. +Refer to the following CVE advisory for more information: https://nvd.nist.gov/vuln/detail/CVE-2014-6271''' self.intensity = 3 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -34,8 +34,8 @@ def check_rule(self, ip, port, values, conf): continue if resp and re.search('root:[x*]:0:0', resp.text): - self.rule_details = 'Remote Code Execution Shellshock' - js_data = { + self.rule_details = 'Remote Code Execution via Shellshock at {}'.format(resp.url) + rds.store_vuln({ 'ip': ip, 'port': port, 'domain': domain, @@ -45,9 +45,7 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm': self.rule_confirm, 'rule_details': self.rule_details, 'rule_mitigation': self.rule_mitigation - } - - rds.store_vuln(js_data) + }) break return \ No newline at end of file diff --git a/rules/vulnerabilities/rule_ssh_filedisclosure.py b/rules/vulnerabilities/rule_ssh_filedisclosure.py index 9525396..5775514 100644 --- a/rules/vulnerabilities/rule_ssh_filedisclosure.py +++ b/rules/vulnerabilities/rule_ssh_filedisclosure.py @@ -1,15 +1,15 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'VLN_EZSD' self.rule_severity = 4 - self.rule_description = 'Finds Exposed UNIX Filesystems' + self.rule_description = 'This rule checks for exposed UNIX Filesystems' self.rule_confirm = 'UNIX File Disclosure' self.rule_details = '' - self.rule_mitigation = '''Disable any ability to directly browse to file system paths''' + self.rule_mitigation = '''Disable the ability to directly browse to file system paths''' self.rule_match_string = { '/.ssh/authorized_keys':{ 'app':'SSH_AUTH_KEYS', @@ -45,7 +45,6 @@ def __init__(self): self.intensity = 2 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -58,7 +57,6 @@ def check_rule(self, ip, port, values, conf): resp = None for uri, values in self.rule_match_string.items(): - app_name = values['app'] app_title = values['title'] resp = t.http_request(ip, port, uri=uri) @@ -66,8 +64,8 @@ def check_rule(self, ip, port, values, conf): if resp is not None: for match in values['match']: if match in resp.text: - self.rule_details = '{} at {}'.format(app_title, uri) - js_data = { + self.rule_details = 'UNIX File Disclosure - {} at {}'.format(app_title, resp.url) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -77,7 +75,5 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - - rds.store_vuln(js_data) + }) return \ No newline at end of file diff --git a/rules/vulnerabilities/rule_svn-repo.py b/rules/vulnerabilities/rule_svn-repo.py index 30ad701..c05ba6e 100644 --- a/rules/vulnerabilities/rule_svn-repo.py +++ b/rules/vulnerabilities/rule_svn-repo.py @@ -1,13 +1,13 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser from core.utils import Utils class Rule: def __init__(self): self.rule = 'VLN_BLKK' self.rule_severity = 4 - self.rule_description = 'Checks for SVN Repositories' + self.rule_description = 'This rule checks for open SVN Repositories' self.rule_confirm = 'SVN Repository Found' self.rule_details = '' self.rule_mitigation = '''Block remote access to the Subversion repository.''' @@ -15,12 +15,10 @@ def __init__(self): def check_rule(self, ip, port, values, conf): t = Triage() - c = ConfParser(conf) p = ScanParser(port, values) domain = p.get_domain() module = p.get_module() - product = p.get_product() if 'http' not in module: return @@ -28,8 +26,8 @@ def check_rule(self, ip, port, values, conf): resp = t.http_request(ip, port, uri='/.svn/text-base') if resp and 'Index of /' in resp.text: - self.rule_details = 'SVN Repository exposed at /.svn/text-base' - js_data = { + self.rule_details = 'SVN Repository exposed at {}'.format(resp.url) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -39,9 +37,7 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - - rds.store_vuln(js_data) + }) return diff --git a/rules/vulnerabilities/rule_unencrypted_login.py b/rules/vulnerabilities/rule_unencrypted_login.py index 36df8ff..c6cd5bf 100644 --- a/rules/vulnerabilities/rule_unencrypted_login.py +++ b/rules/vulnerabilities/rule_unencrypted_login.py @@ -1,14 +1,14 @@ from bs4 import BeautifulSoup from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser from db.db_ports import http_ports class Rule: def __init__(self): self.rule = 'VLN_SKKF' self.rule_severity = 2 - self.rule_description = 'Checks for password forms in HTTP' + self.rule_description = 'This rule checks for password forms over HTTP protocols' self.rule_confirm = 'Unencrypted Login Form' self.rule_details = '' self.rule_mitigation = '''Website accepts credentials via HTML Forms, howeverm, it offers no encryptions and may allow attackers to intercept them.''' @@ -29,34 +29,29 @@ def contains_password_form(self, text): return False def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) domain = p.get_domain() module = p.get_module() - product = p.get_product() - if module == 'http' or port in http_ports: resp = t.http_request(ip, port, follow_redirects=False) if resp: form = self.contains_password_form(resp.text) - if form: - if not resp.url.startswith('https://'): - self.rule_details = 'Login Page over HTTP' - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) - return + if form and not resp.url.startswith('https://'): + self.rule_details = 'Login Page over HTTP at {}'.format(resp.url) + rds.store_vuln({ + 'ip':ip, + 'port':port, + 'domain':domain, + 'rule_id':self.rule, + 'rule_sev':self.rule_severity, + 'rule_desc':self.rule_description, + 'rule_confirm':self.rule_confirm, + 'rule_details':self.rule_details, + 'rule_mitigation':self.rule_mitigation + }) + return diff --git a/rules/vulnerabilities/rule_wordpress-listing.py b/rules/vulnerabilities/rule_wordpress-listing.py index 3b72b05..f9541e9 100644 --- a/rules/vulnerabilities/rule_wordpress-listing.py +++ b/rules/vulnerabilities/rule_wordpress-listing.py @@ -1,19 +1,18 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'VLN_FF00' self.rule_severity = 4 - self.rule_description = 'Checks for Open Wordpress Upload Directories' + self.rule_description = 'This rule checks for Open Wordpress Upload Directories' self.rule_confirm = 'Remote Wordpress has an Uploads Folder with Indexing Enabled' self.rule_details = '' self.rule_mitigation = '''Disable Directory Indexing on the Wordpress instance.''' self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -26,8 +25,8 @@ def check_rule(self, ip, port, values, conf): resp = t.http_request(ip, port, uri='/wp-content/uploads/') if resp and 'Index of /wp-content/uploads' in resp.text: - self.rule_details = 'Found Uploads Directory at /wp-content/uploads/' - js_data = { + self.rule_details = 'Found Uploads Directory at {}'.format(resp.url) + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -37,6 +36,6 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) + return diff --git a/rules/vulnerabilities/rule_xfh-injection.py b/rules/vulnerabilities/rule_xfh-injection.py index 2da0577..866a0fd 100644 --- a/rules/vulnerabilities/rule_xfh-injection.py +++ b/rules/vulnerabilities/rule_xfh-injection.py @@ -1,20 +1,19 @@ from core.redis import rds from core.triage import Triage -from core.parser import ScanParser, ConfParser +from core.parser import ScanParser class Rule: def __init__(self): self.rule = 'VLN_ZD10' self.rule_severity = 2 - self.rule_description = 'Checks for X-Forwarded-Host Injection' + self.rule_description = 'This rule checks for X-Forwarded-Host Injection' self.rule_confirm = 'Remote Server suffers from X-Forwarded-Host Injection' self.rule_details = '' - self.rule_mitigation = '''Configure the server to not redirect based on arbitrary \ -XFH headers provided by the user.''' + self.rule_mitigation = '''Configure the server to not redirect based on arbitrary XFH headers provided by the user. +Refer to the following OWASP article for more information: https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/17-Testing_for_Host_Header_Injection''' self.intensity = 1 def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) t = Triage() p = ScanParser(port, values) @@ -24,15 +23,14 @@ def check_rule(self, ip, port, values, conf): if 'http' not in module: return - target = 'www.nerve.local' - resp = t.http_request(ip, port, follow_redirects=False, headers={'X-Forwarded-Host':target}) + resp = t.http_request(ip, port, follow_redirects=False, headers={'X-Forwarded-Host':'www.nerve.local'}) if resp is None: return - if 'Location' in resp.headers and resp.headers['Location'] == target: + if 'Location' in resp.headers and resp.headers['Location'] == 'www.nerve.local': self.rule_details = 'Server Redirected to an Arbitrary Location' - js_data = { + rds.store_vuln({ 'ip':ip, 'port':port, 'domain':domain, @@ -42,7 +40,6 @@ def check_rule(self, ip, port, values, conf): 'rule_confirm':self.rule_confirm, 'rule_details':self.rule_details, 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) + }) return diff --git a/rules/vulnerabilities/rule_xmlrpc.py b/rules/vulnerabilities/rule_xmlrpc.py deleted file mode 100644 index 6597059..0000000 --- a/rules/vulnerabilities/rule_xmlrpc.py +++ /dev/null @@ -1,47 +0,0 @@ -from core.redis import rds -from core.triage import Triage -from core.parser import ScanParser, ConfParser - -class Rule: - def __init__(self): - self.rule = 'VLN_FAZZ' - self.rule_severity = 2 - self.rule_description = 'Checks for XMLRPC Interfaces' - self.rule_confirm = 'Remote Server has XMLRPC Interface enabled' - self.rule_details = '' - self.rule_mitigation = '''Restrict access to the XMLRPC Interface \ -or disabled it completely if not in use.''' - self.intensity = 1 - - def check_rule(self, ip, port, values, conf): - c = ConfParser(conf) - t = Triage() - p = ScanParser(port, values) - - domain = p.get_domain() - module = p.get_module() - - if 'http' not in module: - return - - resp = t.http_request(ip, port, uri='/xmlrpc.php') - - if resp is None: - return - - if resp.status_code == 405: - self.rule_details = 'Server Allows XMLRPC Connections' - js_data = { - 'ip':ip, - 'port':port, - 'domain':domain, - 'rule_id':self.rule, - 'rule_sev':self.rule_severity, - 'rule_desc':self.rule_description, - 'rule_confirm':self.rule_confirm, - 'rule_details':self.rule_details, - 'rule_mitigation':self.rule_mitigation - } - rds.store_vuln(js_data) - - return diff --git a/static/css/nerve.css b/static/css/nerve.css index 52a147c..f87048e 100644 --- a/static/css/nerve.css +++ b/static/css/nerve.css @@ -119,7 +119,7 @@ span.banner_sm { } .medium { - color:orange + color:darkorange } .low { diff --git a/templates/alert.html b/templates/alert.html new file mode 100644 index 0000000..e22daed --- /dev/null +++ b/templates/alert.html @@ -0,0 +1,113 @@ + + + + + + + NERVE + + + + + + + + +
+ + +
+ + +
+
+
+

{{vuln.data.ip}}:{{vuln.data.port}}

+
+
+ +
+
+
+
Alert
+
+ +
+
{% if vuln %} {{ vuln.data.rule_desc }}. {% endif %}
+
{% if vuln %} {{ vuln.data.rule_details }}. {% endif %}
+
{% if vuln %} {{ vuln.data.rule_mitigation }} {% endif %}
+
+ + + +
+
+
+
+
+
+
+
+ + + + + + + + + + + + + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + + {% endif %} + {% endwith %} + + + \ No newline at end of file diff --git a/templates/assessment.html b/templates/assessment.html index e64f3b5..b08f70a 100644 --- a/templates/assessment.html +++ b/templates/assessment.html @@ -5,10 +5,10 @@ NERVE - - - - + + + + @@ -256,13 +256,14 @@

Assessment

- - - - - - - + + + + + + + + {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} diff --git a/templates/assets.html b/templates/assets.html index e9ecf84..af3c3b7 100644 --- a/templates/assets.html +++ b/templates/assets.html @@ -5,11 +5,11 @@ NERVE - - - - - + + + + + @@ -73,11 +73,12 @@

Assets

{% for d, values in data.items() %} {{loop.index}}. - {{d[4:]}} - + {{d[4:]}} {% if values.domain %} - {{values.domain}} + {{values.domain}} + {% else %} + N/A {% endif %} @@ -111,14 +112,15 @@
{% if values.os %} {{values.os}} {% endif - - - - - - - - + + + + + + + + + {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} - - - - - + + + + + + {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} diff --git a/templates/dashboard.html b/templates/dashboard.html index b65ac76..3882539 100644 --- a/templates/dashboard.html +++ b/templates/dashboard.html @@ -6,12 +6,11 @@ {% if status != "Ready" %}{% endif %} NERVE - - - - - - + + + + + @@ -280,15 +279,15 @@

Live Hosts

- - - - - - - + + + + + + + + - {% if vulns %} + + + + + - - - - - - {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} - - - - + + + + + + {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} - - - - - + + + + + + + {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} - - - - - + + + + + + + {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} - - - - - + + + + + + + - - - - + + + + + +