El equipo de WordPress no se ha demorado y liberaron la versión 2.8.4 corriguiendo este problema que afecta al a rama 2.8.x, y posiblemente a las anteriores también.

El Ataque

Usualmente el proceso de reiniciar la contraseña requiere que se haga una confirmación al visitar una URL especial, que solo llegará a la cuenta de coreo del usuario en cuestión. Pero esta restricción se puede obviar al visitar una URL como:

http://misuperblog.com/wp-login.php?action=rp&key[]=

Lo que parece ser una petición inocente, tiene el detalle que la variable key está definida como un array (key[]=). El código de WordPress válida que dicha variable no esté vacía:

if ( empty( $key ) )

Uno pensaría que esta comprobación debería ser suficiente, ¿no?

Aprendiendo un poco del ataque

Sabemos que la comprobación de WordPress fallaba y según el parche oficial, decidieron agregar otra comprobación al if en cuestión:

if ( empty( $key ) || is_array( $key ) ) 

Entonces, ¿Cuál es el problema de usar solo empty( $key )? Resulta que en este caso $key no es un array vacío, sino que si contiene un elemento:

// si ejecutamos:
var_dump($_GET['key']);

// obtendríamos:
array (
  0 => '',
)

Lo cual viene a ser una particularidad inesperada de PHP, una que el equipo de WordPress no tuvo en cuenta, y que a cualquiera de nosotros también podría pasar por la misma situación. Nos queda de lección que hay que limitar lo más posible el rango de valores posibles en las variables que estamos recibiendo del usuario, por ejemplo a mí se me ocurren estas otras dos opciones para limitar $key:

  • Haciendo un CAST del valor:
$key = (string) $_GET['key'];
var_dump($key);

// Obtenemos:
'Array'
  • Usando preg_match():
$r = preg_match('/[a-z0-9]*/i', $_GET['key'], $matches);

Al pasar un array en preg_match, obtenemos: Warning: preg_match() expects parameter 2 to be string, array given in blablabla.php on line XX. Pero de todos modos $r es false y $matches NULL

¿Alguna otra forma que se les ocurra a ustedes?

Moralejas: Actualicen WordPress o apliquen el parche, y si son programadores revisen los valores que pueden tomar sus variables de decisión 😉