這次以構造DNS報文為例繼續介紹libnet庫編程。
./linuxkiller -o 44 -y 53 -s 192.168.10.1
ping bbs.tsinghua.edu.cn後抓取如下報文:
[ udp ] 192.168.10.1 [ 1476 ] -> 192.168.0.2 [ 53 ]
udpHeadLen = 8 udpDataLen = 37
byteArray [ 37 bytes ] ---->
00000000 42 83 01 00 00 01 00 00-00 00 00 00 03 62 62 73 B?..........bbs
00000010 08 74 73 69 6E 67 68 75-61 03 65 64 75 02 63 6E .tsinghua.edu.cn
00000020 00 00 01 00 01 .....
42 83 id 標識符
01 00 param 參數 正向解析請求報文,允許遞迴解析
00 01 qtcount 問題數
00 00 ancount 回答數
00 00 aucount 管理機構數
00 00 adcount 其他資訊數
03 62 62 73 bbs 長度域為03
08 74 73 69 6E 67 68 75 61 tsinghua 長度域為08
03 65 64 75 edu 長度域為03
02 63 6E cn 長度域為02
00 長度域為0,表示結束
00 01
00 01
這是一個相當標準的DNS查詢報文,不理解的話可以翻看RFC。構造一些邊界情形的
DNS報文,如果DNS SERVER沒有處理邊界情形,結果未知。
./linuxkiller -o 44 -x 53 -s 192.168.0.2
ping bbs.tsinghua.edu.cn後抓取如下報文:
[ udp ] 192.168.0.2 [ 53 ] -> 192.168.10.1 [ 1476 ]
udpHeadLen = 8 udpDataLen = 165
byteArray [ 165 bytes ] ---->
00000000 30 8F 81 80 00 01 00 02-00 02 00 02 03 62 62 73 0弫€.........bbs
00000010 08 74 73 69 6E 67 68 75-61 03 65 64 75 02 63 6E .tsinghua.edu.cn
00000020 00 00 01 00 01 C0 0C 00-05 00 01 00 01 50 DC 00 .....?......P?
00000030 19 03 62 62 73 03 6E 65-74 08 74 73 69 6E 67 68 ..bbs.net.tsingh
00000040 75 61 03 45 44 55 02 43-4E 00 C0 31 00 01 00 01 ua.EDU.CN.?....
00000050 00 00 14 71 00 04 CA 70-3A C8 C0 35 00 02 00 01 ...q..蕄:壤5....
00000060 00 01 50 DD 00 06 03 6F-61 72 C0 35 C0 35 00 02 ..P?..oar??..
00000070 00 01 00 01 50 DD 00 0D-04 6D 6F 6F 6E 05 62 6A ....P?..moon.bj
00000080 6E 65 74 C0 42 C0 66 00-01 00 01 00 01 50 DD 00 net繠纅......P?
00000090 04 CA 70 3A CE C0 78 00-01 00 01 00 01 50 DD 00 .蕄:衛x......P?
000000A0 04 CA 70 04 41 .蕄.A
由於是兩次查詢,所以DNS應答報文的標識符和前面那個DNS查詢報文的標識符並不一
致,如果是配對的兩個報文,該標識符保持一致。回答分組有可能使用壓縮格式,而
請求分組永遠不會採用壓縮格式。
30 8F 標識符
81 80 參數 正向解析響應報文,遞迴解析獲得
00 01 問題數
00 02 回答數
00 02
00 02
03 62 62 73 bbs <-- 指標 = 12 (從資料區頭部開始計算)
08 74 73 69 6E 67 68 75 61
03 65 64 75
02 63 6E
00
00 01
00 01
C0 0C 指標 = 12 (從資料區頭部開始計算)
00 05 type = CNAME
00 01 class
00 01 50 DC 壽命
00 19 len = 25
03 62 62 73 bbs <-- 指標 = 49 (從資料區頭部開始計算)
03 6E 65 74 net <-- 指標 = 53 (從資料區頭部開始計算)
08 74 73 69 6E 67 68 75 61 tsinghua
03 45 44 55 EDU <-- 指標 = 66 (從資料區頭部開始計算)
02 43 4E CN
00 結束
C0 31 指標 = 49 (從資料區頭部開始計算)
00 01 type = A
00 01 class
00 00 14 71 壽命
00 04 len = 4
CA 70 3A C8 202.112.58.200
C0 35 指標 = 53 (從資料區頭部開始計算)
00 02 type = NS
00 01 class
00 01 50 DD 壽命
00 06 len = 6
03 6F 61 72 oar <-- 指標 = 102 (從資料區頭部開始計算)
C0 35 指標 = 53 (從資料區頭部開始計算)
C0 35 指標 = 53 (從資料區頭部開始計算)
00 02 type = NS
00 01 class
00 01 50 DD 壽命
00 0D len = 13
04 6D 6F 6F 6E moon <-- 指標 = 120 (從資料區頭部開始計算)
05 62 6A 6E 65 74 bjnet
C0 42 指標 = 66
C0 66 指標 = 102
00 01 type = A
00 01 class
00 01 50 DD 壽命
00 04 len = 4
CA 70 3A CE 202.112.58.206
C0 78 指標 = 120
00 01 type = A
00 01 class
00 01 50 DD 壽命
00 04 len = 4
CA 70 04 41 202.112.4.65
上面這些報文分析去年在華中站Security版貼過,當時也沒有人討論它,這次再分析
一次,主要是為後面的DoS程式做準備。建議用NetXray抓來回的DNS報文,看看解析
後的直觀顯示,加強理解。
寫linuxkiller的時候發現過許多關於DNS報文的問題。某次由於命令上指定過濾規則
失誤,對非UDP 53連接埠的報文調用了doUdpDns()函數進行解析,結果進入了無限迴圈。
我的解析函數假設指標後面絕對不會再跟指標,對此沒有進一步查看RFC,不知道RFC
是否有這個要求。解析函數的具體實現依賴於所接受的都是正常DNS報文,而非刻意
構造的攻擊性報文。很多sniffer軟體在解析DNS回答分組的時候沒有處理邊界情形,
前幾個月BugTraq來了好幾個關於這個問題的報告,包括tcpdump、L0pht的antisniff
等等都在解析DNS回答分組的時候存在問題。
還存在另外的問題。即使拋開指標,按照非壓縮格式構造一個巨大的DNS回答分組而
不違背RFC是很簡單的事情。我沒有抓取攻擊BIND 8的Exploit Code所發送出去的回
答分組,想來是利用了這點。今天才意識到DNS非壓縮格式居然依賴於長度域為00標
識結束,這就和strcpy等字串函數存在的問題類似了。