Prévia do material em texto
Disciplina Análise de Malware Apresentação Olá alunos, sejam muito bem-vindos na disciplina de análise de malware. Será um prazer percorrer essa jornada com vocês e tenho certeza que será um tempo de muito aprendizado. Saiba que este material foi preparado com muito cuidado para que essa jornada possa ser a mais tranquila possível. Este curso não visa torná-lo um analista, pois sabemos que, para isso, seriam necessários anos de aperfeiçoamento e dedicação. Nossa pretensão é dar uma visão geral e desmistificar nesta grande área da Segurança Cibernética. Essa disciplina, permeia outras grandes ciências e possui diversos requisitos necessários. Não será uma jornada simples, mas estaremos ao seu lado para poder conduzir da melhor forma. Ao final, você será capaz de saber analisar e identificar os tipos de ameaças dos códigos e dos programas maliciosos que impactam na segurança dos sistemas computacionais. Objetivos • Identificar os tipos de ameaças dos códigos e dos programas maliciosos que impactam na segurança dos sistemas computacionais; • Analisar o comportamento dos malwares e conhecer as implicações nos sistemas onde eles residam; • Conhecer as principais técnicas utilizadas para a análise de malwares. Aula 1: Conceitos de Malware Apresentação Nesta primeira aula desmistificaremos o conceito de malwares, assunto que normalmente é tratado com certo medo. Toda linha de código criada com um intuito malicioso pode ser considerado como um malware, portanto saber identificar suas intenções e seu alcance é vital para o analista. Definiremos, também, os principais tipos categorizados e, por fim, faremos uma visão geral da análise estática e dinâmica. Objetivo • Descrever conceitos básicos sobre análise de malware; • Identificar diferenças entre os tipos de malwares existentes; • Distinguir a diferença entre análise dinâmica e estática. Introdução Este conteúdo não visa torná-lo um analista, pois sabemos que, para isso, seriam necessários anos de aperfeiçoamento e dedicação. Nossa pretensão é dar uma visão geral e desmistificar esta área da Segurança Cibernética, que permeia outras grandes áreas e possui diversos requisitos necessários. Ao final, você será capaz de analisar e identificar os tipos de ameaças dos códigos e dos programas maliciosos que impactam na segurança dos sistemas computacionais. Fonte: Adaptado de Freepik Malware: Ameaças Cibernéticas A Internet mudou completamente a indústria de computadores e dos aspectos relacionados à segurança da computação. Softwares maliciosos se espalham rapidamente em um mundo onde bilhões de usuários estão conectados à Internet e usam e-mail, trocam mensagens instantâneas e compartilham dados diariamente. Basta imaginar que, há alguns anos, um malware necessitava de um disquete para ser carregado em outro computador para se propagar, com isso podemos entender o porquê de uma infecção demorar semanas ou meses para atingir milhares de máquinas. O processo de infecção era bastante lento e a defesa muito mais simples, pois os canais de infecção eram poucos e exigiam intervenção humana para que o programa se propagasse. No entanto, hoje isso mudou muito, a Internet criou uma conexão virtual entre quase todos os computadores do planeta. Atualmente, os malwares modernos podem se espalhar automaticamente para milhões de computadores sem qualquer intervenção humana. Fonte: Adaptado de Unsplash E é neste contexto que o analista atua, mas antes de entrarmos nos detalhes de como analisar malwares e resolver todos estes problemas, faz-se necessário definir algumas terminologias, categorizar os tipos mais comuns existentes e, por fim, apresentar as metodologias e formas de abordagem fundamental para sua análise. Um aspecto fundamental de uma boa análise é definir qual o objetivo a ser alcançado. Vamos desenhar um caso genérico: Exemplo João Wannacry é analista de malware da empresa Vulnerável S.A. Houve um grande vazamento de dados e diversas informações que deveriam ser acessadas apenas por algumas pessoas, tornou-se público. O chefe convoca uma reunião cobrando por respostas. João utiliza a solução de antivírus da empresa que localiza algumas máquinas contaminadas. Com isso, ele deleta os arquivos infectados, cria uma assinatura do malware no sistema de detecção de invasões, para realizar bloqueios automáticos em caso de reuso do mesmo e, por fim, faz algumas atualizações de segurança em possíveis sistemas vulneráveis. Será que esses procedimentos serão suficientes para prevenir um futuro vazamento? Dado o cenário proposto, vamos fazer algumas ponderações. De modo geral, a equipe de segurança deve fornecer os indícios para que a empresa possa entender e identificar o porquê, quando e onde de uma possível ocorrência de uma invasão. 1 Por que Qual a motivação do atacante para acessar os computadores da empresa? 2 Quando A quanto tempo os atacantes estão dentro da empresa? Qual foi a primeira invasão? 3 Onde Quais máquinas e que usuários foram comprometidos? A que tipo de informação os atacantes podem ter tido acesso? A partir das respostas será possível um melhor entendimento quanto à identificação da porta de entrada e à mitigação do ataque a fim de que ele não ocorra novamente. Para que esse objetivo seja alcançado, é necessário determinar exatamente o que aconteceu e garantir que foram localizadas todas as máquinas e arquivos afetados. Prosseguindo com o exemplo: Exemplo A equipe de segurança da rede fez uma análise sumária e encontrou alguns arquivos suspeitos. Vamos chamá-los de artefatos, pois ainda não sabemos se tais arquivos são maliciosos ou não. Ao analisar os artefatos suspeitos, seu objetivo será determinar: O que ele pode fazer Seja criar conexões, seja armazenar todas as teclas digitadas, seja criptografar os dados, dentre outros;. Como detectá-lo em na rede Gerar assinatura para futuras detecções e rápida mitigação. Como medir e conter seus danos Entender todas as ações desencadeadas pelo artefato, gerando um mapeamento de todos os danos gerados. Conceitos Agora que você já se familiarizou com o nível e o tipo de cobrança de um analista, é importante diferenciar alguns conceitos que normalmente causam confusão em seu uso. Vamos diferenciar malware, vulnerabilidade e exploit. Malware Tivemos o cuidado de utilizar a palavra “malware” em vez do que popularmente chamamos vírus, pois, como veremos mais a frente, o vírus é apenas um dos tipos de malware. Fonte: Adaptado do Autor. A palavra “malware” vem da junção de duas palavras em inglês – malicious (malicioso) + software (aplicação), ou seja, considera-se um malware qualquer pedaço de algo que faça ações maliciosas que venham prejudicar o usuário, o computador ou a rede. Embora o malware apareça de muitas formas diferentes, técnicas comuns são usadas para sua análise. A escolha da técnica a ser empregada dependerá de seus objetivos. Existem diversos tipos de malware, conforme abordaremos mais à frente. Cada malware possui aspectos únicos, assim como um programa legítimo. Por exemplo, existem diversos tipos de editores de texto, mas cada um possui opções e recursos diferentes que os tornam únicos. Essa analogia também se aplica aos artefatos maliciosos. No caso hipotético apresentado anteriormente, João Wannacry criou uma assinatura dentro do sistema de detecção de invasão (IDS), o que isso significa? Existem dois tipos de assinaturas ou indicadores: Assinaturas baseadas em ativos ou host São usados para detectar código malicioso em computadores de vítimas. Esses indicadores costumam identificar arquivos criados ou modificados pelo malware e/ou alterações específicas que ele realiza no registro. Basicamente, os indicadores de malware focam no que o malware faz a um sistema e não nas características do malware em si. Dessa forma, torna-se mais eficaz a detecçãode malware que tente mudar de forma mesmo após ter sido excluído do disco rígido. Assinaturas de rede São usadas para detectar códigos maliciosos por meio do monitoramento do tráfego da rede. As assinaturas de rede podem ser criadas sem análise de malware, mas assinaturas criadas com a ajuda de análise de malware são geralmente muito mais eficazes, pois oferecem uma taxa de detecção mais alta e menos falsos positivos. Trata-se da verificação de domínios requisitados pelo malware, tentativas de conexões ou downloads por ele realizadas e o futuro bloqueio de qualquer tráfego de/para esses destinos. Depois de obter as assinaturas, o objetivo final é descobrir exatamente como o malware funciona. Frequentemente, essa é a pergunta mais feita pelos chefes que desejam uma explicação completa e rica em detalhes de uma invasão. Fonte: madartzgraphics / Pixabay. https://stecine.azureedge.net/webaula/estacio/go0682/aula1.html#collapse01-01 https://stecine.azureedge.net/webaula/estacio/go0682/aula1.html#collapse01-02 Vulnerabilidade Vulnerabilidade é uma falha no sistema que permite a um atacante usá-lo de uma forma não prevista pelo projetista (ANLEY, 2007). Portanto, é por meio da vulnerabilidade que se obtém a possibilidade de uso indevido de um sistema. De modo geral, existem três causas que podem ser consideradas como causas básicas, a saber: • Falhas de design do projeto Quando da concepção de funcionamento de determinado sistema ou aplicação ; (Rev. MC) acertar alinhamento dos itens 1, 2 e 3. • Erros de implementação Uso de funções ou códigos vulneráveis e que possam causar um fluxo diferentemente do planejado • Erros de configuração ou de infraestrutura do sistema Sistemas que possuam baixo nível de controle ou falta de uso de controles de segurança. Exploit O conjunto de códigos e/ou passos necessários para explorar uma vulnerabilidade é conhecido como exploit, (ANLEY, 2007). O expoit é possível apenas quando existe uma vulnerabilidade, porém ressalta- se que podem existir vulnerabilidades para as quais não exista um exploit. Fonte: Adaptado de Freepik. Tipos de malwares Durante uma análise de malware, é possível acelerar alguns processos se for com que tipo de malware estamos lidando. Com isso, são feitas suposições fundamentadas sobre as atividades dele, o que facilita a análise. Esse tipo de experiência é adquirido ao longo do tempo; você será capaz de fazer suposições cada vez melhores a partir da identificação do tipo de malware, facilitando associações e validações. Saiba mais Veja a lista com tipos de categorias em que a maioria dos malwares se enquadra, conforme Sikorski (2012). Os malwares geralmente abrangem várias categorias. Por exemplo, um programa pode ter um keylogger que coleta as senhas e possuir um componente worm que envia spam. Não se preocupe em classificar malware de acordo com sua funcionalidade, como já mencionado, essa classificação existe como auxílio no processo de análise do mesmo. Outra classificação possível pode ser feita com base no objetivo do invasor: Malware em massa Malwares como o Scareware possuem o objetivo do tipo “em massa” e são projetados para afetar o maior número de máquinas possível. Dos dois objetivos, o malware em massa é o mais comum e, geralmente, o menos sofisticado e mais fácil de ser detectado e combatido porque o software de segurança o tem como alvo. Malware com alvo específico O malware direcionado é criado sob demanda para uma organização específica. Trata-se de uma ameaça maior às redes do que o malware em massa, porque não é generalizado e os produtos de javascript:void(0); javascript:void(0); https://stecine.azureedge.net/webaula/estacio/go0682/aula1.html#collapse01-03 https://stecine.azureedge.net/webaula/estacio/go0682/aula1.html#collapse01-04 segurança provavelmente não possuem sua assinatura e não serão capazes de criar uma proteção contra eles. Sem uma análise detalhada do malware direcionado, é quase impossível proteger a rede contra esse tipo de ameaça e remover infecções realizadas. Trata-se de algo geralmente muito sofisticado e sua análise frequentemente exigirá habilidades de análise avançadas. Análise de malwares – Ransomware Os ransomwares são malwares que, ao infectar um computador, podem bloquear o acesso do usuário ou criptografar dados importantes. Uma vez bem-sucedidos, cobram uma quantia para liberar o acesso ao usuário. Esse tipo de ameaça tem se tornado cada vez mais comum. Saiba mais Casos de infecção de ransomware foram vistos pela primeira vez na Rússia entre 2005-2006. Foi publicado um relatório pela Trend Micro sobre um caso em 2006 que envolvia uma variante de ransomware que compactava certos tipos de arquivos antes de sobrescrever os originais, deixando apenas os arquivos .zip protegidos por senha no sistema do usuário. Por fim, gerava-se um arquivo de texto que funcionava como a nota de resgate informando aos usuários que os arquivos poderiam ser recuperados em troca de $300. Em seus primeiros anos O ransomware normalmente criptografava determinados tipos de arquivo, como .doc, .xls, .jpg .zip, .pdf e outras extensões de arquivo comumente usadas. compare_ arrows Pouco tempo depois Surgiram outros tipos que infectavam o Master Boot Record (MBR) de um sistema vulnerável, evitando que o sistema operacional fosse sequer carregado. Ao ser reiniciado, o sistema infectado exibia a notificação ao usuário e exigia o resgate para devolver o acesso ao usuário da máquina. Comentário Esse tipo de ameaça tem se tornado cada vez mais presente em nosso dia a dia, sem definição de alvos: podendo ser usuários comuns, pequenas e médias empresas, ou grandes redes de hospitais. Possui uma enorme capacidade evolutiva, no que concerne às técnicas de bloqueio de estratégias de defesa; aumentando assim, sua resistência e capacidade de obter sucesso na extorsão. ondemand_videoVídeo Estratégias de ataque Ao realizar uma análise, sua equipe terá, na maioria dos casos, apenas o arquivo executável do malware. Cabe ressaltar que um arquivo binário, caso nunca tenha visto um, não é legível. Assim, para entender seu fluxo e suas intenções, é preciso usar uma variedade de ferramentas e técnicas para montar um quebra-cabeça com cada uma das informações adquiridas. Quanto mais ferramentas e técnicas forem utilizadas mais nítida a imagem ficará. Duas abordagens são consideradas fundamentais dentro da análise de artefatos: estática e dinâmica: 1 Análise estática Envolve examinar o malware sem executá-lo. 2 Análise dinâmica Envolve a execução do malware. Ambas as técnicas ainda podem ser categorizadas como básicas ou avançadas. A seguir vamos conceituar cada uma destas . ondemand_videoVídeo ondemand_videoVídeo Análise Estática Básica A análise estática básica consiste em examinar o arquivo executável sem visualizar as instruções propriamente ditas. A análise estática básica pode (depende muito das situações) confirmar se um arquivo é malicioso, fornecer informações sobre sua funcionalidade e, às vezes, fornecer informações que permitirão que você produza assinaturas de rede simples. Uma característica vital deste tipo de análise é sua velocidade de pronta resposta, porém pode ser (e geralmente é) ineficaz contra artefatos sofisticados. Análise Dinâmica Básica A análise dinâmica básica consiste em executar o artefato e observar seu comportamento no sistema. Simples, certo? Com isso é possível produzir assinaturas eficazes e entender a dinâmica produzida pelo mesmo. No entanto, surge a seguinte questão: “devo executar um vírus em meu computador?” A resposta é sim, mas antes é preciso criar um ambiente seguro. Para isso, você deve configurar um ambiente que permita estudar o artefato em execução sem que haja risco de danos ao sistema ou rede. https://stecine.azureedge.net/webaula/estacio/go0682/aula1.html#collapse01-06 https://stecine.azureedge.net/webaula/estacio/go0682/aula1.html#collapse01-07Análise Estática Avançada É um tipo de análise que requer um nível mais elevado de conhecimento. A análise estática avançada consiste na engenharia reversa dos componentes internos do artefato. Vale ressaltar que artefatos complexos possuem centenas de milhares de instruções as quais devem ser analisadas. Para isso, utilizam-se ferramentas de depuração para analisar o código da aplicação e, com isso, entender o fluxo do binário ao qual se está analisando. No entanto, ressalta-se que estamos falando de uma outra área da Segurança da Informação que já mencionamos anteriormente: Engenharia reversa. Ela por si só seria um curso completo a parte. Com isso, podemos concluir que a análise estática avançada possui uma curva de aprendizado mais íngreme do que a análise estática básica e requer um conhecimento especializado de programação, arquitetura de computadores e conceitos de sistemas operacionais, os quais não abordaremos em profundidade. Análise Dinâmica Avançada Com auxílio de ferramentas de depuração (em inglês: Debugges examina-e o estado interno de um executável malicioso em execução, acompanhando o passo a passo de sua execução e entendendo sua dinâmica, literalmente. Artefatos sofisticados, em sua esmagadora maioria, estão ofuscados, ou seja, em seu estado original não se pode identificar suas reais intenções. Em algum momento o artefato revelará suas reais instruções, então o analista verificará e identificará o seu conteúdo. As técnicas avançadas de análise dinâmica fornecem outra maneira de extrair informações detalhadas de um executável. Faremos algumas demonstrações de como usar a análise dinâmica avançada junto a análise estática avançada para analisar um artefato. Aula 2: Análise Estática e Dinâmica Básica Apresentação Após consolidados os conceitos mínimos necessários, abordaremos as técnicas básicas utilizadas para fazer uma análise estática e dinâmica eficaz. https://stecine.azureedge.net/webaula/estacio/go0682/aula1.html#collapse01-08 https://stecine.azureedge.net/webaula/estacio/go0682/aula1.html#collapse01-09 Veremos, também, formas seguras para execução de artefatos maliciosos. Objetivo • Identificar as técnicas de análise de estáticas básicas; • Explicar os conceitos de uma máquina virtual; • Identificar as técnicas de análise de dinâmicas básicas. Análise básica Começamos nossa jornada da análise de malware com análise estática, que normalmente é a primeira etapa no estudo de malware. Essa análise descreve o processo de análise do código e da estrutura de um programa para determinar seu fluxo e suas intenções. O programa em si não é executado neste momento, isso ocorrerá durante a análise dinâmica. Técnicas de análise estática básica Apresentaremos algumas formas de extrair informações úteis de executáveis, discutindo as seguintes técnicas: Uso de antivírus para verificação do binário. Uso de algoritmos de hashes para identificá-lo. Coleta de informações usando ferramentas e leitura do cabeçalho. Como já vimos em outra ocasião, cada técnica pode fornecer informações diferentes como pequenas peças de um quebra-cabeça. Cabe ao analista juntá-las e montar o cenário propício para as respostas desejadas. Antivírus O primeiro passo ao analisar um artefato suspeito é executar uma checagem por meio de antivírus; alguém já pode ter feito o trabalho manual e catalogado o referido malware. Atenção Porém, cabe a ressalva de que não se trata de uma solução perfeita; não se pode afirmar que um binário é legítimo unicamente porque não foi reconhecido por um software de antivírus comercial. O antivírus se baseia na assinatura de arquivos e em análises comportamentais.| Fonte: TheDigitalArtist / Pixabay. De maneira geral, o antivírus se baseia em dois aspectos: Assinatura de arquivos Tais programas dependem, de maneira geral, de um banco de dados de funções e ações maliciosas de códigos suspeitos já conhecidos, que chamaremos de assinaturas de arquivos. Análises comportamentais Outro ponto é que os antivírus baseiam-se em análises comportamentais e de correspondência de padrões, as chamadas heurísticas, para identificar arquivos suspeitos. Vejamos alguns aspectos que são pontos de atenção em relação ao antivírus: • Tempo limitado O antivírus tem um tempo limitado para realizar um teste em um novo arquivo, bem como um tempo e recurso limitado para dar uma resposta satisfatória ao usuário. • Desatualização Um grande calcanhar de Aquiles dessa solução é a facilidade dos atacantes em modificar seu código, alterando assim a assinatura de seu programa e https://stecine.azureedge.net/webaula/estacio/go0682/aula2.html#collapse01-01 https://stecine.azureedge.net/webaula/estacio/go0682/aula2.html#collapse01-02 criando um artefato completamente novo, que muitas vezes não é detectado pelo software de antivírus, pois simplesmente não está no banco de dados. • Heurística contornável Por fim, a heurística, embora muitas vezes bem- sucedida na identificação de código malicioso desconhecido, pode ser contornada por meio de sistemas de proteção a análises. • Eficácia relativa Cada sistema de antivírus funciona de uma forma diferente, analisando o binário com uma heurística distinta e com diversas assinaturas. Portanto, é útil analisar o artefato em vários programas antivírus diferentes. Dica Para não obrigar a sua empresa a comprar diversas soluções diferentes, existem sites como o VirusTotal (http://www.virustotal.com/), que permitem que você carregue um arquivo para varredura por vários mecanismos antivírus. Atenção Muito cuidado, não existe almoço grátis. Se o produto oferecido é grátis, a empresa tem outra fonte de renda. Portanto, em hipótese alguma submeta arquivos sensíveis a esses sites, pois você estará expondo sua empresa. Se não for o caso de informação sensível, esse tipo de solução é bastante útil. O VirusTotal, por exemplo, gera um relatório que fornece o número total de mecanismos que marcaram o arquivo como malicioso, o nome do malware e, se disponível, informações adicionais. Fonte: VirusTotal (2020). Figura 1 - Site do VirusTotal javascript:void(0); Hashing O hash é um método comum usado para identificar qualquer tipo de arquivo de forma exclusiva. Um algoritmo hash é uma função que converte uma sequência de dados em uma saída numérica hexadecimal de comprimento fixo. O artefato é submetido a essa função, que produz uma sequência exclusiva identificando o mesmo, uma espécie de impressão digital. Comentário Existem casos em que pode haver colisões da saída do hash, porém são raros. Existem diversos tipos de funções hash; para nosso estudo de caso, utilizaremos a função Message-DigestAlgorithm 5 (MD5). Por meio do programa certutil, disponível gratuitamente e que acompanha o Windows 10, calculamos o hash do programa calc.exe, também disponível no Windows: sintaxe: certutil -hashfile<arquivo a ser processado><tipo de algoritmo> comando: certutil -hashfile C:\Windows\System32\calc.exe md5 Fonte: o Autor. Figura 2 - Hash Calc.exe O hash MD5 de calc.exe é: 5da8c98136d98dfec4716edd79c7145f. De posse desse valor único é boa prática que o artefato seja identificado por ele, e que seu valor seja compartilhado com outros analistas para futuras referências, bem como seja feita uma busca online pelo hash para verificar se tal artefato já foi identificado. Strings Uma string é uma sequência de caracteres. Um programa contém strings se: 1 Contiver uma mensagem a ser impressa. 2 Conectar a uma URL ou, ainda. 3 Copiar um arquivo para um local específico. Tais sequências deverão estar guardadas dentro do artefato. Pesquisar por essas informações pode ser uma maneira simples de obter dicas sobre a funcionalidade de um programa. Saiba mais Você pode usar o programa Strings para pesquisar em um executável por qualquer sequência de caracteres, normalmente armazenadas emformato ASCII ou Unicode. O uso da ferramenta é bem simples: Ao abrir um terminal, basta digitar o seguinte comando: sintaxe: strings.exe <opções><binário a ser analisado> O Strings procura em um executável por strings ignorando o contexto e a formatação, a fim de detectar strings em um arquivo inteiro. Por padrão, Strings procura uma sequência de três letras ou mais de caracteres, seguidos por um caractere de terminação de string (byte nulo). Fonte: o Autor. Figura 3 - Strings Calc.exe javascript:void(0); comando: strings.exe -n 10 c:\Windows\System32\calc.exe Realizando o comando com a opção -n 10, ou seja, tamanho mínimo da cadeia de 10 caracteres, podemos ver diversas informações: Nomes de funções, nomes de bibliotecas importadas e nomes de seções. Essas informações auxiliarão o analista durante sua investigação. Comentário A notação ASCII utiliza apenas 1 byte por caractere; já a notação Unicode utiliza 2 bytes. Em algumas situações, isso pode ser um fator decisivo para o sucesso de uma análise. O programa strings já realiza buscas tanto em ASCII quanto em Unicode. Artefatos maliciosos geralmente usam compactação ou ofuscação para tornar seus arquivos mais difíceis de serem analisados. Programas ofuscados são aqueles em que se tenta ocultar sua execução e programas compactados (ou empacotados); são um subconjunto de programas ofuscados nos quais o artefato é compactado e sua análise fica prejudicada. Ambas as técnicas limitarão a análise estática do artefato. Fonte: o Autor. Figura 4 - Programa original e Programa empacotado Ao executar um programa compactado, uma pequena rotina desempacotadora é executada para tornar o binário legível na memória. Portanto, podemos concluir que, ao analisar esse tipo de programa estaticamente, apenas esse pequeno trecho será legível. Essa é uma das técnicas de anti-análise que abordaremos mais adiante. Saiba mais A ferramenta PeiD auxilia na detecção de arquivos empacotados0 Podemos usar o PeiD para detectar o tipo de empacotador ou compilador empregado para construir um aplicativo, facilitando a análise do arquivo. Fonte: Peid (2020). Figura 5 - Uso do PeiD para detecção de empacotamento javascript:void(0); Indicadores de compromentimento (IoC) Indicadores de comprometimento (IoC), segundo a Microsoft, são eventos mal-intencionados conhecidos que indicam que uma rede ou um dispositivo já foi violado. Ao contrário de definições de alerta, esses indicadores são considerados como evidência de uma violação. Muitas vezes, eles são vistos depois que um ataque já foi executado e o objetivo foi atingido, como roubar os dados. Monitorar os IOCs também é importante durante as investigações forenses. Embora ele não possa fornecer a capacidade de intervir em uma cadeia de ataque, coletar esses indicadores pode ser útil na criação de defesas melhores para possíveis ataques futuros. Durante as análises é vital a descoberta e o registro de todos os IoC; assim será possível criar um conjunto de informações que culminarão em assinaturas a serem incorporadas nos sistemas de controle da rede. Tais assinaturas servirão de subsídios para geração de alertas para futuras invasões. Outras ferramentas de análise PEview Outra ferramenta fundamental para o analista é o PEview. Por meio dela é possível verificar a estrutura e o conteúdo não só de arquivos executáveis mas de DLL (Dynamic Link Library) e outros arquivos do tipo. javascript:void(0); Uma DLL é uma biblioteca com funções que podem ser acessadas por outros programas do computador, pois ela exporta a função implementada. ondemand_videoVídeo Dependency Walker A ferramenta Dependency Walker é utilizada para mostrar todas as dependências importadas e utilizadas pelo artefato. Ela não apenas informa as bibliotecas como também disponibiliza as funções importadas pelo binário, auxiliando no entendimento do comportamento do artefato através das chamadas do sistema. Análise de malware em máquinas virtuais Antes de executar qualquer artefato para realizar análises dinâmicas, devemos configurar um ambiente seguro. Por quê? Os malwares recentes podem ser cheios de surpresas; executá-lo em uma máquina de produção pode tornar-se o vetor de infecção de outras máquinas na rede. Um ambiente seguro permitirá que você investigue o malware sem expor sua máquina,ou outras máquinas na rede, a riscos inesperados e desnecessários. Para configurar um ambiente seguro, podemos usar máquinas físicas ou virtuais dedicadas para estudar artefatos com segurança. O malware pode ser analisado usando máquinas físicas individuais em redes isoladas com máquinas desconectadas da Internet ou de qualquer outra rede para evitar que o mesmo se espalhe. javascript:void(0); Máquina virtual As máquinas virtuais são como um computador dentro de um computador. Fonte: SIKORSKI (2012). Figura 6 - Componentes de uma máquina virtual Entre as vantagens desse modelo estão: Sistema operacional livre de risco Um sistema operacional convidado em uma máquina virtual é instalado e funciona de forma isolada dentro do sistema operacional da máquina física. Portanto, em tese, o artefato malicioso executado em uma máquina virtual não pode prejudicar o sistema operacional principal. Snapshots Outra grande vantagem da máquina virtual são os “snapshots”, em que se tira uma fotografia do estado atual da máquina e pode-se retornar a ela quando for da vontade do usuário. Logo, se um malware danificar a máquina virtual, você pode simplesmente reinstalar o sistema operacional na máquina virtual ou recuperar seu estado. https://stecine.azureedge.net/webaula/estacio/go0682/aula2.html#collapse01-03 https://stecine.azureedge.net/webaula/estacio/go0682/aula2.html#collapse01-04 Por outro lado, a máquina virtual conta possui as seguintes desvantagens: Ausência de conexão com a internet Muitos arquivos maliciosos dependem de uma conexão ativa para atualizações, comando, controle e outros recursos e, por isso, não se manifestam em ambientes virtualizados. Contudo, podemos utilizar alguns artifícios para minimizar essa desvantagem ocasionada por alguns artefatos protegidos em relação à análise. compare_ arrows Exigência de um computador de alto nível Outra desvantagem é a exigência de um bom equipamento para suportar mais de uma máquina ao mesmo tempo. Configuração da máquina virtual • Software e instalação Não fará parte dessa aula a escolha do virtualizador ou a instalação passo a passo de uma máquina virtual. Existem diversas opções para tal, sendo as soluções mais comuns Virtual Box e VMWare, ficando a critério do analista a escolha do software que mais se ajuste à necessidade. Outro ponto importante é a instalação das máquinas virtuais. O sistema operacional Windows é protegido por licença, o que impossibilita seu download indiscriminado na internet. Dica A própria Microsoft disponibiliza uma versão para desenvolvedor em seu site com uma licença de 90 dias para testes. Seu conteúdo pode ser acessado em: https://developer.microsoft.com/en-us/microsoft- edge/tools/vms/ As configurações da máquina devem ser ajustadas para que o usuário tenha uma boa experiência. Além disso, a máquina virtual, como já vimos, exige bom equipamento, capaz de suportar mais de uma máquina ao mesmo tempo. • Adaptadores de rede Existe, porém, um ponto muito importante a ser discutido: Adaptadores de rede. Ao criar uma máquina virtual, três opções básicas surgem ao usuário: Modo Bridge, modo NAT e modo Host- Only. 1 Bridge (túnel) A máquina virtual se torna parte da mesma rede que a máquina física, recebendo um IP na mesma faixa. De semelhante forma, é enxergada pelo roteador de sua casa como mais um dispositivo físico. 2 NAT A máquina física mascara todas as atividades da máquina virtual e funciona como um roteador, retransmitindo todas as requisições. Se a máquina físicapossuir internet, a máquina virtual também terá. 3 Host-Only Permite conexão apenas entre a máquina virtual e a máquina física. É possível configurar outras máquinas virtuais do mesmo modo e permitir comunicações entre elas e a máquina física, sem qualquer acesso à internet. javascript:void(0); javascript:void(0); Atenção A máquina de análise de artefatos sempre deve ser configurada em modo Host-Only. Análise dinâmica básica Como já sabemos, a análise dinâmica é a investigação realizada após a execução do artefato a fim de verificar seu comportamento. É considerada a segunda etapa do processo de análise, pois é realizada após a completude das técnicas de análise estáticas disponíveis. Podemos monitorar o comportamento do malware enquanto ele é executado ou pode ser feito um exame do sistema após a sua execução, verificando as mudanças executadas e como o sistema foi afetado. Nessa fase, as hipóteses levantadas durante a análise estática são confirmadas ou refutadas, pois a simples existência de uma função em um binário não significa que ela será executada. A análise dinâmica é a maneira mais eficiente de identificar a funcionalidade e os propósitos do artefato. Exemplo Por exemplo, se o malware for um keylogger, a análise dinâmica pode permitir que você localize o arquivo usado para guardar as informações digitadas em algum local no sistema. É possível verificar os tipos de registros que ele mantém e, ainda, descobrir para onde suas informações são enviadas. Esse tipo de percepção seria mais difícil de obter usando apenas técnicas estáticas básicas. SandBox Definições Vejamos as definições de uma sandbox: • É um mecanismo de segurança para executar programas não confiáveis em um ambiente seguro, sem necessidade de grandes precauções para não prejudicar sistemas “reais”. • É um ambiente virtualizado que muitas vezes simula serviços de rede de alguma forma para garantir que o artefato testado funcione normalmente e realize todas as suas operações, gerando um relatório com todas as atividades realizadas. Saiba mais Existem diversas opções disponíveis no mercado, inclusive de forma gratuita. Uma sandbox disponível e bastante utilizada pela comunidade é a HybridAnalysis. Existe um plano pago com mais opções e um maior acesso, mas por ora o plano grátis nos atenderá. Ao acessar o site, podemos enviar nossa amostra e escolher o sistema operacional a ser testado: Windows, Linux e Android. Depois, preenchemos os dados para recebimento do relatório e seu arquivo vai para uma fila para ser analisado. Caso ele já tenha sido enviado, você já terá acesso ao relatório com os indicadores analisados. Nunca submeta a ferramentas gratuitas arquivos com informações sensíveis. Desvantagens Os sandboxes possuem algumas desvantagens importantes: 01 Não há possibilidade de executar o arquivo suspeito por meio da linha de comando, passando qualquer tipo de argumento, por exemplo. Isso limita as possibilidades pois, nos casos em que o artefato é acionado por linha de comando, não funcionará em uma sandbox padrão. 02 Além disso, nos casos em que a parte maliciosa apenas se manifesta após algum tempo, as sandboxes podem deixar de analisar essa parte. javascript:void(0); Execução do malware Após tomadas todas as precauções já citadas, é hora de executar o artefato. Embora possa parecer simples executar um binário clicando duas vezes ou executando-o via linha de comando, pode ser complicado iniciar DLLs maliciosas, pois o Windows não possui uma forma direta para executá-las. Abordaremos uma maneira de iniciar DLLs para poder realizar a análise dinâmica. O programa rundll32.exe está incluído em todas as versões modernas do Windows e fornece um contêiner para executar uma DLL usando a seguinte sintaxe: rundll32.exe DLLname, Export argumentos Toda DLL exporta uma função e podemos verificar seu nome por meio da ferramenta PEview na tabela de exportação. Vejamos o exemplo a seguir. Exemplo João Wannacry verificou que havia uma dll estranha chamada resgate.dll e, ao analisá-la via PEview, percebeu que existiam duas funções de exportação: Criptografar e descriptografar. Curioso, João procurou na internet como executar a função de uma DLL, executando o seguinte comando: c:\>rundll32.exe resgate.dll, descriptografar. Nada aconteceu, então ele executou c:\>rundll32.exe resgate.dll, criptografar. Imediatamente, todos os arquivos de sua máquina começaram a ser criptografados e, após um tempo, surgiu uma mensagem na tela cobrando um resgate para recuperação dos mesmos. Isso aconteceu porque João realizou a execução em um ambiente que não era seguro. Monitoramento Process Monitor O Process Monitor, ou procmon, é uma ferramenta de monitoramento avançada para Windows que fornece uma maneira de monitorar certos registros, sistemas de arquivos, redes, processos e afins. javascript:void(0); Embora o procmon capture muitos dados, ele não captura tudo. Ele pode perder algumas atividades maliciosas ocultadas por rootkits e chamadas de gráficas. Mesmo sendo uma ferramenta útil, geralmente não é utilizado para registrar a atividade da rede, pois não funciona de forma consistente no Windows. O Procmon monitora todas as chamadas de sistema durante o seu funcionamento. Como existem muitas chamadas de sistema em uma máquina Windows, às vezes mais de 50.000 eventos por minuto, geralmente é impossível examinar todas elas. Para isso, utilizamos o filtro disponível para mostrar apenas determinadas operações que nos interessam. Ele fornece as seguintes informações por padrão: 1 Registro Ao examinar as operações de registro, você pode saber como um malware se instala no mesmo. 2 Sistema de arquivos Explorar a interação do malware com o sistema de arquivos pode revelar todos os arquivos criados, acessados e/ou modificados. 3 Atividade do processo A investigação da atividade do processo pode dizer se o malware gerou processos adicionais. 4 Rede A identificação de conexões de rede pode mostrar a porta e o host que o malware está usando para se comunicar. Process Explorer O Process Explorer é outra ferramenta útil para analisar os processos que estão em execução na memória, organizando-os em forma de árvore e mostrando a hierarquia entre eles. Além disso, pode mostrar todas as DLL que foram carregadas na memória ao clicar na propriedade do processo. Outra informação útil é a possibilidade de comparação de cadeia de caracteres da imagem estática do binário com as informações carregadas em memória. Essa opção mostra a diferença criada por um empacotador; em memória, todos os caracteres são revelados. Regshot Regshot é uma ferramenta de comparação de registro que permite tirar e comparar duas fotografias do registro. Seu uso é simples: Fonte: O autor. Wireshark Uma aplicação capaz de interceptar e analisar pacotes de rede é essencial ao analista. Usaremos o Wiresharkpara esse fim, uma plataforma de código aberto que recebe diversas atualizações e plugins da comunidade, fornecendo visualização, análise de fluxo de pacotes e análise aprofundada de pacotes individuais. O Wireshark pode ser usado tanto para o bem quanto para o mal: Depurar problemas javascript:void(0); javascript:void(0); javascript:void(0); Pode ser usado para analisar o tráfego de redes internas, a fim de depurar problemas de aplicativos e estudar protocolos em execução. compare_ arrows Detectar senhas Também pode ser usado para detectar senhas, fazer engenharia reversa de protocolos de rede, roubar informações confidenciais e capturar conversas trafegando nas redes vizinhas. Comentário O Wireshark irá nos ajudar a entender como o artefato malicioso realiza a comunicação de rede, interceptando os pacotes enquanto se comunica (ou enquanto tenta se comunicar). Para isso, basta conectar- se à Internet ou simular uma conexão, iniciar a captura de pacotescom o Wireshark e, por fim, executar o malware. ondemand_videoVídeo Falsificação de rede O artefato geralmente tenta se comunicar com um servidor de comando e controle, ou tenta fazer download de outro arquivo malicioso. Para isso, podemos criar uma rede falsa e obter rapidamente indicadores de rede, sem realmente se conectar à Internet. Esses indicadores podem incluir nomes DNS, endereços IP e assinaturas de pacote. Para falsificar uma rede com sucesso, devemos evitar que o malware perceba que está sendo executado em um ambiente virtualizado. Ao combinar as ferramentas discutidas aqui com uma configuração de rede de máquina virtual sólida, você aumentará muito suas chances de sucesso. Como isso deve ser feito? REMnux O REMnux é um sistema operacional personalizado criado para auxiliar a análise de malware e engenharia reversa e nós utilizaremos essa distribuição. Por que utilizar um sistema operacional? INetSim ondemand_videoVídeo Existe uma ferramenta fantástica criada para simular serviços comuns de Internet: INetSim, um pacote de software gratuito baseado em Linux. 01 O INetSim é a ferramenta gratuita mais fácil e ágil para fornecer serviços falsos, permitindo que você analise o comportamento de rede dos artefatos emulando serviços como HTTP, HTTPS, FTP, IRC, DNS, SMTP e outros. Por meio de um comando simples, as portas são definidas por padrão mas podem ser modificadas facilmente. 02 Alguns dos melhores recursos do INetSim são integrados à simulação de servidor HTTP e HTTPS. Por exemplo, o INetSim pode fornecer qualquer arquivo solicitado. No caso de um malware solicitar um JPEG de um site para continuar sua operação, o INetSim responderá com um JPEG formatado corretamente, de forma automática. javascript:void(0); javascript:void(0); 03 Embora essa imagem possa não ser o arquivo que o artefato esteja procurando, o servidor não retorna um erro 404, ou outro erro, e sua resposta, mesmo que incorreta, pode manter o artefato em execução. 04 O INetSim também pode registrar todas as solicitações e conexões de entrada, algo bastante útil para determinar se a atividade é legítima,se está se conectando a um serviço padrão ou para registrar as solicitações ilegítimas para futura análise. Por ser extremamente configurável, é possível definir a página ou o item retornado após uma solicitação. Exemplo Por exemplo, ao verificar que o malware está procurando uma página da web específica antes de continuar a execução, o INetSim fornece a página. Aula 3: Análise Estática Avançada e Codificação – Parte I Apresentação Nesta terceira aula, após aprendermos a realizar uma análise básica no artefato, tanto estática quanto dinamicamente, abordaremos a tão temida linguagem de máquina – Assembly. Para isso, revisaremos alguns tópicos necessários para o entendimento da arquitetura Intel x86 e o funcionamento padrão de um programa. Objetivo • Identificar características da arquitetura Intel x86; • Examinar as diferenças entre as bases numéricas; • Identificar comandos na linguagem Assembly. Arquitetura de computadores Para começar, é importante sabermos que: Os métodos básicos de análise estática e dinâmica de artefatos são satisfatórios para a triagem inicial, mas não fornecem informações suficientes para uma análise completa. Porém, estaremos apenas arranhando a superfície se quisermos entender toda a dinâmica e extensão dos danos. Análise básica Por meio de uma análise estática básica é possível identificar as funções que são importadas, mas ainda não é possível determinar como elas serão usadas ou se serão usadas em algum momento. compare_ arrows Análise dinâmica As técnicas dinâmicas básicas também apresentam algumas deficiências. Por meiodelas é possível entender o que um artefato precisa e como age ou responde ao receber um determinado pacote ou arquivo ao requisitá-lo de um determinado domínio. Entretanto, só será possível entender o formato e como toda a engrenagem funciona com aprofundamento no fluxo da aplicação. É nesse ponto que entraremos nas ferramentas de desmontagem (disassembly). Comentário Num primeiro momento, a desmontagem pode parecer algo sem sentido até mesmo para programadores experientes. Mas não desanime, nesta aula cobriremos algumas bases necessárias ao entendimento dos artefatos, dos comuns aos mais complexos. Como esse curso não é de engenharia reversa, não conseguiremos exaurir por completo este campo de estudo, mas daremos os primeiros passos. Níveis de abstração Dentro da arquitetura de computadores tradicionais há vários níveis de abstrações, que existem para facilitar os detalhes de implementação dos programas e sistemas. O que isso significa? Para entender mais facilmente basta imaginarmos que um sistema operacional como o Windows, por exemplo, pode ser executado em diversos tipos de hardware sem que haja qualquer tipo de ajuste. Isso só é possível porque os componentes físicos não são levados em consideração, ou abstraídos, pelo sistema operacional. A Figura 1 mostra três níveis de codificação que serão abarcados em uma análise de um binário. Fonte: Sikorski (2012). Figura 1 - Exemplo de níveis de código Então: • O malware será criado em uma linguagem de alto nível, como a linguagem C, por exemplo. • Depois, utiliza-se um compilador que irá gerar o código de máquina correspondente às instruções criadas pelo autor e que será executado pela CPU. Partiremos desse ponto em nossos exemplos e, é desse ponto também que os analistas de malware trabalham e analisam os binários. A ferramenta de desmontagem (disassembly) transforma o código de máquina em uma linguagem de baixo nível, também conhecida como Assembly. Nesse sentido, o gerenciamento de vulnerabilidde envolve: Hardware Nível físico, consiste em circuitos elétricos que implementam combinações complexas de operações lógicas e não são facilmente manipulados pelo Software. https://stecine.azureedge.net/webaula/estacio/go0682/aula3.html#collapse01-01 Micro-código Também conhecido como firmware, opera apenas no circuito exato para o qual foi projetado. Contém microinstruções que fornecem uma interface de tradução do código de máquina para o hardware. Não será nosso foco, pois é geralmente específico para cada hardware. Código de máquina Consiste basicamente em opcodes (muito importante), que são dígitos hexadecimais que dizem ao processador qual instrução deveser executada. Normalmente implementado com várias instruções de microcódigo para que o hardware subjacente possa executar o código, sendo criado quando uma linguagem de alto nível é compilada. Linguagens de Baixo Nível Versão legível por humanos do conjunto de instruções de uma arquitetura de computador. Sua versão mais comum é a linguagem Assembly. Operaremos nesse nível porque o código de máquina é muito difícil para um ser humano compreender. Linguagens de Alto Nível A maioria dos programas é criada em linguagens de alto nível, pois elas fornecem grande abstração no nível da máquina e facilitam o uso de lógica de programação e dos mecanismos de controle de fluxo. Possuem como exemplos as linguagem C, C++, dentre outras. Essas linguagens são normalmente transformadas em código de máquina por um compilador por meio de um processo conhecido como compilação. Linguagens Interpretadas Essas linguagens não são compiladas em código de máquina; em vez disso, são traduzidas em bytecode — uma representação intermediária específica da linguagem de programação. O bytecode é executado dentro de um interpretador, que é um programa que traduz o bytecode em código de máquina executável durante a execução. São exemplos de linguagens interpretadas: C#, Perl, .NET e Java. Arquitetura Intel x86 Os componentes internos da maioria das arquiteturas de computador modernas (incluindo x86) seguem a arquitetura de Von Neumann, conforme a Figura 2, e possuem trêscomponentes de hardware: Unidade de processamento central (CPU) que executa o código. https://stecine.azureedge.net/webaula/estacio/go0682/aula3.html#collapse01-02 https://stecine.azureedge.net/webaula/estacio/go0682/aula3.html#collapse01-03 https://stecine.azureedge.net/webaula/estacio/go0682/aula3.html#collapse01-04 https://stecine.azureedge.net/webaula/estacio/go0682/aula3.html#collapse01-05 https://stecine.azureedge.net/webaula/estacio/go0682/aula3.html#collapse01-06 Memória principal do sistema (RAM) que armazena todos os dados e códigos. Sistema de entrada/saída que faz interface com dispositivos como discos rígidos, teclados e monitores. Fonte: TANENBAUM (2010). Figura 2 - Arquitetura Von Neumann Conforme a Figura 2, é possível verificar que a CPU contém vários componentes que serão muito importantes para nosso entendimento: Fonte: Adaptado de Freepik. Unidade de controle Obtém instruções a serem executadas da memória RAM usando um registrador (chamado de ponteiro de instrução – EIP), que armazena o endereço da instrução a ser executada. Registradores Unidades básicas de armazenamento de dados da CPU e que são usados para economizar tempo, pois a CPU não precisará acessar a RAM. Unidade Lógica Aritmética (ULA) Responsável por executar a instrução obtida da RAM; armazena os resultados em registradores ou na memória. A memória principal (RAM) para um único programa pode ser dividida em quatro seções principais: 1. Dados 2. Código 3. Heap 4. Pilha Fonte: SIKORSKI (2012). Dados Área da memória reservada para receber variáveis com valores estáticos que serão usados no decorrer do programa ou com valores globais que estarão disponíveis para qualquer parte do programa. Código Área reservada para as instruções buscadas pela CPU para executar as tarefas do programa. Essa área possui as rotinas que definem o que o programa faz e como as tarefas do programa serão orquestradas. Heap Porção da memória utilizada para alocações dinâmicas durante a execução do programa para criar (alocar) novos valores e eliminar (liberar) outros de que o programa não precisa mais. O heap é conhecido como memória dinâmica porque seu conteúdo pode ser alterado com frequência durante a execução do programa. Pilha Área utilizada para variáveis locais e parâmetros para funções, além de auxiliar no controle do fluxo do programa. Linguagem de baixo nível – Assembly Agora que revisamos a arquitetura e a forma como funciona um computador, passaremos a abordar a linguagem de baixo nível assembly. Como em qualquer linguagem, o assembly possui diversas instruções, cada uma com seu propósito;cada instrução possui um mnemônico e zero ou mais operandos. Vejamos como isso funciona: Fonte: O autor. O mnemônico é uma palavra que identifica a instrução a ser executada e o operando identifica as informações usadas pela instrução, seja um registrador ou um dado. Parece confuso, mas vamos explicar melhor. No exemplo a seguir, movemos o valor de 42 em hexadecimal para o registrador ecx, ou seja, o valor de eax passará a ser 0x42 (em hexadecimal): movecx, 0x42 Cada instrução corresponde a opcodes (códigos de operação) que informam à CPU qual operação o programa deseja executar. Uma ferramenta de disassemble traduz opcodes em instruções legíveis para humanos. No exemplo anterior, a instrução movecx, 0x42 possui os seguintes opcodes: B9 42 00 00 00. • O valor B9 corresponde a movecx; e • 0x42000000 corresponde ao valor 0x42. Isso acontece porque a arquitetura x86 usa o formato little-endian na ordem dos bytes. O endianness dos dados descreve se o byte mais significativo (big-endian) ou menos significativo (little-endian) é ordenado primeiro (no menor endereço) dentro de um item de dados maior. Comentário Vamos simplificar. Se estivermos em um ambiente little-endian e quisermos mover 0x12345678 para o eax, os opcodes deverão ser: B9 78 56 34 12; se estivermos em um ambiente big-endian: B9 12 34 56 78. Mudar entre ordem de bytes é algo que o malware deve fazer durante a comunicação de rede, pois os dados de rede usam big-endian e um programa x86 usa little-endian. Portanto, o endereço IP 127.0.0.1, em hexadecimal 127 – 0x7f; 0 – 0x00; 0 – 0x00; e 1 – 0x01, será representado como 0x7F000001 no formato bigendian (pela rede) e 0x0100007F no formato little-endian (localmente na memória). Atenção Como analista de malware, você deve estar ciente da ordem de bytes para garantir que não inverta acidentalmente a ordem de importantes indicadores, como um endereço IP. Os operandos são usados para identificar os dados usados por uma instrução. Existem três tipos de dados que podem ser usados: 1 Imediatos operandos de valor fixo, como no exemplo (0x42); 2 Registradore operandos são registradores, como no exemplo (ecx). 3 Endereço de memória operandos apontam para uma área da memória que contenha algum valor de interesse. Pode ser um valor ou registrador entre colchetes ([ecx] ou [0x11223344]). ondemand_videoVídeo Bases numéricas É importante lembrarmos: Um bit possui dois valores: 0 ou 1, ligado ou desligado. Os computadores trabalham em modo binário, pois são circuitos eletrônicos (complexos). Nossa matemática é baseada em números decimais: 0, 1, 2, 3, 4, 5, 6, 7, 8 e 9. Ao chegar ao limite, adiciona-se uma unidade na frente do número e reinicia a contagem. Fonte: Adi Goldstein / Unsplash. Não entendeu? Quanto é 9 + 1? Não existe uma resposta com o uso de apenas um dígito, então reiniciamos a contagem e adicionamos uma unidade na frente: 10. Isso é simples. Não é à toa que estudamos esse princípio desde a educação básica. No entanto, vamos quebrar alguns paradigmas. Em um sistema binário existem apenas 0 e 1. Quanto é 1 + 1? Para responder precisamos nos lembrar de que a resposta não pode ser representada por um único dígito (no sistema binário só existe 0 e 1). Então, como no decimal, vamos reiniciar a contagem e adicionar uma unidade na frente: 10. Estranho, não? Em binário: 1+1=10; em decimal: 1+1=2. Agora vamos expandir esse conceito para um outro sistema, o hexadecimal. Como você pode imaginar, para representar um valor de 32 bits, na arquitetura x86, são necessários 32 dígitos (0s e1s); para facilitar a sua representação, o hexadecimal é utilizado. Comentário A diferença é que existem algumas opções a mais de dígitos: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E e F. Tabela 1: Correlações entre bases Binário Decimal Hexadecimal 0 0 0 1 1 1 10 2 2 11 3 3 100 4 4 101 5 5 110 6 6 111 7 7 1000 8 8 1001 9 9 1010 10 A 1011 11 B 1100 12 C 1101 13 D 1110 14 E 1111 15 F Fonte: Autor. Como pode ser visto na Tabela 1, o uso de números em hexadecimais economiza na razão 4:1 da quantidade de números binários. Ou seja, para cada 4 binários é necessário apenas 1 hexadecimal para representar seu valor. É importante lembrarmos que um byte são oito bits, portanto, são necessários 2 hexadecimais para representar o mesmo byte. Registradores O que é um registrador? Um registrador nada mais é do que uma pequena quantidade de armazenamento de dados disponíveis para a CPU, cujo conteúdo pode ser acessado mais rapidamente do que em outro lugar. Os processadores x86 têm uma coleção de registros disponíveis para uso como armazenamento temporário, e os mais comuns se enquadram em quatro categorias (SIKORSKI,2012): 1 Registradores gerais Usados pela CPU durante a execução. 2 Registradores Usados para rastrear seções de memória. 3 Flags de status Usados para armazenar dados para tomada de decisões. 4 Ponteiros de instrução Usados para rastrear a próxima instrução a ser executada. A tabela a seguir demonstra os registradores separados por categoria: Tabela 2: Relação de registradores Gerais Segmento Status Ponteiros EAX (AX, AH, AL) CS EFLAGSEIP EBX (BX, BH, BL) SS ECX (CX, CH, CL) DS EDX (DX, DH, DL) ES EBP (BP) FS ESP (SP) GS ESI(SI) Fonte: Autor. Numa arquitetura de x86, os registradores gerais possuem 32 bits, mas podem ser referenciados em 32 ou 16 bits. Para acessar sua parte de 16 bits, basta retirar a letra “E” de seu mnemônico. Existem ainda quatro registradores (EAX, EBX, ECX e EDX), com os quais é possível acessar 8 bits da parte superior e inferior de seu registrador de 16 bits. Portanto, para estes registradores é possível acessar os 32 bits, 16 bits, 8 bits superiores e inferiores da porção de 16 bits, conforme figura a seguir: Tabela 3: Porções do Registrador EAX EAX – 32 BITS AX – 16 BITS AH – 8 BITS AL – 8 BITS Fonte: Autor. Registradores de uso geral Os registradores gerais normalmente armazenam dados ou endereços de memória e costumam ser usados de forma dinâmica para realizar as tarefas no programa. Apesar de o nome sugerir o uso geral, por definição, algumas instruções utilizam registros específicos. As instruções de multiplicação e divisão, por exemplo, sempre usarão os registradores EAX e EDX, mas isso não afetará o uso, nem o entendimento. Comentário Existem algumas convenções usadas pelos compiladores que devem ser de conhecimento de um analista de malware, pois isso permitirá que examine o código mais rapidamente. Um exemplo dessa convenção é que o EAX geralmente é usado para armazenar o valor de retorno nas chamadas de função. Portanto, ao verificar o uso do registrador EAX imediatamente após uma chamada de função, provavelmente verá a manipulação do valor de retorno da função utilizada. Flags (EFLAGS) O registrador EFLAGS é um registrador que armazena os status das operações realizadas durante a execução do programa. Na arquitetura x86, o tamanho do registrador é de 32 bits e cada bit é uma flag. Durante a execução, cada flag possui o valor (1) ou (0) para controlar as operações da CPU ou indicar os resultados de alguma operação realizada pela CPU. Para nossa análise, vamos focar nas seguintes flags: Clique nos botões para ver as informações. Flag zero (zero flag – ZF) A flag zero recebe o valor de 1 quando o resultado de uma operação é igual a 0. Não confunda: Se o resultado de uma operação for zero, a flag zero terá o valor 1. Para os outros casos, ela será zero. Flag de carregamento (Carryflag – CF) A flag de carregamento recebe o valor de 1 quando o resultado de uma operação é muito grande ou muito pequeno para o operando de destino. Por exemplo, um registrador possui o valor de 0xffffffff, ou https://stecine.azureedge.net/webaula/estacio/go0682/aula3.html#collapse01-01 https://stecine.azureedge.net/webaula/estacio/go0682/aula3.html#collapse01-02 seja, o valor máximo paraum registrador de 32 bits. Érealizada uma operação de soma um nesse registrador, o valor do registrador passará a ser 0x00000000 e a flag será ativada. Nos outros casos, ela será zero. Flag de sinal (signflag – SF) A flag de sinal recebe o valor de 1 quando o resultado de uma operação é negativo, e o valor de 0 quando o resultado é positivo. Esse sinalizador também é definido quando o bit mais significativo é definido após uma operação aritmética. Flag de trap – TF A flag de trap é usada para depuração. O processador x86 executará apenas uma instrução por vez se esse sinalizador for definido. ondemand_videoVídeo Registrador de instrução Na arquitetura x86: 01 O EIP, também conhecido como ponteiro de instrução ou, ainda, contador de programa é um registrador que contém o endereço de memória da próxima instrução a ser executada por um programa. O único propósito do EIP é dizer ao processador o local da próxima instrução a ser executada. 02 Apesar de parecer um registrador simples, o EIP é fundamental para uma aplicação pois, quando corrompido, ou seja, se ele apontar para um endereço de memória que não contém código de programa legítimo, a CPU não será capaz de buscar código legítimo para executar, causando um erro e o fechamento do programa em questão. 03 https://stecine.azureedge.net/webaula/estacio/go0682/aula3.html#collapse01-03 https://stecine.azureedge.net/webaula/estacio/go0682/aula3.html#collapse01-04 Além disso, o controle do EIP significa um controle por parte do fluxo do programa. Por isso, os invasores tentam obter o seu controle por meio de exploração de falhas da aplicação. Instruções em Assembly Instrução mov Anteriormente apresentamos um exemplo simples utilizando mov, o comando mais comum que serve para copiar dados de um lugar para outro. Atenção Apesar de o nome do comando ser mov, de “mover”, o comando não move o valor de um local para outro. E qual é a diferença? O ato de mover é retirar algo de um lugar e colocar em outro, ou seja, você limpa a origem e move-a para o destino. Você verá que um programa ou o sistema operacional não tem o costume de limpar áreas da memória após sua utilização;basta torná-la um local usável e ignorar o seu conteúdo. Vamos utilizar a sintaxe Intel de comandos assembly (a mais utilizada no mundo, a outra sintaxe é da AT&T). Portanto, o formato do comando será mov destino, origem. Ou seja, “movemos” o valor do operando da direita para o operando da esquerda. Vejamos a seguir alguns exemplos para entender e fixar o conhecimento. Vale lembrarmos que, ao colocar qualquer operando entre colchetes, acessaremos o valor da memória apontada por ele. movecx, eax movebx, [0x45678] moveax,[ebx+eax] Copia o conteúdo de EAX para o registrador ECX (sem modificar EAX). Copia os 4 bytes que estão na memória em 0x45678 para ebx. Copia os 4 bytes que estão localizados na memória na posição especificada pela equação ebx+eax para o registrador eax. Comentário Este último exemplo só pode ser usado para calcular posições de memória, ou seja, se o colchete não fosse utilizado receberíamos um erro por ser uma instrução inválida. Uma instrução semelhante ao mov é o lea, que significa carregar endereço efetivo (loadeffectiveaddress). Seu formato de instrução é o mesmo do mov: lea destino, origem. Instrução lea A instrução lea é usada para escrever um endereço de memória no destino. Não confunda a instrução mov com a instrução lea. Vejamos a diferença entre elas: leaeax, [ebx + 8] Armazenará em EAX o valor de EBX + 8 em EAX. compare_ arrows moveax, [ebx + 8] Carregará os dados do endereço de memória especificado por EBX + 8 em EAX. Ou seja, leaeax, [ebx + 8] equivale a moveax, ebx + 8 (se essa instrução fosse válida). Instruções aritméticas Num programa, várias instruções aritméticas são usadas, como soma, subtração e operações lógicas. Adição e subtração O formato da adição e da subtração é o mesmo das instruções anteriores: add destino, origem e sub destino, origem. Com um detalhe: O resultado da soma ou da subtração é armazenada no destino. Atenção Devemos lembrar que essas operações podem modificar as flags de zero ou de carregamento, se uma operação tiver como resultado zero ou se ultrapassar o valor máximo de um registrador, respectivamente. Outras instruções importantes são o inc e dec, que incrementam ou decrementam um registrador pelo valor de um. Multiplicação e divisão A multiplicação e a divisão atuam em um registrador predefinido, de modo que o comando é simplificado a uma instrução mais o valor pelo qual o registrador será multiplicado ou dividido. Seu formato de instrução é: mulvalor e divvalor. A atribuição do registrador no qual será armazenado o valor da multiplicação ou da divisão pode ocorrer muitas instruções antes; portanto, pode ser necessário pesquisar em um programa para encontrá-la. A instrução de multiplicação sempre utiliza o registrador EAX pelo valor passado como operando. O resultado é armazenado como um valor de 64 bits em dois registradores: EDX e EAX. O EDX armazena os 32 bits mais significativos e o EAX armazenaos 32 bits menos significativos. Exemplo Vamos supor que o resultado de uma multiplicação seja 800.000.000.000 ou 0xBA43B74000. Como o valor é muito grande para apenas um registrador, edx receberá o valor de 0xBA e eax receberá o valor de 0x43B74000. Já a divisão divide o valor armazenado em edx e eax pelo operando valor, o resultado é armazenado em eax e o resto armazenado em edx. Operadores lógicos Outra operação muito utilizada são os operadores lógicos, como OR, AND e XOR. Sua forma de operação é semelhante à soma e à subtração. Eles executam a operação especificada entre os operandos de origem e destino e armazenam o resultado no destino. Destacamos que as operações lógicas são realizadas na forma bit a bit. Instruções shre e shl As instruções shre shl, usadas para deslocar registradores, também são muito utilizadas. O formato da instrução, tanto do shl quanto do shr, é shl destino, valor. Basicamente, as instruções shr e shl deslocam os bits no destino para a direita ou para a esquerda, respectivamente, pelo número de bits especificado no segundo operando. Preenche-se com bits 0 os valores deslocados durante a mudança. Parece confuso mas é bem simples. Vejamos um exemplo: Exemplo Se tivermos o valor binário 1000 e deslocá-lo para a direita em 1, o resultado será 0100. Se tivermos o valor binário 1000 e deslocá-lo para a esquerda em 1, o resultado será 10000. ondemand_videoVídeo Aula 4: Análise Estática Avançada e Codificação – Parte II Apresentação Nesta quarta aula aprofundaremos a linguagem de máquina – Assembly, com exemplos mais elaborados e sua correlação com estruturas comuns na linguagem em C. Veremos a utilização de uma ferramenta poderosa na análise de malware, finalizando o básico da linguagem para prosseguimento da disciplina. Objetivo • Identificar chamadas de funções e passagem de parâmetros em assembly; • Identificar as funções básicas da ferramenta IDA Pro; • Distinguir Linguagem de alto e baixo nível. Assembly Na última aula introduzimos o básico da linguagem assembly, bem como realizamos alguns exercícios para fixar os conhecimentos. É difícil fazer generalizações, pois toda regra possui uma exceção, mas todos os códigos complexos e bem escritos possuem funções. O que são funções? As funções são partes do código dentro de um programa que executam uma tarefa específica, uma rotina, e que são relativamente independentes do código restante. O código principal chama e transfere temporariamente a execução para funções antes de retornar ao código principal. Ressaltamos que a função pode ser implementada pelo autor do código ou pode ser empregada para abrir uma conexão, um arquivo ou escrever algo na tela. Já mencionamos que todas as operações de um programa são realizadas na memória, e a pilha é o espaço reservado para que isso aconteça. Todas as operações que precisam ser armazenadas temporariamente são armazenadas na pilha. Na arquitetura x86, os parâmetros passados para uma função são passados para a pilha (Stack) para serem manipulados. A instrução utilizada para armazenar dados na pilha é o push, lembrando que os dados são armazenados no tipo FIFO – primeiro a entrar, último a sair –; pense numa pilha de pratos, o primeiro a ser colocado é o último a ser tirado. Saiba mais Existem outros pontos que podem ser necessários, mas que não teremos condições de abordar por falta de tempo. Alguns pontos serão verificados nas próximas sessões, os demais podem ser pesquisados e aprofundados no manual disponível pela própria Intel em: https://software.intel.com/content/www/us/en/develop/articles/int el-sdm.html IDA Pro O Interactive Disassembler Professional (IDA Pro) é um desmontador extremamente poderoso lançado pela empresa Hex-Rays. Embora o IDA Pro não seja o único, é o desmontador mais utilizado na atualidade. Recentemente, a NSA – Agência de Segurança Nacional dos EUA lançou uma ferramenta com os mesmos propósitos chamada Ghidra, que está fazendo muito sucesso. O IDA Pro é uma solução paga; existem duas versões comerciais e a diferença entre elas são os suportes aos processadores. A versão avançada oferece suporte a muitos processadores, e suporta diversos formatos de arquivos, como o Portable Executable (PE) para a plataforma Windows e o Executable and Linking Format (ELF) para a plataforma Linux. Comentário Concentraremos nossa discussão nas arquiteturas x86 e x64 e no formato de arquivo PE para Windows. Utilizaremos uma versão gratuita do IDA Pro, o IDA Pro Free, disponível em http://www.hex- rays.com/idapro/idadownfreeware.htm. Saiba, porém, que esta versão tem funcionalidades limitadas. Ela não é indicada para uso profissional, mas será mais do que suficiente para javascript:void(0); javascript:void(0); javascript:void(0); javascript:void(0); nós. Não se limite ao que for ensinado aqui e procure explorar ainda mais; lembre-se de que a experiência vem com a prática. Basicamente, o IDA Pro processará o programa e realizará tarefas como, mas não limitadas a: Fonte: O autor. Veremos, nessa aula, as técnicas básicas de como traçar um paralelo entre a análise feita pela ferramenta e o código-fonte da aplicação. O IDA Pro possui uma base de dados de assinaturas de código que permitem reconhecer e rotular as funções desmontadas. A ferramenta foi criada para ser interativa; todo o processo de desmontagem pode ser modificado, manipulado, reorganizado ou redefinido. 01 Um dos melhores aspectos do IDA Pro é a sua capacidade de salvar e documentar todo o progresso da análise, sendo possível adicionar comentários, rótulos e nome de funções e, em seguida, salvar seu trabalho em um banco de dados IDA Pro (conhecido como idb) para retorno posterior. O IDA Pro também oferece suporte para adição de extensões próprias ou de terceiros para auxiliar na análise. 02 Ao carregar um executável no IDA Pro, ele tenta reconhecer o formato do arquivo e a arquitetura do processador. No exemplo da figura a seguir (Figura 1), o arquivo é automaticamente reconhecido como formato PE e com a arquitetura Intel x86. Outra característica da ferramenta é o mapeamento do arquivo em memória como se tivesse sido carregado pelo sistema operacional. 03 Uma opção útil é carregar o arquivo como um binário bruto, pois o mesmo pode possuir mecanismos de proteção e não carregar dados adicionais, parâmetros de criptografia e até mesmos outros executáveis na memória quando o malware for executado pelo Windows ou carregado no IDA Pro. Fonte: O autor. Figura 1: Carregamento de arquivo no IDA Pro Por padrão, o IDA Pro não inclui o cabeçalho PE ou as seções de recursos em sua desmontagem; esses locais podem ser utilizados para esconder códigos maliciosos pelo artefato. Basta selecionar a opção de carregamento manual (Manual Load) que a ferramenta perguntará se você deseja carregar cada seção, uma por uma, incluindo o cabeçalho do arquivo PE. Isso será importante para que essas seções não escapem da análise. É possível analisar o código em modo gráfico e em modo de texto. No modo gráfico, a cor e a direção das setas ajudam a mostrar o fluxo do programa durante a análise. A cor da seta informa se o caminho é baseado em uma decisão específica que foi tomada: Vermelho, se determinada condição não for atendida. Verde se for atendida. Azul para um salto incondicional. Exemplo Por exemplo, digamos que determinado trecho de código verifica se existe conexão com a internet; caso haja, o programa executará determinada ação – seta verde;em caso contrário, executará outras ações – seta vermelha. A direção da seta mostra o fluxo do programa; setas para cima normalmente denotam uma situação de loop. É possível também destacar um texto; assim, todas as instâncias do mesmo texto são destacadas, auxiliando a encontrar padrões e repetições. Fonte: O autor. Figura 2: Modo gráfico do IDA Pro Já o modo de texto é uma visãomais tradicional da análise do binário e pode ser usado para análises mais profundas, verificando, por exemplo, outras seções do mesmo. A Figura a seguir exibe a visualização do modo de texto de um binário; o endereço de memória (0040105B) em vermelho, o nome da seção (seg002) e os opcodes em verde, e a instrução correspondente, ao lado direito, em amarelo. Fonte: O autor. Figura 3: Modo texto do IDA Pro Várias outras janelas do IDA Pro destacam itens específicos em um executável. Os itens a seguir são os mais significativos para nossos propósitos: • Janela de funções Lista todas as funções no executável e mostra o tamanho de cada uma. Você pode classificar por comprimento de função e filtrar por funções grandes e complicadas que provavelmente sejam interessante. • Janela de nomes Lista todos os endereços com um nome, incluindo funções, código, dados e strings. • Janela Strings Mostra todas as strings. Por padrão, essa lista mostra apenas strings ASCII com mais de cinco caracteres. Você pode alterar isso clicando com o botão direito na janela e selecionando Setup. • Janela de importações Lista todas as importações de um arquivo. • Janela de exportação Lista todas as funções exportadas para um arquivo. Esta janela é bastante útil quando analisamos DLLs. • Janela de estruturas Lista o layout de todas as estruturas de dados ativas. Essas janelas também oferecem um recurso de referência cruzada que é particularmente útil para localizar códigos interessantes. Exemplo Por exemplo, para encontrar todos os locais de código que chamam uma determinada função, você pode usar a janela de importação, clicar duas vezes na função importada de interesse e usar o recurso de referência cruzada para localizar a chamada de importação na listagem de código. É possível realizar buscas por determinados textos dentro da janela atual no IDA Pro; basta selecionar o menu Search e a opção texto (Text). Outra busca bastante útil é a busca por sequências de bytes, caso seja necessário fazer uma busca binária dentro do contexto. Pode-se buscar, também, por combinações de opcodes e por dados específicos. Outra possibilidade do IDA Pro é a referência cruzada, citada como xref no IDA Pro, que informa onde uma função é chamada ou onde uma string é usada, como pode ser visto na Figura 3. Vejamos um caso de uso. Você identifica uma função útil e precisa saber os parâmetros com os quais ela é chamada; você pode usar uma referência cruzada para navegar rapidamente até o local em que os parâmetros são colocados na pilha através da referência cruzada. Gráficos interessantes também podem ser gerados com base em referências cruzadas, que são úteis para realizar análises. Por padrão, o IDA Pro mostra apenas algumas referências cruzadas para as funções; normalmente existem muitas chamadas a uma função durante a execução de um programa. Caso queira ver todas as referências cruzadas para uma função, basta clicar no nome da função e pressionar a tecla ‘x’; surgirá uma janela que conterá uma lista com todos os locais em queesta função é chamada. Basta dar um clique duplo no item da lista para ir ao local da memória referenciado. Conforme falamos nas aulas anteriores, a análise estática de strings pode frequentemente ser usada como ponto de partida para sua análise. Se você vir uma string interessante, use o recurso de referência cruzada do IDA Pro para saber exatamente onde e como essa string é usada no código. Basta realizar o mesmo procedimento da função: Selecionar a cadeia de caracteres a ser verificada e pressionar a tecla ‘x’. Outra característica muito utilizada é a edição de nomes. Ao carregar um binário dentro do IDA Pro, as funções e variáveis recebem nomes sem muito sentido. Durante a análise, ao encontrar o significado da função, você pode renomear o nome da mesma. Basta modificar o nome desta função ou variável em apenas um local; a ferramenta propagará o nome em todas as referências cruzadas e ficará muito mais simples identificá-la no código. Comentário A capacidade do IDA Pro de realizar a desmontagem do binário é apenas uma das partes de sua funcionalidade; sua capacidade interativa é o seu maior fator de facilitação. Códigos em C x Assembly Na aula anterior, revisamos a arquitetura x86 e suas instruções mais comuns. Entretanto, analistas de malware experientes não avaliam cada instrução individualmente, a menos que seja estritamente necessário. O processo é muito tedioso e as instruções para um programa inteiro desmontado podem chegar a milhares ou até milhões. Como analista de malware, você deve ser capaz de obter uma imagem de alto nível da funcionalidade do código, analisando as instruções como grupos, focando em instruções individuais apenas quando necessário. Essa habilidade leva tempo para ser desenvolvida. Para começar a desenvolver essa habilidade, vamos pensar em como um autor de malware desenvolve o seu código. O artefato é normalmente desenvolvido usando uma linguagem de alto nível; para nosso estudo utilizaremos a linguagem C. A estrutura do código é um nível de abstração que define uma propriedade funcional, mas não os detalhes de sua implementação. Exemplos de estruturas de controle de código incluem: Laços de repetição, instruções de decisão, listas encadeadas, instruções do tipo escolhas múltiplas e outras. Os programas podem ser divididos em construções individuais que, quando combinadas, implementam a funcionalidade geral do programa. Vamos analisar algumas construções em linguagem de alto nível e seu respectivo código em assembly. O analista normalmente faz o caminho inverso, porém aprender na direção reversa é geralmente mais fácil. Por isso, vamos nos concentrar em como as construções mais comuns, como laços de repetições e instruções condicionais, são compiladas. Comentário Lembre-se de que seu objetivo é compreender a funcionalidade geral de um programa, não analisar todas as instruções. Mantenha isso em mente e não se prenda a minúcias. Concentre-se na maneira como os programas funcionam em geral, não em como eles fazem cada coisa em particular. Iniciaremos com simples operações matemáticas e sua correspondente instrução em assembly. Mas, antes de iniciarmos, devemos preparar o ambiente para testes. Além de todas as recomendações já mencionadas, utilizaremos uma ferramenta para programar e compilar os códigos criados. Dica Usaremos o programa Dev-C++ disponível em: https://orwelldevcpp.blogspot.com/ DI ou web, site de fonte não acadêmica (blog). Por favor, verificar se é para manter ou não. Fonte: O autor. Figura 4: Aritmética Simples Na Figura 4 podemos verificar algumas aritméticas simples. Nesse exemplo, x e y são variáveis locais porque são referenciadas pela pilha: x = esp+0c e y = esp+8 – lembrando que o registrador ESP aponta para o topo da pilha. Por questões de performance, as variáveis foram tratadas apenas na memória, não sendo rotuladas pelo IDA Pro. Primeiro, a variável é inicializada com os valores 4 e 5, respectivamente, nas instruções 1 e 2. Depois, acrescentamos 12 unidades (0x0C em hexadecimal) na terceira instrução. Então, a variável y é movida (copiada) para eax e subtrai-se de x o valor contido em eax, instruções 4 e 5. Por fim, as últimas duas instruções incrementam e decrementam em uma unidade o valor de y e x, respectivamente. Apesar de ser um exemplo simples, começamos a entender como as coisas acontecem dentro do processador. ondemand_videoVídeo Fonte: O autor. Figura 5: Estrutura condicional javascript:void(0); As estruturas de controle são bastante utilizadas para alterar a execução do programa com base em certas condições. A figura acima exibe uma instrução em C e com o assembly correspondente. Em uma estrutura condicional deve haver um salto condicional, mas nem todos os saltos condicionais correspondem a uma estrutura condicional. Como você podever na Figura 5, uma decisão deve ser tomada para execução de dois códigos diferentes. Essa decisão corresponde ao salto condicional (jnz) e é feita com base na comparação (cmp), que verifica se x é igual a y (esp+0C e esp+18, respectivamente). Se os valores não forem iguais, o salto ocorre e o código imprime na tela "x diferente de y."; caso contrário, o código continua o caminho de execução e imprime "x igual a y". ondemand_videoVídeo Atenção É importante que você reconheça que apenas um desses dois caminhos de código pode ser seguido. Fonte: O autor. Figura 6: Estrutura de repetição As estruturas de repetição são mecanismos muito utilizados e sempre possuem quatro componentes básicos: Inicialização Comparação Instruções de execução Incremento ou decremento Nesse exemplo, a inicialização define i como 0 (zero), a comparação verifica se i é menor que 10, a instrução printf será executada caso a condição seja atendida e, por fim, o incremento adicionará 1 a i. O ciclo ocorrerá até que i seja maior ou igual a 10. Em assembly: • A primeira instrução corresponde à etapa de inicialização. • A instrução 7 corresponde ao incremento. • A comparação ocorre na instrução 8. • Na instrução 9, a decisão é feita pelo salto condicional. Se o salto for executado, a instrução printf será executada e,em caso contrário, o programa seguirá o fluxo normal. ondemand_videoVídeo Chamadas de função No início da aula, discutimos como a pilha é usada para chamadas de função. As chamadas de função podem aparecer de formas diferentes no código assembly e as convenções de chamada definem a maneira como uma chamada de função ocorre. Essas convenções incluem dois aspectos: 1 A ordem em que os parâmetros são colocados na pilha ou nos registradores. 2 Se o chamador ou a função chamada é responsável por limpar a pilha quando a função for concluída. A convenção de chamada usada depende do compilador, entre outros fatores. Frequentemente, existem diferenças sutis em como os compiladores implementam essas convenções; portanto, pode ser difícil fazer a interface do código compilado por diferentes compiladores. No entanto, você precisa seguir certas convenções ao usar chamadas de funções do sistema operacional Windows; elas são implementadas de maneira uniforme para compatibilidade. Fonte: O autor. Figura 7: Definição e chamada de Funções Como podemos ver na Figura 7, a função é definida em outra parte da memória. 01 Nesse exemplo, o IDA Pro nomeou a função como __Z4somaii. Inicialmente, a função executa o prólogo (pushebp e movesp, ebp), alocando espaço para variáveis locais. Em nosso exemplo, a função recebe dois argumentos (arg_0 e arg_4), que são movidos para o registrador edx e eax, respectivamente. 02 Por fim, o registrador edx é adicionado ao eax e a função é finalizada com o seu epílogo (pop ebp e retn).Lembre-se de que, por convenção, os valores retornados de uma função sempre estarão no registrador eax. Portanto, a função não deve se preocupar em reservar uma área da memória para realizar qualquer operação, basta deixar sua operação no valor em eax. 03 Após verificarmos as operações realizadas pela função, vamos analisar agora como a mesma é chamada. Inicialmente, os valores da variável x e y são armazenados em esp+1C e esp+18, respectivamente. Depois, o registrador eax é utilizado para mover o valor de y e x para esp+4 e esp, respectivamente. Lembre-se de que esp aponta para o topo da pilha, portanto os valores estão sendo colocados ali. A instrução push existe para esse fim, mas por questões de performance o mov também pode ser usado. Depois,a função soma é chamada, passando os dois parâmetros através da pilha. A próxima instrução move para esp+4 o valor contido em eax. Você se lembra de onde vem esse valor? Exato, da própria função soma. Por fim, move-se para esp um ponteiro do tipo dword, de 4 bytes, que aponta para a área da memória que possui a string: “Valor retornado: %d”. Por fim, chama-se a função printf, que entende que o valor a ser substituído em %d está em esp+4. Com isso, fecha-se a execução do programa. Switch-case Para finalizar a aula de hoje, vamos analisar mais um exemplo. Outra estrutura de controle bastante utilizada, chamada de switch-case, está demonstrada na figura a seguir. Essas estruturas são usadas para fazer uma decisão baseada em alguma variável. Um Backdoor, por exemplo, pode se basear em um determinado valor de byte;caso receba o valor correto, ele executa determinada ação que facilitará a entrada do atacante; caso receba outro valor, ele pode hibernar por um determinado tempo. Esse tipo de estrutura é útil, e reconhecer suas instruções é vital para um bom analista. Fonte: O autor. Figura 8: Switch-case Como podemos ver na Figura 8, o compilador compara o valor de “i” e faz um salto condicional para o local da execução daquele caso. O último salto é incondicional, ou seja, se o valor não corresponder a nenhum dos casos criados, ele saltará para o loc_40144C que, no caso do código em C, é o valor default, que exibirá uma mensagem na tela de “Valor incorreto”. Pode parecer não natural em um primeiro momento, mas com o tempo e experiência a linguagem de baixo nível começará a fazer sentido. Lembre-se de que existem diversas outras estruturas em linguagens de alto nível; algumas delas poderão ser abordadas no decorrer do curso, as demais você deverá percorrer sozinho. Aula 5: Análise Dinâmica Avançada Apresentação Nesta quinta aula aprofundaremos nossa análise de malwares por meio de uma análise dinâmica avançada, abordando uma nova classe de ferramentas: Os depuradores. Veremos a utilização da ferramenta OllyDbg para análise em modo de usuário e finalizaremos com a ferramenta WinDbg para análise de malware em modo kernel. Objetivo • Identificar propriedades gerais de um depurador; • Examinar as funções básicas da ferramenta OllyDbg; • Analisar as funções básicas da ferramenta WinDbg. Debuggers Na última aula finalizamos o nosso foco da linguagem assembly e fizemos um paralelo entre uma linguagem em alto nível e sua correspondente estrutura em assembly. A análise dinâmica baseia-se no comportamento do binário. Para a sua análise utilizaremos os debuggers – depuradores, um software (ou hardware) usado para testar ou examinar a execução de outro programa. Os debuggers auxiliam no processo de desenvolvimento de software, pois possibilitam ao desenvolvedor acompanhar o passo a passo da lógica implementada. Eles são projetados para permitir que os desenvolvedores meçam e controlem o estado interno e a execução de um programa. Enquanto o disassembly oferece uma fotografia do programa imediatamente antes da execução da primeira instrução, o debugger fornece uma visão dinâmica de um programa enquanto ele executa, podendo-se verificar, por exemplo, os diferentes valores da memória. A possibilidade de medir e controlar a execução de um programa fornece uma profunda visão para o analista. Os depuradores permitem que você veja o valor de cada local de memória, registro e argumento para cada função, bem como alterar qualquer valor sobre a execução do programa, a qualquer momento. Saiba mais É possível, por exemplo, alterar o valor de uma única variável; basta saber seu local e o novo valor a ser preenchido. Focaremos nessa aula em dois depuradores: OllyDbg e WinDbg, ambos disponíveis em: http://www.ollydbg.de/ e https://docs.microsoft.com/en-us/windows- hardware/drivers/debugger/debugger-download-tools Redator ou DI, site com todos os direitos reservados. Por favor, verificar se é para manter aqui. Modo usuário e Kernel O Windows usa dois níveis de privilégio de processador: Modo kernel e modo de usuário. Comentário Quase todo código é executado no modo de usuário, exceto o próprio Sistema Operacional e drivers de hardware, que são executados no modo kernel.No modo de usuário, cada processo tem sua própria memória, permissões de segurança e recursos. Se um programa em modo de usuário executar uma instrução inválida e travar, o SO pode recuperar todos os recursos e encerrar o programa. Normalmente, o modo de usuário não pode acessar o hardware diretamente e é restrito a apenas um subconjunto de todos os registros e instruções disponíveis na CPU. javascript:void(0); javascript:void(0); Para manipular o hardware ou alterar o estado no kernel enquanto estiver no modo de usuário, você deve contar com as chamadas de sistema. Ao realizar este tipo de chamada do Windows que manipula estruturas do kernel, ela faz uma chamada para o kernel. Para encontrar esse uso durante a análise, basta buscar por instruções do tipo SYSENTER, SYSCALL ou INT 0x2E. Uma vez que não é possível transitar diretamente do modo de usuário para o kernel, essas instruções usam tabelas de pesquisa para localizar uma função predefinida para executar no kernel. Todos os processos em execução no kernel compartilham recursos e endereços de memória, com menos verificações de segurança. Se o código em execução no kernel for executado e contiver instruções inválidas, o sistema operacional não poderá continuar em execução, resultando na famosa tela azul do Windows. Código executado no kernel pode manipular código executado no espaço do usuário, mas o contrário é bem limitado. Embora todo o código em execução no kernel compartilhe memória e recursos, sempre há um único contexto de processo ativo. Execução de código no kernel é muito importante para os criadores de malware por suas possibilidades. A maioria dos programas de segurança, como antivírus e firewalls, são executados nesse modo, para que possam acessar e monitorar a atividade de todos os aplicativos em execução no sistema. Portanto, executar códigos diretamente em kernel possibilita ao código malicioso contornar e interferir mais facilmente nesse tipo de proteção. Além disso, os recursos de auditoria do sistema operacional não se aplicam ao kernel. Por esses motivos, quase todos os rootkits utilizam código para execução nesse modo. Ferramentas de depuração Existem diferentes ferramentas para depuração de modo de usuário e depuração de kernel. Para depuração de kernel utilizaremos o WinDbg. Para o modo de usuário utilizaremos o OllyDbg, já referenciados anteriormente. O WinDbg também oferece suporte à depuração no modo de usuário; o IDA Pro possui um depurador integrado, mas não oferece os mesmos recursos ou facilidade de uso que o OllyDbg. Existem duas maneiras de depurar um programa: Iniciar o programa com o depurador Quando você inicia o programa e ele é carregado na memória, ele para de ser executado imediatamente antes da execução de seu ponto de entrada. A partir daí, você tem controle total do programa. compare_ arrows Anexar o programa a um depurador Ao anexar o programa já em execução a um depurador, todos os threads do programa serão pausados e você pode depurá-lo. Essa é uma boa abordagem quando você deseja depurar um programa após sua execução ou se deseja depurar um processo afetado por malware. Podemos usar um depurador para três coisas: 1 Executar instrução a instrução um programa para ver exatamente o que está acontecendo internamente. 2 Definir breakpoints para obter informações sobre seções específicas da aplicação. 3 Modificar a execução de um programa a fim de obter informações adicionais. Execução do código instrução a instrução É possível executar um programa inteiro instrução por instrução via o “single-step”, mas você não deve fazer isso para programas complexos porque pode (e vai) demorar muito. Esse método é uma boa ferramenta para entender os detalhes de uma seção de código, mas você deve ser seletivo sobre qual código analisar. Concentre-se no quadro geral ou você se perderá nos detalhes. Ao percorrer o código instrução por instrução, o depurador para após cada instrução. No entanto, embora geralmente você esteja preocupado com o que um programa está fazendo, você pode não se preocupar com a funcionalidade de cada chamada de função. Por exemplo, se seu programa chama LoadLibrary, você provavelmente não deseja percorrer todas as instruções desta função. Existem dois controles de instruções bastante úteis no depurador: “step-into” e “step-over”. Ao selecionar o “step-over” antes de uma função ser chamada, o depurador executará toda a função e pausará na próxima instrução após o retorno da chamada de função. Se, por outro lado, selecionar “step-into” antes de uma função ser chamada, a próxima instrução que você verá no depurador é a primeira instrução da mesma. Este artifício é bastante útil para diminuir a quantidade de instruções a https://stecine.azureedge.net/webaula/estacio/go0682/aula5.html#collapse01-01 serem analisadas, porém tenha cuidado ao saltar todas as instruções, pois uma pode ser importante para a análise. Breakpoint Outro controle de instrução muito utilizado é o “breakpoint”, usado para pausar a execução e permitir que você examine o estado de um programa. Os pontos de interrupção são necessários porque você não pode acessar registros ou endereços de memória enquanto um programa está em execução, uma vez que esses valores estão mudando constantemente. Imagine o seguinte cenário: Você verificou que existe uma chamada a uma função do Windows: CreateFile. Para chamar essa função são necessários alguns parâmetros, um deles é o nome do arquivo a ser criado. Como já vimos, todos os parâmetros estarão na pilha, portanto basta colocar um breakpoint na chamada da referida função e analisar a pilha para verificar o nome do mesmo. Ressalta-se que tal nome pode não ser visível ao usar o IDA Pro, pois pode estar codificado. Alteração da execução do programa Outro uso muito útil para um depurador é a alteração da execução do programa. Você pode alterar as flags de controle, o ponteiro de instrução ou o próprio código do programa para modificar a maneira como ele é executado. Por exemplo, para evitar uma chamada de função, você pode definir um breakpoint onde a função é chamada. Quando o ponto de interrupção é atingido, você pode modificar o ponteiro da instrução para a instrução após a chamada, evitando que a chamada ocorra. Saiba que, caso a função seja particularmente importante, o programa pode não funcionar corretamente ou travar. Se a função não afetar outras áreas do programa, ele pode continuar em execução sem problemas. O Debugger é uma ferramenta crítica para obter informações sobre um programa malicioso que seria difícil de obter apenas por meio da desmontagem (Disassembly). https://stecine.azureedge.net/webaula/estacio/go0682/aula5.html#collapse01-02 https://stecine.azureedge.net/webaula/estacio/go0682/aula5.html#collapse01-03 Ollydbg Vejamos o OllyDbg e suas possibilidades durante a análise de malware enquanto ele está sendo executado. Escolhemos essa ferramenta por ser bastante popular entre analistas de malware e engenheiros reversos, por ser gratuito, fácil de usar e pelos plug-ins que aumentam sua capacidade. Para iniciar o processo de análise, você deve carregar o executável dentro da ferramenta. Existem algumas formas de fazê-lo: • Pode-se carregar o executável ou DLLs diretamente na ferramenta. • Caso o arquivo malicioso já esteja em execução, você pode anexar ao processo e depurá-lo. Características do programa Sistema flexível para execução do malware OllyDbg fornece, ainda, um sistema flexível para executar malware com opções de linha de comando ou para executar funcionalidades específicas dentro de uma DLL. A interface carregada é semelhante à da figura a seguir: Fonte: O autor. Figura 1: OllyDbg Layout 1 – Janela do desmontador Mostra o código (instruções) do programa analisado. Normalmente, a próxima instrução a ser executada estará em destaque nesta janela – primeirainstrução no alto. Para modificar instruções ou dados, ou adicionar novas instruções, basta selecionar a instrução a ser alterada e pressionar a barra de espaço. 2 – Janela de registradores Mostra o estado atual dos registradores para o programa antes da próxima instrução ser executada. Conforme elas vão sendo executadas, os registradores mudarão de valor. Todas as vezes em que um registrador for modificado após uma instrução, ele mudará da cor preta para a vermelha nessa janela. Assim como na janela anterior, é possível modificar os valores dos registradores à medida que o programa é depurado. 3 – Janela da pilha Essa janela mostra o estado atual da pilha na memória para o processo que está sendo depurado, e sempre mostrará o topo da pilha. Assim como as demais janelas, é possível manipular os valores presentes nessa área. OllyDbg coloca comentários úteis em alguns locais da pilha para identificar os argumentos colocados na pilha antes de uma chamada de função. https://stecine.azureedge.net/webaula/estacio/go0682/aula5.html#collapse01-04 https://stecine.azureedge.net/webaula/estacio/go0682/aula5.html#collapse01-05 https://stecine.azureedge.net/webaula/estacio/go0682/aula5.html#collapse01-06 4 – Janela da memória Essa janela mostra a área de memória ativa para o processo em depuração, sendo possível modificar/exibir qualquer área de memória desejado. E, obviamente, modificar os valores na memória como, por exemplo, variáveis globais e outros dados que o malware possivelmente armazenará na RAM. Existe uma outra janela muito utilizada: Mapeamento de memória, apresentada na figura a seguir. Nela são exibidos todos os blocos de memória alocados pelo programa depurado. No exemplo abaixo, mostramos o mapeamento de memória para a calculadora; tal visualização é uma boa forma de ver como um programa é organizado na memória. O executável é rotulado junto com seu código e seções de dados. Todas as DLLs e suas seções de código e dados também podem ser visualizadas. Ao clicar duas vezes em qualquer linha no mapa de memória, a ferramenta mostra todas as instruções dessa seção. Fonte: O autor. Figura 2: Mapeamento de Memória https://stecine.azureedge.net/webaula/estacio/go0682/aula5.html#collapse01-07 Verificação dos locais de memória das threads Alguns artefatos maliciosos podem gerar várias threads e é possível ver todas elas dentro do OllyDbg – basta clicar em View→Thread. Com isso será possível verificar os locais de memória de cada uma delas e seu status atual – ativo, pausado ou suspenso. Como a ferramenta OllyDbg é de thread único, pode ser necessário pausar todas as threads, definir um breakpoint e, em seguida, continuar a executar o programa para começar a depuração em uma thread específica. Comentário Quase todo código é executado no modo de usuário, exceto o próprio Sistema É possível matar qualquer thread, basta clicar com o botão direito sobre ela e selecionar a opção Kill. Diversos tipos de controle de execução Existem diferentes maneiras de executar código no OllyDbg e o conhecimento sobre elas será importante para o sucesso da depuração. As opções mais simples, Executar e Pausar, fazem com que um programa seja iniciado ou interrompido. Pausar A pausa é raramente usada, porque pode pausar o programa em um local que não seja muito útil. Em vez de usar a pausa, você normalmente desejará ser mais seletivo definindo pontos de interrupção – breakpoints, conforme já discutido. Executar A opção Executar é usada frequentemente para reiniciar um processo interrompido, geralmente após atingir um ponto de interrupção, a fim de continuar a execução. Executar até a seleção Outra opção útil é a opção Executar até Seleção que executará o código até a instrução imediatamente anterior a selecionada. Se a instrução selecionada nunca for executada, o programa será executado indefinidamente. Existem os passos já discutidos anteriormente – single-step, step-into e step-over. Portanto, o analista deve saber qual controle utilizar para poupar tempo e analisar apenas as partes mais importantes. https://stecine.azureedge.net/webaula/estacio/go0682/aula5.html#collapse01-08 https://stecine.azureedge.net/webaula/estacio/go0682/aula5.html#collapse01-09 https://stecine.azureedge.net/webaula/estacio/go0682/aula5.html#collapse01-10 Capacidade de carregar e depurar Outra possibilidade do OllyDbg é a capacidade de carregar e depurar DLLs. Como as DLLs não podem ser executadas diretamente, a ferramenta dispõe de um artifício usando um programa fictício chamado loaddll.exe para carregá-las. Essa técnica é extremamente útil, porque o malware geralmente vem empacotado como uma DLL, com a maior parte de seu código contido em sua função DllMain – trata-se da função de inicialização chamada quando uma DLL é carregada em um processo. Por padrão, OllyDbg é interrompido no ponto de entrada da DLL (DllMain) assim que a DLL é carregada. Para chamar funções exportadas com argumentos dentro da DLL depurada, primeiro deve-se carregar a DLL com OllyDbg; em seguida, quando ele parar no ponto de entrada da DLL, clique no botão reproduzir para executar o DllMain e qualquer outra inicialização que a DLL requer. O OllyDbg fará uma pausa e com isso será possível chamar exportações específicas com argumentos e depurá-los selecionando DebugCall DLL Export no menu principal. A partir daí é possível executar a função exportada e analisar seu comportamento. 01 Como verificamos, o OllyDbg é o depurador que possui muitos recursos para ajudá-lo a realizar análises dinâmicas de malware. Sua interface rica fornece muitas informações sobre o programa depurado. Os diversos tipos de controle de execução OllyDbg são úteis, e devem ser usados para facilitar a análise e orientar o foco para as partes mais importantes da aplicação analisada. 02 O depurador pode, ainda, modificar o comportamento dos binários em execução para forçar uma execução que não seja comum, e é possível salvar permanentemente as modificações feitas em um novo binário no disco. Há diversos plug-ins que podem ser usados para estender a funcionalidade do OllyDbg e fornecer benefícios além de seus recursos integrados. ondemand_videoVídeo WinDbg Embora OllyDbg seja o depurador de modo de usuário mais popular, ele não pode realizar análises no modo de kernel, como rootkits e drivers de dispositivo. Para esse propósito, mostraremos o WinDbg, uma ferramenta gratuita da própria Microsoft. Antes de começarmos a depurar algum código do kernel malicioso, é importante primeiro entender como ele funciona, as vantagens para os criadores de malware e alguns dos desafios desse tipo de código. Funcionamento do kernel no Windows O Windows possui os drivers de dispositivo, comumente conhecidos como drivers, responsáveis por permitir que desenvolvedores de aplicações executem códigos no kernel do Sistema Operacional. Os drivers são difíceis de analisar porque são carregados na memória e respondem às solicitações dos aplicativos. A coisa ainda complica um pouco mais porque os aplicativos não interagem diretamente com os drivers do kernel. Em vez disso, eles acessam objetos de dispositivo, que enviam solicitações a dispositivos específicos. Os dispositivos não são necessariamente componentes físicos de hardware; o driver cria e destrói dispositivos, que podem ser acessados no espaço do usuário. Vamos dar um exemplo para esclarecer um pouco mais essa dinâmica. Exemplo Consideremos uma unidade flash USB. Existe um driver no sistema que lida com unidades flash USB, mas, como já falamos, um aplicativo não faz solicitações diretamente a esse driver; ele faz solicitações a um objeto de dispositivo específico. Quando o usuário conecta a unidade flash USB ao computador, o Windows cria o objeto de dispositivo unidade “D:”. Um aplicativo agora pode fazer solicitações para a unidade D: que, por fim, serão enviadas ao driver para unidades flashUSB. Como você sabe, podemos inserir mais de uma unidade flash ao mesmo tempo em nossa máquina e o mesmo driver responderá às solicitações dessa segunda unidade flash USB, mas, para os aplicativos, ela será acessada por meio de um novo objeto de dispositivo, a unidade “E:”. Para que todo esse processo funcione, os drivers devem ser carregados no kernel, assim como as DLLs são carregadas nos processos. Quando um driver é carregado pela primeira vez, seu procedimento DriverEntry é chamado, semelhante ao DLLMain para DLLs. Ao contrário das DLLs, que expõem a funcionalidade por meio da tabela de exportação, os drivers devem registrar o endereço para funções de retorno de chamada, que serão chamadas quando um componente de software do espaço do usuário solicitar um serviço. O registro acontece na rotina DriverEntry. O Windows cria uma estrutura de objeto de driver, que é passada para a rotina DriverEntry. A rotina DriverEntry é responsável por preencher esta estrutura com suas funções de callback. A rotina DriverEntry então cria um dispositivo que pode ser acessado a partir do espaço do usuário, e o aplicativo do espaço do usuário interage com o driver enviando solicitações a esse dispositivo. Vantagens para o criadores de malware As chamadas de um aplicativo de modo de usuário para um driver de modo kernel são difíceis de rastrear devido ao código do sistema operacional que oferece suporte à chamada. A figura a seguir exemplifica uma requisição de um aplicativo no modo de usuário; eventualmente, atinge um driver de modo de kernel. Fonte: O autor. Figura 3: Chamadas do modo usuário tratadas pelo Kernel 01 Algumas solicitações são enviadas para drivers que controlam o hardware; outras afetam apenas o estado interno do kernel. Os drivers maliciosos geralmente não controlam o hardware; em vez disso, eles interagem com os principais componentes do kernel do Windows, ntoskrnl.exe e hal.dll. 02 O componente ntoskrnl.exe tem o código para as funções centrais do sistema operacional e hal.dll tem o código para interagir com os principais componentes de hardware. O malware geralmente importa funções de um ou de ambos os arquivos para manipular o kernel. Adaptado de Unsplash. Desafios do código A depuração no kernel é mais complicada do que depurar um programa de espaço do usuário pois, quando o kernel está sendo depurado, o sistema operacional está travado, o que torna impossível executar um depurador. Portanto, a maneira mais comum de depurar o kernel é com máquinas virtuais. Comentário Existe uma configuração básica para que o usuário consiga utilizar o WinDbg; deixamos ao leitor como tarefa a configuração e o uso da ferramenta. A O WinDbg utiliza uma interface de linha de comando para a maioria de suas funcionalidades. Abordaremos alguns dos comandos mais importantes, mas você pode navegar pela lista completa de comandos no menu Ajuda do WinDbg. Comando ‘d’ A janela de memória do WinDbg suporta navegação na memória diretamente da linha de comando. O comando ‘d’ é usado para ler locais na memória, como dados do programa ou a pilha, com a seguinte sintaxe básica: dx endereço – ‘x’ pode ser ‘a’ para leitura da memória em texto ASCII, ‘x’ pode ser ‘u’ para Unicode e ‘d’ para mostrar em 32-bits palavras duplas. Como podemos ver na figura a seguir, lemos a área da memória 0x80520C00. Fonte: O autor. Figura 4: Leitura da Memória via WinDbg É possível realizar operações na memória e registros diretamente via linha de comando usando operações aritméticas simples, como adição, subtração, multiplicação e divisão. Comando ‘dwo’ O comando ‘dwo’ é usado para referenciar um ponteiro de 32 bits e ver o valor naquele local. Caso queira ver o primeiro argumento de uma função, logo antes de ela ser executada, basta verificar o valor em esp+4. Para isso, basta utilizar o seguinte comando: dudwo (esp+4) Comando ‘bp’ O comando ‘bp’ é usado para definir pontos de interrupção básicos no WinDbg. Você também pode especificar comandos a serem executados automaticamente quando ele for atingido. Isso é usado com o comando ‘go’ (g), para que o ponto de interrupção execute uma ação e continue sem esperar pelo usuário. Por exemplo, o comando a seguir imprimirá o segundo argumento – localizado na pilha – sempre que a função GetProcAddress for chamada sem realmente interromper a execução do programa: bpGetProcAddress "da dwo(esp+8); g" Imagine um programa que cria e salva dados em arquivos do espaço do kernel. Para os autores de malware, o benefício desse procedimento no espaço do kernel é a dificuldade de detecção. Pode não ser a maneira mais furtiva de gravar em um arquivo, mas certamente passa desapercebido por certos produtos de segurança e pode enganar os analistas de malware que estão procurando por chamadas no espaço do usuário para as funções CreateFile ou WriteFile. As funções normais do Win32 não são facilmente acessíveis no modo kernel, o que representa um desafio para os autores de malware, mas existem funções semelhantes que são usadas regularmente em malware criado a partir do kernel. Como as funções CreateFile e WriteFile não estão disponíveis no modo kernel, as funções NtCreateFile e NtWriteFile são as correspondentes. Às vezes, o objeto do driver é difícil de encontrar, mas existem ferramentas que podem ajudar. Para entender como essas ferramentas funcionam, lembre-se de que os aplicativos interagem com os dispositivos, não com os drivers. No aplicativo de espaço do usuário, você pode identificar o objeto de dispositivo e, em seguida, usar o objeto de dispositivo para localizar o objeto de driver. Comando ‘!devobj’ Você pode usar o comando ‘!devobj’ para obter informações de objeto de dispositivo usando o nome do dispositivo especificado pela chamada CreateFile do código de espaço do usuário, como por exemplo: !devobjFileWriterDevide O objeto de dispositivo fornece um ponteiro para o objeto de driver; assim que você tiver o endereço do objeto de driver, poderá encontrar a tabela de funções principais. Depois de identificar o driver malicioso, talvez você ainda precise descobrir qual aplicativo o está usando. Uma das saídas do comando ‘!devobj’ é um identificador para o objeto de dispositivo. Comando ‘!devhandles’ Você pode usar esse identificador com o comando ‘!devhandles’ para obter uma lista de todos os aplicativos de espaço do usuário que possuem um identificador para esse dispositivo. Este comando itera por meio de cada tabela de tratamento para cada processo, o que pode demorar um tempo. Rootkits Voltando nossa atenção aos rootkits, eles modificam a funcionalidade interna do sistema operacional para ocultar sua existência. Fonte: Adaptado de Freepik Essas modificações podem ocultar arquivos, outros processos, conexões de rede e outros recursos de programas em execução, tornando difícil para antivírus, administradores e analistas de segurança descobrirem atividades maliciosas. A maioria dos rootkits em uso opera modificando de alguma forma o kernel. Embora os rootkits possam empregar uma gama diversificada de técnicas, na prática, uma técnica é usada mais do que qualquer outra: System Service Descriptor Table Hooking. Apesar de bastante antiga, essa técnica ainda é usada por malwares por sua facilidade de compreensão, flexibilidade e simplicidade de implementação. Conforme abordamos, o código do kernel só pode ser acessado no espaço do usuário por meio das instruções SYSCALL, SYSENTER ou INT 0x2E. As versões modernas do Windows usam a instrução SYSENTER, que obtém instruções de um código de função armazenado no registrador EAX. Caso o EAX contenha o valor de 0x25 e a instrução SYSENTER seja chamada, o sistema operacional consultará a tabela e executará a função NtCreateFile. Segue uma pequena amostra da SSDT: • SSDT[0x22] = 805b28bc (NtCreateaDirectoryObject) • SSDT[0x23] = 80603be0(NtCreateEvent) • SSDT[0x24] = 8060be48 (NtCreateEventPair) • SSDT[0x25] = 8056d3ca (NtCreateFile) • SSDT[0x26] = 8056bc5c (NtCreateIoCompletion) • SSDT[0x27] = 805ca3ca (NtCreateJobObject) Comentário Quando um rootkit se ‘engancha’ (hook) em uma dessas funções, ele altera o valor no SSDT para que o código do rootkit seja chamado em vez da função pretendida no kernel. No exemplo anterior, a entrada em 0x25 seria alterada para apontar para uma função dentro do driver malicioso. Essa mudança pode modificar a função de forma que seja impossível abrir e examinar o arquivo malicioso. Normalmente, é implementado em rootkits chamando o NtCreateFile original e filtrando os resultados com base nas configurações do rootkit. O rootkit simplesmente removerá todos os arquivos que deseja ocultar para evitar que outros aplicativos possam criar ou alterar os arquivos. Conclusão Finalizamos nossa visão geral dos depurados em nível de usuário e de kernel: OllyDbg e WinDbg, respectivamente. Malwares que usam o kernel não são comuns, mas existem, e os analistas de malware devem saber como lidar com isso. Aula 6: Funcionalidades de Malware Apresentação Analisaremos algumas funcionalidades padrões em artefatos,comportamentos de malwares e identificaremos padrões tanto para descriptografá-los quanto para gerar assinaturas de rede. Cada artefato é arquitetado para desempenhar sua função de forma diferente uns dos outros, porém os padrões se repetem e isso pode ser identificado e bloqueado. Objetivo • Interpretar padrões de comportamento de malware; • Diferenciar cifras simples de algoritmos criptográficos; • Identificar assinaturas de rede relevantes durante uma análise. Padrões de comportamento de malware Até agora, nos concentramos em analisar o programa e, em menor grau, o que ele pode fazer. Veremos então as características mais comuns de um programa que o identificam como malware. Tipos de malware Inicialmente, vamos relembrar os tipos de malware e relacioná-los com suas atividades. Para isso, analisaremos alguns comportamentos padrões de malware. Forneceremos uma espécie de resumo dos comportamentos mais comuns e uma base de conhecimento que permitirá o reconhecimento de uma variedade de aplicativos maliciosos. Comentário É humanamente impossível cobrir todos os tipos de malware, até porque novos tipos estão sempre sendo criados com recursos aparentemente ilimitados, mas é possível criar uma boa compreensão dos principais pontos que devemos procurar. Iniciadores e Baixadores Esses são os dois tipos de aplicações maliciosas mais comumente encontrados. Os baixadores (Downloaders), como o próprio nome indica, simplesmente baixam outro malware da Internet e o executam no sistema local. Normalmente, utilizam a função URLDownloadtoFileA do Windows, seguida de uma chamada para WinExec que executa a aplicação baixada. Esses são os dois tipos de aplicações maliciosas mais comumente encontrados. Os baixadores (Downloaders), como o próprio nome indica, simplesmente baixam outro malware da Internet e o executam no sistema local. Normalmente, utilizam a função URLDownloadtoFileA do Windows, seguida de uma chamada para WinExec que executa a aplicação baixada. Com isso finaliza-se o ciclo, uma aplicação aparentemente inofensiva e que não realiza nenhuma atividade suspeita ao ser analisada por um mecanismo de defesa, mas é a porta de entrada para uma outra aplicação realmente maliciosa. Um iniciador, também conhecido como carregador (Launchers), é qualquer executável que instala outro aplicativo para execução secreta ou não imediata ou futura. Os iniciadores geralmente contêm o malware para o qual foram projetados. Backdoors Um backdoor é um tipo de artefato que fornece ao invasor um acesso remoto à máquina da vítima, literalmente deixando uma porta dos fundos aberta a ele. Esse tipo de malware também é bastante encontrado e podem se camuflar em diversas formas e tamanhos, com uma ampla variedade de recursos. Vejamos algumas características dos backdoors: 01 Seu código normalmente implementa todo o conjunto de recursos necessários, portanto, ao usar este tipo de malware, os invasores normalmente não precisam baixar outro executável ou código adicional. 02 Comunicam-se pela Internet de várias maneiras, mas o método mais comum é pela porta 80 e usando o protocolo HTTP. Sendo esse o protocolo mais comum usado para tráfego de rede, oferece a melhor chance de passar desapercebido com o resto do tráfego. Comentário Ressalta-se que há um esforço no mundo para mudar o tráfego na internet para o protocolo HTTPs, ou seja, um tráfego criptografado. Muitos malwares já têm utilizado esse protocolo por dificultar, ainda mais, sua presença. Logo veremos como analisar esse tipo de tráfego a nível do pacote e criar assinaturas de rede mais eficazes. Por enquanto, vamos nos concentrar apenas na comunicação de alto nível. Apesar das diferenças, os backdoors possuem um conjunto comum de funcionalidades. Podemos citar a capacidade de manipular chaves de registro, enumerar janelas de exibição, criar diretórios, pesquisar arquivos e outras. Podemos determinar ainda quais desses recursos são implementados por ele, observando quais funções do Windows ele importa e usa. Uma ferramenta de administração remota (RAT) é usada para gerenciar remotamente um computador ou computadores. Eles são usados em ataques direcionados com objetivos específicos, como roubar informações ou mover-se lateralmente em uma rede. A Figura 1 a seguir mostra uma estrutura da rede RAT: Servidor está sendo executado em uma máquina da vítima que está rodando o malware. compare_ arrows Cliente está executando remotamente como uma unidade de comando e controle operada pelo invasor. Os servidores sinalizam para o cliente iniciar uma conexão e são controlados pelo cliente. A comunicação RAT é normalmente feita por portas comuns, como 80 e 443. Fonte: SIKORSKI (2012). Figura1: Estrutura de rede do RAT Qual é a diferença entre botnets e RATs? Vejamos: Botnets • infecta e controla dezenas de milhares de máquinas; • Todos os zumbis são controlados de forma única pelo botmaster; • realiza ataques em massa. RATs • normalmente, controlam apenas algumas máquinas; • tem um controle vítima por vítima, pois sua interação é mais personalizada e granular; • é usado para ataques direcionados. ondemand_videoVídeo Roubadores de credenciais As credenciais do usuário são ativos bastante valorizados no mundo do crime, por isso os invasores não medem esforços para roubá-las. Existem três formas de capturá-las: 1 Forma 1 Assim que o usuário efetua o login em algum serviço. 2 Forma 2 Vasculhar pelas credenciais armazenadas no Sistema Operacional, como hashes de senha, para serem usados diretamente ou decifrados localmente. 3 Forma 1 Registrar todas as teclas digitadas e armazenar essa informação, podendo ser em nível de usuário ou de kernel – sendo mais difícil de detectar. Mecanismos de persistências Uma vez que o artefato obtém acesso a um sistema, geralmente tentará permanecer por um longo tempo. Esse comportamento é conhecido como persistência. Existem diversas formas de atingir esse objetivo; a seguir, discutiremos alguns dos mais utilizados. Modificação do registro do sistema Um mecanismo bastante utilizado no Windows é a modificação do registro do sistema. Vimos anteriormente que o malware normalmente acessa o registro para acessar ou armazenar alguma informação. Existem registros que são utilizados pelo Sistema Operacional para determinar quais binários serão inicializados junto com o sistema. Por meios do registro é possível associar o binário a algum evento da logon do usuário, como, por exemplo, ao bloquear a tela. Trajonização Outra maneira pela qual o malware ganha persistência é por meio de uma técnica conhecida como “trojanização dos binários”do sistema. Com essa técnica, o malware se associa a outro binário do sistema para forçar sua execução na próxima vez que o binário infectado for executado ou carregado. Os autores de malware normalmente visam um binário do sistema que é usado com frequência na operação normal do Windows, sendo os arquivos DLLsalvos bastante populares. Uma forma simples de “trojanização” é o sequestro da função de entrada de um binário, fazendo o fluxo da aplicação saltar para uma área com código malicioso e depois retornar à execução normal do binário, sendo imperceptível ao usuário. Sequestro de ordem de carregamento de DLL Por fim, existe outro método que garante a persistência sem modificar o registro ou arquivos, conhecido como sequestro de ordem de carregamento de DLL. Trata-se de uma técnica simples que permite aos autores de malware criar DLLs maliciosas e persistentes sem a necessidade de uma entrada de registro ou binário trojanizado. Essa técnica nem mesmo exige um carregador malicioso separado, pois aproveita a maneira como as DLLs são carregadas pelo Windows. A ordem como o Sistema operacional carrega as bibliotecas de link dinâmicas são: Odiretório em quea aplicação é carregada; o diretório corrente; o diretório system32; o diretório system; o diretório windows e os diretórios listados na variável de ambiente. https://stecine.azureedge.net/webaula/estacio/go0682/aula6.html#collapse01-01 https://stecine.azureedge.net/webaula/estacio/go0682/aula6.html#collapse01-02 https://stecine.azureedge.net/webaula/estacio/go0682/aula6.html#collapse01-03 Caso um programa carregue uma DLL que esteja na pasta do Windows, e o malware crie uma DLL maliciosa com o mesmo nome e coloque-a dentro do diretório system, a aplicação carregará a DLL maliciosa dada a ordem de carregamento do sistema operacional. Com isso, o artefato malicioso sempre será carregado em memória quando a aplicação legítima for iniciada, causando a persistência. Escalações de privilégios A maioria dos usuários utiliza sua máquina como administradores locais, o que é um bom cenário para os atacantes. Isso significa que o usuário tem acesso de administrador na máquina e, consequentemente, o malware herdará os mesmos privilégios. Dica Não é recomendado utilizar sua máquina como administrador local pois, se você acidentalmente executar um arquivo malicioso, ele não terá acesso total ao seu sistema automaticamente. Mas isso não garante que o malware não obterá privilégios de administração, você apenas colocará uma pequena camada de proteção a mais. O malware precisará realizar um ataque de escalonamento de privilégios para obter acesso total. Vejamos algumas forma de escalação de privilégios: • Exploração de falhas de arquitetura ou de implementação do sistema operacional A maioria dos ataques de escalonamento de privilégios são explorações conhecidas ou ataques de dia zero (que não são de conhecimento público) contra o próprio sistema operacional local. Ou seja, existem falhas de arquitetura ou de implementação do sistema operacional que possibilitam que um usuário sem privilégios se torne um administrador do sistema, e os malwares tentaram o mesmo procedimento. • Exploração de falhas de arquitetura ou de implementação do sistema operacional Outra forma de escalação de privilégios pode ser a técnica que abordamos no item anterior, o sequestro de ordem de carregamento de DLL. Se o diretório em que a DLL mal-intencionada está localizada puder ser gravado pelo usuário e o processo que carrega a DLL for executado em um nível de privilégio mais alto, a DLL mal- intencionada obterá privilégios escalonados. Comentário Às vezes, mesmo quando o usuário está executando como administrador local, o malware precisará escalonar privilégios. Os processos em execução em uma máquina Windows são executados no nível do usuário ou do sistema. Os usuários geralmente não podem manipular processos em nível de sistema, mesmo se forem administradores. Para determinadas ações o malware precisará migrar para outro processo que tenha esse tipo de privilégio. Cobrindo a execução do malware Clique no botão acima. À medida que os sistemas de computador, suas proteções e os usuários se tornaram mais sofisticados, os aplicativos maliciosos também evoluíram. Um exemplo dessa evolução são as técnicas desenvolvidas para camuflar os artefatos em execução no cenário normal do Windows, pois muitos usuários já sabem como listar os processos com o Gerenciador de Tarefas do Windows – local onde o software malicioso costumava aparecer. Abordaremos alguns métodos utilizados para evitar a detecção, sendo importante ao analista entender como funciona a fundo cada um dos métodos, conhecer sua construção e os padrões de codificação para identificar o uso durante as execuções dos artefatos e identificar a execução de arquivos maliciosos de forma encoberta. Carregadores O carregador, conforme vimos na seção anterior, é um tipo de artefato que programa a execução de si mesmo ou de outro artefato. Portanto, seu objetivo é ocultar o comportamento malicioso do usuário. Os carregadores podem conter ou não o malware para o qual foram projetados para executar; como exemplo, podemos citar um executável ou uma DLL em sua própria seção de recursos. https://stecine.azureedge.net/webaula/estacio/go0682/aula6.html#complementar1 https://stecine.azureedge.net/webaula/estacio/go0682/aula6.html#complementar1 https://stecine.azureedge.net/webaula/estacio/go0682/aula6.html#complementar1 https://stecine.azureedge.net/webaula/estacio/go0682/aula6.html#complementar1 A seção de recursos no formato de arquivo do Windows PE é usada pelo executável e não é considerada parte dele. Exemplos do conteúdo normal da seção de recursos incluem ícones, imagens, menus e strings. Quando o carregador for executado, ele extrairá o executável ou a DLL embutida na seção de recursos antes de executá-lo. Injeção de processo A técnica mais utilizada para encobrir um malware é a injeção de processo. Como o próprio nome indica, essa técnica injeta código em outro processo em execução fazendo com que ele execute o código malicioso. Os atacantes usam a injeção de processo na tentativa de ocultar o comportamento malicioso de seu código e, às vezes, usam isso para tentar contornar mecanismos de segurança específicos de processo. Certas chamadas de função do Windows são comumente usadas para injeção de processo. A função Virtual Alloc Ex pode ser usada para alocar espaço na memória de um processo externo e Write Process Memory pode ser usada para gravar dados nesse espaço alocado. Este par de funções é essencial para diversas técnicas usadas para este tipo de injeção, como: Injeção de DLL – um processo externo é forçado a carregar uma biblioteca; e Injeção direta – aloca-se e insere dentro do espaço de memória de outro processo o código malicioso. Codificação de dados No contexto da análise de malware, o termo codificação de dados se refere a todas as formas de modificação do conteúdo com o objetivo de ocultar a intenção. Os malwares podem utilizar técnicas de codificação para mascarar suas atividades maliciosas, e você precisará entender essas técnicas para realizar uma engenharia reversa eficaz. Ao usar a codificação de dados, os atacantes escolherão um método que melhor atenda a seus objetivos. Pode ser desde cifras simples ou funções de codificação básicas fáceis de codificar e decodificar, mas que fornecem proteção suficiente até cifras criptográficas sofisticadas ou criptografia personalizada para dificultar a identificação e a engenharia reversa. Comentário É humanamente impossível cobrir todos os tipos de malware, até porque novos tipos estão sempre sendo criados com recursos aparentemente ilimitados, mas é possível criar uma boa compreensão dos principais pontos que devemos procurar. Os artefatos maliciosos podem usar a codificação para vários fins: a. Usos maiscomuns o criptografar da comunicação via rede e o evitar o bloqueio dos controles de segurança. b. Outros usos o disfarçar seu funcionamento interno. o ocultar informações de configuração, como um domínio de comando e controle; o salvar informações em um arquivo de teste antes de roubá-lo; o armazenar strings usadas pelo malware e decodificá-las antes de serem necessárias; o disfarçar o artefato como uma ferramenta legítima, ocultando as sequências de caracteres usadas para atividades maliciosas. Nosso objetivo ao analisar algoritmos de codificação sempre consistirá em duas partes: 1 Identificar as funções de codificação. 2 Usar o conhecimento sobre as funções de codificação para decodificar as informações do binário. Cifras simples Cifras simples costumam ser menosprezadas por não serem sofisticadas, mas oferecem algumas vantagens para malware, como a necessidade de pequena quantidade de espaço para suas instruções e menos performance para operar as ações. Os atacantes que utilizam uma cifra simples não esperam ser imunes à detecção, eles estão procurando uma maneira fácil de evitar que a análise básica identifique suas atividades. Um exemplo de cifra simples já abordado em aulas anteriores é o uso do operador XOR e suas propriedades. Sobre a criptografia é importante considerarmos os seguintes aspectos: A criptografia moderna leva em consideração os recursos de computação em crescimento exponencial e garante que os algoritmos sejam projetados para exigir tanto poder computacional que quebrar a criptografia é impraticável. A criptografia evoluiu e se desenvolveu ao longo do tempo e agora está integrada a todos os aspectos do uso do computador, como SSL em um navegador da web ou a criptografia usada em um ponto de acesso sem fio. O uso dessa criptografia em malwares pode ser desvantajoso, pois as bibliotecas criptográficas podem ser grandes e um código teria que carregar integralmente a biblioteca ou apontar para um código já existente, o que diminuiria a portabilidade do mesmo. Muitos algoritmos criptográficos utilizam uma chave forte para criptografar os dados. A ideia é que o algoritmo em si seja amplamente conhecido, mas sem a chave é quase impossível descriptografar o texto cifrado. Para garantir uma quantidade suficiente de trabalho para descriptografar, a chave geralmente deve ser longa o suficiente para que todas as chaves potenciais não possam ser testadas facilmente. Para esses casos, o objetivo do analista é identificar o algoritmo e a chave. Identificação do uso de criptografia Existem várias maneiras fáceis de identificar o uso da criptografia padrão como a procura de strings e importações que fazem referência a funções criptográficas, bem como o uso de várias ferramentas para pesquisar conteúdo específico. 01 O IDA Pro possui um plugin chamado FindCrypt2 que procura no programa por constantes conhecidas por estarem associadas a algoritmos criptográficos. Apesar de simples, essa técnica é bastante útil e pode ser bastante reveladora. 02 Alguns artefatos podem usar esquemas de codificação próprios, por meio de vários métodos de codificação simples para criar uma camada criptográfica, dificultando a identificação. Por exemplo, uma aplicação pode executar uma rodada de criptografia XOR e, em seguida, executar a codificação Base64 no resultado. 03 Outro tipo de esquema é simplesmente desenvolver um algoritmo personalizado, possivelmente com semelhanças com um algoritmo criptográfico padrão publicado. Apenas a experiência vai auxiliar no processo de identificação de criptografia. Tanto os atacantes quanto os analistas de malware aprimoram continuamente seus recursos e habilidades. Em um esforço para evitar a detecção e frustrar os analistas, os atacantes estão cada vez mais empregando medidas para proteger suas intenções, técnicas e comunicações, utilizando, para isso, a codificação e a criptografia. A codificação afeta mais do que apenas as comunicações, também dificulta a análise e compreensão do artefato. Felizmente, com as ferramentas adequadas, muitas técnicas em uso podem ser identificadas e combatidas com relativa facilidade. Assinaturas de rede A maior parte dos malwares faz uso intenso da conectividade de rede, sendo importante saber reconhecer para desenvolver contramedidas eficazes baseadas em rede, identificando e barrando futuros usos do mesmo artefato em outra máquina de sua organização. As contramedidas são ações tomadas em resposta a ameaças, para detectar ou prevenir atividades maliciosas. Para desenvolver contramedidas eficazes, você deve entender como o malware usa a rede e como os desafios enfrentados pelos autores de malware podem ser usados em seu favor. Contramedidas As contramedidas são ações tomadas em resposta a ameaças, para detectar ou prevenir atividades maliciosas. Para desenvolver contramedidas eficazes, você deve entender como o malware usa a rede e como os desafios enfrentados pelos autores de malware podem ser usados em seu favor. Primeiro precisamos definir o que são atributos básicos da atividade de rede, que podem ser: Endereços IP, portas TCP e UDP, nomes de domínio e até o próprio conteúdo de tráfego. Comentário Esses atributos são usados por dispositivos de rede e segurança para fornecer defesas, como os firewalls e roteadores, que podem ser usados para restringir o acesso a uma rede com base em endereços IP e portas. Os servidores DNS podem ser configurados para redirecionar domínios maliciosos conhecidos para um host interno, conhecido como sumidouro (sinkhole);com isso, o malware acreditará estar se comunicando com o domínio malicioso, porém é ativo que nós controlamos. E os servidores proxy podem ser configurados para detectar ou impedir o acesso a domínios específicos. Sistemas de detecção de intrusão (IDSs), sistemas de prevenção de intrusão (IPSs) e outros dispositivos de segurança possibilitam o emprego de contramedidas baseadas em conteúdo. Os sistemas de defesa baseados em conteúdo permitem uma inspeção mais profunda do tráfego, como assinaturas de rede usadas por um IDS e algoritmos usados por um proxy de e-mail para detectar spam. Como indicadores básicos de rede, endereços IP e nomes de domínio são suportados pela maioria dos sistemas defensivos, geralmente são os primeiros itens que um analista de malware investiga. 01 Dentro de um contexto real, a primeira etapa na análise de malware não deveria ser executar o malware em um ambiente de laboratório ou abrir o malware e começar a analisar o código desmontado. Em vez disso, você deve primeiro revisar todos os dados que já possui sobre o malware. 02 Ocasionalmente, um analista recebe um executável suspeito, sem qualquer contexto, mas na maioria das situações você pode adquirir dados adicionais. A melhor maneira de iniciar a análise de malware com foco na rede é explorar os logs, alertas e capturas de pacotes que já foram gerados pelo artefato. 03 Os detalhes verificados na atividade do software malicioso podem fornecer percepções exclusivas que vão acelerar a análise, e o tráfego revelará informações sobre o servidor ao qual o malware se conecta. Além disso, ao revisar passivamente as informações, não há risco de que suas atividades de análise vazem para o invasor. Exemplo Você está analisando um malware e ao executá-lo ele faz uma requisição DNS para o domínio www.jogosonline.com.br; depois, ele faz uma requisição HTTP do tipo POST para o endereço IP traduzido pelo servidor DNS. Até este ponto temos dois indicadores de atividades maliciosas de rede: O domínio e seu respectivo endereço IP requisitado e a requisição HTTP do tipo POST e seu conteúdo. Indicadores básicos Indicadores básicos, como endereços IP e nomes de domínio, podem ser valiosos para a defesa contra uma versão específica do malware, mas seu valor pode durar pouco, já que os invasores são adeptos da movimentaçãorápida para diferentes endereços ou domínios. javascript:void(0); compare_ arrows Indicadores baseados em conteúdo Os indicadores baseados em conteúdo, por outro lado, tendem a ser mais valiosos e duradouros, pois identificam malware por meio de características mais fundamentais. Sistemas de detecção de Intrusão baseados em assinatura são os sistemas mais antigos e mais comumente implantados para detectar atividades maliciosas por meio do tráfego de rede. A detecção depende do conhecimento sobre a assinatura das atividades maliciosas. Ao identificá-la, basta criar uma assinatura para ele; com isso, ele será detectado ao acontecer novamente. O elemento mais valioso para a geração de assinaturas são os dados que estão dentro do malware, ou seja, ao desenvolver a aplicação, o autor armazenou todas as informações dentro do código. O tráfego de rede enviado por malware será construído a partir de um conjunto limitado de fontes originais. A criação de uma assinatura eficaz requer conhecimento da origem de cada parte do conteúdo da rede. O malware que usa chamadas de função de rede do Windows nas camadas mais baixas, como o Winsock, requer mais conteúdo gerado manualmente para imitar um tráfego comum do que um que utiliza uma chamada de função de rede em camadas mais superiores como uma interface COM. Mais conteúdo manual significa mais dados embutidos em código, o que aumenta a probabilidade do autor da aplicação cometer algum erro que você possa usar para gerar uma assinatura. Dica Ao projetar uma estratégia de assinatura, é aconselhável tentar entender a perspectiva do invasor. Os atacantes estão jogando um jogo constante de gato e rato. Sua intenção é se misturar ao tráfego regular para evitar a detecção e manter as operações em andamento bem- sucedidas. Como qualquer desenvolvedor de software, os invasores estão sempre atualizando suas aplicações para mantê-los compatíveis com os sistemas em constante mudança. Todas as alterações necessárias devem ser mínimas, pois grandes alterações podem ameaçar a integridade de seus sistemas. Conforme discutido anteriormente, o uso de várias assinaturas que visam diferentes partes do código malicioso torna a detecção mais resistente às modificações do invasor. Frequentemente, os invasores mudam ligeiramente seu software para evitar a detecção por uma assinatura específica. Ao criar várias assinaturas que identificam diferentes aspectos da comunicação, você ainda pode detectar o malware com êxito, mesmo que o invasor tenha atualizado uma parte do código. Aula 7: Contra Engenharia Reversa Apresentação Nesta sexta aula analisaremos algumas técnicas utilizadas contra a engenharia reversa. Algumas delas já foram mencionadas, como as técnicas contra a execução do malware em ambientes virtualizados, por exemplo. Agora aprofundaremos como essas técnicas serão utilizadas e, mais importante, como identificar e contornar durante a análise. Objetivo • Identificar técnicas de anti-desmontagem; • Identificar técnicas de anti-depuração; • Identificar características dos empacotadores. Contra Engenharia Reversa Vimos nas aulas anteriores diversas formas de analisar os artefatos maliciosos, hoje veremos algumas técnicas utilizadas contra a análise da aplicação. Algumas técnicas já foram abordadas de forma superficial. Vamos aprofundar e aprender como reconhecer algumas delas. Anti-desmontagem A anti-desmontagem é uma técnica que utiliza códigos ou dados especialmente criados no programa para confundir as ferramentas de análise de desmontagem atrasando ou, em determinadas situações, impedindo a análise de código. Lembre-se de que todo malware é projetado com um objetivo específico em mente, com os avanços das técnicas de detecção foi necessário criar técnicas específicas para camuflar do usuário essas intenções. Qualquer aplicação ou pedaço de código que pode ser executado também pode ser submetido à engenharia reversa, mas existem técnicas que os autores podem utilizar para proteger seu código, aumentando o grau de habilidade exigido do analista de malware. O tempo de investigação em artefatos com esse tipo de proteção é incrementado pela incapacidade do analista de malware compreender seus recursos e suas assinaturas. Essas camadas adicionais de proteção podem exaurir o nível de habilidade interna em muitas organizações e exigir consultores especializados apenas para realizar a engenharia reversa. Além de atrasar ou impedir a análise humana, quando bem realizada, é possível, também, prevenir certas técnicas de análise automatizada e, com isso, evitar mecanismos de proteção de segurança. Muitos algoritmos de detecção de similaridade de atividades maliciosas e mecanismos heurísticos de antivírus empregam análises automatizadas para identificar ou classificar a aplicação maliciosa. Comentário A desmontagem não é uma técnica simples de ser realizada. Uma sequência de código pode ter várias representações diferentes, algumas podem ser inválidas e ofuscar a funcionalidade real do programa. Ao implementar a anti-desmontagem, o atacante cria uma sequência que engana o desmontador para mostrar uma lista de instruções que diferem daquelas que serão executadas. As técnicas funcionam se aproveitando de suposições e limitações das ferramentas de desmontagem. Uma técnica simples é deslocar em apenas um byte a execução de uma instrução, pois os desmontadores representam cada byte de um programa como parte de uma instrução por vez. Essa técnica pode causar um desajuste em toda a árvore de códigos e uma instrução válida pode ser camuflada e passar desapercebida pelo analista. Exemplo 1 Vamos analisar o seguinte exemplo de Sikorski: jmp short nearptr loc_2+1 loc_2: callnearptr 15FF2A71h or [eax], dl inceax Esse fragmento de código foi desmontado usando a técnica de desmontagem linear e o resultado não reflete a realidade. Verifica-se uma instrução de chamada para um ponto de memória sem referência. Como podemos verificar, a primeira instrução é uma instrução de salto cujo destino é 1 byte após o início da instrução. Exemplo 2 Ao analisar a mesma sequência de bytes desmontada com uma estratégia diferente e saltando o byte referenciado no salto, obtemos o seguinte conjunto de instruções: jmp short loc_3 db E8h loc_3: push 2Ah callSleep Esse novo fragmento revela uma sequência totalmente diferente de mnemônicos de instruções e parece ser mais informativo. Aqui, vemos uma chamada para a função de Sleep. O destino da instrução de salto agora está representado corretamente e podemos ver que ele salta para uma instrução push seguida pela chamada para Sleep. Atenção O byte na segunda linha do Exemplo 2 é 0xE8, mas esse byte não é executado pelo programa porque o salto o ignora. Comentário No Exemplo 2, foi utilizado um desmontador orientado ao fluxo, diferente do desmontador linear usado no primeiro exemplo. O segundo caso foi mais preciso porque sua lógica se baseia na execução do programa ao invés da desmontagem de todos os bytes na área de código, mesmo daqueles que não fazem parte do fluxo de execução do mesmo. Portanto, uma desmontagem não é tão simples quanto você pode imaginar. Os exemplos acima apresentam dois conjuntos de instruções completamente diferentes para o mesmo conjunto de bytes. As técnicas de anti-desmontagem nascem de fraquezas inerentes aos algoritmos de desmontagem. Qualquer desmontador deve fazer certas suposições para apresentar o código que está desmontando claramente. Quando essas suposições falham, o atacante tem a oportunidade de enganar o analista. Existem dois tipos de algoritmos de desmontagem, conforme já mencionados: Linear e orientado a fluxo. Desmontagem linear A desmontagem linear é mais fácil de implementar, mas também é mais sujeita a erros. A estratégia de desmontagem linear itera sobre um bloco de código, desmontando uma instrução porvez linearmente, sem desvios. Essa estratégia básica é amplamente usada por depuradores. A desmontagem linear usa o tamanho da instrução desmontada para determinar qual byte desmontar a seguir, sem levar em conta as instruções de controle de fluxo. Desmontagem orientada por fluxo Uma categoria mais avançada de algoritmos de desmontagem é o desmontador orientado a fluxo. Esse é o método usado pela maioria dos desmontadores comerciais, como o IDA Pro. Desmontagem orientada por fluxo versus desmontagem linear Clique no botão acima. O A principal diferença entre a desmontagem orientada por fluxo e linear é que o desmontador não itera cegamente em uma parte da memória, assumindo que os dados nada mais são do que instruções agrupadas ordenadamente. Em vez disso, ele examina cada instrução e constrói uma lista de locais a serem desmontados. Na desmontagem linear, o desmontador não tem escolha a fazer sobre quais instruções desmontar em um determinado momento. Os desmontadores orientados ao fluxo fazem escolhas e suposições. Ramificações condicionais fornecem ao desmontador orientado ao fluxo uma escolha de dois locais para desmontar: A ramificação verdadeira ou falsa. Em um código gerado por compilador típico, não haveria diferença na saída se o desmontador processasse primeiro o branch verdadeiro ou https://stecine.azureedge.net/webaula/estacio/go0682/aula7.html#collapse01-01 https://stecine.azureedge.net/webaula/estacio/go0682/aula7.html#collapse01-02 https://stecine.azureedge.net/webaula/estacio/go0682/aula7.html#complementar1 https://stecine.azureedge.net/webaula/estacio/go0682/aula7.html#complementar1 https://stecine.azureedge.net/webaula/estacio/go0682/aula7.html#complementar1 https://stecine.azureedge.net/webaula/estacio/go0682/aula7.html#complementar1 falso, no código de montagem. No entanto, as duas ramificações podem produzir desmontagens diferentes para o mesmo bloco de código. Quando há um conflito, a maioria dos desmontadores confia primeiro em sua interpretação inicial de um determinado local;os desmontadores orientados a fluxo processarão a ramificação falsa de qualquer salto condicional primeiro. Outra técnica bastante comum é a inserção de duas instruções de saltos condicionais consecutivos que apontam para o mesmo alvo. Exemplo Por exemplo, se um jz local_1 for seguido por jnz local_1, esse local será sempre executado. A combinação de jz com jnz é, portanto, um jmp incondicional, mas o desmontador não o reconhece como tal porque ele desmonta apenas uma instrução por vez. Quando o desmontador encontra o jnz, ele continua desmontando o falso branch dessa instrução, apesar do fato de que nunca será executado na prática. Existem alguns casos, sob algumas condições, em que nenhuma lista de montagem tradicional representará com precisão as instruções que são executadas, conhecido como desmontagem impossível. As técnicas simples de anti-desmontagem que discutimos usam um byte de dados colocado estrategicamente após uma instrução de salto condicional, com a ideia de que a desmontagem começando nesse byte impedirá que a instrução real que se segue seja visualizada. Contornamos essa situação ignorando o byte, mas e se ele não puder ser ignorado? E se for parte de uma instrução legítima que é realmente executada em tempo de execução? Aqui, encontramos um cenário complicado em que qualquer byte pode fazer parte de várias instruções que são executadas. Nenhum desmontador atualmente no mercado representará um único byte como parte de duas instruções, embora o processador não tenha essa limitação. Como não há como remover pedaços do código para que todas as instruções em execução sejam representadas, devemos escolher quais instruções devemos deixar. Essa é uma solução um tanto aceitável porque mostra apenas as instruções relevantes para a compreensão do programa. No entanto, essa solução pode interferir nos processos de análise. A anti-desmontagem não se limita às técnicas abordadas nessa aula, existem diversas técnicas que visam tirar proveito das dificuldades inerentes à análise. Ferramentas de desmontagens avançadas fazem um excelente trabalho para determinar quais instruções constituem um programa, mas ainda exigem suposições e escolhas no processo. Para cada escolha ou suposição que pode ser feita por um desmontador, pode haver uma técnica anti-desmontagem correspondente. Anti-Depuração A anti-depuração é uma técnica contra- análise usada pelos malwares para reconhecer quando está sob o controle de um depurador ou para impedir o controle sobre o mesmo. Ao perceber que está sendo executado em um ambiente controlado, a aplicação pode alterar seu fluxo normal de execução ou modificar o código para causar uma falha, interferindo assim nas tentativas dos analistas de compreendê-lo. Existem muitas técnicas anti-depuração, discutiremos algumas das mais populares que encontramos no mundo real. O malware usa uma variedade de técnicas para verificar as indicações de que um depurador está conectado, seja por chamadas de função do Windows, seja através de uma verificação manual da estrutura da memória por artefatos de depuração ou, ainda, procurando no sistema por qualquer possível traço deixado por um depurador. A detecção do depurador é a maneira mais comum de o malware realizar a anti-depuração. O uso de chamada de funções do Windows é a mais óbvia das técnicas anti-depuração. O Windows fornece várias funções que podem ser utilizadas por um programa para determinar se ele está sendo depurado. Algumas dessas funções foram projetadas para detecção do depurador; outras foram projetadas para finalidades diferentes, mas podem ser reaproveitadas para detecção de um depurador. Normalmente, a maneira mais fácil de superar uma chamada para uma dessas funções de anti-depuração é modificar manualmente o malware durante a execução para não executar a chamada, ou modificar a flag após o retorno da chamada para garantir que o fluxo pretendido seja seguido. Uma opção mais difícil seria fazer um gancho (hook) dessas funções, assim como com um rootkit. Listaremos três funções e suas características: IsDebuggerPresent Função mais simples para detectar um depurador. Essa função pesquisa a estrutura PEB (ProcessEnvironmentBlock) para o campo IsDebugged, que retornará zero se você não estiver executando no contexto de um depurador, ou um valor diferente de zero se um depurador estiver anexado. CheckRemoteDebuggerPresent Função semelhante à anterior, apesar do nome, ela não verifica o depurador em uma máquina remota, mas sim localmente. Também verifica a estrutura PEB para o campo IsDebugged; no entanto, pode fazer isso para si mesmo ou para outro processo na máquina local. Essa função recebe um identificador de processo como parâmetro e verificará se esse processo possui um depurador anexado. https://stecine.azureedge.net/webaula/estacio/go0682/aula7.html#collapse01-03 https://stecine.azureedge.net/webaula/estacio/go0682/aula7.html#collapse01-04 NtQueryInformationProcess Função nativa em Ntdll.dll que recupera informações sobre um determinado processo. O primeiro parâmetro para essa função é um identificador de processo; a segunda é usada para informar à função o tipo de informação do processo a ser recuperado. Por exemplo, usar o valor ProcessDebugPort (valor 0x7) para esse parâmetro informará se o processo em questão está sendo depurado. Se o processo não estiver sendo depurado, um zero será retornado; caso contrário, um número de porta será retornado. Usar chamadas de função do Windows pode ser o método mais óbvio para detectar a presença de um depurador, mas a verificação manual das estruturas é o método mais comum usado pelos atacantes. Existem algumas desvantagens no uso de chamada de funções do Windows para anti-depuração. Exemplo Por exemplo, as chamadas de função podem ser conectadas por um rootkit para retornar informaçõesfalsas. Portanto, os autores de malware frequentemente optam por realizar o equivalente à chamada de função manualmente, em vez de depender do Windows. Ao realizar verificações manuais, vários sinalizadores na estrutura PEB fornecem informações sobre a presença de um depurador. Ao analisar malware, normalmente, usamos ferramentas de depuração, que deixam resíduos no sistema. O malware pode pesquisar esse resíduo para determinar quando você está tentando analisá-lo, por exemplo, pesquisando nas chaves de registro por referências para depuradores. A seguinte chave de registro é um local comum para um depurador: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug Essa chave de registro especifica o depurador que é ativado quando ocorre um erro de aplicativo. O malware também pode pesquisar o sistema em busca de arquivos e diretórios, como executáveis de programas de depuração comuns, que normalmente estão presentes durante a análise de malware. Ou o malware pode detectar resíduos na memória ativa, exibindo a lista de processos atuais ou, mais comumente, executando FindWindow em busca de um depurador. https://stecine.azureedge.net/webaula/estacio/go0682/aula7.html#collapse01-05 Os depuradores podem ser usados para definir pontos de interrupção ou para dar uma única etapa em um processo para ajudar o analista de malware na engenharia reversa. No entanto, quando essas operações são realizadas em um depurador, elas modificam o código no processo. Algumas técnicas anti-depuração podem ser usadas pelo malware para detectar esse tipo de comportamento do depurador, como varredura INT e verificações de tempo. 01 A instrução INT 3 é a interrupção de software usada por depuradores para substituir temporariamente uma instrução em um programa em execução e para chamar o manipulador de exceção de depuração: Um mecanismo básico para definir um ponto de interrupção. 02 O opcode para INT 3 é 0xCC;sempre que você usa um depurador para definir um ponto de interrupção, ele modifica o código inserindo um 0xCC. 03 As verificações de tempo são uma das maneiras mais populares de o malware detectar depuradores, pois os processos são executados mais lentamente durante o processo de depuração. Por exemplo, uma única etapa em um programa reduz substancialmente a velocidade de execução. Existem algumas maneiras de usar verificações de tempo para detectar um depurador: Registrar a data/hora, executar algumas operações, registrar novamente a data/hora e depois comparar os dois registros. Se houver um atraso, você pode presumir a presença de um depurador. Registrar a data/hora antes e depois de gerar uma exceção. Se um processo não estiver sendo depurado, a exceção será tratada de forma instantânea; um depurador tratará a exceção muito mais lentamente. Por padrão, a maioria dos depuradores requer intervenção humana para lidar com exceções, o que causa um enorme atraso. Embora muitos depuradores permitam que você ignore as exceções e as transmita ao programa, ainda haverá um atraso considerável em tais casos. Por padrão, a maioria dos depuradores requer intervenção humana para lidar com exceções, o que causa um enorme atraso. Embora muitos depuradores permitam que você ignore as exceções e as transmita ao programa, ainda haverá um atraso considerável em tais casos. Dica Existem diversas técnicas populares de anti-depuração; é preciso paciência e perseverança para aprender a reconhecer e contorná-las. Certifique-se de fazer anotações durante sua análise e lembre-se da localização de todas as técnicas anti-depuração e como você as contorna; isso o ajudará se você precisar reiniciar o processo de depuração. A maioria das técnicas anti-depuração pode ser detectada usando o bom senso, ao depurar um processo lentamente. Por exemplo, se você vir o código terminando prematuramente em um salto condicional, isso pode sugerir uma técnica anti-depuração. Obviamente, como em todas as análises de malware, a melhor maneira de aprender a impedir as técnicas usadas é persistência. As técnicas estão em constante evolução e sempre aparecerão novas maneiras de anti-depuração. ondemand_videoVídeo Anti-máquina virtual Atacantes utilizam técnicas anti-máquina virtual (anti-VM) para impedir as tentativas de análise, pois elas são muito utilizadas para esse fim. Com essas técnicas, o malware tenta detectar se está sendo executado dentro de um ambiente virtual. Caso positivo, ele pode agir de forma diferente da forma pretendida ou, simplesmente, não funcionar e, com isso, atrapalhar sua identificação por parte do analista. As técnicas anti-VM são mais comumente encontradas em malwares enviados em massa, como bots, scareware e spyware. Isto se dá, principalmente, porque as honeypots costumam usar máquinas virtuais e, também, porque esse malware normalmente tem como alvo uma máquina do usuário final, que dificilmente usará uma máquina virtual — em tese. A popularidade desse tipo de técnica diminuiu recentemente devido ao aumento no uso da virtualização. Essa técnica surgiu em um tempo em que as máquinas virtuais eram utilizadas em grande maioria para análise. No entanto, hoje, tanto administradores quanto os usuários finais utilizam as máquinas virtuais por sua facilidade e versatilidade de uso. Por isso, os atacantes não utilizam essa técnica com tanta frequência, pois não significa necessariamente que não seja uma vítima valiosa apenas por se tratar de uma máquina virtual. Pela popularidade, focaremos em algumas técnicas utilizadas para detecção de uma máquina virtual rodando na solução VMWare. Nesse ambiente existem diversos artefatos no sistema, especialmente quando o VMware Tools está instalado. O malware pode usar esses artefatos, que estão presentes no sistema de arquivos, registro e lista de processos, para detectar a virtualização. A Figura 1 a seguir mostra a lista de processos para uma máquina virtual Windows rodando com o VMware Tools instalado. Fonte: Autor. Figura1: Listagem de Processos em uma máquina VMWare Observe que três processos VMware estão em execução: Vmware Tools Core Service (vmtoolsd.exe), duas vezes, e VmwareGuestAuthentication Service (VGAuthService.exe). Qualquer um deles pode ser encontrado pelo malware enquanto ele pesquisa a lista de processos para a string “VMware”. Outra forma de verificar a presença do serviço em execução é através da listagem de serviços na máquina, que pode ser verificadana Figura 2 a seguir: Fonte: Autor. Figura 2: Listagem de serviços e sua filtragem Existem diversas formas, na verdade, de identificar um ambiente virtualizado. Dica Os dispositivos de hardware virtualizados, como a placa de rede, por exemplo, sempre terão uma marca do VMware. O endereço do MAC da placa de rede sempre iniciará com os mesmos 3 bytes: 00:0C:29. A Figura 3 a seguir mostra o registro do identificador do disco da máquina: Fonte: Autor. Figura3: Registro do Hardware Outro comando que pode ser utilizado é a busca pela string “VMware” pelo registro, conforme a Figura 4 a seguir: Fonte: Autor. Figura 4: Busca pela stringVMware no registro Os artefatos mais comuns do VMware podem ser facilmente eliminados desinstalando o VMware Tools ou interrompendo o VMware Tools Service; fazendo isso, já deixará um pouco mais difícil para o malware. Outra solução é impedir que o mesmo procure pelos artefatos. Por exemplo, se você encontrar uma única string relacionada ao VMware no malware, como: “net start | findstrVMware” – você sabe que o malware está tentando detectar artefatos;basta você identificar o trecho do código que realiza essa busca e evitá-la. Outra técnica utilizada para reconhecer se está em um ambiente virtualizado é a busca da string malware na memória. O VMware deixa muitos rastros na memória como resultado do processo de virtualização. Algumas são estruturas críticas do processador que,por serem movidas ou alteradas em uma máquina virtual, deixam rastros reconhecíveis. O VMware tem suas vulnerabilidades, que podem ser exploradas para travar o sistema operacional da máquina física ou até mesmo executar código nele. Muitas vulnerabilidades divulgadas são encontradas no recurso de pastas compartilhadas da VMware ou em ferramentas que exploram a funcionalidade de arrastar e soltar (copiar e colar) do VMware Tools. Outra vulnerabilidade abusa das pastas compartilhadas para permitir que um convidado escreva em qualquer arquivo no sistema operacional da máquina física a fim de modificar ou comprometer seu sistema operacional. Embora essa técnica específica não funcione com a versão atual do VMware, várias falhas diferentes foram descobertas no recurso de pastas compartilhadas. Portanto, na dúvida, desative as pastas compartilhadas nas configurações da máquina virtual para evitar esse tipo de ataque. Agora, você já entendeu as formas utilizadas para descobrir se a máquina é virtual ou não. Como os autores de malware usam essas técnicas para retardar a análise, é importante ser capaz de reconhecê-las. Abordamos algumas delas para que você possa encontrá-las na desmontagem ou depuração, e enumeramos algumas maneiras de superá-las sem a necessidade de modificar o malware no nível de desmontagem. Comentário Ao realizar a análise dinâmica básica, você sempre deve usar uma máquina virtual. No entanto, se o malware em questão não parece funcionar, considere tentar outra máquina virtual com o VMware Tools desinstalado antes de depurar ou desmontar o malware em busca da detecção da máquina virtual. ondemand_videoVídeo Você também pode executar o malware em questão em um ambiente virtual diferente (como VirtualBox ou Parallels) ou mesmo em uma máquina física. Empacotadores e desempacotadores Os programas de empacotamento, ou empacotadores, tornaram-se extremamente populares entre os criadores de malware pois auxiliam no processo de camuflagem e evasão de sistemas de segurança, complicando o trabalho do analista e reduzindoo tamanho de um executável malicioso. Em geral, os empacotadores possuem as seguintes características: Fácil utilização, gratuitos e de código aberto, ou seja, seu código fonte está disponível. O processo de compactação inutiliza a análise estática, pois o processo de compactação remove padrões. Para que a análise estática seja eficaz, é preciso inicialmente descompactar a aplicação primeiro, o que, muitas vezes, não é uma tarefa simples. Embora haja uma grande variedade de empacotadores, todos seguem um padrão semelhante: 1 Transformam um executável original em um novo executável que consiste em duas partes básicas. 2 O executável original é transformado em dados e uma rotina de desempacotamento será chamada pelo sistema operacional ao executá-lo. Vamos discutir algumas informações básicas sobre como eles funcionam e como reconhecê-los. Ao receber um programa malicioso para analisar, ele estará empacotado com um algoritmo, inicialmente, desconhecido do analista. Para ter um acesso ao arquivo original, o analista precisará fazer o caminho reverso do empacotador;para isso, o analista deve ter conhecimento do processo realizado para que possa revertê-lo. Para entender esse processo, vamos analisar o fluxo geral de como os empacotadores funcionam. Eles atuam de forma semelhante a um compactador comum, recebe um arquivo executável como entrada e produz um outro arquivo como saída. Porém, em contraste aos compactadores, o arquivo de saída deve ser independente, ou seja, não deve depender de outro programa para realizar seu objetivo. Função de um empacotador Clique no botão acima. Um empacotador pode compactar, criptografar ou realizar qualquer outra operação com o objetivo de modificar o arquivo original. O objetivo desse tipo de ferramenta é dificultar o reconhecimento e a engenharia reversa, podendo executar, também, as técnicas discutidas na aula de hoje como anti-desmontagem, anti-depuração ou anti-VM. https://stecine.azureedge.net/webaula/estacio/go0682/aula7.html#complementar2 https://stecine.azureedge.net/webaula/estacio/go0682/aula7.html#complementar2 Os empacotadores podem empacotar todo o executável, incluindo todos os dados e a seção de recursos, ou empacotar apenas o código e as seções de dados. Para manter a funcionalidade do programa original, o empacotador precisa armazenar algumas informações do mesmo. Essas informações podem ser armazenadas em qualquer formato e existem várias formas para isso. Os executáveis são carregados pelo sistema operacional, mas, no caso dos empacotados, a rotina de desempacotamento é carregada pelo sistema operacional e, em seguida, ela carrega o programa original. O ponto de entrada do código para o executável aponta para essa rotina e não para o código original. O programa original geralmente é armazenado em uma ou mais seções extras do arquivo. Essa rotina estará em claro para o analista de malware e entender suas diferentes partes é fundamental para o entendimento do artefato original. Ela é geralmente pequena, pois não contribui para a funcionalidade principal do programa, e sua função é tipicamente simples: Desempacotar o executável original. A rotina de desempacotamento executa três etapas: Fonte: Autor. Uma etapa inicial ao analisar malware é reconhecer se ele está ou não empacotado. Abordamos algumas técnicas para essa detecção em aulas anteriores. A lista a seguir resume os sinais a serem observados que auxiliarão nesse processo: • O programa tem poucas importações, principalmente se as únicas importações forem LoadLibrary e GetProcAddress. • Quando o programa é aberto no IDA Pro, apenas uma pequena quantidade de código é reconhecida pela análise automática. • Quando o programa é aberto em OllyDbg, há um aviso de que o programa pode estar empacotado. • O programa mostra nomes de seção que indicam um empacotador específico (como UPX0). • O programa tem tamanhos de seção anormais, como uma seção de texto com um tamanho de dados brutos de 0 e tamanho virtual diferente de zero. Ferramentas de detecção de empacotador, como PEiD, também podem ser usadas para facilitar nessa parte do processo. Os executáveis compactados também podem ser detectados por meio de uma técnica conhecida como cálculo de entropia. Os dados compactados ou criptografados se parecem mais com os dados aleatórios e, portanto, têm alta entropia; executáveis que não são criptografados ou compactados têm entropia mais baixa. ondemand_videoVídeo Fonte: madartzgraphics / Pixabay. Existem programas automatizados de descompactação estática que desempacotam e/ou descriptografam o executável. Esse é o método mais rápido e, quando funciona, é o mais simples, pois não depende da execução da aplicação e restaura o executável ao seu estado original. Os programas de desempacotamento estático são específicos para um único empacotador e não funcionam naqueles projetados para impedir a análise. Comentário Lembrando que não existe solução “bala de prata”, se esta operação falhar em determinar onde a rotina termina, todo o processo falhará. Às vezes, o malware empacotado pode ser desempacotado automaticamente por um programa existente, mas com mais frequência esse processo deve ser feito manualmente. Tal ação pode ser feita rapidamente, com o mínimo de esforço; mas também pode ser um processo longo e árduo. Como mencionamos, sempre haverá essa corrida do gato e rato, do analista e do atacante, com criação de novas técnicas e novas formas de confundir o analista, o atacante estará sempre fugindo. Nenhuma estratégia ou ferramenta única funcionará em todos os casos, então você precisa estar familiarizado com várias técnicas. Aula 8: Investigando Malwares via Análise de Memória – Windows Apresentação Nessa oitava aula veremos algumas técnicas utilizadas paraanálise de memória para busca de atividades maliciosas em ambiente de Windows. Muitas vezes um analista não receberá um executável para analisar, e sim uma máquina possivelmente infectada para entãoencontrar o binário malicioso. Para isso, você deverá utilizar algumas ferramentas que apresentaremos a seguir. Objetivo • Identificar vantagens da aplicação Volatility; • Identificar técnicas de aquisição de memória; • Reconhecer recursos internos do ambiente Windows. Análise de Memória Já abordamos as diversas técnicas a serem empregadas nos momentos em que o analista recebe o artefato malicioso. Mas e se uma máquina de seu parque tecnológico estiver se comportando de forma anormal e você for designado para verificá-la? Quais procedimentos devem ser adotados? Deveria, você, buscar todos os arquivos na máquina até encontrar, por sorte, o arquivo malicioso? Essa não seria a melhor forma de proceder. Por isso, vamos abordar um assunto muito difundido: Perícia forense de memória. A perícia da memória é considerada por muitos a parte mais interessante e desafiadora da perícia digital. Cada função executada por um sistema operacional ou aplicativo resulta em modificações específicas na memória do computador (RAM), que muitas vezes podem persistir por muito tempo após a ação, essencialmente preservando-as, dada a arquitetura de Von-Neumann. Além disso, a análise forense de memória fornece visibilidade do estado de tempo de execução do sistema, como quais processos estavam em execução, conexões de rede abertas e comandos executados recentemente. Saiba mais É possível extrair artefatos da memória de forma independente do sistema operacional que se está investigando, reduzindo a chance de que malwares, especialmenteos rootkits, possam interferir em seus resultados. Os dados críticos geralmente existem exclusivamente na memória, como chaves de criptografia de disco, fragmentos de código injetados na memória, mensagens de e-mail não criptografadas e registros de histórico da Internet não armazenáveis em cache. Aprendendo a capturar a memória do computador e definir o perfil de seu conteúdo, você adicionará um recurso inestimável à sua análise de malware. Embora a inspeção de discos rígidos e capturas de pacotes de rede possam produzir evidências convincentes, muitas vezes é o conteúdo da RAM que permite a reconstrução completa dos eventos e fornece as peças do quebra-cabeça necessárias para determinar o que aconteceu antes, durante e após uma infecção por malware. Vamos iniciar a análise de peculiaridades do sistema operacional Windows, mas antes vamos abordar uma poderosa ferramenta que usaremos ao decorrer da aula: O volatility framework. Volatility Framework O Volatility é uma coleção de ferramentas de código aberto implementada na linguagem Python, ou seja, todo o código fonte está disponível para que qualquer um possa analisar e alterar. Profissionais o utilizam para extração de artefatos digitais de amostras de memória volátil (RAM). Como o Volatility é de código aberto e uso gratuito, você pode baixar o framework e começar a realizar análises avançadas. Além disso, nada o impede de aprender todo o código fonte e explorá-lo em todo seu potencial. Uma grande vantagem para essa abordagem é o apoio da comunidade, que cria e lança complementos que auxiliam cada vez mais a vida do analista. O comando mais básico é construído da seguinte maneira:Executa-se o script Python principal (vol.py) e, em seguida, passa o caminho para o arquivo de memória, o nome do perfil e o plug-in a ser executado (e, opcionalmente, parâmetros específicos do plug-in): javascript:void(0); $ python vol.py –f <NOMEARQUIVO> --profile=<PROFILE><PLUGIN> [ARG] como:$ python vol.py –f /home/memory.dmp --profile=Win7SP1x64 pslist Abordando os benefícios do uso da ferramenta em detrimento a outras, podemos citar alguns, além do fato de sua gratuidade. Volatility pode analisar memórias de 32 ou 64 bits dos sistemas operacionais Windows, Linux e Mac. Dada a sua implementação modular, é fácil realizar as modificações para que ele suporte novos sistemas operacionais e arquiteturas à medida que sejam lançados. Além disso, ele possui uma interface de programação de aplicação (API) extensível e programável, ou seja, a forma de interação com ele é simples e pode ser modificada conforme a sua necessidade. Ele possui uma compatibilidade ampla de formatos de arquivos que ele aceita. Comentário Conforme mencionamos, possui uma comunidade séria, dedicada e poderosa, bem como reúne colaboradores de empresas comerciais, policiais e instituições acadêmicas em todo o mundo. Aproveitamos para ressaltar algumas coisas que a aplicação não é ou não possui. Ele não é uma ferramenta de aquisição de memória, você deve utilizar outra aplicação e analisá-lo com o Volatility. Não possui uma interface gráfica, é uma ferramenta de linha de comando e possui uma biblioteca Python que possibilita a importação de aplicativos. Por fim, trata-se de uma aplicação que não está isenta de erros, a análise forense de memória pode ser frágil e sensível por natureza. Aquisição de memória Aquisição de memória, ou seja, sua captura, envolve a cópia do conteúdo da memória volátil para um armazenamento não volátil. Essa é, sem dúvida, uma das etapas mais importantes e precárias no processo de perícia da memória. Infelizmente, muitos analistas confiam cegamente nas ferramentas de aquisição sem parar para considerar como essas ferramentas funcionam ou os tipos de problemas que podem encontrar. Como resultado, eles analisam imagens de memória corrompidas, evidências destruídas e recursos de análise limitados. 01 Fundamentalmente, a aquisição da memória é o procedimento de cópia do conteúdo da memória física para outro dispositivo de armazenamento para preservação e posterior análise. Porém, existem questões importantes associadas ao acesso aos dados armazenados na memória física e sua posterior gravação dos dados. 02 Os métodos e ferramentas específicos utilizados geralmente dependem dos objetivos da investigação e das características do sistema que está sendo investigado. Um analista busca preservar o estado do ambiente digital para realizar inferências confiáveis por meio da análise. Os dados armazenados no disco e na RAM são dois dos componentes mais importantes desse ambiente. 03 Como mencionado anteriormente, a aquisição de memória não é uma tarefa trivial. Será necessário um conjunto de ferramentas versátil e uma capacidade de adaptar suas técnicas com base nas especificidades de cada caso e ambientes que encontrar. Antes de adquirir memória física de um sistema suspeito, você deve sempre considerar o risco associado. Como a maioria dos sistemas operacionais não fornece um mecanismo nativo compatível para adquirir memória física, você usará o sistema de uma maneira que pode deixá-lo em um estado inesperado. Além disso, um sistema com malware pode ser instável e se comportar de maneira imprevisível. O Volatility realiza diversas ações, menos a aquisição de memória. Para isso, relacionamos algumas ferramentas que podem ser utilizadas com esse objetivo. • AccessData FTK Imager Suporta diversos tipos de dados para serem adquiridos, incluindo a memória RAM. • Winpmem É a única ferramenta de aquisição de memória de código aberto para Windows. Inclui a capacidade de gerar arquivos em formato bruto de memória, escolher entre vários métodos de aquisição e expor a memória física por meio de um dispositivo para análise ao vivo de um sistema local. • MoonSols Windows Memory Toolkit É um utilitário que combina as ferramentas de aquisição de despejo de memória de 32 e 64 bits em um executável que requer apenas um único clique para operar. Nenhuma outra interação é necessária. Existem outras, como FastDump e Memoryze, que são lançadas constantemente. A aquisição de memória físicacom precisão requer planejamento adequado, ferramentas robustas e adesão às melhores práticas. Considere cuidadosamente suas opções com base no ambiente e nas especificações de cada trabalho antes de escolher uma técnica ou ferramenta, pois seus recursos de análise dependem de uma aquisição bem-sucedida. Lembre-se também de que a evidência de memória é frequentemente encontrada em mídia não volátil e pode vir em vários formatos e tamanhos. Esteja ciente dos diferentes formatos, como converter entre os formatos, caso necessário, e os desafios que cada tipo de amostra de memória apresenta. Windows Focaremos nessa aula no sistema operacional Windows e, na próxima, falaremos sobre o Linux. Para realizarmos a análise é necessário entender o funcionamento geral e as peculiaridades desses sistemas. Por isso, vamos abordar alguns aspectos básicos para o entendimento, pois todos os artefatos que estão na memória compartilham uma origem comum: Todos eles começam como uma alocação. Como, quando e por que as regiões de memória foram alocadas as diferencia, além dos dados reais armazenados dentro e ao redor delas. Comentário Do ponto de vista da perícia de memória, estudar essas características pode ajudá-lo a fazer inferências sobre o conteúdo de uma alocação, levando à sua capacidade de localizar e rotular tipos específicos de dados em um grande despejo de memória. Além disso, familiarizar-se com os algoritmos do sistema operacional para alocação e desalocação de memória pode ajudá-lo a entender o contexto dos dados ao encontrar, por exemplo, se eles estão atualmente em uso ou marcados como livres. Objetos e Alocações de Kernel O sistema operacional Windows faz bastante uso de estruturas em C para organizar os dados e atributos. Algumas dessas estruturas são chamadas de “ExecutiveObjects” por serem criadas, removidas e atualizadas pelo gerenciador de objetos do Windows. Saber distinguir é importante para identificar todas as estruturas que serão utilizadas pelos artefatos na memória, como, por exemplo, manipulação de arquivos, criação de conexões, captura de teclas, dentre outras. Todas essas ações deixam um rastro na memória. Um “Kernel Pool” é uma faixa de memória que pode ser dividida em blocos menores para armazenar qualquer tipo de dados que um componente do modo kernel solicitar. Semelhante a um heap, cada bloco alocado tem um cabeçalho (_POOL_HEADER) que contém informações de depuração. Você pode usar esses dados extras para associar blocos de memória utilizados pelo driver que os possui e, até certo ponto, fazer inferências sobre o tipo de estruturas ou objetos contidos nessa alocação. Processos, Variáveis de ambiente e Registros Cada processo tem seu próprio espaço de memória virtual privado, que é isolado de outros processos. Dentro desse espaço de memória, você pode encontrar o executável do programa que gerou o processo, sua lista de módulos carregados (DLLs ou bibliotecas compartilhadas), suas pilhas, heaps e regiões de memória alocadas contendo tudo, desde a entrada do usuário até estruturas de dados específicas do aplicativo, como tabelas SQL, logs de histórico da Internet e arquivos de configuração. Como objetivos durante a análise, em termos de processos, devemos verificar alguns pontos: 1 Processos internos Verifica como o sistema operacional rastreia os processos e como as chamadas de funções do Windows os enumeram, mostrando a razão de as ferramentas dinâmicas serem tão facilmente enganadas. 2 Identifica os processos críticos do Windows Mostra como os sistemas normais operam. Você estará mais preparado para detectar anomalias, especialmente aquelas que envolvem tentativas de se misturar a processos críticos. 3 Gera visualizações Aprenda a criar visualizações que ilustram as relações de pai e filho entre processos. Isso ajuda a determinar a cadeia de eventos que levou ao início de um determinado processo, o que geralmente é muito importante ao montar um incidente. 4 Detecta manipulação direta de objetos do kernel (DKOM) Encontra tentativas de ocultar processos alterando uma ou mais listas de processos na memória do kernel. Todo processo possui uma data de criação, de saída, um número único, um duplo linkpara um processo anterior e um futuro – gerando uma cadeia de processos ativos. Além disso, ele possui uma lista de Threads e a seção a qual pertence, responsável pela execução dos códigos do processo. O Windows possui alguns processos considerados críticos que cuidam das atividades essenciais. São considerados críticos, pois, se algum deles entrar em um estado instável ou fechar por algum motivo, muito provavelmente o sistema operacional irá travar e precisará reiniciar. O Volatility fornece alguns comandos que podem ser utilizados para extrair informações sobre os processos: • pslist: Encontra e percorre a lista duplamente vinculada de processos e imprime um resumo dos dados. Esse método normalmente não mostra processos encerrados ou ocultos; • pstree: Formata a saída do comando anterior em uma visualização em árvore, para que você possa ver facilmente os relacionamentos pai e filho; • psscan: Procura por objetos do tipo _EPROCESS em vez de confiar na lista vinculada. Este plugin também pode localizar processos encerrados e não vinculados (ocultos); e • psxview: Localiza processos usando listagens de processos alternativos, para que você possa cruzar referências de diferentes fontes de informação e revelar discrepâncias maliciosas. ondemand_videoVídeo Variáveis de ambiente são atalhos que os programas utilizam para procurar por executáveis, ou seja, é um valor nomeado dinamicamente que pode afetar o modo como os processos em execução irão se comportar em um computador. Todo processo possui variáveis de ambiente que são apontadas pela estrutura de PEB – ProcessEnvironmentBlock. Alguns malwares marcam sua presença criando variáveis de ambiente; é importante, portanto, saber como verificar entradas suspeitas. O registro de sistema: É um banco de dados que contém várias configurações para o funcionamento do sistema Windows, aplicativos e usuários em um computador. Sendo um componente central, é acessado constantemente durante o funcionamento do computador. A falta de tratamento e observação das inconsistências de dados podem apresentar resultados errados. Análises sobre o mesmo assunto podem apresentar resultados diferentes, prejudicando a tomada de decisão. Portanto, faz sentido que o sistema armazene em cache todos ou parte dos arquivos de registro na memória. Além disso, o registro do Windows contém uma grande quantidade de informações úteis para fins de análise. Com ele, você pode determinar quais programas foram executados recentemente, extrair hashes de senha para fins de auditoria ou investigar chaves e valores que o código malicioso introduziu no sistema. ondemand_videoVídeo Injeção de código A aplicação maliciosa aproveita a injeção de código para realizar ações dentro do contexto de outro processo. Ao fazer isso, ela pode forçar um processo legítimo a executar ações em seu nome, como baixar outros programas ou roubar informações do sistema. Os atacantes podem injetar código em um processo de várias maneiras, como escrever na área de memória do processo remoto diretamente ou adicionar uma chave de registro que faz com que novos processos criados carreguem uma DLL de escolha do invasor. Atenção É importante determinar se algum processo no sistema foi vítima de injeção de código e, em caso afirmativo, como extrair os segmentos de memória que contêm código malicioso. Formas de injeção de código: Injeção remota de DLL Um processo malicioso força o processo de destino a carregar uma DLL especificada do disco, chamando as funções: LoadLibrary ou LdrLoadDll. Por definição, a DLL deve existir no disco antes de ser injetada. Injeção remota de código Um processomalicioso escreve código no espaço de memória de um processo alvo e força sua execução. O código pode ser um bloco de instruções ou pode ser um binário cuja tabela de importação é configurada preventivamente para o processo de destino. Injeção reflexiva de DLL Um processo malicioso escreve uma DLL, como uma sequência de bytes, no espaço de memória de um processo de destino. A DLL lida https://stecine.azureedge.net/webaula/estacio/go0682/aula8.html#collapse01-01 https://stecine.azureedge.net/webaula/estacio/go0682/aula8.html#collapse01-02 https://stecine.azureedge.net/webaula/estacio/go0682/aula8.html#collapse01-03 com sua própria inicialização sem a participação do carregador do Windows. Nesse tipo de ataque, a DLL não precisa existir no disco antes de ser injetada. Injeção de processo oco (Hollow) Um processo malicioso inicia uma nova instância de um processo legítimo no modo suspenso. Antes de retomá-lo, as seções executáveis são liberadas e realocadas com código malicioso. Investigação de rede Quase todo malware tem algum tipo de capacidade de rede, seja trocar dados com um servidor de comando e controle, seja para se espalhar para outras máquinas ou, ainda, para criar um backdoor no sistema. O sistema operacional Windows deve manter o estado e passar os pacotes recebidos para o processo ou driver correto, tudo isso através de chamadas de funções, com registro na memória por meioda criação de artefatos. Além disso, os invasores, sejam remotos ou locais, inevitavelmente deixam rastros de suas atividades de rede nos históricos do navegador, caches DNS e outros. Comentário É vital a compreensão de como os artefatos de rede são criados na memória e quais fatores são mais importantes para sua investigação. Os dois principais tipos de artefatos de rede são os sockets e as conexões. Sockets Os sockets efinem terminais para comunicações https://stecine.azureedge.net/webaula/estacio/go0682/aula8.html#collapse01-04 compare_ arrows Conexão Criam soquetes de cliente para iniciar conexões com servidores remotos, bem como criam soquetes de servidor para ouvir em uma interface as conexões de entrada. O Windows fornece algumas formas de criação: 1 Direto do modo de usuário Os aplicativos podem chamar a função de socket da API Winsock2 (ws2_32.dll). 2 Indireto do modo de usuário Os aplicativos podem chamar funções em bibliotecas como WinINet (wininet.dll), que fornecem invólucros em torno das funções Winsock2. 3 Direto do modo kernel Os drivers de kernel podem criar socket por meio do uso da Interface de driver de transporte (TDI), que é a interface principal para a pilha de transporte usada por componentes de nível superior, como Winsock2. Como analista, existem alguns pontos que você deverá analisar, como identificar portas abertas indevidamente distinguindo entre sockets legítimos e aqueles que estão sendo usados para aceitar conexões de entrada de invasores. Exemplo Se um servidor de arquivos estiver escutando na porta 21 (FTP), isso é esperado; mas se hospedou documentos que foram roubados pode ser que o malware utilizou esse meio para exfiltração de dados. Outra possibilidade é a revelaçãode conexões remotas suspeitas;uma das maneiras mais comuns de os investigadores aproveitarem os artefatos de rede na memória é analisar as conexões remotas. Um processo específico no sistema acessou uma porta TCP em um servidor em um país estrangeiro? Um programa estava usando um cliente TOR para navegar na web? O malware está se comunicando com seu comando e controle usando um protocolo de bate-papo em tempo real, como Jabber ou IRC? Todas essas informações são importantes para identificar o agente malicioso em ação na máquina. Outra ação importante para o analista é detectar portas ocultas em sistemas ativos, pois muitos rootkits filtram portas e endereços IP desviando chamadas de funções em sistemas ativos. Como a análise forense de memória não depende dessas chamadas no sistema operacional, esses desvios são facilmente visíveis e não têm efeito. Assim, ao comparar os dados disponíveis para você por meio das chamadas de funções do Windows em uma máquina ativa com o que o Volatility vê na RAM da máquina, a atividade de rede que está sendo ocultada pode ser revelada. Por fim, é possível reconstruir o histórico do navegador e determinar quais URLs um navegador, ou o malware usando funções do navegador, visitou na máquina suspeita. Se os arquivos de histórico forem excluídos do disco, ainda há uma chance de você encontrar os registros em cache na memória, junto com informações como os últimos registros de data e hora acessados, tamanho dos dados retornados pelos servidores da web e até mesmo os cabeçalhos de resposta HTTP. ondemand_videoVídeo Eventos do Log Os eventos de logs contêm uma grande quantidade de informações e são essenciais em qualquer tipo de investigação. Eles contêm detalhes sobre erros de aplicativos, logins remotos e interativos, mudanças na política de firewall e outros eventos que ocorreram no sistema. Combinados com a marcação de horário fornecido com cada evento, os logs podem ajudá-lo a determinar exatamente o que aconteceu em um sistema ou, pelo menos, fornecer um prazo no qual deve concentrar o restante de seus esforços. Muitos dos arquivos de log são mapeados na memória durante o tempo de execução do sistema, portanto, é comum encontrar centenas, senão milhares, de registros individuais carregados na memória. Em alguns casos, você pode até conseguir extrair entradas depois de serem removidas pelo administrador ou modificadas maliciosamente por um invasor. 01 É importante localizar os eventos de logs na memória. Cada Windows lida de uma maneira diferente, sendo preciso entender e considerar as diferenças. Ao processar os logs, podemos simplesmente analisar os registros da memória com o Volatility ou podemos extrair os arquivos de log para análise com ferramentas externas. 02 É possível detectar tentativas de logins através da força bruta analisando mensagens de falha nos logs de eventos. É possível, também, identificar backdoorspor meiode alterações na política de firewall e/ou conflitos de porta, o que geralmente pode indicar atividade desse tipo. 03 Por fim, é possível identificar logs de eventos apagados;primeiro, é necessário aprender o que acontece quando os logs de eventos são apagados e como determinar se um código malicioso ou invasores tentaram limpá-los. Uma ferramenta nativa que pode ser utilizada para esse fim é o Console de Gerenciamento Microsoft (MMC), que investiga ou controla os serviços em um sistema. Ou então você pode utilizar o cmdletGet-Service conforme a Figura 1 a seguir: Fonte: Autor. Figura1: Uso do PowerShell para listar processos Na visão do analista, existem alguns pontos importantes a serem verificados, como determinar os serviços criados recentemente, aproveitando os registros de data/hora da última modificação na chave de registro de um serviço, determinando, inclusive, o período de tempo em que foi adicionado ao sistema. Bem como realizar a detecção de serviços em estados inválidos, verificar quando serviços não autorizados estão sendo executados ou quando os serviços de segurança foram interrompidos inesperadamente. Ao realizar verificações de rotina de sistemas ativos, você também pode detectar mudanças no estado do serviço entre os períodos de tempo. Um outro ponto é identificar serviços que foram modificados de forma maliciosa;em muitos casos, o malware evita a criação de um novo serviço. Em vez disso, ele seleciona um serviço existente e sobrescreve o caminho para o binário do serviço no registro, apontando-o para um arquivo malicioso. Por fim, localizar registros de serviço ocultos, o rootkit Blazgel, por exemplo, primeiro malware identificado que se camuflou do gerenciador de controle de serviços manipulando a lista na memória de estruturasde registro de serviço. Módulos do Kernel Comentário Quando você está realizando análises de memória do kernel, muitas vezes está procurando um módulo malicioso carregado. Há muitas maneiras de fazer isso:Dentro da estrutura do Kernel, existe um membro denominado PsLoadedModuleList que aponta para uma lista duplamente vinculada de estruturas KLDR_DATA_TABLE_ENTRY. Eles contêm metadados sobre cada módulo do kernel, o seu endereço de base, ou seja, o início do arquivo PE, o tamanho do módulo e o caminho completo para o arquivo do módulo no disco. Para enumerar os módulos, basta percorrer essa lista. Assim, os rootkits podem ocultar sua presença desvinculando uma entrada; essa é uma das formas de atuação desse tipo de malware. Apesar do fato de uma entrada ter sido desvinculada, a estrutura de metadados permanece intacta. Assim, é possível encontrar a estrutura usando outra abordagem, conhecida como pool-scanning. Mas um rootkit um pouco mais completo, pode, além de desvincular- se da estrutura de metadados, substituir todo o seu conteúdo por zeros. Nesse caso, nem a busca na lista nem a varredura do pool podem identificar o módulo oculto. Essas são técnicas anti-forenses, portanto, apenas os metadados são modificados;os dados reais, ou seja, o arquivo executável portátil e todas as suas funções, ainda estarão acessíveis, apenas serão mais difíceis de acessar. Linha do Tempo Uma fase comum da maioria das investigações é organizar os resultados da análise para ajudar a construir teorias sobre o que aconteceu. Uma técnica bastante utilizada envolve a criação de cronogramas para organizar os dados com base nas relações temporais entre artefatos digitais. É importante combinar artefatos digitais extraídos usando a análise de memória com artefatos do sistema de arquivos e análise de rede para reconstruir um entendimento mais completo de tudo que ocorreu na máquina para identificar as atividades maliciosas. Você tem uma máquina que foi possivelmente infectada por um malware, sua missão é identificá-lo e analisá-lo. Essa análise de memória geralmente fornece o contexto necessário para descobrir relações entre eventos e artefatos aparentemente díspares. Ela também permite que os analistas desenvolvam “pegadas temporais” para identificar rapidamente ferramentas e técnicas suspeitas em um sistema. Existem técnicas de reconstrução da linha do tempo que auxiliam o analista em sua tarefa. As etapas principais para realizar a reconstrução temporal são: Extrair os artefatos Gerar linhas do tempo O Volatility fornece vários plug-ins para extrair automaticamente esses artefatos da memória e formatar os dados de maneira afacilitar a formação de cronogramas. São eles: timeliner, mftparsere shellbags. É possível também incluir dados temporais de fontes alternativas, incluindo conteúdo de arquivo, metadados do sistema de arquivos ou capturas de rede. Nessas circunstâncias, você pode executar uma ferramenta, como o log2timeline, direto no dump de memória ou nos arquivos que foram extraídos pelo plug-in. Essa ferramenta tentará extrair dados temporais de todos os arquivos suportados, como logs de eventos, arquivos de registro e arquivos da lixeira. Aula 9: Investigandp via Análise de Memória - Linux Apresentação javascript:void(0); Nessa nona aula revisaremos algumas técnicas utilizadas para análise de memória para busca de atividades maliciosas, porém o foco será em ambiente Linux. Como abordamos na última aula, é importante entender as peculiaridades entres os diferentes sistemas e saber como proceder em cada um deles. Algumas das técnicas podem ser semelhantes, mas o processo de aquisição e análise difere do Windows. Objetivo • Identificar técnicas de aquisição de memória; • Construir profiles do sistema operacional Linux; • Reconhecer recursos internos do ambiente Linux. Linux O sistema operacional Linux, quando foi lançado, revolucionou o mundo. Linus Torvald, seu criador, sempre foi a favor do código aberto. Baseado no sistema UNIX, mesma origem do macOS, a proposta desse sistema operacional sempre foi a gratuidade e inclusão. Aquisição de memória A ideia é abordar os tópicos fundamentais para iniciar a análise da memória. Vamos abordar algumas técnicas de aquisição de memória no Linux e analisar suas vantagens e desvantagens. Comentário Você verá que a utilização do Volatility não é tão simples quanto do Windows; é preciso, primeiro, criar os perfis do sistema Linux utilizado. Um perfil é um arquivo que contém as informações necessárias para que o Volatility encontre e interprete adequadamente os dados dos dumps de memória do Linux. Primeiros métodos O Os primeiros métodos de aquisição de memória no Linux não exigiam qualquer outra aplicação para serem realizados. Havia as interfaces que eram integradas ao próprio sistema operacional que permitiam a leitura e a gravação da memória física, portanto, bastando a leitura do /dev/mem ou /dev/kmem e seu direcionamento para um arquivo. compare_ arrows Sistemas modernos Em sistemas mais modernos, essas interfaces foram desativadas por questões de segurança para evitar abusos. Com as restrições impostas pela desativação das interfaces, os desenvolvedores da comunidade forense criaram ferramentas especializadas de aquisição de memória. Como discutido na aula anterior, apesar do uso de ferramenta de terceiros fornecer aos analistas uma maior flexibilidade e agilidade no processo de aquisição, exige a execução de um processo nos sistemas de destino para coletar as evidências, podendo alterar informações importantes. Com o lançamento dos sistemas de 64 bits, outro dispositivo foi criado e possibilitou a aquisição da memória física sem a necessidade de ferramentas externas: O /proc/kcore. Dados os problemas, já mencionados, da interface /dev/mem em sistemas de 32 bits, foi criado um projeto: fmem. fmem javascript:void(0); Trata-se de um driver de kernel que cria o dispositivo /dev/fmem, o qual exporta a memória física para outros programas acessarem. Vantagens e desvantagens do fmem Clique no botão acima. • Vantagens Uma de suas vantagens é que ele verifica se as páginas físicas residem na memória principal antes de acessá-las, evitando que os analistas tentem ler acidentalmente áreas de memória de dispositivos ou endereços físicos não mapeados, o que poderia causar problemas de estabilidade no sistema. Outra vantagem do fmem é que ele pode acessar páginas físicas acima do limite de 896 MB, ao contrário de /dev/mem. • Desvantagem A única desvantagem do fmem é que ele exige que o investigador inspecione o dispositivo /proc/iomem para determinar onde a RAM está mapeada. Isso é necessário para máquinas que não mapeiam toda a memória principal sem nenhum tipo de deslocamento físico. Pode parecer confuso em um primeiro momento, mas imagine o seguinte cenário: Em alguns sistemas, a memória RAM é dividida em diversos segmentos diferentes que são carregados na memória física. A Figura 1 a seguir mostra a saída inicial do dispositivo /proc/iomem em uma máquina virtual com 4096 MB de memória física. Fonte: Autor. Figura1: Mapeamento da memória física https://stecine.azureedge.net/webaula/estacio/go0682/aula9.html#complementar1 https://stecine.azureedge.net/webaula/estacio/go0682/aula9.html#complementar1 https://stecine.azureedge.net/webaula/estacio/go0682/aula9.html#complementar1 https://stecine.azureedge.net/webaula/estacio/go0682/aula9.html#complementar1 Como se pode notar, existem quatro intervalos de memória física que precisam ser adquiridos. Observe que o último intervalo (100000000- 13fffffff) está acima do limite normal para sistemas de 32 bits, que é 0xffffffff. Portanto, caso seja utilizada a ferramenta dd para adquirir 4096 MB de RAM com fmem, não serão capturados os dados na última região. Atenção Parece um erro simples, porém esse tipo de problema é bastantecomum e precisaria de um analista bastante experiente para identificar, pois o arquivo teria o tamanho correto da RAM (4096 MB) e as ferramentas de análise de memória (incluindo o Volatility) funcionariam normalmente. No entanto, a amostra de memória estaria incompleta. ondemand_videoVídeo Embora o fmem seja um ótimo complemento para a aquisição de memória, trata-se de uma ferramenta que necessita de bastante intervenção do analista, além de um conhecimento profundo do layout da memória física para usá-la adequadamente. Uma ferramenta bastante utilizada é o Linux MemoryExtractor, conhecido como LiME. Ressalta-se que LiME: 01 É a ferramenta de aquisição de memória Linux mais recente. Ela corrige os problemas e desafios envolvidos com as ferramentas e técnicas discutidas anteriormente. 02 Opera carregando um driver do kernel e toda a aquisição é feita diretamente no kernel em contraste às soluções anteriores que criavam um dispositivo no modo de usuário. Isso aumenta significativamente a precisão da amostra resultante pois não criam- javascript:void(0); se alternâncias de contexto entre o ambiente do usuário e o kernel necessários para transferir dados. 03 Tem uma grande vantagem em relação ao fmem ao determinar automaticamente os intervalos de endereços que contêm a memória principal. Para enumerar os intervalos, o LiME percorre a lista encadeada do kernel, que possui os descritores para cada segmento de memória física. Se o nome do segmento corresponder ao da RAM (System RAM), os membros inicial e final correspondentes determinam onde o segmento reside na memória física. Ao realizar a aquisição da memória com LiME, é possível escolher entre vários formatos. Ao selecionar o formato recomendado, um arquivo estruturado é produzido eliminando a necessidade de criar um arquivo preenchido com zeros para preencher os dados da área de memória vazios. Este formato estruturado contém metadados que descrevem de qual deslocamento físico cada seção veio, o que permite que a ferramenta de análise de memória reconstrua dinamicamente o layout de memória original. Para usar o LiME, você deve primeiro compilar o módulo do kernel para a versão do kernel que deseja analisar. Para mais informações, veja a documentação do projeto. Depois de compilar o módulo, você terá um arquivo chamado lime-.ko que pode ser carregado no sistema de destino. O LiME tem a capacidade de adquirir a memória diretamente no disco local ou via rede, e pode fazer isso nos seguintes formatos: 1 raw Todos os intervalos de memória são concatenados juntos. 2 padded Semelhante ao formato anterior, exceto que as lacunas entre os intervalos de memória são preenchidas com zeros. 3 lime Grava no formato LiME mencionado anteriormente (recomendado). Comentário Você pode controlar o destino do arquivo gerado da memória definindo o parâmetro de caminho para o módulo do kernel. Para descarregar o conteúdo da memória em um arquivo em um dispositivo de armazenamento, basta especificar a variável path=/path/to/ mememoria.lime. Nesse caso, a memória é adquirida e gravada no local desejado assim que o módulo é carregado. Um exemplo de aquisição de memória para o disco no formato lime é o seguinte: #insmodlime.ko "path=/tmp/memoria.limeformat=lime” ondemand_videoVídeo Para aquisição via rede, basta modificar a variável como path=tcp:4444, sendo o número da porta escolhida pelo analista. Com isso, um soquete de escuta é criado no sistema de destino e na porta especificada. Basta se conectar ao soquete com uma ferramenta de rede e a aquisição começará assim que a conexão for estabelecida. Segue um exemplo de aquisição de memória via rede com a ferramenta netcat, assumindo que o ip da máquina alvo seja 192.168.10.2: máq alvo: #insmodlime.ko "path=tcp:443 format=lime" máqdest: $ nc 192.168.10.2 443 >memoria.lime Linux Profiles Antes de usar o Volatility para analisar sua amostra de memória adquirida, você deve primeiro criar um perfil para o sistema operacional de destino. Como vimos na aula anterior, o Volatility tem suporte integrado para todas as versões principais do Windows. No entanto, o Linux é diferente devido ao grande número de versões de kernel, versões de subkernel e kernels personalizados. Existem mais de 100 kernels básicos e milhares de sub-versões nessa faixa, cada uma exigindo um perfil separado. Além disso, dada a mobilidade do sistema operacional, quando um usuário compila um kernel do zero, cada opção de configuração alterada pode alterar drasticamente o kernel resultante. Esse grande número de versões do kernel inviabiliza que o Volatility possua os perfis para todas as compilações possíveis do Linux. A solução adotada foi compilar perfis para os kernels mais comuns e possibilitar que o próprio analista crie perfis para o sistema a ser analisado. Existem projetos que visam uma compilação automatizada para o perfil desejado. Para a criação de um perfil são necessárias algumas ferramentas: dwarfdump1, alguns compiladores e cabeçalhos do kernel. São necessários, também, os compiladores da linguagem C como, por exemplo, gcc e make, todos disponíveis no pacote build-essential. Por fim, é necessária a informação sobre os cabeçalhos do kernel, para que se descubra a exata versão do kernel. Para as distribuições do tipo Ubuntu/Debian, como na Figura 2 a seguir, a informação pode ser adquirida pelo comando ‘uname -r’. Fonte: Autor. https://stecine.azureedge.net/webaula/estacio/go0682/aula9.html https://stecine.azureedge.net/webaula/estacio/go0682/aula9.html Figura 2: Exemplo de cabeçalho do kernel • A criação de um perfil consiste em gerar um conjunto de definições de estrutura, conhecidos como VTypes e um arquivo System.map para uma determinada versão do kernel. • O método atual para criá-los é compilar o arquivo module.c, disponibilizado na arquitetura do Volatility e dentro da pasta /tools/linux, contra o kernel que você deseja analisar. Esse módulo foi projetado para declarar os membros de todos os tipos de que a Volatility precisa, e, com isso, serão compiladas todas as informações necessárias para a depuração do módulo. Para compilá-lo, basta estar no diretório do arquivo modulo.c e digitar o comando make. Se for bem-sucedido, sua saída deve ser semelhante à Figura 3 a seguir. Fonte: Autor. Figura 3: Criando um Perfil para o Volatility Observe no final da compilação que a ferramenta dwarfdump é executada recebendo como parâmetro o arquivo module.ko, o módulo do kernel, produzindo o arquivo module.dwarf, que será utilizado mais tarde. Compilar o module.ko não é necessário se você pode usar o arquivo kernel Linux compilado vmlinux, porém o arquivo vmlinux não é fornecido com a maioria das distribuições Linux. Por fim, precisamos gerar os símbolos do sistema operacional, os quais estão contidos no arquivo System.map. É possível encontrá-lo em diversos lugares no sistema, usaremos aquele que está no diretório /boot da máquina em que o kernel está instalado. Se você tiver o arquivo ELF do kernelvmlinux, também pode gerar um arquivo System.map executando a ferramenta nm passando o arquivo como parâmetro. Tome o cuidado de copiar o arquivo correto, com o mesmo valor verificado do comando uname -r. O arquivo System.map contém os endereços de todos os símbolos do kernel que o Volatility usa para localizar as principais estruturas de dados na memória. Agora, basta colocar os arquivos module.dwarf e System.map em um arquivo zip diretório no diretório volatility/plugins/overlays/linux/. Você deve nomear o arquivo zip de acordo com a distribuição, arquitetura e versão do kernel que ele representa. Você pode cuidar de todas essas etapas com um único comando, conforme mostrado na Figura 4 a seguir. Para verificar a eficácia, basta realizar o comando volatility --infoe verificar a existência do novo perfil. Fonte: Autor. Figura4: Finalizandoa criação de um perfil Linux ondemand_videoVídeo Memória e Processos Um ponto crucial durante uma análise da memória de qualquer sistema envolve enumerar processos em execução. Para identificá- los é necessário compreender as estruturas de um processo. Cada processo do Linux é representado por uma estrutura na memória do kernel. Comentário Essa estrutura contém todas as informações necessárias para vincular um processo com seus descritores de arquivo abertos, mapas de memória, credenciais de autenticação e todas suas informações. As instâncias das estruturas são alocadas do cache de memória do kernel e armazenadas em um cache denominado. O kernel usa a lista de processos ativos para manter um conjunto de processos que estejam em execução; ressalta-se que essa lista não está disponível ao usuário. Por esse motivo, a maioria das ferramentas não faz referência a essa lista para enumerar processos. Antigamente, alguns rootkits manipulavam essa estrutura de dados para se camuflarem, pois ferramentas forenses dependiam dessa lista para enumerar os processos ativos. O plugin do Volatility linux_pslist enumera processos percorrendo a lista de processos ativos apontada pela variável global init_task. A variável init_task é alocada estaticamente no kernel, tem um ID de processo (PID) de 0 e tem um nome de swapper. Devido a uma escolha de design do desenvolvedor, ele não aparece nas listas de processos geradas por meio do comando ps, como na Figura 5 a seguir. Fonte: Autor. Figura 5: Reconstrução da lista de processos Um analista deve ter como objetivo a classificação da memória do processo: Aprender a localizar e extrair o heap, a pilha ou código executável de um processo da memória. 1 Argumentos da linha de comando Determinar onde procurar para extrair a linha de comando completa usada para invocar um processo. 2 Variáveis de ambiente Descobrir onde as variáveis de um processo são armazenadas e como verificar se as variáveis de ambiente foram modificadas. 3 Injeção de biblioteca compartilhada Analisar os caminhos completos para bibliotecas compartilhadas e executáveis de processo ajuda a detectar ataques de injeção de código. Artefatos de Redes Conforme já abordamos, quase todo artefato malicioso possui uma capacidade de rede, seja para comunicar-se com o atacante, seja para se espalhar pela rede infectada. Já abordamos nas aulas anteriores técnicas para identificar pacotes enviados pelo artefato para comunicação e como forjar uma rede para identificar e reproduzir requisitos necessários para a completa execução do malware. Mas, no caso da memória, o artefato já foi reproduzido, as peças complementares já foram carregadas e todo os processos já estão em execução ou foram executados. Qual sistema foi inicialmente infectado? Outras máquinas foram comprometidas por meio de movimento lateral? Quais sistemas remotos foram envolvidos na exfiltração de dados ou comando e controle? A análise forense de memória é crítica para responder a essas perguntas porque poucos artefatos relacionados são gravados em disco. É preciso entender como esses dados são armazenados nas amostras colhidas da memória do Linux, como recuperá-los e como tirar conclusões com base no que encontrar. Antes de começar a analisar informações de rede na memória, você deve primeiro localizar os descritores de arquivo de soquete de rede, pois eles representam uma ampla variedade de itens, como, por exemplo, identificadores de arquivo aberto, recursos de entrada e saída, soquetes de rede e canais de comunicação entre processos. O Linux fornece uma interface de programação de aplicativo (API) comum para acessar os descritores e, conhecendo as estruturas de dados dessa API, é possível determinar com sucesso a finalidade de um descritor de arquivo aberto na memória. Existe um plugin do Volatility chamado linux_netstat que possui a capacidade de recuperar os artefatos de rede. A saída replica a mesma saída do comando netstat em um sistema ativo, com a diferença da fonte utilizada pelo comando, consulta da memória RAM ao invés das APIs do sistema operacional, conforme pode ser visto na Figura 6 a seguir. Fonte: Autor. Figura 6: Reconstrução das conexões de rede através da memória Por fim, ressaltamos os seguintes objetivos que o analista deve ter em mente durante sua análise: Recuperar informações de conexão Ao encontrar o descritor de arquivo de socket, deve-se determinar qual protocolo ele representa e como encontrar as estruturas de conexão específicas do protocolo, permitindo a recuperação de endereços IP, portas, estados de conexão. Detectar conexões de rede maliciosas Das informações levantadas, deve-se buscar conexões que fujam do padrão normal. Isso inclui sinais de exfiltração de dados, comunicação de comando e controle ou o uso do sistema suspeito para atacar outros recursos. Sistemas de Arquivos Assim como visto nas aulas anteriores, conforme os arquivos são abertos, criados, lidos e/ou gravados, o Linux armazena informações sobre essas ações em várias estruturas de dados. Os artefatos associados registram a estrutura de diretório, os metadados, como registros de data e hora e, até mesmo, o conteúdo de arquivos acessados recentemente. Particularmente no Linux, essas informações ficam armazenadas apenas na memória e são perdidas quando a máquina é desligada. Portanto, em muitos casos, preservar a memória é o melhor e, às vezes, o único método para determinar quais arquivos foram acessados, onde um rootkit se esconde ou qualquer outra informação valiosa. O Linux mantém uma lista dos sistemas de arquivos ativos e montados no kernel na memória. É fundamental: • Localizar e relacionar todos os sistemas de arquivos que estavam acessíveis e ter uma noção da extensão dos possíveis danos. • Verificar se um determinado arquivo foi acessado no disco rígido local, em uma unidade remota do Network File System (NFS) ou via protocolo Server MessageBlock (SMB) ou, ainda, se existia um disco removível externo conectado na máquina. Como objetivo, um analista deve focar nos seguintes pontos, em relação ao sistema de arquivos: Identificar reconhecimento e a espionagem Muitas empresas têm servidores de arquivos internos que hospedam dados sensíveis. Qualquer invasor tentará encontrar e montar compartilhamentos de rede para pesquisar e exfiltrar arquivos sensíveis. Se o compartilhamento estiver montado no momento da aquisição, todos os artefatos dessa atividade estarão presentes na memória. Detectar vazamento de dados Todos os arquivos acessados, discos removíveis externos e cópias realizadas ficarão registrados na memória. Entender as convenções de montagem do Linux Ao contrário dos sistemas Windows, que geralmente instalam tudo na mesma partição, os sistemas Linux usam muitas partições para armazenar conjuntos de dados. O Linux também pode usar sistemas de arquivos temporários apenas com memória, o que tem implicações forenses interessantes. O plugin linux_mount recupera cada sistema de arquivo e lista dos dispositivos, ponto de montagem, tipo de sistema de arquivo e opções de montagem. Conforme mostrado na Figura 7 a seguir, é possível verificar todas essas informações válidas no momento da aquisição da memória. Fonte: Autor. Figura 7: Sistemas de arquivos montados https://stecine.azureedge.net/webaula/estacio/go0682/aula9.html#collapse01-01 https://stecine.azureedge.net/webaula/estacio/go0682/aula9.html#collapse01-02 https://stecine.azureedge.net/webaula/estacio/go0682/aula9.html#collapse01-03 Rootkit Ao projetar um rootkit, uma das primeiras decisões a serem tomadas é se o mesmo operará em modo do usuário ou no modo kernel. Os rootkits de modo kernel oferecem maior liberdade para o atacante, como recursos de Manipulação Direta de Objetos Kernel (DKOM), capacidade de executar certas operações privilegiadas e interação diretacom dispositivos de hardware. Porém, tarefas comuns de rootkit, como ocultar processos, armazenar as teclas digitadas e espionar atividades de rede, podem ser realizadas no modo de usuário. Modo usuário Modo kernel • Uma vantagem dos rootkits do modo de usuário é a portabilidade. • A detecção de rootkit no espaço do usuário é pouco identificada pelas ferramentas, o que pode ser utilizado por um atacante. • Os rootkits de modo kernel são mais difíceis de manter, pois o kernel é modificado com bastante frequência. • Outro problema é em relação a detecção de rootkit em modo kernel por várias ferramentas de administração do sistema e de Sistema de Prevenção de Intrusão de Host (HIPS). Dentro desse assunto, um analista deve ter como objetivo os seguintes pontos: Detectar injeção de shellcode Os invasores podem injetar shellcode, instruções de assembly brutas, diretamente em processos para modificar o fluxo e manipular e interceptar dados. Encontrar injeção de biblioteca compartilhada A injeção de biblioteca compartilhada permite carregar binários ELF completos em um processo de destino. Esse método é conveniente para invasores de uma perspectiva de desenvolvimento, mas deixa mais rastros na memória do que a simples injeção de shellcode. https://stecine.azureedge.net/webaula/estacio/go0682/aula9.html#collapse01-04 https://stecine.azureedge.net/webaula/estacio/go0682/aula9.html#collapse01-05 Analisar sobrescrição da tabela de offset global (GOT) ou tabela de ligação de procedimento (PLT) Enquanto os endereços dos símbolos são resolvidos em tempo de execução, eles são armazenados nas entradas da GOT do processo. Ao substituir esses ponteiros, o malware pode efetivamente se ligar a chamadas de função desse processo de uma maneira muito simples. Rastreamento de ligações de funções ‘em linha’ Alguns artefatos maliciosos podem sobrescrever o código dentro de uma função legítima para que o controle seja transferido para outra função maliciosa armazenada na memória pelo próprio malware. Essa técnica permite que ele adicione, modifique e exclua quaisquer dados processados ou retornados pela função interceptada. Aula 10: Análise de Malware em ambiente Mobile Apresentação Nesta décima e última aula utilizaremos todos os conhecimentos acumulados até agorapara analisar aplicações maliciosas em dispositivos móveis, em Android e Apple. Abordaremos algumas características da arquitetura ARM e depois veremos as peculiaridades de cada um dos ambientes mobiles. Por fim, elencaremos algumas técnicas de análises de aplicações maliciosas em cada um dos ambientes. Objetivo • Identificar as características da arquitetura ARM; • Identificar as peculiaridades do sistema Android; • Identificar as peculiaridades do sistema iOS. Introdução https://stecine.azureedge.net/webaula/estacio/go0682/aula9.html#collapse01-06 https://stecine.azureedge.net/webaula/estacio/go0682/aula9.html#collapse01-06 https://stecine.azureedge.net/webaula/estacio/go0682/aula9.html#collapse01-07 É inegável o aumento de dispositivos móveis e seu uso em comparação com os computadores tradicionais. Esses dispositivos se tornaram um grande vetor de entrada nas organizações. Por isso, já se justifica a importância em estudar e entender estes dispositivos para que seja analisado seu uso malicioso. Arquitetura ARM Antes de aprofundarmos na linguagem assembly para a arquitetura ARM, precisamos entender uma diferença básica daquilo que vimos até agora. Existem dois grandes grupos de arquiteturas que definem a linguagem assembly: Conjunto Complexo de Instruções de Computador – Complex Instruction Set Computer (CISC). Conjunto Reduzido de Instruções de Computador – Reduced Instruction Set Computer (RISC). A maior diferença entre eles é a complexidade das instruções. A arquitetura Intel, tanto 32 quanto 64 bits, utiliza o conjunto CISC; já a arquitetura ARM, utiliza o conjunto RISC. Linguagem assembly do tipo CISC A linguagem assembly do tipo CISC possui, como já mencionado, instruções mais complexas. A ideia em criar instruções mais complexas visa completar tarefas usando a menor quantidade de instruções possível. Para isso, este modelo inclui instruções que podem executar várias operações, como por exemplo a instrução mul, que pode executar operações de acesso de dados, multiplicação e até armazenamento. Linguagem assembly do tipo RISC Já a linguagem assembly do tipo RISC possui instruções simples que, geralmente, executam apenas uma operação cada. Como consequência, são necessárias mais linhas de código para concluir a mesma tarefa, comparando à linguagem CISC. No entanto, há um ganho em eficiência do uso do processador, pois são utilizadas apenas as instruções necessárias, descartando todas as execuções de quaisquer operações desnecessárias. Comentário Outra grande vantagem das arquiteturas RISC é a menor necessidade de transistores para os processadores que as implementam. Isso traz um maior benefício em relação à eficiência energética e menor dissipação de calor, além de reduzir os custos de fabricação associados, tornando- os uma escolha melhor para dispositivos portáteis. Com tudo isso em mente, podemos entender o motivo das arquiteturas RISC com ARM serem a arquitetura mais utilizada no mundo. Esses processadores podem ser encontrados em vários dispositivos móveis e aparelhos, como telefones, consoles de videogame ou câmeras digitais. Fonte: niekverlaan / Pixabay. Por esse motivo, várias famílias de malware são direcionados às plataformas Android e iOS e com instruções para a arquitetura ARM. Portanto, para poder analisá-los, é necessário primeiro entender como o ARM funciona. Existem vários sistemas operacionais com suporte a essa arquitetura: Windows, Android, iOS, distribuições Unix e Linux, além de outros sistemas operacionais menos conhecidos. O suporte para um espaço de endereço de 64 bits foi adicionado em 2011 com o lançamento do padrão ARMv8. A arquitetura ARM é do tipo armazenamento de carga, a qual divide todas as instruções em dois tipos de categorias: 1 Acesso de memória Movimenta os dados entre memórias e registradores. 2 Operações de unidade lógica e aritmética (ALU) Realiza os cálculos envolvendo registradores,suporta as operações aritméticas de adição, subtração,multiplicação e divisão (a partir do padrão ARMv7). Existem 30 registradores de 32-bits de propósito geral na arquitetura ARM, divididos em baixo e alto registradores, ponteiro para pilha, ponteiro de ligação – que contêm o endereço de retorno da função corrente, registrador de contagem, além de outros para controle de execução do programa e flags de controle de execução. O processador ARM tem dois subconjuntos de instruções: Conjunto ARM tradicional • As instruções são todas de 32 bits. Conjunto Thumb mais condensado • As instruções mais comuns têm 16 bits e algumas têm 32 bits. O conjunto de instruções a ser executado pode ser escolhido pelo desenvolvedor, e apenas um conjunto pode estar ativo, ou seja, uma vez que o processador é alterado para o modo Thumb, todas as instruções serão decodificadas usando o Thumb em vez de ARM. Android Sistema operacional originalmente desenvolvido pela Android Inc. e posteriormente adquirido pelo Google em 2005, trata-se de um sistema operacional de código aberto baseado em uma versão modificada do kernel Linux. Há muitas variantes dele, como Wear OS para dispositivos vestíveis, como relógios, e Android TV, que pode ser encontrada em várias televisões inteligentes. Fonte: andrekheren / Pixabay. Como os dispositivos móveis armazenam ou podem fornecer acesso a cada vez mais informações confidenciais, não é surpresa que as plataformas móveis estejam cada vez mais se tornando alvos deinvasores para fins maliciosos. Hierarquia de arquivos Como o Android é baseado no Linux, sua estrutura de arquivos se assemelha ao que vimosem aulas passadas. O sistema de arquivos é semelhante a uma árvore com a raiz representada pelo símbolo ‘/’ e possui diversos diretórios semelhantes ao Linux, como /proc e /sbin, por exemplo. O kernel do Android possui suporte a diversos sistemas de arquivos dependendo da versão do sistema operacional e do fabricante do dispositivo. Normalmente, tem sido o EXT4 o sistema de arquivos principal padrão desde o Android 2.3. O armazenamento externo e os cartões SD são geralmente formatados usando FAT32 para manter a compatibilidade com o Windows. Em termos específicos, a documentação oficial do Android divide a estrutura de armazenamento em duas opções: Interno Representado pelo diretório /data/data/. Seu principal objetivo é armazenar, com segurança, arquivos privados para aplicativos. Nenhum outro aplicativo, ou mesmo o usuário, tem acesso direto a eles. https://stecine.azureedge.net/webaula/estacio/go0682/aula10.html#collapse01-01 Cada aplicativo obtém sua própria pasta e, se o usuário desinstalar o aplicativo, todo o seu conteúdo será excluído. Assim, os aplicativos usuais não armazenam nada que deva persistir independentemente deles como, por exemplo, fotos tiradas por um usuário com a ajuda de um aplicativo. Externo Geralmente está associado a /storage/emulated/0, /sdcard e /mnt/sdcard. Este espaço é compartilhado por todos os aplicativos e pode ser lido por qualquer usuário. Nesse espaço ficam pastas conhecidas como Downloads e DCIM.Esse local é acessível a todos. Segurança Existem diversos mecanismos de segurança implementados no Android; como em qualquer outro sistema, esses mecanismos têm evoluídos cada vez mais. Em relação a gerenciamento de processos, o Android implementa o Controle de Acesso Obrigatório – Mandatory Access Control (MAC) em todos os processos, e usa o modelo Security-Enhanced Linux (SELinux) para aplicá-lo. O SELinux é baseado no princípio de negação padrão, em que tudo o que não é explicitamente permitido é proibido. Sua implementação evoluiu em diferentes versões do Android; o modo de aplicação foi habilitado no Android 5.0. No Android, cada aplicativo é executado como um processo individual e seu próprio usuário é criado. É assim que a proteção do processo é implementada, para garantir que nenhum processo possa acessar os dados de outro.Os mapeamentos entre aplicativos e os IDs de usuário correspondentes podem ser encontrados no arquivo /data/system/packages.xml, bem como no arquivo packages.list. https://stecine.azureedge.net/webaula/estacio/go0682/aula10.html#collapse01-02 Além dos usuários reais, o Android tem muitas contas de sistema com IDs predefinidos. Além de AID_ROOT (0), que é usado para executar alguns programas nativos necessários, podemos citar: 1 AID_SYSTEM (1000) Conta de usuário regular com permissões especiais para interagir com os serviços do sistema. 2 AID_VPN (1016) Associado ao sistema de Rede Privada Virtual (VPN); AID_SHELL (2000) – conta que o usuário obtém ao utilizar ferramenta depuradora para acessar o terminal de comando. 3 AID_INET (3003) Conta capaz de criar soquetes. Permissões de aplicativos O principal objetivo das permissões de aplicativos é proteger a privacidade do usuário, dando-lhe controle sobre quais dados e funcionalidades do sistema podem ser acessados por aplicativo. Por padrão, nenhum aplicativo pode afetar a execução de outro, a menos que tenha permissão explícita para isso; o mesmo se aplica ao acesso a dados confidenciais do usuário. 01 Dependendo da versão do Android e das configurações, algumas permissões podem ser concedidas automaticamente, enquanto outras requerem aprovação manual do usuário. 02 O comportamento padrão de solicitar o consentimento do usuário depende da versão do Android. A partir do Android 6.0, o usuário não é notificado no momento da instalação; em vez disso, o aplicativo precisa pedir permissão em tempo de execução usando uma janela de diálogo padrão do sistema. Para versões mais antigas do Android, todas as permissões são solicitadas no momento da instalação. 03 Cada aplicativo deve anunciar quais permissões ele requer em seu arquivo de manifesto incorporado – manifest.xml, responsável por enumerar diversas opções e funcionalidades da aplicação. Tal arquivo é uma grande fonte de informações ao analista. ondemand_videoVídeo Root Muitos usuários comuns encontram aplicativos que exigem o root em seus dispositivos. O que exatamente significa e como esse processo realmente funciona? Exemplo Se o usuário precisar de alguma funcionalidade não suportada por APIs de sistema padrão, por exemplo, remover certos aplicativos pré- instalados ou aplicativos de operadora, ou fazer aumentar o clock da CPU, ou substituir completamente o sistema operacional, a única opção que o permite realizar todas essas atividades é obtendo acesso root por meio de alguma vulnerabilidade conhecida. Como resultado, o usuário obtém privilégios elevados e controle total sobre o sistema. A legalidade desse processo varia dependendo do país; é aceitável para atividades não relacionadas a direitos autorais ou é regulamentada por algumas isenções específicas. Às vezes, o processo de root é usado alternadamente com o jailbreak1, geralmente aplicado a dispositivos iOS. No entanto, esses são procedimentos diferentes em termos de escopo. Ao contrário do iOS, no Android é possível habilitar oficialmente a instalação de aplicativos não oficiais, e muitos dispositivos são enviados com bootloaders desbloqueados, ou seja, com capacidade de modificar o sistema operacional, então apenas o root continua sendo um problema. O processo de obtenção do superusuário – root é acompanhado por riscos de segurança, já que, nesse caso, o processo remove a proteção por mecanismos e restrições de segurança incorporados ao sistema. Uma maneira comum de obter privilégios de root é colocar um utilitário Linux su padrão, que é capaz de conceder os privilégios necessários para arquivos personalizados e para um local acessível e usá-lo sob demanda. O malware pode verificar se essa ferramenta já está disponível no dispositivo comprometido e usá-la indevidamente a seu critério, sem que nenhum trabalho extra seja necessário. Muitas famílias de malware Android também vêm com ferramentas para elevar os privilégios por conta própria. Existem vários motivos pelos quais esse tipo de acesso é visado para os atacantes. Particularmente, permite-lhes obter o seguinte: Acesso a dados críticos. Capacidades de persistência aprimoradas. Capacidade de se esconder. Análise estática e dinâmica Já temos quase todos os conhecimentos suficientes para começar a analisar aplicações maliciosas. Para análise estática, o processo e as ferramentas usadas são basicamente os mesmos para diferentes versões do sistema operacional Android, as diferenças estão nas técnicas de análise dinâmica utilizada. Dalvik era uma máquina virtual de processo de código aberto, utilizado até o Android 4.4, que executava aplicativos escritos para Android. Os programas para Android são comumente escritos em Java ou em Kotlin e compilados em bytecode para a máquina virtual https://stecine.azureedge.net/webaula/estacio/go0682/aula10.html https://stecine.azureedge.net/webaula/estacio/go0682/aula10.html Java, depois traduzidos para bytecodeDalvik e armazenado em arquivos dex. O sucessor do Dalvik é o AndroidRuntime (ART), que utiliza os mesmos arquivos bytecode. Sua maior diferença é que, em vez de interpretar diretamente o bytecodedex, o ART o traduz em instruções de código de máquina para obter melhores resultados de desempenho. Análise estática Geralmente, a análise estática de um malware em bytearray envolve desmontá-lo, examinar suas instruções ou descompilar para linguagem originalmente escrita e explorar o código-fonte. Em muitos casos, a última abordagem é preferível sempre que possível, pois a leitura docódigo amigável reduz o tempo associado à análise. A primeira abordagem é frequentemente usada quando a descompilação não funciona por qualquer motivo, como a falta de ferramentas atualizadas ou por causa de técnicas de engenharia anti- reversa implementadas na amostra. Existem algumas ferramentas que visam restaurar as informações, a partir do bytecode compilado: 1 Baksmali Ferramenta que pode ser usada para restaurar o código de montagem Dalvik a partir de instruções de bytecode, bem como recuperar a estrutura de cabeçalho dex. 2 Apktool Fornece a funcionalidade para processar facilmente os arquivos APK e recuperar as instruções para uma linguagem de alto nível. Ferramenta bastante utilizada. 3 oat2dex Ferramenta muito útil para extrair bytecode DEX de arquivos ELF mais antigos, armazenando-os como parte de dados do tipo OAT para que possam ser analisados normalmente. 4 vdexExtractor Pode ser utilizada para extrair bytecode DEX de arquivos VDEX, pois os arquivos OAT modernos não os armazenam mais. ondemand_videoVídeo Embora a montagem de bytecode já possa ser utilizada para propósitos de análise estática, é melhor trabalhar com código descompilado para economizar tempo. Nesse caso, as ferramentas de descompilação são extremamente úteis. Em vez de restaurar as instruções de montagem, esse conjunto de ferramentas restaura o código-fonte: 1 JADX Essa ferramenta fornece linhas de comando e uma ferramenta GUI para obter um código próximo ao código-fonte original na linguagem Java – DEX para descompilador Java. Além disso, fornece funcionalidade básica de desofuscamento. 2 AndroChef Esse descompilador comercial oferece suporte a arquivos Java e Android e fornece uma GUI bastante simples. 3 JEB decompiler Outra solução comercial poderosa de desmontagem e descompilação, suporta tanto Dalvik quanto código de máquina. 4 dex2jar Embora não seja exatamente um descompilador, essa ferramenta permite que os analistas convertam arquivos DEX em JARs. Torna-se possível usar vários descompiladores Java para obter o código-fonte Java. Uma vez obtido o código-fonte, pode ser analisado em qualquer IDE ou editor de texto com destaque de sintaxe que o suporte. ondemand_videoVídeo Análise dinâmica A análise dinâmica eficaz requer algum tipo de emulação ou depuração remota, pois muitos dispositivos móveis tendem a ter telas nativas relativamente pequenas e recursos básicos de entrada. A ferramenta de linha de comando Android Debug Bridge (ADB) é bastante versátil e permite aos usuários interagir com dispositivos móveis a partir de um computador, possibilitando uma variedade de ações. Ela faz parte das ferramentas da plataforma Android SDK e consiste em três partes: Fonte: Autor. No dispositivo, a depuração via ADB pode ser ativada explicitamente usando a opção Depuração USB em Opções do desenvolvedor. Além do acesso via USB, é possível interagir via Wi-Fi com o dispositivo. Para isso, basta emitir o comando: adbtcpip<porta> via USB e, em seguida, desconectar o dispositivo e usar o comando: adbconnect<ip_address>. Como em qualquer outra plataforma, os emuladores visam facilitar a análise dinâmica emulando as instruções executadas sem necessidade do uso de dispositivos reais. Existem várias soluções de terceiros com o objetivo de fornecer acesso mais fácil a aplicativos Android. No entanto, para fins de engenharia reversa, as soluções mais focadas em fornecer aos desenvolvedores a capacidade de criar e depurar aplicativos geralmente oferecem opções melhores. Das diversas existentes, podemos destacar as seguintes: • AndroidEmulator: O emulador Android oficial pode ser instalado como parte das ferramentas oficiais do Android SDK usando o SDK Manager. Ele fornece quase todos os recursos de dispositivos físicos reais e vem com conjuntos predefinidos de configurações com o objetivo de simular vários dispositivos móveis, como telefones, tablets e wearables. • Outra grande vantagem é a capacidade de criar e restaurar snapshots contendo todo o estado de uma máquina emulada. • VMWare/VirtualBox: Essas soluções versáteis podem ser usadas para executar uma imagem Android e realizar análises dinâmicas de maneira semelhante ao que seria feito em uma máquina virtual Linux. • QEMU: Os emuladores baseados em QEMU, como Limbo, podem ser usados para emular código malicioso. • Genymotion: Solução bastante utilizada, fornece dispositivos virtuais Android tanto para desktop quanto para nuvem. Fluxo de análise Android As metodologias a seguir podem ser utilizadas como fluxo de análise de uma aplicação Android: Aquisição de amostra A amostra pode ser fornecida ou baixada de um site de terceiros. No entanto, às vezes é necessário obter amostras do Google Play. Isso pode ser feito de várias maneiras: Usando ferramentas dedicadas, como o APK Downloader, ou instalando um aplicativo no emulador e, em seguida, obtendo seu arquivo APK do disco que ficam no diretório /data/app para as aplicações instaladas pelo usuário e em /system/app para as aplicações pré-instaladas. Descompilação/desmontagem É mais fácil entender a aplicação através de seu código-fonte do que analisar suas instruções em assembly. Caso não seja possível realizar a descompilação, por causa de alguma técnica anti- engenharia reversa, por exemplo, o código pode ser desmontado para que seja realizada sua análise em assembly. Revisar o manifesto do aplicativo Vale a pena passar algum tempo revisando o manifesto do aplicativo primeiro – arquivo manifest.xml, quase sempre presente nas aplicações, pois ele pode fornecer informações sobre a funcionalidade do mesmo. Como as seguintes: https://stecine.azureedge.net/webaula/estacio/go0682/aula10.html#collapse01-06 https://stecine.azureedge.net/webaula/estacio/go0682/aula10.html#collapse01-07 https://stecine.azureedge.net/webaula/estacio/go0682/aula10.html#collapse01-08 • Permissões necessárias ao funcionamento; • Componentes da aplicação; e • Atividade principal e subclasse de aplicativo. Análise de código Abrir o projeto em alguma IDE ou outra ferramenta que forneça uma interface gráfica e revisar a lógica implementada. Um bom ponto de partida é começar com os métodos onCreatedo componente de atividade principal e as sub-classes da aplicação especificadas no manifesto, pois é onde inicia o fluxo de execução do aplicativo. Desofuscação e descriptografia Caso seja identificado que a amostra está ofuscada, primeiro é importante verificar se existem desofuscadores prontos. Caso contrário, existem ferramentas que podem fazer isso, já mencionadas em aulas anteriores. Análise comportamental Faz parte do processo de análise a fase de execução da amostra em um emulador aliado a uma ferramenta de análise comportamental para assim entender as funcionalidades da aplicação. Caso alguma técnica de detecção de emulador sejaimplementada, é necessário identificá-la e removê-la do código-fonte. Depuração Às vezes, é difícil entender certas funcionalidades da aplicação, especialmente aquelas em que há uma forte interação com o sistema operacional. Nesses casos, a execução das instruções passo a passo pode ser necessária para auxiliar a análise. Sempre utilize emuladores que suportem a criação de snapshots, para que seja possível retornar ao estado original e reproduzir a mesma situação quantas vezes forem necessárias. Apple A Apple foi fundada em 1976 para vender um dos primeiros computadores pessoais do mundo. No entanto, seus sistemas https://stecine.azureedge.net/webaula/estacio/go0682/aula10.html#collapse01-09 https://stecine.azureedge.net/webaula/estacio/go0682/aula10.html#collapse01-10 https://stecine.azureedge.net/webaula/estacio/go0682/aula10.html#collapse01-11 https://stecine.azureedge.net/webaula/estacio/go0682/aula10.html#collapse01-12 operacionais modernos, como macOS, iOS, watchOS e tvOS, são baseadosprincipalmente na solução NeXTSTEP desenvolvida pela NeXT, Inc., uma empresa fundada por Steve Jobs após sua renúncia da Apple em 1985, e adquirida pela Apple em 1997. Todos os sistemas operacionais modernos da Apple são baseados em um conjunto de componentes unificados, como o sistema operacional Darwin, que é baseado no kernel híbrido XNU. O macOS foi lançado em 2001; antes disso, uma série de sistemas operacionais desenvolvidos entre 1984 e 2001 para a família Macintosh de PC estava em uso. Derivado do NeXTSTEP, foi originalmente baseado em Unix, particularmente, BSD com o microkernel Mach. Além das linguagens C/C++ tradicionais, as principais linguagens de programação que a Apple suporta em seus produtos são Object-C e Swift, essa última desde 2014. As interações entre os aplicativos e o SO são possíveis por meio da API nativa, chamada Cocoa. Já o iOS é relativamente novo e foi criado exclusivamente para dispositivos móveis,afetando o modelo de segurança introduzido com ele. Outros sistemas operacionais mais recentes, como watchOS e tvOS, são amplamente baseados nele. Semelhante ao macOS, o desenvolvimento pode ser feito nas linguagens de programação Object-C e Swift, e a API, nesse caso, é chamada CocoaTouch, que também inclui recursos voltados para dispositivos móveis, como reconhecimento de gestos. Todos os dispositivos com iOS usam processadores baseados em ARM. Segurança A primeira proteção do iOS é a cadeia de inicialização segura. Isso significa que todos os componentes envolvidos no processo de criação são assinados pela Apple e, portanto, constituem uma cadeia de confiança, incluindo o seguinte: • ROM de inicialização: O primeiro código executado assim que o dispositivo é ligado. Localizado na memória como somente leitura, ele verifica o próximo estágio, o bootloaderiBoot ou o Bootloader de baixo nível2 . Uma falha nesse estágio resulta no dispositivo entrando no modo de proteção – Device Firmware Upgrade (DFU). • iBoot: Uma vez concluído, ele verifica o kernel do sistema operacional antes de permitir que seja carregado. Uma falha no estágio iBoot ou LLB faz com que o dispositivo entre no modo de recuperação. • Kernel do iOS: Após a inicialização, um mecanismo denominado KernelIntegrityProtection (KIP), proteção da integridade do Kernel, é habilitado. Seu objetivo é manter o kernel e o código do driver em uma região de memória protegida para que não seja acessível em operações de gravação depois que a inicialização for concluída. Nos modos de recuperação e DFU, o dispositivo pode ser atualizado ou restaurado para um estado válido do sistema operacional. A diferença entre eles é que o modo de recuperação funciona principalmente por meio do iBoot, que é essencialmente uma parte do sistema operacional, podendo ser atualizado ou modificado, se necessário. Atenção Em contraste, o DFU faz parte da memória somente leitura (ROM) e não pode ser violado. O processo de inicialização garante que apenas o código assinado pela Apple possa ser instalado e executado, o que serve como proteção contra bootkits e ameaças semelhantes. Além disso, a Apple se opõe fortemente ao downgrade de software para versões mais antigas e menos seguras; por isso, introduz um mecanismo chamado autorização de software de sistema que impede a instalação desse tipo de aplicações. https://stecine.azureedge.net/webaula/estacio/go0682/aula10.html https://stecine.azureedge.net/webaula/estacio/go0682/aula10.html https://stecine.azureedge.net/webaula/estacio/go0682/aula10.html Proteção de dados Em termos de criptografia, a Apple introduziu vários recursos importantes para torná-la extremamente robusta e altamente produtiva. Cada dispositivo iOS tem seus IDs exclusivos (UID) e IDs de grupo (GID) para serem usados em operações criptográficas, em que o UID é exclusivo para o dispositivo e o GID é compartilhado por todos os processadores do mesmo tipo. 01 O Secure Enclave é um coprocessador seguro que inclui um gerenciador de chaves baseado em hardware, o qual é isolado do processador principal para fornecer uma camada extra de segurança. 02 As chaves criptográficas são geradas dentro desse coprocessador utilizando um gerador de números aleatórios de hardware verdadeiro; normalmente, os geradores de números de software são pseudo- aleatórios. 03 A criptografia de arquivos é implementada com base na tecnologia chamada Proteção de Dados. Ela gera uma nova chave AES de 256 bits para cada arquivo criado no dispositivo. Em dispositivos mais novos, o modo de criptografia AES-XTS é usado, enquanto os dispositivos mais antigos apresentam o modo AES-CBC. 04 Essa chave por arquivo é então criptografada com a chave de classe correspondente, que varia para diferentes tipos de dados e é tratada de forma diferente de acordo com ela. 05 Quando o usuário define uma senha, a proteção de dados é ativada automaticamente. Como ele está conectado ao UID do dispositivo, que não está acessível, é impossível aplicar senhas de força bruta sem que o dispositivo esteja fisicamente presente. Existem outros mecanismos implementados para complicar a força bruta como, por exemplo, contagem de iterações para desacelerá-la, atrasos de tempo de resposta para cada tentativa ou, como última ação, a limpeza automática de dados após inserção de vários valores inválidos consecutivos. Comentário Outros mecanismos de autenticação, como TouchID e FaceID, trabalham em estreita colaboração com essa tecnologia. Todos os dados confidenciais que pertencem a aplicativos podem ser armazenados no chaveiro do iOS, que consiste em um banco de dados SQLite em que os valores são criptografados usando o algoritmo AES-256-GCM. Esse chaveiro possui sua própria classe para lidar com diferentes tipos de dados. Dessa forma, os desenvolvedores podem impedir o acesso a certos dados em circunstâncias específicas, por exemplo, quando o dispositivo está bloqueado. Os itens de chaveiro podem ser compartilhados por vários aplicativos, mas apenas quando vêm do mesmo desenvolvedor. Certificados Clique no botão acima. O iOS requer que todos os códigos em execução no dispositivo sejam assinados usando um certificado válido emitido pela própria Apple; isso é feito para garantir a integridade do código e da fonte. Uma exceção notável a essa regra é o código assinado com certificados de programa corporativo, cujo objetivo é principalmente permitir a distribuição de software proprietário para uso interno ou versões beta para teste apenas dentro de uma organização. Pode ser muito difícil para um invasor obter um certificado válido, mas, mesmo em caso de sucesso, a Apple tem a opção de revogar imediatamente o mesmo caso seja identificada alguma atividade maliciosa. https://stecine.azureedge.net/webaula/estacio/go0682/aula10.html#complementar1 https://stecine.azureedge.net/webaula/estacio/go0682/aula10.html#complementar1 https://stecine.azureedge.net/webaula/estacio/go0682/aula10.html#complementar1 https://stecine.azureedge.net/webaula/estacio/go0682/aula10.html#complementar1 Todos os aplicativos são executados de forma conteinerizada, para que possam acessar apenas os recursos necessários para executar sua função. Eles são executados sob o usuário móvel sem privilégios e não há APIs que permitem o escalonamento de privilégios próprios. Cada aplicativo tem seu próprio diretório para armazenar arquivos e não pode coletar ou alterar informações associadas a outros aplicativos; apenas aplicativos que pertencem ao mesmo grupo e vêm do mesmo desenvolvedor podem acessar um conjunto limitado de itens compartilhados. Análise estática e dinâmica Como sabemos, as linguagens de programação mais comuns usadas para escrever código para plataformas Apple são Objetive-C e Swift. A desmontagem terá uma aparência diferente dependendo da linguagem que o autor do malware escolher, mas, em ambos os casos, praticamente as mesmas ferramentaspodem ser utilizadas para análise. Análise estática É ideal que as ferramentas de análise estática sejam multiplataforma, pois o acesso a um computador Mac ou VM disponível para executar a aplicação nele não é simples. Com isso, a análise pode ser realizada em outros sistemas operacionais sem afetar a eficácia. Antes que o código malicioso possa ser analisado, primeiro ele precisa ser obtido. Existem algumas ferramentas que permitem essa aquisição e que são multiplataformas, como as seguintes: 7-zip iTunes iMazing Pode ser usada para extrair executáveis reais de pacotes DMG e IPA, formatos de arquivos para instalação, tanto do MacOS quanto do iOS. Se a aplicação em análise estiver hospedada na AppStore, a maneira mais fácil de obtê-la é utilizando o iTunes antes da versão 12.7. Depois de baixada, a aplicação pode ser encontrada no subdiretório Aplicativos Móveis. Alternativa comercial ao iTunes que pode ser utilizada para gerenciar aplicativos oficiais da AppStore e obter dados de aplicativos do dispositivo sem qualquer manipulação no aparelho. Após a aquisição, faz-se necessário a ferramenta para realizar a desmontagem. A seguir, listaremos as ferramentas comumente utilizadas para trabalhar com a desmontagem e que são multiplataformas: 1 IDA A mesma que utilizamos na análise em ambiente Windows e Linux, é uma ferramenta poderosa que também pode ser usada para analisar arquivos Mach-O, padrões para esse tipo de ambiente. 2 Hopper Inicialmente implementada para a plataforma Mac, então os autores estão familiarizados com seus componentes internos. Apresenta um desmontador e descompilador e suporta as linguagens Objective-C e Swift 2 radare2 Alternativa de código aberto, permite que os analistas desmontem e analisem arquivos Mach-O. 4 RetDec Esse descompilador de multiplataforma suporta vários formatos de arquivo, incluindo Mach-O, para várias arquiteturas. 5 Ghidra Recém-lançada pela NSA – Agência de Segurança Nacional dos EUA, é uma ferramenta de código aberto que também oferece suporte a executáveis da Apple. Além disso, ferramentas que já abordamos, como file, strings, dentre outras,podem ser usadas para extrair informações de executáveis. Análise dinâmica Controles de segurança mais rígidos e o AppSandbox no iOS geralmente evitam que os pesquisadores realizem análises de forma simples; portanto, frequentemente, o uso de dispositivos desbloqueados com o gerenciador de pacotes Cydia instalado é preferível. O Cydia oferece um mercado de aplicativos alternativo com muitas ferramentas úteis para fins de engenharia reversa. Além do Cydia, é importante instalar a aplicação OpenSSH, que permite que o analista execute comandos no dispositivo de teste a partir do PC conectado. Também é possível configurar ferramentas de monitoramento para iOS, embora isso possa exigir uma certa perícia por parte do analista. Felizmente, existem várias ferramentas que tornam isso possível: • Theos: Conjunto de ferramentas de desenvolvimento para iOS. Um desses utilitários é o logify, que pode ser usado para gerar arquivos de registro que facilitam o entendimento da aplicação. • Cycrypt: Conjunto de ferramentas que permite aos analistas modificar a funcionalidade da aplicação em execução por meio de injeções da lógica necessária. • Frida: Oferece vários recursos úteis para modificar o fluxo de execução por meio de injeções de JavaScript ou apenas para monitorá-lo, por meio de rastreamento de método através do frida-trace. • fsmon/filemon: Essas ferramentas de código aberto podem ser usadas para monitorar eventos do sistema de arquivos. Em relação ao monitoramento de rede, a própria Apple fornece um mecanismo de Interface Virtual Remota (RVI) para ser usado no Mac conectado ao dispositivo via USB. Depois de criada com a ferramenta rvictl, a interface pode ser usada em conjunto com o tcpdump no Mac para registrar todo o tráfego do dispositivo móvel. Além disso, assim como com o macOS, é possível redirecionar o tráfego de rede necessário para um mecanismo de controle de rede, como um proxy, por exemplo, e revisar ou modificar o pacote, se necessário. Comentário Como último tópico, vale reforçar sobre o Jailbreak. O jailbreak geralmente se aplica a dispositivos móveis iOS e tem como objetivo a obtenção de privilégios elevados para remover certas restrições de software. Existem vários motivos pelos quais os usuários podem querer fazer isso com seus dispositivos, tais como: • Obter acesso à funcionalidade extra; • Desbloquear telefones bloqueados por operadoras; • Instalar aplicações não aprovadas. Embora os termos jailbreaking e root sejam frequentemente usados de forma intercambiável, o jailbreak é um termo mais amplo, pois também envolve desbloquear o bootloader para modificar o sistema operacional, bem como permitir a instalação de aplicativos não assinados ou aplicativos distribuídos fora da AppStore, conforme já mencionado.