├── .github ├── FUNDING.yml └── workflows │ ├── smoke-test-cross-platform.yml │ └── smoke-test.yml ├── .gitignore ├── LICENSE ├── README.md └── tools └── smoke-test └── waf-smoke-test.sh /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: ridjex 14 | thanks_dev: # Replace with a single thanks.dev username 15 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 16 | -------------------------------------------------------------------------------- /.github/workflows/smoke-test-cross-platform.yml: -------------------------------------------------------------------------------- 1 | name: WAF Smoke Test (Cross-Platform) 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * 1' # Weekly on Mondays 6 | workflow_dispatch: # Manual trigger 7 | 8 | jobs: 9 | waf-smoke-test: 10 | runs-on: ${{ matrix.os }} 11 | strategy: 12 | matrix: 13 | os: [macos-latest, ubuntu-latest, windows-latest] 14 | 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v4 18 | 19 | # Setup for Windows 20 | - name: Install dependencies on Windows 21 | if: runner.os == 'Windows' 22 | shell: pwsh 23 | run: | 24 | # Install required tools using Chocolatey 25 | choco install curl grep sed -y 26 | 27 | # Install gawk 28 | choco install gawk -y 29 | 30 | # Add to PATH if needed 31 | echo "C:\Program Files\Git\usr\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append 32 | 33 | # Verify installations 34 | Write-Host "Checking installed dependencies:" 35 | curl --version 36 | grep --version 37 | sed --version 38 | gawk --version 39 | 40 | # Run on Ubuntu (bash) 41 | - name: Run WAF test on Ubuntu 42 | if: runner.os == 'Linux' 43 | shell: bash 44 | run: | 45 | chmod +x ./tools/smoke-test/waf-smoke-test.sh 46 | ./tools/smoke-test/waf-smoke-test.sh "${{ secrets.WAF_TEST_URL }}" 47 | 48 | # Run on macOS (bash) 49 | - name: Run WAF test on macOS 50 | if: runner.os == 'macOS' 51 | shell: bash 52 | run: | 53 | chmod +x ./tools/smoke-test/waf-smoke-test.sh 54 | ./tools/smoke-test/waf-smoke-test.sh "${{ secrets.WAF_TEST_URL }}" 55 | 56 | # Run on Windows (Git Bash) 57 | - name: Run WAF test on Windows 58 | if: runner.os == 'Windows' 59 | shell: bash 60 | run: | 61 | chmod +x ./tools/smoke-test/waf-smoke-test.sh 62 | bash ./tools/smoke-test/waf-smoke-test.sh "${{ secrets.WAF_TEST_URL }}" 63 | -------------------------------------------------------------------------------- /.github/workflows/smoke-test.yml: -------------------------------------------------------------------------------- 1 | name: WAF Smoke Test 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * 1' # Weekly on Mondays 6 | workflow_dispatch: # Manual trigger 7 | 8 | jobs: 9 | test-waf: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | with: 14 | repository: realad/waf-testing 15 | - name: Run WAF test 16 | working-directory: tools/smoke-test 17 | run: | 18 | chmod +x ./waf-smoke-test.sh 19 | ./waf-smoke-test.sh "${{ secrets.WAF_TEST_URL }}" -o report.md 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 RealAd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WAF Testing 2 | 3 | A lightweight toolkit for testing Web Application Firewall (WAF) effectiveness and identifying security gaps. This repository is available as a template that you can quickly customize for your own WAF testing needs. 4 | 5 | ## Overview 6 | 7 | WAF Testing provides a set of tools to verify that your Web Application Firewall is actually blocking common attacks, not just appearing to be configured correctly. The toolkit's flagship component is a fast WAF smoke test script that can evaluate your WAF's effectiveness in seconds. 8 | 9 | ## Key Features 10 | 11 | - **Quick Smoke Testing**: Test your WAF against 15+ attack vectors in under 60 seconds 12 | - **Cross-Platform**: Works on Linux, macOS, and Windows (via Git Bash) 13 | - **Cloud WAF Support**: Includes specific recommendations for AWS WAF and CloudFlare 14 | - **Comprehensive Coverage**: Tests SQL injection, XSS, path traversal, SSRF, and more 15 | - **Human-Readable Reports**: Generates clear Markdown reports with actionable recommendations 16 | - **CI/CD Integration**: Pre-configured GitHub Actions workflow for automated testing 17 | 18 | ## Using This Template 19 | 20 | This repository is configured as a GitHub template, making it easy to get started: 21 | 22 | 1. Click the "Use this template" button at the top of the repository 23 | 2. Name your new repository and click "Create repository from template" 24 | 3. Clone your new repository to your local machine 25 | 4. Set up your GitHub repository secret for `WAF_TEST_URL` (the URL you want to test) 26 | 5. Run the workflow manually through GitHub Actions or wait for the scheduled run 27 | 28 | ### Setting Up the Secret 29 | 30 | For the GitHub Actions workflow to run properly: 31 | 32 | 1. Go to your repository's Settings tab 33 | 2. Navigate to Secrets and variables > Actions 34 | 3. Click "New repository secret" 35 | 4. Name: `WAF_TEST_URL` 36 | 5. Value: The URL of the website/API you want to test (e.g., `https://your-website.com`) 37 | 38 | ## Getting Started Locally 39 | 40 | ### Prerequisites 41 | 42 | - Bash shell environment 43 | - curl 44 | - awk 45 | - grep 46 | - sed 47 | 48 | ### Basic Usage 49 | 50 | ```bash 51 | # Run a basic test against a URL 52 | ./tools/smoke-test/waf-smoke-test.sh "https://your-website.com" 53 | 54 | # Test with custom HTTP headers 55 | ./tools/smoke-test/waf-smoke-test.sh "https://your-website.com" -H "User-Agent: Custom Browser" 56 | 57 | # Generate a Markdown report 58 | ./tools/smoke-test/waf-smoke-test.sh "https://your-website.com" -o waf-report.md 59 | ``` 60 | 61 | ### Custom Test Placement 62 | 63 | By default, the script adds a `?q=FUZZ` parameter to your URL. If you want to test a specific parameter, use the `FUZZ` placeholder in your URL: 64 | 65 | ```bash 66 | ./tools/smoke-test/waf-smoke-test.sh "https://your-website.com/search?term=FUZZ" 67 | ``` 68 | 69 | ## Understanding Results 70 | 71 | The script produces a security score ranging from 0% to 100% based on how many attack vectors your WAF blocks. The rating scale is: 72 | 73 | - **Excellent**: 90-100% 74 | - **Good**: 70-89% 75 | - **Fair**: 50-69% 76 | - **Poor**: 0-49% 77 | 78 | Results also include specific AWS WAF and CloudFlare rule recommendations based on the detected vulnerabilities. 79 | 80 | ## Included CI/CD Integration 81 | 82 | This template includes a pre-configured GitHub Actions workflow (`.github/workflows/smoke-test.yml`) that: 83 | 84 | 1. Runs automatically every Monday at midnight 85 | 2. Can be triggered manually through the Actions tab 86 | 3. Tests your WAF on macOS, Ubuntu, and Windows 87 | 4. Uses the URL specified in your `WAF_TEST_URL` secret 88 | 89 | To customize the schedule, edit the cron expression in the workflow file. 90 | 91 | ## Platform Compatibility 92 | 93 | ### Linux 94 | Works out of the box on most distributions. 95 | 96 | ### macOS 97 | Works out of the box. 98 | 99 | ### Windows 100 | Requires Git Bash or Windows Subsystem for Linux (WSL). 101 | 102 | For Git Bash users, ensure you have awk, grep, and sed installed: 103 | ```bash 104 | # Install dependencies via pacman in Git Bash 105 | pacman -S awk grep sed 106 | ``` 107 | 108 | ## Security Considerations 109 | 110 | The test payloads are designed to test WAF functionality without causing harm. However, use caution when testing production systems and consider: 111 | 112 | 1. Testing in staging environments first 113 | 2. Running tests during low-traffic periods 114 | 3. Informing your security team before testing 115 | 116 | ## Contributing 117 | 118 | Contributions are welcome! Please feel free to submit a Pull Request. 119 | 120 | ## License 121 | 122 | This project is licensed under the MIT License - see the LICENSE file for details. 123 | 124 | ## Further Reading 125 | 126 | For more information on WAF testing best practices, read my article: [Testing Your Firewall in 60 Seconds: A Lightweight WAF Testing Script That Anyone Can Use](https://medium.com/@kochuraa/testing-your-firewall-in-60-seconds-a-lightweight-waf-testing-script-that-anyone-can-use-a7a725fefcb7) 127 | 128 | --- 129 | 130 | ⭐ If this project helped you, please consider giving it a star! 131 | -------------------------------------------------------------------------------- /tools/smoke-test/waf-smoke-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 🚀 Discover More: Testing Your Firewall in 60 Seconds: A Lightweight WAF Testing Script That Anyone Can Use 4 | # Learn how this script works and the best practices for WAF testing. 5 | # Read the full article here: 6 | # 👉 https://medium.com/@kochuraa/testing-your-firewall-in-60-seconds-a-lightweight-waf-testing-script-that-anyone-can-use-a7a725fefcb7 7 | 8 | # Safe WAF Tester Script 9 | # Usage: ./waf-smoke-test.sh [-o output.md] [-H "Header: Value"] 10 | # Examples: 11 | # Default testing: 12 | # ./waf-smoke-test.sh "https://example.com" 13 | # Custom placeholder: 14 | # ./waf-smoke-test.sh "https://example.com/search?search=FUZZ" 15 | # With custom headers and output file: 16 | # ./waf-smoke-test.sh "https://example.com" -o results.md -H "User-Agent: Custom" 17 | 18 | # Check dependencies 19 | for cmd in curl awk sed grep; do 20 | if ! command -v "$cmd" &>/dev/null; then 21 | echo "Error: $cmd is required but not installed." 22 | exit 1 23 | fi 24 | done 25 | 26 | # URL encode function (no Python dependency) 27 | urlencode() { 28 | local string="$1" 29 | local strlen=${#string} 30 | local encoded="" 31 | local pos c o 32 | 33 | for ((pos=0; pos [-o output.md] [-H \"Header: Value\"]" 65 | exit 1 66 | fi 67 | 68 | # Initialize variables 69 | URL="$1" 70 | OUTPUT_FILE="" 71 | HEADERS=() 72 | 73 | # Parse remaining arguments 74 | shift 75 | while [ $# -gt 0 ]; do 76 | case "$1" in 77 | -o) 78 | if [ $# -lt 2 ]; then 79 | echo "Error: -o requires an argument" 80 | exit 1 81 | fi 82 | OUTPUT_FILE="$2" 83 | shift 2 84 | ;; 85 | -H) 86 | if [ $# -lt 2 ]; then 87 | echo "Error: -H requires an argument" 88 | exit 1 89 | fi 90 | HEADERS+=("-H" "$2") 91 | shift 2 92 | ;; 93 | *) 94 | echo "Unknown option: $1" 95 | exit 1 96 | ;; 97 | esac 98 | done 99 | 100 | # Attack payloads across multiple categories - using escaped versions for commands 101 | PAYLOADS=( 102 | # SQL Injection 103 | "' OR '1'='1" 104 | "1; DROP TABLE waftest --" 105 | "admin' --" 106 | 107 | # XSS 108 | "" 109 | "" 110 | "" 111 | 112 | # Path Traversal 113 | "../../etc/passwd" 114 | "../../../../../../../etc/passwd" 115 | 116 | # Command Injection - ESCAPED to prevent shell execution 117 | "\$(cat /etc/passwd)" 118 | "| cat /etc/passwd" 119 | 120 | # SSRF 121 | "http://169.254.169.254/latest/meta-data/" 122 | "file:///etc/passwd" 123 | 124 | # NoSQL Injection 125 | "{'\\$gt':''}" 126 | "{\"\\$where\": \"this.password == this.passwordConfirm\"}" 127 | 128 | # Local File Inclusion 129 | "php://filter/convert.base64-encode/resource=index.php" 130 | ) 131 | 132 | # Categories for each payload (prevents shell execution issues) 133 | CATEGORIES=( 134 | "SQL Injection" 135 | "SQL Injection" 136 | "Other" 137 | 138 | "XSS" 139 | "XSS" 140 | "XSS" 141 | 142 | "Path Traversal" 143 | "Path Traversal" 144 | 145 | "Command Injection" 146 | "Command Injection" 147 | 148 | "SSRF" 149 | "SSRF" 150 | 151 | "NoSQL Injection" 152 | "NoSQL Injection" 153 | 154 | "LFI" 155 | ) 156 | 157 | # Colors 158 | GREEN='\033[0;32m' 159 | RED='\033[0;31m' 160 | YELLOW='\033[1;33m' 161 | BLUE='\033[0;34m' 162 | NC='\033[0m' 163 | 164 | # Insert FUZZ placeholder if missing 165 | if [[ ! "$URL" =~ FUZZ ]]; then 166 | if [[ "$URL" =~ \? ]]; then 167 | URL="${URL}&q=FUZZ" 168 | else 169 | URL="${URL}?q=FUZZ" 170 | fi 171 | fi 172 | 173 | printf "\n🔗 ${BLUE}Learn More:${NC} ${YELLOW}https://medium.com/@kochuraa/testing-your-firewall-in-60-seconds-a-lightweight-waf-testing-script-that-anyone-can-use-a7a725fefcb7${NC}\n" 174 | 175 | printf "\n🔍 ${BLUE}WAF Smoke Test${NC}: ${YELLOW}%s${NC}\n" "$URL" 176 | if [ ${#HEADERS[@]} -gt 0 ]; then 177 | printf "Headers: ${YELLOW}" 178 | for ((i=0; i<${#HEADERS[@]}; i+=2)); do 179 | printf "%s " "${HEADERS[i+1]}" 180 | done 181 | printf "${NC}\n" 182 | fi 183 | printf "\n%-3s %-40s %-12s %-10s %-20s\n" "#" "Payload" "Status" "HTTP Code" "Category" 184 | printf "%s\n" "$(printf '%0.s-' $(seq 1 90))" 185 | 186 | # Store results 187 | results=() 188 | i=1 189 | 190 | # Initialize vulnerability flags 191 | sql_vuln=0 192 | xss_vuln=0 193 | path_vuln=0 194 | cmd_vuln=0 195 | ssrf_vuln=0 196 | nosql_vuln=0 197 | lfi_vuln=0 198 | 199 | # Using numeric indexing to avoid shell execution issues 200 | for ((idx=0; idx<${#PAYLOADS[@]}; idx++)); do 201 | PAYLOAD="${PAYLOADS[$idx]}" 202 | CATEGORY="${CATEGORIES[$idx]}" 203 | 204 | # For display purposes - unescape $ for command injection payloads 205 | DISPLAY_PAYLOAD="${PAYLOAD//\\\$/\$}" 206 | DISPLAY_PAYLOAD="${DISPLAY_PAYLOAD//\\\"/\"}" 207 | 208 | # Encode and test the payload - use the original (escaped) payload for testing 209 | ENCODED_PAYLOAD=$(urlencode "$PAYLOAD") 210 | TARGET_URL=${URL//FUZZ/$ENCODED_PAYLOAD} 211 | 212 | # Use timeout for curl to avoid hanging 213 | RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "${HEADERS[@]}" --connect-timeout 5 --max-time 10 "$TARGET_URL") 214 | 215 | # Evaluate the response 216 | if [[ "$RESPONSE" = "403" || "$RESPONSE" = "406" ]]; then 217 | STATUS="${GREEN}Blocked${NC}" 218 | STATUS_TEXT="Blocked" 219 | elif [[ "$RESPONSE" =~ ^(2|3) ]]; then 220 | STATUS="${RED}Allowed${NC}" 221 | STATUS_TEXT="Allowed" 222 | # Mark category as vulnerable if allowed 223 | if [ "$CATEGORY" = "SQL Injection" ]; then sql_vuln=1; fi 224 | if [ "$CATEGORY" = "XSS" ]; then xss_vuln=1; fi 225 | if [ "$CATEGORY" = "Path Traversal" ]; then path_vuln=1; fi 226 | if [ "$CATEGORY" = "Command Injection" ]; then cmd_vuln=1; fi 227 | if [ "$CATEGORY" = "SSRF" ]; then ssrf_vuln=1; fi 228 | if [ "$CATEGORY" = "NoSQL Injection" ]; then nosql_vuln=1; fi 229 | if [ "$CATEGORY" = "LFI" ]; then lfi_vuln=1; fi 230 | elif [[ "$RESPONSE" =~ ^5 ]]; then 231 | STATUS="${YELLOW}Error${NC}" 232 | STATUS_TEXT="Error" 233 | else: 234 | STATUS="${YELLOW}Check${NC}" 235 | STATUS_TEXT="Check" 236 | fi 237 | 238 | # Display result with safe truncation - properly formatted 239 | if [ ${#DISPLAY_PAYLOAD} -gt 37 ]; then 240 | DISPLAY_PAYLOAD="${DISPLAY_PAYLOAD:0:37}..." 241 | fi 242 | 243 | printf "%-3s %-40s %-12b %-10s %-20s\n" "$((i))" "$DISPLAY_PAYLOAD" "$STATUS" "$RESPONSE" "$CATEGORY" 244 | 245 | # Store the full untruncated payload for the report 246 | results+=("$DISPLAY_PAYLOAD,$STATUS_TEXT,$RESPONSE,$CATEGORY") 247 | ((i++)) 248 | done 249 | 250 | # Calculate statistics 251 | BLOCKED=0 252 | ALLOWED=0 253 | ERROR=0 254 | CHECK=0 255 | 256 | for result in "${results[@]}"; do 257 | IFS=',' read -r _ STATUS _ _ <<< "$result" 258 | if [ "$STATUS" = "Blocked" ]; then ((BLOCKED++)); fi 259 | if [ "$STATUS" = "Allowed" ]; then ((ALLOWED++)); fi 260 | if [ "$STATUS" = "Error" ]; then ((ERROR++)); fi 261 | if [ "$STATUS" = "Check" ]; then ((CHECK++)); fi 262 | done 263 | 264 | TOTAL=${#PAYLOADS[@]} 265 | 266 | echo 267 | printf "%s\n" "$(printf '%0.s-' $(seq 1 90))" 268 | printf "\n📊 ${BLUE}Summary${NC}:\n" 269 | 270 | # Calculate percentages 271 | BLOCKED_PCT=$(calc_percentage $BLOCKED $TOTAL) 272 | ALLOWED_PCT=$(calc_percentage $ALLOWED $TOTAL) 273 | ERROR_PCT=$(calc_percentage $ERROR $TOTAL) 274 | CHECK_PCT=$(calc_percentage $CHECK $TOTAL) 275 | 276 | printf " ${GREEN}Blocked${NC}: %d/%d (%.1f%%)\n" "$BLOCKED" "$TOTAL" "$BLOCKED_PCT" 277 | printf " ${RED}Allowed${NC}: %d/%d (%.1f%%)\n" "$ALLOWED" "$TOTAL" "$ALLOWED_PCT" 278 | if [ $ERROR -gt 0 ]; then 279 | printf " ${YELLOW}Error${NC}: %d/%d (%.1f%%)\n" "$ERROR" "$TOTAL" "$ERROR_PCT" 280 | fi 281 | if [ $CHECK -gt 0 ]; then 282 | printf " ${YELLOW}Check${NC}: %d/%d (%.1f%%)\n" "$CHECK" "$TOTAL" "$CHECK_PCT" 283 | fi 284 | 285 | # Calculate security score 286 | SCORE=$(calc_percentage $BLOCKED $TOTAL 0) 287 | printf "\n🔒 ${BLUE}WAF Security Score${NC}: ${YELLOW}%d%%${NC}\n" "$SCORE" 288 | 289 | # Protection rating 290 | if [ "$SCORE" -ge 90 ]; then 291 | RATING="${GREEN}Excellent${NC}" 292 | elif [ "$SCORE" -ge 70 ]; then 293 | RATING="${GREEN}Good${NC}" 294 | elif [ "$SCORE" -ge 50 ]; then 295 | RATING="${YELLOW}Fair${NC}" 296 | else 297 | RATING="${RED}Poor${NC}" 298 | fi 299 | printf "🔒 ${BLUE}Protection Rating${NC}: %b\n" "$RATING" 300 | 301 | # WAF recommendations 302 | echo -e "\n🔧 ${BLUE}WAF Recommendations${NC}:" 303 | 304 | # Display recommendations for both AWS WAF and CloudFlare 305 | if [ $sql_vuln -eq 1 ]; then 306 | echo -e "- ${RED}SQL Injection${NC}:" 307 | echo -e " • ${GREEN}AWS WAF${NC}: Enable AWSManagedRulesSQLiRuleSet" 308 | echo -e " • ${GREEN}CloudFlare${NC}: Enable OWASP Core Rule Set and SQLi Ruleset" 309 | fi 310 | if [ $xss_vuln -eq 1 ]; then 311 | echo -e "- ${RED}XSS${NC}:" 312 | echo -e " • ${GREEN}AWS WAF${NC}: Enable AWSManagedRulesXSSRuleSet" 313 | echo -e " • ${GREEN}CloudFlare${NC}: Enable Cross-site Scripting Attack Score" 314 | fi 315 | if [ $path_vuln -eq 1 ]; then 316 | echo -e "- ${RED}Path Traversal${NC}:" 317 | echo -e " • ${GREEN}AWS WAF${NC}: Enable AWSManagedRulesKnownBadInputsRuleSet" 318 | echo -e " • ${GREEN}CloudFlare${NC}: Enable Directory Traversal Attack Protection" 319 | fi 320 | if [ $cmd_vuln -eq 1 ]; then 321 | echo -e "- ${RED}Command Injection${NC}:" 322 | echo -e " • ${GREEN}AWS WAF${NC}: Enable AWSManagedRulesLinuxRuleSet" 323 | echo -e " • ${GREEN}CloudFlare${NC}: Enable Server-Side Code Injection Attack Protection" 324 | fi 325 | if [ $ssrf_vuln -eq 1 ]; then 326 | echo -e "- ${RED}SSRF${NC}:" 327 | echo -e " • ${GREEN}AWS WAF${NC}: Configure custom WAF rules for SSRF protection" 328 | echo -e " • ${GREEN}CloudFlare${NC}: Create custom rule to block cloud metadata endpoints" 329 | fi 330 | if [ $nosql_vuln -eq 1 ] || [ $lfi_vuln -eq 1 ]; then 331 | echo -e "- ${RED}Advanced Threats${NC}:" 332 | echo -e " • ${GREEN}AWS WAF${NC}: Enable AWSManagedRulesCommonRuleSet" 333 | echo -e " • ${GREEN}CloudFlare${NC}: Enable High and Medium Risk Level Rules" 334 | fi 335 | 336 | # Generate markdown report if requested - using echo instead of printf for bullet points 337 | if [ -n "$OUTPUT_FILE" ]; then 338 | # Create the file and clear it 339 | > "$OUTPUT_FILE" 340 | 341 | # Add content using echo with >> to append 342 | echo "# WAF Security Test Report" >> "$OUTPUT_FILE" 343 | echo "Date: $(date)" >> "$OUTPUT_FILE" 344 | echo "" >> "$OUTPUT_FILE" 345 | 346 | echo "## Test Configuration" >> "$OUTPUT_FILE" 347 | echo "- URL: $URL" >> "$OUTPUT_FILE" 348 | if [ ${#HEADERS[@]} -gt 0 ]; then 349 | echo -n "- Headers: " >> "$OUTPUT_FILE" 350 | for ((i=0; i<${#HEADERS[@]}; i+=2)); do 351 | echo -n "${HEADERS[i+1]} " >> "$OUTPUT_FILE" 352 | done 353 | echo "" >> "$OUTPUT_FILE" 354 | else 355 | echo "- Headers: None" >> "$OUTPUT_FILE" 356 | fi 357 | echo "" >> "$OUTPUT_FILE" 358 | 359 | echo "## Summary" >> "$OUTPUT_FILE" 360 | echo "- Total Tests: $TOTAL" >> "$OUTPUT_FILE" 361 | echo "- Blocked: $BLOCKED (${BLOCKED_PCT}%)" >> "$OUTPUT_FILE" 362 | echo "- Allowed: $ALLOWED (${ALLOWED_PCT}%)" >> "$OUTPUT_FILE" 363 | if [ $ERROR -gt 0 ]; then 364 | echo "- Error: $ERROR (${ERROR_PCT}%)" >> "$OUTPUT_FILE" 365 | fi 366 | if [ $CHECK -gt 0 ]; then 367 | echo "- Check: $CHECK (${CHECK_PCT}%)" >> "$OUTPUT_FILE" 368 | fi 369 | echo "- Security Score: $SCORE%" >> "$OUTPUT_FILE" 370 | echo "" >> "$OUTPUT_FILE" 371 | 372 | echo "## Results by Category" >> "$OUTPUT_FILE" 373 | echo "" >> "$OUTPUT_FILE" 374 | 375 | # List of categories to check 376 | categories=("SQL Injection" "XSS" "Path Traversal" "Command Injection" "SSRF" "NoSQL Injection" "LFI" "Other") 377 | 378 | # Print results grouped by category 379 | for cat in "${categories[@]}"; do 380 | # Skip categories with no results 381 | cat_exists=0 382 | for result in "${results[@]}"; do 383 | if [[ "$result" == *",$cat" ]]; then 384 | cat_exists=1 385 | break 386 | fi 387 | done 388 | 389 | if [ $cat_exists -eq 1 ]; then 390 | echo "### $cat" >> "$OUTPUT_FILE" 391 | echo "" >> "$OUTPUT_FILE" 392 | echo "| # | Payload | Status | HTTP Code |" >> "$OUTPUT_FILE" 393 | echo "|---|---------|--------|-----------|" >> "$OUTPUT_FILE" 394 | 395 | cat_idx=1 396 | for result in "${results[@]}"; do 397 | IFS=',' read -r PAYLOAD STATUS CODE CATEGORY <<< "$result" 398 | if [ "$CATEGORY" = "$cat" ]; then 399 | # Escape pipe characters for markdown table 400 | PAYLOAD="${PAYLOAD//|/\\|}" 401 | 402 | echo "| $cat_idx | $PAYLOAD | $STATUS | $CODE |" >> "$OUTPUT_FILE" 403 | ((cat_idx++)) 404 | fi 405 | done 406 | echo "" >> "$OUTPUT_FILE" 407 | fi 408 | done 409 | 410 | echo "## WAF Recommendations" >> "$OUTPUT_FILE" 411 | echo "" >> "$OUTPUT_FILE" 412 | 413 | if [ $sql_vuln -eq 1 ]; then 414 | echo "### SQL Injection" >> "$OUTPUT_FILE" 415 | echo "* AWS WAF: Enable AWSManagedRulesSQLiRuleSet" >> "$OUTPUT_FILE" 416 | echo "* CloudFlare: Enable OWASP Core Rule Set and SQLi Ruleset" >> "$OUTPUT_FILE" 417 | echo "" >> "$OUTPUT_FILE" 418 | fi 419 | if [ $xss_vuln -eq 1 ]; then 420 | echo "### XSS" >> "$OUTPUT_FILE" 421 | echo "* AWS WAF: Enable AWSManagedRulesXSSRuleSet" >> "$OUTPUT_FILE" 422 | echo "* CloudFlare: Enable Cross-site Scripting Attack Score" >> "$OUTPUT_FILE" 423 | echo "" >> "$OUTPUT_FILE" 424 | fi 425 | if [ $path_vuln -eq 1 ]; then 426 | echo "### Path Traversal" >> "$OUTPUT_FILE" 427 | echo "* AWS WAF: Enable AWSManagedRulesKnownBadInputsRuleSet" >> "$OUTPUT_FILE" 428 | echo "* CloudFlare: Enable Directory Traversal Attack Protection" >> "$OUTPUT_FILE" 429 | echo "" >> "$OUTPUT_FILE" 430 | fi 431 | if [ $cmd_vuln -eq 1 ]; then 432 | echo "### Command Injection" >> "$OUTPUT_FILE" 433 | echo "* AWS WAF: Enable AWSManagedRulesLinuxRuleSet" >> "$OUTPUT_FILE" 434 | echo "* CloudFlare: Enable Server-Side Code Injection Attack Protection" >> "$OUTPUT_FILE" 435 | echo "" >> "$OUTPUT_FILE" 436 | fi 437 | if [ $ssrf_vuln -eq 1 ]; then 438 | echo "### SSRF" >> "$OUTPUT_FILE" 439 | echo "* AWS WAF: Configure custom WAF rules for SSRF protection" >> "$OUTPUT_FILE" 440 | echo "* CloudFlare: Create custom rule to block cloud metadata endpoints" >> "$OUTPUT_FILE" 441 | echo "" >> "$OUTPUT_FILE" 442 | fi 443 | if [ $nosql_vuln -eq 1 ] || [ $lfi_vuln -eq 1 ]; then 444 | echo "### Advanced Threats" >> "$OUTPUT_FILE" 445 | echo "* AWS WAF: Enable AWSManagedRulesCommonRuleSet" >> "$OUTPUT_FILE" 446 | echo "* CloudFlare: Enable High and Medium Risk Level Rules" >> "$OUTPUT_FILE" 447 | echo "" >> "$OUTPUT_FILE" 448 | fi 449 | 450 | echo -e "\n📄 Report saved to ${YELLOW}$OUTPUT_FILE${NC}" 451 | fi 452 | 453 | echo -e "\n📅 Test Date: $(date)" 454 | echo 455 | --------------------------------------------------------------------------------