Ci sono diversi problemi nel codice:
Il primo è che il target username
è più corto del source msg
e che quindi un lungo msg
può causare un overflow di username
. Ma dato il codice questo si traduce solo nel fluire in msg
, cioè nessun arresto.
Più interessante è la seguente parte:
int i;
...
i = read(STDIN_FILENO, msg, sizeof(msg)-1);
memcpy( username, msg+2, i-2);
Se int i
è 0 o 1, ciò causerà i-2
come ultimo argomento di memcpy da essere negativo (ad esempio -2 o -1). Poiché il tipo dell'ultimo argomento è size_t
, che di solito non è firmato, questo valore con segno negativo verrà trattato come un valore senza segno enorme. In effetti, il codice diventa su piattaforme con 64 bit size_t
quando i
è 1:
memcpy(username, msg+2, 0xffffffffffffffff)
In questo modo la copia raggiungerà rapidamente le aree di memoria che non appartengono al processo in modo che si verifichi un errore di segmentazione.
I valori necessari per i
possono essere raggiunti semplicemente chiudendo l'input ( i=0
) o fornendo esattamente un byte di input ( i=1
, cioè senza nuove righe aggiuntive o simili) con, ad esempio,
echo -n "u" | ./crashme