php_pgsql_convert() is used to convert and escape user-provided parameters in pg_insert(), pg_update(), pg_select(), and pg_delete(). It does so using PQescapeStringConn() and then wraps the result in an escape string constant, E'...' (via php_pgsql_add_quotes()).
|
ZSTR_LEN(str) = PQescapeStringConn(pg_link, ZSTR_VAL(str), |
|
Z_STRVAL_P(val), Z_STRLEN_P(val), &escape_err); |
|
if (escape_err) { |
|
err = 1; |
|
} else { |
|
ZVAL_STR(&new_val, php_pgsql_add_quotes(str)); |
|
} |
With standard_conforming_strings = on (the default since PostgreSQL 9.1), PQescapeStringConn() does not correctly escape values for the escape string constant E'...', as it does not escape \ under this configuration. When PQescapeStringConn() escapes ' as '', an attacker can trivially terminate the string by escaping the first single quote.
$result = pg_select($db, 'user', ['name' => "zzz\\' OR 1=1 --"]);
// SELECT * FROM "user" WHERE "name"='zzz\'' OR 1=1 --';
var_dump($result); // returned all rows
Note that the doubled \\ is a PHP escape sequence and that the \ appears only once in the parameter. Also note that pg_select() escapes the ' by doubling it but does not escape the \. Consequently, the first of the two ' characters is escaped (meaning that it represents a literal '), while the second terminates the string. Everything after that is interpreted as part of the query.
The solution changes php_pgsql_convert() to wrap parameters in non-escaping string constants instead.
php_pgsql_convert()is used to convert and escape user-provided parameters inpg_insert(),pg_update(),pg_select(), andpg_delete(). It does so usingPQescapeStringConn()and then wraps the result in an escape string constant,E'...'(viaphp_pgsql_add_quotes()).php-src/ext/pgsql/pgsql.c
Lines 4751 to 4757 in cbc0489
With
standard_conforming_strings = on(the default since PostgreSQL 9.1),PQescapeStringConn()does not correctly escape values for the escape string constantE'...', as it does not escape\under this configuration. WhenPQescapeStringConn()escapes'as'', an attacker can trivially terminate the string by escaping the first single quote.Note that the doubled
\\is a PHP escape sequence and that the\appears only once in the parameter. Also note thatpg_select()escapes the'by doubling it but does not escape the\. Consequently, the first of the two'characters is escaped (meaning that it represents a literal'), while the second terminates the string. Everything after that is interpreted as part of the query.The solution changes
php_pgsql_convert()to wrap parameters in non-escaping string constants instead.