什麼時候不該用封包嗅探#

有時候封包嗅探(packet sniffing)並不合適。例如你沒有擷取流量的權限——正在對一個沒有管理權限的系統做滲透測試,或面對的是一支只有受限權限 shell 的行動裝置。也有時候你只想看「受測應用程式」的流量,而封包嗅探除非用時間去關聯,否則很難做到這件事。

本節介紹幾種不靠封包嗅探工具、直接從本機應用程式取出網路流量的技術。

系統呼叫追蹤#

現代作業系統多半提供兩種執行模式:核心模式(kernel mode) 以高權限執行,內含實作作業系統核心功能的程式碼;使用者模式(user mode) 則是日常行程執行的地方。核心透過匯出一組特殊的系統呼叫(system call) 為使用者模式提供服務,讓程式能存取檔案、建立行程——而對我們最重要的——連上網路。

圖表 2-4:透過系統呼叫進行的使用者模式對核心模式網路通訊範例

當應用程式要連線到遠端伺服器,它會對核心發出特殊的系統呼叫來開啟連線,接著讀寫網路資料。依作業系統不同,你可以直接監看這些呼叫,被動地把資料從應用程式中抽取出來。

大多數類 Unix 系統的網路系統呼叫都近似 Berkeley Sockets 模型。這並不意外:IP 協定最初就是在 BSD(Berkeley Software Distribution)4.2 Unix 上實作的。這套 socket 實作也是 POSIX 的一部分,使它成為事實標準。

名稱說明
socket建立新的 socket 檔案描述子(file descriptor)。
connect將 socket 連到已知的 IP 位址與連接埠。
bind將 socket 綁定到本機已知的 IP 位址與連接埠。
recv / read / recvfrom透過 socket 從網路接收資料。read 是讀取檔案描述子的通用函式,recvrecvfrom 則專屬於 socket API。
send / write / sendfrom透過 socket 將資料送上網路。

想深入了解這些系統呼叫,《The TCP/IP Guide》(No Starch Press, 2005)是很好的資源;線上資料也很多。多數類 Unix 系統本身就附有手冊,在終端機執行 man 2 syscall_name 即可查閱。

Linux 上的 strace#

在 Linux 上,你可以直接從使用者程式監看系統呼叫,不需要特殊權限——除非目標應用程式是以特權使用者身分執行。許多 Linux 發行版都內建 strace 這支好用的工具;若沒有預裝,可從發行版的套件管理員下載,或自行從原始碼編譯。

/path/to/app 換成受測應用程式、args 換成必要參數,即可記錄該應用程式使用的網路系統呼叫:

strace -e trace=network,read,write /path/to/app args
範例:解讀 strace 的輸出

以下是一支會讀寫幾個字串的網路應用程式,經 strace 監看後的輸出(為求簡潔已移除無關的記錄):

$ strace -e trace=network,read,write customapp
--snip--
socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(5555),
                     sin_addr=inet_addr("192.168.10.1")}, 16) = 0
write(3, "Hello World!\n", 13)          = 13
read(3, "Boo!\n", 2048)                 = 5
  • 第一筆建立了新的 TCP socket,取得代號 3
  • 第二筆的 connect 對 IP 位址 192.168.10.1 的 5555 埠建立 TCP 連線。
  • 接著應用程式寫出字串 Hello World!
  • 最後讀回字串 Boo!

即使沒有高權限,也能從系統呼叫層級對應用程式的行為建立相當清楚的輪廓。

以 DTrace 監看網路連線#

DTrace 是一套非常強大的工具,可用於許多類 Unix 系統,包括 Solaris(它的發源地)、macOS 與 FreeBSD。它讓你在特殊的追蹤提供者(trace provider,含系統呼叫)上設置系統層級的探針(probe)。設定方式是以一種 C 風格語法的語言撰寫腳本。

範例:traceconnect.d 腳本與輸出

以下腳本監看 connect 系統呼叫,輸出 IPv4 的 TCP 與 UDP 連線:

/* traceconnect.d - A simple DTrace script to monitor a connect system call */
struct sockaddr_in {
    short            sin_family;
    unsigned short   sin_port;
    in_addr_t        sin_addr;
    char             sin_zero[8];
};

syscall::connect:entry
/arg2 == sizeof(struct sockaddr_in)/
{
    addr = (struct sockaddr_in*)copyin(arg1, arg2);
    printf("process:'%s' %s:%d", execname, inet_ntop(2, &addr->sin_addr),
        ntohs(addr->sin_port));
}

connect 有三個參數,在 DTrace 腳本語言中以 arg0arg1arg2 表示,並由核心替我們初始化:

  • arg0 是 socket 檔案描述子,本例用不到。
  • arg1 是要連線的 socket 位址結構在使用者行程記憶體中的位址;依 socket 型別不同,大小也不同(例如 IPv4 位址就比 IPv6 小)。
  • arg2 是該位址結構的位元組長度。

腳本先定義了 IPv4 連線使用的 sockaddr_in 結構(很多情況下可直接從系統的 C 標頭檔複製過來),接著指定要監看的系統呼叫,再以 DTrace 專屬的過濾條件確保只追蹤 socket 位址大小等於 sockaddr_inconnect 呼叫。然後把 sockaddr_in 從目標行程複製到本地結構供 DTrace 檢視,最後把行程名稱、目的 IP 位址與連接埠印到主控台。

把腳本存成 traceconnect.d,以 root 身分執行 dtrace -s traceconnect.d。當你使用有網路連線的應用程式時,輸出會類似:

process:'Google Chrome'    173.194.78.125:5222
process:'Google Chrome'    173.194.66.95:443
process:'Google Chrome'    217.32.28.199:80
process:'ntpd'             17.72.148.53:123
process:'Mail'             173.194.67.109:993
process:'syncdefaultsd'    17.167.137.30:443
process:'AddressBookSour'  17.172.192.30:443

DTrace 的輸出不一定像 Linux 上的 strace 那麼有用——它列出的是連線目標而非資料內容——但它仍是價值很高的工具,上面的示範也只觸及它能力的皮毛。更多細節可參考線上的 DTrace Guide:http://www.dtracebook.com/index.php/DTrace_Guide

Windows 上的 Process Monitor#

與類 Unix 系統不同,Windows 的使用者模式網路功能並非以直接的系統呼叫實作。網路堆疊是透過驅動程式對外提供,建立連線時是用檔案的 open、read、write 系統呼叫去設定一個網路 socket。即使 Windows 有類似 strace 的機制,這種實作方式也讓「與其他平台同層級的網路監看」變得更困難。

從 Vista 之後,Windows 支援一套事件產生框架(event generation framework),讓應用程式能監看網路活動。自行實作相當複雜,所幸微軟的 Process Monitor 已經幫你做好了。

圖表 2-5:Process Monitor 擷取範例

在 Process Monitor 中套用只顯示網路連線事件的過濾器後,你會看到受監看行程的網路連線事件,細節包含涉及的主機、使用的協定與連接埠。單一 HTTP 連線的檢視會呈現這些欄位:

  • 建立連線的行程名稱。
  • 操作類型——本例是連線到遠端伺服器、送出初始 HTTP 請求、接收回應。
  • 來源與目的位址。
  • 該擷取事件的更深入資訊。

圖表 2-6:單一擷取到的連線

Process Monitor 還能擷取當下呼叫堆疊(calling stack)的狀態,幫你判斷應用程式是在哪裡建立網路連線的。這一點到第 6 章開始逆向工程二進位檔、推導網路協定時會變得很重要。

這個方法無法擷取連線所帶的資料,它只告訴你連線的存在與後設資訊。不過一旦確定了應用程式使用哪些協定,你就能把這項資訊帶進更主動的擷取方式,繼續往下分析。

被動擷取的優點與缺點#

優點

  • 最大的優點是不會擾亂用戶端與伺服器之間的通訊:不改變流量的來源或目的位址,也不需要修改或重新設定應用程式。
  • 當你無法直接控制用戶端或伺服器時,被動擷取往往是唯一可行的技術。通常你都能找到某種方式聽到網路流量,投入的工夫也有限。
  • 收集到資料之後,你就能判斷該採用哪些主動擷取技術,以及攻擊目標協定的最佳路徑。

缺點

  • 封包嗅探這類技術執行層級太低,難以還原「應用程式實際收到了什麼」。Wireshark 這類工具確實有幫助,但面對自訂協定時,不與它互動往往就無法輕易拆解。
  • 被動擷取不易修改應用程式產生的流量。修改流量不是永遠必要,但在遇到加密協定、想關閉壓縮、或需要為了漏洞利用而竄改流量時就非常有用。

當「分析流量並注入新封包」得不到結果時,就該換戰術,改用主動擷取技術。