1. 前言 3
2. 警報資訊 3
3. NFR的偵測 4
4. 協定分析 小結 20
1. 前言
NFR(Network Flight Recorder)是一個老牌的商業網路IDS產品,最初由Firewall的牛人Marcus J. Ranum創建,是作為一個通用的網路流量分析和記錄軟體來實現的,為了最大限度地發揮分析工具的靈活性,NFR提供了完善強大的N-Code腳本語言,在許多的評測中表現出色。雖然L0pht為NFR提供過數百個簽名庫,但是缺乏一個可靠的簽名集一直是他的軟肋。
使用NFR有一段時間後,發現NFR有不少問題。且不說AI對中文的兼容性差而經常退出,也不說NFR版本升級而攻擊事件說明卻一直用舊版本的說明,單是IDS中最關鍵的攻擊簽名庫,卻讓我大跌眼鏡。除了升級緩慢以外,甚至還有不少錯誤的簽名。本系列文章針對其中我發現的部分問題進行分析和闡述,以便各位更好地利用NFR產品,同時也想和各位同仁討論IDS中攻擊簽名庫的編寫。由於知識與時間的限制,錯誤之處在所難免,也希望得到各位的指教,任何意見或建議請發至:benjurry@xfocus.org
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
Severity: Jul-2003
Source File: packages/mssql/sql2k.nfr
Line: 226
Host: 226
Host: k:buffered_hello
Source ID: mssql_sql2k:source_me
Source: mssql_sql2k:source_me
Source Description: Sqlserver 2k overflow detector
Source PID: 36531
Alert Message: 0.110 in 900 seconds
: 3
Source IP: 192.168.0.110
Destination IP: --
其中包括了事件的嚴重等級、時間、NFR SensorIP、攻擊來源IP、目的名稱和一些其他警報訊息資訊。
在實際的使用中,一天產生了幾百條這種報警,看來這是個誤報,我們可以好好的分析一下了。
3. NFR的偵測
我們先開啟NFR發布的簽章庫MSSQL.fp(或是也可以在AI的package中查看) 看看NFR的針對這個漏洞的攻擊簽章:
…..
變數定義等…
…
sqlserv_schema = library_schema:new(1, [ma:new(1, [ma:new(1, [ma:new(1) "time","ip","int","ip","int", "str"],
scope());
sqlserv_rec = recorder("bin/list %c", "sqlserv_schema ");
HELLO_SIG = "x12x01x00x34x00x00x00x00x00x00x15";
MIN_LEN = strlen(HELLO_SIG);
…….
filter hello tcp ( client, dport: 1433) {
declare $Blob inside tcp.connsym;
if ($Blob == NULL) {
Blob = cat($Blob, tcp.blob);
}
if (strlen($Blob) return;
if (COUNTHELLO[tcp.connsrc]) {
COUNTHELLO[tcp.connsrc] COUNTHELLO[tcp.connsrc] = 1;
}
if (do_alert(hello_overflow_alert, tcp.connsrc)) {
.connsport, tcp.conndst, tcp.conndport,
"--AlertDetails",
"ALERT_ID", "40-8",
"ALERT_SEVERITY", "medium",
"ALERT_IMPACT", " unknown",
"ALERT_EVENT_TYPE", "attack",
"ALERT_ASSESSMENT", "unknown", <.> "PORT_SRC", tcp.connsport,
"IP_ADDR_DST", tcp.conndst,
"PORT_DST", tcp.conndport,
.sec, tcp.conndst, tcp.conndport, tcp .connsrc,
tcp.connsport, $Blob to sqlserv_rec;
misc_attacks:rec(packet.sec ) , tcp.conndst);
}
}
從上面的N-CODE我們可以看到,NFR在做這個檢測的時候步驟如下:
1、定義了一個攻擊特徵碼:
HELLO_SIG = "x12x01x00x34x00x00x00x00x00x00x15";
和攻擊特徵碼的長度:
MIN_LEN = strlen(HELLO_SIG);
MIN_LEN = strlen(HELLO_SIG);
長度和特徵碼長度比較,如果這個資料長度小於攻擊特徵碼的長度,那麼就不再進行下一步的偵測;
3、否則,把這個資料和特徵碼進行字串匹配,如果一致則認為是攻擊行為,然後進行阻止或報警。
接下來我們分析一下NFR IDS Record的數據,在AI中選擇package->Query->MSSQL->MSSQL Server 200,定好條件,按Table查到數據,隨便選取一條,copy出來得到如下內容:
Time: 15-Jul-2003 13:54:21
NFR: benjurry-xfocus
Destination 15831219. 33
Source Address: 192.168. 0.110
Source Port: 1391
Payload:
x12x01xx
x01x02x00x1cx00x0cx03x00(x00x04xffx08x00x00xc2x00
🎜>
上面這條記錄包含了攻擊的時間,報告攻擊行為的NIDS sessor名字,目的IP、目的端口、源ip和源端口,而我們關心的是有效載荷Payload,因為它是NIDS用來和攻擊簽名庫比較的數據。 🎜>1. 會把payload中的能轉換成ASCII字符的16進制數轉換成ASCII碼;
2. 不能處理Unicode的字符,這個將在以後的分析中可以看到。
在這個例子中為了分析方便,我們把上面的payload中的字元特徵碼部分轉換成16進位數:
x12x01x00x34x00x00x00x00x00x00x15x00x06x01x00x 3x00x28x00x04xffx08x00x00
xc2x00x00x00MSSQLServerx00xx03x00x00
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 .
.text:42CF6DDD var_4 = dword ptr -4
.text:42CF6DDD arg_0 = dword ptr 8 .text:42CF6DDD arg 萬_8 = dword ptr 10h
. text:42CF6DDD arg_C = dword ptr 14h
.text:42CF6DDD arg_10 = dword ptr 18h
.text:42CF6D18h ebp
.text:42CF6DDE mov ebp, esp
.text:42CF6DE0 push ecx
.text:42CF6DE1 mov e [eax 94h]
.text:42CF6DEA mov [ebp var_4], ecx
.text:42CF6DED cmp [ebp var_4], 1
.text:42CF6DF1 cmp [ebp var_4], 1
.text:42CF6DF7 jle short loc_42CF6E3D
. text:42CF6DF9 cmp [ebp var_4], 3
…
STATUS字段1個位元組,當它為0x01的時候表示此包為當前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 SINSTNAMENO;
WORD SINSTNAMEOFFSET;
WORD SINSTNAMELEN;
BYTE CTHREADIDNO;
WORD CTHREADIDOFFSET的結構如下:
{
BYTE CNETLIBVER[CNETLIBVERLEN]
BYTE CENYFLAG[CENYFLAGLEN];
BYTE SINSTNAME[SINSTNAMELEN]
>DWORD CDCU4S4S4P474 月(D455>T]]T5P]P]P]P]]PP版本]])> 🎜>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
08 00 02 10 00 00
CENYFLAG欄位
偏移:0X1B
長度:1
意義:客戶端強制加密標誌。
說明:0代表客戶端不強制加密,1代表客戶端使用強制加密
備註:
SINSTNAME字段域
偏移:0X1C
長度:SINSTNAMELEN
偏移:0X1C
長度:SINSTNAMELEN
意義:客戶端要求使用的實例名。
說明:單字節格式
備註:預設實例使用MSSQLserver這個名字
CTHREADID欄位域
偏移:0X1C SINSTNAMELEN
長度:4
意義:客戶端行程的執行緒ID。
說明:欄位格式是主機位元組順序
備註:
由上面的格式可以看出,一個用預設實例名MSSQLserver連接的SQL TDS套件格式將是如下的格式:
x12x01x00x34x00x00x00x00
x00x00x15x00x06x01x00x1b
x00x01x02x00x1cx00x1b
x00x01x02x00x1cx00x0cx00ffx 🎜>xc2x00x00x00MSSQ
LServerx00
x78x03x00x00
而NFR的攻擊簽章庫卻是
HELLO_SIGa>
而NFR的攻擊簽章庫卻是
HELLO_SIGx = "x12x10x"x00x
很明顯是正常TDS 0x12預登陸包的一部分,這就難怪會有這麼多警報了,那NFR的這個攻擊簽名是如何得到的呢?
我們還是從它的漏洞說明入手吧!
5. 漏洞說明
以下是NFR N-CODE中對這個漏洞的說明:
FALSE POSITIVES
False positives are unlikely of to the nature 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中我們可以看到這個漏洞的關鍵就在於以下幾個語句:
pkt_hdr = raw_string(
0x12 ,0x01 ,0x00 ,0x34 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x15 ,0x00 00x,00,00x, 0 ,0x01 ,0x02 ,0x00 ,0x1c ,0x00 ,0x0c ,0x03 ,0x00 ,0x28 ,0x00 ,0x04 ,0xff ,0x08 ,0x00 ,0x02,
0x10 ,0x00,000x tail = raw_string (
0x00 ,0x24 ,0x01 ,0x00 ,0x00
);
…..
if(get_port_state(port))
{; 🎜> soc = open_sock_tcp(port);
if(soc)
{
attack_string=crap(560); ;
send( socket:soc, data:sql_packet);
r = recv(socket:soc, length:4096);
close(soc);
{
display("Security Hole in MSSQLn");
}
其中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_42
.text:42CF6F49 loc_42
.text:42CF6F49 mov eax, [ebp 0xc]
.text:42CF6F4C push eax
.text:42CF6F53 lea ecx, [ebp-0x214]
.text:42CF6F59 push ecx
.text:42CF6F5A all add esp, 8
.text:42CF6F62 push offset unk_42D01104
.text: 42CF6F67 lea edx, [ebp-0x214]
.text:42CF6F6D push edx
這個漏洞的原因就在這裡,當程式用strcpy拷貝的時候,如果來源字串超出0x214(也就是532)後,目標位址後的環境變數就會被覆寫導致溢位。由於這個漏洞很早,經歷了「Slammer」蠕蟲後,基本上所有的系統都補掉了這個漏洞,因此這裡就不在提供攻擊代碼了,有興趣的朋友可以自己分析和編寫。
另外需要在這裡說明的是,如果分析了TDS協定和這個漏洞的成因,完善的攻擊程序中的TDS包的長度是根據計算生成的,明顯不會是」x00x34 ”,以避過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包頭和欄位指示頭的總長度
…….
filter hello tcp (client, dport: 1433) {
declare $Blob inside tcp.connsym;
declare $Blob inside tcp.connsym; ($Blob == NULL) {
$Blob = tcp.blob;
} else {
$Blob = cat($Blob, tcp.blob) return;
if (prefix($Blob, HELLO_SIG) && strlen($Blob) > 295) { 超過255,因此這裡長度選擇了40(包頭) 255=295
#也可以增加一個Value,以便用戶自己根據事件情況進行調節
#警報
….
}
7. 小結
透過對NFR這個攻擊簽章的分析可以看出,發布完善的IDS攻擊簽章不是一個簡單的事情,它需要了解應用的協定格式和漏洞的成因。而不是簡單地收集網路上存在地exploits,然後截取其中的特徵碼。
目前很多人包括IDS開發人月都在討論IDS有沒有前途,需不需要。我想與其在那裡討論,不如靜下來好好分析漏洞,完善攻擊簽名,讓IDS做的更準確。
與其坐而論不如起而行! ! (來源:www.xfocus.net)