mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-19 01:24:50 +00:00
211 lines
21 KiB
Markdown
211 lines
21 KiB
Markdown
|
# Bins & Alocações de Memória
|
||
|
|
||
|
<details>
|
||
|
|
||
|
<summary><strong>Aprenda hacking AWS do zero ao herói com</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
||
|
|
||
|
Outras maneiras de apoiar o HackTricks:
|
||
|
|
||
|
* Se você deseja ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF**, confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
||
|
* Adquira o [**swag oficial PEASS & HackTricks**](https://peass.creator-spring.com)
|
||
|
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||
|
* **Junte-se ao** 💬 [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-nos** no **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||
|
* **Compartilhe seus truques de hacking enviando PRs para os** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
|
||
|
|
||
|
</details>
|
||
|
|
||
|
## Informações Básicas
|
||
|
|
||
|
Para melhorar a eficiência na forma como os chunks são armazenados, cada chunk não está apenas em uma lista encadeada, mas existem vários tipos. Estes são os bins e existem 5 tipos de bins: [62](https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l1407) small bins, 63 large bins, 1 unsorted bin, 10 fast bins e 64 tcache bins por thread.
|
||
|
|
||
|
O endereço inicial para cada bin não ordenado, small e large está dentro do mesmo array. O índice 0 não é usado, 1 é o bin não ordenado, os bins 2-64 são os small bins e os bins 65-127 são os large bins.
|
||
|
|
||
|
### Small Bins
|
||
|
|
||
|
Os small bins são mais rápidos do que os large bins, mas mais lentos do que os fast bins.
|
||
|
|
||
|
Cada bin dos 62 terá **chunks do mesmo tamanho**: 16, 24, ... (com um tamanho máximo de 504 bytes em 32 bits e 1024 em 64 bits). Isso ajuda na velocidade para encontrar o bin onde um espaço deve ser alocado e inserir e remover entradas nessas listas.
|
||
|
|
||
|
### Large Bins
|
||
|
|
||
|
Ao contrário dos small bins, que gerenciam chunks de tamanhos fixos, cada **large bin lida com uma faixa de tamanhos de chunk**. Isso é mais flexível, permitindo que o sistema acomode **vários tamanhos** sem precisar de um bin separado para cada tamanho.
|
||
|
|
||
|
Em um alocador de memória, os large bins começam onde os small bins terminam. As faixas para os large bins crescem progressivamente, o que significa que o primeiro bin pode cobrir chunks de 512 a 576 bytes, enquanto o próximo cobre de 576 a 640 bytes. Esse padrão continua, com o maior bin contendo todos os chunks acima de 1MB.
|
||
|
|
||
|
Os large bins são mais lentos de operar em comparação com os small bins porque eles precisam **ordenar e pesquisar em uma lista de tamanhos de chunk variados para encontrar o melhor encaixe** para uma alocação. Quando um chunk é inserido em um large bin, ele precisa ser ordenado, e quando a memória é alocada, o sistema deve encontrar o chunk certo. Esse trabalho extra os torna **mais lentos**, mas como alocações grandes são menos comuns do que as pequenas, é uma troca aceitável.
|
||
|
|
||
|
Existem:
|
||
|
|
||
|
* 32 bins de faixa de 64B
|
||
|
* 16 bins de faixa de 512B
|
||
|
* 8 bins de faixa de 4096B
|
||
|
* 4 bins de faixa de 32768B
|
||
|
* 2 bins de faixa de 262144B
|
||
|
* 1 bin para tamanhos restantes
|
||
|
|
||
|
### Unsorted Bin
|
||
|
|
||
|
O unsorted bin é um **cache rápido** usado pelo gerenciador de heap para tornar a alocação de memória mais rápida. Veja como funciona: Quando um programa libera memória, o gerenciador de heap não a coloca imediatamente em um bin específico. Em vez disso, primeiro tenta **fundir com quaisquer chunks livres vizinhos** para criar um bloco maior de memória livre. Em seguida, coloca esse novo chunk em um bin geral chamado "unsorted bin".
|
||
|
|
||
|
Quando um programa **solicita memória**, o gerenciador de heap **verifica o unsorted bin** para ver se há um chunk de tamanho suficiente. Se encontrar um, ele o usa imediatamente. Se não encontrar um chunk adequado, move os chunks liberados para seus bins correspondentes, seja small ou large, com base em seus tamanhos.
|
||
|
|
||
|
Portanto, o unsorted bin é uma maneira de acelerar a alocação de memória reutilizando rapidamente a memória liberada recentemente e reduzindo a necessidade de pesquisas e fusões demoradas.
|
||
|
|
||
|
{% hint style="danger" %}
|
||
|
Observe que mesmo que os chunks sejam de categorias diferentes, se um chunk disponível estiver colidindo com outro chunk disponível (mesmo que sejam de categorias diferentes), eles serão mesclados.
|
||
|
{% endhint %}
|
||
|
|
||
|
### Fast Bins
|
||
|
|
||
|
Os fast bins são projetados para **acelerar a alocação de memória para pequenos chunks** mantendo chunks liberados recentemente em uma estrutura de acesso rápido. Esses bins usam uma abordagem Last-In, First-Out (LIFO), o que significa que o **chunk liberado mais recentemente é o primeiro** a ser reutilizado quando há uma nova solicitação de alocação. Esse comportamento é vantajoso para a velocidade, pois é mais rápido inserir e remover do topo de uma pilha (LIFO) em comparação com uma fila (FIFO).
|
||
|
|
||
|
Além disso, **os fast bins usam listas encadeadas simples**, não duplamente encadeadas, o que melhora ainda mais a velocidade. Como os chunks nos fast bins não são mesclados com vizinhos, não há necessidade de uma estrutura complexa que permita a remoção do meio. Uma lista encadeada simples é mais simples e rápida para essas operações.
|
||
|
|
||
|
Basicamente, o que acontece aqui é que o cabeçalho (o ponteiro para o primeiro chunk a ser verificado) está sempre apontando para o chunk liberado mais recentemente desse tamanho. Portanto:
|
||
|
|
||
|
* Quando um novo chunk é alocado desse tamanho, o cabeçalho está apontando para um chunk livre para usar. Como esse chunk livre está apontando para o próximo a ser usado, esse endereço é armazenado no cabeçalho para que a próxima alocação saiba onde obter um chunk disponível.
|
||
|
* Quando um chunk é liberado, o chunk livre salvará o endereço para o chunk disponível atual e o endereço para esse chunk recém-liberado será colocado no cabeçalho.
|
||
|
|
||
|
{% hint style="danger" %}
|
||
|
Chunks nos fast bins não são definidos automaticamente como disponíveis, então eles permanecem como chunks de fast bin por algum tempo em vez de poderem ser mesclados com outros chunks.
|
||
|
{% endhint %}
|
||
|
|
||
|
### Tcache (Cache por Thread) Bins
|
||
|
|
||
|
Mesmo que as threads tentem ter sua própria heap (veja [Arenas](bins-and-memory-allocations.md#arenas) e [Subheaps](bins-and-memory-allocations.md#subheaps)), há a possibilidade de que um processo com muitas threads (como um servidor web) **acabe compartilhando a heap com outras threads**. Nesse caso, a solução principal é o uso de **lockers**, que podem **desacelerar significativamente as threads**.
|
||
|
|
||
|
Portanto, um tcache é semelhante a um fast bin por thread no sentido de que é uma **lista encadeada simples** que não mescla chunks. Cada thread tem **64 tcache bins encadeados simples**. Cada bin pode ter um máximo de [7 chunks do mesmo tamanho](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l323) variando de [24 a 1032B em sistemas de 64 bits e de 12 a 516B em sistemas de 32 bits](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l315).
|
||
|
|
||
|
Quando uma thread **libera** um chunk, **se não for muito grande** para ser alocado no tcache e o respectivo bin do tcache **não estiver cheio** (já com 7 chunks), **ele será alocado lá**. Se não puder ir para o tcache, precisará esperar o bloqueio da heap para poder realizar a operação de liberação globalmente.
|
||
|
|
||
|
Quando um **chunk é alocado**, se houver um chunk livre do tamanho necessário no **Tcache, ele será usado**, caso contrário, precisará esperar o bloqueio da heap para poder encontrar um nos bins globais ou criar um novo.\
|
||
|
Há também uma otimização, nesse caso, enquanto tiver o bloqueio da heap, a thread **preencherá seu Tcache com chunks da heap (7) do tamanho solicitado**, para que, caso precise de mais, os encontre no Tcache.
|
||
|
## Fluxo de Alocação
|
||
|
|
||
|
{% hint style="success" %}
|
||
|
(Esta explicação atual é de [https://heap-exploitation.dhavalkapil.com/diving\_into\_glibc\_heap/core\_functions](https://heap-exploitation.dhavalkapil.com/diving\_into\_glibc\_heap/core\_functions). TODO: Verificar última versão e atualizá-la)
|
||
|
{% endhint %}
|
||
|
|
||
|
As alocações são finalmente realizadas com a função: `void * _int_malloc (mstate av, size_t bytes)` e seguem esta ordem:
|
||
|
|
||
|
1. Atualiza `bytes` para cuidar dos **alinhamentos**, etc.
|
||
|
2. Verifica se `av` é **NULL** ou não.
|
||
|
3. No caso de ausência de **arena utilizável** (quando `av` é NULL), chama `sysmalloc` para obter um chunk usando mmap. Se bem-sucedido, chama `alloc_perturb`. Retorna o ponteiro.
|
||
|
4. Dependendo do tamanho:
|
||
|
* \[Adição ao original] Usa tcache antes de verificar o próximo fastbin.
|
||
|
* \[Adição ao original] Se não houver tcache, mas um bin diferente for usado (ver etapa posterior), tenta preencher a tcache a partir desse bin.
|
||
|
* Se o tamanho estiver na faixa do **fastbin**:
|
||
|
1. Obtém o índice na matriz fastbin para acessar um bin apropriado de acordo com o tamanho solicitado.
|
||
|
2. Remove o primeiro chunk nesse bin e faz com que `victim` aponte para ele.
|
||
|
3. Se `victim` for NULL, passa para o próximo caso (smallbin).
|
||
|
4. Se `victim` não for NULL, verifica o tamanho do chunk para garantir que pertença a esse bin específico. Caso contrário, é lançado um erro ("malloc(): corrupção de memória (fast)").
|
||
|
5. Chama `alloc_perturb` e então retorna o ponteiro.
|
||
|
* Se o tamanho estiver na faixa do **smallbin**:
|
||
|
1. Obtém o índice na matriz smallbin para acessar um bin apropriado de acordo com o tamanho solicitado.
|
||
|
2. Se não houver chunks neste bin, passa para o próximo caso. Isso é verificado comparando os ponteiros `bin` e `bin->bk`.
|
||
|
3. `victim` é igual a `bin->bk` (o último chunk no bin). Se for NULL (ocorre durante a `inicialização`), chama `malloc_consolidate` e pula esta etapa completa de verificação em bins diferentes.
|
||
|
4. Caso contrário, quando `victim` não for NULL, verifica se `victim->bk->fd` e `victim` são iguais ou não. Se não forem iguais, é lançado um erro (`malloc(): lista duplamente vinculada smallbin corrompida`).
|
||
|
5. Define o bit PREV\_INSUSE para o próximo chunk (na memória, não na lista duplamente vinculada) para `victim`.
|
||
|
6. Remove este chunk da lista do bin.
|
||
|
7. Define o bit de arena apropriado para este chunk dependendo de `av`.
|
||
|
8. Chama `alloc_perturb` e então retorna o ponteiro.
|
||
|
* Se o tamanho não estiver na faixa do smallbin:
|
||
|
1. Obtém o índice na matriz largebin para acessar um bin apropriado de acordo com o tamanho solicitado.
|
||
|
2. Verifica se `av` possui fastchunks ou não. Isso é feito verificando o `FASTCHUNKS_BIT` em `av->flags`. Se sim, chama `malloc_consolidate` em `av`.
|
||
|
5. Se nenhum ponteiro foi retornado ainda, isso significa um ou mais dos seguintes casos:
|
||
|
1. O tamanho está na faixa do 'fastbin' mas nenhum fastchunk está disponível.
|
||
|
2. O tamanho está na faixa do 'smallbin' mas nenhum smallchunk está disponível (chama `malloc_consolidate` durante a inicialização).
|
||
|
3. O tamanho está na faixa do 'largebin'.
|
||
|
6. Em seguida, os **chunks não ordenados** são verificados e os chunks percorridos são colocados em bins. Este é o único lugar onde os chunks são colocados em bins. Itera o bin não ordenado a partir do 'TAIL'.
|
||
|
1. `victim` aponta para o chunk atual em consideração.
|
||
|
2. Verifica se o tamanho do chunk de `victim` está dentro da faixa mínima (`2*SIZE_SZ`) e máxima (`av->system_mem`). Lança um erro (`malloc(): corrupção de memória`) caso contrário.
|
||
|
3. Se (o tamanho do chunk solicitado está na faixa do smallbin) e (`victim` é o último chunk restante) e (é o único chunk no bin não ordenado) e (o tamanho dos chunks >= o solicitado): **Divide o chunk em 2 chunks**:
|
||
|
* O primeiro chunk corresponde ao tamanho solicitado e é retornado.
|
||
|
* O chunk restante se torna o novo último chunk restante. Ele é reinserido no bin não ordenado.
|
||
|
1. Define os campos `chunk_size` e `chunk_prev_size` apropriadamente para ambos os chunks.
|
||
|
2. O primeiro chunk é retornado após chamar `alloc_perturb`.
|
||
|
3. Se a condição acima for falsa, o controle chega aqui. Remove `victim` do bin não ordenado. Se o tamanho de `victim` corresponder exatamente ao tamanho solicitado, retorne este chunk após chamar `alloc_perturb`.
|
||
|
4. Se o tamanho de `victim` estiver na faixa do smallbin, adicione o chunk no smallbin apropriado no `HEAD`.
|
||
|
5. Caso contrário, insira no largebin apropriado mantendo a ordem classificada:
|
||
|
6. Primeiro verifica o último chunk (menor). Se `victim` for menor que o último chunk, insere-o no final.
|
||
|
7. Caso contrário, faça um loop para encontrar um chunk com tamanho >= tamanho de `victim`. Se o tamanho for exatamente o mesmo, sempre insira na segunda posição.
|
||
|
8. Repita toda essa etapa um máximo de `MAX_ITERS` (10000) vezes ou até que todos os chunks no bin não ordenado se esgotem.
|
||
|
7. Após verificar os chunks não ordenados, verifique se o tamanho solicitado não está na faixa do smallbin, se sim, verifique os **largebins**.
|
||
|
1. Obtém o índice na matriz largebin para acessar um bin apropriado de acordo com o tamanho solicitado.
|
||
|
2. Se o tamanho do maior chunk (o primeiro chunk no bin) for maior que o tamanho solicitado:
|
||
|
1. Itera a partir do 'TAIL' para encontrar um chunk (`victim`) com o menor tamanho >= o tamanho solicitado.
|
||
|
2. Chama `unlink` para remover o chunk `victim` do bin.
|
||
|
3. Calcula `remainder_size` para o chunk de `victim` (este será o tamanho do chunk de `victim` - tamanho solicitado).
|
||
|
4. Se este `remainder_size` >= `MINSIZE` (o tamanho mínimo do chunk incluindo os cabeçalhos), divide o chunk em dois chunks. Caso contrário, o chunk inteiro de `victim` será retornado. Insira o chunk restante no bin não ordenado (no final do 'TAIL'). É feita uma verificação no bin não ordenado se `unsorted_chunks(av)->fd->bk == unsorted_chunks(av)`. Um erro é lançado caso contrário ("malloc(): chunks não ordenados corrompidos").
|
||
|
5. Retorna o chunk `victim` após chamar `alloc_perturb`.
|
||
|
8. Até agora, verificamos o bin não ordenado e também o respectivo fast, small ou large bin. Observe que um único bin (fast ou small) foi verificado usando o tamanho **exato** do chunk solicitado. Repita as seguintes etapas até que todos os bins se esgotem:
|
||
|
1. O índice na matriz bin é incrementado para verificar o próximo bin.
|
||
|
2. Usa o mapa `av->binmap` para pular os bins vazios.
|
||
|
3. `victim` aponta para o 'TAIL' do bin atual.
|
||
|
4. Usando o binmap garante que se um bin for pulado (no segundo passo acima), ele está definitivamente vazio. No entanto, não garante que todos os bins vazios serão pulados. Verifique se o victim está vazio ou não. Se estiver vazio, pule novamente o bin e repita o processo acima (ou 'continue' este loop) até chegarmos a um bin não vazio.
|
||
|
5. Divida o chunk (`victim` aponta para o último chunk de um bin não vazio) em dois chunks. Insira o chunk restante no bin não ordenado (no final do 'TAIL'). É feita uma verificação no bin não ordenado se `unsorted_chunks(av)->fd->bk == unsorted_chunks(av)`. Um erro é lançado caso contrário ("malloc(): chunks não ordenados corrompidos 2").
|
||
|
6. Retorna o chunk `victim` após chamar `alloc_perturb`.
|
||
|
9. Se ainda nenhum bin vazio for encontrado, o chunk 'top' será usado para atender à solicitação:
|
||
|
1. `victim` aponta para `av->top`.
|
||
|
2. Se o tamanho do chunk 'top' >= 'tamanho solicitado' + `MINSIZE`, divida-o em dois chunks. Neste caso, o chunk restante se torna o novo chunk 'top' e o outro chunk é retornado ao usuário após chamar `alloc_perturb`.
|
||
|
3. Verifica se `av` possui fastchunks ou não. Isso é feito verificando o `FASTCHUNKS_BIT` em `av->flags`. Se sim, chama `malloc_consolidate` em `av`. Retorna para a etapa 6 (onde verificamos o bin não ordenado).
|
||
|
4. Se `av` não tiver fastchunks, chama `sysmalloc` e retorna o ponteiro obtido após chamar `alloc_perturb`.
|
||
|
## Fluxo Livre
|
||
|
|
||
|
{% hint style="success" %}
|
||
|
(Esta explicação atual é de [https://heap-exploitation.dhavalkapil.com/diving\_into\_glibc\_heap/core\_functions](https://heap-exploitation.dhavalkapil.com/diving\_into\_glibc\_heap/core\_functions). TODO: Verificar última versão e atualizá-la)
|
||
|
{% endhint %}
|
||
|
|
||
|
A função final que libera pedaços de memória é `_int_free (mstate av, mchunkptr p, int have_lock)`:
|
||
|
|
||
|
1. Verificar se `p` está antes de `p + chunksize(p)` na memória (para evitar embrulhar). Um erro (`free(): ponteiro inválido`) é lançado caso contrário.
|
||
|
2. Verificar se o pedaço tem pelo menos o tamanho `MINSIZE` ou é um múltiplo de `MALLOC_ALIGNMENT`. Um erro (`free(): tamanho inválido`) é lançado caso contrário.
|
||
|
3. Se o tamanho do pedaço estiver na lista fastbin:
|
||
|
1. Verificar se o tamanho do próximo pedaço está entre o tamanho mínimo e máximo (`av->system_mem`), lançar um erro (`free(): tamanho próximo inválido (rápido)`) caso contrário.
|
||
|
2. Chamar `free_perturb` no pedaço.
|
||
|
3. Definir `FASTCHUNKS_BIT` para `av`.
|
||
|
4. Obter índice na matriz fastbin de acordo com o tamanho do pedaço.
|
||
|
5. Verificar se o topo do bin não é o pedaço que estamos adicionando. Caso contrário, lançar um erro (`dupla liberação ou corrupção (topo rápido)`).
|
||
|
6. Verificar se o tamanho do pedaço fastbin no topo é o mesmo que o pedaço que estamos adicionando. Caso contrário, lançar um erro (`entrada fastbin inválida (liberação)`).
|
||
|
7. Inserir o pedaço no topo da lista fastbin e retornar.
|
||
|
4. Se o pedaço não estiver mapeado:
|
||
|
1. Verificar se o pedaço é o pedaço superior ou não. Se sim, um erro (`dupla liberação ou corrupção (topo)`) é lançado.
|
||
|
2. Verificar se o próximo pedaço (por memória) está dentro dos limites da arena. Se não estiver, um erro (`dupla liberação ou corrupção (fora)`) é lançado.
|
||
|
3. Verificar se o bit anterior em uso do próximo pedaço (por memória) está marcado ou não. Se não estiver, um erro (`dupla liberação ou corrupção (!prev)`) é lançado.
|
||
|
4. Verificar se o tamanho do próximo pedaço está entre o tamanho mínimo e máximo (`av->system_mem`). Se não estiver, um erro (`free(): tamanho próximo inválido (normal)`) é lançado.
|
||
|
5. Chamar `free_perturb` no pedaço.
|
||
|
6. Se o pedaço anterior (por memória) não estiver em uso, chamar `unlink` no pedaço anterior.
|
||
|
7. Se o próximo pedaço (por memória) não for o pedaço superior:
|
||
|
1. Se o próximo pedaço não estiver em uso, chamar `unlink` no próximo pedaço.
|
||
|
2. Mesclar o pedaço com o anterior, próximo (por memória), se algum estiver livre e adicioná-lo ao início do bin não ordenado. Antes de inserir, verificar se `unsorted_chunks(av)->fd->bk == unsorted_chunks(av)` ou não. Se não, um erro ("free(): pedaços não ordenados corrompidos") é lançado.
|
||
|
8. Se o próximo pedaço (por memória) era um pedaço superior, mesclar os pedaços apropriadamente em um único pedaço superior.
|
||
|
5. Se o pedaço estava mapeado, chamar `munmap_chunk`.
|
||
|
|
||
|
## Verificações de Segurança das Funções de Heap
|
||
|
|
||
|
Verifique as verificações de segurança realizadas por funções amplamente utilizadas no heap em:
|
||
|
|
||
|
{% content-ref url="heap-functions-security-checks.md" %}
|
||
|
[heap-functions-security-checks.md](heap-functions-security-checks.md)
|
||
|
{% endcontent-ref %}
|
||
|
|
||
|
## Referências
|
||
|
|
||
|
* [https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/](https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/)
|
||
|
* [https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/](https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/)
|
||
|
* [https://heap-exploitation.dhavalkapil.com/diving\_into\_glibc\_heap/core\_functions](https://heap-exploitation.dhavalkapil.com/diving\_into\_glibc\_heap/core\_functions)
|
||
|
|
||
|
<details>
|
||
|
|
||
|
<summary><strong>Aprenda hacking AWS do zero ao herói com</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
||
|
|
||
|
Outras maneiras de apoiar o HackTricks:
|
||
|
|
||
|
* Se você quiser ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF** Verifique os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
||
|
* Obtenha o [**swag oficial PEASS & HackTricks**](https://peass.creator-spring.com)
|
||
|
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||
|
* **Junte-se ao** 💬 [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-nos** no **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||
|
* **Compartilhe seus truques de hacking enviando PRs para o** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||
|
|
||
|
</details>
|