TALES FROM THE WAF | Attacking Web Application Firewalls From a Real World Perspective
In this article we are going to shed some light on what WAFs are, how they work and how hackers actually bypass them.
Tales From the WAF
Real Payloads, Real Blocks, and Why They Failed or Succeeded
The moment a Web Application Firewall steps between you and a vulnerable app, the game changes completely. You're no longer just writing '; DROP TABLE users; -- and calling it a day.
Instead, you enter a dialogue with an invisible adversary that reads payloads the way a paranoid security guard reads visitor logs. One wrong character → BLOCKED. One weird encoding trick → SLIPPED THROUGH.
These aren't fairy tales. They're real moments from penetration tests where a single payload variation meant the difference between mission success and back to square one.
This Post Covers:
✓ The payloads that WORKED
✗ The ones that FAILED
And the logic behind WHY
Understanding What We're Actually Fighting
Before we dive into the war stories, let's be clear about what a WAF actually does. It's not some all-seeing oracle. It's a set of rules—sometimes intelligent, often brittle—that try to match your request against known attack patterns.
The Truth Most Won't Admit:
WAFs are TERRIBLE at understanding context
They see strings. They see patterns. But they don't understand whether you're making a legitimate database query or extracting password hashes three levels deep in JSON.
That gap between what the WAF understands and what the application understands?
→ That's where every bypass lives.
The XSS That Looked Dead But Wasn't
The Setup
Standard reflected XSS in a search parameter. The target was running an older e-commerce platform behind a mid-market WAF.
The First Probe
REQUEST:
403 FORBIDDEN
"Request blocked by security policy"
Expected. The WAF's signature library knows [<]script[>] and alert are trouble.
The Deconstruction
Filing down the payload piece by piece:
Pattern forming: The WAF hunted specific keywords like alert, eval, onerror, onload.
The Breakthrough
✓ 200 OK - BYPASSED
The Lesson
The WAF was keyword-based. It looked for known functions but missed:
• Character encoding via fromCharCode()
• Multi-step payload construction
• Context-based injection variations
💡 Start loud, observe the block, then systematically strip down to learn which elements trigger the WAF.
The SQL Injection That Hid in JSON
The Setup
Financial services platform. Modern API, RESTful, JSON everywhere. Backend: Microsoft SQL Server. WAF: Enterprise-grade.
Vulnerable endpoint: POST request where account_id was concatenated into SQL.
Classic Bypass (Failed)
"account_id": "12345' UNION SELECT username, password FROM users--"
403 FORBIDDEN
The Breakthrough: JSON-Based SQL
💡 Key Research:
Team82 (2023): Major WAF vendors didn't support JSON syntax in SQL payloads, despite databases supporting JSON functions for years.
The attack: Wrap SQL in database JSON functions.
"account_id": "12345' OR (SELECT COUNT(*) FROM (SELECT 1)
WHERE JSON_QUERY('{"a":1}','$') IS NOT NULL) > 0--"
✓ 200 OK - BYPASSED
Timing-based blind SQLi confirmed
The WAF looked for UNION, SELECT, OR 1=1. But when SQL logic was nested inside JSON functions, it didn't recognize the shape anymore.
The Lesson
Speaking a dialect the WAF didn't understand but the database did = invisible.
💡 Understand what the backend database supports. PostgreSQL? Try pg_sleep(). MySQL? Bit manipulation. Modern SQL Server? Test JSON wrappers.
The Space That Wasn't There
Quick Setup
ModSecurity WAF with OWASP Core Rule Set. Product search filter with URL-encoded parameters.
The Bypass
/products?filter='+AND+1=1--
Using + (URL-encoded space) instead of literal spaces!
💡 Why it worked: WAF's regex expected literal spaces. URL decoder (running AFTER WAF) converted + to spaces for SQL. Encoding inconsistency = bypass.
⏱️ The Timing Attack That Took Too Long
The Problem
SQL Server. Sophisticated WAF blocking time-based SQLi. Login form vulnerable.
admin' WAITFOR DELAY '0:0:5'-- throws 403
The Pivot
WAITFOR isn't the only timing primitive!
admin' AND (SELECT COUNT(*) FROM master[..]spt_values s1,
master[..]spt_values s2) > 0--
Self-join on system table = CPU-bound delay without WAITFOR!
💡 WAF looks for known time-delay functions. Query complexity? Looks legitimate to the rule engine.
The Comment That Wasn't a Comment
The Setup
File upload vulnerability. App parsed image EXIF data and reflected it into web page. XSS vector.
The Unicode Bypass
App accepted UTF-8 with special Unicode characters!
[<]svg onload="alert(1)"[>][<]/svg[>]
Using Unicode NO-BREAK SPACE (U+00A0) between "on" and "load"
-- Note: This payload has been defanged for security reasons.
WAF regex expected regular space: /on\s?load/
Unicode no-break space didn't match \s → but browsers handle Unicode spaces fine → XSS executed!
The Meta-Skill
Systematic WAF Reconnaissance
Step 1: Intentional Loud Triggers
Start with obvious payloads. Goal: Get blocked and learn.
Step 2: Baseline Testing
Test legitimate requests to establish baseline behavior.
Step 3: Systematic Deconstruction
Remove one element at a time to find triggers.
Step 4: Encoding Rotation
Try different encodings to slip through detection.
Step 5: Database Research
Learn database-specific functions WAF might not know.
Step 6: Build, Test, Iterate
Form hypothesis, design payload, test, iterate.
The Hardest Truth
A WAF is a speed bump,
not a wall.
It raises effort for drive-by attacks. Stops automated scanning. Catches sloppy payloads.
But a methodical attacker who understands database functions, encoding quirks, regex limitations, and protocol handling differences will find a way around it.
The WAF's real value? Slowing exploitation to alert your SOC. Logging attempts so you know you're under fire. Enforcing skill over basic awareness.
Lessons to Live By
1. Start Loud, Then Whisper
Obvious payloads teach rules. Subtle variations show where rules break.
2. Understand the Stack
WAFs are one layer. Framework, database, runtime all interpret differently. Exploit those gaps.
3. Database Primitives Are Your Friends
Every database has functions WAF might not account for.
4. Encoding Is Your Palette
URL encoding, Unicode, HTML entities, hex—each decoded at different stages.
5. Test Every Location
Query params, POST body, headers, cookies—WAF checks each differently.
6. When One Method Fails, Pivot
UNION blocked? Try blind extraction. alert() blocked? Try console.log().
7. Document Your Story
Understanding WHY it works transfers to the next target.
The Road Ahead
WAF evasion grows more sophisticated. Modern WAFs use ML and anomaly detection, not just signatures. But human creativity still beats algorithmic detection.
The field moves toward intent-based detection—understanding what requests try to do. Harder to bypass, but not impossible.
The fundamentals never change:
Understand your opponent. Test systematically. Never assume the WAF understands what you understand.
Because often, it doesn't.
And that's your opening.
Author: Flatline
Stay Frosty