Inyección de SQL en WordPress

Luego de que alguien hiciera eco sobre un falso problema de inyección de SQL en WordPress 2.3.1, esta vez han publicado detalles de un bug que permite realizar este tipo de ataques en las ramas 2.2 y 2.3 (podría afectar a versiones anteriores también). Antes de pegar un grito al cielo y maldecir a los programadores de WordPress, vale aclarar que este bug sólo se puede reproducir siempre y cuando la codificación de la base de datos sea SJIS, BIG5 o GBK.

El problema radica en que en los juegos de caracteres de ancho variable mencionados, es posible que a partir de secuencias de caracteres no válidas y luego de aplicar la función addslashes, se pueda realizar ataques de inyección de SQL. Por ejemplo en la prueba de concepto del mencionado bug envían la secuencia 0xb327 (caracter multi-byte no válido en Big5) que luego de aplicarle la función addslashes la cadena resultante será 0xb35c27 (notar que el caracter \ = 0x5c se agregó antes de la comilla simple ' = 0x27), sin embargo en esta codificación la secuencia 0xb35c (許) es un caracter multi-byte válido por lo que en realidad la cadena resultante tendría la comilla simple sin escapar (許').

Dado que WordPress cambia la codificación de la conexión con SET NAMES 'GBK' (que es lo que hace cuando se especifica un valor para DB_CHARSET en el archivo de configuración), este problema de seguridad tendrá los mismos efectos aún usando la función mysql_real_escape_string.

Actualización: He subido un ejemplo que ilustra el problema descrito. El código de ese ejemplo es el siguiente por si quieren hacer pruebas:

php:
<?php
header('Content-Type: text/plain; charset=Big5');

$login = chr(0xB3).chr(0x27) . ' UNION ALL SELECT * FROM foo /*';
if ( isset($_GET['login']) )
        $login = stripslashes($_GET['login']);

$sql = "SELECT * FROM wp_posts WHERE login = '%s'\n";

echo sprintf($sql, addslashes($login));

mysql_connect('localhost', 'tests', '1234');
mysql_query('SET NAMES Big5');

echo sprintf($sql, mysql_real_escape_string($login));

mysql_close();
?>

Lectura recomendada