libnet使用舉例(9)
作者:小四 (scz@nsfocus.com)
首頁:http://www.nsfocus.com
日期:2000-08-15
今次以IGMP攻擊為例繼續介紹libnet庫編程。IGMP補丁我沒有用過,對於Pwin98來說,
IGMP實在沒有什麼用途,可以考慮袁哥的這個辦法:
用ultraedit搜尋6A 02 E8,修改成6A F2 E8。這裡02對應IGMP協議,這樣處理過後,
F2才對應IGMP,所以呢,一般的針對標準IGMP協議的攻擊就全部失效了,當然你也無
法正常使用IGMP協議。完全可以不用F2,換用其他值。
可能需要複習一點IP協議、IP分區的基礎知識:
1) tos應該只指定其中一個bit,同時指定幾個是沒有意義的。至於是不是允許的或
者說接收者如何處理這種報文依賴於具體實現,有可能出錯。
2) IP分區和完整IP報文幾乎擁有同樣的IP頭,id域對於每個分區都是一致的,這樣
才能在重組的時候識別出來自同一IP報文的分區。flags佔用了最高的3bit,按從
左到右表示從高到低,最左bit保留,應該置零,如果非零有什麼後果不清楚;中
間bit置1表示不得對該IP報文分區,如果路由因為MTU緣故必須分區才能發送這種
不可分區IP報文的時候,就先廢棄該IP報文然後用ICMP通知源主機廢棄原因,如
果不是特殊需要不應該置1;最右bit置1表示該報文不是最後一個IP分區。
3) 完整單包IP報文的flags最右bit為零,同時fragment offset為零。第一個IP分區
的flags最右bit為1,同時fragment offset為零。最後一個IP分區的flags最右
bit為0,此時fragment offset必不為零。fragment offset與flags共用兩個位元組,
前者佔用了低13bit。fragment offset給出的位移是相對完整IP報文資料區而言
的,以8bytes為單位。
4) 重組發生在最終目的主機上,中間路由不對分區重組。重組發生在所有分區到達
之後。一般最終目的主機在收到一個IP分區(不一定是第一個分區)的時候啟動一
個定時器,如果逾時而分區仍未到齊,則廢棄具有相同id的所有已到達分區,意
味著丟失一個分區就丟失了完整IP報文,此時IP層本身不會負責重傳,需要上層
協議自己意識到需要重傳了。
可以想象,故意發送部分IP分區而不是全部,導致目標主機總是等待分區消耗占
用系統資源。某些分區風暴攻擊就是這種原理。
5) IP分區的total_len給出的是這個IP分區的總長度,而不是完整IP報文總長度。
6) 使用UDP很容易導致IP分區,而很難強迫TCP發送一個需要進行分區的報文。
早期作業系統實現對IP分區的邊界判斷不夠完善,總是存在這樣那樣的問題,經過近
年各種DoS攻擊的研究、分析、對抗,已經日趨完善,很不容易找到關於分區邊界處
理上的漏洞了。為什麼要複習IP分區,下面介紹的一種IGMP攻擊涉及到IP分區,不複
習一下,怕有些朋友看暈菜掉。
另外一個不太相關的問題,raw_socket可以發送IP分區,但是永遠接收不到IP分區,
核心在重組完成之前是不會給raw_socket一個IP分區的,記住這點很重要。可能有
些朋友看到利用raw_socket發送IP分區的原始碼,而誤以為IP分區對於收發
raw_socket都是可見的。
不打算重複IGMP的整個RFC,下面就IGMP協議的幾個要點回顧一下:
1) IGMP版本目前為1,類型只有兩種,1表示組播路由器發出的查詢,2表示組內主機
發出的響應。校正和是針對8位元組的IGMP報文的。未用域必須清零。
2) 兩個有效IGMP報文例子
IGMP響應(2)
TTL = 1
所加入的組地址
目的IP = 組地址
源IP = 本機IP
IGMP查詢(1)
TTL = 1
組地址 = 0
目的IP = 224.0.0.1
源IP = 組播路由器IP
3) 主機上某個進程在本機某個介面上加入某個組時,如果前面沒有本機其他進程加
入該組,則發送一個IGMP響應。本機會維護相關資訊,直到所有本機進程退出該
組。
進程離開某個組時並不發送IGMP響應。當本機所有進程退出所有組後,如果有組
播路由器發送查詢報文,本機不做IGMP響應。
組播路由器定時發送查詢,這個查詢報文的組地址固定為0,目標IP為224.0.0.1。
4) 224.0.0.0 - 239.255.255.255的D類地址屬於組播地址。但是224.0.0.0不能用於
任何組。224.0.0.1表示區域網路內所有擁有組播能力的主機、路由器,每個網路接
口初始化後如果擁有組播能力,會自動加入該組,即使沒有本機進程明確加入該
組,不會因為加入該組而發送IGMP響應。組播地址可以作為目標IP出現,但不能
作為源IP出現。
224.0.0.0 - 224.0.0.255之間的組播地址如果出現在目標IP上,無論TTL多大,
組播路由器也不會轉寄這種報文,這種報文只能出現在區域網路內。顯然這裡包括
了224.0.0.1。
5) TTL為0的組播報文根本就無法出主機,為1表示組播報文只能在區域網路內傳送。如
果想被組播路由器轉寄出去,必須設定更大的TTL。
上述描述是W.Richard.Stevens對4.x BSD實現的描述,現在可能有變化。版本和類型
共用一個位元組,版本佔用高4bit,所以很多標頭檔裡定義0x11、0x12這樣的宏,至於
0x16、0x17,注釋解釋得比較清楚。
組內成員主機收到IGMP查詢後,會在隨機時間段內作出響應,因為組播導致組內其他
成員主機均收到響應,不僅僅是發出查詢報文的主機,所以其餘成員主機不再響應,
避免了響應風暴。非組內成員主機可以發送查詢報文,但它一定收不到相應的IGMP響
應。不是只有組播路由器才可以發送IGMP查詢,其他IGMP查詢報文的資料有所區別,
比如目的IP不一定是224.0.0.1,可以是某個其他組播地址,組地址也不一定是0,可
以是某個確定的組地址。
libnet庫中有如下函數原型:
int libnet_build_igmp ( u_char type, u_char code, u_long ip,
const u_char * payload, int payload_s,
u_char * buf );
該函數用於構造IGMP報文,type取值在/usr/include/libnet/libnet-headers.h中有
如下宏定義:
#define IGMP_MEMBERSHIP_QUERY 0x11 /* membership query */
#define IGMP_V1_MEMBERSHIP_REPORT 0x12 /* Ver. 1 membership report */
#define IGMP_V2_MEMBERSHIP_REPORT 0x16 /* Ver. 2 membership report */
#define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */
這裡0x17似乎意味著以後離開組需要發送IGMP報文通知大家,不清楚。0x16更讓人迷
糊,既然是版本2的,就應該是0x26,不懂。反正我們不用它們,懶得深究。
形參code應該指定未用域的,那就只能是零了。形參ip指定D類組播地址,payload為
NULL,payload_s為零。形參buf需要指向一個已指派好的資料區,IGMP頭從該指標開
始。
校正和計算套用libnet_do_checksum( packet, IPPROTO_IGMP, LIBNET_IGMP_H )函
數,當然,如果非正常IGMP報文,帶了負載的話就需要調整參數值。
遺憾的是,此次攻擊程式並沒有真正利用上述函數,僅僅是IP頭的部上層協議域指明
負載是IGMP報文。
下面將要介紹的這個IGMP攻擊程式有很多地方異常:
1) IP頭部上層協議指明IP資料區出現IGMP報文,但是IP頭部的目標地址不是組播地
址而是單播地址(也是被攻擊的目標地址),所以這樣的報文能不能稱做IGMP報文
值得推敲,是否作為IGMP報文被處理值得懷疑。
2) IGMP報文總共8位元組,沒有其他負載。但這個攻擊程式有其他負載,並且負載很大,
刻意製造了IP分區。攻擊程式在發送IP分區的時候採用倒序,先發送最後一個分
片,最後發送第一個分區。這裡採用raw_socket人為製造的異常分區,不是讓IP
協議棧自行分區,事實上在發送方始終沒有出現過那個分區前的超大完整IP報文。
3) IGMP報文版本、類型、校正和、組地址全部為零,顯然異常。
4) 如果以完整的一批IP分區為單位,原來的程式迴圈發送了兩次。在測試過程感覺
還是依賴於發送速度和發送數量的,預設使用兩次,不是每次都攻擊成功,這種
情況下重複攻擊效果也不是很好。在程式中把迴圈次數調整成200,一次攻擊就成
功,明顯和攻擊速度、報文數量有關。
源IP不要求等於目標IP,可以是任意偽造的源IP。目標IP地址並不是組播地址,
對於只看到IP層的路由器來說,就是普通單播IP報文,並不會意識到正在路由一
個IGMP報文(如果這個報文能被稱做IGMP報文的話)。以前有朋友說不能在廣域網路
上進行IGMP攻擊,而又有一些朋友卻說遠程攻擊奏效。據我這次分析,遠程攻擊
有些時候失效,並不是因為常規路由不轉寄組播報文,前面解釋過了,路由看到
的是單播IP報文,而是因為分區丟失。這個攻擊程式每次迴圈製造11個分區,遠
程攻擊不能保證11個分區都能按時到達目標IP進而重組。這樣看來,還是重組後
巨大的異常IGMP報文帶來麻煩。
總有朋友問這類DoS攻擊原理何在,也總有朋友回答就是發送什麼什麼樣的報文,
感覺回答的只是表象,真正解釋為什麼藍屏、為什麼死機,需要用softice跟蹤目
標主機對這種報文的處理過程。一個有效DoS報文本身說明不了問題,通過協議分
析軟體抓取報文、通過閱讀原始碼分析報文都僅僅是搞清楚什麼樣的報文會導致
DoS,為什麼這樣的報文會導致DoS不是網路資料本身能給出答案的。前陣子那個
jot2.c,我只能知道那種類型的報文可能導致DoS,但為什麼導致,不清楚,不分
析具體作業系統在這些協議處理上的實現,只看網路資料,能得到什麼答案,隔
靴搔癢。不大喜歡別人用這種方式討論這種問題,有夸夸其談的嫌疑。也沒有必
要過深瞭解這類DoS的真實原因,除非你有能力修改系統,象Linux那樣能修理源
代碼的另當別論。
這個攻擊首先導致目標藍屏,斷行符號後IP棧基本廢掉了,從遠程無法ping通目標,
需要重啟動恢複。但沒有導致死機,還可以做其他非網路工作。如果存在
softice,情況不大一樣,我對此並不熟悉,不多描述。
5) IP頭部的id域始終沒有改變,後一輪迴圈中的分區和前一輪迴圈中的分區如何區
分,我看就無法區分,對接收方分區重組帶來什麼樣的影響?
個人覺得這個攻擊完全可以遠程進行,而且不要求源IP等於目標IP,機會很大。命令
行上指定偽造的源IP、攻擊目標IP、IGMP報文數目(以一批分區為單位)。
--------------------------------------------------------------------------
void igmpSend ( u_long srcIp, u_long dstIp )
{
u_short ipDataLen;
u_short frag;
u_short bit;
bit = 0;
ipDataLen = 200; /* 200位元組的負載,總共15000位元組的負載 */
frag = 1850;
do
{
/* 構造IP頭 */
libnet_build_ip( ipDataLen, /* IP資料區長度 */
IPTOS_LOWDELAY, /* IP tos */
19774, /* IP ID */
frag | bit, /* frag stuff */
255, /* TTL */
IPPROTO_IGMP, /* 上層協議 */
srcIp, /* big-endian序 */
dstIp, /* 目標IP */
NULL, /* 無選項 */
0, /* 選項長度零 */
packet ); /* 指向IP頭 */
Libnet_write_ip( rawSocket, packet, LIBNET_IP_H + ipDataLen );
if ( frag == 0 )
{
break;
}
ipDataLen = IPDATALEN;
bit = 0x2000; /* 非最後分區 */
frag -= 185;
} while ( 1 ); /* 總共11個分區發送出去 */
return;
} /* end of igmpSend */