1. 前言 3
2. 报警信息 3
3. NFRde检测 4
4. 协议分析 8
5. 漏洞说明 15
6. 漏洞分析 18
7. 小结 20
1. 前言
NFR(Network Flight Recorder)是一个老牌de商业网络IDS产品,最初由Firewallde牛人Marcus J. Ranum创建,是作为一个通用de网络流量分析和记录软件来实现de,为了最大限度地发挥分析工具de灵活性,NFR提供了完善强大deN-Code脚本语言,在很多de评测中表现出色.虽然L0pht为NFR提供过数百个签名库,但是缺乏一个可靠de签名集一直是他de软肋.
使用NFR有一段时间后,发现NFR存在着不少问题.且不说AI对中文de兼容性差而经常退出,也不说NFR版本升级而攻击事件说明却一直用旧版本de说明,单是IDS中最关键de攻击签名库,却让我大跌眼镜.除了升级缓慢以外,甚至还存在不少错误de签名.本系列文章针对其中我发现de部分问题进行分析和阐述,以便各位更好地利用NFR产品,同时也想和各位同仁讨论IDS中攻击签名库de编写.由于知识和时间de限制,错误之处在所难免,还希望得到各位de指教,任何意见或建议请发至:benjurry@xfocus.org
SQL Server是微软为对抗Oracle推出de数据库, 占领de市场份额已经仅次于Oracle,居世界第二,但是其安全性也一直受到用户de置疑.从1996年,Microsoft公司推出deSQL Server 6.5版本到1998年推出deSQL Server 7.0,以及到2000年8月推出了SQL Server 2000,在版本和功能不断升级de情况下,安全问题却没有得到很好地改善,不断发布针对SQL Serverde安全公告和补丁.在2003年1月24日,针对SQL Serverde“Slammer”蠕虫在Internet上肆虐,导致网络流量激增,严重影响了世界范围内de计算机和网络系统.SQL Serverde漏洞引起了各大安全公司和厂商de重视,因此NFR也立即发布了多个针对SQL Serverde攻击签名,其中包括了2002年8月7日Immunity公司Dave Aitel发现deHello Buffer Overflow漏洞.但是在使用过程中,我发现NFR针对该漏洞de报警非常多,于是我对此进行了分析,于是写成了这个文章,以做记录.
2. 报警信息
下面是NFR针对MS SQL Hello Buffer Overflowde报警信息:
Severity: Attack
Time: 13:54:21 15-Jul-2003
Source File: packages/mssql/sql2k.nfr
Line: 226
Host: benjurry-xfocus
Alert ID: mssql_sql2k:buffered_hello
Source ID: mssql_sql2k:source_me
Source: mssql_sql2k:source_me
Source Description: Sqlserver 2k overflow detector
Source PID: 36531
Alert Message: Saw 8 Mssql HELLO overflows from 192.168
0.110 in 900 seconds
: 3
Source IP: 192.168.0.110
Destination IP: —
其中包括了事件de严重等级、时间、NFR Sensor名字、攻击源IP、目deIP和一些其他报警信息.
在实际de使用中,一天产生了几百条这种报警,看来这是个误报,我可以好好de分析一下了.
3. NFRde检测
我首先打开NFR发布de签名库 MSSQL.fp(或者也可以在AIdepackage中查看) 看一下NFRde针对这个漏洞de攻击签名:
<snip>
…..
变量定义等…
…
<snip>
sqlserv_schema = library_schema:new(1, ["time","ip","int","ip","int", "str"],
scope());
sqlserv_rec = recorder(”bin/list %c”, “sqlserv_schema”);
HELLO_SIG = “\x12\x01\x00\x34\x00\x00\x00\x00\x00\x00\x15″;
MIN_LEN = strlen(HELLO_SIG);
…….
<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)) {
if (COUNTHELLO[tcp.connsrc]) {
COUNTHELLO[tcp.connsrc] = COUNTHELLO[tcp.connsrc] 1;
} else {
COUNTHELLO[tcp.connsrc] = 1;
}
if (do_alert(hello_overflow_alert, tcp.connsrc)) {
alert(source_me, hello_overflow_alert, tcp.connsrc,
tcp.connsport, tcp.conndst, tcp.conndport,
“–AlertDetails”,
“ALERT_ID”, “40-8″,
“ALERT_CONFIDENCE”, 60,
“ALERT_SEVERITY”, “medium”,
“ALERT_IMPACT”, “unknown”,
“ALERT_EVENT_TYPE”, “attack”,
“ALERT_ASSESSMENT”, “unknown”,
“IP_ADDR_SRC”, tcp.connsrc,
“PORT_SRC”, tcp.connsport,
“IP_ADDR_DST”, tcp.conndst,
“PORT_DST”, tcp.conndport,
“IP_PROTO_NUM”, 6);
}
record packet.sec, tcp.conndst, tcp.conndport, tcp.connsrc,
tcp.connsport, $Blob to sqlserv_rec;
misc_attacks:rec(packet.sec, scope(),
“Mssql HELLO overflow!”, tcp.connsrc, tcp.conndst);
}
}
从上面deN-CODE中我可以看到,NFR在做这个检测de时候步骤如下:
1、定义了一个攻击特征码:
HELLO_SIG = “\x12\x01\x00\x34\x00\x00\x00\x00\x00\x00\x15″;
和攻击特征码de长度:
MIN_LEN = strlen(HELLO_SIG);
2、从TCPde载荷数据中取出数据,把这个数据de长度和特征码长度比较,如果这个数据长度小于攻击特征码de长度,那么就不再进行下一步de检测;
3、否则,把这个数据和特征码进行字符串匹配,如果一致则认为是攻击行为,然后进行阻止或者报警.
接下来我分析一下NFR IDS Recordde数据,在AI中选择package->Query->MSSQL->MSSQL Server 200,定好条件,按Table查到数据,随便选取一条,copy出来得到如下内容:
Time: 15-Jul-2003 13:54:21
NFR: benjurry-xfocus
Destination Address:192.168.0.135
Destination Port: 1433
Source Address: 192.168.0.110
Source Port: 1391
Payload:
\x12\x01\x004\x00\x00\x00\x00\x00\x00\x15\x00\x06\x01\x00\x1b\x00
\x01\x02\x00\x1c\x00\x0c\x03\x00(\x00\x04\xff\x08\x00\x00\xc2\x00
\x00\x00MSSQLServer\x00x\x03\x00\x00
上面这条记录包含了攻击de时间,报告攻击行为deNIDS sessor名字,目deIP、目de端口、源ip和源端口,而我关心de是有效载荷Payload,因为它是NIDS用来和攻击签名库比较de数据.但是NFR在这里有几个小问题:
1. 会把payload中de能转换成ASCII字符de16进制数转换成ASCII码;
2. 不能处理Unicodede字符,这个将在以后de分析中可以看到.
在这个例子中为了分析方便,我把上面depayload中de字符特征码部分转换成16进制数:
\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\x00MSSQLServer\x00x\x03\x00\x00
NFR抓到数据组包后,发现是SQL Server包,便把里面de内容和SQL Serverde攻击库进行比较,很明显,上面所列de数据和攻击库是相符合de,因此一个报警便产生了,但是这真是一个攻击行为吗?我继续看下面de分析.
4. 协议分析
根据Xfocusde协议分析项目(将会在近期公布项目成果),MS SQL 2000用de是TDS8.0,它de格式如下:
————————————————-
| TDS包头(8字节) | TDS负载数据 |
————————————————-
其中MS SQL SERVER 2000 TDSde包头结构如下:
——————————————————————-
| TOKEN | STATUS | LENGTH | SIGNED NUM | PACKET NUM | WINDOW SIZE |
——————————————————————-
其中TOKEN字段域1个字节,用来表示TDS操作请求种类.在这个漏洞中是0×12,也就是NFR记录中de有效负载中de第一个字节0×12, 0×12是预登录验证命令请求.其目de是获得当前MS SQL SERVER2000de一些设置值,比如SQL SERVER版本,是否支持加密等信息,作为客户端在构造TDS包de一个依据.SQL Server在接受到该类型de包de时候,将会由SSlibnet.dll中de相应函数做处理,在我de系统SQL Server 2000(没有SP)de情况下,相应函数如下:
.text:42CF6DDD ; Attributes: bp-based frame
.text:42CF6DDD
.text:42CF6DDD public ConnectionPreLogin
.text:42CF6DDD ConnectionPreLogin proc near
.text:42CF6DDD
.text:42CF6DDD var_4 = dword ptr -4
.text:42CF6DDD arg_0 = dword ptr 8
.text:42CF6DDD arg_4 = dword ptr 0Ch
.text:42CF6DDD arg_8 = dword ptr 10h
.text:42CF6DDD arg_C = dword ptr 14h
.text:42CF6DDD arg_10 = dword ptr 18h
.text:42CF6DDD
.text:42CF6DDD push ebp
.text:42CF6DDE mov ebp, esp
.text:42CF6DE0 push ecx
.text:42CF6DE1 mov eax, [ebp arg_0]
.text:42CF6DE4 mov ecx, [eax 94h]
.text:42CF6DEA mov [ebp var_4], ecx
.text:42CF6DED cmp [ebp var_4], 1
.text:42CF6DF1 jz short loc_42CF6E01
.text:42CF6DF3 cmp [ebp var_4], 1
.text:42CF6DF7 jle short loc_42CF6E3D
.text:42CF6DF9 cmp [ebp var_4], 3
……
STATUS字段域1个字节,当它为0×01de时候表示此包为当前TDS会话中de最后一个TDS包.
LENGTH字段域2个字节,表示TDS包de总长度,包括TDS包头de长度.
SIGNED NUM字段域2个字节,目前保留未用.
PACKET NUM字段域1个字节,表示此TDS包在当前TDS操作请求中de序号
WINDOW SIZE字段域1个字节,目前保留未用.
MS SQL SERVER 0X12 TDSde包主要包格式如下:
——————————————————
| TDS包头(8字节)| 字段指示头 | 信息 |
——————————————————
其中字段指示头是一个可以变长de表,表de每一项代表了在一个字段在信息中de偏移地址和长度信息,在SQL2000中主要是4个字段,其对应de字段指示头de结构如下:
{
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;
}
信息内容de结构如下:
{
BYTE CNETLIBVER[CNETLIBVERLEN]
BYTE CENYFLAG[CENYFLAGLEN];
BYTE SINSTNAME[SINSTNAMELEN]
DWORD CTHREADID[CTHREADIDLEN];
}
其中:
CNETLIBVERNO字段域
偏移:0
长度:1
含义:客户端使用de网络连接库(NETLIB)de版本号信息de字段编号.
说明:
备注:该值固定为0
CNETLIBVEROFFSET字段域
偏移:1
长度:2
含义:客户端使用de网络连接库(NETLIB)de版本号信息de字段偏移.
说明:字段格式是网络字节顺序
备注:
CNETLIBVERLEN字段域
偏移:3
长度:2
含义:客户端使用de网络连接库(NETLIB)de版本号信息de字段长度.
说明:字段格式是网络字节顺序
备注:该值固定为6
CENYFLAGNO字段域
偏移:5
长度:1
含义:客户端使用强制加密标记字段de字段号.
说明:
备注:该值固定为1
CENYFLAGOFFSET字段域
偏移:6
长度:2
含义:客户端使用强制加密标记字段de偏移.
说明:字段格式是网络字节顺序
备注:
CENYFLAGLEN字段域
偏移:8
长度:2
含义:客户端使用强制加密标记字段de长度.
说明:字段格式是网络字节顺序
备注:该值固定为1
SINSTNAMENO字段域
偏移:0XA
长度:1
含义:客户端要求使用服务器de实例名字段de字段号.
说明:
备注:该值固定为2
SINSTNAMEOFFSET字段域
偏移:0XB
长度:2
含义:客户端要求使用服务器de实例名字段de偏移.
说明:字段格式是网络字节顺序
备注:
SINSTNAMELEN字段域
偏移:0XD
长度:2
含义:客户端要求使用服务器de实例名字段de长度.
说明:字段格式是网络字节顺序
备注:
CTHREADIDNO字段域
偏移:0XF
长度:1
含义:客户端进程de线程ID字段de字段号.
说明:
备注:该值固定为3
CTHREADIDOFFSET字段域
偏移:0X10
长度:2
含义:客户端进程de线程ID字段dede偏移.
说明:字段格式是网络字节顺序
备注:
CTHREADIDLEN字段域
偏移:0X12
长度:2
含义:客户端进程de线程ID字段de长度.
说明:字段格式是网络字节顺序
备注:该值固定为4
FILEDEND字段域
偏移:0X14
长度:1
含义:此字段标记字段指示头已经结实,下面de就是字段de信息.
说明:结束标记是0XFF
备注:
CNETLIBVER字段域
偏移:0X15
长度:6
含义:客户端使用de网络连接库(NETLIB)de版本号.
说明:其版本号取de是DBNETLIB.DLLde版本
备注:其格式是网络字节格式,如版本号为80.528.00,则为
08 00 02 10 00 00
CENYFLAG字段域
偏移:0X1B
长度:1
含义:客户端强制加密标志.
说明:0代表客户端不强制加密,1代表客户端使用强制加密
备注:
SINSTNAME字段域
偏移:0X1C
长度:SINSTNAMELEN
含义:客户端要求使用de实例名.
说明:单字节格式
备注:默认实例使用MSSQLserver这个名字
CTHREADID字段域
偏移:0X1C SINSTNAMELEN
长度:4
含义:客户端进程de线程ID.
说明:字段格式是主机字节顺序
备注:
由上面de格式可以看出,一个用默认实例名MSSQLserver连接deSQL TDS包格式将是如下de格式:
\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
而NFRde攻击签名库却是
HELLO_SIG = “\x12\x01\x00\x34\x00\x00\x00\x00\x00\x00\x15″;
明显是正常TDS 0×12预登陆包de一部分,这就难怪会有这么多报警了,那NFRde这个攻击签名是如何得到de呢?
我还是从它de漏洞说明入手吧!
5. 漏洞说明
下面是NFR N-CODE中对这个漏洞de说明:
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/ deDave Aitel,而从http://cert.uni-stuttgart.de/archive/bugtraq/2002/08/msg00125.html所列deMS SQL Server Hello Overflow NASL script中我可以看到这个漏洞de关键就在于以下几个语句:
<snip>
pkt_hdr = raw_string(
0×12 ,0×01 ,0×00 ,0×34 ,0×00 ,0×00 ,0×00 ,0×00 ,0×00 ,0×00 ,0×15 ,0×00 ,0×06 ,0×01 ,0×00 ,0×1b,
0×00 ,0×01 ,0×02 ,0×00 ,0×1c ,0×00 ,0×0c ,0×03 ,0×00 ,0×28 ,0×00 ,0×04 ,0xff ,0×08 ,0×00 ,0×02,
0×10 ,0×00 ,0×00 ,0×00
);
pkt_tail = raw_string (
0×00 ,0×24 ,0×01 ,0×00 ,0×00
);
<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协议构造de包,中间加了560个字符X,pkt_tail是构造deTDS包尾.
从这里我可以看到,可怜deNFR居然不负责任地把MS SQL Server Hello Overflow NASL script中depkt_hdr取出11个字符,毅然决然地把它们作为其签名.更为可笑de是居然还写着“False positives are unlikely due to the nature of the attack ”.
这就是在许多评测中遥遥领先deNFR?后来和stardust聊起这个事情de时候,认为这个现象和很多评测机构在评测IDS产品de时候,重视对产品漏报de检测而忽视对误报de评测有关.因为在评测产品时,基本上都是大部分都是黑箱评测,要检测漏报只要收集几个Exploits就可以进行,但要检测漏报却要产生正常de包,有些系统比如这里deSql Server,如果不了解它de协议包格式,是很难产生de.因此一些IDS产生便钻了这样de空子,只要收集一些Exploits,把其中de攻击相关代码作为攻击签名直接发布,而不去分析漏洞产生de真正原因.
下面我来分析一下这个漏洞产生de原因,然后我就可以根据这个分析,写出比较完善de攻击签名.
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
这个漏洞de原因就在这里,当程序用strcpy拷贝de时候,如果源字符串超出0×214(也就是532)后,目标地址后de环境变量就会被覆盖导致溢出.由于这个漏洞很早,经历了“Slammer”蠕虫后,基本上所有de系统都补掉了这个漏洞,因此这里就不在提供攻击相关代码了,有兴趣de朋友可以自己分析和编写一下.
另外需要在这里说明de是,如果分析了TDS协议和这个漏洞de成因,完善de攻击程序中deTDS包de长度是根据计算生成de,明显不会是”\x00\x34”,以避过SQL Server中针对TDS包长度de校验(当然在这个版本deSQL Server中还不包含这个校验),或者攻击程序把这攻击相关代码分成多个包,因此TDS格式中destatus就不会是0×01,因此NFR是检测不出完善de攻击程序dede,也就是说针对这个漏洞,NFR 同时存在误报和漏洞de情况.
在分析了这个漏洞de成因后,我就可以针对这个问题写出自己deNFR检测相关代码:
sqlserv_schema = library_schema:new(1, ["time","ip","int","ip","int", "str"],
scope());
sqlserv_rec = recorder(”bin/list %c”, “sqlserv_schema”);
HELLO_SIG = “\x12 “;
#考虑了分包和长度不固定de因素,去除了后面不可靠de特征串
MIN_LEN =29;
#包括TDS包头和字段指示头de总长度
…….
<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这个攻击签名de分析可以看出,发布完善deIDS攻击签名不是一个简单de事情,它需要了解应用de协议格式和漏洞de成因.而不是简单地收集网络上存在地exploits,然后截取其中de特征码.
目前很多人包括IDS开发人月都在讨论IDS有没有前途,需不需要.我想与其在那里讨论,不如静下来好好分析漏洞,完善攻击签名,使IDS做de更准确.
与其坐而论不如起而行!!(出处:www.xfocus.net)