Learn & practice AWS Hacking:<imgsrc="/.gitbook/assets/arte.png"alt=""data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<imgsrc="/.gitbook/assets/arte.png"alt=""data-size="line">\
Learn & practice GCP Hacking: <imgsrc="/.gitbook/assets/grte.png"alt=""data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<imgsrc="/.gitbook/assets/grte.png"alt=""data-size="line">](https://training.hacktricks.xyz/courses/grte)
* 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.
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.
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.
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**:
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.
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()`** é 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()`** 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.
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.
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
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:
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).
**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**
**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)**
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, 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.
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.
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.
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)
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].
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.
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.
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.
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.
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).
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.
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.
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).
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.
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.
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á:
É 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.
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.
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).
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.
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.
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.
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 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.
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.
Aprenda e pratique AWS Hacking:<imgsrc="/.gitbook/assets/arte.png"alt=""data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<imgsrc="/.gitbook/assets/arte.png"alt=""data-size="line">\
Aprenda e pratique GCP Hacking: <imgsrc="/.gitbook/assets/grte.png"alt=""data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<imgsrc="/.gitbook/assets/grte.png"alt=""data-size="line">](https://training.hacktricks.xyz/courses/grte)
* 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.