-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(gcp): add Shodan check for GCP External Addresses
- Loading branch information
Showing
11 changed files
with
223 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
34 changes: 34 additions & 0 deletions
34
...ervices/compute/compute_public_address_shodan/compute_public_address_shodan.metadata.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
{ | ||
"Provider": "compute", | ||
"CheckID": "compute_public_address_shodan", | ||
"CheckTitle": "Check if any of the Public Addresses are in Shodan (requires Shodan API KEY).", | ||
"CheckType": [ | ||
"Infrastructure Security" | ||
], | ||
"ServiceName": "compute", | ||
"SubServiceName": "", | ||
"ResourceIdTemplate": "", | ||
"Severity": "high", | ||
"ResourceType": "AwsEc2Eip", | ||
"Description": "Check if any of the Public Addresses are in Shodan (requires Shodan API KEY).", | ||
"Risk": "Sites like Shodan index exposed systems and further expose them to wider audiences as a quick way to find exploitable systems.", | ||
"RelatedUrl": "", | ||
"Remediation": { | ||
"Code": { | ||
"CLI": "", | ||
"NativeIaC": "", | ||
"Other": "", | ||
"Terraform": "" | ||
}, | ||
"Recommendation": { | ||
"Text": "Check Identified IPs; consider changing them to private ones and delete them from Shodan.", | ||
"Url": "https://www.shodan.io/" | ||
} | ||
}, | ||
"Categories": [ | ||
"internet-exposed" | ||
], | ||
"DependsOn": [], | ||
"RelatedTo": [], | ||
"Notes": "" | ||
} |
40 changes: 40 additions & 0 deletions
40
...iders/gcp/services/compute/compute_public_address_shodan/compute_public_address_shodan.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import shodan | ||
|
||
from prowler.lib.check.models import Check, Check_Report_GCP | ||
from prowler.lib.logger import logger | ||
from prowler.providers.gcp.services.compute.compute_client import compute_client | ||
|
||
|
||
class compute_public_address_shodan(Check): | ||
def execute(self): | ||
findings = [] | ||
shodan_api_key = compute_client.audit_config.get("shodan_api_key") | ||
if shodan_api_key: | ||
api = shodan.Shodan(shodan_api_key) | ||
for address in compute_client.addresses: | ||
if address.type == "EXTERNAL": | ||
report = Check_Report_GCP(self.metadata()) | ||
report.project_id = address.project_id | ||
report.resource_id = address.id | ||
report.location = address.region | ||
try: | ||
shodan_info = api.host(address.ip) | ||
report.status = "FAIL" | ||
report.status_extended = f"Public Address {address.ip} listed in Shodan with open ports {str(shodan_info['ports'])} and ISP {shodan_info['isp']} in {shodan_info['country_name']}. More info at https://www.shodan.io/host/{address.ip}." | ||
findings.append(report) | ||
except shodan.APIError as error: | ||
if "No information available for that IP" in error.value: | ||
report.status = "PASS" | ||
report.status_extended = ( | ||
f"Public Address {address.ip} is not listed in Shodan." | ||
) | ||
findings.append(report) | ||
continue | ||
else: | ||
logger.error(f"Unknown Shodan API Error: {error.value}") | ||
|
||
else: | ||
logger.error( | ||
"No Shodan API Key -- Please input a Shodan API Key with -N/--shodan or in config.yaml" | ||
) | ||
return findings |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
79 changes: 79 additions & 0 deletions
79
.../gcp/services/compute/compute_public_address_shodan/compute_public_address_shodan_test.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
from unittest import mock | ||
|
||
from prowler.providers.gcp.services.compute.compute_service import Address | ||
from tests.providers.gcp.lib.audit_info_utils import GCP_PROJECT_ID | ||
|
||
|
||
class Test_compute_public_address_shodan: | ||
def test_no_public_ip_addresses(self): | ||
compute_client = mock.MagicMock | ||
compute_client.addresses = {} | ||
compute_client.audit_info = mock.MagicMock | ||
|
||
with mock.patch( | ||
"prowler.providers.gcp.services.compute.compute_service.Network", | ||
new=compute_client, | ||
) as service_client, mock.patch( | ||
"prowler.providers.gcp.services.compute.compute_client.compute_client", | ||
new=service_client, | ||
): | ||
from prowler.providers.gcp.services.compute.compute_public_address_shodan.compute_public_address_shodan import ( | ||
compute_public_address_shodan, | ||
) | ||
|
||
compute_client.audit_config = {"shodan_api_key": "api_key"} | ||
|
||
check = compute_public_address_shodan() | ||
result = check.execute() | ||
assert len(result) == 0 | ||
|
||
def test_compute_ip_in_shodan(self): | ||
compute_client = mock.MagicMock | ||
public_ip_id = "id" | ||
public_ip_name = "name" | ||
ip_address = "ip_address" | ||
shodan_info = { | ||
"ports": [80, 443], | ||
"isp": "Microsoft Corporation", | ||
"country_name": "country_name", | ||
} | ||
compute_client.audit_info = mock.MagicMock | ||
|
||
compute_client.addresses = [ | ||
Address( | ||
id=public_ip_id, | ||
name=public_ip_name, | ||
type="EXTERNAL", | ||
ip=ip_address, | ||
region="region", | ||
network="network", | ||
project_id=GCP_PROJECT_ID, | ||
) | ||
] | ||
|
||
with mock.patch( | ||
"prowler.providers.gcp.services.compute.compute_service.Network", | ||
new=compute_client, | ||
) as service_client, mock.patch( | ||
"prowler.providers.gcp.services.compute.compute_client.compute_client", | ||
new=service_client, | ||
), mock.patch( | ||
"prowler.providers.gcp.services.compute.compute_public_address_shodan.compute_public_address_shodan.shodan.Shodan.host", | ||
return_value=shodan_info, | ||
): | ||
from prowler.providers.gcp.services.compute.compute_public_address_shodan.compute_public_address_shodan import ( | ||
compute_public_address_shodan, | ||
) | ||
|
||
compute_client.audit_config = {"shodan_api_key": "api_key"} | ||
check = compute_public_address_shodan() | ||
result = check.execute() | ||
assert len(result) == 1 | ||
assert result[0].status == "FAIL" | ||
assert ( | ||
result[0].status_extended | ||
== f"Public Address {ip_address} listed in Shodan with open ports {str(shodan_info['ports'])} and ISP {shodan_info['isp']} in {shodan_info['country_name']}. More info at https://www.shodan.io/host/{ip_address}." | ||
) | ||
assert result[0].project_id == GCP_PROJECT_ID | ||
assert result[0].location == "region" | ||
assert result[0].resource_id == public_ip_id |