it-swarm-pt.tech

Por que um ataque ret2libc deve seguir a ordem "system (), exit (), command?

Em um ataque ret2libc, entendo que o endereço de retorno pode ser sobrescrito pelo endereço do comando do sistema, que recebe uma sequência de comandos como argumento. Nesse caso, o endereço da cadeia de comandos não deve vir diretamente após o endereço de system ()? No entanto, a maioria dos tutoriais que vi seguem o formato: endereço do sistema (). Endereço da saída (). Endereço da cadeia de comando.

Por que é obrigatório incluir o endereço de exit ()? O ataque ainda funcionará se exit () for excluído?

8
Lew Wei Hao

A técnica ret2libc (e programação orientada a retorno (ROP)) depende da substituição da pilha para criar um novo quadro de pilha que chama a função do sistema. Este artigo da wikipedia explica detalhadamente os quadros de pilha: https://en.wikipedia.org/wiki/Call_stack#Stack_and_frame_pointers

O quadro da pilha determina a ordem em que a chamada de função e os parâmetros são gravados:

function address return address parameters

Portanto, no seu exemplo, você deseja chamar system() com cmdstring e retornar à função exit() quando a chamada system() retornar. Então você escreve o seguinte quadro de pilha:

system_addr exit_addr cmdstring_addr

Se você remover o endereço de saída, altere o quadro da pilha para o seguinte:

system_addr cmdstring_addr existingdataonstack_aka_junk

Então agora você está chamando system() com um argumento de endereço indesejado e tentando retornar à sua cadeia de comandos assim que a função for concluída. É por isso que falha. Você pode substituir o endereço exit() por outros dados, como 0x41414141, O que causará uma segfault assim que a chamada system() for concluída. Ou você pode substituí-lo pelo endereço de um local pop pop ret E depois escrever mais quadros de pilha embaixo. Agora é uma carga útil de ROP. Aqui está um exemplo básico de como isso ficaria na pilha:

system_addr poppopret_addr cmdstring_addr printf_addr exit_addr addr_of_string_to_printf

Isso permitiria imprimir algo como You got hacked Antes de sair.

7
wireghoul

O motivo exit() está incluído é para encerrar o programa normalmente. Se você não tiver exit() no final da sua cadeia, o programa continuará sendo executado de maneira estranha ou provavelmente terminará com uma falha de segmentação. Não é obrigatório incluir uma chamada para exit(). Idealmente, você constrói sua exploração de tal maneira que, posteriormente, o programa continue sendo executado normalmente, para que ninguém fique desconfiado porque o serviço não está mais sendo executado.

2
mroman