nccgroup / PMapper

A tool for quickly evaluating IAM permissions in AWS.
GNU Affero General Public License v3.0
1.41k stars 169 forks source link

False negative - lambda:UpdateFunctionCode & lambda:UpdateFunctionConfiguration #86

Closed sethsec closed 3 years ago

sethsec commented 3 years ago

Brief Description I can't get pmapper to trigger on EditExistingLambdaFunctionWithRole even though I have have verified the exploit path manually (simulator results pasted below).

For additional context, PassExistingRoleToNewLambdaThenInvoke and PassRoleToNewLambdaThenTriggerWithNewDynamo are both detected correctly!

Side note: Pmapper is awesome! I love the recent improvements and the new detections!

IAM Action, Resource, and Condition Being Authorized & IAM Policies Attached to Principal Here's the IAM policy attached to my caller principal:

{
    "Statement": [
        {
            "Action": [
                "lambda:UpdateFunctionCode",
                "lambda:UpdateFunctionConfiguration"
            ],
            "Effect": "Allow",
            "Resource": "*"
        }
    ],
    "Version": "2012-10-17"
}

This policy is attached to the role arn:aws:iam::[ACCOUNT]:role/privesc17-EditExistingLambdaFunctionWithRole-role.

There is one lambda in the account, and that lambba has a high privileged role attached to it:

Lambda:

aws lambda list-functions
{
    "Functions": [
        {
            "FunctionName": "test_lambda",
            "FunctionArn": "arn:aws:lambda:us-east-1:[ACCOUNT]:function:test_lambda",
            "Runtime": "nodejs12.x",
            "Role": "arn:aws:iam::[ACCOUNT]:role/privesc-high-priv-lambda-role2",
            "Handler": "index.handler",
            "CodeSize": 240,
            "Description": "",
            "Timeout": 3,
            "MemorySize": 128,
            "LastModified": "2021-07-09T01:16:27.313+0000",
            "CodeSha256": "OT2zB5ADpBxEV3dYxHs6xl0IHaO6XXwABGvncPiBct0=",
            "Version": "$LATEST",
            "TracingConfig": {
                "Mode": "PassThrough"
            },
            "RevisionId": "4fdb8ba2-08a8-422d-8f9f-2708a35eef1c",
            "PackageType": "Zip"
        }
    ]
}

Here is the policy attached to "Role": "arn:aws:iam::[ACCOUNT]:role/privesc-high-priv-lambda-role2"

{
    "Statement": [
        {
            "Action": "*",
            "Effect": "Allow",
            "Resource": "*"
        }
    ],
    "Version": "2012-10-17"
}

Expected Behavior This should be detected as a privesc, but it is not detected.

AWS IAM Policy Simulation Result

Simulator confirms it is allowed

 aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::[ACCOUNT]:role/privesc17-EditExistingLambdaFunctionWithRole-role \
--action-names lambda:UpdateFunctionCode \
--resource-arns arn:aws:lambda:us-east-1:[ACCOUNT]:function:test_lambda
{
    "EvaluationResults": [
        {
            "EvalActionName": "lambda:UpdateFunctionCode",
            "EvalResourceName": "arn:aws:lambda:us-east-1:[ACCOUNT]:function:test_lambda",
            "EvalDecision": "allowed",
            "MatchedStatements": [
                {
                    "SourcePolicyId": "privesc17-EditExistingLambdaFunctionWithRole",
                    "SourcePolicyType": "IAM Policy",
                    "StartPosition": {
                        "Line": 1,
                        "Column": 15
                    },
                    "EndPosition": {
                        "Line": 1,
                        "Column": 124
                    }
                }
            ],
            "MissingContextValues": [],
            "EvalDecisionDetails": {},
            "ResourceSpecificResults": [
                {
                    "EvalResourceName": "arn:aws:lambda:us-east-1:[ACCOUNT]:function:test_lambda",
                    "EvalResourceDecision": "allowed",
                    "MatchedStatements": [
                        {
                            "SourcePolicyId": "privesc17-EditExistingLambdaFunctionWithRole",
                            "SourcePolicyType": "IAM Policy",
                            "StartPosition": {
                                "Line": 1,
                                "Column": 15
                            },
                            "EndPosition": {
                                "Line": 1,
                                "Column": 124
                            }
                        }
                    ],
                    "MissingContextValues": []
                }
            ]
        }
    ]
}
ncc-erik-steringer commented 3 years ago

Thank you for the report! Just a couple follow-up questions:

Additional context, here's the source code that is supposed to detect this type of Edge: https://github.com/nccgroup/PMapper/blob/v1.1.3-dev/principalmapper/graphing/lambda_edges.py#L139-L176

ncc-erik-steringer commented 3 years ago

Found the issue, applied a fix in 05504a756a0b444023112c529f012c1e5d5ba4a8 and verified it worked on my machine. This has affected all v1.1.X up until this point. Please try the latest release (master branch of the repo or v1.1.3 from PyPI) and verify that it is working for you as well.

sethsec commented 3 years ago

Confirmed on my end. Nice work!