close

Shellcode

Ir para a navegação Ir para a pesquisa

Na ciência da computação, um shellcode é um programa em linguagem assembly que tradicionalmente executa um shell , como o shell Unix '/bin/sh' ou o shell command.com nos sistemas operacionais DOS e Microsoft Windows . Um shellcode pode ser usado para explorar um bug por meio de um exploit , permitindo que um hacker ou cracker tenha acesso à linha de comando de um computador ou, mais geralmente, para executar código .arbitrário.

Descrição

Tipos de Shellcode

Existem dois tipos diferentes de shellcode, local e remoto. A distinção depende do tipo de controle que a execução do shellcode fornece na máquina de destino, que pode ser local ou remota (se ocorrer pela rede).

Locais

Um shellcode local é usado por um invasor que tem acesso limitado à máquina, mas que explorando uma vulnerabilidade em um processo com privilégios mais altos, por exemplo, um estouro de buffer, pode obter os mesmos privilégios se a execução do shellcode for bem-sucedida.

Remoto

O shellcode remoto é usado quando um invasor deseja explorar uma vulnerabilidade de um processo de outra máquina na rede local ou em uma intranet. Se o Shellcode for executado corretamente, ele retornará o controle da máquina de destino pela rede. Os shellcodes remotos normalmente usam o soquete TCP/IP padrão para permitir o acesso ao shell da máquina de destino. Outras distinções podem ser classificadas de acordo com o método pelo qual a conexão é estabelecida. Se é o próprio shellcode que pode estabelecer a conexão, isso é chamado de "shell reverso" ou shellcode connect-back , porque o shellcode executado na máquina remota se conecta à máquina do invasor. Se, por outro lado, o invasor precisar criar a conexão, o shellcode é chamado de bindshell , pois o shellcode se vincula a uma determinada porta, que será usada pelo invasor para conectar e controlar a máquina de destino. Um terceiro tipo de shellcode menos comum é o shellcode de reutilização de soquete . Esse tipo de shellcode geralmente é usado quando uma exploração estabelece uma conexão com o processo vulnerável que não é fechada antes que o shellcode seja executado. O shellcode pode reutilizar essa conexão para se comunicar com o invasor. O shellcode de reutilização de Socket é mais complexo de implementar, pois o shellcode deve identificar qual conexão ele pode usar (entre as possíveis abertas na máquina). [1] Um firewall pode ser usado para identificar conexões de saída feitas por um shellcode connect-back e uma tentativa de conexão de entrada de um bindshell. O firewall pode fornecer proteção adicional contra um invasor, mesmo que o sistema seja vulnerável, prevenindo preventivamente o acesso ao shell criado pela execução do shellcode. Esta é uma das razões pelas quais um shellcode reutilizável de soquete às vezes é usado, porque não criar novas conexões é mais difícil de identificar e bloquear.

Baixe e execute

Download and execute é um tipo de shellcode remoto que executa um download e executa algum tipo de malware no sistema de destino. Esse tipo de shellcode não cria um shell, mas instrui a máquina a baixar um determinado arquivo executável da rede, salvá-lo em disco e executá-lo. Hoje em dia, é comumente usado em ataques de download drive-by , quando uma vítima visita um site malicioso que tenta iniciar um download e executar um shellcode para instalar o software na máquina da vítima. Uma variação desse tipo de shellcode é "baixar e carregar uma biblioteca". [2] [3] As vantagens desta técnica são que o código shellcode pode ser menor, não requer a criação de um novo processo na máquina alvo, e que o shellcode não precisa implementar o código para limpar o alvo. process , mas isso pode ser feito a partir de uma biblioteca carregada no processo.

Encenado

Quando a quantidade de dados que um invasor pode injetar em um processo de destino é muito pequena para que o shellcode seja executado corretamente, ele pode ser executado em etapas. Primeiro, um pequeno pedaço de shellcode (estágio 1) é executado. Esse código despeja um pedaço maior do shellcode (fase 2) na memória do processo e o executa.

Caça aos ovos

A caça ao ovo é outro tipo de shellcode em fases. Ele é usado quando um invasor tem a capacidade de inserir um shellcode grande em um processo, mas não pode determinar onde ele será colocado na memória. Em seguida, uma pequena caça ao ovo é inserida no processo em um local previsível e então executada. O código procura no espaço de memória um shellcode maior (o ovo) e o executa.

Omelete

Este tipo de shellcode é semelhante ao egg-hunt, mas procura por blocos menores (ovos) e os recombina em um maior (omelete) que é então executado. Essa técnica é usada quando um invasor está limitado, por algum motivo, a inserir pequenos blocos de dados no processo. [4]

Operação

Estratégia de Execução de Shellcode

Uma exploração geralmente insere um shellcode no processo de destino antes ou ao mesmo tempo em que ocorre uma exploração de vulnerabilidade, para obter controle sobre o contador do programa . O contador de programa é direcionado para apontar para o shellcode a ser executado. A injeção do shellcode geralmente é feita armazenando o código nos dados enviados pela rede para o processo vulnerável, disponibilizando-o em um arquivo que é lido pelo processo ou através da linha de comando ou variáveis ​​de ambiente no caso de exploits locais.

Codificação de shellcode

Como muitos processos filtram ou limitam os dados que podem ser inseridos, muitas vezes o shellcode deve ser escrito para superar essas restrições, tornando o código pequeno, livre de caracteres nulos ou alfanuméricos. Várias soluções foram encontradas para contornar essas restrições:

  • Otimizações de design e implementação para reduzir o tamanho do shellcode.
  • Mudanças de implementação para contornar limitações no intervalo de bytes usados ​​no shellcode.
  • Código automodificável que modifica o número de bytes de seu código antes de executá-los, para recriar bytes que normalmente não podem ser inseridos no processo.

Como as ferramentas de detecção de intrusão podem identificar a assinatura de shellcodes simples enviados pela rede, eles são codificados e autodescriptografados ou polimórficos para evitar serem reconhecidos.

Codificação percentual

As explorações direcionadas a navegadores geralmente codificam shellcode em uma string JavaScript usando notação de codificação de porcentagem ou codificação de URL, escapando "\ uXXXX" ou usando entity . Algumas explorações ofuscam ainda mais o shellcode codificado em string para evitar serem detectados pelas ferramentas do IDS . Por exemplo, em uma arquitetura IA-32 , duas instruções (sem operação) NOPtêm este formato antes de serem codificadas.

90 NOP
90 NOP

Eles são codificados em uma string com codificação percentual. (usando o método unescape() para decodificação)

unscape ("% u9090");

É então codificado na notação "\ uXXXX":

"\u9090";

E finalmente na codificação da entidade.

"& # x9090;"

ou

"& # 37008;"

Shellcode Null-Free

Muitos shellcodes são escritos sem usar bytes nulos , porque eles são projetados para serem inseridos no processo de destino por meio de uma string terminada em nulo. Quando uma string terminada em nulo é copiada, a cópia incluirá o primeiro caractere nulo , mas os bytes seguintes não serão processados. Quando o shellcode que contém o nulo é inserido dessa maneira, apenas uma parte do shellcode será inserida, impossibilitando a execução posterior. Para produzir um shellcode sem nulo começando com um que contém bytes nulos, as instruções de máquina que contêm zeros podem ser substituídas por instruções que produzem o mesmo efeito, mas não têm bytes nulos. Por exemplo, em uma arquitetura IA-32 , essa substituição pode ser realizada:

B8 01000000     MOV EAX, 1 // Configura o registro EAX para 0x000000001

esta instrução contém zeros como parte do literal (1 é expandido como 0x000000001) com estas instruções:

33C0            XOR EAX, EAX // Configura o registro EAX para 0x000000000
40              INC EAX // Aumenta o valor EAX para 0x00000001

que têm o mesmo efeito, mas requerem menos bytes para codificação e são livres de bytes nulos.

Shellcodes alfanuméricos e imprimíveis

Sob certas circunstâncias, um processo de destino pode filtrar todos os bytes do shellcode inserido que não são imprimíveis ou alfanuméricos. Sob essas condições, a gama de instruções que podem ser usadas para escrever um shellcode se torna muito limitada. Uma solução para este problema foi publicada por Rix no Phrack 57 [5] onde é mostrado como é possível converter qualquer tipo de código em um alfanumérico. Uma técnica amplamente utilizada é a criação de código automodificável, pois isso permite que o código modifique seus próprios bytes para incluir outros que não estão incluídos entre os permitidos e expandir o intervalo de instruções utilizáveis. Com esse tipo de truque, um decodificador auto-modificável pode ser criado inicialmente usando apenas bytes dentro do intervalo permitido. Quando o shellcode de saída entra em execução, o decodificador pode modificar seu código para poder usar qualquer instrução necessária para permitir que funcione corretamente e ao mesmo tempo continuar a decodificar o shellcode original. Depois de fazer a decodificação, o decodificador transfere o controle para o shellcode, para que ele funcione normalmente. Foi mostrado como é possível criar shellcodes de complexidade arbitrária que se assemelham ao texto normal em inglês. [6]

Shellcode à prova de caracteres Unicode

Muitos programas modernos usam a codificação de string de formato Unicode para permitir a internalização de texto. Muitas vezes, esses programas convertem as strings ASCII de entrada antes de processá-las. As strings Unicode codificadas em UTF-16 usam dois bytes para decodificar cada caractere (ou quatro bytes para alguns caracteres especiais). Quando uma string ASCII é convertida em UTF-16, um byte zero é inserido após cada byte da string original. Obscu mostrou no Phrack 61 [7] que é possível escrever shellcodes que podem ser executados corretamente mesmo após essa transformação. Existem programas que podem alterar automaticamente cada shellcode em um codificado por UTF-16 e são baseados no mesmo princípio de um decodificador automodificável que decodifica o shellcode original.

Plataformas

Muitos shellcodes são escritos em código de máquina devido ao baixo nível em que a vulnerabilidade se torna explorável. O shellcode geralmente é criado para atacar uma combinação específica de processador, sistema operacional e service pack, que são comumente chamados de plataforma. Para alguns exploits, devido às restrições impostas pelo processo alvo, é necessário criar um shellcode específico. No entanto, nem sempre é possível que um shellocde funcione para vários exploits, service packs, sistemas operacionais e possivelmente processadores. [8] Uma versatilidade pode ser dada criando diferentes versões do shellcode, com base nas várias plataformas a serem atacadas e criando um cabeçalho que identifica a versão correta para a plataforma em uso. Quando executado, o código se comporta de maneira diferente por plataforma e é capaz de executar a versão correta do shellcode.

Notas

  1. ^ BHA, Shellcode / Socket-reuse , em blackhatlibrary.net , 6 de junho de 2013. Recuperado em 7 de junho de 2013 .
  2. SkyLined, Download and LoadLibrary shellcode lançado , em skypher.com , 11 de janeiro de 2010. Recuperado em 19 de janeiro de 2010 (arquivado do original em 23 de janeiro de 2010) .
  3. ^ SkyLined, Download and LoadLibrary shellcode for x86 Windows , em code.google.com , 11 de janeiro de 2010. Recuperado em 19 de janeiro de 2010 .
  4. SkyLined, w32 SEH omelet shellcode , em skypher.com , 16 de março de 2009. Recuperado em 19 de março de 2009 (arquivado do original em 23 de março de 2009) .
  5. ^ Rix, Writing ia32 alphanumeric shellcodes , phrack.org , Phrack, 8 de novembro de 2001. Recuperado em 29 de fevereiro de 2008 .
  6. Joshua Mason, Small, Sam, Monrose, Fabian and MacManus, Greg, English Shellcode ( PDF ), cs.jhu.edu , novembro de 2009. Recuperado em 10 de janeiro de 2010 .
  7. ^ Obscou, Construindo IA32 'Unicode-Proof' Shellcodes , phrack.org , Phrack, 13 de agosto de 2003. Recuperado em 29 de fevereiro de 2008 .
  8. ^ Eugene, Architecture Spanning Shellcode , phrack.org , Phrack, 11 de agosto de 2001. Recuperado em 29 de fevereiro de 2008 .

Itens relacionados

Links externos