程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> 優化NFR之一 --MSSQL Hello Buffer Overflow

優化NFR之一 --MSSQL Hello Buffer Overflow

編輯:關於PHP編程


1.  前言  3
2.  報警信息  3
3.  NFR的檢測  4
4.  協議分析  8
5.  漏洞說明  15
6.  漏洞分析  18
7.  小結  20


1.  前言
NFR(Network Flight Recorder)是一個老牌的商業網絡IDS產品,最初由Firewall的牛人Marcus J. Ranum創建,是作為一個通用的網絡流量分析和記錄軟件來實現的,為了最大限度地發揮分析工具的靈活性,NFR提供了完善強大的N-Code腳本語言,在很多的評測中表現出色。雖然L0pht為NFR提供過數百個簽名庫,但是缺乏一個可靠的簽名集一直是他的軟肋。

使用NFR有一段時間後,發現NFR存在著不少問題。且不說AI對中文的兼容性差而經常退出,也不說NFR版本升級而攻擊事件說明卻一直用舊版本的說明,單是IDS中最關鍵的攻擊簽名庫,卻讓我大跌眼鏡。除了升級緩慢以外,甚至還存在不少錯誤的簽名。本系列文章針對其中我發現的部分問題進行分析和闡述,以便各位更好地利用NFR產品,同時也想和各位同仁討論IDS中攻擊簽名庫的編寫。由於知識和時間的限制,錯誤之處在所難免,還希望得到各位的指教,任何意見或建議請發至:[email protected]

SQL Server是微軟為對抗Oracle推出的數據庫, 占領的市場份額已經僅次於Oracle,居世界第二,但是其安全性也一直受到用戶的置疑。從1996年,Microsoft公司推出的SQL Server 6.5版本到1998年推出的SQL Server 7.0,以及到2000年8月推出了SQL Server 2000,在版本和功能不斷升級的情況下,安全問題卻沒有得到很好地改善,不斷發布針對SQL Server的安全公告和補丁。在2003年1月24日,針對SQL Server的“Slammer”蠕蟲在Internet上肆虐,導致網絡流量激增,嚴重影響了世界范圍內的計算機和網絡系統。SQL Server的漏洞引起了各大安全公司和廠商的重視,因此NFR也立即發布了多個針對SQL Server的攻擊簽名,其中包括了2002年8月7日Immunity公司Dave Aitel發現的Hello Buffer Overflow漏洞。但是在使用過程中,我發現NFR針對該漏洞的報警非常多,於是我對此進行了分析,於是寫成了這個文章,以做記錄。


2.  報警信息
下面是NFR針對MS SQL Hello Buffer Overflow的報警信息:

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:       --

其中包括了事件的嚴重等級、時間、NFR Sensor名字、攻擊源IP、目的IP和一些其他報警信息。
在實際的使用中,一天產生了幾百條這種報警,看來這是個誤報,我們可以好好的分析一下了。


3.  NFR的檢測
我們首先打開NFR發布的簽名庫 MSSQL.fp(或者也可以在AI的package中查看) 看一下NFR的針對這個漏洞的攻擊簽名:

<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);
  }
}

從上面的N-CODE中我們可以看到,NFR在做這個檢測的時候步驟如下:

1、定義了一個攻擊特征碼:
HELLO_SIG = "\x12\x01\x00\x34\x00\x00\x00\x00\x00\x00\x15";
和攻擊特征碼的長度:
MIN_LEN = strlen(HELLO_SIG);

2、從TCP的載荷數據中取出數據,把這個數據的長度和特征碼長度比較,如果這個數據長度小於攻擊特征碼的長度,那麼就不再進行下一步的檢測;

3、否則,把這個數據和特征碼進行字符串匹配,如果一致則認為是攻擊行為,然後進行阻止或者報警。
接下來我們分析一下NFR IDS Record的數據,在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

上面這條記錄包含了攻擊的時間,報告攻擊行為的NIDS sessor名字,目的IP、目的端口、源ip和源端口,而我們關心的是有效載荷Payload,因為它是NIDS用來和攻擊簽名庫比較的數據。但是NFR在這裡有幾個小問題:

1.  會把payload中的能轉換成ASCII字符的16進制數轉換成ASCII碼;

2.  不能處理Unicode的字符,這個將在以後的分析中可以看到。

在這個例子中為了分析方便,我們把上面的payload中的字符特征碼部分轉換成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包,便把裡面的內容和SQL Server的攻擊庫進行比較,很明顯,上面所列的數據和攻擊庫是相符合的,因此一個報警便產生了,但是這真是一個攻擊行為嗎?我們繼續看下面的分析。


4.  協議分析

根據Xfocus的協議分析項目(將會在近期公布項目成果),MS SQL 2000用的是TDS8.0,它的格式如下:
-------------------------------------------------
| TDS包頭(8字節) |  TDS負載數據       |
-------------------------------------------------
其中MS SQL SERVER 2000 TDS的包頭結構如下:
-------------------------------------------------------------------
| TOKEN | STATUS | LENGTH | SIGNED NUM | PACKET NUM | WINDOW SIZE |
-------------------------------------------------------------------
其中TOKEN字段域1個字節,用來表示TDS操作請求種類。在這個漏洞中是0x12,也就是NFR記錄中的有效負載中的第一個字節0x12, 0x12是預登錄驗證命令請求。其目的是獲得當前MS SQL SERVER2000的一些設置值,比如SQL SERVER版本,是否支持加密等信息,作為客戶端在構造TDS包的一個依據。SQL Server在接受到該類型的包的時候,將會由SSlibnet.dll中的相應函數做處理,在我的系統SQL Server 2000(沒有SP)的情況下,相應函數如下:


.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個字節,當它為0x01的時候表示此包為當前TDS會話中的最後一個TDS包。
LENGTH字段域2個字節,表示TDS包的總長度,包括TDS包頭的長度。
SIGNED NUM字段域2個字節,目前保留未用。
PACKET NUM字段域1個字節,表示此TDS包在當前TDS操作請求中的序號
WINDOW SIZE字段域1個字節,目前保留未用。
MS SQL SERVER 0X12 TDS的包主要包格式如下:
------------------------------------------------------
| TDS包頭(8字節)| 字段指示頭 |    信息      |
------------------------------------------------------
其中字段指示頭是一個可以變長的表,表的每一項代表了在一個字段在信息中的偏移地址和長度信息,在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)

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved