Redirecionamento de Ponteiros

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks

Ponteiros de string

Se uma chamada de função for usar o endereço de uma string que está localizada na stack, é possível abusar do buffer overflow para sobrescrever esse endereço e colocar um endereço para uma string diferente dentro do binário.

Por exemplo, se uma chamada da função system for usar o endereço de uma string para executar um comando, um atacante poderia colocar o endereço de uma string diferente na stack, export PATH=.:$PATH e criar no diretório atual um script com o nome da primeira letra da nova string, pois ele será executado pelo binário.

Em alvos reais, reapontar um ponteiro de string na stack costuma ser mais interessante do que apenas mudar o texto impresso:

  • Redirecionar um argumento posterior de system/popen/execl* para um "/bin/sh" existente ou para uma string de comando controlada pelo atacante já presente na memória.
  • Redirecionar um sink de read posterior, como puts("%s", ptr) ou write(fd, ptr, len), para leak dados do stack, heap ou do binário.
  • Redirecionar um sink de write posterior como strcpy(dst, ...), memcpy(dst, src, len) ou uma atribuição de campo de estrutura via ptr->field = value para transformar o stack overflow em uma escrita arbitrária de segunda fase.

Ao auditar, priorize locais na stack como char *cmd, char *path, char *buf, FILE *fp, ou ponteiros dentro de structs temporárias de request/response que são usados após o overflow mas antes da função retornar. Isso é especialmente útil quando o overflow não pode alcançar com segurança o saved return address por causa de um canary ou porque corromper um ponteiro próximo já é suficiente.

Se a corrupção estiver limitada a uma sobrescrita parcial (por exemplo porque o bug adiciona um 0x00), tente redirecionar o ponteiro para:

  • Uma string próxima no mesmo stack frame
  • Outro objeto no mesmo módulo / imagem non-PIE
  • Uma região controlada cujos high bytes permanecem inalterados

Para o caso relacionado orientado a ASLR em que um NUL final modifica um ponteiro de stack existente em vez de uma variável local dedicada, veja Ret2ret & Reo2pop.

Você pode encontrar um exemplo disso em:

Ponteiros de função

Mesmo que um ponteiro de string, mas aplicando-se a funções: se a stack contém o endereço de uma função que será chamada, é possível alterá-lo (por exemplo para chamar system).

Alvos úteis não são apenas variáveis de callback explícitas como void (*fp)(). Na prática, procure por:

  • Callbacks armazenados em structs locais passados depois para funções auxiliares
  • Destructor / cleanup handlers invocados em caminhos de erro
  • Parser dispatch tables ou state-machine handlers copiadas para a stack
  • Structs / objetos locais que depois disparam via uma chamada indireta

Na exploração moderna, o redirecionamento de ponteiros frequentemente é a última primitiva disponível antes de atingir o canary. Um writeup de exploração de 2024 para CVE-2024-20017 mostra o padrão típico: o overflow alcança várias variáveis locais antes do stack canary, o atacante corrompe um stack pointer mais seu comprimento/valor associado, e uma atribuição posterior através desse ponteiro torna-se uma escrita arbitrária sem nunca precisar retornar através do frame corrompido.

Corrupção de ponteiros para primitivas de segunda etapa

Se um ponteiro próximo for depois desreferenciado para uma escrita, o objetivo geralmente não é pular diretamente com o primeiro overflow, mas elevar a primitiva:

  1. Transborde um buffer local e corrompa um ponteiro além de qualquer length / integer / index associado.
  2. Espere a função executar uma desreferência pós-overflow como ptr->len = x, memcpy(ptr, src, n) ou *ptr = value.
  3. Use o write-what-where resultante para sobrescrever um slot GOT, callback, ponteiro de configuração, ou outro callsite indireto.

Isto é uma boa opção quando:

  • O bug para no canary
  • O próprio ponteiro de função não é diretamente alcançável
  • Uma data write de 4 ou 8 bytes é mais fácil de obter do que um sequestro imediato do control-flow

A mesma ideia também funciona para primitivas de read se o ponteiro corrompido for depois passado para helpers de logging, impressão, ou envio pela rede.

Observação moderna AArch64: PAC / BTI

Em alvos AArch64 atuais, uma clássica sobrescrita do saved return address pode falhar porque o epílogo autentica x30 com PAC. Nesses casos, non-return hijacks como ponteiros de função locais corrompidos ou ponteiros de callback tornam-se mais atraentes.

Entretanto, se BTI estiver habilitado, o alvo de chamada indireta sobrescrito ainda deve aterrissar em um valid landing pad (tipicamente uma entrada de função com bti c, ou em código com PAC habilitado um prólogo começando com paciasp/pacibsp). Portanto, ao redirecionar um ponteiro de função na stack em AArch64, prefira:

  • Entradas reais de função em vez de gadgets no meio da função
  • Alvos cujo prólogo já satisfaz o BTI
  • Alvos onde o ponteiro de chamada indireta não é autenticado adicionalmente antes do uso

Para um contexto relacionado de stack-overflow em AArch64, veja ret2win-arm64.

Você pode encontrar um exemplo em:

Referências

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks