Exemplo de injeção de código

Esse exemplo está no meu livro… Recentemente li uma dúvida sobre problemas de segmentation fault numa tentativa de injetar código da seguinte maneira:

/* buffer contendo o código a ser injetado. */
char buffer[1] = { '\xc3' };

/* Ponteiro para função, inicializado para o início do 
   buffer acima. */
void (*fptr)(void) = (void (*)(void))buffer;

/* Chamada de função - causa "segmentation fault"! */
fptr();

Mesmo que você aloque o ‘buffer’ com malloc() e escreva um ‘\xc3’ na posição inicial, irá obter o mesmo resultado: segmentation fault.

O que acontece aqui é que as páginas alocadas para a sessão de dados de seu código possuem o atributo PROT_EXEC desabilitado (ou, o bit XD setado!). Isso impede que o processador execute código contido nessas páginas, causando a exceção.

Para injetar código você terá que alocar páginas com o atributo PROT_EXEC, copiar o código para essa página e saltar para o ponto de entrada… Isso pode ser feito, no Linux, assim:

/* exploit.c */
#include <stdio.h>
#include <memory.h>
#include <sys/mman.h>

/* Tamanho de uma página. */
#define PAGE_SIZE 4096

/* Código que vai ser injetado. */
const unsigned char code[] = {
  0x48, 0x89, 0xf8, /* mov rax,rdi; */
  0x48, 0x01, 0xf8, /* add rax,rdi; */
  0xc3              /* ret; */
};

int main(int argc, char *argv)
{
  /* Ponteiro para função de protótipo 'long f(long)'. */
  long (*fp)(long);
  int x = 3, value;

  /* Aloca uma única página. 
     Poderíamos alocar o tamanho suficiente para caber 
     o código, mas mmap vai alocar uma página 
     de qualquer jeito! */
  fp = mmap(NULL, PAGE_SIZE, 
         PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 
         -1, 0);
  if (fp != NULL)
  {
    /* Copia o código para a página */
    memcpy(fp, code, sizeof(code));

    /* Desabilita a escrita na página e 
       habilita a execução. */
    mprotect(fp, PAGE_SIZE, PROT_READ | PROT_EXEC);

    /* Executa o código injetado via ponteiro. */
    value = fp(x);

    /* Dealoca a página! */
    munmap(fp, PAGE_SIZE);

    printf("O dobro de %d é %d.\n", x, value);
  }
  else
   puts("Não consegui alocar uma página!");

  return 0; 
}

No caso do Windows, você pode usar as funções VirtualAlloc e VirtualFree (bem como VirtualProtect, se quiser alterar os atributos da página, como fiz).

Anúncios

Deixe um comentário

Faça o login usando um destes métodos para comentar:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s