[RL] PostgreSQL String Filter Evasion & UDFPosted by Kos on 02/02/2012 at 12:18 am | Last modified: 05/09/2012 8:38 am
Recently I came across an application that:
- Converted " to "
- Doubled ' (single quote became '' – note two single ticks, not a double tick)
I had straight up SQL injection (on an INSERT statement, but fortunately stacked queries are supported in PostgreSQL + ASP.NET/JSP), but I was having a hard time getting things to work nicely.
After a little bit of searching for filter evasion and PostgreSQL, I discovered this paper: Advanced PostgreSQL SQL Injection and Filter Bypass Techniques by
Leon Juranić of DefenseCode.
I suggest reading the whole paper, it’s great, but what I took away from it was exactly what I needed at the time. It turns out that in PostgreSQL, to denominate a string, you can use single tick (‘), quotes (“), or, get this, double dollar signs ($$).
The reason for this is to make SQL more readable when including single ticks and qoutes.
Imagine a query like:
SELECT * FROM shops WHERE shopName ID = 'Rick\'s Ice Cream';
Notice the escape character? (Disregard the fact that I could have just used double quotes instead.) PostgreSQL decided to solve this solution by adding another delimiter, the double dollar signs ($$). So suddenly, the above statement becomes:
SELECT * FROM shops WHERE shopName ID = $$Rick's Ice Cream$$;
Here’s the documentation on it. What does this mean? Easier filter evasion for us!
But that’s not all I faced during my testing. It turns out, that as of PostgreSQL 8.2 or 8.3, PostgreSQL will not longer allow you to load a C library unless the PostgreSQL “Magic Token” has been defined, PG_MODULE_MAGIC;. This means that I can’t simply load /lib/libc.so anymore, which means I can’t map a new user defined function to system()! Bummer!
Fortunately, I was able to discover file upload functionality in this application that let me upload binary files, I simply snipped out SQLMap‘s lib_postgresqludf_sys.c, compiled it against the version of PostgreSQL I was attacking, and boom, I had a valid C library that I could load into PostgreSQL with and execute system() functions.
In the end, the SQL statement looked like this, with my attack vector in bold.
SELECT * FROM users WHERE ID = 1;CREATE OR REPLACE FUNCTION system(cstring) RETURNS int AS $$/www/some/upload/path/uploadedfile.so$$, $$system$$ LANGUAGE $$C$$ STRICT;select system($$ nc -e /bin/sh -l 1025 $$);– and password = ‘password’;