mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/binary-exploitation/basic-stack-binary-exploitation-met
This commit is contained in:
parent
36b06191a6
commit
c490aead16
@ -37,7 +37,7 @@ Segment Sections...
|
||||
07
|
||||
08 .init_array .fini_array .dynamic .got
|
||||
```
|
||||
O programa anterior tem **9 cabeçalhos de programa**, então, o **mapeamento de segmentos** indica em qual cabeçalho de programa (de 00 a 08) **cada seção está localizada**.
|
||||
O programa anterior possui **9 cabeçalhos de programa**, então, o **mapeamento de segmentos** indica em qual cabeçalho de programa (de 00 a 08) **cada seção está localizada**.
|
||||
|
||||
### PHDR - Cabeçalho do Programa
|
||||
|
||||
@ -47,6 +47,8 @@ Contém as tabelas de cabeçalho do programa e os metadados em si.
|
||||
|
||||
Indica o caminho do carregador a ser usado para carregar o binário na memória.
|
||||
|
||||
> Dica: Binários vinculados estaticamente ou static-PIE não terão uma entrada `INTERP`. Nesses casos, não há carregador dinâmico envolvido, o que desabilita técnicas que dependem dele (por exemplo, `ret2dlresolve`).
|
||||
|
||||
### LOAD
|
||||
|
||||
Esses cabeçalhos são usados para indicar **como carregar um binário na memória.**\
|
||||
@ -56,12 +58,18 @@ Por exemplo, o segundo tem um tamanho de 0x1190, deve estar localizado em 0x1fc4
|
||||
|
||||
### DYNAMIC
|
||||
|
||||
Esse cabeçalho ajuda a vincular programas às suas dependências de biblioteca e aplicar realocações. Verifique a seção **`.dynamic`**.
|
||||
Este cabeçalho ajuda a vincular programas às suas dependências de biblioteca e aplicar realocações. Verifique a seção **`.dynamic`**.
|
||||
|
||||
### NOTE
|
||||
|
||||
Isso armazena informações de metadados do fornecedor sobre o binário.
|
||||
|
||||
- No x86-64, `readelf -n` mostrará as flags `GNU_PROPERTY_X86_FEATURE_1_*` dentro de `.note.gnu.property`. Se você ver `IBT` e/ou `SHSTK`, o binário foi construído com CET (Rastreamento de Ramificações Indiretas e/ou Pilha Sombra). Isso impacta ROP/JOP porque os alvos de ramificação indireta devem começar com uma instrução `ENDBR64` e os retornos são verificados contra uma pilha sombra. Veja a página CET para detalhes e notas de bypass.
|
||||
|
||||
{{#ref}}
|
||||
../common-binary-protections-and-bypasses/cet-and-shadow-stack.md
|
||||
{{#endref}}
|
||||
|
||||
### GNU_EH_FRAME
|
||||
|
||||
Define a localização das tabelas de desempilhamento de pilha, usadas por depuradores e funções de tempo de execução de tratamento de exceções em C++.
|
||||
@ -70,13 +78,21 @@ Define a localização das tabelas de desempilhamento de pilha, usadas por depur
|
||||
|
||||
Contém a configuração da defesa de prevenção de execução de pilha. Se habilitado, o binário não poderá executar código da pilha.
|
||||
|
||||
- Verifique com `readelf -l ./bin | grep GNU_STACK`. Para alternar forçosamente durante os testes, você pode usar `execstack -s|-c ./bin`.
|
||||
|
||||
### GNU_RELRO
|
||||
|
||||
Indica a configuração RELRO (Relocation Read-Only) do binário. Essa proteção marcará como somente leitura certas seções da memória (como o `GOT` ou as tabelas `init` e `fini`) após o programa ter sido carregado e antes de começar a ser executado.
|
||||
Indica a configuração RELRO (Relocation Read-Only) do binário. Essa proteção marcará como somente leitura certas seções da memória (como o `GOT` ou as tabelas `init` e `fini`) após o programa ter sido carregado e antes de começar a execução.
|
||||
|
||||
No exemplo anterior, está copiando 0x3b8 bytes para 0x1fc48 como somente leitura, afetando as seções `.init_array .fini_array .dynamic .got .data .bss`.
|
||||
|
||||
Observe que RELRO pode ser parcial ou total, a versão parcial não protege a seção **`.plt.got`**, que é usada para **lazy binding** e precisa desse espaço de memória para ter **permissões de escrita** para gravar o endereço das bibliotecas na primeira vez que sua localização é pesquisada.
|
||||
Note que RELRO pode ser parcial ou total, a versão parcial não protege a seção **`.plt.got`**, que é usada para **vinculação preguiçosa** e precisa desse espaço de memória para ter **permissões de escrita** para escrever o endereço das bibliotecas na primeira vez que sua localização é pesquisada.
|
||||
|
||||
> Para técnicas de exploração e notas de bypass atualizadas, verifique a página dedicada:
|
||||
|
||||
{{#ref}}
|
||||
../common-binary-protections-and-bypasses/relro.md
|
||||
{{#endref}}
|
||||
|
||||
### TLS
|
||||
|
||||
@ -149,9 +165,9 @@ Também indica a localização, deslocamento, permissões, mas também o **tipo
|
||||
|
||||
### Seções Meta
|
||||
|
||||
- **Tabela de strings**: Contém todas as strings necessárias pelo arquivo ELF (mas não as realmente usadas pelo programa). Por exemplo, contém nomes de seções como `.text` ou `.data`. E se `.text` está no deslocamento 45 na tabela de strings, usará o número **45** no campo **nome**.
|
||||
- **String table**: Contém todas as strings necessárias pelo arquivo ELF (mas não as realmente usadas pelo programa). Por exemplo, contém nomes de seções como `.text` ou `.data`. E se `.text` está no deslocamento 45 na tabela de strings, usará o número **45** no campo **name**.
|
||||
- Para encontrar onde está a tabela de strings, o ELF contém um ponteiro para a tabela de strings.
|
||||
- **Tabela de símbolos**: Contém informações sobre os símbolos, como o nome (deslocamento na tabela de strings), endereço, tamanho e mais metadados sobre o símbolo.
|
||||
- **Symbol table**: Contém informações sobre os símbolos, como o nome (deslocamento na tabela de strings), endereço, tamanho e mais metadados sobre o símbolo.
|
||||
|
||||
### Seções Principais
|
||||
|
||||
@ -194,6 +210,10 @@ Cada entrada de símbolo contém:
|
||||
- **Valor** (endereço na memória)
|
||||
- **Tamanho**
|
||||
|
||||
#### Versionamento de Símbolos GNU (dynsym/dynstr/gnu.version)
|
||||
|
||||
A glibc moderna usa versões de símbolos. Você verá entradas em `.gnu.version` e `.gnu.version_r` e nomes de símbolos como `strlen@GLIBC_2.17`. O vinculador dinâmico pode exigir uma versão específica ao resolver um símbolo. Ao criar realocações manuais (por exemplo, ret2dlresolve), você deve fornecer o índice de versão correto, caso contrário, a resolução falha.
|
||||
|
||||
## Seção Dinâmica
|
||||
```
|
||||
readelf -d lnstat
|
||||
@ -231,6 +251,23 @@ Tag Type Name/Value
|
||||
```
|
||||
O diretório NEEDED indica que o programa **precisa carregar a biblioteca mencionada** para continuar. O diretório NEEDED é completado uma vez que a **biblioteca compartilhada está totalmente operacional e pronta** para uso.
|
||||
|
||||
### Ordem de busca do carregador dinâmico (RPATH/RUNPATH, $ORIGIN)
|
||||
|
||||
As entradas `DT_RPATH` (obsoleto) e/ou `DT_RUNPATH` influenciam onde o carregador dinâmico procura por dependências. Ordem aproximada:
|
||||
|
||||
- `LD_LIBRARY_PATH` (ignorado para programas setuid/sgid ou de "execução segura" de outra forma)
|
||||
- `DT_RPATH` (somente se `DT_RUNPATH` estiver ausente)
|
||||
- `DT_RUNPATH`
|
||||
- `ld.so.cache`
|
||||
- diretórios padrão como `/lib64`, `/usr/lib64`, etc.
|
||||
|
||||
`$ORIGIN` pode ser usado dentro de RPATH/RUNPATH para se referir ao diretório do objeto principal. Do ponto de vista de um atacante, isso é importante quando você controla o layout do sistema de arquivos ou o ambiente. Para binários endurecidos (AT_SECURE), a maioria das variáveis de ambiente é ignorada pelo carregador.
|
||||
|
||||
- Inspecione com: `readelf -d ./bin | egrep -i 'r(path|unpath)'`
|
||||
- Teste rápido: `LD_DEBUG=libs ./bin 2>&1 | grep -i find` (mostra decisões de caminho de busca)
|
||||
|
||||
> Dica de priv-esc: Prefira abusar de RUNPATHs graváveis ou caminhos relativos a `$ORIGIN` mal configurados que você possui. LD_PRELOAD/LD_AUDIT são ignorados em contextos de execução segura (setuid).
|
||||
|
||||
## Relocações
|
||||
|
||||
O carregador também deve realocar dependências após tê-las carregado. Essas realocações são indicadas na tabela de realocação nos formatos REL ou RELA e o número de realocações é dado nas seções dinâmicas RELSZ ou RELASZ.
|
||||
@ -274,7 +311,6 @@ Offset Info Type Sym. Value Sym. Name + Addend
|
||||
00000001fea0 000900000402 R_AARCH64_JUMP_SL 0000000000000000 perror@GLIBC_2.17 + 0
|
||||
00000001fea8 000b00000402 R_AARCH64_JUMP_SL 0000000000000000 __cxa_finalize@GLIBC_2.17 + 0
|
||||
00000001feb0 000c00000402 R_AARCH64_JUMP_SL 0000000000000000 putc@GLIBC_2.17 + 0
|
||||
00000001feb8 000d00000402 R_AARCH64_JUMP_SL 0000000000000000 opendir@GLIBC_2.17 + 0
|
||||
00000001fec0 000e00000402 R_AARCH64_JUMP_SL 0000000000000000 fputc@GLIBC_2.17 + 0
|
||||
00000001fec8 001100000402 R_AARCH64_JUMP_SL 0000000000000000 snprintf@GLIBC_2.17 + 0
|
||||
00000001fed0 001200000402 R_AARCH64_JUMP_SL 0000000000000000 __snprintf_chk@GLIBC_2.17 + 0
|
||||
@ -314,13 +350,31 @@ Por exemplo, qualquer seção do tipo `R_AARCH64_RELATIV` deve ter modificado o
|
||||
|
||||
### Relocações Dinâmicas e GOT
|
||||
|
||||
A relocação também pode referenciar um símbolo externo (como uma função de uma dependência). Como a função malloc da libC. Então, o carregador ao carregar a libC em um endereço verificando onde a função malloc está carregada, escreverá esse endereço na tabela GOT (Global Offset Table) (indicado na tabela de relocação) onde o endereço de malloc deve ser especificado.
|
||||
A relocação também pode referenciar um símbolo externo (como uma função de uma dependência). Como a função malloc da libC. Então, o carregador, ao carregar a libC em um endereço, verificando onde a função malloc está carregada, escreverá esse endereço na tabela GOT (Global Offset Table) (indicado na tabela de relocação) onde o endereço de malloc deve ser especificado.
|
||||
|
||||
### Tabela de Ligação de Procedimentos
|
||||
|
||||
A seção PLT permite realizar vinculação preguiçosa, o que significa que a resolução da localização de uma função será realizada na primeira vez que for acessada.
|
||||
|
||||
Assim, quando um programa chama malloc, na verdade chama a localização correspondente de `malloc` na PLT (`malloc@plt`). Na primeira vez que é chamada, resolve o endereço de `malloc` e o armazena para que na próxima vez que `malloc` for chamada, esse endereço seja usado em vez do código PLT.
|
||||
Assim, quando um programa chama malloc, na verdade chama a localização correspondente de `malloc` no PLT (`malloc@plt`). Na primeira vez que é chamado, resolve o endereço de `malloc` e o armazena, para que na próxima vez que `malloc` seja chamado, esse endereço seja usado em vez do código PLT.
|
||||
|
||||
#### Comportamentos modernos de vinculação que impactam a exploração
|
||||
|
||||
- `-z now` (Full RELRO) desabilita a vinculação preguiçosa; as entradas PLT ainda existem, mas GOT/PLT é mapeado como somente leitura, então técnicas como **sobrescrita de GOT** e **ret2dlresolve** não funcionarão contra o binário principal (as bibliotecas ainda podem ser parcialmente RELRO). Veja:
|
||||
|
||||
{{#ref}}
|
||||
../common-binary-protections-and-bypasses/relro.md
|
||||
{{#endref}}
|
||||
|
||||
- `-fno-plt` faz com que o compilador chame funções externas através da **entrada GOT diretamente** em vez de passar pelo stub PLT. Você verá sequências de chamadas como `mov reg, [got]; call reg` em vez de `call func@plt`. Isso reduz o abuso de execução especulativa e altera ligeiramente a busca por gadgets ROP em torno dos stubs PLT.
|
||||
|
||||
- PIE vs static-PIE: PIE (ET_DYN com `INTERP`) precisa do carregador dinâmico e suporta a maquinaria usual PLT/GOT. Static-PIE (ET_DYN sem `INTERP`) tem relocações aplicadas pelo carregador do kernel e sem `ld.so`; espere nenhuma resolução PLT em tempo de execução.
|
||||
|
||||
> Se GOT/PLT não for uma opção, pivote para outros ponteiros de código graváveis ou use ROP/SROP clássico em libc.
|
||||
|
||||
{{#ref}}
|
||||
../arbitrary-write-2-exec/aw2exec-got-plt.md
|
||||
{{#endref}}
|
||||
|
||||
## Inicialização do Programa
|
||||
|
||||
@ -352,16 +406,26 @@ A partir do código C, é possível obter o mesmo resultado usando as extensões
|
||||
__attributte__((constructor)) //Add a constructor to execute before
|
||||
__attributte__((destructor)) //Add to the destructor list
|
||||
```
|
||||
Do ponto de vista de um compilador, para executar essas ações antes e depois da função `main`, é possível criar uma função `init` e uma função `fini`, que seriam referenciadas na seção dinâmica como **`INIT`** e **`FIN`**. e são colocadas nas seções `init` e `fini` do ELF.
|
||||
Do ponto de vista de um compilador, para executar essas ações antes e depois da função `main`, é possível criar uma função `init` e uma função `fini` que seriam referenciadas na seção dinâmica como **`INIT`** e **`FIN`**. e são colocadas nas seções `init` e `fini` do ELF.
|
||||
|
||||
A outra opção, como mencionado, é referenciar as listas **`__CTOR_LIST__`** e **`__DTOR_LIST__`** nas entradas **`INIT_ARRAY`** e **`FINI_ARRAY`** na seção dinâmica, e o comprimento dessas é indicado por **`INIT_ARRAYSZ`** e **`FINI_ARRAYSZ`**. Cada entrada é um ponteiro de função que será chamado sem argumentos.
|
||||
A outra opção, como mencionado, é referenciar as listas **`__CTOR_LIST__`** e **`__DTOR_LIST__`** nas entradas **`INIT_ARRAY`** e **`FINI_ARRAY`** na seção dinâmica e o comprimento delas é indicado por **`INIT_ARRAYSZ`** e **`FINI_ARRAYSZ`**. Cada entrada é um ponteiro de função que será chamado sem argumentos.
|
||||
|
||||
Além disso, também é possível ter um **`PREINIT_ARRAY`** com **ponteiros** que serão executados **antes** dos ponteiros **`INIT_ARRAY`**.
|
||||
|
||||
#### Nota de Exploração
|
||||
|
||||
- Sob Partial RELRO, esses arrays vivem em páginas que ainda são graváveis antes que `ld.so` mude `PT_GNU_RELRO` para somente leitura. Se você conseguir uma gravação arbitrária cedo o suficiente ou se puder direcionar os arrays graváveis de uma biblioteca, você pode sequestrar o fluxo de controle sobrescrevendo uma entrada com uma função de sua escolha. Sob Full RELRO, eles são somente leitura em tempo de execução.
|
||||
|
||||
- Para abuso de vinculação preguiçosa do vinculador dinâmico para resolver símbolos arbitrários em tempo de execução, veja a página dedicada:
|
||||
|
||||
{{#ref}}
|
||||
../rop-return-oriented-programing/ret2dlresolve.md
|
||||
{{#endref}}
|
||||
|
||||
### Ordem de Inicialização
|
||||
|
||||
1. O programa é carregado na memória, variáveis globais estáticas são inicializadas em **`.data`** e as não inicializadas são zeradas em **`.bss`**.
|
||||
2. Todas as **dependências** para o programa ou bibliotecas são **inicializadas** e o **link dinâmico** é executado.
|
||||
2. Todas as **dependências** para o programa ou bibliotecas são **inicializadas** e a **vinculação dinâmica** é executada.
|
||||
3. Funções **`PREINIT_ARRAY`** são executadas.
|
||||
4. Funções **`INIT_ARRAY`** são executadas.
|
||||
5. Se houver uma entrada **`INIT`**, ela é chamada.
|
||||
@ -379,4 +443,31 @@ Cada variável terá uma entrada no cabeçalho TLS especificando o tamanho e o d
|
||||
|
||||
O `__TLS_MODULE_BASE` é um símbolo usado para se referir ao endereço base do armazenamento local de thread e aponta para a área na memória que contém todos os dados locais de thread de um módulo.
|
||||
|
||||
## Vetor Auxiliar (auxv) e vDSO
|
||||
|
||||
O kernel Linux passa um vetor auxiliar para processos contendo endereços e flags úteis para o tempo de execução:
|
||||
|
||||
- `AT_RANDOM`: aponta para 16 bytes aleatórios usados pela glibc para o canário de pilha e outras sementes de PRNG.
|
||||
- `AT_SYSINFO_EHDR`: endereço base do mapeamento vDSO (útil para encontrar chamadas de sistema `__kernel_*` e gadgets).
|
||||
- `AT_EXECFN`, `AT_BASE`, `AT_PAGESZ`, etc.
|
||||
|
||||
Como um atacante, se você puder ler memória ou arquivos em `/proc`, muitas vezes pode vazar esses dados sem um infoleak no processo alvo:
|
||||
```bash
|
||||
# Show the auxv of a running process
|
||||
cat /proc/$(pidof target)/auxv | xxd
|
||||
|
||||
# From your own process (helper snippet)
|
||||
#include <sys/auxv.h>
|
||||
#include <stdio.h>
|
||||
int main(){
|
||||
printf("AT_RANDOM=%p\n", (void*)getauxval(AT_RANDOM));
|
||||
printf("AT_SYSINFO_EHDR=%p\n", (void*)getauxval(AT_SYSINFO_EHDR));
|
||||
}
|
||||
```
|
||||
Vazar `AT_RANDOM` fornece o valor do canário se você puder desreferenciar esse ponteiro; `AT_SYSINFO_EHDR` fornece uma base vDSO para minerar gadgets ou para chamar syscalls rápidas diretamente.
|
||||
|
||||
## Referências
|
||||
|
||||
- ld.so(8) – Ordem de busca do carregador dinâmico, RPATH/RUNPATH, regras de execução segura (AT_SECURE): https://man7.org/linux/man-pages/man8/ld.so.8.html
|
||||
- getauxval(3) – Vetor auxiliar e constantes AT_*: https://man7.org/linux/man-pages/man3/getauxval.3.html
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user