it-swarm-pt.tech

O estouro do buffer de 64 bits falha com SIGILL, não consigo entender o motivo

Eu tenho feito buffer overflows de 32 bits há algum tempo e decidi tentar alguns overflows de 64 bits, para explorar alguns cenários mais realistas. Compilei meu código com gcc -fno-stack-protector -z execstack -no-pie overflow.c -o Overflow .

Aqui está o código:

#include <stdio.h>
#include <string.h>
void function(char *str)
{
    char buffer[32];
    strcpy(buffer,str);
    puts(buffer);
}

int main(int argc, char **argv)
{
    function(argv[1]);
}

Usando gdb, determinei quantos bytes preciso escrever para controlar o endereço de retorno. Isso tem 40 bytes. Então, primeiro tentei escrever 40 bytes de "A" e depois 6 bytes de "B" para testar o controle do endereço de retorno.

Aqui está uma captura de tela: enter image description here

Eu encontrei e testei um shellcode de 23 bytes que executa "/ bin/sh", então tento escrever um nop-sled de 13 bytes, o shellcode e os primeiros 6 bytes do endereço de retorno que precisam ser alterados. Então eu vim com isto (em gdb):

r $(python -c'print "\x90"*13+"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"+"\x10\xe1\xff\xff\xff\x7f"')

Eu configurei 2 pontos de interrupção antes e depois da execução de strcpy e examinei a memória.

Esta é a pilha antes do strcpy: enter image description here

onde no endereço 0x00007fffffffe138 é o endereço de retorno da função function enter image description here

E esta é a pilha logo após a execução strcpy: enter image description here

Portanto, no meu entendimento, depois de pressionar c para continuar a execução, devo "retornar" ao nopsled e executar o shellcode no gdb.

Em vez disso, recebo um SIGILL, para instrução ilegal.

enter image description here

Não consigo descobrir por que isso está acontecendo, qualquer ajuda/sugestão/indicação seria muito apreciada.

1
George Sp

Em primeiro lugar (apenas porque você mencionou "realista"), este não é exatamente um cenário realista para um sistema de 64 bits. O principal motivo é que o espaço de endereço é muito maior, o que torna muito mais difícil prever e pousar no seu trenó NOP. Para obter uma explicação mais detalhada, consulte esta resposta . Além disso, o no-execute-stack (NX) está quase universalmente habilitado atualmente.

Em vez disso, você normalmente desejará usar a programação orientada a retorno (ROP).

Dito isso, vamos abordar seu cenário atual. Passei muito tempo tentando descobrir o que estava errado, mas parece que você está fazendo tudo corretamente (presumindo que você tenha o endereço correto para onde retornar).

Parece que na verdade é um shellcode de 27 bytes, mas você tinha a quantidade correta de preenchimento igual a 40 bytes para o endereço de retorno, então tudo bem.

Acontece que a maneira de fazer isso funcionar é experimentando de fora do GDB. Você pode notar, se passar mais devagar, que o SIGILL está realmente ocorrendo após a instrução syscall, mas GDB é de alguma forma fingindo que parece acontecer antes. Rolei para cima enquanto percorria, e parece que Push rbx instrução estava jogando fora do GDB; estava tentando anular a referência 0x68732f6e69622f (que é apenas/bin/sh em representação hexadecimal) e reclamando disso, o que pode ter feito outras coisas darem errado (o GDB também estava inserindo segfaults e instruções fantasmas para mim). Talvez outra pessoa tenha uma explicação melhor para o motivo disso.

Portanto, tente executá-lo fora do GDB. Você quase certamente precisará desligar o ASLR e precisará encontrar uma maneira de obter o endereço do buffer. Você pode adicionar uma declaração de impressão à fonte original para imprimir o endereço com %p.

2
multithr3at3d