Ir para conteúdo
  • anderson_leite
    Olá! No artigo anterior falamos sobre Signals, que é de suma importância para a comunicação entre processos, mas para construir o nosso debugger precisamos muito mais do que apenas isso, precisamos de fato ter total controle sobre um dado processo e se possível controlar até o seu própio início.
    Neste artigo será explicado o que são forks e seu uso em desenvolvimento de aplicações em sistemas UNIX. Sem mais delongas, vamos prosseguir!!!?
    Resumidamente a syscall fork é usada para a duplicação e criação de um processo. Quando um dado processo chama a função fork(), é criada uma cópia idêntinca de seus dados. Note que apenas uma cópia é feita, o processo filho não compartilha o mesmo espaço de memória do pai.
    A syscall fork retorna um PID que é usado para indetificar em qual processos estamos e também dar acesso ao ID do processo filho. Caso o PID seja 0 estamos executando no filho, caso seja qualquer outro somos o processo pai, isso ocorre pois o pai precisa saber o PID do filho, mas o filho não necessariamente precisa saber o seu própio (da mesma maneira que o seu processo não sabe o própio PID ao menos que o mesmo peça).
    Algo interessante de se notar é que os Init System usados para subir e gerenciar serviços de sua máquina trabalham dessa mesma maneira, você pode checar sua árvore de processo usando comando pstree:
    $ pstree Dessa maneira você tem uma representação bem visual de como está dividida a sua estrutura de processos ?. Note que todos os processos são filhos do seu Init system (seja ele SystemV, Systemd, etc). Aconselho você explorar o comando pstree para uma visão bem mais detalhada do seu sistema! Outra abordagem é usar o própio comando ps:
    $ ps -ef Rode o comando acima (dependendo da quantidade de processos use um pipe para o less ?) e com ele teremos uma visão mais detalhada. A coluna PID representa o ID do processo em si e a coluna PPID representa o "Parent Process ID", que nada mais é que o ID do processo pai. Note que o PID 1 é o seu Init System e os seus processos rodam como filho dele!

    Vale notar que o processo Pai do própio init é o PID 0, que é conhecido como "swapper" ou "scheduler", que é o processo responsavel para realização de paging. Paging é o sistema de gerenciamento de memória que salva os dados da RAM em uma memória secundária (HD, SSD e etc) e recupera em formato de páginas (outros PID também são filhos do propio PID 0 como PID 2 que gerencia todas as threads que rodam em Kernel Land(KThread) etc).
     
    Programando Forks
    A syscall fork está na lib  <unistd.h> (Unix Standard library) e tem a seguinte construção:
    #include <sys/types.h> #include <unistd.h> pid_t fork(void); Precisamos incluir a lib <sys/types.h> para que seja possivel acessar o tipo pid_t. A função fork não espera nenhum parâmetro para a sua construção e o código abaixo demonstra o quão simples é cria um fork.
    #include <stdio.h> // Acesso a syscall #include <unistd.h> // Acesso ao tipo variavel pid_t #include <sys/types.h> int main(void) { int x; printf("Processo normal...\n"); printf("Forking...\n"); sleep(5); pid_t pid = fork(); x = 40; if (pid == 0) { printf("Eu sou o processo filho meu PID: %d\n", pid); } else { printf("Eu sou o processo pai de %d\n", pid); } sleep(5); return 0; } Compile o código acima da seguinte forma:
    $ gcc -o fork fork.c $ ./fork Note que o código se "divide" a partir da chamada fork e um if  é usado para saber se estamos executando no pai ou no filho, note também que o pai sabe o PID e o filho não.
    Para melhor visualização o código acima roda por 10 segundos (por conta da chamada ao sleep com esse tempo de espera). Abra um outro terminal e rode o comando:
    $ watch -n1 pstree O comando acima vai executar o pstree a cada 1 segundo, desta forma você verá o exato momento da criação do fork.

    Comunicando-se com o processo fork
    Agora imagine que um  processo precisa esperar o seu filho terminar algum trabalho e dependendo do seu sinal o processo pai realiza alguma ação. A comunicação entre o processo pai e o filho se da por signals. O pai pode saber exatamente o estado do seu processo filho usando a syscall wait e waitpid, ambas na lib <sys/wait.h>:
    #include <sys/types.h> #include <sys/wait.h> pid_t wait(int *status); pid_t waitpid(pid_t pid, int *status, int options); A syscall wait espera que ao menos 1 de seus processos filho troque de estado, já a waitpid espera por um processo específico. Como sabemos exatamente qual processo queremos rastrear iremos usar esta call ?:
    #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> int main(void) { printf("Spliting work...\n"); pid_t pid = fork(); if (!pid) { int a = 0; for(int i = 0; i < 100000000; i++ ) { a += i*2 + 10 *i; } return 9; } int status; int signal; printf("Waiting child finish work...\n"); waitpid(pid, &status, 0); if (WIFEXITED(status)) { signal = WEXITSTATUS(status); printf("Child exited, status = %s\n", strsignal(signal)); } return 1; } Compile o código acima e execute:
    $ gcc -o work work.c $ ./work Spliting work... Waiting child finish work... Child exited, status = Killed Veja que após a chamada de fork nosso processo filho executa várias iterações e realiza um cálculo (um cálculo totalmente randômico) e após isso retorna 9. Este retorno em questão é apenas por motivos educativos (no artigo anterior falamos de sinais e como eles funcionam). O processo pai usa a syscall waitpid para esperar que qualquer signal seja enviada do pid especificado. Após receber um status é verificado se o fork saiu (WIFEXITED) e se sim, pegamos o signal enviado usando WEXITSTATUS(status da saída) e usamos a chamada strsignal(provida pela string.h) para recuperar uma versão em texto do signal. Nesse caso iremos recuperar o signal "KILLED", pois colocamos 9 apenas por razões educativas.
    Normalmente se tudo ocorreu bem colocamos 0 (inclusive é dessa maneira que sua shell avalia se o programa rodou certo).
    $./work && echo "Filho saiu com 0, tudo certo..." || echo "Filho saiu com 1, algo errado..." No caso acima a nossa shell irá criar um fork do nosso work, executar o nosso programa (que por sua vez também executa um fork mas não entra em questão aqui) e se o signal retornado pelo fork for 0 ele imprime uma mensagem, caso contrario ele imprime uma mensagem de erro, dessa maneira você pode orquestrar um shell scripting usando o própio retorno do processo ?
    Tente mudar o retorno do fork acima e verifique seu status usando funções providas pela <sys/wait.h>. No exemplo acima usamos apenas a call WIFEXITED e WEXITSTATUS, mas existem várias outras.
    Forks são de extrema importância para criação e gerenciamento de processos e iremos usar forks para que seja possível executar o programa que queremos debugar, dessa maneira o software em questão vai ser filho do nosso debugger, o que nós da total controle sobre o mesmo.
    Comentarios são todos bem vindos e todos os códigos usados estão disponíveis no github! ?

    Links úteis:
        Process Control
        fork
        wait
        Process State
        Fork Bomb - Cuidado com isso

    anderson_leite
    Olá, neste artigo compartilharei um pouco da minha pesquisa no desenvolvimento de debuggers. No momento estou trabalhando em um protótipo de debugger para Linux, mas nada tão avançado quanto um gdb ou radare (muitas coisas são necessárias para chegar neste nível de maturidade de software).
    O desenvolvimento de debuggers é uma atividade muito interessante, já que, em sua forma mais básica, pode ser resumido em uma série de chamadas de sistema (syscalls) para que seja possível o controle do processo a ser depurado (muitas vezes chamado de debuggee) e de seus recursos, mas não vamos colocar a carroça na frente dos cavalos e vamos em partes.
    Antes de começarmos a discutir detalhes mais específicos acerca da depuração de processos, é necessário um entendimento básico de como os mesmos se comunicam na plataforma que vamos desenvolver o tal debugger, no nosso caso, UNIX-like.
    Inter-process communication (IPC)
    IPC é uma forma que processos podem utilizar para se comunicar dentro de um sistema operacional. Existem diversas maneiras de comunicação: via sinais (signals), sockets, etc, mas para a criação de um debugger é apenas necessário usar sinais para a execução.
    Sinais funcionam como uma notificação que pode ser enviada à um processo específico para avisar que algum evento ocorreu.
    É possível também programar um processo para reagir aos sinais de maneira não padrão. Se você já teve um uso razoável de Linux, você provavelmente já enviou sinais à um processo. Por exemplo, quando você aperta Ctrl+C para interromper a execução de um processo, é enviado um sinal do tipo SIGINT, que nada mais é que uma abreviação para Signal Interruption. Se o processo em questão não está preparado para reagir a este sinal, o mesmo é terminado. Por exemplo, considere o seguinte código:
    #include <stdio.h> int main(void) { while(1) printf("hi\n"); return 0; } Ao compilar e executar o código acima e apertar Ctrl+C, o mesmo encerra como esperado, porém podemos verificar que um SIGINT foi enviado usando a ferramenta ltrace, que além de listar chamadas a bibliotecas também mostra os sinais enviados ao processo:
    $ gcc -o hello hello.c $ ltrace ./hello Rode o comando acima e aperte Ctrl+C para verificar o sinal enviado!
    Programando reações a sinais
    A capacidade de enviar sinais a um processo nos dá a possibilidade de saber o que esta acontecendo com algum processo específico que estejamos depurando.
    Para programar reações a algum tipo de sinal, podemos incluir a biblioteca signal, para que possamos usar a função e estrutura (struct) sigaction:
    struct sigaction { void (*sa_handler)(int); void (*sa_sigaction)(int, siginfo_t *, void *); sigset_t sa_mask; int sa_flags; void (*sa_restorer)(void); };  
    int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); A struct sigaction nos permite adicionar handlers (tratadores) para nossos sinais, enviando o endereço de nossa função que realiza algum tipo de ação baseada no sinal enviado para o campo sa_handler(sigaction handler).
    Um handler neste contexto nada mais é que uma função que sempre vai ser chamada quando um dado sinal for enviado, dessa maneira podemos executar alguma ação quando recebermos um sinal.
    Já a função sigaction recebe o número do sinal, porém uma série de macros já são pré-definidas e podemos passar como argumento apenas o nome do sinal, como SIGINT por exemplo. A função recebe também a referência da struct previamente definida (struct sigaction) e, caso precise trocar um handler por outro, também recebe no último argumento (oldact) o handler anterior, para que possa ser feita a troca pelo novo. Como não é o nosso caso, vamos passar NULL neste último argumento.
    O código abaixo simula um uso de handlers de sinais, que imprime uma mensagem quando um sinal é enviado:
    #include <stdio.h> #include <signal.h> #include <unistd.h> // sleep void simple_handler(int sig) { printf("Hello SIGINT\n"); } int main() { struct sigaction sig_handler = { simple_handler }; sigaction(SIGINT, &sig_handler, NULL); sleep(1000); return 0; } Ao executar o código acima, aperte Ctrl+C e veja que será imprimido a mensagem do nosso handler!
    O manual da signal contém uma tabela com todos os sinais usados por sistemas POSIX.
    Para enviarmos sinais facilmente em sistemas UNIX podemos usar o comando kill:
    $ kill -l O comando acima mostra todos os sinais e seus respectivos números, com isso podemos fazer algo interessante. Por exemplo, rode o código acima em um terminal separado e use o kill para se comunicar com o seu processo, assim:
    $ ps ax | grep simple_signal $ kill -2 <pid> Primeiro buscamos o PID do nosso processo então usamos o kill que espera como primeiro argumento numero do sinal (listado em kill -l) e o segundo o PID do processo alvo.
    Ao enviar o sinal, podemos ver que o nosso código reage aos sinais que foram associados a um handler especifico! Tente criar handlers para vários sinais e teste usando o comando kill. ?
    Abaixo um código para demonstrar um uso real de um software que escreve dados aleatórios nos arquivos temporários e antes de uma finalização abrupta, é deletado o que foi usado:
    #include <stdio.h> #include <signal.h> #include <unistd.h> // Log errors void fatal(const char* err_msg) { fprintf(stderr, "Error: %s\n", err_msg); } // Escreve algo random em um arquivo void random_work() { FILE* temp_files = fopen("/tmp/foo", "w"); if (!temp_files) { fatal("Cant open foo!"); } else { fprintf(temp_files, "%s", "Random random random!\n"); fclose(temp_files); } } // Handler para deleta arquivos criados void handler_termination(int sig) { // Verifica se existe usando a function access // Caso existe usa a syscall unlink para remover o arquivo if (access("/tmp/foo", R_OK) < 0) return; unlink("/tmp/foo"); printf("All clean! closing...\n"); } int main() { //struct sigaction que recebe a function handler_termination como valor do seu handler struct sigaction interruption_handler; interruption_handler.sa_handler = handler_termination; // Syscall sigaction que associa o nosso handler para um sinal especifico // O ultimo campo NULL, espera o handler anterior para que posso tornar o novo handler o default sigaction(SIGINT, &interruption_handler, NULL); random_work(); sleep(1000); handler_termination(0); return 0; } Dica: Dê uma olhada na tabela de sinais e crie handlers para o mesmo código acima!
    Para a construção do nosso debugger iremos focar mais no signal SIGTRAP, para que seja possível detectar se o nosso processo sofreu uma "trap" da CPU. Uma trap ocorre quando acontece alguma interrupção síncrona na execução, que faz o processo ficar parado até que o sistema operacional execute alguma ação. Isto será usado para implementar e interpretar breakpoints. Veremos tudo isso com mais detalhes em breve!
    Sinta-se livre para comentar e sugerir correções e melhorias. Até o próximo artigo!
    Links úteis:
    Syscall IPC CERO 11 – Linux Syscalls Syscalls, Kernel mode vs User mode Programação em C

    Fernando Mercês

    Comparando executáveis

    Por Fernando Mercês, em Engenharia Reversa,

    Saudações, leitores do Mente Binária! Hoje me deu vontade de falar sobre uma tarefa que eventualmente preciso fazer na empresa onde trabalho, que é a de verificar as diferenças entre arquivos executáveis, normalmente de Windows, também conhecidos por executáveis PE.
    Há vários usos ao comparar binários. É possível avaliar o que mudou na versão atual de um software em relação à anterior, descobrir o que muda em cada sample diferente de uma mesma família de malware, etc. Esses dias mesmo me foi pedido que verificasse a diferença entre 6 arquivos maliciosos, que compartilho abaixo como fiz.
    Reconhecimento básico
    Os arquivos que recebi tinham seu hash SHA-256 como nome. A primeira coisa que fiz foi checar seu tipo (usando comandos do macOS, mas o Linux tem comandos similares):
    $ file * fdba340bb35635934aa43b4bddd11df31f2204e73394b59756931aa2f7f59e04: PE32 executable (GUI) Intel 80386, for MS Windows fdf3060eb9c39b1a2be168b1ac52c2f80171394e73fe03c4e0c57911cb9358a9: PE32 executable (GUI) Intel 80386, for MS Windows fedf9d9815b3d0ad28e62f99d5dcf92ec0f5fcb90135b4bdc30bb5709ab9ff05: PE32 executable (GUI) Intel 80386, for MS Windows ff2f1be6f64c91fa0a144cbc3c49f1970ba8107599d5c66d494ffb5550b0f7fd: PE32 executable (GUI) Intel 80386, for MS Windows ff53c7ba285ffdc2c29683bb79bb239ea59b3532f8b146523adf24d6d61fc640: PE32 executable (GUI) Intel 80386, for MS Windows ffee504e292a9f3ae6c439736881ebb314c05eac8b73d8b9c7a5a33605be658e: PE32 executable (GUI) Intel 80386, for MS Windows Só para garantir, também chequei o SHA-256 deles e realmente bateu com o nome, o que era esperado:
    $ shasum -a256 * fdba340bb35635934aa43b4bddd11df31f2204e73394b59756931aa2f7f59e04 fdba340bb35635934aa43b4bddd11df31f2204e73394b59756931aa2f7f59e04 fdf3060eb9c39b1a2be168b1ac52c2f80171394e73fe03c4e0c57911cb9358a9 fdf3060eb9c39b1a2be168b1ac52c2f80171394e73fe03c4e0c57911cb9358a9 fedf9d9815b3d0ad28e62f99d5dcf92ec0f5fcb90135b4bdc30bb5709ab9ff05 fedf9d9815b3d0ad28e62f99d5dcf92ec0f5fcb90135b4bdc30bb5709ab9ff05 ff2f1be6f64c91fa0a144cbc3c49f1970ba8107599d5c66d494ffb5550b0f7fd ff2f1be6f64c91fa0a144cbc3c49f1970ba8107599d5c66d494ffb5550b0f7fd ff53c7ba285ffdc2c29683bb79bb239ea59b3532f8b146523adf24d6d61fc640 ff53c7ba285ffdc2c29683bb79bb239ea59b3532f8b146523adf24d6d61fc640 ffee504e292a9f3ae6c439736881ebb314c05eac8b73d8b9c7a5a33605be658e ffee504e292a9f3ae6c439736881ebb314c05eac8b73d8b9c7a5a33605be658e PS.: No Linux o comando seria sha256sum ao invés de shasum -a256.
    O próximo passo foi checar o tamanho deles:
    $ wc -c * 396973 fdba340bb35635934aa43b4bddd11df31f2204e73394b59756931aa2f7f59e04 396973 fdf3060eb9c39b1a2be168b1ac52c2f80171394e73fe03c4e0c57911cb9358a9 396973 fedf9d9815b3d0ad28e62f99d5dcf92ec0f5fcb90135b4bdc30bb5709ab9ff05 396973 ff2f1be6f64c91fa0a144cbc3c49f1970ba8107599d5c66d494ffb5550b0f7fd 396973 ff53c7ba285ffdc2c29683bb79bb239ea59b3532f8b146523adf24d6d61fc640 396973 ffee504e292a9f3ae6c439736881ebb314c05eac8b73d8b9c7a5a33605be658e 2381838 total Aqui apresentou-se um caso atípico: os binários possuem exatamente o mesmo tamanho! Já pensei que havia grandes chances de as diferenças entre eles serem mínimas: provavelmente algo usado pelo autor do malware só para "mudar o hash" na tentativa de evitar que os antivírus detectem os arquivos idênticos, por exemplo. Essa tentativa é na verdade frustrada visto que, ao contrário do que muitos pensam, os antivírus não detectam malware por hash normalmente, já que isso seria muito custoso do ponto de vista do desempenho (seria preciso ler todos os bytes do arquivo!) e também seria muito fácil tornar um novo arquivo indetectável - bastaria alterar um único byte para um hash final completamente diferente.
    Comparação de estrutura
    Se estivéssemos tratando arquivos de texto, poderia simplesmente usar o comando diff, mas o assunto aqui é PE, então algo interessante de verificar é sua estrutura, que consiste basicamente em cabeçalhos, localizados antes das seções. Se você não sabe do que estou falando, recomendo os seguintes recursos:
    Posts do @Leandro Fróes sobre o formato PE e suas referências. Capítulo sobre PE do livro Fundamentos de Engenharia Reversa. Aulas 5 e 6 do CERO, nosso Curso de Engenharia Reversa Online em vídeo. Digitar "PE executable" no Google ler o que curtir. Depois dessa imersão no mundo dos executáveis PE, não tenho dúvidas de que você vai se apaixonar por eles também! ?
    Voltando à comparação, o que eu quero dizer com estrutura? Bem, os valores dos campos dos cabeçalhos. Por exemplo, para ver o cabeçalho COFF de um arquivo PE, usei o readpe, parte do kit de ferramentas pev:
    $ readpe -h coff fdba340bb35635934aa43b4bddd11df31f2204e73394b59756931aa2f7f59e04 COFF/File header Machine: 0x14c IMAGE_FILE_MACHINE_I386 Number of sections: 5 Date/time stamp: 1401620468 (Sun, 01 Jun 2014 11:01:08 UTC) Symbol Table offset: 0 Number of symbols: 0 Size of optional header: 0xe0 Characteristics: 0x102 Characteristics names IMAGE_FILE_EXECUTABLE_IMAGE IMAGE_FILE_32BIT_MACHINE Mas não, não usei o pev por saudosismo! A ideia de ter uma saída em texto da estrutura desses binários é depois usar o comando diff para compará-las. A primeira coisa que precisei então foi gerar um .txt contendo toda a estrutura, e não só o cabeçalho COFF, para cada um dos arquivos. Uma repetição em bash dá conta do recado:
    $ ls -1 readpe_output_* readpe_output_fdba340bb35635934aa43b4bddd11df31f2204e73394b59756931aa2f7f59e04.txt readpe_output_fdf3060eb9c39b1a2be168b1ac52c2f80171394e73fe03c4e0c57911cb9358a9.txt readpe_output_fedf9d9815b3d0ad28e62f99d5dcf92ec0f5fcb90135b4bdc30bb5709ab9ff05.txt readpe_output_ff2f1be6f64c91fa0a144cbc3c49f1970ba8107599d5c66d494ffb5550b0f7fd.txt readpe_output_ff53c7ba285ffdc2c29683bb79bb239ea59b3532f8b146523adf24d6d61fc640.txt readpe_output_ffee504e292a9f3ae6c439736881ebb314c05eac8b73d8b9c7a5a33605be658e.txt Eu usei o readpe sem nenhuma opção, assim ele imprime todos os cabeçalhos, incluindo os de seções. Só pra começar fiz um diff do primeiro para o segundo e não houve qualquer saída, ou seja, a estrutura dos arquivos eram idênticas! E eram mesmo:
    $ wc -c readpe_output_* 21627 readpe_output_fdba340bb35635934aa43b4bddd11df31f2204e73394b59756931aa2f7f59e04.txt 21627 readpe_output_fdf3060eb9c39b1a2be168b1ac52c2f80171394e73fe03c4e0c57911cb9358a9.txt 21627 readpe_output_fedf9d9815b3d0ad28e62f99d5dcf92ec0f5fcb90135b4bdc30bb5709ab9ff05.txt 21627 readpe_output_ff2f1be6f64c91fa0a144cbc3c49f1970ba8107599d5c66d494ffb5550b0f7fd.txt 21627 readpe_output_ff53c7ba285ffdc2c29683bb79bb239ea59b3532f8b146523adf24d6d61fc640.txt 21627 readpe_output_ffee504e292a9f3ae6c439736881ebb314c05eac8b73d8b9c7a5a33605be658e.txt 129762 total $ md5 !$ md5 readpe_output_* MD5 (readpe_output_fdba340bb35635934aa43b4bddd11df31f2204e73394b59756931aa2f7f59e04.txt) = 05b36b89b1165b3d619bee16f8a1d7f7 MD5 (readpe_output_fdf3060eb9c39b1a2be168b1ac52c2f80171394e73fe03c4e0c57911cb9358a9.txt) = 05b36b89b1165b3d619bee16f8a1d7f7 MD5 (readpe_output_fedf9d9815b3d0ad28e62f99d5dcf92ec0f5fcb90135b4bdc30bb5709ab9ff05.txt) = 05b36b89b1165b3d619bee16f8a1d7f7 MD5 (readpe_output_ff2f1be6f64c91fa0a144cbc3c49f1970ba8107599d5c66d494ffb5550b0f7fd.txt) = 05b36b89b1165b3d619bee16f8a1d7f7 MD5 (readpe_output_ff53c7ba285ffdc2c29683bb79bb239ea59b3532f8b146523adf24d6d61fc640.txt) = 05b36b89b1165b3d619bee16f8a1d7f7 MD5 (readpe_output_ffee504e292a9f3ae6c439736881ebb314c05eac8b73d8b9c7a5a33605be658e.txt) = 05b36b89b1165b3d619bee16f8a1d7f7
    Os hashes MD5 da saída em texto da estrutura de todos os arquivos batem. Eles são mesmo iguais estruturalmente!
    Passado o choque, percebi que teria que comparar o conteúdo das seções (código, dados, talvez resources, etc). Aí fui obrigado a inicializar minha VM do Janelas mesmo...
    Comparação do conteúdo das seções
    Existem alguns softwares que trabalham com PE e possuem funções de comparação de dois executáveis. Eu costumava usar o Cold Fusion (um antigo gerador de patch) pra isso, mas ele tem alguns bugs que me impediram. Achei a mesma função no Stud_PE, mas ele localiza arquivos por extensão na janela de comparação, então renomeei o primeiro e o segundo arquivo que tinha para a.exe e b.exe respectivamente.
    Ao abrir o a.exe no Stud_PE, usei o botão "File Compare", selecionei o método "Binary", setei o "Starting from" pra "Raw" e cliquei em "Compare":

    Se você não entendeu por que fiz isso, volte uma casa ou leia os tutorias de PE que indiquei. Ou pergunte que eu falo. ?
    Bem, entre esses dois caras então havia 9 bytes que o diferenciavam e eu já tinha os offsets a partir do início do arquivo. Agora é descobrir em que seção eles estavam no PE, o que são, o que comem e como eles vivem. ?
    Descobrindo como as diferenças são usadas
    Abri o executável no x64dbg (na verdade no x32dbg, já que este binário é de 32-bits) mas percebi que o entrypoint estava no endereço 013706AA. Como o ImageBase deste binário é 00400000, percebi que o ASLR estava habilitado e, antes de continuar , desabilitei-o com o DIE, como mostro neste vídeo rápido no canal Papo Binário:
    Antes de reabrir o binário no x32dbg, convém lembrar que eu tinha um offset e precisava convertê-lo para endereço virtual (VA). Isso é feito com o que alguns analisadores de PE chamam de FLC (File Location Calculator). O DIE tem, o Stud_PE tem e o pev também tem, com a ferramenta ofs2rva:
    $ ofs2rva 0x4c451 a.exe 0x4dc51 Mas pra não você não me acusar de saudosismo de novo, vou mostrar no Stud_PE ?

    Percebe que o Stud_PE já diz que este byte pertence à seção .rdata, o que à esta altura você já sabe, caso tenha feito o trabalho de casa de estudo do PE, que é provavelmente uma seção de dados somente-leitura, então há grandes chances de nossa sequência diferentona pertencer à uma string constante, por exemplo. Fui ver no debugger como é que tava a festa. Abri o a.exe lá e dei um Ctrl+G no Dump pra ir pro endereço 44DC51:

    De fato tinha uma string lá: zuk0KRrGrP, mas ela na verdade começava em 44DC44 e pra saber quando ela era usada no malware, coloquei um breakpoint de hardware no acesso ao byte, que é o primeiro da string e cheguei à conclusão de que, como o nome sugere, é realmente uma string de identificação da campanha do malware, sempre no mesmo offset (calculei de novo usando FLC).  Agora foi só ver a dos outros e novamente recorri à uma ferramenta do pev (?), a pestr:
    $ for i in *; do echo $i; pestr -so $i | grep 0x4c444; echo; done fdba340bb35635934aa43b4bddd11df31f2204e73394b59756931aa2f7f59e04 0x4c444 .rdata identifierStrzuk0KRrGrP fdf3060eb9c39b1a2be168b1ac52c2f80171394e73fe03c4e0c57911cb9358a9 0x4c444 .rdata identifierStrAR0U4hr1wW fedf9d9815b3d0ad28e62f99d5dcf92ec0f5fcb90135b4bdc30bb5709ab9ff05 0x4c444 .rdata identifierStrswEYVkFWeg ff2f1be6f64c91fa0a144cbc3c49f1970ba8107599d5c66d494ffb5550b0f7fd 0x4c444 .rdata identifierStrKXaUzlBDIj ff53c7ba285ffdc2c29683bb79bb239ea59b3532f8b146523adf24d6d61fc640 0x4c444 .rdata identifierStrv91TJ5c3Lr ffee504e292a9f3ae6c439736881ebb314c05eac8b73d8b9c7a5a33605be658e 0x4c444 .rdata identifierStrOzJnvFQy2U Bom, daí o céu é o limite. Dá pra criar assinatura, criar um script pra extrair esse ID da campanha, enfim, missão cumprida.

    FAQ
    1. Por que você não utilizou só um comparador de arquivos qualquer, que compara os bytes em hexadecimal?
    Eu queria saber exatamente onde estavam as diferenças entre os arquivos, se na estrutura ou não. Em caso negativo, é código? Se sim, que código? Que faz o que? São dados? Usados onde? Em qual seção? Um editor hexadecimal ignorantão não me daria isso. Além disso, se os arquivos fossem diferente estruturalmente, ou em tamanho, eu queria saber antes, pra não perder tempo analisando diferenças de bytes hexa que eu não sei o que é.
    2. Existem softwares para comparar binários PE muito mais poderosos, como o BinDiff. Por que caralhas você não o usou?
    O BinDiff é pra comparar código. Minha diferença estava nos dados. Além disso, o BinDiff e seus amigos traduzem o Assembly original do binário para uma linguagem intermediária própria e comparam lógica, não instruções. É bem fodão, mas não me atendia neste caso, afinal eu já sabia que os binários eram idênticos em funcionalidade. Só queria saber onde estava a diferença exata.
    3. Percebi pela screenshot do Stud_PE que ele também compara a estrutura dos arquivos PE, então todo aquele processo com o readpe foi à toa?
    Sim, foi só pra Inglês ver. Não, brincadeira! O Stud_PE compara os cabeçalhos COFF, Optional e os diretórios de dados somente. O readpe imprime todos os cabeçalhos, incluindo todas as seções mais os imports. É outro nível, moleque! ?

    4. E quanto à executáveis ELF?
    O título não fala somente de PE propositalmente, já que a mesma técnica pode ser usada para arquivos ELF, só mudando os programas (readelf, etc).
    Por hora é só. Se você deixar sua análise abaixo ou quiser fazer um comentário/pergunta, ficarei muito grato. Considera apoiar a gente também vai. ?

    Leandro Fróes

    Comando find e suas miscelâneas

    Por Leandro Fróes, em Linux,

    Após ver sobre o comando find no nosso canal Papo Binário decidi estudar um pouco mais sobre o mesmo. Revisando estas anotações pensei que seria interessante compartilhá-las, tendo em vista que o find é um comando extremamente poderoso. Alguns dos parâmetros já foram abordados no vídeo, mas vou repassar alguns aqui, não custa nada, não é mesmo?!
    Este comando pode ser útil para diversas tarefas, dentre elas investigação, administração ou mesmo aprendizado sobre o sistema.
    Indo direto ao ponto, o find é um comando para procurar itens no filesystem (arquivos, links, diretórios, etc). O que o difere de outros programas que fazem isto é a quantidade de opções que a ferramenta possui e o fato de não depender da variável $PATH para encontrar um binário. O comando leva como principal parâmetro um path, ou seja, um caminho para procurar algo. Se não passarmos nada ele entenderá que o path é o diretório atual:
    find find /etc Se não especificarmos exatamente o que queremos buscar o find simplesmente nos mostra tudo o que achar pois ele varre o filesystem recursivamente na hora de procurar algo, mas não queremos isso tudo, até porque não seria muito útil. ?
    Vamos tentar entender alguns filtros interessantes... Imagine que você é um administrador e precisa verificar todos os arquivos que pertencem a um usuário em específico:
    find / -type f -user leandro O que fizemos aqui? Utilizamos 2 tipos de filtros, um deles foi o -user, que busca arquivos que pertencem apenas à aquele usuário. O -type filtra pelo tipo de item no filesystem e suporta os seguintes tipos:
    d -> diretório f -> arquivo regular l -> link simbólico s -> socket     Procurando por arquivos perdidos:   Imagine agora que seu sistema está uma bagunça e você não faz ideia onde está um arquivo em específico, pense que você tem no mínimo 8 subdiretórios lotados de arquivos e você não lembra onde está o que você está procurando, só lembra que existe a palavra "mentebinaria" no nome dele. Além disso, você também sabe que não está nos primeiros 2 subdiretórios. Podemos resolver com: find . -mindepth 2 -name "*mentebinaria*" -type f A primeira coisa que fizemos foi utilizar a opção -mindepth, que especifica quantos níveis na hierarquia o find deve olhar no mínimo (a opção -maxdepth especifica o máximo). A outra opção foi a -name, que procura por um nome completo ou parte dele como fizemos no exemplo utilizando o wildcard * (asterisco) para bater com qualquer string antes de depois da palavra "mentebinaria".   Executando comandos:
    Na minha opinião uma das opções mais interessantes do find é a -exec, que praticamente executa comandos em cima do que o find encontrar. Não entendeu? Vamos lá... supondo que queiramos ver qual o tipo de arquivo de todos os arquivo que encontrarmos em um diretório em específico com o comando file:
    find . -type f -exec file {} \; Temos muita coisa pra entender nesta linha. Primeiro, o -exec trabalha com o conceito de targets (as chaves {} ) e isto significa: coloque tudo o que o find devolver no local da chave. Para cada arquivo que o find achar ele rodará o comando file naquele arquivo. Incrível, não?
    Sim, mas com isto estaremos executanto o mesmo comandos múltiplas vezes, por exemplo:
    leandro@teste:~$ find . -type f | wc -l 295 Imagine rodar isto 295 vezes, muita coisa, não? Se notarmos no primeiro exemplo do -exec vemos que no fim da linha tem um ponto de vírgula e este indica o fim do -exec para o find (e não para o shell). Temos que usar a contra barra para escapar e o shell não pensar que é para ele.
    Ok, mas até agora não vimos como melhorar isto. Concordam que o comando file aceita mais de um parâmetro?
    file arq1 arq2 arq3 E se pudéssemos pegar tudo que o find achar e, ao invés de rodar um comando do -exec por vez passamos tudo um atrás do outro? É exatamente isto o que o + faz e para ele não precisamos escapar:
    find . -type f -exec file {} + Este exemplo é a mesma coisa do anterior, mas de forma mais automatizada. Vamos medir a velocidade dos dois comandos:
    root@teste:~# time find / -type l -exec file {} \; ... real 0m15,127s user 0m0,336s sys 0m1,640s root@teste:~# time find / -type l -exec file {} + ... real 0m1,119s user 0m0,212s sys 0m0,396s Bem mais rápido com o +, não acham? ?
     
    Investigando o sistema:
    Seu servidor foi atacado, você não sabe exatamente o que aconteceu e como aconteceu, só sabe que nem tudo está funcionando do jeito que deveria. Uma coisa interessante à se fazer é tentar olhar para o que exatamente foi alterado desde o ataque. Imagine que isto ocorreu à 2 dias: find / -mtime -2 Aqui estamos dizendo que a partir da hora que rodarmos o comando olhar para tudo que foi modificado 48 horas atrás. Podemos também verificar se algo foi acessado com -atime.
    E se você não sabe exatamente quando foi o ataque? A única coisa que você sabe é que a última coisa que você fez foi adicionar novas funcionalidades à um script que você tem. Podemos procurar por tudo que foi modificado após este arquivo com a opção -newer:
    find /etc -newer <arquivo_velho> Mas como isto? O Linux guarda um tipo de informação chamada MAC no inode de cada arquivo, resumindo é simplesmente a data da última modificação, acesso e criação do arquivo ao qual aquele inode se refere. Apenas como curiosidade, o comando stat lê essas informações também. ?
     
    Mais algumas informações:
    Ok, agora você não teve nenhum problema, só quer algumas informações sobre os arquivos que o find encontrar. A opção -size <n> pode ajudar a procurar por arquivos maiores (+) ou menores (-) que o especificado:
    find /var -size +20k Podemos trabalhar com os seguintes formatos:
    c -> bytes k -> KB 0 ou -empty -> vazio find . -empty Não está satisfeito? Ok, a opção -ls ti da muito mais informações (praticamente aplica um ls -lids em cima de tudo que o find achar)
    find . -user leandro -type d -ls  
    Facilitando o parsing:
    Achou as opções de informações fracas? De fato a saída fica bem poluída. E se você precisasse todo dia monitorar informações específicas sobre arquivos específicos e criasse um script para isso, como você faria para obter estas informações? O find ti ajuda nisso também!!! Se você está familiarizado com a linguagem C (se não está veja isto) a função printf do C pode imprimir uma saída formatada de acordo com o que você escolher (string, inteiro, inteiro sem sinal, etc).
    Assim como em C, a opção -printf possui uma série de diretivas para formatarmos a saída do find como quisermos, algumas delas são:
    %f -> nome do arquivo %p -> path completo %i -> inode %M -> permissões %n -> número de hard links find / -type f -atime -1 -printf '%p %i %M \n' O único detalhe aqui é que por padrão o -printf não coloca um caractere de nova linha, devemos adicionar como no exemplo. Com isto a saída fica bem mais interesante para um script ler, não acham?! Aqui está o exemplo de uma saída:
    file1 262295 -rw-r--r-- file2 262283 -rw-r--r-- file3 262296 -rw-r--r-- Estas foram algumas dicas sobre o comando find. Com certeza informações mais completas podem ser encontradas no manual do comando, este tutorial tem como objetivo simplesmente compartilhar minhas anotações sobre o que acho bem interessante e usual sobre o comando find.
    Qualquer dúvida, crítica ou sugestão, por favor, sinta-se à vontade para comentar e obrigado! ?

    barbieauglend
    No artigo anterior, discutimos como encontrar informações importantes para se comunicar com seu dispositivo. Neste, vamos falar sobre uma abordagem genérica antes de reverter o código do firmware de fato.
    Objetivos
    A coisa mais importante durante o processo a partir de agora  é saber quais perguntas você quer responder. Se você começa a querer entender tudo, sem focar, no final acaba perdido numa montanha de informações sem sentido.
    Dê uma de Jack, O Estripador clássico: entenda tudo, mas por partes. Eu normalmente começo procurando o protocolo de comunicação no caso dele não estar documentado. Após isso quero entender geralmente o algoritmo usado para autenticação ou o gerador de senhas ou algo que me dê acesso a dados interessantes que possam ser usados em outros $hardware iguais. Normalmente a segurança de sistemas embarcados não é muito boa nisso: todos os hardware precisam de alguma forma de identificação única presente no firmware. Como você solucionaria o problema pensando em larga escala?
    Conversando com o seu $sistema
    A melhor parte e o principal diferencial da análise de hardware é ter o bare metal (o equipamento físico) nas suas mãos. Ter acesso aos sinais eletrônicos, poder medir frequências e VER como o sistema trabalha (adicionar LEDs em todos os circuitos possíveis e adaptar a frequência por exemplo, sempre lindo!) são coisas que fazem o coração palpitar bem mais do que algumas linhas de código. Acredite ? Sem muita informação prévia e com alguns equipamentos baratos, é possível obter dados interessantes para a análise. Poderíamos começar a controlar o tráfego de dados usando o analisadores lógicos simples e ao mesmo tempo podemos usar equipamentos mais avançados para medir o consumo de energia no processo de inicialização do hardware com tanta precisão, que poderíamos deduzir possíveis valores de chaves privadas - é pura ciência, física ? - e claro que funciona em condições ideais, como aprendemos na escola.
    Fluxo de dados na PCB
    Não adianta muito ter dados se você não pode ler, escrever ou transferi-los de alguma maneira. Olhar a placa deve ser suficiente para entender como o fluxo de dados ocorre, simplesmente pensando na posição do CI (Circuito Integrado) e das marcas na PCB, ou seja, na placa. Outra coisa importante: quase todas as plaquinhas têm uma datasheet voando na !nternetz e acessível publicamente, contendo toda a informação técnica (da pinagem, voltagem e o PROTOCOLO DE COMUNICAÇÃO). Sempre vale a pena usar o DuckDuckGo antes de começar a ter dores de cabeça por algo que esta documentado, certo?
    Vamos começar sem gastar muito $$$:
    Procure a fonte!
    Quem esta começando agora pode não ter todas as ferramentas disponíveis ou não ter acesso a uma oficina / laboratório. Por isso, vamos dump o código direto do hardware e abrir mao do contexto - que teríamos no caso da leitura dos dados no hardware - mas economizaremos dinheiro e teremos acesso a toda informação possível do $device. 
    Acesso ao firmware e memória
    Dumpe o código do CI e o descomprima. Essa é a parte mais fácil e mais difícil de todo o processo, mas para isso você não precisa de nenhum equipamento e pode usar várias ferramentas de graça (algumas inclusive de código aberto).
    Como eu falei anteriormente, é possível achar na Internet os datasheets (documentação completa, normalmente em PDF) de quase todos os dispositivos. Ache a datasheet para o seu CI e assim não terá necessidade nem de identificar a pinagem nem de reverter o conjunto de instruções necessárias para a comunicação. Algo também importante é saber como parar a comunicação entre o seu CI e os outros pontos de comunicação da placa, pois isso pode interferir na leitura dos dados. Como interromper o fluxo de dados depende bastante do circuito que você esta analizando.
    Mas eu preciso desoldar?
    Esse seria o caminho mais óbvio certo? Não quer interferência, desconecte seu CI da placa e vai para o abraço. Esse método te dá controle total sobre o seu CI ? O problema aqui é que esse processo requer experiencia e TEMPO.
    A ideia deste artigo é para ser algo mais simples e barato, então tente evitar essa situação e pense em ideias mais "criativas". Normalmente é possível conectar os dispositivos num osciloscópio ou voltímetro para monitorar e ter certeza que não há interferência dos sinais de cada pino do CI. Fique atento nos outros componentes, se algum tráfego de dados está ocorrendo (instale por exemplo um monitor na outra porta UART). Se algum tráfego ocorrer, daí não tem outro jeito a não ser desconectar o seu CI - use um fim de semana. ?
    Assim que o seu CI estiver isolado, conecte ele a qualquer aparelho que "fale" o mesmo protocolo e comece a ler a memória bloco por bloco. Isso pode demorar, por isso aconselho quando começar a leitura, vá a cozinha e faça um café! ?
    Dumping os dados
    Criar suas próprias ferramentas pode ser super divertido, mas custa tempo e é bem mais fácil quando você sabe o que está procurando. Por enquanto, podemos usar vários projetos de código aberto disponíveis:
    Para fazer o dump, flashrom é uma das ferramentas populares. É facil de usar, cheia de bugs mas tem suporte para várias arquiteturas diferentes. Funciona muito bem no Rasperry Pi. ?
    Normalmente vale a pena usar o comando file para ter uma ideia do tipo de arquivo que você esta lidando. Se ele não te ajudar em nada, tem o famoso binwalk.
    Os logs do binwalk the darão os endereços importantes. Então agora podemos usar o dd e dividir o seu binário em segmentos específicos. O comando dd precisa dos parâmetros bs (block size), do skip (offset) e o count (que aqui signifca quantos blocos você tem/quer copiar). Normalmente você terá pelo menos 3 blocos:
    O bootloader.bin: geralmente não esta criptografado pelo fato do microcontrolador não poder descriptografar. O mainkernel.bin: se você tiver sorte será algum kernel Linux. Esse é o firmware que controla o bare metal. ? Geralmente o mais divertido de ler e várias vezes comprimido - use o file novamente para saber como descomprimir. O mainrootfs.bin: para quem entende um pouco de Linux e sistemas BSD, esse é o sistema de arquivos, contendo todos os arquivos com configurações, os binários do sistema, etc. Use novamente o file para verificar se está comprimido. No caso da imagem estar criptografada, é possível quebrá-la utilizando o fcrackzip. 
    No próximo artigo eu vou tentar entrar em detalhes desses três binários - vamos ver se eu acho algum hardware interessante. ?

    sfigueiredobr
    Ataques cibernéticos estão cada vez mais presentes no nosso dia-a-dia, sendo assim, as empresas devem fortalecer seus mecanismos de defesa e capacitar seus usuários para que informação privilegiada não caia nas mãos erradas.
    Depois do acesso remoto aberto para a internet, justificar o orçamento para diretoria é o problema mais comum de 9 a cada 10 profissionais da área de segurança. Essa dificuldade muitas vezes está relacionada à falta de um planejamento ou estratégia que justifique o projeto, a diretoria precisa enxergar retorno ou resultado palpável que aquela despesa vai trazer.
    Ai você se pergunta: Como eu vou construir defesas, se não tenho orçamento?
    O primeiro passo é entender que nem todo mecanismo de defesa consiste na aquisição de uma ferramenta ou despesa financeira. Uma mudança de processo e otimização no uso de recursos que já estão implementados, na maioria das vezes, trás um retorno bem legal.
    Para te ajudar nessa jornada, alguns frameworks foram desenvolvidos com estratégias para que você, como profissional de segurança da informação, possa elaborar um plano bem definido e endereçar de forma estruturada as demandas de sua companhia. Neste artigo, vou te apresentar três frameworks  que são amplamente utilizados pelo mercado e ao final compartilho minha experiência sobre a adoção destes modelos.
    Familia de normas ISO 27000 As normas da família ISO/IEC 27000, podendo citar como as mais conhecidas as ISO 27001 e ISO 27002, estão diretamente relacionadas à segurança de dados digitais e sistemas de armazenamento eletrônico.
    Como destaque, posso indicar a ISO/IEC 27032 que literalmente oferece um guia de como estruturar sua operação em quesitos como segurança da informação e segurança de redes.
    Nesta norma, você também encontra uma literatura bacana sobre o relacionamento da área de segurança com o restante dos setores da companhia e te apresenta dicas bacanas de como trazer a nossa matéria para realidade do restante da galera.
    Conteúdo complementar: http://abntcatalogo.com.br/norma.aspx?ID=91527
    NIST Cybersecurity Framework Este framework é bastante reconhecido nos Estados Unidos pela sua presença em empresas públicas e privadas. Para equipes pequenas, pode ser complicado implementar seus controles devido à complexidade considerada no momento de sua concepção.
    O core deste framework é organizados em etapas, executadas de forma sequencial para estabelecer um ciclo de vida para as operações relacionadas a segurança. As etapas são: Identificar, Proteger, Detectar, Responder e Recuperar.
    Conteúdo complementar:  https://nvlpubs.nist.gov/nistpubs/CSWP/NIST.CSWP.04162018.pdf
    COBIT A Associação de Auditoria e Controle de Segurança da Informação (ISACA), produziu uma estrutura de controles para a tecnologia da Informação, o COBIT. Em sua revisão mais recente ele evoluiu para abordar as melhores práticas buscando alinhar funções, processos e tecnologia à estratégia de negócios.
    Apesar deste framework não ser diretamente ligado a segurança da informação, perceba o link entre o problema exposto na introdução deste artigo e o objetivo final do COBIT. Os investimentos de segurança só fazem sentido se minimizam riscos de negócio, independentemente se estão atrelados à correção de uma vulnerabilidade técnica ou conscientização de usuários. Estabelecer estes links é fundamental.
    Conteúdo complementar: http://www.isaca.org/COBIT/Pages/default.aspx
    Conclusão
    Logo de cara, depois de pesquisar um pouco melhor, você vai pensar.. Putz! É coisa para caramba.
    Quando estamos aprendendo assuntos de viés mais técnico, é um grande erro tentar atacar todos as materáis ou tecnologias de uma só vez, com gestão não é diferente.  
    No inicio é importante elaborar um plano de estudo e aos poucos entender qual é a função de cada um destes frameworks na estratégia de segurança.
    Não encare a documentação como uma receita de bolo, mas sim como um mapa que vai te ensinar percorrer o caminho de pedras.
    Ter um norte a seguir, facilita a caminhada.
    Grande abraço e até o próximo artigo!

    barbieauglend
    barbie's hardware 101
    Primeiro passo: Procure por portas de Debug
        
    Na verdade, esse deveria ser o passo zero, já que a primeira coisa que devemos fazer antes de começar qualquer outra coisa é dar uma boa olhada no hardware que você tem na mão.
    Nesse processo, faça uma lista das portas físicas que você tem acesso, conte os pinos que você vê, etc. O seu foco aqui é achar a porta de debug que geralmente é deixada na placa para reparos e suporte técnico.
    Essa porta está disponível em qualquer dispositivo (estamos falando de sistemas embarcados), ou seja, as queridas impressoras, câmeras de segurança, a torradeira no canto da cozinha, o roteador, etc. Outro fato importante: todo dispositivo mais complexo é um pouco mais fácil, pois estará provavelmente usando alguma versão do kernel Linux (que é open source :D). Se você não ver nenhuma porta de Debug diretamente, não desista. Muitas vezes elas estão um pouco escondidas e você terá que abrir o aparelho ou até romper algum lacre. ?
    As portas de debug são normalmente do tipo serial, UART, possuem de 4 a 6 pinos, e são literalmente desenhadas na placa. Sim, na PCB (placa) geralmente há uma marcação para a porta de debug, contornada, esperando para ser achada. ? Como elas são feitas para o suporte técnico usar, elas não são cobertas, não tem um plug bonitinho esperando por você... Os conectores ou as ilhas (os buraquinhos na placa onde os fios ou terminais de componentes são soldados) vão estar soltos, sem proteção e não estarão conectados a lugar nenhum no dispositivo.
    Aqui o exemplo da placa do roteador FritzBox 4020:

    Localize as ilhas/conectores que não estão em uso e solde os pinos. Se a sua placa tem mais do que um CI (Circuito integrado), procure pelo principal e solde os pinos na porta que esta conectada a ele (geralmente a parte mais interessante está rodando lá de qualquer maneira!). Eu prefiro sempre soldar pinos para que fique mais fácil o acesso.
    Continuando
    É importante entender como o protocolo de transmissão da porta funciona. O protocolo de comunicação UART (Universal Asymchtonous Receiver / Transmitter) difere de outros protocolos de comunicação como o I2C, basicamente por ser um circuito físico do microcontrolador com a única função de transmitir e receber dados de forma serial. A parte boa é que por não ser de propósito geral como o USB, é possível transmitir dados usando apenas dois cabos entre dois dispositivos. Esse tipo de comunicação pode ser chamada de comunicação direta.
    Os dados são transmitidos do pino Tx (transmissor) da origem para o pino Rx (receptor) do destino.
    +-------+                      +-------+
    |                |                       |                |
    |          Tx +--           --> Tx            |
    |                |     `   . .  '         |                |
    |         Rx +-- .  ' `  .  --> Rx            |
    |                |                       |                |
    |      GND +----------+ GND      |
    |                |                       |                |
    +-------+                      +-------+
    Como o próprio nome diz, a transmissão de dados usando o protocolo UART é assíncrona, o que significa que não existe um relógio (sinal de clock) que sincronize os dados de saída do UART de origem com o os dados recebidos pelo UART de destino. Ao invés disso, o UART de origem adiciona bits de sinalização de "início" e  "fim" em cada pacote de dados transmitido. Esses bits irão então definir o começo e o final de um pacote de dados de uma maneira que o UART de destino sabe onde começar e onde terminar a leitura.
    Quando o UART de destino recebe um "bit de início", ele começa a ler os dados recebidos na frequência chamada de baud rate (taxa de transferência). Essa frequência é a velocidade de transmissão de dados em bps (bits por segundo) e os dois UART devem estar operando na mesma frequência (ou com um erro de no máximo 10%) e a estrutura dos dados deve ser a mesma para que a comunicação ocorra sem problemas.
    Achando o output de cada pino:
    Até agora sabemos que as portas seriais possuem entre 4 e 6 pinos. Algo importante é saber que eles operam de acordo com a seguinte especificação ou "pinagem":
    Tx ou Transmitting: esse pino será conectado com o Rx do nosso leitor. Rx ou Receiving: esse pino será conectado com o Tx do nosso leitor. Vcc: POWER \o/ NÃO CONECTE! Geralmente 3.3V ou 5V. GND ou Ground (terra): esse será conectado com o GND do nosso leitor. (DTR e CTS) são dois pinos que não são obrigatórios e normalmente não são necessários. Talvez escreva mais sobre eles na próxima série! ? Tx e Rx possuem o valor 1 / verdadeiro / ligado (por padrão). Proximo passo: Multímetro!
    Claro que você pode simplesmente olhar as conexões desenhadas na sua PCB e usar a técnica da "tentativa & erro", mas dependendo do dispositivo que você está analisando, pode acabar ficando caro ? Então o melhor é analisar um pouco mais a sua PCB antes de mandar sinais aleatórios e por fogo em tudo - been there, done that! not fun!
    E não é tão dificil assim ? Geralmente um multímetro simples é o suficiente para nos oferecer a maioria das informações necessárias para dizer quem é quem na nossa plaquinha! Mas é claro que eu nunca direi não a um osciloscópio! ?
    O osciloscópio não só nos dá "informações suficientes para deduzir" quem é quem, mas nos mostra exatamente quem é quem, de acordo com as especificações esperadas:
    O pino com valor 0V constante é o GND. O pino com valores constantes 3.3V ou 5V deverá ser o Vcc. Um dos pinos com valor flutuante próximo de 0V deve ser o Rx (faz sentido? Não? Pensa assim, Rx esta "escutando" mas não está conectado a nada ainda!) Yay! Agora que sabemos qual pino é qual, só falta saber a nossa taxa de transferência (baud rate) para montar o nosso leitor. Para descobri-la, a maneira mais facil que conheço é usando um analisador lógico: Conecte seus pinos, ligue (acione) a opção "análise de protocolo" e vai na adivinhação, simplesmente mudando o baud rate até você ver texto na saída de dados serial.
    Tendo o layout dos pinos e a taxa de transferência, nós podemos começar a nos comunicar com o dispositivo. \o/

    l0gan
    Complementando os artigos criados sobre máquina virtual para ambiente Windows e Linux, este tutorial tem como finalidade auxiliar na criação de uma máquina virtual para análise de binários, possivelmente maliciosos, em ambiente macOS. 
    Configurações da Máquina Virtual
    2 processadores (cores). 2GB de RAM. Placa de rede em modo NAT (em casos aonde você realmente precisa de comunicação com um C&C). Placa de rede em modo Host-Only. Compartilhamento de Pastas desativado ou Host-Only (com host local). Aqui vem um ponto interessante: como tenho receio de malwares que detectam o ambiente de virtualização (ex: VMware Fusion) e tentam escapar do guest pro host, rodo sempre o SO guest num SO host diferente. No caso, rodo a máquina virtual com macOS mas o SO host é Linux.
    Sistema Operacional virtual
    10.10.1 (Yosemite) publicado em 2014 10.13.4 (High Sierra) Versão Atual Obs.:  As duas versões do macOS mencionados acima são para demonstrar a tela de configuração do Gatekeeper de cada versão. A importância das versões está nos diferentes tipos de malware  que podem se propagar em versões específicas. No entanto, basta escolher uma.
    O Gatekeeper é um componente de proteção para o macOS existente desde a edição Mountain Lion. A responsabilidade deste constituinte é encontrar a identificação do desenvolvedor (Developer ID, também conhecido como “assinatura de autenticidade”), que é fornecido pela própria Apple. Quando em conformidade, o Gatekeeper mantém-se adormecido até o momento do cujo arquivo executável ou instalador ser flagrado com a assinatura de autenticidade ausente ou por ser reconhecido pela semelhança de algum tipo de malware.
    Uma vez que você utiliza softwares baixados através da App Store e ou assinados pela Apple você já possui uma certa segurança. Tendo consciência que boa parte dos últimos malwares para macOS dependiam que este recurso estivesse desativado, consequentemente, permitindo o download e instalação de qualquer software não identificado.
    Desativando o Gatekeeper

    Imagem 1: versão Yosemite
     No macOS Sierra e posterior a opção “Anywhere” não aparece mais, agora o sistema operacional perguntará para o usuário se ele deseja permitir que o software realmente seja instalado / executado no sistema. Porém há maneira de desabilitar o Gatekeeper e voltar com a opção como mostra na Imagem 1, usando o spctl (SecAssessment system policy security), via Terminal:
    $ sudo spctl --master-disable
    Imagem 2: versão high-sierra
    Outro sistema de segurança é o SIP (System Integrity Protection). Eu ainda não vi nenhuma necessidade de desativar para rodar malware porem caso precisem:
    SIP (proteção de integridade do sistema)
    Clique no menu  Selecione Reiniciar ... Mantenha pressionado o ⌘comando-R para inicializar no sistema de recuperação. Clique no menu Utilitários e selecione Terminal. Digite csrutil disable e pressione Enter. Feche o aplicativo Terminal. Clique no menu  e selecione Reiniciar .... Ferramentas
    No macOS além da própria Apple Store (que com certeza neste caso não terá as principais ferramentas que precisamos), também temos algumas boas fontes de ferramentas. O MacPorts, sistema de pacotes muito utilizado, e também o Homebrew suprem muito bem nossas necessidades quanto aos pacotes.
    Abaixo deixei um lista de ferramentas tanto para análise estática quanto dinâmica, claro que em alguns casos a mesma ferramenta pode ser utilizada em ambos os tipos de análise.
     
    Analise Estática
    xxd                 -> Cria um dump a partir de um binário, parecido com o hexdump.
    strip               -> Remove e ou modifica a tabela de símbolos de um binario.
    hexEdit         -> Editor hexadecimal.
    lipo                 -> Cria ou modifica arquivos multi-arquitetura, na imagem 6 tempos um exemplo da sua funcionalidade.
    otool              -> Exibe informações sobre binários Mach-O (tipo um objdump).
    jtool                -> Versão melhoradas do otool.
    nm                   -> Exibe a tabela de símbolos.
    codesign       -> Usado para criar, verificar e exibir assinaturas de código.
    machOView -> Interface visual para edição de binários mach-o. 
    class-dump -> Usado para examinar informações em tempo de execução do Objective-C armazenadas em arquivos Mach-O.
    dtrace             -> Ferramenta usada para analisar comportamento do Sistema Operacional e dos programas em execução.
    fs_usage       -> Exibe informações sobre chamadas de sistemas, executa rastreamento do kernel e processos, tudo em real-time.
    xattr                 -> Usado para exibir, modificar e ou remover atributos(metadados) de arquivos, diretórios e links simbólicos.
    Analise Dinâmica
    xcode                         -> IDE de desenvolvimento de software oficial da apple, possui recursos internos para testes de perfomance de sistema.
    hopper                      -> Ferramenta usada para disassemble e decompile de arquivos mach-o 32/64bits.
    lldb                             -> Debugger utilizado para depurar programas C, C ++, Objective-C, Objective-C ++ e Swift.
    fseventer                 -> Ferramenta gráfica usada para verificar atividades em disco e execução de processos de forma visual.
    open snoop             -> Usado para rastrear acessos de arquivos, aplicativos, processos e também monitoramento do 
                                              filesystem, você pode utilizar ele em conjunto com o Dtrace.
    activity Monitor    -> Exibe processos que estão sendo executados no macOS.
    procexp                    -> Ferramenta exibe informações acessíveis pelo proc_info para exibição de processos, parecido com o top e htop.
    lsock                          -> Baseado no PF_SYSTEM o lsock e usado para visualização em real time das conexões (Sockets) no sistema, similar ao netstat.
    Por se tratar de máquina virtual para pesquisas em macOS, não poderia deixar de mencionar as ferramentas do pessoal da Objective-See. Vale a pena testar e acompanhar os artigos deles.
     
    Imagem 3: ferramentas objective-see
     Destaco três ferramentas especificas para quem estiver analisando binários do tipo Mach-O:

    Imagem 4: ferramenta otool exibindo o magic number do binário.

    Imagem 5: ferramenta jtool exibindo o endereço da função main() do binário Mach-O
     
    Imagem 6: ferramenta lipo extraindo o suporte a uma arquitetura especifica em binários do tipo fat.
    Considerações finais
    Criar um snapshot da instalação default; Ficar atento: Anti-Disasssembly Anti-Debugging Sistemas de Ofuscação Anti-VM Ficar atento às falhas publicadas  

    AndreAlves

    Entenda o DNS sobre HTTPS

    Por AndreAlves, em Redes,

    Um pouco depois das revelaçōes de Edward Snowden sobre monitoração generalizada da internet por entidades governamentais, a IETF (Internet Engineering Taskforce - uma comunidade de gente interessada na engenharia da internet) criou um grupo de trabalho para rever a privacidade do DNS e o nomeou "DPRIVE" - abreviação para DNS Privacy.
    Pensar em jeitos de tornar as resoluçōes deste protocolo tão fundamental menos manipuláveis e mais secretas sem perder muita velocidade é o abacaxi que foi dado a esse grupo, que tem trabalhado bastante e gerado alguns frutos.
    Mais recentemente um deles ficou mais conhecido entre nós quando a Cloudflare lançou um serviço de DNS focado em privacidade e rapidez e anunciou suporte a uma das propostas do IETF para DNS seguro-privado-rápido , o DOH (DNS over HTTPS), que dá nome à este artigo.
    A sacada do DOH é possibilitar queries (consultas) DNS criptografadas (tchau entidades governamentais tentando espionar ?) que são difíceis de diferenciar de outros tráfegos criptofragados (tchau provedores tentando fazer bandwith throttling ou traffic shaping).
    Mas afinal, como isto funciona?
    Basicamente as queries DNS se tornam um request HTTP do tipo POST ou GET para uma URL definida pelo serviço de DNS. Essas requests são trafegadas dentro de uma sessão TLS e formatadas como JSONs codificados em base64. No JSON temos os campos definindo o tipo do registro a ser consultado (A, CNAME, AAA, etc).
    Para visualizar aqui vai um exemplo de solicitação de uma query para resolver o nome www.exemplo.com usando o método POST, tirado direto do rascunho da RFC:
    :method = POST :scheme = https :authority = dnsserver.example.net :path = /dns-query accept = application/dns-udpwireformat content-type = application/dns-udpwireformat content-length = 33 E o conteúdo de 33 bytes da query:
    00 00 01 00 00 01 00 00 00 00 00 00 03 77 77 77 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 01 00 01 Não é lindo? Sim é. Mas se você quiser usar por enquanto terá que se aventurar. Um dos poucos (único?) navegadores que suporta este recurso é o Firefox em sua versão Nightly (sai um novo release toda noite!). Para configurar, os passos são:
    Digite about:config na barra de endereços e pressione [ENTER]. Altere o valor dos seguintes parâmetros de acordo: netowrk.trr.bootstrapAddress: 1.1.1.1 network.trr.uri: https://mozilla.cloudflare-dns.com/dns-query network.trr.mode: 2 (usa DOH primariamente, mas faz fallback pro DNS atual) Outros projetos utilizando DOH estão surgindo no Github. O DNS-over-HTTPS proxy, por exemplo, cria um proxy de modo que as consultas DNS sejam redirecionadas para o serviço do Google que suporta DOH.
    O mais legal é que a preocupação com privacidade e liberdade individual continuará a resultar em mais projetos como este para salvar nossa internet de quem se acha dono dela. ?
    Se você ficou interessado, dá uma pesquisada nos outros candidatos a DNS seguro:
    DNS over TLS (RFC 7858) DNS over DTLS (RFC 8094) DNS over QUIC (ID-draft) DNS over DNSCrypt (independente) DNS over TOR (independente)

    gzn
    Caro leitor, você gosta de desafios? Neste artigo vou contar como resolvi um desafio de engenharia reversa do Shellterlabs, mas sem usar um disassembly!
    Para quem não é acostumado com o termo, de acordo com o grupo CTF-BR!, um CTF (Capture The Flag) nada mais é do que uma competição que envolve diversas áreas mas principalmente as áreas ligadas à segurança da informação. No Papo Binário também há um vídeo sobre o assunto.
    O desafio em questão é o Shellter Hacking Express Acidentalmente. Em sua descrição, há a seguinte frase: Acidentalmente codificamos a chave.
    Isso não diz muita coisa mas ao baixar o binário, percebemos que há dois arquivos:
    tar tf ~/Downloads/e74a74b5-86cf-4cb3-a5bb-18a36ef067cf.tgz RevEng400/ RevEng400/encoder RevEng400/key.enc Usando o comando file, verifiquei de que tipo são os arquivos extraídos:
    cd RevEng400/ $ file * encoder: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.2.5, stripped key.enc: data Ao ver que o encoder é um binário ELF, fui direto analisar seu código num disassembler usando objdump e gdb, mas percebi que o binário não continha os símbolos, o que torna sua análise um pouco mais difícil.
    Sendo iniciante em engenharia reversa e depois de horas analisando a função de cifragem, confesso que fiquei sem saber para onde ir (já viu algum apressadinho tentando aprender a tocar guitarra? Pois é, já quer ir lá tocar aquele solo, e na velocidade Steve Vai, aí não dá né? rs) e desisti, mas não por muito tempo (ei crianças, nunca desistam dos seus sonhos viu! rs), e procurei o nosso querido prof. @Fernando Mercês lá no servidor do Discord, que me deu umas dicas. Segue trecho da conversa:
    > @fernandom @gzn sei que vc ta treinando ER, mas nem precisa disassemblar esse binario pra esse desafio nego > se vc olhar bem, vai ver que a saída do encoder tem o tamanho da string de entrada + o byte 0x03 no final > olhando a chave encodada (key.enc), é razoável admitir que ela tenha 16 caracteres então > você só precisa encontrar qual deles é o 0xef .. um loop com bash mata > supondo que seja o 'A'... então 'A' -> 0xef, aí você vai precisar da letra que gera o 0xf9 e assim sucessivamente, até chegar em 16 Já ouviu a expressão "pensar fora da caixa"? Pois é! Por que eu fui direto disassemblar? Esse é um dos problemas quando nós estamos começando: às vezes a gente acha que o método mais difícil deve ser o único ou o melhor para se resolver problemas, mas nem sempre é assim. Daí pensei: se o Mercês falou que não é muito difícil, vamos ao menos tentar não é?
    Bem, a primeira coisa que fiz foi ver uma maneira de imprimir o conteúdo do binário em hexadecimal. Para isso criei um pequeno script que usa o hexdump para me dar uma saída somente com os bytes em hexadecimal do parâmetro que receber. Chamei o script de hexdump.sh e depois dei permissão de execução nele (chmod +x). Seu conteúdo é o seguinte:
    #!/bin/sh hexdump -v -e '/1 "%02X "' $1 Então comecei os testes:
    for letra in 0 A a; do echo -n "$letra "; ./encoder $letra | ./hexdump.sh; echo; done 0 7F 01 A F7 02 a F7 03 Parece que nem sempre o final é 0x03... Bem, fui verificar o conteúdo do arquivo key.enc e encontrei isso:
    ./hexdump.sh < key.enc EF F9 42 09 A3 1A 43 F7 8C 8B BB 22 2A C2 A3 14 03  Pela lógica, já que essa é a chave codificada, se eu passar a chave correta original em texto como parâmetro para o binário encode ele terá que gerar a sequência acima. Seguindo a dica do Mercês, usei o próprio bash para tentar quebrar o desafio, primeiro mostrando o conteúdo em hexadecimal da chave codificada, depois iterando pelos caracteres possíveis e filtrando pelo primeiro byte dela:
    hexdump.sh < key.enc; echo for ((i=32;i<=126;i++)); do > l=$(printf "\x$(printf "%x" $i)") > echo -n "$l " > ./encoder "$l" | ./hexdump.sh > echo done | grep 'EF' Este código basicamente faz:
    Mostra os bytes em hexadecimal da chave a cada vez que executarmos esse comando (só pra saber qual byte é o próximo). Itera por todos caracteres imprimíveis da tabela ASCII (faixa de 32 à 126 em decimal). Imprime o caractere na tela sem a quebra de linha. Passa essa letra para como argumento para o binário encode e imprime a saída dele em hexadecimal. Por fim, usa o grep para encontrar uma combinação que tenha o próximo byte da chave. Partindo para um exemplo prático, fui tentar encontrar a primeira letra dessa chave, sabendo que sua versão codificada deve resultar no byte 0xEF:
    ./hexdump.sh < key.enc; echo EF F9 42 09 A3 1A 43 F7 8C 8B BB 22 2A C2 A3 14 03  for ((i=32;i<=126;i++)); do > caractere=$(printf "\x$(printf "%x" $i)") > echo -n "$caractere ";./encoder "$l" | ./hexdump > echo done | grep 'EF' " EF 01  B EF 02  b EF 03 Conforme pode ver acima, encontrei três caracteres diferentes que, quando encodados pelo encoder, geram o byte 0xEF: ", B, e b. Escolhi seguir com o B, prefixando-o na chave para dar sequência ao script e ver se encontramos o caractere que resulta no próximo byte da chave codificada (0xF9):
    ./hexdump.sh < key.enc; echo EF F9 42 09 A3 1A 43 F7 8C 8B BB 22 2A C2 A3 14 03  for ((i=32;i<=126;i++)); do > caractere=$(printf "\x$(printf "%x" $i)") > echo -n "B${caractere} " > ./encoder "B$l" | ./hexdump > echo done | grep 'EF F9' % EF F9 01  E EF F9 02  e EF F9 03  Mais uma vez encontrei três opções. Foi só continuar este processo até encontrar a chave que gera os exatos 16 bytes do arquivo key.enc.
    Aproveitei e automatizei um brute forcer com Python:
    #!/usr/bin/env python3 # -*- coding: utf-8 -*- import subprocess def encode(arg): result = subprocess.run(['./encoder', arg], stdout=subprocess.PIPE) return result.stdout def loadKey(): key_enc = [] with open('./key.enc', 'rb') as file: while True: byte = file.read(1) if byte: # a ordem dos bytes aqui não importa (porque trata-se apenas de 1 byte), mas é necessário especificar key_enc.append(int.from_bytes(byte, byteorder='little')) else: break return key_enc def permutations(key='', key_enc=loadKey(), key_i=0): if key_i == len(key_enc) - 1: print(key) return for char in (chr(i) for i in range(32, 127)): result = encode(key + char) if result[key_i] == key_enc[key_i] and key_i < len(key_enc): permutations(key=key + char, key_enc=key_enc, key_i=key_i + 1) def main(): permutations() if __name__ == "__main__": main() Saída codificada em base64 (pra não estragar a brincadeira de quem vai tentar resolver o desafio por conta própria):
    QmV3aXRjaGluZyBTZXh0LwpCZXdpdGNoaW5nIFNleHRPCkJld2l0Y2hpbmcgU2V4dG8K Segue vídeo do canal com a explicação do algortimo de encoding desse desafio: 
     

×
×
  • Criar Novo...