mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 14:55:00 +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_internet_facing": "extra79",
|
||||||
"elbv2_listeners_underneath": "extra7158",
|
"elbv2_listeners_underneath": "extra7158",
|
||||||
"elbv2_logging_enabled": "extra717",
|
"elbv2_logging_enabled": "extra717",
|
||||||
"elbv2_request_smugling": "extra7142",
|
|
||||||
"elbv2_ssl_listeners": "extra793",
|
"elbv2_ssl_listeners": "extra793",
|
||||||
"elbv2_waf_acl_attached": "extra7129",
|
"elbv2_waf_acl_attached": "extra7129",
|
||||||
"emr_cluster_account_public_block_enabled": "extra7178",
|
"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]]
|
[[package]]
|
||||||
name = "about-time"
|
name = "about-time"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"Provider": "aws",
|
"Provider": "aws",
|
||||||
"CheckID": "elbv2_desync_mitigation_mode",
|
"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": [
|
"CheckType": [
|
||||||
"Data Protection"
|
"Data Protection"
|
||||||
],
|
],
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
|
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
|
||||||
"Severity": "medium",
|
"Severity": "medium",
|
||||||
"ResourceType": "AwsElasticLoadBalancingV2LoadBalancer",
|
"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.",
|
"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": "",
|
"RelatedUrl": "",
|
||||||
"Remediation": {
|
"Remediation": {
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
"Terraform": ""
|
"Terraform": ""
|
||||||
},
|
},
|
||||||
"Recommendation": {
|
"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/"
|
"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 = "PASS"
|
||||||
report.status_extended = f"ELBv2 ALB {lb.name} is configured with correct desync mitigation mode."
|
report.status_extended = f"ELBv2 ALB {lb.name} is configured with correct desync mitigation mode."
|
||||||
if lb.desync_mitigation_mode == "monitor":
|
if lb.desync_mitigation_mode == "monitor":
|
||||||
report.status = "FAIL"
|
if lb.drop_invalid_header_fields == "false":
|
||||||
report.status_extended = f"ELBv2 ALB {lb.name} does not have desync mitigation mode set as defensive or strictest."
|
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)
|
findings.append(report)
|
||||||
|
|
||||||
return findings
|
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:
|
class Test_elbv2_desync_mitigation_mode:
|
||||||
@mock_elbv2
|
@mock_elbv2
|
||||||
def test_elb_no_balancers(self):
|
def test_elb_no_balancers(self):
|
||||||
|
|
||||||
from prowler.providers.aws.lib.audit_info.audit_info import current_audit_info
|
from prowler.providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||||
from prowler.providers.aws.services.elbv2.elbv2_service import ELBv2
|
from prowler.providers.aws.services.elbv2.elbv2_service import ELBv2
|
||||||
|
|
||||||
@@ -33,7 +32,7 @@ class Test_elbv2_desync_mitigation_mode:
|
|||||||
|
|
||||||
@mock_ec2
|
@mock_ec2
|
||||||
@mock_elbv2
|
@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)
|
conn = client("elbv2", region_name=AWS_REGION)
|
||||||
ec2 = resource("ec2", region_name=AWS_REGION)
|
ec2 = resource("ec2", region_name=AWS_REGION)
|
||||||
|
|
||||||
@@ -60,6 +59,10 @@ class Test_elbv2_desync_mitigation_mode:
|
|||||||
LoadBalancerArn=lb["LoadBalancerArn"],
|
LoadBalancerArn=lb["LoadBalancerArn"],
|
||||||
Attributes=[
|
Attributes=[
|
||||||
{"Key": "routing.http.desync_mitigation_mode", "Value": "monitor"},
|
{"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 len(result) == 1
|
||||||
assert result[0].status == "FAIL"
|
assert result[0].status == "FAIL"
|
||||||
assert search(
|
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,
|
result[0].status_extended,
|
||||||
)
|
)
|
||||||
assert result[0].resource_id == "my-lb"
|
assert result[0].resource_id == "my-lb"
|
||||||
|
|||||||
@@ -8,10 +8,9 @@ AWS_REGION = "eu-west-1"
|
|||||||
AWS_ACCOUNT_NUMBER = "123456789012"
|
AWS_ACCOUNT_NUMBER = "123456789012"
|
||||||
|
|
||||||
|
|
||||||
class Test_elbv2_request_smugling:
|
class Test_elbv2_internet_facing:
|
||||||
@mock_elbv2
|
@mock_elbv2
|
||||||
def test_elb_no_balancers(self):
|
def test_elb_no_balancers(self):
|
||||||
|
|
||||||
from prowler.providers.aws.lib.audit_info.audit_info import current_audit_info
|
from prowler.providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||||
from prowler.providers.aws.services.elbv2.elbv2_service import ELBv2
|
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