mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 06:45:08 +00:00
fix(elbv2 desync check): Mixed elbv2 desync and smuggling (#2171)
This commit is contained in:
@@ -137,7 +137,6 @@ checks_v3_to_v2_mapping = {
|
||||
"elbv2_internet_facing": "extra79",
|
||||
"elbv2_listeners_underneath": "extra7158",
|
||||
"elbv2_logging_enabled": "extra717",
|
||||
"elbv2_request_smugling": "extra7142",
|
||||
"elbv2_ssl_listeners": "extra793",
|
||||
"elbv2_waf_acl_attached": "extra7129",
|
||||
"emr_cluster_account_public_block_enabled": "extra7178",
|
||||
|
||||
2
poetry.lock
generated
2
poetry.lock
generated
@@ -1,4 +1,4 @@
|
||||
# This file is automatically @generated by Poetry and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 1.4.0 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "about-time"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"Provider": "aws",
|
||||
"CheckID": "elbv2_desync_mitigation_mode",
|
||||
"CheckTitle": "Check whether the Application Load Balancer is configured with defensive or strictest desync mitigation mode.",
|
||||
"CheckTitle": "Check whether the Application Load Balancer is configured with defensive or strictest desync mitigation mode, if not check if at least is configured with the drop_invalid_header_fields attribute",
|
||||
"CheckType": [
|
||||
"Data Protection"
|
||||
],
|
||||
@@ -10,7 +10,7 @@
|
||||
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "AwsElasticLoadBalancingV2LoadBalancer",
|
||||
"Description": "Check whether the Application Load Balancer is configured with defensive or strictest desync mitigation mode.",
|
||||
"Description": "Check whether the Application Load Balancer is configured with defensive or strictest desync mitigation mode, if not check if at least is configured with the drop_invalid_header_fields attribute",
|
||||
"Risk": "HTTP Desync issues can lead to request smuggling and make your applications vulnerable to request queue or cache poisoning; which could lead to credential hijacking or execution of unauthorized commands.",
|
||||
"RelatedUrl": "",
|
||||
"Remediation": {
|
||||
@@ -21,7 +21,7 @@
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Ensure Application Load Balancer is configured with defensive or strictest desync mitigation mode.",
|
||||
"Text": "Ensure Application Load Balancer is configured with defensive or strictest desync mitigation mode or with the drop_invalid_header_fields attribute enabled",
|
||||
"Url": "https://aws.amazon.com/about-aws/whats-new/2020/08/application-and-classic-load-balancers-adding-defense-in-depth-with-introduction-of-desync-mitigation-mode/"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -15,9 +15,11 @@ class elbv2_desync_mitigation_mode(Check):
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"ELBv2 ALB {lb.name} is configured with correct desync mitigation mode."
|
||||
if lb.desync_mitigation_mode == "monitor":
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"ELBv2 ALB {lb.name} does not have desync mitigation mode set as defensive or strictest."
|
||||
|
||||
if lb.drop_invalid_header_fields == "false":
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"ELBv2 ALB {lb.name} does not have desync mitigation mode set as defensive or strictest and is not dropping invalid header fields"
|
||||
elif lb.drop_invalid_header_fields == "true":
|
||||
report.status_extended = f"ELBv2 ALB {lb.name} does not have desync mitigation mode set as defensive or strictest but is dropping invalid header fields"
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
{
|
||||
"Provider": "aws",
|
||||
"CheckID": "elbv2_request_smugling",
|
||||
"CheckTitle": "Check if Application Load Balancer is dropping invalid packets to prevent header based HTTP request smuggling.",
|
||||
"CheckType": [
|
||||
"Data Protection"
|
||||
],
|
||||
"ServiceName": "elbv2",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "AwsElasticLoadBalancingV2LoadBalancer",
|
||||
"Description": "Check if Application Load Balancer is dropping invalid packets to prevent header based HTTP request smuggling.",
|
||||
"Risk": "ALB can be target of actors sending bad HTTP headers.",
|
||||
"RelatedUrl": "",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "aws elbv2 modify-load-balancer-attributes --load-balancer-arn <lb_arn> --attributes Key=routing.http.drop_invalid_header_fields.enabled,Value=true",
|
||||
"NativeIaC": "",
|
||||
"Other": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/ELBv2/drop-invalid-header-fields-enabled.html",
|
||||
"Terraform": "https://docs.bridgecrew.io/docs/ensure-that-alb-drops-http-headers#terraform"
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Ensure Application Load Balancer is configured for HTTP headers with header fields that are not valid are removed by the load balancer (true).",
|
||||
"Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/application-load-balancers.html#deletion-protection"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": ""
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_AWS
|
||||
from prowler.providers.aws.services.elbv2.elbv2_client import elbv2_client
|
||||
|
||||
|
||||
class elbv2_request_smugling(Check):
|
||||
def execute(self):
|
||||
findings = []
|
||||
for lb in elbv2_client.loadbalancersv2:
|
||||
if lb.type == "application":
|
||||
report = Check_Report_AWS(self.metadata())
|
||||
report.region = lb.region
|
||||
report.resource_id = lb.name
|
||||
report.resource_arn = lb.arn
|
||||
report.resource_tags = lb.tags
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"ELBv2 ALB {lb.name} is not dropping invalid header fields."
|
||||
)
|
||||
if lb.drop_invalid_header_fields == "true":
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"ELBv2 ALB {lb.name} is dropping invalid header fields."
|
||||
)
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -11,7 +11,6 @@ AWS_ACCOUNT_NUMBER = "123456789012"
|
||||
class Test_elbv2_desync_mitigation_mode:
|
||||
@mock_elbv2
|
||||
def test_elb_no_balancers(self):
|
||||
|
||||
from prowler.providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||
from prowler.providers.aws.services.elbv2.elbv2_service import ELBv2
|
||||
|
||||
@@ -33,7 +32,7 @@ class Test_elbv2_desync_mitigation_mode:
|
||||
|
||||
@mock_ec2
|
||||
@mock_elbv2
|
||||
def test_elbv2_without_desync_mitigation_mode(self):
|
||||
def test_elbv2_without_desync_mitigation_mode_and_not_dropping_headers(self):
|
||||
conn = client("elbv2", region_name=AWS_REGION)
|
||||
ec2 = resource("ec2", region_name=AWS_REGION)
|
||||
|
||||
@@ -60,6 +59,10 @@ class Test_elbv2_desync_mitigation_mode:
|
||||
LoadBalancerArn=lb["LoadBalancerArn"],
|
||||
Attributes=[
|
||||
{"Key": "routing.http.desync_mitigation_mode", "Value": "monitor"},
|
||||
{
|
||||
"Key": "routing.http.drop_invalid_header_fields.enabled",
|
||||
"Value": "false",
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
@@ -82,7 +85,68 @@ class Test_elbv2_desync_mitigation_mode:
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert search(
|
||||
"does not have desync mitigation mode set as defensive or strictest",
|
||||
"does not have desync mitigation mode set as defensive or strictest and is not dropping invalid header fields",
|
||||
result[0].status_extended,
|
||||
)
|
||||
assert result[0].resource_id == "my-lb"
|
||||
assert result[0].resource_arn == lb["LoadBalancerArn"]
|
||||
|
||||
@mock_ec2
|
||||
@mock_elbv2
|
||||
def test_elbv2_without_desync_mitigation_mode_but_dropping_headers(self):
|
||||
conn = client("elbv2", region_name=AWS_REGION)
|
||||
ec2 = resource("ec2", region_name=AWS_REGION)
|
||||
|
||||
security_group = ec2.create_security_group(
|
||||
GroupName="a-security-group", Description="First One"
|
||||
)
|
||||
vpc = ec2.create_vpc(CidrBlock="172.28.7.0/24", InstanceTenancy="default")
|
||||
subnet1 = ec2.create_subnet(
|
||||
VpcId=vpc.id, CidrBlock="172.28.7.192/26", AvailabilityZone=f"{AWS_REGION}a"
|
||||
)
|
||||
subnet2 = ec2.create_subnet(
|
||||
VpcId=vpc.id, CidrBlock="172.28.7.0/26", AvailabilityZone=f"{AWS_REGION}b"
|
||||
)
|
||||
|
||||
lb = conn.create_load_balancer(
|
||||
Name="my-lb",
|
||||
Subnets=[subnet1.id, subnet2.id],
|
||||
SecurityGroups=[security_group.id],
|
||||
Scheme="internal",
|
||||
Type="application",
|
||||
)["LoadBalancers"][0]
|
||||
|
||||
conn.modify_load_balancer_attributes(
|
||||
LoadBalancerArn=lb["LoadBalancerArn"],
|
||||
Attributes=[
|
||||
{"Key": "routing.http.desync_mitigation_mode", "Value": "monitor"},
|
||||
{
|
||||
"Key": "routing.http.drop_invalid_header_fields.enabled",
|
||||
"Value": "true",
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
from prowler.providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||
from prowler.providers.aws.services.elbv2.elbv2_service import ELBv2
|
||||
|
||||
current_audit_info.audited_partition = "aws"
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.services.elbv2.elbv2_desync_mitigation_mode.elbv2_desync_mitigation_mode.elbv2_client",
|
||||
new=ELBv2(current_audit_info),
|
||||
):
|
||||
from prowler.providers.aws.services.elbv2.elbv2_desync_mitigation_mode.elbv2_desync_mitigation_mode import (
|
||||
elbv2_desync_mitigation_mode,
|
||||
)
|
||||
|
||||
check = elbv2_desync_mitigation_mode()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert search(
|
||||
"does not have desync mitigation mode set as defensive or strictest but is dropping invalid header fields",
|
||||
result[0].status_extended,
|
||||
)
|
||||
assert result[0].resource_id == "my-lb"
|
||||
|
||||
@@ -8,10 +8,9 @@ AWS_REGION = "eu-west-1"
|
||||
AWS_ACCOUNT_NUMBER = "123456789012"
|
||||
|
||||
|
||||
class Test_elbv2_request_smugling:
|
||||
class Test_elbv2_internet_facing:
|
||||
@mock_elbv2
|
||||
def test_elb_no_balancers(self):
|
||||
|
||||
from prowler.providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||
from prowler.providers.aws.services.elbv2.elbv2_service import ELBv2
|
||||
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
from re import search
|
||||
from unittest import mock
|
||||
|
||||
from boto3 import client, resource
|
||||
from moto import mock_ec2, mock_elbv2
|
||||
|
||||
AWS_REGION = "eu-west-1"
|
||||
AWS_ACCOUNT_NUMBER = "123456789012"
|
||||
|
||||
|
||||
class Test_elbv2_request_smugling:
|
||||
@mock_elbv2
|
||||
def test_elb_no_balancers(self):
|
||||
|
||||
from prowler.providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||
from prowler.providers.aws.services.elbv2.elbv2_service import ELBv2
|
||||
|
||||
current_audit_info.audited_partition = "aws"
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.services.elbv2.elbv2_request_smugling.elbv2_request_smugling.elbv2_client",
|
||||
new=ELBv2(current_audit_info),
|
||||
):
|
||||
# Test Check
|
||||
from prowler.providers.aws.services.elbv2.elbv2_request_smugling.elbv2_request_smugling import (
|
||||
elbv2_request_smugling,
|
||||
)
|
||||
|
||||
check = elbv2_request_smugling()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 0
|
||||
|
||||
@mock_ec2
|
||||
@mock_elbv2
|
||||
def test_elbv2_without_dropping(self):
|
||||
conn = client("elbv2", region_name=AWS_REGION)
|
||||
ec2 = resource("ec2", region_name=AWS_REGION)
|
||||
|
||||
security_group = ec2.create_security_group(
|
||||
GroupName="a-security-group", Description="First One"
|
||||
)
|
||||
vpc = ec2.create_vpc(CidrBlock="172.28.7.0/24", InstanceTenancy="default")
|
||||
subnet1 = ec2.create_subnet(
|
||||
VpcId=vpc.id, CidrBlock="172.28.7.192/26", AvailabilityZone=f"{AWS_REGION}a"
|
||||
)
|
||||
subnet2 = ec2.create_subnet(
|
||||
VpcId=vpc.id, CidrBlock="172.28.7.0/26", AvailabilityZone=f"{AWS_REGION}b"
|
||||
)
|
||||
|
||||
lb = conn.create_load_balancer(
|
||||
Name="my-lb",
|
||||
Subnets=[subnet1.id, subnet2.id],
|
||||
SecurityGroups=[security_group.id],
|
||||
Scheme="internal",
|
||||
Type="application",
|
||||
)["LoadBalancers"][0]
|
||||
|
||||
conn.modify_load_balancer_attributes(
|
||||
LoadBalancerArn=lb["LoadBalancerArn"],
|
||||
Attributes=[
|
||||
{
|
||||
"Key": "routing.http.drop_invalid_header_fields.enabled",
|
||||
"Value": "false",
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
from prowler.providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||
from prowler.providers.aws.services.elbv2.elbv2_service import ELBv2
|
||||
|
||||
current_audit_info.audited_partition = "aws"
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.services.elbv2.elbv2_request_smugling.elbv2_request_smugling.elbv2_client",
|
||||
new=ELBv2(current_audit_info),
|
||||
):
|
||||
from prowler.providers.aws.services.elbv2.elbv2_request_smugling.elbv2_request_smugling import (
|
||||
elbv2_request_smugling,
|
||||
)
|
||||
|
||||
check = elbv2_request_smugling()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert search(
|
||||
"is not dropping invalid header fields",
|
||||
result[0].status_extended,
|
||||
)
|
||||
assert result[0].resource_id == "my-lb"
|
||||
assert result[0].resource_arn == lb["LoadBalancerArn"]
|
||||
|
||||
@mock_ec2
|
||||
@mock_elbv2
|
||||
def test_elbv2_with_dropping(self):
|
||||
conn = client("elbv2", region_name=AWS_REGION)
|
||||
ec2 = resource("ec2", region_name=AWS_REGION)
|
||||
|
||||
security_group = ec2.create_security_group(
|
||||
GroupName="a-security-group", Description="First One"
|
||||
)
|
||||
vpc = ec2.create_vpc(CidrBlock="172.28.7.0/24", InstanceTenancy="default")
|
||||
subnet1 = ec2.create_subnet(
|
||||
VpcId=vpc.id, CidrBlock="172.28.7.192/26", AvailabilityZone=f"{AWS_REGION}a"
|
||||
)
|
||||
subnet2 = ec2.create_subnet(
|
||||
VpcId=vpc.id, CidrBlock="172.28.7.0/26", AvailabilityZone=f"{AWS_REGION}b"
|
||||
)
|
||||
|
||||
lb = conn.create_load_balancer(
|
||||
Name="my-lb",
|
||||
Subnets=[subnet1.id, subnet2.id],
|
||||
SecurityGroups=[security_group.id],
|
||||
Scheme="internal",
|
||||
)["LoadBalancers"][0]
|
||||
|
||||
conn.modify_load_balancer_attributes(
|
||||
LoadBalancerArn=lb["LoadBalancerArn"],
|
||||
Attributes=[
|
||||
{
|
||||
"Key": "routing.http.drop_invalid_header_fields.enabled",
|
||||
"Value": "true",
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
from prowler.providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||
from prowler.providers.aws.services.elbv2.elbv2_service import ELBv2
|
||||
|
||||
current_audit_info.audited_partition = "aws"
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.services.elbv2.elbv2_request_smugling.elbv2_request_smugling.elbv2_client",
|
||||
new=ELBv2(current_audit_info),
|
||||
):
|
||||
from prowler.providers.aws.services.elbv2.elbv2_request_smugling.elbv2_request_smugling import (
|
||||
elbv2_request_smugling,
|
||||
)
|
||||
|
||||
check = elbv2_request_smugling()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert search(
|
||||
"is dropping invalid header fields",
|
||||
result[0].status_extended,
|
||||
)
|
||||
assert result[0].resource_id == "my-lb"
|
||||
assert result[0].resource_arn == lb["LoadBalancerArn"]
|
||||
Reference in New Issue
Block a user