Leaking libc address with ROP
Resumo Rápido
Encontre o deslocamento do overflow
Encontre o gadget
POP_RDI
,PUTS_PLT
eMAIN
Use os gadgets anteriores para vazar o endereço de memória do puts ou outra função libc e encontre a versão da libc (baixe-a)
Com a biblioteca, calcule o ROP e explore-o
Outros tutoriais e binários para praticar
Este tutorial vai explorar o código/binário proposto neste tutorial: https://tasteofsecurity.com/security/ret2libc-unknown-libc/ Outros tutoriais úteis: https://made0x78.com/bseries-ret2libc/, https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html
Código
Nome do arquivo: vuln.c
ROP - Modelo de vazamento de LIBC
Baixe o exploit e coloque-o no mesmo diretório do binário vulnerável e forneça os dados necessários ao script:
pageLeaking libc - template1- Encontrando o deslocamento
O modelo precisa de um deslocamento antes de continuar com o exploit. Se nenhum for fornecido, ele executará o código necessário para encontrá-lo (por padrão OFFSET = ""
):
Executar python template.py
uma console GDB será aberta com o programa sendo encerrado. Dentro dessa console GDB execute x/wx $rsp
para obter os bytes que iriam sobrescrever o RIP. Por fim, obtenha o deslocamento usando uma console python:
Depois de encontrar o deslocamento (neste caso 40), altere a variável OFFSET dentro do modelo usando esse valor.
OFFSET = "A" * 40
Outra maneira seria usar: pattern create 1000
-- execute until ret -- pattern seach $rsp
do GEF.
2- Encontrando Gadgets
Agora precisamos encontrar gadgets ROP dentro do binário. Esses gadgets ROP serão úteis para chamar puts
para encontrar a libc sendo usada e, posteriormente, lançar o exploit final.
O PUTS_PLT
é necessário para chamar a função puts.
O MAIN_PLT
é necessário para chamar a função principal novamente após uma interação para explorar o estouro novamente (rodadas infinitas de exploração). É usado no final de cada ROP para chamar o programa novamente.
O POP_RDI é necessário para passar um parâmetro para a função chamada.
Nesta etapa, você não precisa executar nada, pois tudo será encontrado pelo pwntools durante a execução.
3- Encontrando a biblioteca libc
Agora é hora de descobrir qual versão da biblioteca libc está sendo usada. Para fazer isso, vamos vazar o endereço na memória da função puts
e então vamos pesquisar em qual versão da biblioteca a versão do puts está nesse endereço.
Para fazer isso, a linha mais importante do código executado é:
Isso enviará alguns bytes sobrescrevendo o RIP é possível: OFFSET
.
Em seguida, ele definirá o endereço do gadget POP_RDI
para que o próximo endereço (FUNC_GOT
) seja salvo no registro RDI. Isso ocorre porque queremos chamar puts passando o endereço do PUTS_GOT
como o endereço na memória da função puts é salvo no endereço apontado por PUTS_GOT
.
Depois disso, PUTS_PLT
será chamado (com PUTS_GOT
dentro do RDI) para que puts leia o conteúdo dentro de PUTS_GOT
(o endereço da função puts na memória) e o imprima.
Por fim, a função principal é chamada novamente para que possamos explorar o estouro novamente.
Dessa forma, enganamos a função puts para imprimir o endereço na memória da função puts (que está dentro da biblioteca libc). Agora que temos esse endereço, podemos verificar qual versão da libc está sendo usada.
Como estamos explorando um binário local, não é necessário descobrir qual versão da libc está sendo usada (apenas encontre a biblioteca em /lib/x86_64-linux-gnu/libc.so.6
).
Mas, em um caso de exploração remota, explicarei aqui como você pode encontrá-la:
3.1- Procurando pela versão da libc (1)
Você pode procurar qual biblioteca está sendo usada na página da web: https://libc.blukat.me/ Isso também permitirá que você baixe a versão descoberta da libc
3.2- Procurando pela versão da libc (2)
Você também pode fazer:
$ git clone https://github.com/niklasb/libc-database.git
$ cd libc-database
$ ./get
Isso levará algum tempo, seja paciente. Para isso funcionar, precisamos de:
Nome do símbolo da libc:
puts
Endereço da libc vazado:
0x7ff629878690
Podemos descobrir qual libc está sendo usada.
Obtemos 2 correspondências (deve tentar a segunda se a primeira não funcionar). Baixe a primeira:
Copie a libc de libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so
para o nosso diretório de trabalho.
3.3- Outras funções para vazamento
4- Encontrando o endereço base da libc e explorando
Neste ponto, devemos saber qual biblioteca libc está sendo usada. Como estamos explorando um binário local, vou usar apenas: /lib/x86_64-linux-gnu/libc.so.6
Portanto, no início do arquivo template.py
, altere a variável libc para: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #Defina o caminho da biblioteca quando souber
Ao fornecer o caminho para a biblioteca libc, o restante da exploit será calculado automaticamente.
Dentro da função get_addr
, o endereço base da libc será calculado:
Note que o endereço base final da libc deve terminar em 00. Se esse não for o seu caso, você pode ter vazado uma biblioteca incorreta.
Em seguida, o endereço da função system
e o endereço da string "/bin/sh" serão calculados a partir do endereço base da libc e considerando a biblioteca libc fornecida.
Finalmente, o exploit de execução /bin/sh está prestes a ser preparado para ser enviado:
Vamos explicar este ROP final.
O último ROP (rop1
) terminou chamando novamente a função principal, então podemos explorar novamente o estouro de buffer (por isso o OFFSET
está aqui novamente). Em seguida, queremos chamar POP_RDI
apontando para o endereço de "/bin/sh" (BINSH
) e chamar a função system (SYSTEM
) porque o endereço de "/bin/sh" será passado como parâmetro.
Por fim, o endereço da função exit é chamado para que o processo saia corretamente e nenhum alerta seja gerado.
Dessa forma, o exploit executará um shell _/bin/sh_**.
4(2)- Usando ONE_GADGET
Você também poderia usar ONE_GADGET para obter um shell em vez de usar system e "/bin/sh". ONE_GADGET encontrará dentro da biblioteca libc alguma maneira de obter um shell usando apenas um endereço ROP.
No entanto, normalmente existem algumas restrições, as mais comuns e fáceis de evitar são como [rsp+0x30] == NULL
. Como você controla os valores dentro do RSP, basta enviar mais valores NULL para evitar a restrição.
FICHEIRO DE EXPLOIT
Pode encontrar um modelo para explorar esta vulnerabilidade aqui:
pageLeaking libc - templateProblemas Comuns
MAIN_PLT = elf.symbols['main'] não encontrado
Se o símbolo "main" não existir. Então pode encontrar onde está o código principal:
e defina o endereço manualmente:
Puts não encontrado
Se o binário não estiver usando Puts, você deve verificar se está usando
sh: 1: %s%s%s%s%s%s%s%s: not found
sh: 1: %s%s%s%s%s%s%s%s: not found
Se você encontrar este erro após criar todo o exploit: sh: 1: %s%s%s%s%s%s%s%s: not found
Tente subtrair 64 bytes do endereço de "/bin/sh":
Last updated