El código ya está 'compilado' código de máquina. Solo haz algo como esto en main()
:
int *ret;
ret = (int *)&ret + 2;
*ret = (int) buf;
Solo asegúrate de deshabilitar la pila no ejecutable con el indicador -z execstack
al compilar.
EDITAR:
Desglosando el código -
int *ret;
Estamos declarando un puntero int denominado ret
como una variable local en main()
. Siendo la primera y única variable, se encuentra inmediatamente debajo del puntero de marco antiguo en la pila.
ret = (int *)&ret + 2;
A continuación, agregamos 2 a la dirección del puntero ret
y lo almacenamos nuevamente en ret
. Si observa la figura, la dirección de retorno se encuentra exactamente 2 palabras clave por encima de ret
. Básicamente, estamos almacenando la dirección de la dirección de retorno en ret
.
*ret = (int) buf;
Finalmente, estamos haciendo una desreferenciación de ret
para reemplazar la dirección de devolución existente con la dirección de buf
(nuestro código de shell, presumiblemente declarado en forma global).
Por lo tanto,
main()
regresará a buf
en lugar de a donde se suponía. Los bytes en buf
se interpretarán como código y se ejecutarán alegremente. Esto es lo que suele suceder en un exploit de desbordamiento de búfer de vainilla. El flujo de control se secuestra provocando un desbordamiento del búfer y sobrescribiendo la dirección de retorno con algo sobre lo que el pirata informático tiene control (generalmente código de shell inyectado).
Tenga en cuenta que los sistemas operativos modernos generalmente almacenan canarios de pila adicionales para detectar desbordamientos. Por lo tanto, el desplazamiento '2' podría no ser verdadero. Para simplificar, use el indicador -fno-stack-protector
mientras compila en gcc para deshabilitar los canarios.