audit-labs/audit-tools

A collection of scripts, queries, and other goodies you can use in an audit.

clone: git clone https://gitbay.org/audit-labs/audit-tools.git

2713564fbe3060219d6e19a450793814147f8bb1

unsigned

author: Christian Cleberg <hello@cleberg.net> · 2025-12-15T02:18:40Z

add aws s3 bucket testing
 applications/aws/README.md         |  37 +++++++++++
 applications/aws/aws_s3_buckets.sh | 131 +++++++++++++++++++++++++++++++++++++
 2 files changed, 168 insertions(+)

diff --git a/applications/aws/README.md b/applications/aws/README.md
index 5d08f5d..310e505 100644
--- a/applications/aws/README.md
+++ b/applications/aws/README.md
@@ -204,4 +204,41 @@ Rule#,Policy‑Item,Expected,Actual,Result
 8,Maximum password age (days),90,90,PASS
 9,Prevent password reuse (last N),4,4,PASS
 10,Hard expiry (no grace period),false,false,PASS
+```
+
+# `aws_s3_buckets.sh`
+
+This script requires one non-interactive step. Simply run the script:
+
+``` bash
+chmod +x aws_s3_buckets.sh
+./aws_s3_buckets.sh
+```
+
+The shell will show you each bucket discovered during the scanning process, as well as the final result. This final result is a combination of the bucket's Public Access Block (PAB), Policy Status (IsPublic), and ACLs (AllUsers Group).
+
+``` text
+Starting FULL S3 Public Access Audit for the CURRENT account...
+---
+1. Retrieving all bucket names...
+Processing bucket: 13bf5920-a09f-47bc-a75a-394a09f18d6a
+  Region determined: eu-west-1
+  Final Status: FALSE
+Processing bucket: c67fa6bd-2fd5-4bc5-825d-587fb535bf2e
+  Region determined: eu-west-1
+  Final Status: FALSE
+---
+✅ Audit Complete.
+Final report saved to **s3_full_public_access_audit.csv**
+BucketName,Region,PAB_FullyRestricted,Policy_IsPublic,ACL_AllUsersRead,ACL_AllUsersWrite,OverallPublicStatus
+13bf5920-a09f-47bc-a75a-394a09f18d6a,eu-west-1,FALSE-VULNERABLE,No Policy,FALSE,FALSE,"FALSE"
+c67fa6bd-2fd5-4bc5-825d-587fb535bf2e,eu-west-1,TRUE,No Policy,FALSE,FALSE,"FALSE"
+```
+
+It will also save the results shown above to the `s3_full_public_access_audit.csv` file:
+
+``` csv
+BucketName,Region,PAB_FullyRestricted,Policy_IsPublic,ACL_AllUsersRead,ACL_AllUsersWrite,OverallPublicStatus
+13bf5920-a09f-47bc-a75a-394a09f18d6a,eu-west-1,FALSE-VULNERABLE,No Policy,FALSE,FALSE,"FALSE"
+c67fa6bd-2fd5-4bc5-825d-587fb535bf2e,eu-west-1,TRUE,No Policy,FALSE,FALSE,"FALSE"
 ```
\ No newline at end of file
diff --git a/applications/aws/aws_s3_buckets.sh b/applications/aws/aws_s3_buckets.sh
new file mode 100644
index 0000000..4c76c02
--- /dev/null
+++ b/applications/aws/aws_s3_buckets.sh
@@ -0,0 +1,131 @@
+#!/bin/bash
+
+# --- Configuration ---
+# File to store the final report
+REPORT_FILE="s3_full_public_access_audit.csv"
+# The region to use for the initial global list-buckets call (e.g., 'us-east-1')
+MASTER_REGION="us-east-1" 
+
+# AWS Regions to check for bucket location. Add more regions if your organization uses them.
+AWS_REGIONS="us-east-1 us-west-2 eu-central-1 ap-southeast-2"
+
+# --- Initialization ---
+echo "BucketName,Region,PAB_FullyRestricted,Policy_IsPublic,ACL_AllUsersRead,ACL_AllUsersWrite,OverallPublicStatus" > "$REPORT_FILE"
+echo "Starting FULL S3 Public Access Audit for the CURRENT account..."
+echo "---"
+
+# 1. Retrieve all bucket names
+echo "1. Retrieving all bucket names..."
+BUCKET_LIST=$(aws s3api list-buckets --region "$MASTER_REGION" --query 'Buckets[].Name' --output text)
+
+if [ -z "$BUCKET_LIST" ]; then
+    echo "✅ No S3 buckets found in this account."
+    exit 0
+fi
+
+# 2. & 3. Iterate through each bucket to find location and run checks
+for BUCKET_NAME in $BUCKET_LIST; do
+    
+    echo "Processing bucket: $BUCKET_NAME"
+    BUCKET_REGION=""
+
+    # 2. Find the bucket region
+    for REGION in $AWS_REGIONS; do
+        BUCKET_LOCATION_RESPONSE=$(aws s3api get-bucket-location --bucket "$BUCKET_NAME" --region "$REGION" 2>/dev/null)
+        if [ $? -eq 0 ]; then
+            LOCATION_CONSTRAINT=$(echo "$BUCKET_LOCATION_RESPONSE" | jq -r '.LocationConstraint')
+            BUCKET_REGION=${LOCATION_CONSTRAINT:-"us-east-1"}
+            break
+        fi
+    done
+    
+    if [ -z "$BUCKET_REGION" ]; then
+        echo "  ⚠️ WARNING: Could not determine region for $BUCKET_NAME. Skipping all checks."
+        echo "$BUCKET_NAME,UNKNOWN,N/A,N/A,N/A,N/A,UNKNOWN" >> "$REPORT_FILE"
+        continue
+    fi
+    
+    echo "  Region determined: $BUCKET_REGION"
+
+    # --- Variables for the three checks ---
+    PAB_FULLY_RESTRICTED="UNKNOWN"
+    POLICY_IS_PUBLIC="UNKNOWN"
+    ACL_ALL_USERS_READ="FALSE"
+    ACL_ALL_USERS_WRITE="FALSE"
+    OVERALL_PUBLIC_STATUS="FALSE" # Assume safe until proven otherwise
+
+    # --- CHECK A: Public Access Block (PAB) ---
+    PAB_STATUS=$(aws s3api get-public-access-block --bucket "$BUCKET_NAME" --region "$BUCKET_REGION" 2>/dev/null)
+    
+    if [ $? -ne 0 ]; then
+        # PAB Missing is the highest risk state.
+        PAB_FULLY_RESTRICTED="CRITICAL-MISSING"
+        OVERALL_PUBLIC_STATUS="TRUE - PAB Missing"
+    else
+        # Check if ALL four PAB flags are true
+        PAB_CONFIG=$(echo "$PAB_STATUS" | jq -r '.PublicAccessBlockConfiguration')
+        if [ "$(echo "$PAB_CONFIG" | jq -r '.BlockPublicAcls and .IgnorePublicAcls and .BlockPublicPolicy and .RestrictPublicBuckets')" = "true" ]; then
+            PAB_FULLY_RESTRICTED="TRUE"
+        else
+            PAB_FULLY_RESTRICTED="FALSE-VULNERABLE"
+        fi
+    fi
+
+    # --- CHECK B: Bucket Policy Status (If S3 service thinks it's public) ---
+    POLICY_STATUS=$(aws s3api get-bucket-policy-status --bucket "$BUCKET_NAME" --region "$BUCKET_REGION" 2>/dev/null)
+    
+    if [ $? -eq 0 ]; then
+        POLICY_IS_PUBLIC=$(echo "$POLICY_STATUS" | jq -r '.PolicyStatus.IsPublic')
+        if [ "$POLICY_IS_PUBLIC" = "true" ]; then
+            OVERALL_PUBLIC_STATUS="TRUE - Policy"
+        fi
+    else
+        # Expected error if no bucket policy exists, treat as NOT public via policy.
+        POLICY_IS_PUBLIC="No Policy"
+    fi
+
+    # --- CHECK C: Bucket ACLs (for AllUsers group) ---
+    ACL_RESPONSE=$(aws s3api get-bucket-acl --bucket "$BUCKET_NAME" --region "$BUCKET_REGION" 2>/dev/null)
+    
+    if [ $? -eq 0 ]; then
+        # Find if any grant to 'http://acs.amazonaws.com/groups/global/AllUsers' exists
+        
+        # Check for READ access
+        if echo "$ACL_RESPONSE" | jq -e '.Grants[] | select(.Grantee.URI=="http://acs.amazonaws.com/groups/global/AllUsers") | select(.Permission | test("READ|FULL_CONTROL"))' >/dev/null; then
+            ACL_ALL_USERS_READ="TRUE"
+            if [ "$OVERALL_PUBLIC_STATUS" = "FALSE" ]; then
+                 OVERALL_PUBLIC_STATUS="TRUE - ACL Read"
+            fi
+        fi
+
+        # Check for WRITE access (often less common for public, but still public exposure)
+        if echo "$ACL_RESPONSE" | jq -e '.Grants[] | select(.Grantee.URI=="http://acs.amazonaws.com/groups/global/AllUsers") | select(.Permission | test("WRITE|FULL_CONTROL"))' >/dev/null; then
+            ACL_ALL_USERS_WRITE="TRUE"
+            if [ "$OVERALL_PUBLIC_STATUS" = "FALSE" ]; then
+                 OVERALL_PUBLIC_STATUS="TRUE - ACL Write"
+            fi
+        fi
+    else
+        ACL_ALL_USERS_READ="ACL Check Failed"
+        ACL_ALL_USERS_WRITE="ACL Check Failed"
+    fi
+    
+    # Final check for PAB failure (PAB is the highest authority)
+    if [ "$PAB_FULLY_RESTRICTED" = "CRITICAL-MISSING" ]; then
+        OVERALL_PUBLIC_STATUS="TRUE - PAB Missing (CRITICAL)"
+    elif [ "$OVERALL_PUBLIC_STATUS" != "FALSE" ] && [ "$PAB_FULLY_RESTRICTED" != "TRUE" ]; then
+        # If the bucket is found public by Policy or ACL AND PAB isn't fully set, confirm it's public
+        : # Status already set by Policy or ACL check above
+    fi
+
+
+    # --- Save the output as CSV ---
+    echo "$BUCKET_NAME,$BUCKET_REGION,$PAB_FULLY_RESTRICTED,$POLICY_IS_PUBLIC,$ACL_ALL_USERS_READ,$ACL_ALL_USERS_WRITE,\"$OVERALL_PUBLIC_STATUS\"" >> "$REPORT_FILE"
+    echo "  Final Status: $OVERALL_PUBLIC_STATUS"
+
+done
+
+echo "---"
+echo "✅ Audit Complete."
+echo "Final report saved to **$REPORT_FILE**"
+cat "$REPORT_FILE"
\ No newline at end of file