Enhanced evaluate-iam-role.sh

This commit is contained in:
mgeeky 2019-12-06 13:28:08 +01:00
parent fb01387ed3
commit 98262b1cee
2 changed files with 261 additions and 76 deletions

View File

@ -93,7 +93,78 @@ Afterwards, one should see following logs in CloudWatch traces for planted Lambd
[*] Following S3 object could be removed: (Bucket=90112981864022885796153088027941100000000000000000000000, Key=cloudtrail/AWSLogs/712800000000/CloudTrail/us-west-2/2019/03/20/712800000000_CloudTrail_us-west-2_20190320T1000Z_oxxxxxxxxxxxxc.json.gz) [*] Following S3 object could be removed: (Bucket=90112981864022885796153088027941100000000000000000000000, Key=cloudtrail/AWSLogs/712800000000/CloudTrail/us-west-2/2019/03/20/712800000000_CloudTrail_us-west-2_20190320T1000Z_oxxxxxxxxxxxxc.json.gz)
``` ```
- **`evaluate-iam-role.sh`** - Enumerates attached IAM Role policies, goes through all of granted permissions and lists those that are known for Privilege Escalation risks. Based on [Rhino Security Labs work](https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation/). [gist](https://gist.github.com/mgeeky/14685d94af7848e64afefe6fd2341a18) - **`evaluate-iam-role.sh`** - Enumerates attached IAM Role policies or specified Policy by it's Arn, goes through all of granted permissions and lists those that are known for Privilege Escalation or other risks. If `all` was specified as a role-name, the tool will evaluate all of the user-specified IAM Roles, iteratively. Based on [Rhino Security Labs work](https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation/). [gist](https://gist.github.com/mgeeky/14685d94af7848e64afefe6fd2341a18)
```
attacker $ ./evaluate-iam-role.sh awl CustomSysOpsRole
[+] Working on specified Role: CustomSysOpsRole
[+] Role (CustomSysOpsRole) has following policies attached:
- arn:aws:iam::aws:policy/AmazonRDSFullAccess
- arn:aws:iam::aws:policy/AmazonEC2FullAccess
- arn:aws:iam::aws:policy/AWSLambdaFullAccess
- arn:aws:iam::aws:policy/AmazonS3FullAccess
- arn:aws:iam::aws:policy/ReadOnlyAccess
- arn:aws:iam::aws:policy/AmazonSSMFullAccess
- arn:aws:iam::aws:policy/AmazonMQFullAccess
- arn:aws:iam::aws:policy/AWSBackupAdminPolicy
[+] =============== Permissions granted ===============
a4b:Describe*
a4b:Get*
a4b:List*
a4b:Search*
acm:Describe*
acm:DescribeCertificate
acm:Get*
acm:List*
[...]
workdocs:Get*
worklink:Describe*
worklink:List*
workmail:Describe*
workmail:Get*
workmail:List*
workmail:Search*
workspaces:Describe*
xray:BatchGet*
xray:Get*
xray:PutTelemetryRecords
xray:PutTraceSegments
[-] =============== Detected POTENTIALLY dangerous permissions granted ===============
[...]
backup:*
backup-storage:*
clouddirectory:BatchRead
cloudformation:*
cloudformation:CreateStack
[...]
iot:CreateThing
iot:CreateTopicRule
sns:*
sqs:*
sqs:SendMessage
ssm:*
ssmmessages:CreateControlChannel
ssmmessages:CreateDataChannel
support:*
xray:BatchGet*
xray:PutTelemetryRecords
xray:PutTraceSegments
[!] =============== Detected DANGEROUS permissions granted ===============
cloudformation:CreateStack
iam:AttachRolePolicy
iam:PassRole
```
- **`exfiltrate-ec2.py`** - This script exploits insecure permissions given to the EC2 IAM Role allowing to exfiltrate target EC2's filesystem data in a form of it's shared EBS snapshot or publicly exposed AMI image. - **`exfiltrate-ec2.py`** - This script exploits insecure permissions given to the EC2 IAM Role allowing to exfiltrate target EC2's filesystem data in a form of it's shared EBS snapshot or publicly exposed AMI image.

View File

@ -1,131 +1,245 @@
#!/bin/bash #!/bin/bash
#
# Evaluates specified AWS IAM Role or Policy given their name/Arn.
# Dumps all of the attached policies in case of Role and all of defined
# policy statements. Then goes through allowed permissions to pick all of them out.
# Finally, checks every allowed permission against a list of known troublesome ones.
#
# Mariusz B., mgeeky '19, <mb@binary-offensive.com>
# v0.1
#
if [ $# -ne 2 ]; then if [ $# -lt 2 ] ; then
echo "Usage: evaluate-iam-role.sh <profile> <role-name>" echo "Usage: evaluate-iam-role.sh [-v] <profile> <role-name|policy-arn>"
echo
echo -e "-v\t\t\tVerbose mode. Dumps full roles/policies contents."
echo -e "profile\t\t\tAWS credentials profile name."
echo -e "role-name|policy-name\tEither IAM Role name or Policy Arn to evaluate."
echo -e "\t\t\tIf 'all' was specified, will evaluate ALL used IAM Roles"
exit 1 exit 1
fi fi
VERBOSE=0
if [[ "$1" == "-v" ]]; then
VERBOSE=1
shift
fi
PROFILE=$1 PROFILE=$1
ROLE_NAME=$2 ROLE_NAME=$2
known_potentially_dangerous_permissions=( known_potentially_dangerous_permissions=(
".*:\*" ".+:\*"
".*:.*Attach.*" ".*:Add.*"
".*:.*Create.*" ".*:Attach.*"
".*:.*Delete.*" ".*:Batch.*"
".*:.*Reboot.*" ".*:Change.*"
".*:.*Command.*" ".*:Command.*"
".*:.*Run.*" ".*:Create.*"
".*:.*Send.*" ".*:Delete.*"
".*:.*Batch.*" ".*:Execute.*"
".*:.*Set.*" ".*:Invoke.*"
".*:.*Invoke.*" ".*:Modify.*"
".*:.*Add.*" ".*:Put.*"
".*:.*Execute.*" ".*:Reboot.*"
".*:.*Start.*" ".*:Register.*"
".*:.*Modify.*" ".*:Replace.*"
".*:.*Register.*" ".*:Run.*"
".*:.*Replace.*" ".*:Send.*"
".*:.*Change.*" ".*:Set.*"
".*:.*Update.*" ".*:Start.*"
".*:.*Put.*" ".*:Update.*"
) )
known_dangerous_permissions=( known_dangerous_permissions=(
"\*:\*" "\*:\*"
"iam:\*"
"iam:CreatePolicyVersion"
"iam:SetDefaultPolicyVersion"
"iam:PassRole"
"ec2:RunInstances"
"iam:CreateAccessKey"
"iam:CreateLoginProfile"
"iam:UpdateLoginProfile"
"iam:AttachUserPolicy"
"iam:AttachGroupPolicy"
"iam:AttachRolePolicy"
"iam:PutUserPolicy"
"iam:PutGroupPolicy"
"iam:PutRolePolicy"
"iam:AddUserToGroup"
"iam:UpdateAssumeRolePolicy"
"sts:AssumeRole"
"iam:PassRole"
"lambda:CreateFunction"
"lambda:InvokeFunction"
"lambda:CreateEventSourceMapping"
"lambda:UpdateFunctionCode"
"glue:CreateDevEndpoint"
"glue:UpdateDevEndpoint"
"cloudformation:CreateStack" "cloudformation:CreateStack"
"datapipeline:CreatePipeline" "datapipeline:CreatePipeline"
"datapipeline:PutPipelineDefinition" "datapipeline:PutPipelineDefinition"
"ec2:RunInstances"
"glue:CreateDevEndpoint"
"glue:UpdateDevEndpoint"
"iam:\*"
"iam:AddUserToGroup"
"iam:AttachGroupPolicy"
"iam:AttachRolePolicy"
"iam:AttachUserPolicy"
"iam:CreateAccessKey"
"iam:CreateLoginProfile"
"iam:CreatePolicyVersion"
"iam:PassRole"
"iam:PassRole"
"iam:PutGroupPolicy"
"iam:PutRolePolicy"
"iam:PutUserPolicy"
"iam:SetDefaultPolicyVersion"
"iam:UpdateAssumeRolePolicy"
"iam:UpdateLoginProfile"
"lambda:CreateEventSourceMapping"
"lambda:CreateFunction"
"lambda:InvokeFunction"
"lambda:UpdateFunctionCode"
"sts:AssumeRole"
) )
role_policy=$(aws --profile $PROFILE iam get-role --role-name $ROLE_NAME) known_dangerous_aws_managed_policies=(
"arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM"
echo -e "=============== Role: $ROLE_NAME ===============" "arn:aws:iam::aws:policy/service-role/AmazonMachineLearningRoleforRedshiftDataSource"
echo "$role_policy" )
IFS=$'\n'
attached_role_policies=($(aws --profile $PROFILE iam list-attached-role-policies --role-name $ROLE_NAME | jq -r '.AttachedPolicies[].PolicyArn'))
dangerous_permissions=() dangerous_permissions=()
potentially_dangerous_permissions=() potentially_dangerous_permissions=()
all_perms=() all_perms=()
used_bad_policies=()
for policy in "${attached_role_policies[@]}" ; do function examine_policy() {
echo -e "\n=============== Attached Policy Arn: $policy ===============" policy=$1
role_name=$2
version_id=$(aws --profile $PROFILE iam get-policy --policy-arn $policy | jq -r '.Policy.DefaultVersionId') out=$(aws --profile $PROFILE iam get-policy --policy-arn $policy)
version_id=$(echo "$out" | jq -r '.Policy.DefaultVersionId')
policy_name=$(echo "$out" | jq -r '.Policy.PolicyName')
policy_version=$(aws --profile $PROFILE iam get-policy-version --policy-arn $policy --version-id $version_id) policy_version=$(aws --profile $PROFILE iam get-policy-version --policy-arn $policy --version-id $version_id)
if [[ $VERBOSE == 1 ]]; then
echo -e "\n------------[ Policy Arn: $policy ]------------"
echo "$policy_version" echo "$policy_version"
fi
permissions=($(echo "$policy_version" | jq -r '.PolicyVersion.Document.Statement[] | select(.Effect=="Allow") | if .Action|type=="string" then [.Action] else .Action end | .[]')) permissions=($(echo "$policy_version" | jq -r '.PolicyVersion.Document.Statement[] | select(.Effect=="Allow") | if .Action|type=="string" then [.Action] else .Action end | .[]'))
for perm in "${permissions[@]}" ; do path=""
all_perms+=("$perm") if [[ "$role_name" != "" ]]; then
for dangperm in "${known_dangerous_permissions[@]}"; do path="$role_name.$policy_name."
if echo "$dangperm" | grep -iq $perm ; then else
dangerous_permissions+=("$perm") path="$policy_name."
fi fi
done
for dangperm in "${known_potentially_dangerous_permissions[@]}"; do if [[ "$ROLE_NAME" != "all" ]] ; then
if echo "$perm" | grep -Piq "$dangperm" ; then path=""
potentially_dangerous_permissions+=("$perm") fi
for bad_policy in "${known_dangerous_aws_managed_policies[@]}"; do
if echo "$policy" | grep -iq "$bad_policy" ; then
used_bad_policies+=("$path$bad_policy")
fi fi
done
done
done done
for perm in "${permissions[@]}" ; do
permadd="$path$perm"
all_perms+=("$permadd")
for potdangperm in "${known_potentially_dangerous_permissions[@]}"; do
if [[ "$perm" == "iam:*" ]]; then continue ; fi
if echo "$perm" | grep -Piq "$potdangperm" ; then
potentially_dangerous_permissions+=("$permadd")
fi
done
for dangperm in "${known_dangerous_permissions[@]}"; do
if echo "$perm" | grep -iq "$dangperm" ; then
dangerous_permissions+=("$permadd")
fi
done
done
}
function examine_role() {
role_name=$1
role_policy=$(aws --profile $PROFILE iam get-role --role-name $role_name)
if [[ $VERBOSE == 1 ]]; then
echo -e "------------[ Role: $role_name ]------------"
echo "$role_policy"
fi
attached_role_policies=($(aws --profile $PROFILE iam list-attached-role-policies --role-name $role_name | jq -r '.AttachedPolicies[].PolicyArn'))
if [[ $VERBOSE == 1 ]]; then
echo
fi
echo "[+] Role ($role_name) has following policies attached:"
for policy in "${attached_role_policies[@]}" ; do
echo -e "\t- $policy"
done
if [[ $VERBOSE == 1 ]]; then
echo
fi
for policy in "${attached_role_policies[@]}" ; do
examine_policy $policy $role_name
done
}
#
#------------------------------------------------------------------
#
IFS=$'\n'
if [[ "$ROLE_NAME" == "all" ]]; then
echo "[+] Evaluating ALL used IAM Roles"
echo
out=($(aws --profile awl iam list-roles --query 'Roles[*].RoleName' --output text | tr '\t' '\n'))
for role in "${out[@]}"; do
examine_role $role
done
elif echo "$ROLE_NAME" | grep -q "arn:aws:iam:" && echo "$ROLE_NAME" | grep -q ":policy/" ; then
echo "[+] Working on specified Policy Arn: $ROLE_NAME"
echo
examine_policy $ROLE_NAME
else
echo "[+] Working on specified Role: $ROLE_NAME"
echo
examine_role $ROLE_NAME
fi
#------------------------------------------------------------------
if [[ ${#used_bad_policies[@]} -gt 0 ]]; then
echo -e "\n\n[-] =============== Found AWS Managed Insecure Policies in Use ==============="
echo
sorted=($(echo "${used_bad_policies[@]}" | tr ' ' '\n' | sort -u ))
for pol in "${sorted[@]}"; do
echo -e "\t$pol"
done
fi
if [[ ${#all_perms[@]} -gt 0 ]]; then if [[ ${#all_perms[@]} -gt 0 ]]; then
echo -e "\n\n=============== All permissions granted to this role ===============" echo -e "\n\n[+] =============== Permissions granted ==============="
echo
sorted=($(echo "${all_perms[@]}" | tr ' ' '\n' | sort -u )) sorted=($(echo "${all_perms[@]}" | tr ' ' '\n' | sort -u ))
for perm in "${sorted[@]}"; do for perm in "${sorted[@]}"; do
echo -e "\t$perm" echo -e "\t$perm" | sed -r 's/\./ -> /g'
done done
if [[ ${#potentially_dangerous_permissions[@]} -gt 0 ]]; then if [[ ${#potentially_dangerous_permissions[@]} -gt 0 ]]; then
echo -e "\n\n=============== Detected POTENTIALLY dangerous permissions granted ===============" echo -e "\n\n[-] =============== Detected POTENTIALLY dangerous permissions granted ==============="
echo
sorted=($(echo "${potentially_dangerous_permissions[@]}" | tr ' ' '\n' | sort -u )) sorted=($(echo "${potentially_dangerous_permissions[@]}" | tr ' ' '\n' | sort -u ))
for dangperm in "${sorted[@]}"; do for dangperm in "${sorted[@]}"; do
echo -e "\t$dangperm" echo -e "\t$dangperm" | sed -r 's/\./ -> /g'
done done
else
echo -e "\nNo potentially dangerous permissions were found to be granted."
fi fi
if [[ ${#dangerous_permissions[@]} -gt 0 ]]; then if [[ ${#dangerous_permissions[@]} -gt 0 ]]; then
echo -e "\n\n=============== Detected dangerous permissions granted ===============" echo -e "\n\n[!] =============== Detected DANGEROUS permissions granted ==============="
echo
sorted=($(echo "${dangerous_permissions[@]}" | tr ' ' '\n' | sort -u )) sorted=($(echo "${dangerous_permissions[@]}" | tr ' ' '\n' | sort -u ))
for dangperm in "${sorted[@]}"; do for dangperm in "${sorted[@]}"; do
echo -e "\t$dangperm" echo -e "\t$dangperm" | sed -r 's/\./ -> /g'
done done
else
echo -e "\nNo dangerous permissions were found to be granted."
fi fi
else else
echo -e "\nNo permissions were found to be granted." echo -e "\nNo permissions were found to be granted."
fi fi
echo