Jump to content

Search the Community

Showing results for tags 'forense'.



More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Conteúdo Mente Binária
    • Núcleo
    • Projeto Bumerangue
    • Fale com a gente!
  • Comunidade
    • Engenharia Reversa
    • Programação
    • Redes
    • Análise de malware
    • Teste de intrusão
    • Sistemas operacionais
    • Certificações
    • Oportunidades
    • Outros
  • Segurança na Internet's Discussão

Categories

  • Crackmes
  • Documentação
  • Debuggers
  • Ferramentas para PE
  • Utilitários
  • Packers
  • Unpackers

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Como veio parar aqui?


Website


Github/Gitlab


LinkedIn

Found 2 results

  1. 1. Introdução Dumps de memória, discos ou arquivos binários em geral podem conter outros arquivos dentro. Por exemplo, um arquivo TAR (agrupado, sem compactação) praticamente concatena vários arquivos e um só. O arquivo resultante contém todos os bytes dos arquivos de entrada e mais algumas informações que o formato TAR exige. O mesmo acontece com dumps feitos de memória gerados com software de cópia bit a bit, como o dd, parte integrante do coreutils [1], do projeto GNU. Estes podem, e geralmente é que acontece, conter vários arquivos de diferentes tipos. Neste artigo mostrarei uma forma manual, usando ferramentas básicas, para extrair dados de dentro destes dumps. Ao ministrar um dos cursos de segurança na 4Linux, gerei este desafio: O objetivo é extrair dados válidos de um dump de 1 MB fornecido. Dentro dele, há dois arquivos. Não sabemos que tipo de arquivo há dentro do dump, então temos que procurar. NOTA: Este texto é didático e você pode seguir utilizando uma máquina com Linux para fazer a análise do dump. Basta baixar o binário dump.bin. 2. Como procurar tipos de arquivo Antes de tudo, é preciso saber o que se vai procurar. Você pode querer procurar milhares de tipos diferentes, mas terá que conhecer o formato de cada um deles para identificar possíveis bytes dentro do dump. Neste artigo vamos buscar por arquivos BMP e GIF mas este texto pode servir de guia para buscar qualquer tipo. Para isso precisamos estudar o a especificação de cada formato. Este tipo de documento quem fez é o desenvolvedor do formato e é particularmente interessante para desenvovledores de software que trabalharão com imagens como editores, visualizadores, browsers etc. A Wikipedia é uma ótima fonte para isso, mas o site dos consórcios que desenvolvem e mantêm os padrões também podem ser utilizados. Basta googlar por “<extensão> file format” e você achará muitos links. 3. Analisando a especificação do bitmap (BMP) Para o nosso interesse, que não é desenvolver um aplicativo que trabalhe com o formato, mas sim entender o básico do formato, a parte mais interessante está na estrutura de um arquivo bitmap [2], onde cada grupo de bytes de um arquivo deste tipo ganha um significado. O que queremos é saber os bytes que definem o início de um arquivo bitmap. Em outras palavras, queremos saber que bytes estão no cabeçalho (header) de um arquivo bitmap. Veja que na especificação consta: “the header field used to identify the BMP & DIB file is 0x42 0x4D in hexadecimal, same as BM in ASCII” Achamos. Isso nos leva a crer que um bitmap tradicional começa com os bytes 0x42 e 0x4d, o mesmo que BM em ASCII. Sabendo disso podemos checar as strings dentro de nosso dump e fazer um filtro pela string “BM”, certo? 3.1 Buscando a string que identifica um bitmap Para isso, nada mais indicado que o strings, do conjunto binutils [3], também do projeto GNU (thanks FSF!). $ strings -t x dump.bin | grep BM 6ae6d BMP& 8f699 g,UBM_ be081 ?O~BMY ed589 YBMG f63c2 xBM5 A opção “-t x” do strings faz com que ele imprima os endereços (posições) em hexa das strings que encontrou. NOTA: Já se perguntou como funciona o strings? Uma ideia é ler cada byte e testar se este é imprimível, ou seja, tem representação gráfica na tabela ASCII. Caso seja imprimível, só mandar pra tela. Um código de exemplo seria: #include <stdio.h> #include <string.h> int main(int argc, char *argv[1]) { unsigned char byte; FILE *fp = fopen(argv[1], “rb”); while (fread(&byte, sizeof(unsigned char), 1, fp)) putchar(isprint(byte) ? byte : ‘n’); fclose(fp); } Código apenas para fins didáticos. Precisaria de melhorias se fosse usado pra valer. De acordo com a saída do strings, parece que temos 5 bitmaps dentro deste arquivo. Será? Na verdade não podemos garantir. Os bytes referentes aos caracteres ‘B’ e ‘M’ podem ser parte de outro arquivo, de uma música, de um texto ou simplesmente parte de uma instrução de algum programa. Não pode-se garantir que é um bitmap. Temos que analisar! 3.2 Analisando a primeira ocorrência da string BM Sabemos a posição da primeira ocorrência porque o comando strings nos deu. Agora vamos usar um visualizador hexa/ascii para ver o que há próximo destes bytes. No conjunto coreutils há o od, mas eu estou acostumado ao hexdump (hd), do BSD: $ hd -s 0x6ae6d -n 32 dump.bin 0006ae6d 42 4d 50 26 bf 29 c1 f3 f3 81 f0 99 aa f0 aa fd |BMP&.)……….| 0006ae7d d3 d1 e0 3e 92 54 84 b1 18 74 4e b5 00 c1 ce 06 |…>.T…tN…..| A opção “-s 0x6ae6d” faz com que o hd pule (skip) essa quantidade de bytes a partir do início do arquivo, caindo diretamente em nossa string. Já a opção “-n 32” faz com que o hd mostre apenas bytes à frente. Só estamos dando uma olhada, não precisamos ver o arquivo inteiro neste momento. A documentação também diz que os próximos 4 bytes de um bitmap representam o tamanho do arquivo em bytes. Então o tamanho da nossa *possível* imagem seriam os 4 bytes “50 26 bf 29”. Organizando-dos em little-endian (de trás para frente) pois estes representam um número inteiro e não texto, temos 0x29bf2650. Quanto dá isso em decimal? O bash responde: $ echo $((0x29bf2650)) 700393040 O bc também responderia (mas as letras precisam estar em maiúsculo): $ echo “ibase=16;29BF2650” | bc 700393040 Quanto dá isso em megabytes? $ echo $((0x29bf2650 / 1024 / 1024)) 667 Então nosso provável bitmap tem mais de 700 milhões de bytes, aproximadamente 667 MB. Impossível para um dump de 1 MB, certo? Descartado… esses bytes não fazem parte de um bitmap e foi somente coincidência a string “BM”, ainda mais seguida de um “P” (eu fiz isso sem querer hehe). Deixarei para o leitor analisar as outras ocorrências da string “BM”. Vá se divertir! 4. Buscando a string que identifica um GIF Agora vamos buscar GIF. Assim como fizemos com o bitmap, vamos olhar a especificação do GIF [4]. De cara, vemos o header da última versão do formato, que deve ser composto pelos bytes 0x47 0x49 0x46 0x38 0x39 0x61, que representam em ASCII a string “GIF89a”. Se quiser confirmar, pode usar o comando ascii do Linux: $ sudo apt-get install ascii $ ascii Então vamos ao grep: $ strings -t x dump.bin | grep GIF89a 80000 GIF89ae Opa, casamos com a string inteira. Seria muita coincidência esses 6 caracteres casarem se isso não for o início de um GIF? Não sei. Vamos analisar: $ hd -s 0x80000 -n 64 dump.bin 00080000 47 49 46 38 39 61 65 01 1a 02 f7 00 00 bb 9c 91 |GIF89ae………| 00080010 6e 5b 54 d9 ad 9c 6b 69 69 ca a4 94 e3 8c 7d 3f |n[T…kii…..}?| 00080020 1e 0e 33 0d 09 f6 cb ba e1 b4 a3 e3 bb aa eb ca |..3………….| 00080030 8a c8 44 39 0b 05 04 6b 26 21 44 27 19 fa f2 e4 |..D9…k&!D’….| A documentação diz que depois do header de 6 bytes, temos 2 bytes identificando a largura (0x165) e mais 2 para a altura (0x21a), o que definiria um GIF de 357×538 pixels. Aceitável… O próximo byte, segundo o exemplo na documentação, quando é 0xf7, diz que o GIF tem 256 cores, dentre outras informações. Este byte bate com o nosso 0xf7. Parece mesmo ser um GIF… Vamos testar se é um GIF mesmo? Não precisamos ir até o final checando todos os campos. A maioria dos formatos de arquivo definem um ou mais bytes para marcar o fim do arquivo. No caso do GIF, veja na documentação que os últimos bytes são 0x00 (end) e 0x3b (GIF terminator). Lembre-se que isso é *específico* do formato GIF e não é regra para qualquer tipo de arquivo. Cada um tem seu formato. NOTA: Os formatos que não possuem bytes que marcam o fim geralmente possuem um campo que diz o tamanho completo do arquivo, como vimos no bitmap. 4.1 Estratégia para extrair o possível GIF do dump Podemos usar a estratégia de extrair os bytes desde o ‘G’ do “GIF89a” até a primeira sequência 0x00 0x3b. Se for um GIF real, funcionaria, concorda? Vamos buscar então: $ hd -s 0x80000 dump.bin | grep –color “00 3b” 00082b60 3d 97 87 80 00 00 3b 55 d9 60 ab 23 eb 24 ac f1 |=…..;U.`.#.$..| 000ef4e0 2b 61 8d 77 00 3b 7c 58 62 23 4a dc 4c 15 42 da |+a.w.;|Xb#J.L.B.| A primeira sequência que “00 3b” que o grep encontrou após o offset 0x80000 (início do GIF) está em 0x82b65, conseguiu visualizar? É só ir somando 1 em hexa, para cada byte. Neste offset está o 0x00 e em 0x82b66 está o 0x3b. Seguindo nossa teoria, o próximo byte, 0x55 em 0x82b67 não faz parte do GIF. Se diminuirmos este valor de 0x80000, teremos o tamanho total do suposto GIF. Vamos ver: $ echo $((0x82b67-0x80000)) 11111 A resposta é em decimal. Só lembrando algumas informações que leventamos: Tipo: GIFResolução: 357×538 pixelsTamanho: 11111 bytes (11 KB) 4.2 Extração com o dd Se estivermos certo, veremos um GIF quando extrairmos esses bytes. Para isso, podemos usar o dd: $ dd if=dump.bin of=possivel.gif bs=1 count=11111 skip=$((0x80000)) 11111+0 registros de entrada 11111+0 registros de saída 11111 bytes (11 kB) copiados, 0,036675 s, 303 kB/s A opção bs (block size) informa ao dd para assumir blocos de 1 byte. A opção count diz quantos blocos ele vai ler, então vão dar exatamente 11111 bytes. E por fim a opção skip, que só aceita números em decimal (por isso a conversão com o bash) informa quantos bytes o dd vai pular para começar a ler, assim como a opção “-s” do hd. Temos que começar a extração do byte 0x80000, que é onde começa o GIF, lembra? Vamos conferir: $ file possivel.gif possivel.gif: GIF image data, version 89a, 357 x 538 $ wc -c possivel.gif 11111 possivel.gif Agora é só visualizar… 5. Ferramentas para automatizar o trabalho Agora a notícia chata depois que você leu tudo isso: existem ferramentas que fazem tudo isso de maneira automatizada. Uma delas é o foremost [5], que conhece vários tipos de arquivo e é capaz de extrair com precisão a partir de dumps como este. No entanto, considero que mais importante que conhecer ferramentas é saber como elas funcionam e/ou como fazer as coisas sozinho. Sem elas. Say no to script kiddies! 6. Referências A ilustração utilizada neste artigo foi gentilmente cedida por Anderson Barros [6] e seu uso foi autorizado. [1] http://www.gnu.org/software/coreutils/ [2] http://en.wikipedia.org/wiki/BMP_file_format#Bitmap_file_header [3] http://www.gnu.org/software/binutils/ [4] http://en.wikipedia.org/wiki/Graphics_Interchange_Format#Example_GIF_file [5] http://foremost.sourceforge.net/ [6] http://anderson-barros.blogspot.com
  2. No dia-a-dia da programação, análise de binários e outras áreas relacionadas à segurança da informação é comum profissionais precisarem de conversões rápidas de dados, normalmente números e strings. Muitas vezes recorremos a sites, scripts, programas gráficos, calculadores e outros, mas como nos sentimos mais confortáveis na linha de comando, foi lá que decidi fazer algo. Há alguns anos iniciei um projeto que chamei de bashacks, que é um conjunto de funções em bash para as mais variadas tarefas, mas percebi que muitas vezes não sei que tipo de informação estou tratando e gostaria de ver rapidamente diversas conversões para um certo tipo de dado (um número por exemplo), para ver qual deles faz mais sentido. Foi aí que pensei em criar o eXamine, cujo nome veio do comando homônimo do gdb (GNU Debugger). Trata-se de um software de linha de comando para o que chamo de conversão indiscriminada e irresponsável de dados. Para ficar ainda mais enxuto, e também roubando a ideia do gdb, eu o chamo de x. Então supondo que você na sua análise você tenha encontrado um número hexadecimal, por exemplo, 0x585ca92c e deseja ver as conversões possíveis para ele. É só mandar pro x: $ echo 0x585ca92c | x Hex string: 30783538356361393263 Byte array: \x30\x78\x35\x38\x35\x63\x61\x39\x32\x63 URL encoding: %30%78%35%38%35%63%61%39%32%63 ROT13: 0k585pn92p Signed int: 1482467628 Unsigned int: 1482467628 Float: 9.70477e+14 Hexadecimal: 0x585ca92c Octal: 013027124454 Binary: 0b1011000010111001010100100101100 IPv4: 88.92.169.44 Timestamp: Fri, 23 Dec 2016 04:33:48 UTC/GMT-0 O jeito correto de interpretar a saída do eXamine é: se a entrada for tratada como x, então é y, ou seja, no exemplo, se o número for tratado como string (texto), então os bytes em hexadecimal equivalente são 30 78 35 38 35 63 61 39 32 e 63. Já se for tratado como número, então a conversão para inteiro fica 1482467628. Ainda tratando como número, pode ser o endereço IPv4 88.92.169.44 ou a data/hora de hoje. Qual é o certo? A resposta é: depende de como você quer tratar. Vê o que faz mais sentido pra sua análise e vai na fé. Sabemos que bytes são bytes e como serão usados depende da interpretação dada. 0x41 pode ser utilizado num programa como um inteiro de 8 bits, ou como parte de um inteiro de 16, 32 ou 64-bits, ou mesmo como o caractere ‘A’ (depende de como o programa usa essa informação). O eXamine não te ajuda nisso, mas imprime como saída algumas conversões possíveis e deixa você decidir. Por exemplo, você pode passar uma string para ele: $ echo 'feliz natal' | x Hex string: 66656c697a206e6174616c Byte array: \x66\x65\x6c\x69\x7a\x20\x6e\x61\x74\x61\x6c URL encoding: %66%65%6C%69%7A%20%6E%61%74%61%6C ROT13: sryvm angny Signed int: 0 Unsigned int: 0 Float: 0 Hexadecimal: 00 Octal: 0 Binary: 0b ASCII char: NUL RGB: (0, 0, 0) IPv4: 0.0.0.0 Timestamp: Thu, 01 Jan 1970 00:00:00 UTC/GMT-0 As saídas numéricas neste caso ficam zeradas e cabe a você saber que isso faz sentido, afinal, não passei um número como entrada. É possível também utilizá-lo no modo interativo. Neste caso, primeiro comandei x, depois digitei o número 65: $ x 65 Hex string: 3635 Byte array: \x36\x35 URL encoding: %36%35 ROT13: 65 Signed int: 65 Unsigned int: 65 Float: 0 Hexadecimal: 0x41 Octal: 0101 Binary: 0b1000001 ASCII char: A RGB: (0, 0, 65) IPv4: 0.0.0.65 Timestamp: Thu, 01 Jan 1970 00:01:05 UTC/GMT-0 Ainda há muito o que fazer no eXamine. Há várias conversões possíveis com strings, inteiros de outros tamanhos, hashes, etc. Se você tiver alguma sugestão de conversão, basta abrir uma issue na página do projeto no Github e a discutimos lá. Se souber programar em C, ficarei feliz em receber seu pull request após a discussão.
×
×
  • Create New...