the_open_door
café
ESEN
← Volver al índice

PHP Type Juggling

ATT&CKT1190

El Type Juggling es un abuso de las comparaciones flexibles de PHP. El operador de igualdad laxa == intenta convertir los operandos a un tipo común antes de compararlos, en vez de exigir que sean idénticos como hace el estricto ===. Esa conversión implícita produce igualdades sorprendentes que rompen comprobaciones de seguridad: tokens, contraseñas o firmas que se validan con == pueden saltarse enviando un valor que PHP considere "igual" tras la conversión.

El caso más famoso son los magic hashes: si un hash empieza por 0e seguido solo de dígitos, PHP lo interpreta como notación científica (0 * 10^n = 0), así que dos hashes distintos con esa forma se comparan como iguales. Una contraseña cuyo md5 sea 0e... iguala a cualquier otra 0e...:

"0e123456" == "0e999999"   // true: ambas valen 0
md5("240610708") == md5("QNKCDZO")   // true: dos magic hashes 0e...

Entradas conocidas cuyo hash tiene forma 0e[0-9]+ (para pegar directamente en el campo):

md5:   240610708   QNKCDZO   aabg7XSs   aabC9RqS
sha1:  aaroZmOk   aaK1STfY   aaO8zKZF
# tambien vale un valor cuyo propio texto sea "0e...": muchas apps comparan token==hash

El otro clásico llega por arrays en la entrada. Si el código compara con == o pasa un array a funciones como strcmp, se fuerza un resultado favorable: strcmp(array, string) devuelve NULL en PHP antiguo, y NULL == 0 es true, con lo que la comprobación pasa. En una API JSON basta con enviar el tipo inesperado:

// si el backend hace  if (strcmp($_POST['pass'], $real) == 0)
pass[]=x            // strcmp(array, str) -> NULL -> NULL==0 -> bypass
// o en JSON, forzar un booleano/entero donde se espera string
{"password": true}

Requisitos. El backend debe (1) estar en PHP y (2) comparar datos sensibles con == (o funciones laxas) en vez de ===/hash_equals, y aceptar que la entrada llegue con un tipo controlable por el atacante (array, booleano, cadena 0e). Con comparación estricta y validación de tipo, el juggling no tiene por dónde entrar.

Cómo detectarlo. En el log de la aplicación, la firma son parámetros con tipo anómalo para el campo: sufijos [] que convierten un valor en array (pass[]=), o cadenas con forma 0e[0-9]+ en campos de contraseña o token. Un pico de intentos de login con esos patrones sobre el mismo endpoint delata el ataque.

Defensa. Comparar siempre con === (o con hash_equals() para secretos y firmas, que además es de tiempo constante), validar y forzar el tipo de cada entrada (is_string, casteo explícito) antes de compararla, y no confiar en la conversión implícita. Se solapa con el bypass de autenticación cuando el objetivo es saltarse un login.