mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-24 13:01:56 +00:00
refactor(attack-paths): show target roles in PassRole escalation paths
Updated PassRole queries to display which specific role(s) can be passed in the visualization, instead of just showing a count. The path now shows: Principal → New Resource → Target Role → Privilege Escalation This allows users to see exactly which admin roles a principal can pass to escalate privileges, which is crucial for security analysis. Queries updated: Lambda, ECS, Glue, Bedrock, CloudFormation
This commit is contained in:
@@ -629,9 +629,6 @@ _QUERY_DEFINITIONS: dict[str, list[AttackPathsQueryDefinition]] = {
|
||||
OR action = '*'
|
||||
)
|
||||
|
||||
// Deduplicate principals FIRST (before matching target roles)
|
||||
WITH DISTINCT escalation_outcome, aws, principal
|
||||
|
||||
// Find target roles with elevated permissions that could be passed
|
||||
MATCH (aws)--(target_role:AWSRole)--(role_policy:AWSPolicy)--(role_stmt:AWSPolicyStatement)
|
||||
WHERE role_stmt.effect = 'Allow'
|
||||
@@ -640,7 +637,10 @@ _QUERY_DEFINITIONS: dict[str, list[AttackPathsQueryDefinition]] = {
|
||||
OR any(action IN role_stmt.action WHERE toLower(action) = 'iam:*')
|
||||
)
|
||||
|
||||
// Collect all target roles per principal
|
||||
// Deduplicate per (principal, target_role) pair
|
||||
WITH DISTINCT escalation_outcome, aws, principal, target_role
|
||||
|
||||
// Group by principal, collect target_roles
|
||||
WITH escalation_outcome, aws, principal,
|
||||
collect(DISTINCT target_role) AS target_roles,
|
||||
count(DISTINCT target_role) AS target_count
|
||||
@@ -659,16 +659,23 @@ _QUERY_DEFINITIONS: dict[str, list[AttackPathsQueryDefinition]] = {
|
||||
}, lambda_node)
|
||||
YIELD rel AS create_rel
|
||||
|
||||
CALL apoc.create.vRelationship(lambda_node, 'GRANTS_ACCESS', {
|
||||
// UNWIND target_roles to show which roles can be passed
|
||||
UNWIND target_roles AS target_role
|
||||
|
||||
CALL apoc.create.vRelationship(lambda_node, 'PASSES_ROLE', {}, target_role)
|
||||
YIELD rel AS pass_rel
|
||||
|
||||
CALL apoc.create.vRelationship(target_role, 'GRANTS_ACCESS', {
|
||||
reference: 'https://pathfinding.cloud/paths/lambda-001'
|
||||
}, escalation_outcome)
|
||||
YIELD rel AS grants_rel
|
||||
|
||||
// Re-match paths for visualization
|
||||
MATCH path_principal = (aws)--(principal)
|
||||
MATCH path_target = (aws)--(target_role)
|
||||
|
||||
RETURN path_principal,
|
||||
lambda_node, escalation_outcome, create_rel, grants_rel, target_count
|
||||
RETURN path_principal, path_target,
|
||||
lambda_node, escalation_outcome, create_rel, pass_rel, grants_rel, target_count
|
||||
""",
|
||||
parameters=[],
|
||||
),
|
||||
@@ -767,9 +774,6 @@ _QUERY_DEFINITIONS: dict[str, list[AttackPathsQueryDefinition]] = {
|
||||
any(action IN ecs_stmt.action WHERE toLower(action) = 'ecs:createservice' OR toLower(action) = 'ecs:runtask' OR action = '*' OR toLower(action) = 'ecs:*')
|
||||
)
|
||||
|
||||
// Deduplicate principals FIRST (before matching target roles)
|
||||
WITH DISTINCT escalation_outcome, aws, principal, effective_principal
|
||||
|
||||
// Find target roles with elevated permissions that could be passed
|
||||
MATCH (aws)--(target_role:AWSRole)--(target_policy:AWSPolicy)--(target_stmt:AWSPolicyStatement)
|
||||
WHERE target_stmt.effect = 'Allow'
|
||||
@@ -778,7 +782,10 @@ _QUERY_DEFINITIONS: dict[str, list[AttackPathsQueryDefinition]] = {
|
||||
OR any(action IN target_stmt.action WHERE toLower(action) = 'iam:*')
|
||||
)
|
||||
|
||||
// Collect all target roles per principal
|
||||
// Deduplicate per (principal, target_role) pair
|
||||
WITH DISTINCT escalation_outcome, aws, principal, effective_principal, target_role
|
||||
|
||||
// Group by principal, collect target_roles
|
||||
WITH escalation_outcome, aws, principal, effective_principal,
|
||||
collect(DISTINCT target_role) AS target_roles,
|
||||
count(DISTINCT target_role) AS target_count
|
||||
@@ -798,16 +805,23 @@ _QUERY_DEFINITIONS: dict[str, list[AttackPathsQueryDefinition]] = {
|
||||
}, ecs_task)
|
||||
YIELD rel AS create_rel
|
||||
|
||||
CALL apoc.create.vRelationship(ecs_task, 'GRANTS_ACCESS', {
|
||||
// UNWIND target_roles to show which roles can be passed
|
||||
UNWIND target_roles AS target_role
|
||||
|
||||
CALL apoc.create.vRelationship(ecs_task, 'PASSES_ROLE', {}, target_role)
|
||||
YIELD rel AS pass_rel
|
||||
|
||||
CALL apoc.create.vRelationship(target_role, 'GRANTS_ACCESS', {
|
||||
reference: 'https://pathfinding.cloud/paths/ecs-001'
|
||||
}, escalation_outcome)
|
||||
YIELD rel AS grants_rel
|
||||
|
||||
// Re-match paths for visualization
|
||||
MATCH path_principal = (aws)--(principal)
|
||||
MATCH path_target = (aws)--(target_role)
|
||||
|
||||
RETURN path_principal,
|
||||
ecs_task, escalation_outcome, create_rel, grants_rel, target_count
|
||||
RETURN path_principal, path_target,
|
||||
ecs_task, escalation_outcome, create_rel, pass_rel, grants_rel, target_count
|
||||
""",
|
||||
parameters=[],
|
||||
),
|
||||
@@ -911,9 +925,6 @@ _QUERY_DEFINITIONS: dict[str, list[AttackPathsQueryDefinition]] = {
|
||||
WHERE glue_stmt.effect = 'Allow'
|
||||
AND any(action IN glue_stmt.action WHERE toLower(action) = 'glue:createdevendpoint' OR action = '*' OR toLower(action) = 'glue:*')
|
||||
|
||||
// Deduplicate principals FIRST (before matching target roles)
|
||||
WITH DISTINCT escalation_outcome, aws, principal, effective_principal
|
||||
|
||||
// Find target roles with elevated permissions that could be passed
|
||||
MATCH (aws)--(target_role:AWSRole)--(target_policy:AWSPolicy)--(target_stmt:AWSPolicyStatement)
|
||||
WHERE target_stmt.effect = 'Allow'
|
||||
@@ -922,7 +933,10 @@ _QUERY_DEFINITIONS: dict[str, list[AttackPathsQueryDefinition]] = {
|
||||
OR any(action IN target_stmt.action WHERE toLower(action) = 'iam:*')
|
||||
)
|
||||
|
||||
// Collect all target roles per principal
|
||||
// Deduplicate per (principal, target_role) pair
|
||||
WITH DISTINCT escalation_outcome, aws, principal, effective_principal, target_role
|
||||
|
||||
// Group by principal, collect target_roles
|
||||
WITH escalation_outcome, aws, principal, effective_principal,
|
||||
collect(DISTINCT target_role) AS target_roles,
|
||||
count(DISTINCT target_role) AS target_count
|
||||
@@ -942,16 +956,23 @@ _QUERY_DEFINITIONS: dict[str, list[AttackPathsQueryDefinition]] = {
|
||||
}, glue_endpoint)
|
||||
YIELD rel AS create_rel
|
||||
|
||||
CALL apoc.create.vRelationship(glue_endpoint, 'GRANTS_ACCESS', {
|
||||
// UNWIND target_roles to show which roles can be passed
|
||||
UNWIND target_roles AS target_role
|
||||
|
||||
CALL apoc.create.vRelationship(glue_endpoint, 'PASSES_ROLE', {}, target_role)
|
||||
YIELD rel AS pass_rel
|
||||
|
||||
CALL apoc.create.vRelationship(target_role, 'GRANTS_ACCESS', {
|
||||
reference: 'https://pathfinding.cloud/paths/glue-001'
|
||||
}, escalation_outcome)
|
||||
YIELD rel AS grants_rel
|
||||
|
||||
// Re-match paths for visualization
|
||||
MATCH path_principal = (aws)--(principal)
|
||||
MATCH path_target = (aws)--(target_role)
|
||||
|
||||
RETURN path_principal,
|
||||
glue_endpoint, escalation_outcome, create_rel, grants_rel, target_count
|
||||
RETURN path_principal, path_target,
|
||||
glue_endpoint, escalation_outcome, create_rel, pass_rel, grants_rel, target_count
|
||||
""",
|
||||
parameters=[],
|
||||
),
|
||||
@@ -998,17 +1019,6 @@ _QUERY_DEFINITIONS: dict[str, list[AttackPathsQueryDefinition]] = {
|
||||
any(action IN bedrock_stmt.action WHERE toLower(action) = 'bedrock-agentcore:invoke' OR action = '*' OR toLower(action) = 'bedrock-agentcore:*')
|
||||
)
|
||||
|
||||
// Find target role with elevated permissions
|
||||
MATCH (aws)--(target_role:AWSRole)--(target_policy:AWSPolicy)--(target_stmt:AWSPolicyStatement)
|
||||
WHERE target_stmt.effect = 'Allow'
|
||||
AND (
|
||||
any(action IN target_stmt.action WHERE action = '*')
|
||||
OR any(action IN target_stmt.action WHERE toLower(action) = 'iam:*')
|
||||
)
|
||||
|
||||
// Deduplicate principals FIRST (before matching target roles)
|
||||
WITH DISTINCT escalation_outcome, aws, principal, effective_principal
|
||||
|
||||
// Find target roles with elevated permissions that could be passed
|
||||
MATCH (aws)--(target_role:AWSRole)--(target_policy:AWSPolicy)--(target_stmt:AWSPolicyStatement)
|
||||
WHERE target_stmt.effect = 'Allow'
|
||||
@@ -1017,7 +1027,10 @@ _QUERY_DEFINITIONS: dict[str, list[AttackPathsQueryDefinition]] = {
|
||||
OR any(action IN target_stmt.action WHERE toLower(action) = 'iam:*')
|
||||
)
|
||||
|
||||
// Collect all target roles per principal
|
||||
// Deduplicate per (principal, target_role) pair
|
||||
WITH DISTINCT escalation_outcome, aws, principal, effective_principal, target_role
|
||||
|
||||
// Group by principal, collect target_roles
|
||||
WITH escalation_outcome, aws, principal, effective_principal,
|
||||
collect(DISTINCT target_role) AS target_roles,
|
||||
count(DISTINCT target_role) AS target_count
|
||||
@@ -1037,16 +1050,23 @@ _QUERY_DEFINITIONS: dict[str, list[AttackPathsQueryDefinition]] = {
|
||||
}, bedrock_agent)
|
||||
YIELD rel AS create_rel
|
||||
|
||||
CALL apoc.create.vRelationship(bedrock_agent, 'GRANTS_ACCESS', {
|
||||
// UNWIND target_roles to show which roles can be passed
|
||||
UNWIND target_roles AS target_role
|
||||
|
||||
CALL apoc.create.vRelationship(bedrock_agent, 'PASSES_ROLE', {}, target_role)
|
||||
YIELD rel AS pass_rel
|
||||
|
||||
CALL apoc.create.vRelationship(target_role, 'GRANTS_ACCESS', {
|
||||
reference: 'https://pathfinding.cloud/paths/bedrock-001'
|
||||
}, escalation_outcome)
|
||||
YIELD rel AS grants_rel
|
||||
|
||||
// Re-match paths for visualization
|
||||
MATCH path_principal = (aws)--(principal)
|
||||
MATCH path_target = (aws)--(target_role)
|
||||
|
||||
RETURN path_principal,
|
||||
bedrock_agent, escalation_outcome, create_rel, grants_rel, target_count
|
||||
RETURN path_principal, path_target,
|
||||
bedrock_agent, escalation_outcome, create_rel, pass_rel, grants_rel, target_count
|
||||
""",
|
||||
parameters=[],
|
||||
),
|
||||
@@ -1085,9 +1105,6 @@ _QUERY_DEFINITIONS: dict[str, list[AttackPathsQueryDefinition]] = {
|
||||
WHERE cfn_stmt.effect = 'Allow'
|
||||
AND any(action IN cfn_stmt.action WHERE toLower(action) = 'cloudformation:createstack' OR action = '*' OR toLower(action) = 'cloudformation:*')
|
||||
|
||||
// Deduplicate principals FIRST (before matching target roles)
|
||||
WITH DISTINCT escalation_outcome, aws, principal, effective_principal
|
||||
|
||||
// Find target roles with elevated permissions that could be passed
|
||||
MATCH (aws)--(target_role:AWSRole)--(target_policy:AWSPolicy)--(target_stmt:AWSPolicyStatement)
|
||||
WHERE target_stmt.effect = 'Allow'
|
||||
@@ -1096,7 +1113,10 @@ _QUERY_DEFINITIONS: dict[str, list[AttackPathsQueryDefinition]] = {
|
||||
OR any(action IN target_stmt.action WHERE toLower(action) = 'iam:*')
|
||||
)
|
||||
|
||||
// Collect all target roles per principal
|
||||
// Deduplicate per (principal, target_role) pair
|
||||
WITH DISTINCT escalation_outcome, aws, principal, effective_principal, target_role
|
||||
|
||||
// Group by principal, collect target_roles
|
||||
WITH escalation_outcome, aws, principal, effective_principal,
|
||||
collect(DISTINCT target_role) AS target_roles,
|
||||
count(DISTINCT target_role) AS target_count
|
||||
@@ -1116,16 +1136,23 @@ _QUERY_DEFINITIONS: dict[str, list[AttackPathsQueryDefinition]] = {
|
||||
}, cfn_stack)
|
||||
YIELD rel AS create_rel
|
||||
|
||||
CALL apoc.create.vRelationship(cfn_stack, 'GRANTS_ACCESS', {
|
||||
// UNWIND target_roles to show which roles can be passed
|
||||
UNWIND target_roles AS target_role
|
||||
|
||||
CALL apoc.create.vRelationship(cfn_stack, 'PASSES_ROLE', {}, target_role)
|
||||
YIELD rel AS pass_rel
|
||||
|
||||
CALL apoc.create.vRelationship(target_role, 'GRANTS_ACCESS', {
|
||||
reference: 'https://pathfinding.cloud/paths/cloudformation-001'
|
||||
}, escalation_outcome)
|
||||
YIELD rel AS grants_rel
|
||||
|
||||
// Re-match paths for visualization
|
||||
MATCH path_principal = (aws)--(principal)
|
||||
MATCH path_target = (aws)--(target_role)
|
||||
|
||||
RETURN path_principal,
|
||||
cfn_stack, escalation_outcome, create_rel, grants_rel, target_count
|
||||
RETURN path_principal, path_target,
|
||||
cfn_stack, escalation_outcome, create_rel, pass_rel, grants_rel, target_count
|
||||
""",
|
||||
parameters=[],
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user