Neste artigo, trataremos da vulnerabilidade de estouro de buffer no heap e também resolveremos a 19ª tarefa do site
pwnable.kr .
Informações OrganizacionaisEspecialmente para aqueles que desejam aprender algo novo e se desenvolver em qualquer uma das áreas de segurança da informação e da informática, escreverei e falarei sobre as seguintes categorias:
- PWN;
- criptografia (criptografia);
- tecnologias de rede (rede);
- reverso (engenharia reversa);
- esteganografia (estegano);
- pesquisa e exploração de vulnerabilidades na WEB.
Além disso, compartilharei minha experiência em análise forense de computadores, análise de malware e firmware, ataques a redes sem fio e redes locais, realização de protestos e explorações por escrito.
Para que você possa descobrir sobre novos artigos, software e outras informações, criei um
canal no Telegram e um
grupo para discutir quaisquer questões no campo da CID. Além disso, considerarei pessoalmente seus pedidos, perguntas, sugestões e recomendações
pessoais e responderei a todos .
Todas as informações são fornecidas apenas para fins educacionais. O autor deste documento não se responsabiliza por nenhum dano causado a alguém como resultado do uso dos conhecimentos e métodos obtidos como resultado do estudo deste documento.
Como um grupo é organizado
A memória pode estar ocupada (alocada) e livre. A figura mostra a memória dinâmica.
- SSize - o tamanho do bloco de memória anterior, desde que esteja livre.
- Tamanho - o tamanho do bloco de memória fornecido, ao qual são adicionados 2 bits de status.
- Dados - dados do usuário.
- Fd é um ponteiro para o próximo bloco livre.
- Bk - ponteiro para o bloco livre anterior.
- Memória livre - livre.

Assim, nenhum dois blocos livres podem ser vizinhos. Além disso, na fronteira da memória do sistema livre e ocupada, há um bloco W livre especialmente processado.

A representação dos blocos nas listas (cestas) é a seguinte.

O método de desvinculação é usado para remover um bloco livre da lista.
void unlink(S, BK, FD){ BK = S->bk; FD = S->fd; FD->bk=BK; FD->fd=FD; }
Alocação e liberação de memória
Vamos ver como o mmap funciona. Na primeira etapa, as matrizes dos tamanhos necessários são verificadas (por exemplo, 24 bytes). Se houver um bloco necessário, ele será separado usando o link.

Na segunda etapa, se esse bloco for grande o suficiente, ele será dividido em duas partes. A primeira parte é alocada e a segunda é redistribuída para outra matriz.

Na terceira etapa, se o bloco do tamanho necessário não tiver sido alocado, o bloco W será verificado. Se ele satisfizer, então os dois passos são realizados com ele. Se o bloco W for pequeno, sbrk () e mmap () serão usados para expandir a memória disponível. O método Free é completamente oposto ao mmap.
Estouro de buffer de pilha
Um estouro de heap é um tipo de estouro de buffer que ocorre na área de dados do heap. A memória no heap é alocada dinamicamente pelo aplicativo em tempo de execução e geralmente contém dados do programa. A exploração é realizada corrompendo esses dados de uma maneira especial, para que o aplicativo substitua estruturas internas, como ponteiros, em uma lista vinculada. O método de estouro de heap canônico substitui o relacionamento de alocação de memória dinâmica (por exemplo, metadados malloc) e usa a troca de ponteiro para reescrever um ponteiro em uma função de programa.
Como exemplo, na função Desvincular, usando FD-> bk, você pode alterar o valor de uma palavra arbitrária na memória. Por exemplo, coloque o código da shell para alterar o endereço GOT. Um exemplo de estouro será um exemplo.
Desvincular solução de trabalho
Clicamos no primeiro ícone com a assinatura desvinculada e somos informados de que precisamos nos conectar via SSH com a senha de convidado.

Quando conectado, vemos o banner correspondente.

Vamos descobrir quais arquivos estão no servidor e quais direitos temos.

Vamos ver o código fonte.

Portanto, temos o objeto B associado aos objetos A e C. Em seguida, o objeto A é inserido e preenchido. Tendo os objetos A - B - C conectados e controlando o preenchimento de A, podemos sobrecarregar o heap e reescrever os objetos B e C. Precisamos encontrar uma maneira de explorar a vulnerabilidade. Vamos dar uma olhada no gdb.

Assim, você pode escrever o código de shell e reescrever o endereço de retorno do main para o nosso código de shell. O endereço de retorno cai em esp a partir do registro ecx, onde é alimentado pelo ebp-4. Desmontando a função de desvinculação, notamos que o ebp-4 pode ser controlado pela entrada do usuário.

Vamos ver como nossos objetos estão localizados na memória e como a função desvincular funciona. Cada objeto ocupa 16 bytes na memória (4 para ponteiros e 8 para buffers).

A alocação de memória para objetos ocorre nas linhas principal + 38, principal + 54 e principal + 70. Antes de cada chamada, o ponteiro da pilha (esp) aumenta em 16 e diminui em 12, após o qual 16 bytes são reservados.


Ou seja, existem 4 bytes entre estruturas.

Em seguida é a vinculação e vinculação de objetos.


Portanto, precisamos que, ao retornar da função, o endereço vá para o local heap + 12, que transferirá o controle para o endereço em que o código da shell está localizado.

from pwn import * s = ssh("unlink", "pwnable.kr", password="guest", port=2222) ex = s.process("./unlink") shell_address = p32(0x80484eb) ans = ex.recv().split("\n") stack_addr = p32(int(ans[0].split(" ")[5],16) + 16) heap_addr = p32(int(ans[1].split(" ")[5],16) + 12) payload = shell_address + "A"*12 + heap_addr + stack_addr ex.sendline(payload) ex.interactive()

Conseguimos a concha, lemos a bandeira, ganha 10 pontos.

Você pode se juntar a nós no
Telegram . Da próxima vez, trataremos do estouro de heap.