Execução Remota de código (RCE), explicado: o que é e como evitá-lo

A Execução Remota de código (RCE) é uma classe de falhas/vulnerabilidades de segurança de software. As vulnerabilidades RCE permitirão que um ator malicioso execute qualquer código de sua escolha em uma máquina remota por LAN, WAN ou internet. O RCE pertence à classe mais ampla de vulnerabilidades de execução arbitrária de código (ACE). Com a internet se tornando onipresente, no entanto, o impacto das vulnerabilidades do RCE cresce rapidamente. Portanto, os RCEs agora são provavelmente o tipo mais importante de vulnerabilidade ACE.

como é o caso, queríamos dar uma olhada mais detalhada nos vários tipos de vulnerabilidades RCE e nas possíveis contramedidas.

classificação RCE por origem

a maioria, senão todas, das vulnerabilidades RCE conhecidas tem um pequeno número de causas subjacentes.

execução dinâmica de código

a execução dinâmica de código tende a ser o vetor de ataque mais comum que leva ao RCE. A maioria das linguagens de programação tem alguma maneira de gerar código com código e executá-lo no local. Este é um conceito muito poderoso que ajuda a resolver muitos problemas complexos. No entanto, um terceiro malicioso pode facilmente abusar dele para obter recursos de RCE.

frequentemente, o código gerado em tempo de execução é baseado em alguma entrada do Usuário. Na maioria das vezes, o código inclui essa entrada de alguma forma. Um ator malicioso, percebendo que a geração de código dinâmico fará uso de uma determinada entrada, poderia fornecer código válido como uma entrada para atacar seu aplicativo. Se as entradas do Usuário não forem examinadas, esse código será executado na máquina de destino.

em termos gerais, a execução dinâmica de código causa duas classes principais de vulnerabilidades RCE: direta e indireta.

Direct

no caso de execução dinâmica direta de código, o ator malicioso está ciente de que sua entrada seria usada na geração de código.

indireto

um caso indireto, novamente, resume-se à geração dinâmica de código, incluindo entradas de usuário. A entrada do usuário, no entanto, passa por uma ou mais camadas. Algumas das camadas podem até transformar essa entrada antes que ela acabe com a geração dinâmica de código. Além disso, a geração de código dinâmico pode ser um efeito colateral e não o uso primário da entrada. Como tal, não é realmente evidente para o usuário que fornece a entrada que a entrada será usada como um bloco de construção em um trecho de código a ser executado em uma máquina remota.

a desserialização

a desserialização é um exemplo muito bom desse cenário. Aparentemente, nenhuma geração dinâmica de código deve acontecer na desserialização. Esse é realmente o caso quando o objeto serializado contém apenas campos de dados de tipos primitivos ou outros objetos desse tipo. As coisas ficam mais complicadas, no entanto, quando métodos/funções de um objeto são serializados. A desserialização geralmente incluirá alguma forma de geração dinâmica de código.

você pode pensar que as linguagens dinâmicas são o único lugar onde a serialização de funções faz sentido. O problema será de escopo limitado então. Mas também é um cenário útil em linguagens estáticas. É um pouco mais difícil de alcançar em uma linguagem estática, mas de longe não é impossível.

muitas vezes, a implementação consiste em objetos/funções proxy gerados por desserialização. Gerar objetos / funções em tempo de execução é um caso de geração dinâmica de código. Portanto, se os dados a serem desserializados se originarem de uma solicitação feita por uma máquina remota, um ator malicioso poderá modificá-los. Trechos de código serializados cuidadosamente criados podem ser injetados que enganam a geração dinâmica de código para executá-los quando invocados como parte da desserialização.

Segurança Da Memória

outra causa de vulnerabilidades RCE tem a ver com a segurança da memória. Segurança da memória significa impedir que o código acesse partes da memória que ele não inicializou ou obteve como entrada. Intuitivamente, você pode esperar que a falta de segurança da memória resulte em acesso não autorizado a dados. No entanto, o sistema operacional e o hardware subjacente usam memória para armazenar o código executável real. Metadados sobre a execução de código também são armazenados na memória. Ter acesso a esse tipo de memória pode resultar em ACE e possivelmente RCE. Então, quais são as principais razões por trás dos problemas de segurança da memória?

falhas de design de Software

falhas de design de Software são um tipo de vulnerabilidade de segurança de memória onde há um erro de design em algum componente subjacente. Na maioria das vezes, isso seria um compilador, intérprete ou máquina virtual, ou potencialmente o kernel ou bibliotecas do sistema operacional. Existem várias falhas diferentes que pertencem a esta classe. Vamos dar uma olhada mais detalhada no que é indiscutivelmente o mais comum.

buffer overflow ou buffer overread

Buffer overflow (também conhecido como buffer overread) é uma técnica bastante simples e conhecida para violar a segurança da memória. Ele explora uma falha de design ou um bug para gravar nas células de memória que seguem o final Real de um buffer de memória. O buffer em si é retornado de uma chamada legítima para a API pública. No entanto, o buffer serve apenas como um ponto de origem para calcular os endereços de memória física de valores de campo/membro privados de algum objeto ou contador de programa. Sua posição relativa ao buffer é bem conhecida ou pode ser adivinhada. Pesquisar o código se disponível ou depurar a execução do programa em tempo de execução pode ajudar um ator malicioso a obter posições relativas.

portanto, um estouro de buffer permite modificar a memória que deve ser inacessível por design. Esse buffer pode residir no espaço de endereço de outra máquina e ser modificado chamando uma API remota. Isso permitirá o acesso à memória remota da máquina. Claramente, existem várias maneiras de usar esse tipo de acesso na instrumentação de um RCE. A suposição geral é que, se uma vulnerabilidade de estouro de buffer existir, um RCE será possível. Portanto, os proprietários de código devem corrigir estouros de buffer o mais rápido possível, bem antes que o ataque RCE real surja.

escopo

na maioria das vezes, o estouro de buffer tem como alvo o código C/C++, uma vez que essas linguagens não possuem verificações de tamanho de buffer integradas. Muitas outras estruturas e tecnologias populares acabam usando bibliotecas C / C++ no fundo da superfície que automaticamente as torna vulneráveis a esse tipo de ataque.

nó.js é um bom exemplo disso, pois, além de ser baseado em C/C++, O tempo de execução do JavaScript também permite complementos nativos de C/C++. Por causa disso, um invasor pode criar cuidadosamente as solicitações para um nó.servidor js para causar estouro de buffer e, assim, modificar a memória do sistema na máquina afetada, causando a execução de código arbitrário.

falhas de design de Hardware

curiosamente, violações de segurança de memória podem ocorrer por causa de falhas de design de segurança de hardware também. Embora menos comuns e difíceis de encontrar, essas vulnerabilidades geralmente têm um impacto extremamente alto.

ataques RCE desviantes

embora o resultado de cada ataque RCE seja o mesmo em termos de um código de execução do atacante, os vetores de ataque são de natureza muito diferente. Bloquear todos eles exige um esforço significativo. Além disso, o esforço cresce junto com a pilha de tecnologia. Todos os vetores de ataque descritos neste post são agnósticos em tecnologia. No entanto, todas as implementações são específicas da tecnologia, assim como os mecanismos de defesa.Portanto, uma abordagem tradicional de economia de tempo é monitorar o tráfego de rede em busca de conteúdo suspeito em vez de monitorar cada ponto de extremidade com sua tecnologia específica. Um firewall de aplicativo da web (WAF) normalmente executa esse trabalho. Embora isso Economize tempo, ele também tem um preço—o WAF é um gargalo de desempenho da rede e carece de todas as informações básicas disponíveis no ponto final real ou nos níveis do aplicativo e do Usuário. Portanto, a análise de tráfego WAF nunca poderia ser perfeita. A heurística é inevitável sem dados completos, portanto, nem todas as ameaças surgirão ou surgirão falsos positivos ou, na maioria das vezes, ambos.

movendo-se dentro do aplicativo: A abordagem do Sqreen

sqreen aborda essas deficiências do WAF sem aumentar o custo de desenvolvimento para o usuário final, movendo a visibilidade dentro do aplicativo, trazendo proteção mais completa com um grosa específico da tecnologia e WAF no aplicativo. O RASP e o WAF do Sqreen são executados dentro do aplicativo da web real, da API ou do tráfego de rede de recebimento de microsserviços. No entanto, não requer nenhuma modificação de código. Ele usa pontos de instrumentação específicos para cada tecnologia (por exemplo, API JVM para Java, API v8 para Node.js, etc.) para modificar o código antes da execução em tempo de execução. Assim, é capaz de monitorar e modificar eventos do sistema e da rede, tendo o contexto completo de tudo o que acontece dentro do aplicativo.

assim, Sqreen pode detectar que o aplicativo está usando componentes com problemas de segurança de memória conhecidos. Ele também pode detectar as entradas reais do usuário que chegam aos eventos dinâmicos de execução de código. Naturalmente, esta é uma abordagem superior para detectar e prevenir RCEs em comparação com um WAF tradicional que tem acesso apenas ao tráfego de rede.

concluindo

claramente, o RCE é um vetor de ataque muito potente. Mas, felizmente, também é possível se defender contra ataques RCE. As informações acima podem realmente ajudar na construção de sua estratégia de defesa. Se você estiver interessado em outros vetores de ataque e detalhes, confira nossas postagens anteriores sobre SQL injection, XXE e LFI.

Leave a Reply