mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 14:55:00 +00:00
fix(route53_dangling_ip_subdomain_takeover): notify only IPs with AWS IP Ranges (#2396)
This commit is contained in:
14
poetry.lock
generated
14
poetry.lock
generated
@@ -67,6 +67,18 @@ docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-
|
||||
tests = ["attrs[tests-no-zope]", "zope-interface"]
|
||||
tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
|
||||
|
||||
[[package]]
|
||||
name = "awsipranges"
|
||||
version = "0.3.3"
|
||||
description = "Work with the AWS IP address ranges in native Python."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7,<4.0"
|
||||
files = [
|
||||
{file = "awsipranges-0.3.3-py3-none-any.whl", hash = "sha256:f3d7a54aeaf7fe310beb5d377a4034a63a51b72677ae6af3e0967bc4de7eedaf"},
|
||||
{file = "awsipranges-0.3.3.tar.gz", hash = "sha256:4f0b3f22a9dc1163c85b513bed812b6c92bdacd674e6a7b68252a3c25b99e2c0"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "azure-common"
|
||||
version = "1.1.28"
|
||||
@@ -2891,4 +2903,4 @@ docs = ["mkdocs", "mkdocs-material"]
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.9"
|
||||
content-hash = "25f5c9874335d9fe564abc5bd7938c9350fc083dc6074f5de9f75a916ba4d71c"
|
||||
content-hash = "60d5a4537ef2c46cf9ae54378fe801fda4adec8251c03cf60b815889b433f48f"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from ipaddress import ip_address
|
||||
|
||||
import awsipranges
|
||||
|
||||
from prowler.lib.check.models import Check, Check_Report_AWS
|
||||
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
|
||||
from prowler.providers.aws.services.route53.route53_client import route53_client
|
||||
@@ -32,8 +34,12 @@ class route53_dangling_ip_subdomain_takeover(Check):
|
||||
report.status_extended = f"Route53 record {record} in Hosted Zone {route53_client.hosted_zones[record_set.hosted_zone_id].name} is not a dangling IP."
|
||||
# If Public IP check if it is in the AWS Account
|
||||
if not ip_address(record).is_private and record not in public_ips:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Route53 record {record} in Hosted Zone {route53_client.hosted_zones[record_set.hosted_zone_id].name} is a dangling IP which can lead to a subdomain takeover attack!"
|
||||
report.status_extended = f"Route53 record {record} in Hosted Zone {route53_client.hosted_zones[record_set.hosted_zone_id].name} does not belong to AWS and it is not a dangling IP."
|
||||
# Check if potential dangling IP is within AWS Ranges
|
||||
aws_ip_ranges = awsipranges.get_ranges()
|
||||
if aws_ip_ranges.get(record):
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Route53 record {record} in Hosted Zone {route53_client.hosted_zones[record_set.hosted_zone_id].name} is a dangling IP which can lead to a subdomain takeover attack!"
|
||||
|
||||
findings.append(report)
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ version = "3.5.2"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
alive-progress = "3.1.1"
|
||||
awsipranges = "0.3.3"
|
||||
azure-identity = "1.13.0"
|
||||
azure-mgmt-authorization = "3.0.0"
|
||||
azure-mgmt-security = "5.0.0"
|
||||
|
||||
@@ -164,7 +164,7 @@ class Test_route53_dangling_ip_subdomain_takeover:
|
||||
|
||||
@mock_ec2
|
||||
@mock_route53
|
||||
def test_hosted_zone_dangling_public_record(self):
|
||||
def test_hosted_zone_external_record(self):
|
||||
conn = client("route53", region_name=AWS_REGION)
|
||||
|
||||
zone_id = conn.create_hosted_zone(
|
||||
@@ -191,6 +191,67 @@ class Test_route53_dangling_ip_subdomain_takeover:
|
||||
|
||||
audit_info = self.set_mocked_audit_info()
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.lib.audit_info.audit_info.current_audit_info",
|
||||
new=audit_info,
|
||||
):
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.services.route53.route53_dangling_ip_subdomain_takeover.route53_dangling_ip_subdomain_takeover.route53_client",
|
||||
new=Route53(audit_info),
|
||||
):
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.services.route53.route53_dangling_ip_subdomain_takeover.route53_dangling_ip_subdomain_takeover.ec2_client",
|
||||
new=EC2(audit_info),
|
||||
):
|
||||
# Test Check
|
||||
from prowler.providers.aws.services.route53.route53_dangling_ip_subdomain_takeover.route53_dangling_ip_subdomain_takeover import (
|
||||
route53_dangling_ip_subdomain_takeover,
|
||||
)
|
||||
|
||||
check = route53_dangling_ip_subdomain_takeover()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert search(
|
||||
"does not belong to AWS and it is not a dangling IP",
|
||||
result[0].status_extended,
|
||||
)
|
||||
assert result[0].resource_id == zone_id.replace("/hostedzone/", "")
|
||||
assert (
|
||||
result[0].resource_arn
|
||||
== f"arn:{audit_info.audited_partition}:route53:::{zone_id.replace('/hostedzone/','')}"
|
||||
)
|
||||
|
||||
@mock_ec2
|
||||
@mock_route53
|
||||
def test_hosted_zone_dangling_public_record(self):
|
||||
conn = client("route53", region_name=AWS_REGION)
|
||||
|
||||
zone_id = conn.create_hosted_zone(
|
||||
Name="testdns.aws.com.", CallerReference=str(hash("foo"))
|
||||
)["HostedZone"]["Id"]
|
||||
|
||||
conn.change_resource_record_sets(
|
||||
HostedZoneId=zone_id,
|
||||
ChangeBatch={
|
||||
"Changes": [
|
||||
{
|
||||
"Action": "CREATE",
|
||||
"ResourceRecordSet": {
|
||||
"Name": "foo.bar.testdns.aws.com",
|
||||
"Type": "A",
|
||||
"ResourceRecords": [{"Value": "54.152.12.70"}],
|
||||
},
|
||||
}
|
||||
]
|
||||
},
|
||||
)
|
||||
from prowler.providers.aws.services.ec2.ec2_service import EC2
|
||||
from prowler.providers.aws.services.route53.route53_service import Route53
|
||||
|
||||
audit_info = self.set_mocked_audit_info()
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.lib.audit_info.audit_info.current_audit_info",
|
||||
new=audit_info,
|
||||
|
||||
Reference in New Issue
Block a user