forked from p15670423/monkey
Merge pull request #1699 from guardicore/1669-remove-scoutsuite-integration
Remove scoutsuite
This commit is contained in:
commit
5a64db4ce9
|
@ -42,6 +42,7 @@ Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
- MySQL fingerprinter. #1648
|
||||
- MS08-067 (Conficker) exploiter. #1677
|
||||
- Agent bootloader. #1676
|
||||
- Zero Trust integration with ScoutSuite. #1669
|
||||
|
||||
### Fixed
|
||||
- A bug in network map page that caused delay of telemetry log loading. #1545
|
||||
|
|
|
@ -4,7 +4,7 @@ date: 2020-07-14T08:09:53+03:00
|
|||
draft: false
|
||||
pre: '<i class="fas fa-laptop"></i> '
|
||||
weight: 10
|
||||
tags: ["setup", "reference", "windows", "linux"]
|
||||
tags: ["setup", "reference", "windows", "linux"]
|
||||
---
|
||||
|
||||
The Infection Monkey project supports many popular OSes (but we are always interested in supporting more).
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
---
|
||||
title: "Scoutsuite"
|
||||
date: 2021-03-02T16:23:06+02:00
|
||||
draft: false
|
||||
description: "Scout Suite is an open-source cloud security-auditing tool."
|
||||
weight: 10
|
||||
---
|
||||
|
||||
### About ScoutSuite
|
||||
|
||||
<a href="https://github.com/nccgroup/ScoutSuite" target="_blank" >Scout Suite</a> is an open-source cloud security-auditing tool.
|
||||
It queries the cloud API to gather configuration data. Based on configuration
|
||||
data gathered, ScoutSuite shows security issues and risks present in your infrastructure.
|
||||
|
||||
### Supported cloud providers
|
||||
|
||||
Currently, ScoutSuite integration only supports AWS environments.
|
||||
|
||||
### Enabling ScoutSuite
|
||||
|
||||
First, Infection Monkey needs access to your cloud API. You can provide access
|
||||
in the following ways:
|
||||
|
||||
- Provide access keys:
|
||||
- Create a new user with ReadOnlyAccess and SecurityAudit policies and generate keys
|
||||
- Generate keys for your current user (faster but less secure)
|
||||
- Configure AWS CLI:
|
||||
- If the command-line interface is available on the Island, it will be used to access
|
||||
the cloud API
|
||||
|
||||
More details about configuring ScoutSuite can be found in the tool itself, by choosing
|
||||
"Cloud Security Scan" in the "Run Monkey" options.
|
||||
|
||||
![Cloud scan option in run page](/images/usage/integrations/scoutsuite_run_page.png
|
||||
"Successful setup indicator")
|
||||
|
||||
After you're done with the setup, make sure that a checkmark appears next to the AWS option. This
|
||||
verifies that ScoutSuite can access the API.
|
||||
|
||||
![Successfull setup indicator](/images/usage/integrations/scoutsuite_aws_configured.png
|
||||
"Successful setup indicator")
|
||||
|
||||
### Running a cloud security scan
|
||||
|
||||
If you have successfully configured the cloud scan, Infection Monkey will scan
|
||||
your cloud infrastructure when the Monkey Agent is run **on the Island**. You
|
||||
can simply click on "From Island" in the run options to start the scan. The
|
||||
scope of the network scan and other activities you may have configured the Agent
|
||||
to perform are ignored by the ScoutSuite integration, except **Monkey
|
||||
Configuration -> System info collectors -> AWS collector**, which needs to
|
||||
remain **enabled**.
|
||||
|
||||
|
||||
### Assessing scan results
|
||||
|
||||
After the scan is done, ScoutSuite results will be categorized according to the
|
||||
ZeroTrust Extended framework and displayed as a part of the ZeroTrust report.
|
||||
The main difference between Infection Monkey findings and ScoutSuite findings
|
||||
is that ScoutSuite findings contain security rules. To see which rules were
|
||||
checked, click on the "Rules" button next to the relevant test. You'll see a
|
||||
list of rule dropdowns that are color coded according to their status. Expand a
|
||||
rule to see its description, remediation and more details about resources
|
||||
flagged. Each flagged resource has a path so you can easily locate it in the
|
||||
cloud and remediate the issue.
|
||||
|
||||
![Open ScoutSuite rule](/images/usage/integrations/scoutsuite_report_rule.png
|
||||
"Successful setup indicator")
|
|
@ -11,8 +11,6 @@ weight: 1
|
|||
Want to assess your progress in achieving a Zero Trust network? The Infection Monkey can automatically evaluate your readiness across the different
|
||||
[Zero Trust Extended Framework](https://www.forrester.com/report/The+Zero+Trust+eXtended+ZTX+Ecosystem/-/E-RES137210) principles.
|
||||
|
||||
You can additionally scan your cloud infrastructure's compliance to ZeroTrust principles using [ScoutSuite integration.]({{< ref "/usage/integrations/scoutsuite" >}})
|
||||
|
||||
## Configuration
|
||||
|
||||
- **Exploits -> Credentials** This configuration value will be used for brute-forcing. The Infection Monkey uses the most popular default passwords and usernames, but feel free to adjust it according to the default passwords common in your network. Keep in mind a longer list means longer scanning times.
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
from enum import Enum
|
||||
|
||||
|
||||
class CloudProviders(Enum):
|
||||
AWS = "aws"
|
|
@ -1,4 +1,5 @@
|
|||
import logging
|
||||
import time
|
||||
|
||||
from common.cloud.aws.aws_service import AwsService
|
||||
from common.cmd.aws.aws_cmd_result import AwsCmdResult
|
||||
|
@ -20,6 +21,7 @@ class AwsCmdRunner(CmdRunner):
|
|||
self.ssm = AwsService.get_client("ssm", region)
|
||||
|
||||
def query_command(self, command_id):
|
||||
time.sleep(2)
|
||||
return self.ssm.get_command_invocation(CommandId=command_id, InstanceId=self.instance_id)
|
||||
|
||||
def get_command_result(self, command_info):
|
||||
|
|
|
@ -2,7 +2,6 @@ class TelemCategoryEnum:
|
|||
EXPLOIT = "exploit"
|
||||
POST_BREACH = "post_breach"
|
||||
SCAN = "scan"
|
||||
SCOUTSUITE = "scoutsuite"
|
||||
STATE = "state"
|
||||
SYSTEM_INFO = "system_info"
|
||||
TRACE = "trace"
|
||||
|
|
|
@ -41,13 +41,6 @@ TEST_MALICIOUS_ACTIVITY_TIMELINE = "malicious_activity_timeline"
|
|||
TEST_SEGMENTATION = "segmentation"
|
||||
TEST_TUNNELING = "tunneling"
|
||||
TEST_COMMUNICATE_AS_BACKDOOR_USER = "communicate_as_backdoor_user"
|
||||
TEST_SCOUTSUITE_PERMISSIVE_FIREWALL_RULES = "scoutsuite_permissive_firewall_rules"
|
||||
TEST_SCOUTSUITE_UNENCRYPTED_DATA = "scoutsuite_unencrypted_data"
|
||||
TEST_SCOUTSUITE_DATA_LOSS_PREVENTION = "scoutsuite_data_loss_prevention"
|
||||
TEST_SCOUTSUITE_SECURE_AUTHENTICATION = "scoutsuite_secure_authentication"
|
||||
TEST_SCOUTSUITE_RESTRICTIVE_POLICIES = "scoutsuite_unrestrictive_policies"
|
||||
TEST_SCOUTSUITE_LOGGING = "scoutsuite_logging"
|
||||
TEST_SCOUTSUITE_SERVICE_SECURITY = "scoutsuite_service_security"
|
||||
|
||||
TESTS = (
|
||||
TEST_SEGMENTATION,
|
||||
|
@ -59,13 +52,6 @@ TESTS = (
|
|||
TEST_DATA_ENDPOINT_ELASTIC,
|
||||
TEST_TUNNELING,
|
||||
TEST_COMMUNICATE_AS_BACKDOOR_USER,
|
||||
TEST_SCOUTSUITE_PERMISSIVE_FIREWALL_RULES,
|
||||
TEST_SCOUTSUITE_UNENCRYPTED_DATA,
|
||||
TEST_SCOUTSUITE_DATA_LOSS_PREVENTION,
|
||||
TEST_SCOUTSUITE_SECURE_AUTHENTICATION,
|
||||
TEST_SCOUTSUITE_RESTRICTIVE_POLICIES,
|
||||
TEST_SCOUTSUITE_LOGGING,
|
||||
TEST_SCOUTSUITE_SERVICE_SECURITY,
|
||||
)
|
||||
|
||||
PRINCIPLE_DATA_CONFIDENTIALITY = "data_transit"
|
||||
|
@ -219,77 +205,6 @@ TESTS_MAP = {
|
|||
PILLARS_KEY: [PEOPLE, NETWORKS, VISIBILITY_ANALYTICS],
|
||||
POSSIBLE_STATUSES_KEY: [STATUS_UNEXECUTED, STATUS_FAILED, STATUS_PASSED],
|
||||
},
|
||||
TEST_SCOUTSUITE_PERMISSIVE_FIREWALL_RULES: {
|
||||
TEST_EXPLANATION_KEY: "ScoutSuite assessed cloud firewall rules and settings.",
|
||||
FINDING_EXPLANATION_BY_STATUS_KEY: {
|
||||
STATUS_FAILED: "ScoutSuite found overly permissive firewall rules.",
|
||||
STATUS_PASSED: "ScoutSuite found no problems with cloud firewall rules.",
|
||||
},
|
||||
PRINCIPLE_KEY: PRINCIPLE_RESTRICTIVE_NETWORK_POLICIES,
|
||||
PILLARS_KEY: [NETWORKS],
|
||||
POSSIBLE_STATUSES_KEY: [STATUS_UNEXECUTED, STATUS_FAILED, STATUS_PASSED],
|
||||
},
|
||||
TEST_SCOUTSUITE_UNENCRYPTED_DATA: {
|
||||
TEST_EXPLANATION_KEY: "ScoutSuite searched for resources containing " "unencrypted data.",
|
||||
FINDING_EXPLANATION_BY_STATUS_KEY: {
|
||||
STATUS_FAILED: "ScoutSuite found resources with unencrypted data.",
|
||||
STATUS_PASSED: "ScoutSuite found no resources with unencrypted data.",
|
||||
},
|
||||
PRINCIPLE_KEY: PRINCIPLE_DATA_CONFIDENTIALITY,
|
||||
PILLARS_KEY: [DATA],
|
||||
POSSIBLE_STATUSES_KEY: [STATUS_UNEXECUTED, STATUS_FAILED, STATUS_PASSED],
|
||||
},
|
||||
TEST_SCOUTSUITE_DATA_LOSS_PREVENTION: {
|
||||
TEST_EXPLANATION_KEY: "ScoutSuite searched for resources which are not "
|
||||
"protected against data loss.",
|
||||
FINDING_EXPLANATION_BY_STATUS_KEY: {
|
||||
STATUS_FAILED: "ScoutSuite found resources not protected against data loss.",
|
||||
STATUS_PASSED: "ScoutSuite found that all resources are secured against data loss.",
|
||||
},
|
||||
PRINCIPLE_KEY: PRINCIPLE_DISASTER_RECOVERY,
|
||||
PILLARS_KEY: [DATA],
|
||||
POSSIBLE_STATUSES_KEY: [STATUS_UNEXECUTED, STATUS_FAILED, STATUS_PASSED],
|
||||
},
|
||||
TEST_SCOUTSUITE_SECURE_AUTHENTICATION: {
|
||||
TEST_EXPLANATION_KEY: "ScoutSuite searched for issues related to users' " "authentication.",
|
||||
FINDING_EXPLANATION_BY_STATUS_KEY: {
|
||||
STATUS_FAILED: "ScoutSuite found issues related to users' authentication.",
|
||||
STATUS_PASSED: "ScoutSuite found no issues related to users' authentication.",
|
||||
},
|
||||
PRINCIPLE_KEY: PRINCIPLE_SECURE_AUTHENTICATION,
|
||||
PILLARS_KEY: [PEOPLE, WORKLOADS],
|
||||
POSSIBLE_STATUSES_KEY: [STATUS_UNEXECUTED, STATUS_FAILED, STATUS_PASSED],
|
||||
},
|
||||
TEST_SCOUTSUITE_RESTRICTIVE_POLICIES: {
|
||||
TEST_EXPLANATION_KEY: "ScoutSuite searched for permissive user access " "policies.",
|
||||
FINDING_EXPLANATION_BY_STATUS_KEY: {
|
||||
STATUS_FAILED: "ScoutSuite found permissive user access policies.",
|
||||
STATUS_PASSED: "ScoutSuite found no issues related to user access policies.",
|
||||
},
|
||||
PRINCIPLE_KEY: PRINCIPLE_USERS_MAC_POLICIES,
|
||||
PILLARS_KEY: [PEOPLE, WORKLOADS],
|
||||
POSSIBLE_STATUSES_KEY: [STATUS_UNEXECUTED, STATUS_FAILED, STATUS_PASSED],
|
||||
},
|
||||
TEST_SCOUTSUITE_LOGGING: {
|
||||
TEST_EXPLANATION_KEY: "ScoutSuite searched for issues, related to logging.",
|
||||
FINDING_EXPLANATION_BY_STATUS_KEY: {
|
||||
STATUS_FAILED: "ScoutSuite found logging issues.",
|
||||
STATUS_PASSED: "ScoutSuite found no logging issues.",
|
||||
},
|
||||
PRINCIPLE_KEY: PRINCIPLE_MONITORING_AND_LOGGING,
|
||||
PILLARS_KEY: [AUTOMATION_ORCHESTRATION, VISIBILITY_ANALYTICS],
|
||||
POSSIBLE_STATUSES_KEY: [STATUS_UNEXECUTED, STATUS_FAILED, STATUS_PASSED],
|
||||
},
|
||||
TEST_SCOUTSUITE_SERVICE_SECURITY: {
|
||||
TEST_EXPLANATION_KEY: "ScoutSuite searched for service security issues.",
|
||||
FINDING_EXPLANATION_BY_STATUS_KEY: {
|
||||
STATUS_FAILED: "ScoutSuite found service security issues.",
|
||||
STATUS_PASSED: "ScoutSuite found no service security issues.",
|
||||
},
|
||||
PRINCIPLE_KEY: PRINCIPLE_MONITORING_AND_LOGGING,
|
||||
PILLARS_KEY: [DEVICES, NETWORKS],
|
||||
POSSIBLE_STATUSES_KEY: [STATUS_UNEXECUTED, STATUS_FAILED, STATUS_PASSED],
|
||||
},
|
||||
}
|
||||
|
||||
EVENT_TYPE_MONKEY_NETWORK = "monkey_network"
|
||||
|
|
|
@ -3,19 +3,6 @@ from typing import Optional, Tuple
|
|||
from urllib.parse import urlparse
|
||||
|
||||
|
||||
def get_host_from_network_location(network_location: str) -> str:
|
||||
"""
|
||||
URL structure is "<scheme>://<net_loc>/<path>;<params>?<query>#<fragment>" (
|
||||
https://tools.ietf.org/html/rfc1808.html)
|
||||
And the net_loc is "<user>:<password>@<host>:<port>" (
|
||||
https://tools.ietf.org/html/rfc1738#section-3.1)
|
||||
:param network_location: server network location
|
||||
:return: host part of the network location
|
||||
"""
|
||||
url = urlparse("http://" + network_location)
|
||||
return str(url.hostname)
|
||||
|
||||
|
||||
def remove_port(url):
|
||||
parsed = urlparse(url)
|
||||
with_port = f"{parsed.scheme}://{parsed.netloc}"
|
||||
|
|
|
@ -22,10 +22,6 @@ class IncorrectCredentialsError(Exception):
|
|||
""" Raise to indicate that authentication failed """
|
||||
|
||||
|
||||
class RulePathCreatorNotFound(Exception):
|
||||
""" Raise to indicate that ScoutSuite rule doesn't have a path creator"""
|
||||
|
||||
|
||||
class InvalidAWSKeys(Exception):
|
||||
""" Raise to indicate that AWS API keys are invalid"""
|
||||
|
||||
|
@ -34,10 +30,6 @@ class NoInternetError(Exception):
|
|||
""" Raise to indicate problems caused when no internet connection is present"""
|
||||
|
||||
|
||||
class ScoutSuiteScanError(Exception):
|
||||
""" Raise to indicate problems ScoutSuite encountered during scanning"""
|
||||
|
||||
|
||||
class UnknownFindingError(Exception):
|
||||
""" Raise when provided finding is of unknown type"""
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ pypykatz = "==0.3.12"
|
|||
requests = ">=2.24"
|
||||
urllib3 = "==1.26.5"
|
||||
WMI = {version = "==1.5.1", sys_platform = "== 'win32'"}
|
||||
ScoutSuite = {git = "git://github.com/guardicode/ScoutSuite"}
|
||||
pyopenssl = "==19.0.0" # We can't build 32bit ubuntu12 binary with newer versions of pyopenssl
|
||||
pypsrp = "*"
|
||||
typing-extensions = "*" # Allows us to use 3.9 typing features on 3.7 project
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "250fc3013e7083083999fbf289f8898d63ceffc95a02e87920d254950832ea68"
|
||||
"sha256": "90dbc7b9edaacc7324c3e1cc9ab1bd618dd62951216cf993225937b20f657779"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
|
@ -38,20 +38,13 @@
|
|||
],
|
||||
"version": "==1.4.0"
|
||||
},
|
||||
"asyncio-throttle": {
|
||||
"hashes": [
|
||||
"sha256:a01a56f3671e961253cf262918f3e0741e222fc50d57d981ba5c801f284eccfe"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==0.1.1"
|
||||
},
|
||||
"asysocks": {
|
||||
"hashes": [
|
||||
"sha256:5ec0582252b0085d9337d13c6b03ab7fd062e487070667f9140e6972bd9db256",
|
||||
"sha256:b97ac905cd4ca1e7a8e7c295f9cb22ced5dfd3f17e888e71cbf05a1d67a4d393"
|
||||
"sha256:23d5fcfae71a75826c3ed787bd9b1bc3b189ec37658961bce83c9e99455e354c",
|
||||
"sha256:731eda25d41783c5243153d3cb4f9357fef337c7317135488afab9ecd6b7f1a1"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==0.1.6"
|
||||
"version": "==0.1.7"
|
||||
},
|
||||
"attrs": {
|
||||
"hashes": [
|
||||
|
@ -84,22 +77,6 @@
|
|||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.2.0"
|
||||
},
|
||||
"boto3": {
|
||||
"hashes": [
|
||||
"sha256:1903e4462b08f7696a8d0977361fe9e35e7a50d9e70d7abd72a3a17012741938",
|
||||
"sha256:34e5ae33ef65b1c4e2e197009e88df5dc217386699939ae897d7fcdb5a6ff295"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==1.20.47"
|
||||
},
|
||||
"botocore": {
|
||||
"hashes": [
|
||||
"sha256:82da38e309bd6fd6303394e6e9d1ea50626746f2911e3fec996f9046c5d85085",
|
||||
"sha256:a89b1be0a7f235533d8279d90b0b15dc2130d0552a9f7654ba302b564ab5688a"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==1.23.47"
|
||||
},
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872",
|
||||
|
@ -178,30 +155,6 @@
|
|||
"markers": "python_version >= '3'",
|
||||
"version": "==2.0.11"
|
||||
},
|
||||
"cheroot": {
|
||||
"hashes": [
|
||||
"sha256:366adf6e7cac9555486c2d1be6297993022eff6f8c4655c1443268cca3f08e25",
|
||||
"sha256:62cbced16f07e8aaf512673987cd6b1fc5ad00073345e9ed6c4e2a5cc2a3a22d"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==8.6.0"
|
||||
},
|
||||
"cherrypy": {
|
||||
"hashes": [
|
||||
"sha256:55659e6f012d374898d6d9d581e17cc1477b6a14710218e64f187b9227bea038",
|
||||
"sha256:f33e87286e7b3e309e04e7225d8e49382d9d7773e6092241d7f613893c563495"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==18.6.1"
|
||||
},
|
||||
"cherrypy-cors": {
|
||||
"hashes": [
|
||||
"sha256:eb512e20fa9e478abd1868b1417814a4e9240ed0c403472a2c624460e49ab0d5",
|
||||
"sha256:f7fb75f6e617ce29c9ec3fdd8b1ff6ec64fec2c56371182525e22bcf4c180513"
|
||||
],
|
||||
"markers": "python_version >= '2.7'",
|
||||
"version": "==1.6"
|
||||
},
|
||||
"click": {
|
||||
"hashes": [
|
||||
"sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3",
|
||||
|
@ -210,12 +163,13 @@
|
|||
"markers": "python_version >= '3.6'",
|
||||
"version": "==8.0.3"
|
||||
},
|
||||
"coloredlogs": {
|
||||
"colorama": {
|
||||
"hashes": [
|
||||
"sha256:34fad2e342d5a559c31b6c889e8d14f97cb62c47d9a2ae7b5ed14ea10a79eff8",
|
||||
"sha256:b869a2dda3fa88154b9dd850e27828d8755bfab5a838a1c97fbc850c6e377c36"
|
||||
"sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b",
|
||||
"sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"
|
||||
],
|
||||
"version": "==10.0"
|
||||
"markers": "platform_system == 'Windows'",
|
||||
"version": "==0.4.4"
|
||||
},
|
||||
"constantly": {
|
||||
"hashes": [
|
||||
|
@ -272,20 +226,6 @@
|
|||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.18.2"
|
||||
},
|
||||
"httpagentparser": {
|
||||
"hashes": [
|
||||
"sha256:a190dfdc5e63b2f1c87729424b19cbc49263d6a1fb585a16ac1c9d9ce127a4bf"
|
||||
],
|
||||
"version": "==1.9.2"
|
||||
},
|
||||
"humanfriendly": {
|
||||
"hashes": [
|
||||
"sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477",
|
||||
"sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==10.0"
|
||||
},
|
||||
"hyperlink": {
|
||||
"hashes": [
|
||||
"sha256:427af957daa58bc909471c6c40f74c5450fa123dd093fc53efd2e91d2705a56b",
|
||||
|
@ -316,14 +256,6 @@
|
|||
"markers": "python_version < '3.8'",
|
||||
"version": "==4.10.1"
|
||||
},
|
||||
"importlib-resources": {
|
||||
"hashes": [
|
||||
"sha256:33a95faed5fc19b4bc16b29a6eeae248a3fe69dd55d4d229d2b480e23eeaad45",
|
||||
"sha256:d756e2f85dd4de2ba89be0b21dba2a3bbec2e871a42a3a16719258a11f87506b"
|
||||
],
|
||||
"markers": "python_version < '3.9'",
|
||||
"version": "==5.4.0"
|
||||
},
|
||||
"incremental": {
|
||||
"hashes": [
|
||||
"sha256:02f5de5aff48f6b9f665d99d48bfc7ec03b6e3943210de7cfc88856d755d6f57",
|
||||
|
@ -347,46 +279,6 @@
|
|||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.0.1"
|
||||
},
|
||||
"jaraco.classes": {
|
||||
"hashes": [
|
||||
"sha256:22ac35313cf4b145bf7b217cc51be2d98a3d2db1c8558a30ca259d9f0b9c0b7d",
|
||||
"sha256:ed54b728af1937dc16b7236fbaf34ba561ba1ace572b03fffa5486ed363ecf34"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.2.1"
|
||||
},
|
||||
"jaraco.collections": {
|
||||
"hashes": [
|
||||
"sha256:b04f00bd4b3c4fc4ba5fe1baf8042c0efd192b13e386830ea23fff77bb69dc88",
|
||||
"sha256:ef7c308d6d7cadfb16b32c7e414d628151ab02b57a5702b9d9a293148c035e70"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==3.5.1"
|
||||
},
|
||||
"jaraco.context": {
|
||||
"hashes": [
|
||||
"sha256:17b909da2fb37ad237ca7ff9523977f8665a47a25b90aec6a99a3e0959c86141",
|
||||
"sha256:f0d4d82ffbbbff680384eba48a32a3167f12a91a30a7db56fd97b87e73a87241"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==4.1.1"
|
||||
},
|
||||
"jaraco.functools": {
|
||||
"hashes": [
|
||||
"sha256:141f95c490a18eb8aab86caf7a2728f02f604988a26dc36652e3d9fa9e4c49fa",
|
||||
"sha256:31e0e93d1027592b7b0bec6ad468db850338981ebee76ba5e212e235f4c7dda0"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==3.5.0"
|
||||
},
|
||||
"jaraco.text": {
|
||||
"hashes": [
|
||||
"sha256:17b43aa0bd46e97c368ccd8a4c8fef2719ca121b6d39ce4be9d9e0143832479a",
|
||||
"sha256:a7f9cc1b44a5f3096a216cbd130b650c7a6b2c9f8005b000ae97f329239a7c00"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.7.0"
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
"sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8",
|
||||
|
@ -395,14 +287,6 @@
|
|||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.0.3"
|
||||
},
|
||||
"jmespath": {
|
||||
"hashes": [
|
||||
"sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9",
|
||||
"sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.10.0"
|
||||
},
|
||||
"ldap3": {
|
||||
"hashes": [
|
||||
"sha256:2bc966556fc4d4fa9f445a1c31dc484ee81d44a51ab0e2d0fd05b62cac75daa6",
|
||||
|
@ -514,19 +398,11 @@
|
|||
},
|
||||
"minikerberos": {
|
||||
"hashes": [
|
||||
"sha256:eba89d5c649241a3367839ebd1c0333b9a9e4fe514746e246a6a1f2cb7bde26e",
|
||||
"sha256:f556a6015904147c3302e9038b49f766c975df6aeb1725027cd7fc68ba993864"
|
||||
"sha256:a1596916c93910910e65ab43e2b0e770c9af0d2da77505c089ed8bc3ee40e872",
|
||||
"sha256:ca83d44f0a6c93cc2298df435c5173e99262d6d234b8055c7c08b9062c2c7c93"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==0.2.16"
|
||||
},
|
||||
"more-itertools": {
|
||||
"hashes": [
|
||||
"sha256:43e6dd9942dffd72661a2c4ef383ad7da1e6a3e968a927ad7a6083ab410a688b",
|
||||
"sha256:7dc6ad46f05f545f900dd59e8dfb4e84a4827b97b3cfecb175ea0c7d247f6064"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==8.12.0"
|
||||
"version": "==0.2.17"
|
||||
},
|
||||
"msldap": {
|
||||
"hashes": [
|
||||
|
@ -536,13 +412,6 @@
|
|||
"markers": "python_version >= '3.7'",
|
||||
"version": "==0.3.30"
|
||||
},
|
||||
"netaddr": {
|
||||
"hashes": [
|
||||
"sha256:9666d0232c32d2656e5e5f8d735f58fd6c7457ce52fc21c98d45f2af78f990ac",
|
||||
"sha256:d6cc57c7a07b1d9d2e917aa8b36ae8ce61c35ba3fcd1b83ca31c5a0ee2b5a243"
|
||||
],
|
||||
"version": "==0.8.0"
|
||||
},
|
||||
"netifaces": {
|
||||
"hashes": [
|
||||
"sha256:043a79146eb2907edf439899f262b3dfe41717d34124298ed281139a8b93ca32",
|
||||
|
@ -608,28 +477,20 @@
|
|||
],
|
||||
"version": "==1.7.4"
|
||||
},
|
||||
"policyuniverse": {
|
||||
"pefile": {
|
||||
"hashes": [
|
||||
"sha256:116b808554d7ea75efc97b4cb904085546db45934ef315175cb4755c7a4489de",
|
||||
"sha256:7440ac520bb791e0318e3d99f9b0e76b7b2b604e7160f1d8341ded060f9ff1cd"
|
||||
"sha256:344a49e40a94e10849f0fe34dddc80f773a12b40675bf2f7be4b8be578bdd94a"
|
||||
],
|
||||
"version": "==1.4.0.20220110"
|
||||
},
|
||||
"portend": {
|
||||
"hashes": [
|
||||
"sha256:239e3116045ea823f6df87d6168107ad75ccc0590e37242af0cc1e98c5d224e4",
|
||||
"sha256:9e735cee3a5c1961f09e3f3ba6dc498198c2d70b473d98d0d1504b8d1e7a3d61"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==3.1.0"
|
||||
"markers": "sys_platform == 'win32'",
|
||||
"version": "==2021.9.3"
|
||||
},
|
||||
"prompt-toolkit": {
|
||||
"hashes": [
|
||||
"sha256:4bcf119be2200c17ed0d518872ef922f1de336eb6d1ddbd1e089ceb6447d97c6",
|
||||
"sha256:a51d41a6a45fd9def54365bca8f0402c8f182f2b6f7e29c74d55faeb9fb38ac4"
|
||||
"sha256:cb7dae7d2c59188c85a1d6c944fad19aded6a26bd9c8ae115a4e1c20eb90b713",
|
||||
"sha256:f2b6a8067a4fb959d3677d1ed764cc4e63e0f6f565b9a4fc7edc2b18bf80217b"
|
||||
],
|
||||
"markers": "python_full_version >= '3.6.2'",
|
||||
"version": "==3.0.26"
|
||||
"version": "==3.0.27"
|
||||
},
|
||||
"psutil": {
|
||||
"hashes": [
|
||||
|
@ -715,39 +576,36 @@
|
|||
},
|
||||
"pycryptodomex": {
|
||||
"hashes": [
|
||||
"sha256:00eb17ee2b8eb9d84df37d54bc7070ff45903b90535558c2e0ddb5e6957521d3",
|
||||
"sha256:05b36726ce5521ce0feb25ea11e866261089edd7fad44df4ced9f7f45a9d4c3b",
|
||||
"sha256:110b319189915a66d14df13d233a2dbb54f00df21f3167de1cad340bf4dd88bd",
|
||||
"sha256:15e6f5b4a81109eb8e9a02c954fe119f6c57836fd55a9891ba703ddfbd690587",
|
||||
"sha256:1b07a13ed73d00a97af7c3733b807007d2249cd236a33955a7dec1939c232b28",
|
||||
"sha256:2040a22a30780da743835c7c71307558688065d6c22e18ac3e44082dc3323d8f",
|
||||
"sha256:264a701bb6e8aedf4b71bcb9eb83b93020041e96112ccfe873a16964d41ade74",
|
||||
"sha256:2d8bda8f949b79b78b293706aa7fc1e5c171c62661252bfdd5d12c70acd03282",
|
||||
"sha256:2e2da1eabb426cbeb4922c981bb843f36427f8365ef7e46bc581a55d7ea67643",
|
||||
"sha256:3ad75e24a0e25396901273a9a2aaba0286fa74703e5b61731942f6914a1e1cbe",
|
||||
"sha256:3c06abf17c68cf87c4e81e1745f0afbe4427413684a122a9d044a8a1d3c6d959",
|
||||
"sha256:3c195eecd43e48d0a06267df6945958f5f566eef160a5b01c519434cfa6d368a",
|
||||
"sha256:3c9ee5e77dd9cb19fe09765b6c02e3784cdbd2e5ecfbc67c8e9628073f79b981",
|
||||
"sha256:484ad0f50fd49bec4d2b8c0e5a3ad70e278ed3390bfd5c4515dc896f31b45d6c",
|
||||
"sha256:4b046c3d50fe4bb57386567ff47a588b1bbe1ddf3d9e2b23aede09fa97511f5f",
|
||||
"sha256:50684f16b12f1dcca8018d2711fb87044c74038ce9322d36f6ee9d09fcda7e6f",
|
||||
"sha256:6940b6730bab7128c993b562abf018560aa5b861da92854cf050b5f96d4713df",
|
||||
"sha256:76fe9ad943480507952cd7c96c20f6c8af78145f944cb66bbba63f2872d9988e",
|
||||
"sha256:7bcc5d3904abe5cfac5acc67679e330b0402473e839f94b59e13efdc2c2945d5",
|
||||
"sha256:8310782ac84fa1df93703081af6791549451a380ad88670c2484f75e26c6485f",
|
||||
"sha256:88eb239d6af71ba2098a4cfea516add37881d55b76b38d9e297f77a65bb9a8cf",
|
||||
"sha256:9afea78c31f3714b06673d2c5b8874f31c19c03258645733546a320da2e6df23",
|
||||
"sha256:a11884621c2a5fe241ccf2adf34e4fdde162e91fbc3207f0a0db122ad2b7a061",
|
||||
"sha256:b0277a201196b7825b21a405e0a70167f277b8d5666031e65c9af7a715cb0833",
|
||||
"sha256:b5ff95687c4008f76091849e5333692e6a54a93399cd8fda7e1ba523734136f4",
|
||||
"sha256:c565b89fb91ecb60273b2dcedb5149b48a1ec4227cef8c63fd77ec0f33eaf75a",
|
||||
"sha256:d689b368ca8b3ec1e60cc609eae14d4e352d10fe807ca9906f77f0712ab05a37",
|
||||
"sha256:f3bb1e722ad57de1999c8db54b58507b47771de4a294115c00f785f1d5913ec1",
|
||||
"sha256:fbff384c2080106b3f5f7cfa96728f02e627be7f7cd1657d9cf63300a16d0864",
|
||||
"sha256:fd2657134b633523db551b96b095387083a459d77e93b9cc888c9f13edb7a6f6"
|
||||
"sha256:1ca8e1b4c62038bb2da55451385246f51f412c5f5eabd64812c01766a5989b4a",
|
||||
"sha256:298c00ea41a81a491d5b244d295d18369e5aac4b61b77b2de5b249ca61cd6659",
|
||||
"sha256:2aa887683eee493e015545bd69d3d21ac8d5ad582674ec98f4af84511e353e45",
|
||||
"sha256:2ce76ed0081fd6ac8c74edc75b9d14eca2064173af79843c24fa62573263c1f2",
|
||||
"sha256:3da13c2535b7aea94cc2a6d1b1b37746814c74b6e80790daddd55ca5c120a489",
|
||||
"sha256:406ec8cfe0c098fadb18d597dc2ee6de4428d640c0ccafa453f3d9b2e58d29e2",
|
||||
"sha256:4d0db8df9ffae36f416897ad184608d9d7a8c2b46c4612c6bc759b26c073f750",
|
||||
"sha256:530756d2faa40af4c1f74123e1d889bd07feae45bac2fd32f259a35f7aa74151",
|
||||
"sha256:77931df40bb5ce5e13f4de2bfc982b2ddc0198971fbd947776c8bb5050896eb2",
|
||||
"sha256:797a36bd1f69df9e2798e33edb4bd04e5a30478efc08f9428c087f17f65a7045",
|
||||
"sha256:8085bd0ad2034352eee4d4f3e2da985c2749cb7344b939f4d95ead38c2520859",
|
||||
"sha256:8536bc08d130cae6dcba1ea689f2913dfd332d06113904d171f2f56da6228e89",
|
||||
"sha256:a4d412eba5679ede84b41dbe48b1bed8f33131ab9db06c238a235334733acc5e",
|
||||
"sha256:aebecde2adc4a6847094d3bd6a8a9538ef3438a5ea84ac1983fcb167db614461",
|
||||
"sha256:b276cc4deb4a80f9dfd47a41ebb464b1fe91efd8b1b8620cf5ccf8b824b850d6",
|
||||
"sha256:b5a185ae79f899b01ca49f365bdf15a45d78d9856f09b0de1a41b92afce1a07f",
|
||||
"sha256:c4d8977ccda886d88dc3ca789de2f1adc714df912ff3934b3d0a3f3d777deafb",
|
||||
"sha256:c5dd3ffa663c982d7f1be9eb494a8924f6d40e2e2f7d1d27384cfab1b2ac0662",
|
||||
"sha256:ca88f2f7020002638276439a01ffbb0355634907d1aa5ca91f3dc0c2e44e8f3b",
|
||||
"sha256:d2cce1c82a7845d7e2e8a0956c6b7ed3f1661c9acf18eb120fc71e098ab5c6fe",
|
||||
"sha256:d709572d64825d8d59ea112e11cc7faf6007f294e9951324b7574af4251e4de8",
|
||||
"sha256:da8db8374295fb532b4b0c467e66800ef17d100e4d5faa2bbbd6df35502da125",
|
||||
"sha256:e36c7e3b5382cd5669cf199c4a04a0279a43b2a3bdd77627e9b89778ac9ec08c",
|
||||
"sha256:e95a4a6c54d27a84a4624d2af8bb9ee178111604653194ca6880c98dcad92f48",
|
||||
"sha256:ee835def05622e0c8b1435a906491760a43d0c462f065ec9143ec4b8d79f8bff",
|
||||
"sha256:f75009715dcf4a3d680c2338ab19dac5498f8121173a929872950f4fb3a48fbf",
|
||||
"sha256:f8524b8bc89470cec7ac51734907818d3620fb1637f8f8b542d650ebec42a126"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==3.14.0"
|
||||
"version": "==3.14.1"
|
||||
},
|
||||
"pyinstaller": {
|
||||
"hashes": [
|
||||
|
@ -871,20 +729,30 @@
|
|||
"markers": "python_version >= '3.6'",
|
||||
"version": "==0.3.1"
|
||||
},
|
||||
"python-dateutil": {
|
||||
"pywin32": {
|
||||
"hashes": [
|
||||
"sha256:7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb",
|
||||
"sha256:c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e"
|
||||
"sha256:2a09632916b6bb231ba49983fe989f2f625cea237219530e81a69239cd0c4559",
|
||||
"sha256:51cb52c5ec6709f96c3f26e7795b0bf169ee0d8395b2c1d7eb2c029a5008ed51",
|
||||
"sha256:5f9ec054f5a46a0f4dfd72af2ce1372f3d5a6e4052af20b858aa7df2df7d355b",
|
||||
"sha256:6fed4af057039f309263fd3285d7b8042d41507343cd5fa781d98fcc5b90e8bb",
|
||||
"sha256:793bf74fce164bcffd9d57bb13c2c15d56e43c9542a7b9687b4fccf8f8a41aba",
|
||||
"sha256:79cbb862c11b9af19bcb682891c1b91942ec2ff7de8151e2aea2e175899cda34",
|
||||
"sha256:7d3271c98434617a11921c5ccf74615794d97b079e22ed7773790822735cc352",
|
||||
"sha256:aad484d52ec58008ca36bd4ad14a71d7dd0a99db1a4ca71072213f63bf49c7d9",
|
||||
"sha256:b1675d82bcf6dbc96363fca747bac8bff6f6e4a447a4287ac652aa4b9adc796e",
|
||||
"sha256:c268040769b48a13367221fced6d4232ed52f044ffafeda247bd9d2c6bdc29ca",
|
||||
"sha256:d9b5d87ca944eb3aa4cd45516203ead4b37ab06b8b777c54aedc35975dec0dee",
|
||||
"sha256:fcf44032f5b14fcda86028cdf49b6ebdaea091230eb0a757282aa656e4732439"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.8.0"
|
||||
"version": "==303"
|
||||
},
|
||||
"pytz": {
|
||||
"pywin32-ctypes": {
|
||||
"hashes": [
|
||||
"sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c",
|
||||
"sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"
|
||||
"sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942",
|
||||
"sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"
|
||||
],
|
||||
"version": "==2021.3"
|
||||
"markers": "sys_platform == 'win32'",
|
||||
"version": "==0.2.0"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
|
@ -894,18 +762,6 @@
|
|||
"index": "pypi",
|
||||
"version": "==2.27.1"
|
||||
},
|
||||
"s3transfer": {
|
||||
"hashes": [
|
||||
"sha256:25c140f5c66aa79e1ac60be50dcd45ddc59e83895f062a3aab263b870102911f",
|
||||
"sha256:69d264d3e760e569b78aaa0f22c97e955891cd22e32b10c51f784eeda4d9d10a"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==0.5.1"
|
||||
},
|
||||
"scoutsuite": {
|
||||
"git": "git://github.com/guardicode/ScoutSuite",
|
||||
"ref": "eac33ac5b0a84e4a2e29682cf3568271eb595003"
|
||||
},
|
||||
"service-identity": {
|
||||
"hashes": [
|
||||
"sha256:6e6c6086ca271dc11b033d17c3a8bea9f24ebff920c587da090afc9519419d34",
|
||||
|
@ -929,20 +785,6 @@
|
|||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.16.0"
|
||||
},
|
||||
"sqlitedict": {
|
||||
"hashes": [
|
||||
"sha256:2affcc301aacd4da7511692601ecbde392294205af418498f7d6d3ec0dbcad56"
|
||||
],
|
||||
"version": "==1.7.0"
|
||||
},
|
||||
"tempora": {
|
||||
"hashes": [
|
||||
"sha256:cba0f197a64883bf3e73657efbc0324d5bf17179e7769b1385b4d75d26cd9127",
|
||||
"sha256:fbca6a229af666ea4ea8b2f9f80ac9a074f7cf53a97987855b1d15b6e93fd63b"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==5.0.1"
|
||||
},
|
||||
"tqdm": {
|
||||
"hashes": [
|
||||
"sha256:8dd278a422499cd6b727e6ae4061c40b48fce8b76d1ccbf5d34fca9b7f925b0c",
|
||||
|
@ -956,11 +798,29 @@
|
|||
"tls"
|
||||
],
|
||||
"hashes": [
|
||||
"sha256:13c1d1d2421ae556d91e81e66cf0d4f4e4e1e4a36a0486933bee4305c6a4fb9b",
|
||||
"sha256:2cd652542463277378b0d349f47c62f20d9306e57d1247baabd6d1d38a109006"
|
||||
"sha256:b7971ec9805b0f80e1dcb1a3721d7bfad636d5f909de687430ce373979d67b61",
|
||||
"sha256:ccd638110d9ccfdc003042aa3e1b6d6af272eaca45d36e083359560549e3e848"
|
||||
],
|
||||
"markers": "python_full_version >= '3.6.7'",
|
||||
"version": "==21.7.0"
|
||||
"version": "==22.1.0"
|
||||
},
|
||||
"twisted-iocpsupport": {
|
||||
"hashes": [
|
||||
"sha256:306becd6e22ab6e8e4f36b6bdafd9c92e867c98a5ce517b27fdd27760ee7ae41",
|
||||
"sha256:3c61742cb0bc6c1ac117a7e5f422c129832f0c295af49e01d8a6066df8cfc04d",
|
||||
"sha256:72068b206ee809c9c596b57b5287259ea41ddb4774d86725b19f35bf56aa32a9",
|
||||
"sha256:7d972cfa8439bdcb35a7be78b7ef86d73b34b808c74be56dfa785c8a93b851bf",
|
||||
"sha256:81b3abe3527b367da0220482820cb12a16c661672b7bcfcde328902890d63323",
|
||||
"sha256:851b3735ca7e8102e661872390e3bce88f8901bece95c25a0c8bb9ecb8a23d32",
|
||||
"sha256:985c06a33f5c0dae92c71a036d1ea63872ee86a21dd9b01e1f287486f15524b4",
|
||||
"sha256:9dbb8823b49f06d4de52721b47de4d3b3026064ef4788ce62b1a21c57c3fff6f",
|
||||
"sha256:b435857b9efcbfc12f8c326ef0383f26416272260455bbca2cd8d8eca470c546",
|
||||
"sha256:b76b4eed9b27fd63ddb0877efdd2d15835fdcb6baa745cb85b66e5d016ac2878",
|
||||
"sha256:b9fed67cf0f951573f06d560ac2f10f2a4bbdc6697770113a2fc396ea2cb2565",
|
||||
"sha256:bf4133139d77fc706d8f572e6b7d82871d82ec7ef25d685c2351bdacfb701415"
|
||||
],
|
||||
"markers": "platform_system == 'Windows'",
|
||||
"version": "==1.0.2"
|
||||
},
|
||||
"typing-extensions": {
|
||||
"hashes": [
|
||||
|
@ -987,11 +847,11 @@
|
|||
},
|
||||
"werkzeug": {
|
||||
"hashes": [
|
||||
"sha256:63d3dc1cf60e7b7e35e97fa9861f7397283b75d765afcaefd993d6046899de8f",
|
||||
"sha256:aa2bb6fc8dee8d6c504c0ac1e7f5f7dc5810a9903e793b6f715a9f015bdadb9a"
|
||||
"sha256:1421ebfc7648a39a5c58c601b154165d05cf47a3cd0ccb70857cbdacf6c8f2b8",
|
||||
"sha256:b863f8ff057c522164b6067c9e28b041161b4be5ba4d0daceeaa50a163822d3c"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.0.2"
|
||||
"version": "==2.0.3"
|
||||
},
|
||||
"winacl": {
|
||||
"hashes": [
|
||||
|
@ -1021,16 +881,10 @@
|
|||
"sha256:1d6b085e5c445141c475476000b661f60fff1aaa19f76bf82b7abb92e0ff4942",
|
||||
"sha256:b6a6be5711b1b6c8d55bda7a8befd75c48c12b770b9d227d31c1737dbf0d40a6"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "sys_platform == 'win32'",
|
||||
"version": "==1.5.1"
|
||||
},
|
||||
"zc.lockfile": {
|
||||
"hashes": [
|
||||
"sha256:307ad78227e48be260e64896ec8886edc7eae22d8ec53e4d528ab5537a83203b",
|
||||
"sha256:cc33599b549f0c8a248cb72f3bf32d77712de1ff7ee8814312eb6456b42c015f"
|
||||
],
|
||||
"version": "==2.0"
|
||||
},
|
||||
"zipp": {
|
||||
"hashes": [
|
||||
"sha256:9f50f446828eb9d45b267433fd3e9da8d801f614129124863f9c51ebceafb87d",
|
||||
|
|
|
@ -5,13 +5,10 @@ import sys
|
|||
|
||||
|
||||
|
||||
from PyInstaller.utils.hooks import collect_data_files
|
||||
|
||||
block_cipher = None
|
||||
|
||||
|
||||
def main():
|
||||
print(collect_data_files('policyuniverse'))
|
||||
a = Analysis(['main.py'],
|
||||
pathex=['..'],
|
||||
hiddenimports=get_hidden_imports(),
|
||||
|
|
|
@ -4,9 +4,7 @@ import socket
|
|||
import struct
|
||||
import sys
|
||||
|
||||
from common.network.network_utils import get_host_from_network_location
|
||||
from infection_monkey.config import WormConfiguration
|
||||
from infection_monkey.network.info import get_routes, local_ips
|
||||
from infection_monkey.network.info import get_routes
|
||||
|
||||
DEFAULT_TIMEOUT = 10
|
||||
BANNER_READ = 1024
|
||||
|
@ -117,13 +115,3 @@ def get_interface_to_target(dst):
|
|||
paths.sort()
|
||||
ret = paths[-1][1]
|
||||
return ret[1]
|
||||
|
||||
|
||||
def is_running_on_island():
|
||||
current_server_without_port = get_host_from_network_location(WormConfiguration.current_server)
|
||||
running_on_island = is_running_on_server(current_server_without_port)
|
||||
return running_on_island and WormConfiguration.depth == WormConfiguration.max_depth
|
||||
|
||||
|
||||
def is_running_on_server(ip: str) -> bool:
|
||||
return ip in local_ips()
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
import logging
|
||||
|
||||
from common.cloud.aws.aws_instance import AwsInstance
|
||||
from common.cloud.scoutsuite_consts import CloudProviders
|
||||
from common.common_consts.system_info_collectors_names import AWS_COLLECTOR
|
||||
from infection_monkey.network.tools import is_running_on_island
|
||||
from infection_monkey.system_info.collectors.scoutsuite_collector.scoutsuite_collector import (
|
||||
scan_cloud_security,
|
||||
)
|
||||
from infection_monkey.system_info.system_info_collector import SystemInfoCollector
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -22,11 +17,6 @@ class AwsCollector(SystemInfoCollector):
|
|||
|
||||
def collect(self) -> dict:
|
||||
logger.info("Collecting AWS info")
|
||||
if is_running_on_island():
|
||||
logger.info("Attempting to scan AWS security with ScoutSuite.")
|
||||
scan_cloud_security(cloud_type=CloudProviders.AWS)
|
||||
else:
|
||||
logger.info("Didn't scan AWS security with ScoutSuite, because not on island.")
|
||||
aws = AwsInstance()
|
||||
info = {}
|
||||
if aws.is_instance():
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
import logging
|
||||
from typing import Union
|
||||
|
||||
import ScoutSuite.api_run
|
||||
from ScoutSuite.providers.base.provider import BaseProvider
|
||||
|
||||
from common.cloud.scoutsuite_consts import CloudProviders
|
||||
from common.utils.exceptions import ScoutSuiteScanError
|
||||
from infection_monkey.config import WormConfiguration
|
||||
from infection_monkey.telemetry.scoutsuite_telem import ScoutSuiteTelem
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def scan_cloud_security(cloud_type: CloudProviders):
|
||||
try:
|
||||
results = run_scoutsuite(cloud_type.value)
|
||||
if isinstance(results, dict) and "error" in results and results["error"]:
|
||||
raise ScoutSuiteScanError(results["error"])
|
||||
send_scoutsuite_run_results(results)
|
||||
except (Exception, ScoutSuiteScanError) as e:
|
||||
logger.error(f"ScoutSuite didn't scan {cloud_type.value} security because: {e}")
|
||||
|
||||
|
||||
def run_scoutsuite(cloud_type: str) -> Union[BaseProvider, dict]:
|
||||
return ScoutSuite.api_run.run(
|
||||
provider=cloud_type,
|
||||
aws_access_key_id=WormConfiguration.aws_access_key_id,
|
||||
aws_secret_access_key=WormConfiguration.aws_secret_access_key,
|
||||
aws_session_token=WormConfiguration.aws_session_token,
|
||||
)
|
||||
|
||||
|
||||
def send_scoutsuite_run_results(run_results: BaseProvider):
|
||||
ScoutSuiteTelem(run_results).send()
|
|
@ -1,17 +0,0 @@
|
|||
from ScoutSuite.output.result_encoder import ScoutJsonEncoder
|
||||
from ScoutSuite.providers.base.provider import BaseProvider
|
||||
|
||||
from common.common_consts.telem_categories import TelemCategoryEnum
|
||||
from infection_monkey.telemetry.base_telem import BaseTelem
|
||||
|
||||
|
||||
class ScoutSuiteTelem(BaseTelem):
|
||||
def __init__(self, provider: BaseProvider):
|
||||
super().__init__()
|
||||
self.provider_data = provider
|
||||
|
||||
json_encoder = ScoutJsonEncoder
|
||||
telem_category = TelemCategoryEnum.SCOUTSUITE
|
||||
|
||||
def get_data(self):
|
||||
return {"data": self.provider_data}
|
|
@ -22,7 +22,6 @@ Flask-PyMongo = ">=2.3.0"
|
|||
Flask-RESTful = ">=0.3.8"
|
||||
Flask = ">=1.1"
|
||||
Werkzeug = ">=1.0.1"
|
||||
ScoutSuite = {git = "https://github.com/guardicode/ScoutSuite"}
|
||||
pyaescrypt = "*"
|
||||
python-dateutil = "*"
|
||||
cffi = "*" # Without explicit install: ModuleNotFoundError: No module named '_cffi_backend'
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -46,8 +46,6 @@ from monkey_island.cc.resources.telemetry import Telemetry
|
|||
from monkey_island.cc.resources.telemetry_feed import TelemetryFeed
|
||||
from monkey_island.cc.resources.version_update import VersionUpdate
|
||||
from monkey_island.cc.resources.zero_trust.finding_event import ZeroTrustFindingEvent
|
||||
from monkey_island.cc.resources.zero_trust.scoutsuite_auth.aws_keys import AWSKeys
|
||||
from monkey_island.cc.resources.zero_trust.scoutsuite_auth.scoutsuite_auth import ScoutSuiteAuth
|
||||
from monkey_island.cc.resources.zero_trust.zero_trust_report import ZeroTrustReport
|
||||
from monkey_island.cc.server_utils.consts import MONKEY_ISLAND_ABS_PATH
|
||||
from monkey_island.cc.server_utils.custom_json_encoder import CustomJSONEncoder
|
||||
|
@ -168,8 +166,6 @@ def init_api_resources(api):
|
|||
api.add_resource(VersionUpdate, "/api/version-update")
|
||||
api.add_resource(StopAgentCheck, "/api/monkey_control/needs-to-stop/<int:monkey_guid>")
|
||||
api.add_resource(StopAllAgents, "/api/monkey_control/stop-all-agents")
|
||||
api.add_resource(ScoutSuiteAuth, "/api/scoutsuite_auth/<string:provider>")
|
||||
api.add_resource(AWSKeys, "/api/aws_keys")
|
||||
|
||||
# Resources used by black box tests
|
||||
api.add_resource(MonkeyBlackboxEndpoint, "/api/test/monkey")
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
from mongoengine import Document, DynamicField
|
||||
|
||||
|
||||
class ScoutSuiteRawDataJson(Document):
|
||||
"""
|
||||
This model is a container for ScoutSuite report data dump.
|
||||
"""
|
||||
|
||||
# SCHEMA
|
||||
scoutsuite_data = DynamicField(required=True)
|
||||
|
||||
# LOGIC
|
||||
@staticmethod
|
||||
def add_scoutsuite_data(scoutsuite_data: str) -> None:
|
||||
try:
|
||||
current_data = ScoutSuiteRawDataJson.objects()[0]
|
||||
except IndexError:
|
||||
current_data = ScoutSuiteRawDataJson()
|
||||
current_data.scoutsuite_data = scoutsuite_data
|
||||
current_data.save()
|
|
@ -1,20 +0,0 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from mongoengine import LazyReferenceField
|
||||
|
||||
from monkey_island.cc.models.zero_trust.finding import Finding
|
||||
from monkey_island.cc.models.zero_trust.scoutsuite_finding_details import ScoutSuiteFindingDetails
|
||||
|
||||
|
||||
class ScoutSuiteFinding(Finding):
|
||||
# We put additional info into a lazy reference field, because this info should be only
|
||||
# pulled when explicitly needed due to performance
|
||||
details = LazyReferenceField(ScoutSuiteFindingDetails, required=True)
|
||||
|
||||
@staticmethod
|
||||
def save_finding(
|
||||
test: str, status: str, detail_ref: ScoutSuiteFindingDetails
|
||||
) -> ScoutSuiteFinding:
|
||||
finding = ScoutSuiteFinding(test=test, status=status, details=detail_ref)
|
||||
finding.save()
|
||||
return finding
|
|
@ -1,13 +0,0 @@
|
|||
from mongoengine import Document, EmbeddedDocumentListField
|
||||
|
||||
from monkey_island.cc.models.zero_trust.scoutsuite_rule import ScoutSuiteRule
|
||||
|
||||
|
||||
class ScoutSuiteFindingDetails(Document):
|
||||
# SCHEMA
|
||||
scoutsuite_rules = EmbeddedDocumentListField(document_type=ScoutSuiteRule, required=False)
|
||||
|
||||
def add_rule(self, rule: ScoutSuiteRule) -> None:
|
||||
if rule not in self.scoutsuite_rules:
|
||||
self.scoutsuite_rules.append(rule)
|
||||
self.save()
|
|
@ -1,25 +0,0 @@
|
|||
from mongoengine import DynamicField, EmbeddedDocument, IntField, ListField, StringField
|
||||
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts import rule_consts
|
||||
|
||||
|
||||
class ScoutSuiteRule(EmbeddedDocument):
|
||||
"""
|
||||
This model represents ScoutSuite security rule check results:
|
||||
how many resources break the security rule
|
||||
security rule description and remediation and etc.
|
||||
"""
|
||||
|
||||
# SCHEMA
|
||||
description = StringField(required=True)
|
||||
path = StringField(required=True)
|
||||
level = StringField(required=True, options=rule_consts.RULE_LEVELS)
|
||||
items = ListField()
|
||||
dashboard_name = StringField(required=True)
|
||||
checked_items = IntField(min_value=0)
|
||||
flagged_items = IntField(min_value=0)
|
||||
service = StringField(required=True)
|
||||
rationale = StringField(required=True)
|
||||
remediation = StringField(required=False)
|
||||
compliance = DynamicField(required=False)
|
||||
references = ListField(required=False)
|
|
@ -1,10 +0,0 @@
|
|||
import flask_restful
|
||||
|
||||
from monkey_island.cc.resources.auth.auth import jwt_required
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.scoutsuite_auth_service import get_aws_keys
|
||||
|
||||
|
||||
class AWSKeys(flask_restful.Resource):
|
||||
@jwt_required
|
||||
def get(self):
|
||||
return get_aws_keys()
|
|
@ -1,37 +0,0 @@
|
|||
import json
|
||||
|
||||
import flask_restful
|
||||
from flask import request
|
||||
|
||||
from common.cloud.scoutsuite_consts import CloudProviders
|
||||
from common.utils.exceptions import InvalidAWSKeys
|
||||
from monkey_island.cc.resources.auth.auth import jwt_required
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.scoutsuite_auth_service import (
|
||||
is_cloud_authentication_setup,
|
||||
set_aws_keys,
|
||||
)
|
||||
|
||||
|
||||
class ScoutSuiteAuth(flask_restful.Resource):
|
||||
@jwt_required
|
||||
def get(self, provider: CloudProviders):
|
||||
if provider == CloudProviders.AWS.value:
|
||||
is_setup, message = is_cloud_authentication_setup(provider)
|
||||
return {"is_setup": is_setup, "message": message}
|
||||
else:
|
||||
return {"is_setup": False, "message": ""}
|
||||
|
||||
@jwt_required
|
||||
def post(self, provider: CloudProviders):
|
||||
key_info = json.loads(request.data)
|
||||
error_msg = ""
|
||||
if provider == CloudProviders.AWS.value:
|
||||
try:
|
||||
set_aws_keys(
|
||||
access_key_id=key_info["accessKeyId"],
|
||||
secret_access_key=key_info["secretAccessKey"],
|
||||
session_token=key_info["sessionToken"],
|
||||
)
|
||||
except InvalidAWSKeys as e:
|
||||
error_msg = str(e)
|
||||
return {"error_msg": error_msg}
|
|
@ -1,7 +1,7 @@
|
|||
import http.client
|
||||
|
||||
import flask_restful
|
||||
from flask import Response, jsonify
|
||||
from flask import jsonify
|
||||
|
||||
from monkey_island.cc.resources.auth.auth import jwt_required
|
||||
from monkey_island.cc.services.zero_trust.zero_trust_report.finding_service import FindingService
|
||||
|
@ -9,14 +9,10 @@ from monkey_island.cc.services.zero_trust.zero_trust_report.pillar_service impor
|
|||
from monkey_island.cc.services.zero_trust.zero_trust_report.principle_service import (
|
||||
PrincipleService,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.zero_trust_report.scoutsuite_raw_data_service import (
|
||||
ScoutSuiteRawDataService,
|
||||
)
|
||||
|
||||
REPORT_DATA_PILLARS = "pillars"
|
||||
REPORT_DATA_FINDINGS = "findings"
|
||||
REPORT_DATA_PRINCIPLES_STATUS = "principles"
|
||||
REPORT_DATA_SCOUTSUITE = "scoutsuite"
|
||||
|
||||
|
||||
class ZeroTrustReport(flask_restful.Resource):
|
||||
|
@ -28,10 +24,5 @@ class ZeroTrustReport(flask_restful.Resource):
|
|||
return jsonify(PrincipleService.get_principles_status())
|
||||
elif report_data == REPORT_DATA_FINDINGS:
|
||||
return jsonify(FindingService.get_all_findings_for_ui())
|
||||
elif report_data == REPORT_DATA_SCOUTSUITE:
|
||||
# Raw ScoutSuite data is already solved as json, no need to jsonify
|
||||
return Response(
|
||||
ScoutSuiteRawDataService.get_scoutsuite_data_json(), mimetype="application/json"
|
||||
)
|
||||
|
||||
flask_restful.abort(http.client.NOT_FOUND)
|
||||
|
|
|
@ -4,7 +4,6 @@ from common.common_consts.telem_categories import TelemCategoryEnum
|
|||
from monkey_island.cc.services.telemetry.processing.exploit import process_exploit_telemetry
|
||||
from monkey_island.cc.services.telemetry.processing.post_breach import process_post_breach_telemetry
|
||||
from monkey_island.cc.services.telemetry.processing.scan import process_scan_telemetry
|
||||
from monkey_island.cc.services.telemetry.processing.scoutsuite import process_scoutsuite_telemetry
|
||||
from monkey_island.cc.services.telemetry.processing.state import process_state_telemetry
|
||||
from monkey_island.cc.services.telemetry.processing.system_info import process_system_info_telemetry
|
||||
from monkey_island.cc.services.telemetry.processing.tunnel import process_tunnel_telemetry
|
||||
|
@ -18,7 +17,6 @@ TELEMETRY_CATEGORY_TO_PROCESSING_FUNC = {
|
|||
TelemCategoryEnum.SCAN: process_scan_telemetry,
|
||||
TelemCategoryEnum.SYSTEM_INFO: process_system_info_telemetry,
|
||||
TelemCategoryEnum.POST_BREACH: process_post_breach_telemetry,
|
||||
TelemCategoryEnum.SCOUTSUITE: process_scoutsuite_telemetry,
|
||||
# `lambda *args, **kwargs: None` is a no-op.
|
||||
TelemCategoryEnum.TRACE: lambda *args, **kwargs: None,
|
||||
TelemCategoryEnum.ATTACK: lambda *args, **kwargs: None,
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
import json
|
||||
|
||||
from monkey_island.cc.database import mongo
|
||||
from monkey_island.cc.models.zero_trust.scoutsuite_data_json import ScoutSuiteRawDataJson
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.scoutsuite_findings_list import (
|
||||
SCOUTSUITE_FINDINGS,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import SERVICES
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_parser import RuleParser
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.scoutsuite_rule_service import (
|
||||
ScoutSuiteRuleService,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.scoutsuite_zt_finding_service import (
|
||||
ScoutSuiteZTFindingService,
|
||||
)
|
||||
|
||||
|
||||
def process_scoutsuite_telemetry(telemetry_json):
|
||||
# Encode data to json, because mongo can't save it as document (invalid document keys)
|
||||
telemetry_json["data"] = json.dumps(telemetry_json["data"])
|
||||
ScoutSuiteRawDataJson.add_scoutsuite_data(telemetry_json["data"])
|
||||
scoutsuite_data = json.loads(telemetry_json["data"])["data"]
|
||||
create_scoutsuite_findings(scoutsuite_data[SERVICES])
|
||||
update_data(telemetry_json)
|
||||
|
||||
|
||||
def create_scoutsuite_findings(cloud_services: dict):
|
||||
for finding in SCOUTSUITE_FINDINGS:
|
||||
for rule in finding.rules:
|
||||
rule_data = RuleParser.get_rule_data(cloud_services, rule)
|
||||
rule = ScoutSuiteRuleService.get_rule_from_rule_data(rule_data)
|
||||
ScoutSuiteZTFindingService.process_rule(finding, rule)
|
||||
|
||||
|
||||
def update_data(telemetry_json):
|
||||
mongo.db.scoutsuite.insert_one(
|
||||
{"guid": telemetry_json["monkey_guid"]}, {"results": telemetry_json["data"]}
|
||||
)
|
|
@ -1,4 +0,0 @@
|
|||
RULE_LEVEL_DANGER = "danger"
|
||||
RULE_LEVEL_WARNING = "warning"
|
||||
|
||||
RULE_LEVELS = (RULE_LEVEL_DANGER, RULE_LEVEL_WARNING)
|
|
@ -1,8 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.rule_name_enum import (
|
||||
RuleNameEnum,
|
||||
)
|
||||
|
||||
|
||||
class CloudformationRules(RuleNameEnum):
|
||||
# Service Security
|
||||
CLOUDFORMATION_STACK_WITH_ROLE = "cloudformation-stack-with-role"
|
|
@ -1,13 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.rule_name_enum import (
|
||||
RuleNameEnum,
|
||||
)
|
||||
|
||||
|
||||
class CloudTrailRules(RuleNameEnum):
|
||||
# Logging
|
||||
CLOUDTRAIL_DUPLICATED_GLOBAL_SERVICES_LOGGING = "cloudtrail-duplicated-global-services-logging"
|
||||
CLOUDTRAIL_NO_DATA_LOGGING = "cloudtrail-no-data-logging"
|
||||
CLOUDTRAIL_NO_GLOBAL_SERVICES_LOGGING = "cloudtrail-no-global-services-logging"
|
||||
CLOUDTRAIL_NO_LOG_FILE_VALIDATION = "cloudtrail-no-log-file-validation"
|
||||
CLOUDTRAIL_NO_LOGGING = "cloudtrail-no-logging"
|
||||
CLOUDTRAIL_NOT_CONFIGURED = "cloudtrail-not-configured"
|
|
@ -1,8 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.rule_name_enum import (
|
||||
RuleNameEnum,
|
||||
)
|
||||
|
||||
|
||||
class CloudWatchRules(RuleNameEnum):
|
||||
# Logging
|
||||
CLOUDWATCH_ALARM_WITHOUT_ACTIONS = "cloudwatch-alarm-without-actions"
|
|
@ -1,8 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.rule_name_enum import (
|
||||
RuleNameEnum,
|
||||
)
|
||||
|
||||
|
||||
class ConfigRules(RuleNameEnum):
|
||||
# Logging
|
||||
CONFIG_RECORDER_NOT_CONFIGURED = "config-recorder-not-configured"
|
|
@ -1,37 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.rule_name_enum import (
|
||||
RuleNameEnum,
|
||||
)
|
||||
|
||||
|
||||
class EC2Rules(RuleNameEnum):
|
||||
# Permissive firewall rules
|
||||
SECURITY_GROUP_ALL_PORTS_TO_ALL = "ec2-security-group-opens-all-ports-to-all"
|
||||
SECURITY_GROUP_OPENS_TCP_PORT_TO_ALL = "ec2-security-group-opens-TCP-port-to-all"
|
||||
SECURITY_GROUP_OPENS_UDP_PORT_TO_ALL = "ec2-security-group-opens-UDP-port-to-all"
|
||||
SECURITY_GROUP_OPENS_RDP_PORT_TO_ALL = "ec2-security-group-opens-RDP-port-to-all"
|
||||
SECURITY_GROUP_OPENS_SSH_PORT_TO_ALL = "ec2-security-group-opens-SSH-port-to-all"
|
||||
SECURITY_GROUP_OPENS_MYSQL_PORT_TO_ALL = "ec2-security-group-opens-MySQL-port-to-all"
|
||||
SECURITY_GROUP_OPENS_MSSQL_PORT_TO_ALL = "ec2-security-group-opens-MsSQL-port-to-all"
|
||||
SECURITY_GROUP_OPENS_MONGODB_PORT_TO_ALL = "ec2-security-group-opens-MongoDB-port-to-all"
|
||||
SECURITY_GROUP_OPENS_ORACLE_DB_PORT_TO_ALL = "ec2-security-group-opens-Oracle DB-port-to-all"
|
||||
SECURITY_GROUP_OPENS_POSTGRESQL_PORT_TO_ALL = "ec2-security-group-opens-PostgreSQL-port-to-all"
|
||||
SECURITY_GROUP_OPENS_NFS_PORT_TO_ALL = "ec2-security-group-opens-NFS-port-to-all"
|
||||
SECURITY_GROUP_OPENS_SMTP_PORT_TO_ALL = "ec2-security-group-opens-SMTP-port-to-all"
|
||||
SECURITY_GROUP_OPENS_DNS_PORT_TO_ALL = "ec2-security-group-opens-DNS-port-to-all"
|
||||
SECURITY_GROUP_OPENS_ALL_PORTS_TO_SELF = "ec2-security-group-opens-all-ports-to-self"
|
||||
SECURITY_GROUP_OPENS_ALL_PORTS = "ec2-security-group-opens-all-ports"
|
||||
SECURITY_GROUP_OPENS_PLAINTEXT_PORT_FTP = "ec2-security-group-opens-plaintext-port-FTP"
|
||||
SECURITY_GROUP_OPENS_PLAINTEXT_PORT_TELNET = "ec2-security-group-opens-plaintext-port-Telnet"
|
||||
SECURITY_GROUP_OPENS_PORT_RANGE = "ec2-security-group-opens-port-range"
|
||||
EC2_SECURITY_GROUP_WHITELISTS_AWS = "ec2-security-group-whitelists-aws"
|
||||
|
||||
# Encryption
|
||||
EBS_SNAPSHOT_NOT_ENCRYPTED = "ec2-ebs-snapshot-not-encrypted"
|
||||
EBS_VOLUME_NOT_ENCRYPTED = "ec2-ebs-volume-not-encrypted"
|
||||
EC2_INSTANCE_WITH_USER_DATA_SECRETS = "ec2-instance-with-user-data-secrets"
|
||||
|
||||
# Permissive policies
|
||||
AMI_PUBLIC = "ec2-ami-public"
|
||||
EC2_DEFAULT_SECURITY_GROUP_IN_USE = "ec2-default-security-group-in-use"
|
||||
EC2_DEFAULT_SECURITY_GROUP_WITH_RULES = "ec2-default-security-group-with-rules"
|
||||
EC2_EBS_SNAPSHOT_PUBLIC = "ec2-ebs-snapshot-public"
|
|
@ -1,12 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.rule_name_enum import (
|
||||
RuleNameEnum,
|
||||
)
|
||||
|
||||
|
||||
class ELBRules(RuleNameEnum):
|
||||
# Logging
|
||||
ELB_NO_ACCESS_LOGS = "elb-no-access-logs"
|
||||
|
||||
# Encryption
|
||||
ELB_LISTENER_ALLOWING_CLEARTEXT = "elb-listener-allowing-cleartext"
|
||||
ELB_OLDER_SSL_POLICY = "elb-older-ssl-policy"
|
|
@ -1,18 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.rule_name_enum import (
|
||||
RuleNameEnum,
|
||||
)
|
||||
|
||||
|
||||
class ELBv2Rules(RuleNameEnum):
|
||||
# Encryption
|
||||
ELBV2_LISTENER_ALLOWING_CLEARTEXT = "elbv2-listener-allowing-cleartext"
|
||||
ELBV2_OLDER_SSL_POLICY = "elbv2-older-ssl-policy"
|
||||
|
||||
# Logging
|
||||
ELBV2_NO_ACCESS_LOGS = "elbv2-no-access-logs"
|
||||
|
||||
# Data loss prevention
|
||||
ELBV2_NO_DELETION_PROTECTION = "elbv2-no-deletion-protection"
|
||||
|
||||
# Service security
|
||||
ELBV2_HTTP_REQUEST_SMUGGLING = "elbv2-http-request-smuggling"
|
|
@ -1,41 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.rule_name_enum import (
|
||||
RuleNameEnum,
|
||||
)
|
||||
|
||||
|
||||
class IAMRules(RuleNameEnum):
|
||||
# Authentication/authorization
|
||||
IAM_USER_NO_ACTIVE_KEY_ROTATION = "iam-user-no-Active-key-rotation"
|
||||
IAM_PASSWORD_POLICY_MINIMUM_LENGTH = "iam-password-policy-minimum-length"
|
||||
IAM_PASSWORD_POLICY_NO_EXPIRATION = "iam-password-policy-no-expiration"
|
||||
IAM_PASSWORD_POLICY_REUSE_ENABLED = "iam-password-policy-reuse-enabled"
|
||||
IAM_USER_WITH_PASSWORD_AND_KEY = "iam-user-with-password-and-key"
|
||||
IAM_ASSUME_ROLE_LACKS_EXTERNAL_ID_AND_MFA = "iam-assume-role-lacks-external-id-and-mfa"
|
||||
IAM_USER_WITHOUT_MFA = "iam-user-without-mfa"
|
||||
IAM_ROOT_ACCOUNT_NO_MFA = "iam-root-account-no-mfa"
|
||||
IAM_ROOT_ACCOUNT_WITH_ACTIVE_KEYS = "iam-root-account-with-active-keys"
|
||||
IAM_USER_NO_INACTIVE_KEY_ROTATION = "iam-user-no-Inactive-key-rotation"
|
||||
IAM_USER_WITH_MULTIPLE_ACCESS_KEYS = "iam-user-with-multiple-access-keys"
|
||||
|
||||
# Least privilege
|
||||
IAM_ASSUME_ROLE_POLICY_ALLOWS_ALL = "iam-assume-role-policy-allows-all"
|
||||
IAM_EC2_ROLE_WITHOUT_INSTANCES = "iam-ec2-role-without-instances"
|
||||
IAM_GROUP_WITH_INLINE_POLICIES = "iam-group-with-inline-policies"
|
||||
IAM_GROUP_WITH_NO_USERS = "iam-group-with-no-users"
|
||||
IAM_INLINE_GROUP_POLICY_ALLOWS_IAM_PASSROLE = "iam-inline-group-policy-allows-iam-PassRole"
|
||||
IAM_INLINE_GROUP_POLICY_ALLOWS_NOTACTIONS = "iam-inline-group-policy-allows-NotActions"
|
||||
IAM_INLINE_GROUP_POLICY_ALLOWS_STS_ASSUMEROLE = "iam-inline-group-policy-allows-sts-AssumeRole"
|
||||
IAM_INLINE_ROLE_POLICY_ALLOWS_IAM_PASSROLE = "iam-inline-role-policy-allows-iam-PassRole"
|
||||
IAM_INLINE_ROLE_POLICY_ALLOWS_NOTACTIONS = "iam-inline-role-policy-allows-NotActions"
|
||||
IAM_INLINE_ROLE_POLICY_ALLOWS_STS_ASSUMEROLE = "iam-inline-role-policy-allows-sts-AssumeRole"
|
||||
IAM_INLINE_USER_POLICY_ALLOWS_IAM_PASSROLE = "iam-inline-user-policy-allows-iam-PassRole"
|
||||
IAM_INLINE_USER_POLICY_ALLOWS_NOTACTIONS = "iam-inline-user-policy-allows-NotActions"
|
||||
IAM_INLINE_USER_POLICY_ALLOWS_STS_ASSUMEROLE = "iam-inline-user-policy-allows-sts-AssumeRole"
|
||||
IAM_MANAGED_POLICY_ALLOWS_IAM_PASSROLE = "iam-managed-policy-allows-iam-PassRole"
|
||||
IAM_MANAGED_POLICY_ALLOWS_NOTACTIONS = "iam-managed-policy-allows-NotActions"
|
||||
IAM_MANAGED_POLICY_ALLOWS_STS_ASSUMEROLE = "iam-managed-policy-allows-sts-AssumeRole"
|
||||
IAM_MANAGED_POLICY_NO_ATTACHMENTS = "iam-managed-policy-no-attachments"
|
||||
IAM_ROLE_WITH_INLINE_POLICIES = "iam-role-with-inline-policies"
|
||||
IAM_ROOT_ACCOUNT_USED_RECENTLY = "iam-root-account-used-recently"
|
||||
IAM_ROOT_ACCOUNT_WITH_ACTIVE_CERTS = "iam-root-account-with-active-certs"
|
||||
IAM_USER_WITH_INLINE_POLICIES = "iam-user-with-inline-policies"
|
|
@ -1,21 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.rule_name_enum import (
|
||||
RuleNameEnum,
|
||||
)
|
||||
|
||||
|
||||
class RDSRules(RuleNameEnum):
|
||||
# Encryption
|
||||
RDS_INSTANCE_STORAGE_NOT_ENCRYPTED = "rds-instance-storage-not-encrypted"
|
||||
|
||||
# Data loss prevention
|
||||
RDS_INSTANCE_BACKUP_DISABLED = "rds-instance-backup-disabled"
|
||||
RDS_INSTANCE_SHORT_BACKUP_RETENTION_PERIOD = "rds-instance-short-backup-retention-period"
|
||||
RDS_INSTANCE_SINGLE_AZ = "rds-instance-single-az"
|
||||
|
||||
# Firewalls
|
||||
RDS_SECURITY_GROUP_ALLOWS_ALL = "rds-security-group-allows-all"
|
||||
RDS_SNAPSHOT_PUBLIC = "rds-snapshot-public"
|
||||
|
||||
# Service security
|
||||
RDS_INSTANCE_CA_CERTIFICATE_DEPRECATED = "rds-instance-ca-certificate-deprecated"
|
||||
RDS_INSTANCE_NO_MINOR_UPGRADE = "rds-instance-no-minor-upgrade"
|
|
@ -1,21 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.rule_name_enum import (
|
||||
RuleNameEnum,
|
||||
)
|
||||
|
||||
|
||||
class RedshiftRules(RuleNameEnum):
|
||||
# Encryption
|
||||
REDSHIFT_CLUSTER_DATABASE_NOT_ENCRYPTED = "redshift-cluster-database-not-encrypted"
|
||||
REDSHIFT_PARAMETER_GROUP_SSL_NOT_REQUIRED = "redshift-parameter-group-ssl-not-required"
|
||||
|
||||
# Firewalls
|
||||
REDSHIFT_SECURITY_GROUP_WHITELISTS_ALL = "redshift-security-group-whitelists-all"
|
||||
|
||||
# Restrictive Policies
|
||||
REDSHIFT_CLUSTER_PUBLICLY_ACCESSIBLE = "redshift-cluster-publicly-accessible"
|
||||
|
||||
# Logging
|
||||
REDSHIFT_PARAMETER_GROUP_LOGGING_DISABLED = "redshift-parameter-group-logging-disabled"
|
||||
|
||||
# Service security
|
||||
REDSHIFT_CLUSTER_NO_VERSION_UPGRADE = "redshift-cluster-no-version-upgrade"
|
|
@ -1,5 +0,0 @@
|
|||
from enum import Enum
|
||||
|
||||
|
||||
class RuleNameEnum(Enum):
|
||||
pass
|
|
@ -1,31 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.rule_name_enum import (
|
||||
RuleNameEnum,
|
||||
)
|
||||
|
||||
|
||||
class S3Rules(RuleNameEnum):
|
||||
# Encryption
|
||||
S3_BUCKET_ALLOWING_CLEARTEXT = "s3-bucket-allowing-cleartext"
|
||||
S3_BUCKET_NO_DEFAULT_ENCRYPTION = "s3-bucket-no-default-encryption"
|
||||
|
||||
# Data loss prevention
|
||||
S3_BUCKET_NO_MFA_DELETE = "s3-bucket-no-mfa-delete"
|
||||
S3_BUCKET_NO_VERSIONING = "s3-bucket-no-versioning"
|
||||
|
||||
# Logging
|
||||
S3_BUCKET_NO_LOGGING = "s3-bucket-no-logging"
|
||||
|
||||
# Permissive access rules
|
||||
S3_BUCKET_AUTHENTICATEDUSERS_WRITE_ACP = "s3-bucket-AuthenticatedUsers-write_acp"
|
||||
S3_BUCKET_AUTHENTICATEDUSERS_WRITE = "s3-bucket-AuthenticatedUsers-write"
|
||||
S3_BUCKET_AUTHENTICATEDUSERS_READ_ACP = "s3-bucket-AuthenticatedUsers-read_acp"
|
||||
S3_BUCKET_AUTHENTICATEDUSERS_READ = "s3-bucket-AuthenticatedUsers-read"
|
||||
S3_BUCKET_ALLUSERS_WRITE_ACP = "s3-bucket-AllUsers-write_acp"
|
||||
S3_BUCKET_ALLUSERS_WRITE = "s3-bucket-AllUsers-write"
|
||||
S3_BUCKET_ALLUSERS_READ_ACP = "s3-bucket-AllUsers-read_acp"
|
||||
S3_BUCKET_ALLUSERS_READ = "s3-bucket-AllUsers-read"
|
||||
S3_BUCKET_WORLD_PUT_POLICY = "s3-bucket-world-Put-policy"
|
||||
S3_BUCKET_WORLD_POLICY_STAR = "s3-bucket-world-policy-star"
|
||||
S3_BUCKET_WORLD_LIST_POLICY = "s3-bucket-world-List-policy"
|
||||
S3_BUCKET_WORLD_GET_POLICY = "s3-bucket-world-Get-policy"
|
||||
S3_BUCKET_WORLD_DELETE_POLICY = "s3-bucket-world-Delete-policy"
|
|
@ -1,9 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.rule_name_enum import (
|
||||
RuleNameEnum,
|
||||
)
|
||||
|
||||
|
||||
class SESRules(RuleNameEnum):
|
||||
# Permissive policies
|
||||
SES_IDENTITY_WORLD_SENDRAWEMAIL_POLICY = "ses-identity-world-SendRawEmail-policy"
|
||||
SES_IDENTITY_WORLD_SENDEMAIL_POLICY = "ses-identity-world-SendEmail-policy"
|
|
@ -1,14 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.rule_name_enum import (
|
||||
RuleNameEnum,
|
||||
)
|
||||
|
||||
|
||||
class SNSRules(RuleNameEnum):
|
||||
# Permissive policies
|
||||
SNS_TOPIC_WORLD_SUBSCRIBE_POLICY = "sns-topic-world-Subscribe-policy"
|
||||
SNS_TOPIC_WORLD_SETTOPICATTRIBUTES_POLICY = "sns-topic-world-SetTopicAttributes-policy"
|
||||
SNS_TOPIC_WORLD_REMOVEPERMISSION_POLICY = "sns-topic-world-RemovePermission-policy"
|
||||
SNS_TOPIC_WORLD_RECEIVE_POLICY = "sns-topic-world-Receive-policy"
|
||||
SNS_TOPIC_WORLD_PUBLISH_POLICY = "sns-topic-world-Publish-policy"
|
||||
SNS_TOPIC_WORLD_DELETETOPIC_POLICY = "sns-topic-world-DeleteTopic-policy"
|
||||
SNS_TOPIC_WORLD_ADDPERMISSION_POLICY = "sns-topic-world-AddPermission-policy"
|
|
@ -1,16 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.rule_name_enum import (
|
||||
RuleNameEnum,
|
||||
)
|
||||
|
||||
|
||||
class SQSRules(RuleNameEnum):
|
||||
# Permissive policies
|
||||
SQS_QUEUE_WORLD_SENDMESSAGE_POLICY = "sqs-queue-world-SendMessage-policy"
|
||||
SQS_QUEUE_WORLD_RECEIVEMESSAGE_POLICY = "sqs-queue-world-ReceiveMessage-policy"
|
||||
SQS_QUEUE_WORLD_PURGEQUEUE_POLICY = "sqs-queue-world-PurgeQueue-policy"
|
||||
SQS_QUEUE_WORLD_GETQUEUEURL_POLICY = "sqs-queue-world-GetQueueUrl-policy"
|
||||
SQS_QUEUE_WORLD_GETQUEUEATTRIBUTES_POLICY = "sqs-queue-world-GetQueueAttributes-policy"
|
||||
SQS_QUEUE_WORLD_DELETEMESSAGE_POLICY = "sqs-queue-world-DeleteMessage-policy"
|
||||
SQS_QUEUE_WORLD_CHANGEMESSAGEVISIBILITY_POLICY = (
|
||||
"sqs-queue-world-ChangeMessageVisibility-policy"
|
||||
)
|
|
@ -1,17 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.rule_name_enum import (
|
||||
RuleNameEnum,
|
||||
)
|
||||
|
||||
|
||||
class VPCRules(RuleNameEnum):
|
||||
# Logging
|
||||
SUBNET_WITHOUT_FLOW_LOG = "vpc-subnet-without-flow-log"
|
||||
|
||||
# Firewalls
|
||||
SUBNET_WITH_ALLOW_ALL_INGRESS_ACLS = "vpc-subnet-with-allow-all-ingress-acls"
|
||||
SUBNET_WITH_ALLOW_ALL_EGRESS_ACLS = "vpc-subnet-with-allow-all-egress-acls"
|
||||
NETWORK_ACL_NOT_USED = "vpc-network-acl-not-used"
|
||||
DEFAULT_NETWORK_ACLS_ALLOW_ALL_INGRESS = "vpc-default-network-acls-allow-all-ingress"
|
||||
DEFAULT_NETWORK_ACLS_ALLOW_ALL_EGRESS = "vpc-default-network-acls-allow-all-egress"
|
||||
CUSTOM_NETWORK_ACLS_ALLOW_ALL_INGRESS = "vpc-custom-network-acls-allow-all-ingress"
|
||||
CUSTOM_NETWORK_ACLS_ALLOW_ALL_EGRESS = "vpc-custom-network-acls-allow-all-egress"
|
|
@ -1,224 +0,0 @@
|
|||
from abc import ABC, abstractmethod
|
||||
from typing import List
|
||||
|
||||
from common.common_consts import zero_trust_consts
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.cloudformation_rules import (
|
||||
CloudformationRules,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.cloudtrail_rules import (
|
||||
CloudTrailRules,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.cloudwatch_rules import (
|
||||
CloudWatchRules,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.config_rules import (
|
||||
ConfigRules,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.ec2_rules import EC2Rules
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.elb_rules import ELBRules
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.elbv2_rules import ELBv2Rules
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.iam_rules import IAMRules
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.rds_rules import RDSRules
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.redshift_rules import (
|
||||
RedshiftRules,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.rule_name_enum import (
|
||||
RuleNameEnum,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.s3_rules import S3Rules
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.ses_rules import SESRules
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.sns_rules import SNSRules
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.sqs_rules import SQSRules
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.vpc_rules import VPCRules
|
||||
|
||||
|
||||
# Class which links ZT tests and rules to ScoutSuite finding
|
||||
class ScoutSuiteFindingMap(ABC):
|
||||
@property
|
||||
@abstractmethod
|
||||
def rules(self) -> List[RuleNameEnum]:
|
||||
pass
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def test(self) -> str:
|
||||
pass
|
||||
|
||||
|
||||
class PermissiveFirewallRules(ScoutSuiteFindingMap):
|
||||
rules = [
|
||||
EC2Rules.SECURITY_GROUP_ALL_PORTS_TO_ALL,
|
||||
EC2Rules.SECURITY_GROUP_OPENS_TCP_PORT_TO_ALL,
|
||||
EC2Rules.SECURITY_GROUP_OPENS_UDP_PORT_TO_ALL,
|
||||
EC2Rules.SECURITY_GROUP_OPENS_RDP_PORT_TO_ALL,
|
||||
EC2Rules.SECURITY_GROUP_OPENS_SSH_PORT_TO_ALL,
|
||||
EC2Rules.SECURITY_GROUP_OPENS_MYSQL_PORT_TO_ALL,
|
||||
EC2Rules.SECURITY_GROUP_OPENS_MSSQL_PORT_TO_ALL,
|
||||
EC2Rules.SECURITY_GROUP_OPENS_MONGODB_PORT_TO_ALL,
|
||||
EC2Rules.SECURITY_GROUP_OPENS_ORACLE_DB_PORT_TO_ALL,
|
||||
EC2Rules.SECURITY_GROUP_OPENS_POSTGRESQL_PORT_TO_ALL,
|
||||
EC2Rules.SECURITY_GROUP_OPENS_NFS_PORT_TO_ALL,
|
||||
EC2Rules.SECURITY_GROUP_OPENS_SMTP_PORT_TO_ALL,
|
||||
EC2Rules.SECURITY_GROUP_OPENS_DNS_PORT_TO_ALL,
|
||||
EC2Rules.SECURITY_GROUP_OPENS_ALL_PORTS_TO_SELF,
|
||||
EC2Rules.SECURITY_GROUP_OPENS_ALL_PORTS,
|
||||
EC2Rules.SECURITY_GROUP_OPENS_PLAINTEXT_PORT_FTP,
|
||||
EC2Rules.SECURITY_GROUP_OPENS_PLAINTEXT_PORT_TELNET,
|
||||
EC2Rules.SECURITY_GROUP_OPENS_PORT_RANGE,
|
||||
EC2Rules.EC2_SECURITY_GROUP_WHITELISTS_AWS,
|
||||
VPCRules.SUBNET_WITH_ALLOW_ALL_INGRESS_ACLS,
|
||||
VPCRules.SUBNET_WITH_ALLOW_ALL_EGRESS_ACLS,
|
||||
VPCRules.NETWORK_ACL_NOT_USED,
|
||||
VPCRules.DEFAULT_NETWORK_ACLS_ALLOW_ALL_INGRESS,
|
||||
VPCRules.DEFAULT_NETWORK_ACLS_ALLOW_ALL_EGRESS,
|
||||
VPCRules.CUSTOM_NETWORK_ACLS_ALLOW_ALL_INGRESS,
|
||||
VPCRules.CUSTOM_NETWORK_ACLS_ALLOW_ALL_EGRESS,
|
||||
RDSRules.RDS_SECURITY_GROUP_ALLOWS_ALL,
|
||||
RedshiftRules.REDSHIFT_SECURITY_GROUP_WHITELISTS_ALL,
|
||||
]
|
||||
|
||||
test = zero_trust_consts.TEST_SCOUTSUITE_PERMISSIVE_FIREWALL_RULES
|
||||
|
||||
|
||||
class UnencryptedData(ScoutSuiteFindingMap):
|
||||
rules = [
|
||||
EC2Rules.EBS_SNAPSHOT_NOT_ENCRYPTED,
|
||||
EC2Rules.EBS_VOLUME_NOT_ENCRYPTED,
|
||||
EC2Rules.EC2_INSTANCE_WITH_USER_DATA_SECRETS,
|
||||
ELBv2Rules.ELBV2_LISTENER_ALLOWING_CLEARTEXT,
|
||||
ELBv2Rules.ELBV2_OLDER_SSL_POLICY,
|
||||
RDSRules.RDS_INSTANCE_STORAGE_NOT_ENCRYPTED,
|
||||
RedshiftRules.REDSHIFT_CLUSTER_DATABASE_NOT_ENCRYPTED,
|
||||
RedshiftRules.REDSHIFT_PARAMETER_GROUP_SSL_NOT_REQUIRED,
|
||||
S3Rules.S3_BUCKET_ALLOWING_CLEARTEXT,
|
||||
S3Rules.S3_BUCKET_NO_DEFAULT_ENCRYPTION,
|
||||
ELBRules.ELB_LISTENER_ALLOWING_CLEARTEXT,
|
||||
ELBRules.ELB_OLDER_SSL_POLICY,
|
||||
]
|
||||
|
||||
test = zero_trust_consts.TEST_SCOUTSUITE_UNENCRYPTED_DATA
|
||||
|
||||
|
||||
class DataLossPrevention(ScoutSuiteFindingMap):
|
||||
rules = [
|
||||
RDSRules.RDS_INSTANCE_BACKUP_DISABLED,
|
||||
RDSRules.RDS_INSTANCE_SHORT_BACKUP_RETENTION_PERIOD,
|
||||
RDSRules.RDS_INSTANCE_SINGLE_AZ,
|
||||
S3Rules.S3_BUCKET_NO_MFA_DELETE,
|
||||
S3Rules.S3_BUCKET_NO_VERSIONING,
|
||||
ELBv2Rules.ELBV2_NO_DELETION_PROTECTION,
|
||||
]
|
||||
|
||||
test = zero_trust_consts.TEST_SCOUTSUITE_DATA_LOSS_PREVENTION
|
||||
|
||||
|
||||
class SecureAuthentication(ScoutSuiteFindingMap):
|
||||
rules = [
|
||||
IAMRules.IAM_USER_NO_ACTIVE_KEY_ROTATION,
|
||||
IAMRules.IAM_PASSWORD_POLICY_MINIMUM_LENGTH,
|
||||
IAMRules.IAM_PASSWORD_POLICY_NO_EXPIRATION,
|
||||
IAMRules.IAM_PASSWORD_POLICY_REUSE_ENABLED,
|
||||
IAMRules.IAM_USER_WITH_PASSWORD_AND_KEY,
|
||||
IAMRules.IAM_ASSUME_ROLE_LACKS_EXTERNAL_ID_AND_MFA,
|
||||
IAMRules.IAM_USER_WITHOUT_MFA,
|
||||
IAMRules.IAM_ROOT_ACCOUNT_NO_MFA,
|
||||
IAMRules.IAM_ROOT_ACCOUNT_WITH_ACTIVE_KEYS,
|
||||
IAMRules.IAM_USER_NO_INACTIVE_KEY_ROTATION,
|
||||
IAMRules.IAM_USER_WITH_MULTIPLE_ACCESS_KEYS,
|
||||
]
|
||||
|
||||
test = zero_trust_consts.TEST_SCOUTSUITE_SECURE_AUTHENTICATION
|
||||
|
||||
|
||||
class RestrictivePolicies(ScoutSuiteFindingMap):
|
||||
rules = [
|
||||
IAMRules.IAM_ASSUME_ROLE_POLICY_ALLOWS_ALL,
|
||||
IAMRules.IAM_EC2_ROLE_WITHOUT_INSTANCES,
|
||||
IAMRules.IAM_GROUP_WITH_INLINE_POLICIES,
|
||||
IAMRules.IAM_GROUP_WITH_NO_USERS,
|
||||
IAMRules.IAM_INLINE_GROUP_POLICY_ALLOWS_IAM_PASSROLE,
|
||||
IAMRules.IAM_INLINE_GROUP_POLICY_ALLOWS_NOTACTIONS,
|
||||
IAMRules.IAM_INLINE_GROUP_POLICY_ALLOWS_STS_ASSUMEROLE,
|
||||
IAMRules.IAM_INLINE_ROLE_POLICY_ALLOWS_IAM_PASSROLE,
|
||||
IAMRules.IAM_INLINE_ROLE_POLICY_ALLOWS_NOTACTIONS,
|
||||
IAMRules.IAM_INLINE_ROLE_POLICY_ALLOWS_STS_ASSUMEROLE,
|
||||
IAMRules.IAM_INLINE_USER_POLICY_ALLOWS_IAM_PASSROLE,
|
||||
IAMRules.IAM_INLINE_USER_POLICY_ALLOWS_NOTACTIONS,
|
||||
IAMRules.IAM_INLINE_USER_POLICY_ALLOWS_STS_ASSUMEROLE,
|
||||
IAMRules.IAM_MANAGED_POLICY_ALLOWS_IAM_PASSROLE,
|
||||
IAMRules.IAM_MANAGED_POLICY_ALLOWS_NOTACTIONS,
|
||||
IAMRules.IAM_MANAGED_POLICY_ALLOWS_STS_ASSUMEROLE,
|
||||
IAMRules.IAM_MANAGED_POLICY_NO_ATTACHMENTS,
|
||||
IAMRules.IAM_ROLE_WITH_INLINE_POLICIES,
|
||||
IAMRules.IAM_ROOT_ACCOUNT_USED_RECENTLY,
|
||||
IAMRules.IAM_ROOT_ACCOUNT_WITH_ACTIVE_CERTS,
|
||||
IAMRules.IAM_USER_WITH_INLINE_POLICIES,
|
||||
EC2Rules.AMI_PUBLIC,
|
||||
S3Rules.S3_BUCKET_AUTHENTICATEDUSERS_WRITE_ACP,
|
||||
S3Rules.S3_BUCKET_AUTHENTICATEDUSERS_WRITE,
|
||||
S3Rules.S3_BUCKET_AUTHENTICATEDUSERS_READ_ACP,
|
||||
S3Rules.S3_BUCKET_AUTHENTICATEDUSERS_READ,
|
||||
S3Rules.S3_BUCKET_ALLUSERS_WRITE_ACP,
|
||||
S3Rules.S3_BUCKET_ALLUSERS_WRITE,
|
||||
S3Rules.S3_BUCKET_ALLUSERS_READ_ACP,
|
||||
S3Rules.S3_BUCKET_ALLUSERS_READ,
|
||||
S3Rules.S3_BUCKET_WORLD_PUT_POLICY,
|
||||
S3Rules.S3_BUCKET_WORLD_POLICY_STAR,
|
||||
S3Rules.S3_BUCKET_WORLD_LIST_POLICY,
|
||||
S3Rules.S3_BUCKET_WORLD_GET_POLICY,
|
||||
S3Rules.S3_BUCKET_WORLD_DELETE_POLICY,
|
||||
EC2Rules.EC2_DEFAULT_SECURITY_GROUP_IN_USE,
|
||||
EC2Rules.EC2_DEFAULT_SECURITY_GROUP_WITH_RULES,
|
||||
EC2Rules.EC2_EBS_SNAPSHOT_PUBLIC,
|
||||
SQSRules.SQS_QUEUE_WORLD_SENDMESSAGE_POLICY,
|
||||
SQSRules.SQS_QUEUE_WORLD_RECEIVEMESSAGE_POLICY,
|
||||
SQSRules.SQS_QUEUE_WORLD_PURGEQUEUE_POLICY,
|
||||
SQSRules.SQS_QUEUE_WORLD_GETQUEUEURL_POLICY,
|
||||
SQSRules.SQS_QUEUE_WORLD_GETQUEUEATTRIBUTES_POLICY,
|
||||
SQSRules.SQS_QUEUE_WORLD_DELETEMESSAGE_POLICY,
|
||||
SQSRules.SQS_QUEUE_WORLD_CHANGEMESSAGEVISIBILITY_POLICY,
|
||||
SNSRules.SNS_TOPIC_WORLD_SUBSCRIBE_POLICY,
|
||||
SNSRules.SNS_TOPIC_WORLD_SETTOPICATTRIBUTES_POLICY,
|
||||
SNSRules.SNS_TOPIC_WORLD_REMOVEPERMISSION_POLICY,
|
||||
SNSRules.SNS_TOPIC_WORLD_RECEIVE_POLICY,
|
||||
SNSRules.SNS_TOPIC_WORLD_PUBLISH_POLICY,
|
||||
SNSRules.SNS_TOPIC_WORLD_DELETETOPIC_POLICY,
|
||||
SNSRules.SNS_TOPIC_WORLD_ADDPERMISSION_POLICY,
|
||||
SESRules.SES_IDENTITY_WORLD_SENDRAWEMAIL_POLICY,
|
||||
SESRules.SES_IDENTITY_WORLD_SENDEMAIL_POLICY,
|
||||
RedshiftRules.REDSHIFT_CLUSTER_PUBLICLY_ACCESSIBLE,
|
||||
]
|
||||
|
||||
test = zero_trust_consts.TEST_SCOUTSUITE_RESTRICTIVE_POLICIES
|
||||
|
||||
|
||||
class Logging(ScoutSuiteFindingMap):
|
||||
rules = [
|
||||
CloudTrailRules.CLOUDTRAIL_DUPLICATED_GLOBAL_SERVICES_LOGGING,
|
||||
CloudTrailRules.CLOUDTRAIL_NO_DATA_LOGGING,
|
||||
CloudTrailRules.CLOUDTRAIL_NO_GLOBAL_SERVICES_LOGGING,
|
||||
CloudTrailRules.CLOUDTRAIL_NO_LOG_FILE_VALIDATION,
|
||||
CloudTrailRules.CLOUDTRAIL_NO_LOGGING,
|
||||
CloudTrailRules.CLOUDTRAIL_NOT_CONFIGURED,
|
||||
CloudWatchRules.CLOUDWATCH_ALARM_WITHOUT_ACTIONS,
|
||||
ELBRules.ELB_NO_ACCESS_LOGS,
|
||||
S3Rules.S3_BUCKET_NO_LOGGING,
|
||||
ELBv2Rules.ELBV2_NO_ACCESS_LOGS,
|
||||
VPCRules.SUBNET_WITHOUT_FLOW_LOG,
|
||||
ConfigRules.CONFIG_RECORDER_NOT_CONFIGURED,
|
||||
RedshiftRules.REDSHIFT_PARAMETER_GROUP_LOGGING_DISABLED,
|
||||
]
|
||||
|
||||
test = zero_trust_consts.TEST_SCOUTSUITE_LOGGING
|
||||
|
||||
|
||||
class ServiceSecurity(ScoutSuiteFindingMap):
|
||||
rules = [
|
||||
CloudformationRules.CLOUDFORMATION_STACK_WITH_ROLE,
|
||||
ELBv2Rules.ELBV2_HTTP_REQUEST_SMUGGLING,
|
||||
RDSRules.RDS_INSTANCE_CA_CERTIFICATE_DEPRECATED,
|
||||
RDSRules.RDS_INSTANCE_NO_MINOR_UPGRADE,
|
||||
RedshiftRules.REDSHIFT_CLUSTER_NO_VERSION_UPGRADE,
|
||||
]
|
||||
|
||||
test = zero_trust_consts.TEST_SCOUTSUITE_SERVICE_SECURITY
|
|
@ -1,19 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.scoutsuite_finding_maps import (
|
||||
DataLossPrevention,
|
||||
Logging,
|
||||
PermissiveFirewallRules,
|
||||
RestrictivePolicies,
|
||||
SecureAuthentication,
|
||||
ServiceSecurity,
|
||||
UnencryptedData,
|
||||
)
|
||||
|
||||
SCOUTSUITE_FINDINGS = [
|
||||
PermissiveFirewallRules,
|
||||
UnencryptedData,
|
||||
DataLossPrevention,
|
||||
SecureAuthentication,
|
||||
RestrictivePolicies,
|
||||
Logging,
|
||||
ServiceSecurity,
|
||||
]
|
|
@ -1,31 +0,0 @@
|
|||
from enum import Enum
|
||||
|
||||
SERVICES = "services"
|
||||
FINDINGS = "findings"
|
||||
|
||||
|
||||
class SERVICE_TYPES(Enum):
|
||||
ACM = "acm"
|
||||
AWSLAMBDA = "awslambda"
|
||||
CLOUDFORMATION = "cloudformation"
|
||||
CLOUDTRAIL = "cloudtrail"
|
||||
CLOUDWATCH = "cloudwatch"
|
||||
CONFIG = "config"
|
||||
DIRECTCONNECT = "directconnect"
|
||||
EC2 = "ec2"
|
||||
EFS = "efs"
|
||||
ELASTICACHE = "elasticache"
|
||||
ELB = "elb"
|
||||
ELB_V2 = "elbv2"
|
||||
EMR = "emr"
|
||||
IAM = "iam"
|
||||
KMS = "kms"
|
||||
RDS = "rds"
|
||||
REDSHIFT = "redshift"
|
||||
ROUTE53 = "route53"
|
||||
S3 = "s3"
|
||||
SES = "ses"
|
||||
SNS = "sns"
|
||||
SQS = "sqs"
|
||||
VPC = "vpc"
|
||||
SECRETSMANAGER = "secretsmanager"
|
|
@ -1,40 +0,0 @@
|
|||
from enum import Enum
|
||||
|
||||
from common.utils.code_utils import get_value_from_dict
|
||||
from common.utils.exceptions import RulePathCreatorNotFound
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.rule_path_creators_list import ( # noqa: E501
|
||||
RULE_PATH_CREATORS_LIST,
|
||||
)
|
||||
|
||||
|
||||
def __build_rule_to_rule_path_creator_hashmap():
|
||||
hashmap = {}
|
||||
for rule_path_creator in RULE_PATH_CREATORS_LIST:
|
||||
for rule_name in rule_path_creator.supported_rules:
|
||||
hashmap[rule_name] = rule_path_creator
|
||||
return hashmap
|
||||
|
||||
|
||||
RULE_TO_RULE_PATH_CREATOR_HASHMAP = __build_rule_to_rule_path_creator_hashmap()
|
||||
|
||||
|
||||
class RuleParser:
|
||||
@staticmethod
|
||||
def get_rule_data(scoutsuite_data: dict, rule_name: Enum) -> dict:
|
||||
rule_path = RuleParser._get_rule_path(rule_name)
|
||||
return get_value_from_dict(scoutsuite_data, rule_path)
|
||||
|
||||
@staticmethod
|
||||
def _get_rule_path(rule_name: Enum):
|
||||
creator = RuleParser._get_rule_path_creator(rule_name)
|
||||
return creator.build_rule_path(rule_name)
|
||||
|
||||
@staticmethod
|
||||
def _get_rule_path_creator(rule_name: Enum):
|
||||
try:
|
||||
return RULE_TO_RULE_PATH_CREATOR_HASHMAP[rule_name]
|
||||
except KeyError:
|
||||
raise RulePathCreatorNotFound(
|
||||
f"Rule path creator not found for rule {rule_name.value}. Make sure to assign"
|
||||
f"this rule to any rule path creators."
|
||||
)
|
|
@ -1,28 +0,0 @@
|
|||
from abc import ABC, abstractmethod
|
||||
from enum import Enum
|
||||
from typing import List, Type
|
||||
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.rule_name_enum import (
|
||||
RuleNameEnum,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import (
|
||||
FINDINGS,
|
||||
SERVICE_TYPES,
|
||||
)
|
||||
|
||||
|
||||
class AbstractRulePathCreator(ABC):
|
||||
@property
|
||||
@abstractmethod
|
||||
def service_type(self) -> SERVICE_TYPES:
|
||||
pass
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def supported_rules(self) -> Type[RuleNameEnum]:
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def build_rule_path(cls, rule_name: Enum) -> List[str]:
|
||||
assert rule_name in cls.supported_rules
|
||||
return [cls.service_type.value, FINDINGS, rule_name.value]
|
|
@ -1,12 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.cloudformation_rules import (
|
||||
CloudformationRules,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import SERVICE_TYPES
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.abstract_rule_path_creator import ( # noqa: E501
|
||||
AbstractRulePathCreator,
|
||||
)
|
||||
|
||||
|
||||
class CloudformationRulePathCreator(AbstractRulePathCreator):
|
||||
service_type = SERVICE_TYPES.CLOUDFORMATION
|
||||
supported_rules = CloudformationRules
|
|
@ -1,12 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.cloudtrail_rules import (
|
||||
CloudTrailRules,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import SERVICE_TYPES
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.abstract_rule_path_creator import ( # noqa: E501
|
||||
AbstractRulePathCreator,
|
||||
)
|
||||
|
||||
|
||||
class CloudTrailRulePathCreator(AbstractRulePathCreator):
|
||||
service_type = SERVICE_TYPES.CLOUDTRAIL
|
||||
supported_rules = CloudTrailRules
|
|
@ -1,12 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.cloudwatch_rules import (
|
||||
CloudWatchRules,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import SERVICE_TYPES
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.abstract_rule_path_creator import ( # noqa: E501
|
||||
AbstractRulePathCreator,
|
||||
)
|
||||
|
||||
|
||||
class CloudWatchRulePathCreator(AbstractRulePathCreator):
|
||||
service_type = SERVICE_TYPES.CLOUDWATCH
|
||||
supported_rules = CloudWatchRules
|
|
@ -1,12 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.config_rules import (
|
||||
ConfigRules,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import SERVICE_TYPES
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.abstract_rule_path_creator import ( # noqa: E501
|
||||
AbstractRulePathCreator,
|
||||
)
|
||||
|
||||
|
||||
class ConfigRulePathCreator(AbstractRulePathCreator):
|
||||
service_type = SERVICE_TYPES.CONFIG
|
||||
supported_rules = ConfigRules
|
|
@ -1,10 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.ec2_rules import EC2Rules
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import SERVICE_TYPES
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.abstract_rule_path_creator import ( # noqa: E501
|
||||
AbstractRulePathCreator,
|
||||
)
|
||||
|
||||
|
||||
class EC2RulePathCreator(AbstractRulePathCreator):
|
||||
service_type = SERVICE_TYPES.EC2
|
||||
supported_rules = EC2Rules
|
|
@ -1,10 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.elb_rules import ELBRules
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import SERVICE_TYPES
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.abstract_rule_path_creator import ( # noqa: E501
|
||||
AbstractRulePathCreator,
|
||||
)
|
||||
|
||||
|
||||
class ELBRulePathCreator(AbstractRulePathCreator):
|
||||
service_type = SERVICE_TYPES.ELB
|
||||
supported_rules = ELBRules
|
|
@ -1,10 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.elbv2_rules import ELBv2Rules
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import SERVICE_TYPES
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.abstract_rule_path_creator import ( # noqa: E501
|
||||
AbstractRulePathCreator,
|
||||
)
|
||||
|
||||
|
||||
class ELBv2RulePathCreator(AbstractRulePathCreator):
|
||||
service_type = SERVICE_TYPES.ELB_V2
|
||||
supported_rules = ELBv2Rules
|
|
@ -1,10 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.iam_rules import IAMRules
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import SERVICE_TYPES
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.abstract_rule_path_creator import ( # noqa: E501
|
||||
AbstractRulePathCreator,
|
||||
)
|
||||
|
||||
|
||||
class IAMRulePathCreator(AbstractRulePathCreator):
|
||||
service_type = SERVICE_TYPES.IAM
|
||||
supported_rules = IAMRules
|
|
@ -1,10 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.rds_rules import RDSRules
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import SERVICE_TYPES
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.abstract_rule_path_creator import ( # noqa: E501
|
||||
AbstractRulePathCreator,
|
||||
)
|
||||
|
||||
|
||||
class RDSRulePathCreator(AbstractRulePathCreator):
|
||||
service_type = SERVICE_TYPES.RDS
|
||||
supported_rules = RDSRules
|
|
@ -1,12 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.redshift_rules import (
|
||||
RedshiftRules,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import SERVICE_TYPES
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.abstract_rule_path_creator import ( # noqa: E501
|
||||
AbstractRulePathCreator,
|
||||
)
|
||||
|
||||
|
||||
class RedshiftRulePathCreator(AbstractRulePathCreator):
|
||||
service_type = SERVICE_TYPES.REDSHIFT
|
||||
supported_rules = RedshiftRules
|
|
@ -1,10 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.s3_rules import S3Rules
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import SERVICE_TYPES
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.abstract_rule_path_creator import ( # noqa: E501
|
||||
AbstractRulePathCreator,
|
||||
)
|
||||
|
||||
|
||||
class S3RulePathCreator(AbstractRulePathCreator):
|
||||
service_type = SERVICE_TYPES.S3
|
||||
supported_rules = S3Rules
|
|
@ -1,10 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.ses_rules import SESRules
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import SERVICE_TYPES
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.abstract_rule_path_creator import ( # noqa: E501
|
||||
AbstractRulePathCreator,
|
||||
)
|
||||
|
||||
|
||||
class SESRulePathCreator(AbstractRulePathCreator):
|
||||
service_type = SERVICE_TYPES.SES
|
||||
supported_rules = SESRules
|
|
@ -1,10 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.sns_rules import SNSRules
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import SERVICE_TYPES
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.abstract_rule_path_creator import ( # noqa: E501
|
||||
AbstractRulePathCreator,
|
||||
)
|
||||
|
||||
|
||||
class SNSRulePathCreator(AbstractRulePathCreator):
|
||||
service_type = SERVICE_TYPES.SNS
|
||||
supported_rules = SNSRules
|
|
@ -1,10 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.sqs_rules import SQSRules
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import SERVICE_TYPES
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.abstract_rule_path_creator import ( # noqa: E501
|
||||
AbstractRulePathCreator,
|
||||
)
|
||||
|
||||
|
||||
class SQSRulePathCreator(AbstractRulePathCreator):
|
||||
service_type = SERVICE_TYPES.SQS
|
||||
supported_rules = SQSRules
|
|
@ -1,10 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.vpc_rules import VPCRules
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import SERVICE_TYPES
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.abstract_rule_path_creator import ( # noqa: E501
|
||||
AbstractRulePathCreator,
|
||||
)
|
||||
|
||||
|
||||
class VPCRulePathCreator(AbstractRulePathCreator):
|
||||
service_type = SERVICE_TYPES.VPC
|
||||
supported_rules = VPCRules
|
|
@ -1,63 +0,0 @@
|
|||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.rule_path_creators.cloudformation_rule_path_creator import ( # noqa: E501
|
||||
CloudformationRulePathCreator,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.rule_path_creators.cloudtrail_rule_path_creator import ( # noqa: E501
|
||||
CloudTrailRulePathCreator,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.rule_path_creators.cloudwatch_rule_path_creator import ( # noqa: E501
|
||||
CloudWatchRulePathCreator,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.rule_path_creators.config_rule_path_creator import ( # noqa: E501
|
||||
ConfigRulePathCreator,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.rule_path_creators.ec2_rule_path_creator import ( # noqa: E501
|
||||
EC2RulePathCreator,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.rule_path_creators.elb_rule_path_creator import ( # noqa: E501
|
||||
ELBRulePathCreator,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.rule_path_creators.elbv2_rule_path_creator import ( # noqa: E501
|
||||
ELBv2RulePathCreator,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.rule_path_creators.iam_rule_path_creator import ( # noqa: E501
|
||||
IAMRulePathCreator,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.rule_path_creators.rds_rule_path_creator import ( # noqa: E501
|
||||
RDSRulePathCreator,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.rule_path_creators.redshift_rule_path_creator import ( # noqa: E501
|
||||
RedshiftRulePathCreator,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.rule_path_creators.s3_rule_path_creator import ( # noqa: E501
|
||||
S3RulePathCreator,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.rule_path_creators.ses_rule_path_creator import ( # noqa: E501
|
||||
SESRulePathCreator,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.rule_path_creators.sns_rule_path_creator import ( # noqa: E501
|
||||
SNSRulePathCreator,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.rule_path_creators.sqs_rule_path_creator import ( # noqa: E501
|
||||
SQSRulePathCreator,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.rule_path_creators.vpc_rule_path_creator import ( # noqa: E501
|
||||
VPCRulePathCreator,
|
||||
)
|
||||
|
||||
RULE_PATH_CREATORS_LIST = [
|
||||
EC2RulePathCreator,
|
||||
ELBv2RulePathCreator,
|
||||
RDSRulePathCreator,
|
||||
RedshiftRulePathCreator,
|
||||
S3RulePathCreator,
|
||||
IAMRulePathCreator,
|
||||
CloudTrailRulePathCreator,
|
||||
ELBRulePathCreator,
|
||||
VPCRulePathCreator,
|
||||
CloudWatchRulePathCreator,
|
||||
SQSRulePathCreator,
|
||||
SNSRulePathCreator,
|
||||
SESRulePathCreator,
|
||||
ConfigRulePathCreator,
|
||||
CloudformationRulePathCreator,
|
||||
]
|
|
@ -1,58 +0,0 @@
|
|||
from typing import Tuple
|
||||
|
||||
from ScoutSuite.providers.base.authentication_strategy import AuthenticationException
|
||||
|
||||
from common.cloud.scoutsuite_consts import CloudProviders
|
||||
from common.config_value_paths import AWS_KEYS_PATH
|
||||
from common.utils.exceptions import InvalidAWSKeys
|
||||
from monkey_island.cc.server_utils.encryption import get_datastore_encryptor
|
||||
from monkey_island.cc.services.config import ConfigService
|
||||
|
||||
|
||||
def is_cloud_authentication_setup(provider: CloudProviders) -> Tuple[bool, str]:
|
||||
if provider == CloudProviders.AWS.value:
|
||||
if is_aws_keys_setup():
|
||||
return True, "AWS keys already setup."
|
||||
|
||||
import ScoutSuite.providers.aws.authentication_strategy as auth_strategy
|
||||
|
||||
try:
|
||||
profile = auth_strategy.AWSAuthenticationStrategy().authenticate()
|
||||
return True, f' Profile "{profile.session.profile_name}" is already setup. '
|
||||
except AuthenticationException:
|
||||
return False, ""
|
||||
|
||||
|
||||
def is_aws_keys_setup():
|
||||
return ConfigService.get_config_value(
|
||||
AWS_KEYS_PATH + ["aws_access_key_id"]
|
||||
) and ConfigService.get_config_value(AWS_KEYS_PATH + ["aws_secret_access_key"])
|
||||
|
||||
|
||||
def set_aws_keys(access_key_id: str, secret_access_key: str, session_token: str):
|
||||
if not access_key_id or not secret_access_key:
|
||||
raise InvalidAWSKeys(
|
||||
"Missing some of the following fields: access key ID, secret access key."
|
||||
)
|
||||
_set_aws_key("aws_access_key_id", access_key_id)
|
||||
_set_aws_key("aws_secret_access_key", secret_access_key)
|
||||
_set_aws_key("aws_session_token", session_token)
|
||||
|
||||
|
||||
def _set_aws_key(key_type: str, key_value: str):
|
||||
path_to_keys = AWS_KEYS_PATH
|
||||
encrypted_key = get_datastore_encryptor().encrypt(key_value)
|
||||
ConfigService.set_config_value(path_to_keys + [key_type], encrypted_key)
|
||||
|
||||
|
||||
def get_aws_keys():
|
||||
return {
|
||||
"access_key_id": _get_aws_key("aws_access_key_id"),
|
||||
"secret_access_key": _get_aws_key("aws_secret_access_key"),
|
||||
"session_token": _get_aws_key("aws_session_token"),
|
||||
}
|
||||
|
||||
|
||||
def _get_aws_key(key_type: str):
|
||||
path_to_keys = AWS_KEYS_PATH
|
||||
return ConfigService.get_config_value(config_key_as_arr=path_to_keys + [key_type])
|
|
@ -1,29 +0,0 @@
|
|||
from monkey_island.cc.models.zero_trust.scoutsuite_rule import ScoutSuiteRule
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts import rule_consts
|
||||
|
||||
|
||||
class ScoutSuiteRuleService:
|
||||
@staticmethod
|
||||
def get_rule_from_rule_data(rule_data: dict) -> ScoutSuiteRule:
|
||||
rule = ScoutSuiteRule()
|
||||
rule.description = rule_data["description"]
|
||||
rule.path = rule_data["path"]
|
||||
rule.level = rule_data["level"]
|
||||
rule.items = rule_data["items"]
|
||||
rule.dashboard_name = rule_data["dashboard_name"]
|
||||
rule.checked_items = rule_data["checked_items"]
|
||||
rule.flagged_items = rule_data["flagged_items"]
|
||||
rule.service = rule_data["service"]
|
||||
rule.rationale = rule_data["rationale"]
|
||||
rule.remediation = rule_data["remediation"]
|
||||
rule.compliance = rule_data["compliance"]
|
||||
rule.references = rule_data["references"]
|
||||
return rule
|
||||
|
||||
@staticmethod
|
||||
def is_rule_dangerous(rule: ScoutSuiteRule):
|
||||
return rule.level == rule_consts.RULE_LEVEL_DANGER and len(rule.items) != 0
|
||||
|
||||
@staticmethod
|
||||
def is_rule_warning(rule: ScoutSuiteRule):
|
||||
return rule.level == rule_consts.RULE_LEVEL_WARNING and len(rule.items) != 0
|
|
@ -1,81 +0,0 @@
|
|||
from typing import List
|
||||
|
||||
from common.common_consts import zero_trust_consts
|
||||
from monkey_island.cc.models.zero_trust.scoutsuite_finding import ScoutSuiteFinding
|
||||
from monkey_island.cc.models.zero_trust.scoutsuite_finding_details import ScoutSuiteFindingDetails
|
||||
from monkey_island.cc.models.zero_trust.scoutsuite_rule import ScoutSuiteRule
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.scoutsuite_finding_maps import (
|
||||
ScoutSuiteFindingMap,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.scoutsuite_rule_service import (
|
||||
ScoutSuiteRuleService,
|
||||
)
|
||||
|
||||
|
||||
class ScoutSuiteZTFindingService:
|
||||
@staticmethod
|
||||
def process_rule(finding: ScoutSuiteFindingMap, rule: ScoutSuiteRule):
|
||||
existing_findings = ScoutSuiteFinding.objects(test=finding.test)
|
||||
assert len(existing_findings) < 2, "More than one finding exists for {}".format(
|
||||
finding.test
|
||||
)
|
||||
|
||||
if len(existing_findings) == 0:
|
||||
ScoutSuiteZTFindingService._create_new_finding_from_rule(finding, rule)
|
||||
else:
|
||||
ScoutSuiteZTFindingService.add_rule(existing_findings[0], rule)
|
||||
|
||||
@staticmethod
|
||||
def _create_new_finding_from_rule(finding: ScoutSuiteFindingMap, rule: ScoutSuiteRule):
|
||||
details = ScoutSuiteFindingDetails()
|
||||
details.scoutsuite_rules = [rule]
|
||||
details.save()
|
||||
status = ScoutSuiteZTFindingService.get_finding_status_from_rules(details.scoutsuite_rules)
|
||||
ScoutSuiteFinding.save_finding(finding.test, status, details)
|
||||
|
||||
@staticmethod
|
||||
def get_finding_status_from_rules(rules: List[ScoutSuiteRule]) -> str:
|
||||
if len(rules) == 0:
|
||||
return zero_trust_consts.STATUS_UNEXECUTED
|
||||
elif filter(lambda x: ScoutSuiteRuleService.is_rule_dangerous(x), rules):
|
||||
return zero_trust_consts.STATUS_FAILED
|
||||
elif filter(lambda x: ScoutSuiteRuleService.is_rule_warning(x), rules):
|
||||
return zero_trust_consts.STATUS_VERIFY
|
||||
else:
|
||||
return zero_trust_consts.STATUS_PASSED
|
||||
|
||||
@staticmethod
|
||||
def add_rule(finding: ScoutSuiteFinding, rule: ScoutSuiteRule):
|
||||
ScoutSuiteZTFindingService.change_finding_status_by_rule(finding, rule)
|
||||
finding.save()
|
||||
finding.details.fetch().add_rule(rule)
|
||||
|
||||
@staticmethod
|
||||
def change_finding_status_by_rule(finding: ScoutSuiteFinding, rule: ScoutSuiteRule):
|
||||
rule_status = ScoutSuiteZTFindingService.get_finding_status_from_rules([rule])
|
||||
finding_status = finding.status
|
||||
new_finding_status = ScoutSuiteZTFindingService.get_finding_status_from_rule_status(
|
||||
finding_status, rule_status
|
||||
)
|
||||
if finding_status != new_finding_status:
|
||||
finding.status = new_finding_status
|
||||
|
||||
@staticmethod
|
||||
def get_finding_status_from_rule_status(finding_status: str, rule_status: str) -> str:
|
||||
if (
|
||||
finding_status == zero_trust_consts.STATUS_FAILED
|
||||
or rule_status == zero_trust_consts.STATUS_FAILED
|
||||
):
|
||||
return zero_trust_consts.STATUS_FAILED
|
||||
elif (
|
||||
finding_status == zero_trust_consts.STATUS_VERIFY
|
||||
or rule_status == zero_trust_consts.STATUS_VERIFY
|
||||
):
|
||||
return zero_trust_consts.STATUS_VERIFY
|
||||
elif (
|
||||
finding_status == zero_trust_consts.STATUS_PASSED
|
||||
or rule_status == zero_trust_consts.STATUS_PASSED
|
||||
):
|
||||
return zero_trust_consts.STATUS_PASSED
|
||||
else:
|
||||
return zero_trust_consts.STATUS_UNEXECUTED
|
|
@ -7,7 +7,6 @@ from common.common_consts import zero_trust_consts
|
|||
from common.utils.exceptions import UnknownFindingError
|
||||
from monkey_island.cc.models.zero_trust.finding import Finding
|
||||
from monkey_island.cc.models.zero_trust.monkey_finding import MonkeyFinding
|
||||
from monkey_island.cc.models.zero_trust.scoutsuite_finding import ScoutSuiteFinding
|
||||
from monkey_island.cc.services.zero_trust.monkey_findings.monkey_zt_details_service import (
|
||||
MonkeyZTDetailsService,
|
||||
)
|
||||
|
@ -55,7 +54,5 @@ class FindingService:
|
|||
def _get_finding_details(finding: Finding) -> Union[dict, SON]:
|
||||
if type(finding) == MonkeyFinding:
|
||||
return MonkeyZTDetailsService.fetch_details_for_display(finding.details.id)
|
||||
elif type(finding) == ScoutSuiteFinding:
|
||||
return finding.details.fetch().to_mongo()
|
||||
else:
|
||||
raise UnknownFindingError(f"Unknown finding type {str(type(finding))}")
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
from monkey_island.cc.models.zero_trust.scoutsuite_data_json import ScoutSuiteRawDataJson
|
||||
|
||||
|
||||
class ScoutSuiteRawDataService:
|
||||
|
||||
# Return unparsed json of ScoutSuite results,
|
||||
# so that UI can pick out values it needs for report
|
||||
@staticmethod
|
||||
def get_scoutsuite_data_json() -> str:
|
||||
try:
|
||||
return ScoutSuiteRawDataJson.objects.get().scoutsuite_data
|
||||
except Exception:
|
||||
return "{}"
|
|
@ -71,7 +71,7 @@ class ReportPageComponent extends AuthComponent {
|
|||
}
|
||||
|
||||
getZeroTrustReportFromServer = async () => {
|
||||
let ztReport = {findings: {}, principles: {}, pillars: {}, scoutsuite_data: {}};
|
||||
let ztReport = {findings: {}, principles: {}, pillars: {}};
|
||||
await this.authFetch('/api/report/zero-trust/findings')
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
|
@ -87,11 +87,6 @@ class ReportPageComponent extends AuthComponent {
|
|||
.then(res => {
|
||||
ztReport.pillars = res;
|
||||
});
|
||||
await this.authFetch('/api/report/zero-trust/scoutsuite')
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
ztReport.scoutsuite_data = res;
|
||||
});
|
||||
return ztReport
|
||||
};
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import {cloneDeep} from 'lodash';
|
|||
import {faCloud, faExpandArrowsAlt} from '@fortawesome/free-solid-svg-icons';
|
||||
import RunOnIslandButton from './RunOnIslandButton';
|
||||
import AWSRunButton from './RunOnAWS/AWSRunButton';
|
||||
import CloudOptions from './scoutsuite-setup/CloudOptions';
|
||||
|
||||
const CONFIG_URL = '/api/configuration/island';
|
||||
|
||||
|
@ -56,7 +55,7 @@ function RunOptions(props) {
|
|||
return InlineSelection(defaultContents, newProps);
|
||||
}
|
||||
|
||||
function shouldShowScoutsuite(islandMode){
|
||||
function isNotRansomwareMode(islandMode){
|
||||
return islandMode !== 'ransomware';
|
||||
}
|
||||
|
||||
|
@ -73,15 +72,7 @@ function RunOptions(props) {
|
|||
setComponent(LocalManualRunOptions,
|
||||
{ips: ips, setComponent: setComponent})
|
||||
}}/>
|
||||
{shouldShowScoutsuite(props.islandMode) && <AWSRunButton setComponent={setComponent}/> }
|
||||
{shouldShowScoutsuite(props.islandMode) && <NextSelectionButton title={'Cloud security scan'}
|
||||
description={'Explains how to enable cloud security scan.'}
|
||||
icon={faCloud}
|
||||
onButtonClick={() => {
|
||||
setComponent(CloudOptions,
|
||||
{ips: ips, setComponent: setComponent})
|
||||
}}/>
|
||||
}
|
||||
{isNotRansomwareMode(props.islandMode) && <AWSRunButton setComponent={setComponent}/> }
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
import {Button} from 'react-bootstrap';
|
||||
import React from 'react';
|
||||
import InlineSelection from '../../../../ui-components/inline-selection/InlineSelection';
|
||||
import {COLUMN_SIZES} from '../../../../ui-components/inline-selection/utils';
|
||||
import '../../../../../styles/components/scoutsuite/AWSSetup.scss';
|
||||
import AWSSetupOptions from './AWSSetupOptions';
|
||||
|
||||
|
||||
export default function AWSCLISetup(props) {
|
||||
return InlineSelection(getContents, {
|
||||
...props,
|
||||
collumnSize: COLUMN_SIZES.LARGE,
|
||||
onBackButtonClick: () => {
|
||||
props.setComponent(AWSSetupOptions, props);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const getContents = (props) => {
|
||||
return (
|
||||
<div className={'aws-scoutsuite-configuration'}>
|
||||
<h2>AWS CLI configuration for scan</h2>
|
||||
<p>To assess your AWS infrastructure's security do the following:</p>
|
||||
<ol>
|
||||
<li>
|
||||
1. Configure AWS CLI on Monkey Island Server (if you already have a configured CLI you can skip this step).
|
||||
<ol className={'nested-ol'}>
|
||||
<li>
|
||||
a. Download <Button href={'https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html'}
|
||||
target={'_blank'} variant={'link'}>AWS CLI</Button> and
|
||||
install it on the Monkey Island server (machine running this page).
|
||||
</li>
|
||||
<li>
|
||||
b. Run <code>aws configure</code>. It's important to configure credentials as it
|
||||
allows ScoutSuite to get information about your cloud configuration. The simplest way to do so is to
|
||||
provide
|
||||
<Button
|
||||
href={'https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-creds'}
|
||||
variant={'link'}
|
||||
className={'cli-link'}
|
||||
target={'_blank'}>
|
||||
Access key ID and secret access key
|
||||
</Button>.
|
||||
</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>
|
||||
2. If you change the configuration, make sure not to disable AWS system info collector.
|
||||
</li>
|
||||
<li>
|
||||
3. Go <Button onClick={() => props.setComponent()}
|
||||
variant={'link'}
|
||||
className={'cli-link'}>back</Button>
|
||||
and run Monkey on the Island server.
|
||||
</li>
|
||||
<li>
|
||||
4. Assess results in Zero Trust report.
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -1,179 +0,0 @@
|
|||
import React, {useEffect, useState} from 'react';
|
||||
import InlineSelection from '../../../../ui-components/inline-selection/InlineSelection';
|
||||
import {COLUMN_SIZES} from '../../../../ui-components/inline-selection/utils';
|
||||
import AWSSetupOptions from './AWSSetupOptions';
|
||||
import {Button, Col, Form, Row} from 'react-bootstrap';
|
||||
import AuthComponent from '../../../../AuthComponent';
|
||||
import '../../../../../styles/components/scoutsuite/AWSSetup.scss';
|
||||
import {PROVIDERS} from '../ProvidersEnum';
|
||||
import classNames from 'classnames';
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
||||
import {faChevronDown} from '@fortawesome/free-solid-svg-icons/faChevronDown';
|
||||
import {faChevronUp} from '@fortawesome/free-solid-svg-icons/faChevronUp';
|
||||
import {faQuestion} from '@fortawesome/free-solid-svg-icons';
|
||||
import Collapse from '@kunukn/react-collapse/dist/Collapse.umd';
|
||||
import keySetupForAnyUserImage from '../../../../../images/aws_keys_tutorial-any-user.png';
|
||||
import keySetupForCurrentUserImage from '../../../../../images/aws_keys_tutorial-current-user.png';
|
||||
import ImageModal from '../../../../ui-components/ImageModal';
|
||||
|
||||
|
||||
export default function AWSCLISetup(props) {
|
||||
return InlineSelection(getContents, {
|
||||
...props,
|
||||
collumnSize: COLUMN_SIZES.LARGE,
|
||||
onBackButtonClick: () => {
|
||||
props.setComponent(AWSSetupOptions, props);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const authComponent = new AuthComponent({})
|
||||
|
||||
const getContents = (props) => {
|
||||
|
||||
const [accessKeyId, setAccessKeyId] = useState('');
|
||||
const [secretAccessKey, setSecretAccessKey] = useState('');
|
||||
const [sessionToken, setSessionToken] = useState('');
|
||||
const [errorMessage, setErrorMessage] = useState('');
|
||||
const [successMessage, setSuccessMessage] = useState('');
|
||||
const [docCollapseOpen, setDocCollapseOpen] = useState(false);
|
||||
|
||||
function submitKeys(event) {
|
||||
event.preventDefault();
|
||||
setSuccessMessage('');
|
||||
setErrorMessage('');
|
||||
authComponent.authFetch(
|
||||
'/api/scoutsuite_auth/' + PROVIDERS.AWS,
|
||||
{
|
||||
'method': 'POST',
|
||||
'body': JSON.stringify({
|
||||
'accessKeyId': accessKeyId,
|
||||
'secretAccessKey': secretAccessKey,
|
||||
'sessionToken': sessionToken
|
||||
})
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
if (res['error_msg'] === '') {
|
||||
setSuccessMessage('AWS keys saved!');
|
||||
} else if (res['message'] === 'Internal Server Error') {
|
||||
setErrorMessage('Something went wrong, double check keys and contact support if problem persists.');
|
||||
} else {
|
||||
setErrorMessage(res['error_msg']);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
authComponent.authFetch('/api/aws_keys')
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
setAccessKeyId(res['access_key_id']);
|
||||
setSecretAccessKey(res['secret_access_key']);
|
||||
setSessionToken(res['session_token']);
|
||||
});
|
||||
}, [props]);
|
||||
|
||||
|
||||
// TODO separate into standalone component
|
||||
function getKeyCreationDocsContent() {
|
||||
return (
|
||||
<div className={'key-creation-tutorial'}>
|
||||
<h5>Tips</h5>
|
||||
<p>Consider creating a new user account just for this activity. Assign only <b>ReadOnlyAccess</b> and
|
||||
<b>SecurityAudit</b> policies.</p>
|
||||
|
||||
<h5>Keys for custom user</h5>
|
||||
<p>1. Open the IAM console at <a href={'https://console.aws.amazon.com/iam/'}
|
||||
target={'_blank'}
|
||||
rel="noopener noreferrer">https://console.aws.amazon.com/iam/</a>.</p>
|
||||
<p>2. In the navigation pane, choose Users.</p>
|
||||
<p>3. Choose the name of the user whose access keys you want to create, and then choose the Security credentials
|
||||
tab.</p>
|
||||
<p>4. In the Access keys section, choose Create Access key.</p>
|
||||
<p>To view the new access key pair, choose Show. Your credentials will look something like this:</p>
|
||||
<p>Access key ID: AKIAIOSFODNN7EXAMPLE</p>
|
||||
<p>Secret access key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY</p>
|
||||
<Row>
|
||||
<Col lg={3} md={3} sm={5} xs={12}>
|
||||
<ImageModal image={keySetupForAnyUserImage}/>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<h5>Keys for current user</h5>
|
||||
<p>1. Click on your username in the upper right corner.</p>
|
||||
<p>2. Click on "My security credentials".</p>
|
||||
<p>3. In the Access keys section, choose Create Access key.</p>
|
||||
<p>To view the new Access key pair, choose Show. Your credentials will look something like this:</p>
|
||||
<p>Access key ID: AKIAIOSFODNN7EXAMPLE</p>
|
||||
<p>Secret access key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY</p>
|
||||
<Row>
|
||||
<Col lg={3} md={3} sm={5} xs={12}>
|
||||
<ImageModal image={keySetupForCurrentUserImage}/>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>);
|
||||
}
|
||||
|
||||
function getKeyCreationDocs() {
|
||||
return (
|
||||
<div className={classNames('collapse-item', {'item--active': docCollapseOpen})}>
|
||||
<button className={'btn-collapse'}
|
||||
onClick={() => setDocCollapseOpen(!docCollapseOpen)}>
|
||||
<span>
|
||||
<FontAwesomeIcon icon={faQuestion} className={'question-icon'}/>
|
||||
<p>How to generate keys</p>
|
||||
</span>
|
||||
<span>
|
||||
<FontAwesomeIcon icon={docCollapseOpen ? faChevronDown : faChevronUp}/>
|
||||
</span>
|
||||
</button>
|
||||
<Collapse
|
||||
className='collapse-comp'
|
||||
isOpen={docCollapseOpen}
|
||||
render={getKeyCreationDocsContent}/>
|
||||
</div>);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={'aws-scoutsuite-key-configuration'}>
|
||||
{getKeyCreationDocs()}
|
||||
<Form className={'auth-form'} onSubmit={submitKeys}>
|
||||
<Form.Control onChange={evt => setAccessKeyId(evt.target.value)}
|
||||
type='text'
|
||||
placeholder='Access key ID'
|
||||
value={accessKeyId}/>
|
||||
<Form.Control onChange={evt => setSecretAccessKey(evt.target.value)}
|
||||
type='password'
|
||||
placeholder='Secret access key'
|
||||
value={secretAccessKey}/>
|
||||
<Form.Control onChange={evt => setSessionToken(evt.target.value)}
|
||||
type='text'
|
||||
placeholder='Session token (optional, only for temp. keys)'
|
||||
value={sessionToken}/>
|
||||
{
|
||||
errorMessage ?
|
||||
<div className="alert alert-danger" role="alert">{errorMessage}</div>
|
||||
:
|
||||
''
|
||||
}
|
||||
{
|
||||
successMessage ?
|
||||
<div className="alert alert-success" role="alert">{successMessage}
|
||||
Go back and
|
||||
<Button variant={'link'} onClick={() => props.setComponent()} className={'link-in-success-message'}>
|
||||
run Monkey from the Island server </Button> to start AWS scan!</div>
|
||||
:
|
||||
''
|
||||
}
|
||||
<Row className={'justify-content-center'}>
|
||||
<Col lg={4} md={6} sm={8} xs={12}>
|
||||
<Button className={'monkey-submit-button'} type={'submit'}>
|
||||
Submit
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
import React from 'react';
|
||||
import InlineSelection from '../../../../ui-components/inline-selection/InlineSelection';
|
||||
import NextSelectionButton from '../../../../ui-components/inline-selection/NextSelectionButton';
|
||||
import {faKey, faTerminal} from '@fortawesome/free-solid-svg-icons';
|
||||
import AWSCLISetup from './AWSCLISetup';
|
||||
import CloudOptions from '../CloudOptions';
|
||||
import AWSKeySetup from './AWSKeySetup';
|
||||
|
||||
|
||||
const AWSSetupOptions = (props) => {
|
||||
return InlineSelection(getContents, {
|
||||
...props,
|
||||
onBackButtonClick: () => {
|
||||
props.setComponent(CloudOptions, props);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getContents = (props) => {
|
||||
return (
|
||||
<>
|
||||
<NextSelectionButton title={'Security keys'}
|
||||
description={'Provide security keys for monkey to authenticate.'}
|
||||
icon={faKey}
|
||||
onButtonClick={() => {
|
||||
props.setComponent(AWSKeySetup,
|
||||
{setComponent: props.setComponent})
|
||||
}}/>
|
||||
<NextSelectionButton title={'AWS CLI'}
|
||||
description={'Manually configure AWS CLI yourself.'}
|
||||
icon={faTerminal}
|
||||
onButtonClick={() => {
|
||||
props.setComponent(AWSCLISetup,
|
||||
{setComponent: props.setComponent})
|
||||
}}/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default AWSSetupOptions;
|
|
@ -1,65 +0,0 @@
|
|||
import React, {useEffect, useState} from 'react';
|
||||
import InlineSelection from '../../../ui-components/inline-selection/InlineSelection';
|
||||
import NextSelectionButton from '../../../ui-components/inline-selection/NextSelectionButton';
|
||||
import {faCheck, faCloud, faSync} from '@fortawesome/free-solid-svg-icons';
|
||||
import AWSSetupOptions from './AWSConfiguration/AWSSetupOptions';
|
||||
import {PROVIDERS} from './ProvidersEnum';
|
||||
import AuthComponent from '../../../AuthComponent';
|
||||
|
||||
|
||||
const CloudOptions = (props) => {
|
||||
return InlineSelection(getContents, {
|
||||
...props,
|
||||
onBackButtonClick: () => {
|
||||
props.setComponent()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const authComponent = new AuthComponent({})
|
||||
|
||||
const getContents = (props) => {
|
||||
|
||||
const [description, setDescription] = useState('Loading...');
|
||||
const [iconType, setIconType] = useState('spinning-icon');
|
||||
const [icon, setIcon] = useState(faSync);
|
||||
|
||||
useEffect(() => {
|
||||
authComponent.authFetch('/api/scoutsuite_auth/' + PROVIDERS.AWS)
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
if(res.is_setup){
|
||||
setDescription(getDescription(res.message));
|
||||
setIconType('icon-success');
|
||||
setIcon(faCheck);
|
||||
} else {
|
||||
setDescription('Setup Amazon Web Services infrastructure scan.');
|
||||
setIconType('')
|
||||
setIcon(faCloud);
|
||||
}
|
||||
});
|
||||
}, [props]);
|
||||
|
||||
function getDescription(message){
|
||||
return (
|
||||
<>
|
||||
{message} Run <b>from the Island</b> to start the scan. Click next to change the configuration.
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<NextSelectionButton title={'AWS'}
|
||||
description={description}
|
||||
icon={icon}
|
||||
iconType={iconType}
|
||||
onButtonClick={() => {
|
||||
props.setComponent(AWSSetupOptions,
|
||||
{setComponent: props.setComponent})
|
||||
}}/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default CloudOptions;
|
|
@ -1,9 +0,0 @@
|
|||
// Should match enum in monkey/common/cloud/scoutsuite_consts.py
|
||||
|
||||
export const PROVIDERS = {
|
||||
AWS : 'aws',
|
||||
AZURE : 'azure',
|
||||
GCP : 'gcp',
|
||||
ALIBABA : 'aliyun',
|
||||
ORACLE : 'oci'
|
||||
}
|
|
@ -30,8 +30,7 @@ class ZeroTrustReportPageComponent extends AuthComponent {
|
|||
<PrinciplesSection principles={this.state.principles}
|
||||
pillarsToStatuses={this.state.pillars.pillarsToStatuses}/>
|
||||
<FindingsSection pillarsToStatuses={this.state.pillars.pillarsToStatuses}
|
||||
findings={this.state.findings}
|
||||
scoutsuite_data={this.state.scoutsuite_data}/>
|
||||
findings={this.state.findings}/>
|
||||
</div>;
|
||||
}
|
||||
|
||||
|
@ -59,8 +58,7 @@ class ZeroTrustReportPageComponent extends AuthComponent {
|
|||
stillLoadingDataFromServer() {
|
||||
return typeof this.state.findings === 'undefined'
|
||||
|| typeof this.state.pillars === 'undefined'
|
||||
|| typeof this.state.principles === 'undefined'
|
||||
|| typeof this.state.scoutsuite_data === 'undefined';
|
||||
|| typeof this.state.principles === 'undefined';
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -33,13 +33,10 @@ class FindingsSection extends Component {
|
|||
</p>
|
||||
|
||||
<FindingsTable data={findingsByStatus[ZeroTrustStatuses.failed]}
|
||||
scoutsuite_data={this.props.scoutsuite_data}
|
||||
status={ZeroTrustStatuses.failed}/>
|
||||
<FindingsTable data={findingsByStatus[ZeroTrustStatuses.verify]}
|
||||
scoutsuite_data={this.props.scoutsuite_data}
|
||||
status={ZeroTrustStatuses.verify}/>
|
||||
<FindingsTable data={findingsByStatus[ZeroTrustStatuses.passed]}
|
||||
scoutsuite_data={this.props.scoutsuite_data}
|
||||
status={ZeroTrustStatuses.passed}/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -4,7 +4,6 @@ import PaginatedTable from '../common/PaginatedTable';
|
|||
import * as PropTypes from 'prop-types';
|
||||
import PillarLabel from './PillarLabel';
|
||||
import EventsButton from './EventsButton';
|
||||
import ScoutSuiteRuleButton from './scoutsuite/ScoutSuiteRuleButton';
|
||||
|
||||
const EVENTS_COLUMN_MAX_WIDTH = 180;
|
||||
const PILLARS_COLUMN_MAX_WIDTH = 260;
|
||||
|
@ -36,16 +35,11 @@ export class FindingsTable extends Component {
|
|||
];
|
||||
|
||||
getFindingDetails(finding) {
|
||||
if ('scoutsuite_rules' in finding.details) {
|
||||
return <ScoutSuiteRuleButton scoutsuite_rules={finding.details.scoutsuite_rules}
|
||||
scoutsuite_data={this.props.scoutsuite_data}/>;
|
||||
} else {
|
||||
return <EventsButton finding_id={finding.finding_id}
|
||||
latest_events={finding.details.latest_events}
|
||||
oldest_events={finding.details.oldest_events}
|
||||
event_count={finding.details.event_count}
|
||||
exportFilename={'Events_' + finding.test_key}/>;
|
||||
}
|
||||
return <EventsButton finding_id={finding.finding_id}
|
||||
latest_events={finding.details.latest_events}
|
||||
oldest_events={finding.details.oldest_events}
|
||||
event_count={finding.details.event_count}
|
||||
exportFilename={'Events_' + finding.test_key}/>;
|
||||
}
|
||||
|
||||
getFindingPillars(finding) {
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
import React, {useState} from 'react';
|
||||
import * as PropTypes from 'prop-types';
|
||||
import '../../../../styles/components/scoutsuite/RuleDisplay.scss'
|
||||
import classNames from 'classnames';
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
||||
import {faChevronDown} from '@fortawesome/free-solid-svg-icons/faChevronDown';
|
||||
import {faChevronUp} from '@fortawesome/free-solid-svg-icons/faChevronUp';
|
||||
import ScoutSuiteDataParser from './ScoutSuiteDataParser';
|
||||
import Collapse from '@kunukn/react-collapse';
|
||||
import {faArrowRight} from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
export default function ResourceDropdown(props) {
|
||||
|
||||
const [isCollapseOpen, setIsCollapseOpen] = useState(false);
|
||||
let parser = new ScoutSuiteDataParser(props.scoutsuite_data.data.services);
|
||||
let resource_value = parser.getResourceValue(props.resource_path, props.template_path);
|
||||
|
||||
function getResourceDropdown() {
|
||||
return (
|
||||
<div key={props.resource_path} className={classNames('collapse-item',
|
||||
'resource-collapse', {'item--active': isCollapseOpen})}>
|
||||
<button className={'btn-collapse'}
|
||||
onClick={() => setIsCollapseOpen(!isCollapseOpen)}>
|
||||
<span>
|
||||
{Object.prototype.hasOwnProperty.call(resource_value, 'name') ?
|
||||
resource_value.name : props.resource_path}
|
||||
</span>
|
||||
<span>
|
||||
<FontAwesomeIcon icon={isCollapseOpen ? faChevronDown : faChevronUp}/>
|
||||
</span>
|
||||
</button>
|
||||
<Collapse
|
||||
className='collapse-comp'
|
||||
isOpen={isCollapseOpen}
|
||||
render={getResourceDropdownContents}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function replacePathDotsWithArrows(resourcePath) {
|
||||
let path_vars = resourcePath.split('.')
|
||||
let display_path = []
|
||||
for (let i = 0; i < path_vars.length; i++) {
|
||||
display_path.push(path_vars[i])
|
||||
if (i !== path_vars.length - 1) {
|
||||
display_path.push(<FontAwesomeIcon icon={faArrowRight} key={'arrow-' + i}/>)
|
||||
}
|
||||
}
|
||||
return display_path;
|
||||
}
|
||||
|
||||
function prettyPrintJson(data) {
|
||||
return JSON.stringify(data, null, 4);
|
||||
}
|
||||
|
||||
function getResourceValueDisplay() {
|
||||
return (
|
||||
<div>
|
||||
<p className={'resource-value-title'}>Value:</p>
|
||||
<pre className={'resource-value-json'}>{prettyPrintJson(resource_value)}</pre>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function getResourceDropdownContents() {
|
||||
return (
|
||||
<div className={'resource-display'}>
|
||||
<div>
|
||||
<p className={'resource-path-title'}>Path:</p>
|
||||
<p className={'resource-path-contents'}>{replacePathDotsWithArrows(props.resource_path)}</p>
|
||||
</div>
|
||||
{getResourceValueDisplay()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return getResourceDropdown();
|
||||
}
|
||||
|
||||
ResourceDropdown.propTypes = {
|
||||
template_path: PropTypes.string,
|
||||
resource_path: PropTypes.string,
|
||||
scoutsuite_data: PropTypes.object
|
||||
};
|
|
@ -1,70 +0,0 @@
|
|||
import React from 'react';
|
||||
import * as PropTypes from 'prop-types';
|
||||
import '../../../../styles/components/scoutsuite/RuleDisplay.scss'
|
||||
import ResourceDropdown from './ResourceDropdown';
|
||||
|
||||
export default function RuleDisplay(props) {
|
||||
|
||||
return (
|
||||
<div className={'scoutsuite-rule-display'}>
|
||||
<div className={'description'}>
|
||||
<h3>{props.rule.description}({props.rule.service})</h3>
|
||||
</div>
|
||||
<div className={'rationale'}>
|
||||
<p dangerouslySetInnerHTML={{__html: props.rule.rationale}}/>
|
||||
</div>
|
||||
<div className={'checked-resources'}>
|
||||
<p className={'checked-resources-title'}>Resources checked: </p>
|
||||
<p>{props.rule.checked_items}</p>
|
||||
</div>
|
||||
{getReferences()}
|
||||
{getResources()}
|
||||
</div>);
|
||||
|
||||
function getReferences() {
|
||||
let references = []
|
||||
props.rule.references.forEach(reference => {
|
||||
references.push(<a href={reference}
|
||||
className={'reference-link'}
|
||||
target={'_blank'}
|
||||
rel="noopener noreferrer"
|
||||
key={reference}>{reference}</a>)
|
||||
})
|
||||
if (references.length) {
|
||||
return (
|
||||
<div className={'reference-list'}>
|
||||
<p className={'reference-list-title'}>References:</p>
|
||||
{references}
|
||||
</div>)
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function getResources() {
|
||||
let resources = []
|
||||
for (let i = 0; i < props.rule.items.length; i++) {
|
||||
let item = props.rule.items[i];
|
||||
let template_path = Object.prototype.hasOwnProperty.call(props.rule, 'display_path')
|
||||
? props.rule.display_path : props.rule.path;
|
||||
resources.push(<ResourceDropdown resource_path={item}
|
||||
template_path={template_path}
|
||||
scoutsuite_data={props.scoutsuite_data}
|
||||
key={template_path + i}/>)
|
||||
}
|
||||
if (resources.length) {
|
||||
return (
|
||||
<div className={'reference-list'}>
|
||||
<p className={'reference-list-title'}>Flagged resources (<b>{props.rule.flagged_items}</b>):</p>
|
||||
{resources}
|
||||
</div>)
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RuleDisplay.propTypes = {
|
||||
rule: PropTypes.object,
|
||||
scoutsuite_data: PropTypes.object
|
||||
};
|
|
@ -1,118 +0,0 @@
|
|||
export default class ScoutSuiteDataParser {
|
||||
constructor(runResults) {
|
||||
this.runResults = runResults
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets value of cloud resource based on path of specific checked field and more abstract template path,
|
||||
* which describes the scope of resource values.
|
||||
* @param itemPath contains path to a specific value e.g. s3.buckets.da1e7081077ce92.secure_transport_enabled
|
||||
* @param templatePath contains a template path for resource we would want to display e.g. s3.buckets.id
|
||||
* @returns {*[]|*} resource value e.g. {'bucket_id': 123, 'bucket_max_size': '123GB'}
|
||||
*/
|
||||
getResourceValue(itemPath, templatePath) {
|
||||
let resourcePath = this.fillTemplatePath(itemPath, templatePath);
|
||||
return this.getObjectValueByPath(resourcePath, this.runResults);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces id's in template path with id's from item path to form actual path to the object
|
||||
* @param itemPath e.g. s3.buckets.da1e7081077ce92.secure_transport_enabled
|
||||
* @param templatePath e.g. s3.buckets.id
|
||||
* @returns {*} e.g. s3.buckets.da1e7081077ce92
|
||||
*/
|
||||
fillTemplatePath(itemPath, templatePath) {
|
||||
let itemPathArray = itemPath.split('.');
|
||||
let templatePathArray = templatePath.split('.');
|
||||
let resourcePathArray = templatePathArray.map((val, i) => {
|
||||
return val === 'id' ? itemPathArray[i] : val
|
||||
})
|
||||
return resourcePathArray.join('.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves value from ScoutSuite data object based on path, provided in the rule
|
||||
* @param path E.g. a.id.c.id.e
|
||||
* @param source E.g. {a: {b: {c: {d: {e: [{result1: 'result1'}, {result2: 'result2'}]}}}}}
|
||||
* @returns {*[]|*} E.g. ['result1', 'result2']
|
||||
*/
|
||||
getObjectValueByPath(path, source) {
|
||||
let key;
|
||||
|
||||
while (path) {
|
||||
key = this.getNextKeyInPath(path);
|
||||
source = this.getValueForKey(key, path, source);
|
||||
path = this.trimFirstKey(path);
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets next key from the path
|
||||
* @param path e.g. s3.buckets.id
|
||||
* @returns {string|*} s3
|
||||
*/
|
||||
getNextKeyInPath(path) {
|
||||
if (path.indexOf('.') !== -1) {
|
||||
return path.substr(0, path.indexOf('.'));
|
||||
} else {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns value from object, based on path and current key
|
||||
* @param key E.g. "a"
|
||||
* @param path E.g. "a.b.c"
|
||||
* @param source E.g. {a: {b: {c: 'result'}}}
|
||||
* @returns {[]|*} E.g. {b: {c: 'result'}}
|
||||
*/
|
||||
getValueForKey(key, path, source) {
|
||||
if (key === 'id') {
|
||||
return this.getValueByReplacingUnknownKey(path, source);
|
||||
} else {
|
||||
return source[key];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets value from object if first key in path doesn't match source object
|
||||
* @param path unknown.b.c
|
||||
* @param source {a: {b: {c: [{result:'result'}]}}}
|
||||
* @returns {[]} 'result'
|
||||
*/
|
||||
getValueByReplacingUnknownKey(path, source) {
|
||||
let value = [];
|
||||
for (let key in source) {
|
||||
value = this.getObjectValueByPath(this.replaceFirstKey(path, key), source);
|
||||
value = value.concat(Object.values(value));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces first key in path
|
||||
* @param path E.g. "one.two.three"
|
||||
* @param replacement E.g. "four"
|
||||
* @returns string E.g. "four.two.three"
|
||||
*/
|
||||
replaceFirstKey(path, replacement) {
|
||||
return replacement + path.substr(path.indexOf('.'), path.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims the first key from dot separated path.
|
||||
* @param path E.g. "one.two.three"
|
||||
* @returns {string|boolean} E.g. "two.three"
|
||||
*/
|
||||
trimFirstKey(path) {
|
||||
if (path.indexOf('.') !== -1) {
|
||||
return path.substr(path.indexOf('.') + 1, path.length);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
import React, {Component} from 'react';
|
||||
import {Button} from 'react-bootstrap';
|
||||
import * as PropTypes from 'prop-types';
|
||||
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
||||
import {faList} from '@fortawesome/free-solid-svg-icons/faList';
|
||||
import ScoutSuiteRuleModal from './ScoutSuiteRuleModal';
|
||||
import CountBadge from '../../../ui-components/CountBadge';
|
||||
|
||||
export default class ScoutSuiteRuleButton extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isModalOpen: false
|
||||
}
|
||||
}
|
||||
|
||||
toggleModal = () => {
|
||||
this.setState({isModalOpen: !this.state.isModalOpen});
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<ScoutSuiteRuleModal scoutsuite_rules={this.props.scoutsuite_rules}
|
||||
scoutsuite_data={this.props.scoutsuite_data}
|
||||
isModalOpen={this.state.isModalOpen}
|
||||
hideCallback={this.toggleModal} />
|
||||
<div className="text-center" style={{'display': 'grid'}}>
|
||||
<Button variant={'monkey-info'} size={'lg'} onClick={this.toggleModal}>
|
||||
<FontAwesomeIcon icon={faList}/> Rules
|
||||
<CountBadge count={this.props.scoutsuite_rules.length}/>
|
||||
</Button>
|
||||
</div>
|
||||
</>);
|
||||
}
|
||||
|
||||
createRuleCountBadge() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ScoutSuiteRuleButton.propTypes = {
|
||||
scoutsuite_rules: PropTypes.array,
|
||||
scoutsuite_data: PropTypes.object
|
||||
};
|
|
@ -1,94 +0,0 @@
|
|||
import React, {useState} from 'react';
|
||||
import {Modal} from 'react-bootstrap';
|
||||
import * as PropTypes from 'prop-types';
|
||||
import Pluralize from 'pluralize';
|
||||
import ScoutSuiteSingleRuleDropdown from './ScoutSuiteSingleRuleDropdown';
|
||||
import '../../../../styles/components/scoutsuite/RuleModal.scss';
|
||||
import STATUSES from '../../common/consts/StatusConsts';
|
||||
import {getRuleCountByStatus, sortRules} from './rule-parsing/ParsingUtils';
|
||||
|
||||
|
||||
export default function ScoutSuiteRuleModal(props) {
|
||||
const [openRuleId, setOpenRuleId] = useState(null)
|
||||
|
||||
function toggleRuleDropdown(ruleId) {
|
||||
let ruleIdToSet = (openRuleId === ruleId) ? null : ruleId;
|
||||
setOpenRuleId(ruleIdToSet);
|
||||
}
|
||||
|
||||
function renderRuleDropdowns() {
|
||||
let dropdowns = [];
|
||||
let rules = sortRules(props.scoutsuite_rules);
|
||||
rules.forEach(rule => {
|
||||
let dropdown = (<ScoutSuiteSingleRuleDropdown isCollapseOpen={openRuleId === rule.description}
|
||||
toggleCallback={() => toggleRuleDropdown(rule.description)}
|
||||
rule={rule}
|
||||
scoutsuite_data={props.scoutsuite_data}
|
||||
key={rule.description + rule.path}/>)
|
||||
dropdowns.push(dropdown)
|
||||
});
|
||||
return dropdowns;
|
||||
}
|
||||
|
||||
function getGeneralRuleOverview() {
|
||||
return <>
|
||||
There {Pluralize('is', props.scoutsuite_rules.length)}
|
||||
<span className={'badge badge-primary'}>{props.scoutsuite_rules.length}</span>
|
||||
ScoutSuite {Pluralize('rule', props.scoutsuite_rules.length)} associated with this finding.
|
||||
</>
|
||||
}
|
||||
|
||||
function getFailedRuleOverview() {
|
||||
let failedRuleCnt = getRuleCountByStatus(props.scoutsuite_rules, STATUSES.STATUS_FAILED) +
|
||||
+ getRuleCountByStatus(props.scoutsuite_rules, STATUSES.STATUS_VERIFY);
|
||||
return <>
|
||||
<span className={'badge badge-danger'}>{failedRuleCnt}</span>
|
||||
failed security {Pluralize('rule', failedRuleCnt)}.
|
||||
</>
|
||||
}
|
||||
|
||||
function getPassedRuleOverview() {
|
||||
let passedRuleCnt = getRuleCountByStatus(props.scoutsuite_rules, STATUSES.STATUS_PASSED);
|
||||
return <>
|
||||
<span className={'badge badge-success'}>{passedRuleCnt}</span>
|
||||
passed security {Pluralize('rule', passedRuleCnt)}.
|
||||
</>
|
||||
}
|
||||
|
||||
function getUnexecutedRuleOverview() {
|
||||
let unexecutedRuleCnt = getRuleCountByStatus(props.scoutsuite_rules, STATUSES.STATUS_UNEXECUTED);
|
||||
return <>
|
||||
<span className={'badge badge-default'}>{unexecutedRuleCnt}</span>
|
||||
{Pluralize('rule', unexecutedRuleCnt)} {Pluralize('was', unexecutedRuleCnt)} not
|
||||
checked (no relevant resources for the rule).
|
||||
</>
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Modal show={props.isModalOpen} onHide={() => props.hideCallback()} className={'scoutsuite-rule-modal'}>
|
||||
<Modal.Body>
|
||||
<h3>
|
||||
<div className="text-center">ScoutSuite rules</div>
|
||||
</h3>
|
||||
<hr/>
|
||||
<p>
|
||||
{getGeneralRuleOverview()}
|
||||
{getFailedRuleOverview()}
|
||||
{getPassedRuleOverview()}
|
||||
{getUnexecutedRuleOverview()}
|
||||
</p>
|
||||
{renderRuleDropdowns()}
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
ScoutSuiteRuleModal.propTypes = {
|
||||
isModalOpen: PropTypes.bool,
|
||||
scoutsuite_rules: PropTypes.array,
|
||||
scoutsuite_data: PropTypes.object,
|
||||
hideCallback: PropTypes.func
|
||||
};
|
|
@ -1,79 +0,0 @@
|
|||
import React from 'react';
|
||||
import Collapse from '@kunukn/react-collapse';
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'
|
||||
import {faChevronUp} from '@fortawesome/free-solid-svg-icons/faChevronUp'
|
||||
import {faChevronDown} from '@fortawesome/free-solid-svg-icons/faChevronDown'
|
||||
|
||||
import classNames from 'classnames';
|
||||
import * as PropTypes from 'prop-types';
|
||||
import STATUSES from '../../common/consts/StatusConsts';
|
||||
import {faCheckCircle, faCircle, faExclamationCircle} from '@fortawesome/free-solid-svg-icons';
|
||||
import RuleDisplay from './RuleDisplay';
|
||||
import {getRuleStatus} from './rule-parsing/ParsingUtils';
|
||||
|
||||
export default function ScoutSuiteSingleRuleDropdown(props) {
|
||||
|
||||
function getRuleCollapse() {
|
||||
return (
|
||||
<div className={classNames('collapse-item',
|
||||
'rule-collapse', {'item--active': props.isCollapseOpen})}>
|
||||
<button className={classNames('btn-collapse', getDropdownClass())}
|
||||
onClick={props.toggleCallback}>
|
||||
<span>
|
||||
<FontAwesomeIcon icon={getRuleIcon()}/>
|
||||
{props.rule.description}
|
||||
</span>
|
||||
<span>
|
||||
<FontAwesomeIcon icon={props.isCollapseOpen ? faChevronDown : faChevronUp}/>
|
||||
</span>
|
||||
</button>
|
||||
<Collapse
|
||||
className='collapse-comp'
|
||||
isOpen={props.isCollapseOpen}
|
||||
render={renderRule}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function getRuleIcon() {
|
||||
let ruleStatus = getRuleStatus(props.rule);
|
||||
switch (ruleStatus) {
|
||||
case STATUSES.STATUS_PASSED:
|
||||
return faCheckCircle;
|
||||
case STATUSES.STATUS_VERIFY:
|
||||
return faExclamationCircle;
|
||||
case STATUSES.STATUS_FAILED:
|
||||
return faExclamationCircle;
|
||||
case STATUSES.STATUS_UNEXECUTED:
|
||||
return faCircle;
|
||||
}
|
||||
}
|
||||
|
||||
function getDropdownClass() {
|
||||
let ruleStatus = getRuleStatus(props.rule);
|
||||
switch (ruleStatus) {
|
||||
case STATUSES.STATUS_PASSED:
|
||||
return 'collapse-success';
|
||||
case STATUSES.STATUS_VERIFY:
|
||||
return 'collapse-danger';
|
||||
case STATUSES.STATUS_FAILED:
|
||||
return 'collapse-danger';
|
||||
case STATUSES.STATUS_UNEXECUTED:
|
||||
return 'collapse-default';
|
||||
}
|
||||
}
|
||||
|
||||
function renderRule() {
|
||||
return <RuleDisplay rule={props.rule} scoutsuite_data={props.scoutsuite_data}/>
|
||||
}
|
||||
|
||||
return getRuleCollapse();
|
||||
}
|
||||
|
||||
|
||||
ScoutSuiteSingleRuleDropdown.propTypes = {
|
||||
isCollapseOpen: PropTypes.bool,
|
||||
rule: PropTypes.object,
|
||||
scoutsuite_data: PropTypes.object,
|
||||
toggleCallback: PropTypes.func
|
||||
};
|
|
@ -1,40 +0,0 @@
|
|||
import STATUSES from '../../../common/consts/StatusConsts';
|
||||
import RULE_LEVELS from '../../../common/consts/ScoutSuiteConsts/RuleLevels';
|
||||
|
||||
export function getRuleStatus(rule) {
|
||||
if (rule.checked_items === 0) {
|
||||
return STATUSES.STATUS_UNEXECUTED
|
||||
} else if (rule.items.length === 0) {
|
||||
return STATUSES.STATUS_PASSED
|
||||
} else if (rule.level === RULE_LEVELS.LEVEL_WARNING) {
|
||||
return STATUSES.STATUS_VERIFY
|
||||
} else {
|
||||
return STATUSES.STATUS_FAILED
|
||||
}
|
||||
}
|
||||
|
||||
export function getRuleCountByStatus(rules, status) {
|
||||
return rules.filter(rule => getRuleStatus(rule) === status).length;
|
||||
}
|
||||
|
||||
export function sortRules(rules) {
|
||||
rules.sort(compareRules);
|
||||
return rules;
|
||||
}
|
||||
|
||||
function compareRules(firstRule, secondRule) {
|
||||
let firstStatus = getRuleStatus(firstRule);
|
||||
let secondStatus = getRuleStatus(secondRule);
|
||||
return compareRuleStatuses(firstStatus, secondStatus);
|
||||
}
|
||||
|
||||
function compareRuleStatuses(ruleStatusOne, ruleStatusTwo) {
|
||||
const severity_order = {
|
||||
[STATUSES.STATUS_FAILED]: 1,
|
||||
[STATUSES.STATUS_VERIFY]: 2,
|
||||
[STATUSES.STATUS_PASSED]: 3,
|
||||
[STATUSES.STATUS_UNEXECUTED]: 4
|
||||
}
|
||||
|
||||
return severity_order[ruleStatusOne] - severity_order[ruleStatusTwo]
|
||||
}
|
|
@ -13,7 +13,6 @@
|
|||
@import 'components/PreviewPane';
|
||||
@import 'components/AdvancedMultiSelect';
|
||||
@import 'components/particle-component/ParticleBackground';
|
||||
@import 'components/scoutsuite/ResourceDropdown';
|
||||
@import 'components/ImageModal';
|
||||
@import 'components/Icons';
|
||||
@import 'components/inline-selection/InlineSelection';
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
.aws-scoutsuite-configuration a {
|
||||
display: inline-block;
|
||||
padding: 0 0 3px 0;
|
||||
}
|
||||
|
||||
.aws-scoutsuite-configuration ol {
|
||||
padding-left: 15px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.aws-scoutsuite-configuration ol.nested-ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.aws-scoutsuite-configuration li {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.aws-scoutsuite-configuration h2 {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.aws-scoutsuite-configuration p {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.aws-scoutsuite-configuration .cli-link {
|
||||
padding: 0 0 4px 0;
|
||||
}
|
||||
|
||||
.monkey-submit-button {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.aws-scoutsuite-key-configuration .collapse-item {
|
||||
padding: 0;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.aws-scoutsuite-key-configuration .collapse-item .btn-collapse .question-icon {
|
||||
display: inline-block;
|
||||
margin-right: 7px;
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
|
||||
.aws-scoutsuite-key-configuration .collapse-item .btn-collapse p {
|
||||
display: inline-block;
|
||||
margin-bottom: 0;
|
||||
font-size: 1.2em;
|
||||
margin-left: 5px
|
||||
}
|
||||
|
||||
.aws-scoutsuite-key-configuration .key-creation-tutorial {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.aws-scoutsuite-key-configuration .key-creation-tutorial p {
|
||||
margin-bottom: 2px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.aws-scoutsuite-key-configuration .key-creation-tutorial h5 {
|
||||
margin-top: 15px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.aws-scoutsuite-key-configuration .key-creation-tutorial p:first-child {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.aws-scoutsuite-key-configuration .image-modal {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.aws-scoutsuite-key-configuration .key-creation-tutorial img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
.link-in-success-message {
|
||||
padding: 0 !important;
|
||||
vertical-align: initial !important;
|
||||
}
|
||||
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
.resource-display {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.resource-display .resource-value-json {
|
||||
background-color: $gray-200;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.resource-display .resource-path-contents svg {
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
.resource-display .resource-value-title,
|
||||
.resource-display .resource-path-title {
|
||||
margin-right:5px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 0;
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
.scoutsuite-rule-display .description h3{
|
||||
font-size: 1.2em;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.scoutsuite-rule-display p{
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.scoutsuite-rule-display .checked-resources-title,
|
||||
.scoutsuite-rule-display .flagged-resources-title,
|
||||
.scoutsuite-rule-display .reference-list-title{
|
||||
font-weight: 500;
|
||||
margin-right: 5px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.scoutsuite-rule-display .reference-list a {
|
||||
display: block;
|
||||
margin-left: 10px;
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
.scoutsuite-rule-modal .modal-dialog {
|
||||
max-width: 1000px;
|
||||
top: 0;
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.collapse-item.rule-collapse button > span:nth-child(2) {
|
||||
flex: 1
|
||||
}
|
|
@ -1,20 +1,9 @@
|
|||
from unittest import TestCase
|
||||
|
||||
from common.network.network_utils import (
|
||||
address_to_ip_port,
|
||||
get_host_from_network_location,
|
||||
remove_port,
|
||||
)
|
||||
from common.network.network_utils import address_to_ip_port, remove_port
|
||||
|
||||
|
||||
class TestNetworkUtils(TestCase):
|
||||
def test_get_host_from_network_location(self):
|
||||
assert get_host_from_network_location("127.0.0.1:12345") == "127.0.0.1"
|
||||
assert get_host_from_network_location("127.0.0.1:12345") == "127.0.0.1"
|
||||
assert get_host_from_network_location("127.0.0.1") == "127.0.0.1"
|
||||
assert get_host_from_network_location("www.google.com:8080") == "www.google.com"
|
||||
assert get_host_from_network_location("user:password@host:8080") == "host"
|
||||
|
||||
def test_remove_port_from_url(self):
|
||||
assert remove_port("https://google.com:80") == "https://google.com"
|
||||
assert remove_port("https://8.8.8.8:65336") == "https://8.8.8.8"
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
import pytest
|
||||
from mongoengine import ValidationError
|
||||
from tests.unit_tests.monkey_island.cc.services.zero_trust.test_common.scoutsuite_finding_data import ( # noqa: E501
|
||||
RULES,
|
||||
)
|
||||
|
||||
import common.common_consts.zero_trust_consts as zero_trust_consts
|
||||
from monkey_island.cc.models.zero_trust.finding import Finding
|
||||
from monkey_island.cc.models.zero_trust.monkey_finding_details import MonkeyFindingDetails
|
||||
from monkey_island.cc.models.zero_trust.scoutsuite_finding import ScoutSuiteFinding
|
||||
from monkey_island.cc.models.zero_trust.scoutsuite_finding_details import ScoutSuiteFindingDetails
|
||||
|
||||
MONKEY_FINDING_DETAIL_MOCK = MonkeyFindingDetails()
|
||||
MONKEY_FINDING_DETAIL_MOCK.events = ["mock1", "mock2"]
|
||||
SCOUTSUITE_FINDING_DETAIL_MOCK = ScoutSuiteFindingDetails()
|
||||
SCOUTSUITE_FINDING_DETAIL_MOCK.scoutsuite_rules = []
|
||||
|
||||
|
||||
class TestScoutSuiteFinding:
|
||||
@pytest.mark.usefixtures("uses_database")
|
||||
def test_save_finding_validation(self):
|
||||
with pytest.raises(ValidationError):
|
||||
_ = ScoutSuiteFinding.save_finding(
|
||||
test=zero_trust_consts.TEST_SEGMENTATION,
|
||||
status="bla bla",
|
||||
detail_ref=SCOUTSUITE_FINDING_DETAIL_MOCK,
|
||||
)
|
||||
|
||||
@pytest.mark.usefixtures("uses_database")
|
||||
def test_save_finding_sanity(self):
|
||||
assert len(Finding.objects(test=zero_trust_consts.TEST_SEGMENTATION)) == 0
|
||||
|
||||
rule_example = RULES[0]
|
||||
scoutsuite_details_example = ScoutSuiteFindingDetails()
|
||||
scoutsuite_details_example.scoutsuite_rules.append(rule_example)
|
||||
scoutsuite_details_example.save()
|
||||
ScoutSuiteFinding.save_finding(
|
||||
test=zero_trust_consts.TEST_SEGMENTATION,
|
||||
status=zero_trust_consts.STATUS_FAILED,
|
||||
detail_ref=scoutsuite_details_example,
|
||||
)
|
||||
|
||||
assert len(ScoutSuiteFinding.objects(test=zero_trust_consts.TEST_SEGMENTATION)) == 1
|
||||
assert len(ScoutSuiteFinding.objects(status=zero_trust_consts.STATUS_FAILED)) == 1
|
||||
assert len(Finding.objects(status=zero_trust_consts.STATUS_FAILED)) == 1
|
|
@ -1,169 +0,0 @@
|
|||
# This is what our codebase receives after running ScoutSuite module.
|
||||
# Object '...': {'...': '...'} represents continuation of similar objects as above
|
||||
RAW_SCOUTSUITE_DATA = {
|
||||
"sg_map": {
|
||||
"sg-abc": {"region": "ap-northeast-1", "vpc_id": "vpc-abc"},
|
||||
"sg-abcd": {"region": "ap-northeast-2", "vpc_id": "vpc-abc"},
|
||||
"...": {"...": "..."},
|
||||
},
|
||||
"subnet_map": {
|
||||
"subnet-abc": {"region": "ap-northeast-1", "vpc_id": "vpc-abc"},
|
||||
"subnet-abcd": {"region": "ap-northeast-1", "vpc_id": "vpc-abc"},
|
||||
"...": {"...": "..."},
|
||||
},
|
||||
"provider_code": "aws",
|
||||
"provider_name": "Amazon Web Services",
|
||||
"environment": None,
|
||||
"result_format": "json",
|
||||
"partition": "aws",
|
||||
"account_id": "125686982355",
|
||||
"last_run": {
|
||||
"time": "2021-02-05 16:03:04+0200",
|
||||
"run_parameters": {
|
||||
"services": [],
|
||||
"skipped_services": [],
|
||||
"regions": [],
|
||||
"excluded_regions": [],
|
||||
},
|
||||
"version": "5.10.0",
|
||||
"ruleset_name": "default",
|
||||
"ruleset_about": "This ruleset",
|
||||
"summary": {
|
||||
"ec2": {
|
||||
"checked_items": 3747,
|
||||
"flagged_items": 262,
|
||||
"max_level": "warning",
|
||||
"rules_count": 28,
|
||||
"resources_count": 176,
|
||||
},
|
||||
"s3": {
|
||||
"checked_items": 88,
|
||||
"flagged_items": 25,
|
||||
"max_level": "danger",
|
||||
"rules_count": 18,
|
||||
"resources_count": 5,
|
||||
},
|
||||
"...": {"...": "..."},
|
||||
},
|
||||
},
|
||||
"metadata": {
|
||||
"compute": {
|
||||
"summaries": {
|
||||
"external attack surface": {
|
||||
"cols": 1,
|
||||
"path": "service_groups.compute.summaries.external_attack_surface",
|
||||
"callbacks": [["merge", {"attribute": "external_attack_surface"}]],
|
||||
}
|
||||
},
|
||||
"...": {"...": "..."},
|
||||
},
|
||||
"...": {"...": "..."},
|
||||
},
|
||||
# This is the important part, which we parse to get resources
|
||||
"services": {
|
||||
"ec2": {
|
||||
"regions": {
|
||||
"ap-northeast-1": {
|
||||
"vpcs": {
|
||||
"vpc-abc": {
|
||||
"id": "vpc-abc",
|
||||
"security_groups": {
|
||||
"sg-abc": {
|
||||
"name": "default",
|
||||
"rules": {
|
||||
"ingress": {
|
||||
"protocols": {
|
||||
"ALL": {
|
||||
"ports": {
|
||||
"1-65535": {
|
||||
"cidrs": [{"CIDR": "0.0.0.0/0"}]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"count": 1,
|
||||
},
|
||||
"egress": {
|
||||
"protocols": {
|
||||
"ALL": {
|
||||
"ports": {
|
||||
"1-65535": {
|
||||
"cidrs": [{"CIDR": "0.0.0.0/0"}]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"count": 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
"...": {"...": "..."},
|
||||
}
|
||||
},
|
||||
# Interesting info, maybe could be used somewhere in the report
|
||||
"external_attack_surface": {
|
||||
"52.52.52.52": {
|
||||
"protocols": {"TCP": {"ports": {"22": {"cidrs": [{"CIDR": "0.0.0.0/0"}]}}}},
|
||||
"InstanceName": "InstanceName",
|
||||
"PublicDnsName": "ec2-52-52-52-52.eu-central-1.compute.amazonaws.com",
|
||||
}
|
||||
},
|
||||
# We parse these into ScoutSuite security rules
|
||||
"findings": {
|
||||
"ec2-security-group-opens-all-ports-to-all": {
|
||||
"description": "Security Group Opens All Ports to All",
|
||||
"path": "ec2.regions.id.vpcs.id.security_groups"
|
||||
".id.rules.id.protocols.id.ports.id.cidrs.id.CIDR",
|
||||
"level": "danger",
|
||||
"display_path": "ec2.regions.id.vpcs.id.security_groups.id",
|
||||
"items": [
|
||||
"ec2.regions.ap-northeast-1.vpcs.vpc-abc.security_groups"
|
||||
".sg-abc.rules.ingress.protocols.ALL.ports.1-65535.cidrs.0.CIDR"
|
||||
],
|
||||
"dashboard_name": "Rules",
|
||||
"checked_items": 179,
|
||||
"flagged_items": 2,
|
||||
"service": "EC2",
|
||||
"rationale": "It was detected that all ports in the security group are "
|
||||
"open <...>",
|
||||
"remediation": None,
|
||||
"compliance": None,
|
||||
"references": None,
|
||||
},
|
||||
"...": {"...": "..."},
|
||||
},
|
||||
},
|
||||
"...": {"...": "..."},
|
||||
},
|
||||
"service_list": [
|
||||
"acm",
|
||||
"awslambda",
|
||||
"cloudformation",
|
||||
"cloudtrail",
|
||||
"cloudwatch",
|
||||
"config",
|
||||
"directconnect",
|
||||
"dynamodb",
|
||||
"ec2",
|
||||
"efs",
|
||||
"elasticache",
|
||||
"elb",
|
||||
"elbv2",
|
||||
"emr",
|
||||
"iam",
|
||||
"kms",
|
||||
"rds",
|
||||
"redshift",
|
||||
"route53",
|
||||
"s3",
|
||||
"ses",
|
||||
"sns",
|
||||
"sqs",
|
||||
"vpc",
|
||||
"secretsmanager",
|
||||
],
|
||||
"service_groups": {"...": {"...": "..."}},
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
from enum import Enum
|
||||
|
||||
import pytest
|
||||
from tests.unit_tests.monkey_island.cc.services.zero_trust.raw_scoutsute_data import (
|
||||
RAW_SCOUTSUITE_DATA,
|
||||
)
|
||||
|
||||
from common.utils.exceptions import RulePathCreatorNotFound
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.ec2_rules import EC2Rules
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import SERVICES
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_parser import RuleParser
|
||||
|
||||
|
||||
class ExampleRules(Enum):
|
||||
NON_EXSISTENT_RULE = "bogus_rule"
|
||||
|
||||
|
||||
ALL_PORTS_OPEN = EC2Rules.SECURITY_GROUP_ALL_PORTS_TO_ALL
|
||||
|
||||
EXPECTED_RESULT = {
|
||||
"description": "Security Group Opens All Ports to All",
|
||||
"path": "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols.id.ports.id"
|
||||
".cidrs.id.CIDR",
|
||||
"level": "danger",
|
||||
"display_path": "ec2.regions.id.vpcs.id.security_groups.id",
|
||||
"items": [
|
||||
"ec2.regions.ap-northeast-1.vpcs.vpc-abc.security_groups."
|
||||
"sg-abc.rules.ingress.protocols.ALL.ports.1-65535.cidrs.0.CIDR"
|
||||
],
|
||||
"dashboard_name": "Rules",
|
||||
"checked_items": 179,
|
||||
"flagged_items": 2,
|
||||
"service": "EC2",
|
||||
"rationale": "It was detected that all ports in the security group are open <...>",
|
||||
"remediation": None,
|
||||
"compliance": None,
|
||||
"references": None,
|
||||
}
|
||||
|
||||
|
||||
def test_get_rule_data():
|
||||
# Test proper parsing of the raw data to rule
|
||||
results = RuleParser.get_rule_data(RAW_SCOUTSUITE_DATA[SERVICES], ALL_PORTS_OPEN)
|
||||
assert results == EXPECTED_RESULT
|
||||
|
||||
with pytest.raises(RulePathCreatorNotFound):
|
||||
RuleParser.get_rule_data(RAW_SCOUTSUITE_DATA[SERVICES], ExampleRules.NON_EXSISTENT_RULE)
|
||||
pass
|
|
@ -1,38 +0,0 @@
|
|||
from unittest.mock import MagicMock
|
||||
|
||||
import dpath.util
|
||||
import pytest
|
||||
|
||||
from common.config_value_paths import AWS_KEYS_PATH
|
||||
from monkey_island.cc.database import mongo
|
||||
from monkey_island.cc.server_utils.encryption import get_datastore_encryptor
|
||||
from monkey_island.cc.services.config import ConfigService
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.scoutsuite_auth_service import (
|
||||
is_aws_keys_setup,
|
||||
)
|
||||
|
||||
|
||||
class MockObject:
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.slow
|
||||
@pytest.mark.usefixtures("uses_database", "uses_encryptor")
|
||||
def test_is_aws_keys_setup(tmp_path):
|
||||
# Mock default configuration
|
||||
ConfigService.init_default_config()
|
||||
mongo.db = MockObject()
|
||||
mongo.db.config = MockObject()
|
||||
ConfigService.encrypt_config(ConfigService.default_config)
|
||||
mongo.db.config.find_one = MagicMock(return_value=ConfigService.default_config)
|
||||
assert not is_aws_keys_setup()
|
||||
|
||||
bogus_key_value = get_datastore_encryptor().encrypt("bogus_aws_key")
|
||||
dpath.util.set(
|
||||
ConfigService.default_config, AWS_KEYS_PATH + ["aws_secret_access_key"], bogus_key_value
|
||||
)
|
||||
dpath.util.set(
|
||||
ConfigService.default_config, AWS_KEYS_PATH + ["aws_access_key_id"], bogus_key_value
|
||||
)
|
||||
|
||||
assert is_aws_keys_setup()
|
|
@ -1,66 +0,0 @@
|
|||
from copy import deepcopy
|
||||
|
||||
from tests.unit_tests.monkey_island.cc.services.zero_trust.test_common.scoutsuite_finding_data import ( # noqa: E501
|
||||
RULES,
|
||||
)
|
||||
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_consts import (
|
||||
RULE_LEVEL_DANGER,
|
||||
RULE_LEVEL_WARNING,
|
||||
)
|
||||
from monkey_island.cc.services.zero_trust.scoutsuite.scoutsuite_rule_service import (
|
||||
ScoutSuiteRuleService,
|
||||
)
|
||||
|
||||
example_scoutsuite_data = {
|
||||
"checked_items": 179,
|
||||
"compliance": None,
|
||||
"dashboard_name": "Rules",
|
||||
"description": "Security Group Opens All Ports to All",
|
||||
"flagged_items": 2,
|
||||
"items": [
|
||||
"ec2.regions.eu-central-1.vpcs.vpc-0ee259b1a13c50229.security_groups.sg-035779fe5c293fc72"
|
||||
".rules.ingress.protocols.ALL.ports.1-65535.cidrs.2.CIDR",
|
||||
"ec2.regions.eu-central-1.vpcs.vpc-00015526b6695f9aa.security_groups.sg-019eb67135ec81e65"
|
||||
".rules.ingress.protocols.ALL.ports.1-65535.cidrs.0.CIDR",
|
||||
],
|
||||
"level": "danger",
|
||||
"path": "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols.id.ports.id"
|
||||
".cidrs.id.CIDR",
|
||||
"rationale": "It was detected that all ports in the security group are open, "
|
||||
"and any source IP address"
|
||||
" could send traffic to these ports, which creates a wider attack surface "
|
||||
"for resources "
|
||||
"assigned to it. Open ports should be reduced to the minimum needed to "
|
||||
"correctly",
|
||||
"references": [],
|
||||
"remediation": None,
|
||||
"service": "EC2",
|
||||
}
|
||||
|
||||
|
||||
def test_get_rule_from_rule_data():
|
||||
assert ScoutSuiteRuleService.get_rule_from_rule_data(example_scoutsuite_data) == RULES[0]
|
||||
|
||||
|
||||
def test_is_rule_dangerous():
|
||||
test_rule = deepcopy(RULES[0])
|
||||
assert ScoutSuiteRuleService.is_rule_dangerous(test_rule)
|
||||
|
||||
test_rule.level = RULE_LEVEL_WARNING
|
||||
assert not ScoutSuiteRuleService.is_rule_dangerous(test_rule)
|
||||
|
||||
test_rule.level = RULE_LEVEL_DANGER
|
||||
test_rule.items = []
|
||||
assert not ScoutSuiteRuleService.is_rule_dangerous(test_rule)
|
||||
|
||||
|
||||
def test_is_rule_warning():
|
||||
test_rule = deepcopy(RULES[0])
|
||||
assert not ScoutSuiteRuleService.is_rule_warning(test_rule)
|
||||
|
||||
test_rule.level = RULE_LEVEL_WARNING
|
||||
assert ScoutSuiteRuleService.is_rule_warning(test_rule)
|
||||
|
||||
test_rule.items = []
|
||||
assert not ScoutSuiteRuleService.is_rule_warning(test_rule)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue