Introdução:

A segurança de infraestrutura fortalece as aplicações contra ataques, criando camadas que dificultam a exploração por agentes mal-intencionados. No entanto, essas medidas, por si só, não eliminam completamente as ameaças, pois atacantes determinados ainda podem explorar vulnerabilidades no código fonte. Em uma análise recente que fiz conduzida pela FikreSekhel, detectamos uma brecha que revela a importância da segurança de código, mostrando como uma vulnerabilidade de escrita de arquivos em uma aplicação Node.js poderia ser transformada em execução remota de código – mesmo em um ambiente com sistema de arquivos somente leitura.

Vulnerabilidades de Escrita de Arquivo Arbitrária

Durante nossa pesquisa, frequentemente nos deparamos com vulnerabilidades como Cross-Site Scripting (XSS), Injeção SQL, Desserialização Insegura e Server-Side Request Forgery (SSRF). Entre elas, vulnerabilidades de Escrita de Arquivo Arbitrária se destacam por permitir que um atacante comprometa uma aplicação completamente, uma vez identificadas.

Exemplo de Código Vulnerável:

Abaixo está um trecho de código encontrado em uma aplicação de um cliente, que utiliza Node.js:

app.post('/upload', (req, res) => {
   const { filename, content } = req.body;
   fs.writeFile(filename, content, () => {
       res.json({ message: 'Arquivo carregado com sucesso!' });
   });
});

Nesse exemplo, os parâmetros filename e content são totalmente controláveis pelo usuário, permitindo que atacantes utilizem a função fs.writeFile para escrever arquivos arbitrários. A vulnerabilidade em questão é um ponto crítico para execução remota de código, mesmo em um sistema com restrições severas.

Escrita de Arquivos em Ambientes Endurecidos

Durante a análise do APP de um cliente, encontramos uma vulnerabilidade de Escrita de Arquivo Arbitrária em um sistema onde a maioria do sistema de arquivos estava montado como somente leitura, restringindo o acesso de escrita a uma pasta de uploads. No entanto, exploramos a questão: É possível transformar uma vulnerabilidade de Escrita de Arquivo Arbitrária em execução de código mesmo em um sistema com acesso de escrita restrito?

Técnica Utilizada: Aproveitamento de Descritores de Arquivo Abertos

Em sistemas baseados em Unix, como Linux, o conceito de “tudo é um arquivo” abre superfícies de ataque incomuns. Exploramos o sistema virtual procfs, que permite acesso a descritores de arquivos abertos, incluindo pipes anônimos utilizados por bibliotecas como o libuv no Node.js.

Um exemplo de como listar descritores de arquivos abertos:

user@host:~$ ls -al /proc/`pidof node`/fd

Ao explorar descritores abertos, conseguimos alimentar o manipulador de eventos da aplicação com dados maliciosos e, assim, pavimentar o caminho para a execução de código.

Pipes no Node.js e o Manipulador de Eventos

O Node.js utiliza o libuv para gerenciar um loop de eventos assíncrono, onde pipes anônimos comunicam e sinalizam eventos. Em nosso teste, observamos que, ao escrever dados em pipes através de uma vulnerabilidade de escrita, podemos manipular um manipulador de eventos sensível e provocar a execução de um ponteiro de função.

Estrutura de Dados Manipulada

A estrutura que o manipulador de eventos espera é semelhante a esta:

struct uv_signal_s {
  UV_HANDLE_FIELDS
  uv_signal_cb signal_cb;  // Ponteiro de função que pode ser manipulado
  int signum;
};

Através da escrita controlada, conseguimos direcionar o signal_cb para um endereço arbitrário, permitindo a execução de comandos específicos.

Explorando com Correntes ROP (Return-Oriented Programming)

Como parte do processo, identificamos e utilizamos gadgets ROP dentro do segmento Node.js, o que nos permitiu contornar restrições de leitura e escrita. Ao construir uma sequência ROP em memória, executamos uma instrução controlada pelo atacante, como system(“touch /tmp/pwned”), comprovando a viabilidade do ataque.

Exemplo de Exploração com Corrente ROP

Utilizando o seguinte gadget, conseguimos obter execução remota de código:

0x4354ca1 -> 0x12d0000: pop rsi; pop r15; pop rbp; ret

Esse gadget, combinado com uma estrutura uv_signal_s falsa, demonstrou o potencial de invasão em um sistema supostamente protegido.

Nossa análise reafirmou que, embora hardening de infraestrutura agreguem segurança, eles não substituem uma base de código segura. Um código seguro e limpo, com vulnerabilidades resolvidas na sua origem, é essencial para evitar que atacantes explorem brechas, especialmente em sistemas críticos.

Na FikreSekhel, focamos na proteção contra essas e outras ameaças. Nosso processo de análise de código e infraestrutura não só identifica vulnerabilidades, mas também implementa controles robustos para mitigar ataques complexos.

Leave a Reply

Your email address will not be published. Required fields are marked *