議全流程深度解析:從密鑰交換到Wireshark實(shí)戰(zhàn)抓包)
1. SSH協(xié)議從密碼到密鑰的信任建立之旅當(dāng)你需要遠(yuǎn)程管理一臺服務(wù)器或者安全地傳輸文件時SSHSecure Shell幾乎是唯一的選擇。它就像一個加密的隧道把你在本地敲擊的每一個字符、傳輸?shù)拿恳粋€字節(jié)都嚴(yán)嚴(yán)實(shí)實(shí)地包裹起來防止任何窺探。但你是否想過這個看似簡單的“連接”動作背后究竟發(fā)生了多少輪復(fù)雜的“握手”和“協(xié)商”為什么第一次連接時會彈出一個警告公鑰和私鑰又是如何協(xié)同工作讓你實(shí)現(xiàn)免密登錄的理解SSH的完整流程絕不僅僅是滿足技術(shù)好奇心。當(dāng)連接超時、認(rèn)證失敗、或者速度異常時清晰的流程認(rèn)知能讓你像偵探一樣快速定位問題究竟出在“握手”、“密鑰交換”、“認(rèn)證”還是“會話建立”的哪一個環(huán)節(jié)。而Wireshark這個網(wǎng)絡(luò)世界的“顯微鏡”則能將協(xié)議層抽象的交互還原成一個個看得見、摸得著的網(wǎng)絡(luò)數(shù)據(jù)包讓理論照進(jìn)現(xiàn)實(shí)。今天我們就拋開枯燥的RFC文檔以一次完整的SSH連接為線索親手用Wireshark抓取并剖析每一個數(shù)據(jù)包。我會帶你走一遍從TCP三次握手開始到最終打開一個遠(yuǎn)程Shell的完整旅程。你會看到加密是如何層層加碼的認(rèn)證是如何步步為營的以及那些常見的連接錯誤在數(shù)據(jù)包層面究竟長什么樣。無論你是運(yùn)維工程師、開發(fā)人員還是網(wǎng)絡(luò)安全愛好者這次深入的抓包分析都將讓你對SSH的理解提升一個維度。2. 實(shí)驗(yàn)環(huán)境搭建與Wireshark抓包準(zhǔn)備在開始解剖SSH協(xié)議之前我們得先準(zhǔn)備好手術(shù)臺和顯微鏡。一個可控的實(shí)驗(yàn)環(huán)境是成功抓包分析的前提它能避免公網(wǎng)復(fù)雜環(huán)境的干擾讓我們專注于協(xié)議本身。2.1 構(gòu)建本地SSH實(shí)驗(yàn)環(huán)境最干凈、最理想的實(shí)驗(yàn)環(huán)境是在本地用虛擬機(jī)搭建。我推薦使用VirtualBox或VMware創(chuàng)建兩臺Linux虛擬機(jī)如Ubuntu Server一臺作為客戶端一臺作為服務(wù)器。將它們的網(wǎng)絡(luò)模式設(shè)置為“僅主機(jī)Host-Only”網(wǎng)絡(luò)這樣所有流量都只在你的物理主機(jī)內(nèi)部循環(huán)不會被路由到外部網(wǎng)絡(luò)也方便Wireshark在物理主機(jī)上抓取到所有流量。在服務(wù)器虛擬機(jī)上我們需要確保SSH服務(wù)正在運(yùn)行。通常OpenSSH server默認(rèn)可能沒有安裝。你可以通過以下命令來安裝和啟動它sudo apt update sudo apt install openssh-server -y sudo systemctl enable ssh sudo systemctl start ssh安裝完成后使用sudo systemctl status ssh命令檢查服務(wù)狀態(tài)確認(rèn)其處于“active (running)”狀態(tài)。默認(rèn)情況下SSH服務(wù)監(jiān)聽在22號端口。在客戶端虛擬機(jī)上只需要安裝SSH客戶端即可通常它已經(jīng)包含在openssh-client包中。你可以通過ssh -V命令來檢查客戶端版本。2.2 Wireshark配置與抓包過濾器技巧接下來是關(guān)鍵的抓包工具——Wireshark。請務(wù)必從官網(wǎng)下載安裝以保證功能的完整性。安裝后啟動Wireshark你會看到一系列網(wǎng)絡(luò)接口列表。在我們的“僅主機(jī)網(wǎng)絡(luò)”環(huán)境下你需要選擇對應(yīng)VirtualBox或VMware創(chuàng)建的虛擬網(wǎng)卡名稱可能類似“VirtualBox Host-Only Ethernet Adapter”。直接開始抓包會捕獲到海量的無關(guān)數(shù)據(jù)包比如ARP廣播、DHCP請求等。為了精準(zhǔn)捕獲SSH流量我們必須使用捕獲過濾器。在開始抓包前在捕獲過濾器的輸入框中填入tcp port 22。這個過濾器告訴Wireshark“只抓取源端口或目標(biāo)端口是22的TCP數(shù)據(jù)包。”因?yàn)镾SH默認(rèn)使用22端口這樣能極大減少噪音。注意這里用的是“捕獲過濾器”它在抓包時生效直接丟棄不匹配的數(shù)據(jù)包可以節(jié)省系統(tǒng)資源。而“顯示過濾器”是在抓包后用來篩選查看的兩者語法相似但作用階段不同不要混淆。點(diǎn)擊開始抓包后窗口可能暫時一片空白。這時從你的客戶端虛擬機(jī)執(zhí)行一個簡單的連接測試命令ssh 服務(wù)器IP地址。如果這是首次連接會提示你確認(rèn)服務(wù)器指紋輸入yes后會提示你輸入密碼。我們先輸入錯誤的密碼讓認(rèn)證失敗然后關(guān)閉連接。這個簡單的操作會觸發(fā)SSH協(xié)議從連接到失敗退出的完整流程非常適合我們分析。2.3 首次連接的關(guān)鍵數(shù)據(jù)包保存在客戶端完成一次失敗的連接嘗試后回到Wireshark點(diǎn)擊停止抓包。你應(yīng)該能看到一系列數(shù)據(jù)包。立即將抓包結(jié)果保存為一個文件例如ssh_analysis.pcapng。這是一個好習(xí)慣因?yàn)閃ireshark的默認(rèn)內(nèi)存緩沖區(qū)可能有限保存文件可以確保我們后續(xù)能從容地、反復(fù)地分析這些數(shù)據(jù)?,F(xiàn)在我們有了“手術(shù)樣本”。在開始分析前我建議在Wireshark的顯示過濾器欄輸入ssh這樣會只顯示SSH協(xié)議的數(shù)據(jù)包界面會更加清晰。準(zhǔn)備工作就緒讓我們正式進(jìn)入SSH協(xié)議的核心流程。3. 逐層拆解一次SSH連接的完整報文對話現(xiàn)在我們面對Wireshark窗口中按時間順序排列的數(shù)據(jù)包就像拿到了一部電影的原始膠片。我們的任務(wù)是把它們按場景剪輯理解每一段對話的意義。一個完整的SSH連接大致可以分為四個階段TCP連接建立、SSH協(xié)議版本協(xié)商、密鑰交換與算法協(xié)商、用戶認(rèn)證。讓我們跟隨數(shù)據(jù)包的腳步一步步拆解。3.1 基石TCP三次握手與連接建立任何基于TCP的應(yīng)用層協(xié)議都始于一次經(jīng)典的三次握手。SSH也不例外。在你的抓包文件中找到最開始的三個數(shù)據(jù)包它們通常標(biāo)記為[SYN],[SYN, ACK],[ACK]。數(shù)據(jù)包1客戶端 - 服務(wù)器客戶端發(fā)送一個TCP報文其標(biāo)志位SYNSynchronize Sequence Numbers被置為1序列號Seq為一個隨機(jī)數(shù)比如0。這好比客戶端對服務(wù)器說“嗨我想和你建立連接我的初始序列號是X?!睌?shù)據(jù)包2服務(wù)器 - 客戶端服務(wù)器回應(yīng)一個報文標(biāo)志位SYN和ACK同時置1。它確認(rèn)ACK了客戶端的序列號Ack 客戶端的Seq1并發(fā)出自己的初始序列號Seq為另一個隨機(jī)數(shù)。這相當(dāng)于服務(wù)器回答“收到你的請求了ACK我同意連接我的初始序列號是Y。”數(shù)據(jù)包3客戶端 - 服務(wù)器客戶端再發(fā)送一個ACK報文確認(rèn)服務(wù)器的序列號Ack 服務(wù)器的Seq1。至此雙向通信通道建立完成。客戶端說“好的收到你的同意了我們可以開始通話了?!边@個階段在Wireshark的Info列會顯示為“TCP 3-Way Handshake”。如果這一步失敗可能是網(wǎng)絡(luò)不通、防火墻攔截了22端口或者服務(wù)器SSH服務(wù)未啟動。在分析SSH問題時首先確認(rèn)TCP握手是否成功是排除網(wǎng)絡(luò)層故障的第一步。3.2 握手伊始SSH協(xié)議版本協(xié)商TCP連接建立后應(yīng)用層的SSH對話正式開始。緊接著三次握手你應(yīng)該會看到客戶端發(fā)出第一個實(shí)際攜帶SSH協(xié)議內(nèi)容的數(shù)據(jù)包。數(shù)據(jù)包4客戶端 - 服務(wù)器客戶端向服務(wù)器發(fā)送一個明文報文。在Wireshark中展開這個數(shù)據(jù)包的“Secure Shell Layer”你會看到類似這樣的內(nèi)容SSH Version: SSH-2.0-OpenSSH_8.9p1這是一個明文字符串宣告客戶端支持的SSH協(xié)議最高版本是2.0并且客戶端軟件是OpenSSH 8.9p1。SSH協(xié)議版本協(xié)商非常簡單粗暴雙方都發(fā)出自己支持的版本號如果兼容通常都支持2.0則使用兩者中較低的版本實(shí)際上現(xiàn)在基本都固定用2.0。早期的SSH-1.0協(xié)議存在設(shè)計(jì)缺陷現(xiàn)已基本廢棄。數(shù)據(jù)包5服務(wù)器 - 客戶端服務(wù)器回應(yīng)自己的版本信息例如SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.6。這表示服務(wù)器也支持SSH-2.0。這個交換是明文的沒有加密。因此在Wireshark里我們可以直接看到。版本協(xié)商成功后雙方才會進(jìn)入下一個更復(fù)雜的階段。3.3 核心機(jī)密密鑰交換與算法協(xié)商這是SSH協(xié)議最精妙、最核心的部分目的是在一個不安全的網(wǎng)絡(luò)環(huán)境中安全地協(xié)商出一個后續(xù)用于加密通信的“會話密鑰”。這個過程利用了Diffie-Hellman密鑰交換算法。算法列表交換在版本協(xié)商后客戶端和服務(wù)器會互相發(fā)送一個“密鑰交換初始化”報文SSH_MSG_KEXINIT。在Wireshark中這些報文內(nèi)容看起來是一長串用逗號分隔的算法名稱。它們各自列出了自己支持的密鑰交換算法如curve25519-sha256,ecdh-sha2-nistp256,diffie-hellman-group14-sha1等。用于生成共享秘密。服務(wù)器主機(jī)密鑰算法如ssh-ed25519,ecdsa-sha2-nistp256,rsa-sha2-256等。用于服務(wù)器身份認(rèn)證。加密算法如chacha20-poly1305openssh.com,aes128-gcm,aes256-cbc等。用于加密后續(xù)傳輸?shù)臄?shù)據(jù)。消息認(rèn)證碼算法如umac-64-etmopenssh.com,hmac-sha2-256等。用于驗(yàn)證數(shù)據(jù)完整性。壓縮算法通常是none表示不壓縮。雙方會從對方的列表中選擇自己列表中也存在的、且優(yōu)先級最高的算法。例如客戶端列表是A, B, C服務(wù)器列表是C, B, D那么雙方最終會選擇B因?yàn)锳不在服務(wù)器列表C的優(yōu)先級在客戶端可能低于B。Diffie-Hellman密鑰交換算法選定后假設(shè)是diffie-hellman-group14-sha1雙方開始執(zhí)行DH交換。服務(wù)器會發(fā)送一個包含大素數(shù)p、生成元g、以及服務(wù)器公鑰e的報文??蛻舳耸盏胶笊勺约旱墓€f發(fā)送給服務(wù)器。 這個過程的精妙之處在于雙方利用對方的公鑰和自己的私鑰可以獨(dú)立計(jì)算出一個相同的“共享秘密”Shared Secret。而竊聽者即使截獲了網(wǎng)絡(luò)上傳輸?shù)膒,g,e,f在有限時間內(nèi)也無法計(jì)算出這個共享秘密基于離散對數(shù)難題。生成會話密鑰與服務(wù)器認(rèn)證利用這個“共享秘密”以及交換過程中所有報文的哈希值雙方可以派生出一組對稱密鑰包括初始加密密鑰IV、數(shù)據(jù)加密密鑰、完整性驗(yàn)證密鑰等。同時服務(wù)器會用自己的主機(jī)私鑰對本次交換過程中所有關(guān)鍵數(shù)據(jù)進(jìn)行簽名并將簽名和它的主機(jī)公鑰一起發(fā)送給客戶端。這是關(guān)鍵一步客戶端此時已經(jīng)有了服務(wù)器的公鑰可能是第一次見。它會用這個公鑰去驗(yàn)證簽名。如果驗(yàn)證通過就證明了兩個事實(shí)第一與我通信的對方確實(shí)擁有與這個公鑰配對的私鑰第二剛才的密鑰交換過程沒有被篡改。至此客戶端完成了對服務(wù)器身份的驗(yàn)證。這也是為什么第一次連接時客戶端會提示你“無法確認(rèn)主機(jī)真實(shí)性”并顯示一個公鑰指紋通常是公鑰的MD5或SHA256哈希值讓你人工核對。你確認(rèn)了這個公鑰就被保存在客戶端的~/.ssh/known_hosts文件里下次連接就不會再警告了。這個階段結(jié)束后后續(xù)所有的通信都將使用剛剛協(xié)商出的對稱密鑰進(jìn)行加密。你在Wireshark里會看到之后的SSH協(xié)議數(shù)據(jù)包的“Encrypted packet”部分變成了亂碼無法直接解讀。3.4 最后關(guān)卡用戶認(rèn)證階段服務(wù)器身份驗(yàn)證通過后接下來就是客戶端向服務(wù)器證明“我是誰”。SSH支持多種認(rèn)證方式最常見的是密碼認(rèn)證和公鑰認(rèn)證。密碼認(rèn)證流程客戶端發(fā)送一個認(rèn)證請求SSH_MSG_USERAUTH_REQUEST聲明想使用password認(rèn)證方式并帶上用戶名。服務(wù)器回復(fù)一個認(rèn)證挑戰(zhàn)可能直接接受或要求進(jìn)行PAM交互等。在我們的簡單場景中服務(wù)器通常會直接進(jìn)入下一步??蛻舳嗽俅伟l(fā)送請求這次包含了加密后的密碼。注意密碼是在已經(jīng)加密的隧道中傳輸?shù)乃訵ireshark看到的是加密后的數(shù)據(jù)非常安全。服務(wù)器驗(yàn)證密碼。如果正確回復(fù)認(rèn)證成功SSH_MSG_USERAUTH_SUCCESS如果錯誤回復(fù)認(rèn)證失敗SSH_MSG_USERAUTH_FAILURE并可能告知還允許哪些認(rèn)證方式。公鑰認(rèn)證流程免密登錄客戶端發(fā)送認(rèn)證請求聲明使用publickey方式并附帶用于認(rèn)證的公鑰。服務(wù)器檢查該公鑰是否存在于相應(yīng)用戶的~/.ssh/authorized_keys文件中。如果存在服務(wù)器生成一個隨機(jī)挑戰(zhàn)challenge。服務(wù)器將這個挑戰(zhàn)用客戶端提供的公鑰加密后發(fā)送給客戶端。客戶端用自己的私鑰解密這個挑戰(zhàn)然后對挑戰(zhàn)進(jìn)行某種運(yùn)算如簽名將結(jié)果發(fā)回服務(wù)器。服務(wù)器用存儲的公鑰驗(yàn)證這個簽名。驗(yàn)證通過則認(rèn)證成功。公鑰認(rèn)證的安全性更高因?yàn)樗恍枰诰W(wǎng)絡(luò)上傳送密碼即使是加密的并且可以抵抗暴力破解。在Wireshark中你只能看到認(rèn)證方式的聲明和加密后的挑戰(zhàn)/響應(yīng)數(shù)據(jù)流無法看到私鑰或密碼的任何信息。4. 從理論到實(shí)戰(zhàn)Wireshark深度排查常見SSH問題掌握了正常流程Wireshark就從一個觀察工具變成了強(qiáng)大的排錯利器。很多棘手的SSH連接問題在數(shù)據(jù)包層面都會留下清晰的蛛絲馬跡。我們來看幾個典型場景。4.1 案例診斷連接超時與握手失敗癥狀客戶端執(zhí)行ssh userhost后長時間掛起最終報錯“Connection timed out”。排查思路檢查TCP握手在Wireshark中過濾tcp.port 22。觀察是否有客戶端發(fā)出的[SYN]包。無[SYN]包可能是客戶端防火墻阻止了出站連接或者DNS解析失敗你用了主機(jī)名而非IP。檢查客戶端防火墻規(guī)則和/etc/hosts文件。有[SYN]包但無回應(yīng)服務(wù)器沒有返回[SYN, ACK]。這強(qiáng)烈指向網(wǎng)絡(luò)路由問題或服務(wù)器端防火墻如iptables, firewalld丟棄了22端口的入站請求。你可以在服務(wù)器上使用sudo iptables -L -n或sudo firewall-cmd --list-all來檢查規(guī)則。有完整的TCP三次握手那么問題出在TCP之上。繼續(xù)看后續(xù)是否有SSH版本協(xié)商包。檢查SSH版本協(xié)商如果TCP握手成功但緊接著沒有SSH版本字符串的交換連接就斷了。可能的原因包括服務(wù)器SSH服務(wù)未運(yùn)行在服務(wù)器上執(zhí)行sudo systemctl status sshd確認(rèn)。服務(wù)器監(jiān)聽地址SSH服務(wù)可能只綁定在127.0.0.1本地回環(huán)而不是0.0.0.0所有接口。檢查/etc/ssh/sshd_config中的ListenAddress配置。中間設(shè)備干擾有些網(wǎng)絡(luò)設(shè)備如某些防火墻、入侵檢測系統(tǒng)可能會異常斷開空閑的TCP連接或者錯誤地處理了SSH協(xié)議的初始報文。4.2 案例診斷認(rèn)證反復(fù)失敗與算法不匹配癥狀連接能建立但總是在輸入密碼或使用密鑰后認(rèn)證失敗日志提示“Permission denied”或“Authentication failed”。排查思路觀察認(rèn)證階段報文在Wireshark中跟隨TCP流右鍵數(shù)據(jù)包 - Follow - TCP Stream可以更清晰地看到文本交互對于版本協(xié)商等明文部分。關(guān)注服務(wù)器返回的SSH_MSG_USERAUTH_FAILURE報文。它里面會包含一個partial success標(biāo)志和auth that can continue字段。如果auth that can continue字段包含publickey說明服務(wù)器期望公鑰認(rèn)證但你可能未提供或提供了錯誤的密鑰。檢查客戶端的-i參數(shù)或~/.ssh/id_rsa等密鑰文件。如果包含password說明密碼認(rèn)證可用但你的密碼錯了。注意服務(wù)器可能配置了禁止密碼登錄PasswordAuthentication no此時這個字段就不會有password。深挖算法協(xié)商問題這是一個更隱蔽的坑。有時客戶端和服務(wù)器支持的算法列表沒有交集導(dǎo)致密鑰交換失敗。雖然連接會早期斷開但錯誤信息可能很模糊。在Wireshark中對比仔細(xì)查看客戶端和服務(wù)器發(fā)出的SSH_MSG_KEXINIT數(shù)據(jù)包。展開列表對比雙方的“密鑰交換算法”、“加密算法”等。例如舊的客戶端可能只支持diffie-hellman-group1-sha1而現(xiàn)代的服務(wù)器出于安全考慮已禁用此算法只支持group14或curve25519。這就導(dǎo)致了協(xié)商失敗。解決方案升級客戶端/服務(wù)器的OpenSSH版本或者在配置文件中顯式指定雙方都支持的算法。例如在客戶端的~/.ssh/config或服務(wù)器的/etc/ssh/sshd_config中可以使用KexAlgorithms,Ciphers,MACs等指令進(jìn)行配置。4.3 高級技巧解密SSH加密流量與跟蹤應(yīng)用數(shù)據(jù)默認(rèn)情況下Wireshark無法解密SSH流量因?yàn)闀捗荑€是在內(nèi)存中動態(tài)生成的。但是對于調(diào)試和深度安全分析OpenSSH提供了一種將密鑰材料導(dǎo)出供Wireshark使用的機(jī)制。步驟設(shè)置環(huán)境變量在啟動SSH客戶端時設(shè)置一個特殊的環(huán)境變量指示OpenSSH將會話密鑰寫入一個文件。SSH_DEBUG1 SSH_AUTH_SOCK ssh -o SetEnv SSH_DEBUG1 -o SetEnv SSH_DEBUG_WIRESHARK1 userhost更通用的方法是在客戶端機(jī)器的~/.ssh/config文件中為特定主機(jī)配置Host debug_host HostName your_server_ip User your_username SetEnv SSH_DEBUG_WIRESHARK1然后使用ssh debug_host連接。連接成功后在當(dāng)前目錄會生成一個名為ssh-XXXXXX.log的文件XXXXXX是隨機(jī)字符。在Wireshark中加載密鑰打開Wireshark進(jìn)入編輯 - 首選項(xiàng) - 協(xié)議 - SSH。在“RSA keys list”或“Decryption keys”區(qū)域點(diǎn)擊“瀏覽”選擇剛才生成的.log文件。Wireshark會自動識別其中的密鑰。重新加載抓包文件加載密鑰后關(guān)閉再重新打開你的ssh_analysis.pcapng文件或者如果你正在實(shí)時抓包后續(xù)的SSH數(shù)據(jù)包就會被自動解密。此時原本顯示為“Encrypted packet”的數(shù)據(jù)現(xiàn)在可以展開看到內(nèi)部的SSH_MSG_CHANNEL_DATA等內(nèi)容甚至能看到你輸入的每一個命令和服務(wù)器返回的每一個字符。重要警告此方法導(dǎo)出的密鑰文件是高度敏感的它允許任何人解密此次會話的所有通信。務(wù)必僅在絕對安全的調(diào)試環(huán)境中使用并在調(diào)試結(jié)束后立即徹底刪除該密鑰文件。通過這個技巧你就能真正“看到”加密隧道內(nèi)的所有活動對于理解SSH通道、端口轉(zhuǎn)發(fā)、SFTP等高級功能的數(shù)據(jù)流非常有幫助。當(dāng)然這也從另一個角度證明了SSH協(xié)議的安全性——在不知道這個特定會話的密鑰文件的情況下即使截獲了所有流量也無法解密其內(nèi)容。