CTF-BR: firstflask Write-Up

E aí, galera, beleza? Meu nick é v3ntur4X e eu vou explicar como eu resolvi a chall que o j3r3mias fez pro CTF-BR!

Eu entrei no link que eles disponibilizaram: http://142.93.73.149:1337

...
Index do site


Analisei, fui no robots.txt e não tinha.

Abri a source da página e vi um "/pagina" comentado no código:

...
Código fonte da index


Acessei o /pagina e apareceu a source de um arquivo (código do app.py):

...
Source do app.py


Não sabia muito o que fazer pois nunca tinha trabalhado com Flask, então fiquei um tempo analisando o código e mandei pra um editor para poder ter melhor manuseio do mesmo.

Quando eu consegui compreender parte do código, eu me liguei que precisava ter uma sessão para fazer a maioria das ações no servidor.

Então vi que conseguiria criar um usuário sem ter sessão usando o /add_user:

...
Parte do código, referente ao /add_user


Então criei uma requisição com o Burpsuite, copiando a requisição do /login (enviei algumas credenciais quaisquer apenas para gerar a requisição):

...
Criando um usuário (id=username, pw=password)


Como é possível ver, deu reposta 302, ou seja, o usuário foi criado!

É só logar!

...
Logado no usuário "wr1t3up"


Em "Imagem", antes de logar era possível ver uma imagem do Pikachu:

...
Imagem do Pikachu


Depois de logado, é possível ver uma outra imagem, uma imagem do "'Pickle' Rick" da animação "Rick and Morty":

...
Imagem do "Pickle" Rick


E isso era uma DICA da vulnerabilidade a ser explorada!

E em "Notas" é possível criar uma nota:

...
Página do "Notas"
"Notas" page


Porém, para acessar uma nota, era necessário estar logado como ADMIN:

...
Parte do código, referente ao /note


Logo, não faria sentido criar uma nota com aquele usuário, pois teria que logar como ADMIN para acessar-lá, então era mais prático logar como ADMIN. Para isso, utilizei o /info para obter informação do ADMIN.

No código do /info é possível acessar informações de um usuário passando "?username=usuariodesejado" via GET:

...
Parte do código, referente ao /info


Obtendo, então, informação do usuário ADMIN:

...
Resultado do /info


É possível ver uma hash:

0a65b5cf991cc23229b63fa717373b0bc0475e2fa6710320357c4176eddcdb62

"Quebrando" ela, tem-se: hitmebab1mortym

...
Hash quebrada


Então, agora é só logar como ADMIN!

...
Logado como admin


Acessando "Notas" é possível ver que já tem uma nota cadastrada, usarei ela apenas para entender como acessar as notas (algo bem simples, na verdade).

Segundo o próprio código do /note, só é preciso passar o id da nota no parâmetro "ni":

...
Parte do código, referente ao /note


ID da nota que já está cadastrada:

...
ID da nota pré-cadastrada


Acessando a nota:

...
Acessando a nota


Voltando ao "Notas"...

Agora, é necessário criar uma nota, porém é preciso entender algumas coisas antes:

  • O código está usando um "object serialization": pickle.
  • O pickle é usado para serializar e desserializar uma estrutura de objetos Python, então para explorar o pickle nada melhor que criar um objeto que executa algum comando.
  • Mas antes disso é preciso entender que mandar só o objeto serializado não fará com que o mesmo seja executado pelo servidor, é necessário encodar com base64, já que o código faz decode de base64, para ser executado.
  • E para que a requisição aceite e faça o decode do base64, é necessário adicionar "usebase64" na mesma.

E sobre a exploração do pickle, irei deixar alguns links, no final do write-up, que eu li para entender como explorar a vulnerabilidade.

...
Parte do código, referente ao /write_note


Eu criei um objeto, instanciei ele no dump do pickle e encodei a saída do dump com base64:

...
Explorando o pickle


E enviei a requisição:

...
Enviando a requisição para tentar a exploração


Acessando a nota criada é possível ver um erro 500:

...
Erro 500, servidor possívelmente recusou o uso da biblioteca "os"


Eu pensei que poderia ser que o sistema não aceita o uso da biblioteca "os" e resolvi mudar a biblioteca para outra que tem o mesmo papel - "commands":

...
Alterando a biblioteca usada


Enviando a requisição...

...
Enviando a requisição do base64 com a biblioteca alterada


E deu certo!

...
Resposta do servidor ao comando requerido (id)


A partir daí só foi necessário listar os diretórios e ir procurando a flag, que estava em "files/e7e7a4697554b5ae/flag".

E era só dar um cat nela!

...
Cat na flag


...
Enviando a requisição do cat


...
Flag!


Bom, é isso galera.

Qualquer dúvida, crítica ou elogio ao write-up, fiquem à vontade para fazer!!


Links sobre a exploração do pickle:

Exploiting misuse of Python's "pickle"

Explaining and exploiting deserialization vulnerability with Python (EN)

Rotten pickles: A quick introduction to offensive serialization techniques