Hay varios problemas en el código:
La primera es que el objetivo username
es más corto que el origen msg
y que, por lo tanto, un largo msg
puede causar un desbordamiento de username
. Pero dado el código, esto solo da como resultado que fluya a msg
, es decir, que no se bloquee.
Más interesante es la siguiente parte:
int i;
...
i = read(STDIN_FILENO, msg, sizeof(msg)-1);
memcpy( username, msg+2, i-2);
Si int i
es 0 o 1, esto causará que i-2
como último argumento de memcpy sea negativo (es decir, -2 o -1). Dado que el tipo del último argumento es size_t
, que generalmente no está firmado, este valor con signo negativo se tratará como un valor sin firmar enorme. Por lo tanto, en efecto, el código llega a las plataformas con 64 bit size_t
cuando i
es 1:
memcpy(username, msg+2, 0xffffffffffffffff)
De esta manera, la copia alcanzará rápidamente las áreas de memoria que no pertenecen al proceso para que se produzca un fallo de segmentación.
Los valores necesarios para i
pueden alcanzarse simplemente cerrando la entrada ( i=0
) o proporcionando exactamente un byte de entrada ( i=1
, es decir, no hay nuevas líneas adicionales o similares) con, por ejemplo,
echo -n "u" | ./crashme