Top Qs
Linha do tempo
Chat
Contexto

Shellcode

Da Wikipédia, a enciclopédia livre

Remove ads
 Nota: Para código escrito na linguagem de comando de um shell, veja Shell script.

Shellcode é código executável destinado a ser usado como uma carga útil para explorar uma vulnerabilidade de software. O termo inclui shell (em inglês, "casca" ou "interpretador de comandos") porque o ataque originalmente descrito abria um interpretador de comandos que o atacante poderia usar para controlar a máquina alvo, mas qualquer código injetado para obter acesso que de outra forma não é permitido pode ser chamado de shellcode. Por este motivo, alguns consideram o nome shellcode impreciso.[1]

Um ataque geralmente injeta dados que consistem em código executável em um processo antes ou enquanto explora uma vulnerabilidade para obter o controle. O contador de programa é definido para o ponto de entrada [en] do shellcode para que o shellcode seja executado. A implantação de shellcode é frequentemente realizada incluindo o código em um arquivo que um processo vulnerável baixa e, em seguida, carrega em sua memória.

O senso comum dita que, para máxima eficácia, uma carga útil de shellcode deve ser pequena.[2] Código de máquina fornece a flexibilidade necessária para atingir o objetivo. Autores de shellcode aproveitam pequenos opcodes para criar shellcode compacto.[3][4]

Remove ads

Tipos

Resumir
Perspectiva
Local

Um ataque de shellcode local permite que um atacante obtenha privilégios de acesso elevados em seu próprio computador. Em alguns casos, a exploração de uma vulnerabilidade pode ser alcançada causando um erro como estouro de buffer. Se bem-sucedido, o shellcode permite o acesso à máquina por meio dos privilégios elevados concedidos ao processo alvo.

Remoto

Um ataque de shellcode remoto visa um processo em execução em uma máquina remota na mesma rede de área local, intranet ou na Internet. Se bem-sucedido, o shellcode fornece acesso à máquina alvo através da rede. O shellcode normalmente abre uma conexão de soquete, do tipo stream, TCP/IP para permitir o acesso a um shell na máquina alvo. 

Um ataque de shellcode remoto pode ser categorizado pelo seu comportamento. Se o shellcode estabelece a conexão, ele é chamado de shell reverso (reverse shell), ou shellcode de conexão de volta (connect-back). Por outro lado, se o atacante estabelece a conexão, o shellcode é chamado de shell de ligação (bindshell) porque o shellcode se liga a uma determinada porta na máquina da vítima. Um bindshell de porta aleatória (bindshell random port) ignora a parte de ligação e escuta em uma porta aleatória.[a] Um shellcode de reutilização de soquete (socket-reuse) é uma exploração (exploit) que estabelece uma conexão com o processo vulnerável que não é fechada antes que o shellcode seja executado, para que o shellcode possa reutilizar a conexão para permitir o acesso remoto. O shellcode de reutilização de soquete é mais elaborado, pois ele precisa descobrir qual conexão reutilizar e a máquina pode ter muitas conexões abertas.[5]

Um firewall pode detectar conexões de saída feitas por shellcode de conexão de volta, bem como conexões de entrada feitas por shell de ligação e, portanto, oferece alguma proteção contra um ataque. Mesmo que o sistema seja vulnerável, um firewall pode impedir que o atacante se conecte ao shell criado pelo shellcode. Uma das razões pelas quais o shellcode de reutilização de soquete é usado é que ele não cria novas conexões e, portanto, é mais difícil de detectar e bloquear.

Download e execução

Um ataque de shellcode de download e execução baixa e executa malware no sistema alvo. Este tipo de shellcode não gera um shell, mas sim instrui a máquina a baixar um determinado arquivo executável da rede e executá-lo. Hoje em dia, é comumente usado em ataques de drive-by download, onde uma vítima visita uma página web maliciosa que, por sua vez, tenta executar tal shellcode de download e execução para instalar software na máquina da vítima. 

Uma variação deste ataque baixa e carrega [en] uma biblioteca.[6][7] As vantagens desta técnica são que o código pode ser menor, que não requer que o shellcode gere um novo processo no sistema alvo e que o shellcode não precisa de código para limpar o processo alvo, pois isso pode ser feito pela biblioteca carregada no processo.

Em estágios (Staged)

Quando a quantidade de dados que um atacante pode injetar no processo alvo é muito limitada para alcançar o efeito desejado, pode ser possível implantar o shellcode em estágios que progressivamente fornecem mais acesso. O primeiro estágio pode fazer nada mais do que baixar o segundo estágio que então fornece o acesso desejado.

Caça-ao-ovo (Egg-hunt)

Um ataque de shellcode de caça-ao-ovo (egg-hunt) é um ataque em estágios no qual o atacante pode injetar shellcode em um processo, mas não sabe onde ele está dentro do processo. Um shellcode de segundo estágio, geralmente menor que o primeiro, é injetado no processo para procurar o primeiro shellcode (o ovo ou egg) no espaço de endereçamento do processo e o executa.[8]

Omelete

Um ataque de shellcode omelete (omelet), semelhante ao de caça-ao-ovo, procura vários pequenos blocos de dados (ovos ou eggs) e os combina em um bloco maior (omelete ou omelet) que é então executado. Isso é usado quando um atacante é limitado no tamanho do código injetado, mas pode injetar vários blocos.[9]

Remove ads

Codificação

Resumir
Perspectiva

O Shellcode é frequentemente escrito para contornar as restrições sobre os dados que um processo irá permitir. As técnicas gerais incluem:

Otimizar para tamanho

Otimizar o código para diminuir seu tamanho.

Código automodificável

Modificar seu próprio código [en] antes de executá-lo para usar valores de byte que são de outra forma restritos.

Criptografia

Para evitar detecção de intrusão, codificar como autodecriptação ou polimórfico [en].

Codificação de caracteres

Um ataque que visa um navegador pode ofuscar o shellcode em uma string JavaScript usando uma codificação de caracteres expandida.[10] Por exemplo, na arquitetura IA-32, aqui estão duas instruções de não-operação (no-operation, NOP) não codificadas (usadas em um NOP slide [en]):

90             NOP
90             NOP

Codificado como:

Livre de nulo (Null-free)

O shellcode deve ser escrito sem bytes de valor zero quando se destina a ser injetado em uma {pill|en||string terminada em nulo|null-terminated string}} que é copiada no processo alvo através do algoritmo usual (ou seja, strcpy [en]) de encerrar a cópia no primeiro byte zero chamado de caractere nulo em conjuntos de caracteres comuns. Se o shellcode contivesse um nulo, a cópia seria truncada e não funcionaria corretamente. Para produzir código livre de nulo a partir de código que contém nulos, pode-se substituir instruções de máquina que contêm zeros por instruções que não contêm. Por exemplo, na arquitetura IA-32 a instrução para definir o registrador EAX para 1 contém zeros como parte do literal (1 expande para 0x00000001).

B8 01000000    MOV [en] EAX,1

As seguintes instruções realizam o mesmo objetivo (EAX contendo 1) sem bytes zero embutidos, primeiro definindo EAX para 0 e depois incrementando EAX para 1:

33C0           XOR [en] EAX,EAX
40             INC [en] EAX
Texto

Um shellcode alfanumérico consiste apenas em caracteres alfanuméricos (0–9, A–Z e a–z).[11][12] Este tipo de codificação foi criado por hackers para ofuscar o código de máquina dentro do que parece ser texto simples. Isso pode ser útil para evitar a detecção do código; para permitir que o código passe por filtros que removem caracteres não alfanuméricos de strings.[b]. Um tipo de codificação semelhante é chamado de código imprimível (printable code) e usa todos os caracteres imprimíveis (alfanuméricos mais símbolos como !@#%^&*). Uma variante semelhante e restrita é o código ECHOável que não contém nenhum caractere que não seja aceito pelo comando ECHO. Foi demonstrado que é possível criar shellcode que se parece com texto normal em inglês.[13] Escrever tal shellcode requer uma compreensão aprofundada da arquitetura do conjunto de instruções [en] das máquinas alvo. Foi demonstrado que é possível escrever código alfanumérico que é executável em mais de uma máquina,[14] constituindo, assim, código executável multi-arquitetura.

Uma solução alternativa (work-around) foi publicada por Rix na Phrack [en] 57[11] no qual ele mostra que é possível transformar qualquer código em código alfanumérico. Frequentemente, o código automodificável é aproveitado porque permite que o código tenha valores de byte que de outra forma não são permitidos, substituindo valores codificados em tempo de execução. Um decodificador automodificável pode ser criado que inicialmente usa apenas bytes permitidos. O código principal do shellcode é codificado, também usando apenas bytes no intervalo permitido. Quando o shellcode de saída é executado, o decodificador modifica seu código para usar as instruções que ele requer e, em seguida, decodifica o shellcode original. Após decodificar o shellcode, o decodificador transfere o controle para ele. Foi demonstrado que é possível criar shellcode arbitrariamente complexo que se parece com texto normal em inglês.[13]

O software moderno usa Unicode para suportar internacionalização e localização. Frequentemente, o texto de entrada ASCII é convertido para Unicode antes do processamento. Quando um caractere ASCII (geralmente Latin-1) é transformado em UTF-16 (Unicode de 16 bits), um byte zero é inserido após cada byte (caractere) do texto original. Obscou provou na {{ill|en|Phrack|Phrack}[ 61[12] que é possível escrever shellcode que pode ser executado com sucesso após esta transformação. Existem programas que podem codificar automaticamente qualquer shellcode em shellcode UTF-16 alfanumérico à prova, baseado no mesmo princípio de um pequeno decodificador auto-modificável que decodifica o shellcode original.

Remove ads

Compatibilidade

Geralmente, o shellcode é implantado como código de máquina, pois proporciona acesso relativamente desprotegido ao processo alvo. Como o código de máquina é compatível dentro de um contexto de computação relativamente estreito (processador, sistema operacional e assim por diante), um fragmento de shellcode tem compatibilidade [en] limitada. Além disso, como um ataque de shellcode tende a funcionar melhor quando o código é pequeno e atingir múltiplas explorações (exploits) aumenta o tamanho, tipicamente o código visa apenas uma exploração. No entanto, um único fragmento de shellcode pode funcionar para múltiplos contextos  e explorações.[15][16][17] A versatilidade pode ser alcançada criando um único fragmento que contenha uma implementação para múltiplos contextos. O código comum ramifica para a implementação para o contexto de tempo de execução.

Análise

Resumir
Perspectiva

Como o shellcode geralmente não é executável por conta própria, para estudar o que ele faz, ele é tipicamente carregado em um processo especial. Uma técnica comum é escrever um pequeno programa em C que contém o shellcode como dados (ou seja, em um buffer de bytes) e transfere o controle para as instruções codificadas nos dados (através de um ponteiro de função [en] ou código assembly em linha). Outra técnica é usar uma ferramenta online, como shellcode_2_exe, para incorporar o shellcode em uma carcaça executável pré-fabricada que pode então ser analisada em um depurador padrão. Ferramentas especializadas de análise de shellcode também existem, como o projeto sclog da iDefense (originalmente lançado em 2005 no Malcode Analyst Pack). O sclog é projetado para carregar arquivos de shellcode externos e executá-los dentro de uma estrutura de registro (logging) de API. Também existem ferramentas de análise de shellcode baseadas em emulação, como a aplicação sctest que faz parte do pacote libemu de plataforma cruzada. Outra ferramenta de análise de shellcode baseada em emulação, construída em torno da biblioteca libemu, é o scdbg que inclui um shell de depuração básico e recursos de relatório integrados.

Remove ads

Ver também

  • Estouro de buffer de pilha [en]
  • Estouro de heap — tipo de estouro de buffer
  • Projeto Metasploit — ferramenta de teste de segurança de computador
  • Segurança de computadores — a proteção de sistemas e redes de computadores contra roubo, danos, uso indevido ou vazamento de dados
  • Shell shoveling — redirecionar a entrada e a saída de um shell para um serviço, permitindo o acesso remoto

Notas

  1. O bindshell random port é o menor shellcode bindshell estável para x86_64 disponível até hoje.
  2. em parte, tais filtros foram uma resposta a exploits de shellcode não alfanuméricos

Referências

Loading related searches...

Wikiwand - on

Seamless Wikipedia browsing. On steroids.

Remove ads