[摘要]------------------------------------------------------ 其中字段指示头是一个可以变长的表,表的每一项代表了在一个字段在信息中的偏移地址和长度信息...
------------------------------------------------------
其中字段指示头是一个可以变长的表,表的每一项代表了在一个字段在信息中的偏移地址和长度信息,在SQL2000中主要是4个字段,其对应的字段指示头的结构如下:
{
BYTE CNETLIBVERNO;
WORD CNETLIBVEROFFSET;
WORD CNETLIBVERLEN;
BYTE CENYFLAGNO;
WORD CENYFLAGOFFSET;
WORD CENYFLAGLEN;
BYTE SINSTNAMENO;
WORD SINSTNAMEOFFSET;
WORD SINSTNAMELEN;
BYTE CTHREADIDNO;
WORD CTHREADIDOFFSET;
WORD CTHREADIDLEN;
BYTE FILEDEND;
}
信息内容的结构如下:
{
BYTE CNETLIBVER[CNETLIBVERLEN]
BYTE CENYFLAG[CENYFLAGLEN];
BYTE SINSTNAME[SINSTNAMELEN]
DWORD CTHREADID[CTHREADIDLEN];
}
其中:
CNETLIBVERNO字段域
偏移:0
长度:1
含义:客户端使用的网络连接库(NETLIB)的版本号信息的字段编号。
说明:
备注:该值固定为0
CNETLIBVEROFFSET字段域
偏移:1
长度:2
含义:客户端使用的网络连接库(NETLIB)的版本号信息的字段偏移。
说明:字段格式是网络字节顺序
备注:
CNETLIBVERLEN字段域
偏移:3
长度:2
含义:客户端使用的网络连接库(NETLIB)的版本号信息的字段长度。
说明:字段格式是网络字节顺序
备注:该值固定为6
CENYFLAGNO字段域
偏移:5
长度:1
含义:客户端使用强制加密标记字段的字段号。
说明:
备注:该值固定为1
CENYFLAGOFFSET字段域
偏移:6
长度:2
含义:客户端使用强制加密标记字段的偏移。
说明:字段格式是网络字节顺序
备注:
CENYFLAGLEN字段域
偏移:8
长度:2
含义:客户端使用强制加密标记字段的长度。
说明:字段格式是网络字节顺序
备注:该值固定为1
SINSTNAMENO字段域
偏移:0XA
长度:1
含义:客户端要求使用服务器的实例名字段的字段号。
说明:
备注:该值固定为2
SINSTNAMEOFFSET字段域
偏移:0XB
长度:2
含义:客户端要求使用服务器的实例名字段的偏移。
说明:字段格式是网络字节顺序
备注:
SINSTNAMELEN字段域
偏移:0XD
长度:2
含义:客户端要求使用服务器的实例名字段的长度。
说明:字段格式是网络字节顺序
备注:
CTHREADIDNO字段域
偏移:0XF
长度:1
含义:客户端进程的线程ID字段的字段号。
说明:
备注:该值固定为3
CTHREADIDOFFSET字段域
偏移:0X10
长度:2
含义:客户端进程的线程ID字段的的偏移。
说明:字段格式是网络字节顺序
备注:
CTHREADIDLEN字段域
偏移:0X12
长度:2
含义:客户端进程的线程ID字段的长度。
说明:字段格式是网络字节顺序
备注:该值固定为4
FILEDEND字段域
偏移:0X14
长度:1
含义:此字段标记字段指示头已经结实,下面的就是字段的信息。
说明:结束标记是0XFF
备注:
CNETLIBVER字段域
偏移:0X15
长度:6
含义:客户端使用的网络连接库(NETLIB)的版本号。
说明:其版本号取的是DBNETLIB.DLL的版本
备注:其格式是网络字节格式,如版本号为80.528.00,则为
08 00 02 10 00 00
CENYFLAG字段域
偏移:0X1B
长度:1
含义:客户端强制加密标志。
说明:0代表客户端不强制加密,1代表客户端使用强制加密
备注:
SINSTNAME字段域
偏移:0X1C
长度:SINSTNAMELEN
含义:客户端要求使用的实例名。
说明:单字节格式
备注:默认实例使用MSSQLserver这个名字
CTHREADID字段域
偏移:0X1C+SINSTNAMELEN
长度:4
含义:客户端进程的线程ID。
说明:字段格式是主机字节顺序
备注:
由上面的格式可以看出,一个用默认实例名MSSQLserver连接的SQL TDS包格式将是如下的格式:
\x12\x01\x00\x34\x00\x00\x00\x00
\x00\x00\x15\x00\x06\x01\x00\x1b
\x00\x01\x02\x00\x1c\x00\x0c\x03
\x00\x28\x00\x04\xff\x08\x00\x00
\xc2\x00\x00\x00MSSQ
LServer\x00
\x78\x03\x00\x00
而NFR的攻击签名库却是
HELLO_SIG = "\x12\x01\x00\x34\x00\x00\x00\x00\x00\x00\x15";
明显是正常TDS 0x12预登陆包的一部分,这就难怪会有这么多报警了,那NFR的这个攻击签名是如何得到的呢?
我们还是从它的漏洞说明入手吧!
5. 漏洞说明
下面是NFR N-CODE中对这个漏洞的说明:
FALSE POSITIVES
False positives are unlikely due to the nature of the attack
REFERENCES
Bugtraq Post
http://cert.uni-stuttgart.de/archive/bugtraq/2002/08/msg00125.html
Exploit
http://www.scan-associates.net/papers/sql2kx2.txt
我们可以看到这个漏洞来自于http://www.immunitysec.com/ 的Dave Aitel,而从http://cert.uni-stuttgart.de/archive/bugtraq/2002/08/msg00125.html所列的MS SQL Server Hello Overflow NASL script中我们可以看到这个漏洞的关键就在于以下几个语句:
<snip>
pkt_hdr = raw_string(
0x12 ,0x01 ,0x00 ,0x34 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x15 ,0x00 ,0x06 ,0x01 ,0x00 ,0x1b,
0x00 ,0x01 ,0x02 ,0x00 ,0x1c ,0x00 ,0x0c ,0x03 ,0x00 ,0x28 ,0x00 ,0x04 ,0xff ,0x08 ,0x00 ,0x02,
0x10 ,0x00 ,0x00 ,0x00
);
pkt_tail = raw_string (
0x00 ,0x24 ,0x01 ,0x00 ,0x00
);
<snip>
…..
if(get_port_state(port))
{
soc = open_sock_tcp(port);
if(soc)
{
attack_string=crap(560);
sql_packet = pkt_hdr+attack_string+pkt_tail;
send(socket:soc, data:sql_packet);
r = recv(socket:soc, length:4096);
close(soc);
display ("Result:",r,"\n");
if(!r)
{
display("Security Hole in MSSQL\n");
security_hole(port:port, data:report);
}
}
其中pkt_hdr是根据TDS协议构造的包,中间加了560个字符X,pkt_tail是构造的TDS包尾。
从这里我们可以看到,可怜的NFR居然不负责任地把MS SQL Server Hello Overflow NASL script中的pkt_hdr取出11个字符,毅然决然地把它们作为其签名。更为可笑的是居然还写着“False positives are unlikely due to the nature of the attack ”。
这就是在许多评测中遥遥领先的NFR?后来和stardust聊起这个事情的时候,认为这个现象和很多评测机构在评测IDS产品的时候,重视对产品漏报的检测而忽视对误报的评测有关。因为在评测产品时,基本上都是大部分都是黑箱评测,要检测漏报只要收集几个Exploits就可以进行,但要检测漏报却要产生正常的包,有些系统比如这里的Sql Server,如果不了解它的协议包格式,是很难产生的。因此一些IDS产生便钻了这样的空子,只要收集一些Exploits,把其中的攻击代码作为攻击签名直接发布,而不去分析漏洞产生的真正原因。
下面我们来分析一下这个漏洞产生的原因,然后我们就可以根据这个分析,写出比较完善的攻击签名。
6. 漏洞分析
用IDA对SSlibnet.dll反汇编,我们可以看到:
.text:42CF6F49 loc_42CF6F49: ; CODE XREF: sub_42CF6E4F+EA j
.text:42CF6F49 mov eax, [ebp+0xc]
.text:42CF6F4C add eax, [ebp-0x218]
.text:42CF6F52 push eax
.text:42CF6F53 lea ecx, [ebp-0x214]
.text:42CF6F59 push ecx
.text:42CF6F5A call strcpy
.text:42CF6F5F add esp, 8
.text:42CF6F62 push offset unk_42D01104
.text:42CF6F67 lea edx, [ebp-0x214]
.text:42CF6F6D push edx
.text:42CF6F6E call strcmp
.text:42CF6F73 add esp, 8
这个漏洞的原因就在这里,当程序用strcpy拷贝的时候,如果源字符串超出0x214(也就是532)后,目标地址后的环境变量就会被覆盖导致溢出。由于这个漏洞很早,经历了“Slammer”蠕虫后,基本上所有的系统都补掉了这个漏洞,因此这里就不在提供攻击代码了,有兴趣的朋友可以自己分析和编写一下。
另外需要在这里说明的是,如果分析了TDS协议和这个漏洞的成因,完善的攻击程序中的TDS包的长度是根据计算生成的,明显不会是”\x00\x34”,以避过SQL Server中针对TDS包长度的校验(当然在这个版本的SQL Server中还不包含这个校验),或者攻击程序把这攻击代码分成多个包,因此TDS格式中的status就不会是0x01,因此NFR是检测不出完善的攻击程序的的,也就是说针对这个漏洞,NFR 同时存在误报和漏洞的情况。
在分析了这个漏洞的成因后,我们就可以针对这个问题写出自己的NFR检测代码:
sqlserv_schema = library_schema:new(1, ["time","ip","int","ip","int", "str"],
scope());
sqlserv_rec = recorder("bin/list %c", "sqlserv_schema");
HELLO_SIG = "\x12 ";
#考虑了分包和长度不固定的因素,去除了后面不可靠的特征串
MIN_LEN =29;
#包括TDS包头和字段指示头的总长度
…….
<snip>
filter hello tcp (client, dport: 1433) {
declare $Blob inside tcp.connsym;
if ($Blob == NULL) {
$Blob = tcp.blob;
} else {
$Blob = cat($Blob, tcp.blob);
}
if (strlen($Blob) < MIN_LEN)
return;
if (prefix($Blob, HELLO_SIG) && strlen($Blob) > 295) {
#考虑到实例名不可能超过255,因此这里长度选择了40(包头)+255=295
#也可以增加一个Value,以便用户自己根据事件情况进行调节
#报警
….
}
7. 小结
通过对NFR这个攻击签名的分析可以看出,发布完善的IDS攻击签名不是一个简单的事情,它需要了解应用的协议格式和漏洞的成因。而不是简单地收集网络上存在地exploits,然后截取其中的特征码。
目前很多人包括IDS开发人月都在讨论IDS有没有前途,需不需要。我想与其在那里讨论,不如静下来好好分析漏洞,完善攻击签名,使IDS做的更准确。
与其坐而论不如起而行!!(出处:www.xfocus.net)
关键词:优化NFR之一 --MSSQL Hello Buffer Overflow