Pergunta

Recebi uma tarefa de casa me pedindo para invocar uma função sem chamá -la explicitamente, usando o buffer estouro. O código é basicamente isso:

#include <stdio.h>
#include <stdlib.h>

void g()
{
    printf("now inside g()!\n");
}


void f()
{   
    printf("now inside f()!\n");
    // can only modify this section
    // cant call g(), maybe use g (pointer to function)
}

int main (int argc, char *argv[])
{
    f();
    return 0;
}

Embora eu não tenha certeza de como proceder. Pensei em alterar o endereço de retorno do contador do programa para que ele prossiga diretamente para o endereço de G (), mas não tenho certeza de como acessá -lo. De qualquer forma, as dicas serão ótimas.

Foi útil?

Solução

A idéia básica é alterar o endereço de retorno da função, para que, quando a função retornar, continue sendo executada em um novo endereço hackeado. Como é feito por Nils em uma das respostas, você pode declarar uma peça de memória (geralmente matriz) e transbordar de tal maneira que o endereço de retorno também seja substituído.

Eu sugiro que você não tome cegamente nenhum dos programas apresentados aqui sem realmente entender como eles funcionam. Este artigo está muito bem escrito e você achará muito útil:

Um passo a passo na vulnerableidade do buffer de transbordamento

Outras dicas

Isso depende do compilador, para que nenhuma resposta única possa ser dada.

O código a seguir fará o que você deseja para o GCC 4.4.1. Compilar com otimizações desativadas (importante!)

#include <stdio.h>
#include <stdlib.h>

void g()
{
    printf("now inside g()!\n");
}


void f()
{   
  int i;
  void * buffer[1];
  printf("now inside f()!\n");

  // can only modify this section
  // cant call g(), maybe use g (pointer to function)

  // place the address of g all over the stack:
  for (i=0; i<10; i++)
     buffer[i] = (void*) g;

  // and goodbye..
}

int main (int argc, char *argv[])
{
    f();
    return 0;
}

Resultado:

nils@doofnase:~$ gcc overflow.c
nils@doofnase:~$ ./a.out
now inside f()!
now inside g()!
now inside g()!
now inside g()!
now inside g()!
now inside g()!
now inside g()!
Segmentation fault

Como é a lição de casa, eu gostaria de ecoar Sugestão do Codeaddict de entender como um excesso de buffer realmente funciona.

Aprendi a técnica lendo o excelente artigo/tutorial de excelente (se um pouco datado) sobre explorar vulnerabilidades de transbordamento de buffer Esmagando a pilha por diversão e lucro.

Tente este:

void f()
{   
    void *x[1];
    printf("now inside f()!\n");
    // can only modify this section
    // cant call g(), maybe use g (pointer to function)
    x[-1]=&g;
}

ou este:

void f()
{   
    void *x[1];
    printf("now inside f()!\n");
    // can only modify this section
    // cant call g(), maybe use g (pointer to function)
    x[1]=&g;
}

Embora essa solução não use uma técnica de transbordamento para substituir o endereço de retorno da função na pilha, ela ainda causa g() para ser chamado de f() no caminho de volta para main() apenas modificando f() e não ligar g() diretamente.

Epílogo da função-como a montagem em linha é adicionada a f() para modificar o valor do endereço de retorno na pilha para que f() Voltará g().

#include <stdio.h>

void g()
{
    printf("now inside g()!\n");
}

void f()
{   
    printf("now inside f()!\n");
    // can only modify this section
    // cant call g(), maybe use g (pointer to function)

    /* x86 function epilogue-like inline assembly */
    /* Causes f() to return to g() on its way back to main() */
    asm(
        "mov %%ebp,%%esp;"
        "pop %%ebp;"
        "push %0;"
        "ret"
        : /* no output registers */
        : "r" (&g)
        : "%ebp", "%esp"
       );
}

int main (int argc, char *argv[])
{
    f();
    return 0;
}

Entender como esse código funciona pode levar a uma melhor compreensão de como o quadro de pilha de uma função é configurado para uma arquitetura específica que forma a base das técnicas de transbordamento de buffer.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top