前言
自騰訊與京東建立了戰略合作關系之后,筆者網上購物就首選京東了。某天在家里訪問京東首頁的時候突然吃驚地發現瀏覽器突然跳到了第三方網站再回到京東,心里第一個反應就是中木馬了。
竟然有這樣的事,一定要把木馬大卸八塊。
原因排查
首先在重現的情況下抓包,京東官網確實返回了一段JavaScript讓瀏覽器跳轉到了yiqifa.com。
下圖是應用層的抓包。

服務器返回的代碼導致跳轉,基本可以排除本地木馬,推測是網絡或者服務器的問題。根據筆者的經驗,這種情況很大可能是鏈路上的流量劫持攻擊。當然也不能排除京東服務器被黑的情況。
繼續排查。應用層已經不行了,我們要用Wireshark抓網絡層的包。

從Wireshark結果可以看到,網絡上出現了兩個京東的HTTP響應。第一個先到,所以瀏覽器執行里面的JavaScript代碼轉到了yiqifa.com;第二個HTTP響應由于晚到,被系統忽略(Wireshark識別為out-of-order)。
兩個京東的HTTP響應包,必然一真一假。快揭示真相了。
再來看看兩個HTTP響應的IP頭。
第一個包TTL值是252,第二個包TTL值是56,而之前TCP三次握手時京東服務器的TTL值是56,故可以判斷先到的包是偽造的,真的包晚到而被系統忽略。

至此,確認是鏈路上的劫持。
攻擊方式
繼續分析偽造的數據包。
偽造包的TTL值是252,也就是說它的原始TTL值應該是255(大于252的系統默認TTL值只能是255了,一般不會修改),也就表明攻擊者的設備離我隔了3個路由;而正常的京東網站的HTTP響應TTL值是56,隔了8個路由。物理上假的設備離我近,所以偽造的HTTP響應會先到——比較有意思的是,筆者實際監測時候發現也有偽造包晚到導致劫持失敗的情況。
推測是一個旁路設備偵聽所有的數據包,發現請求京東首頁的HTTP請求就立即返回一個定制好的HTTP響應。大致的攻擊示意圖如下。

當時筆者推測攻擊者在鏈路上大動干戈應該不會只針對一個網站,于是就訪問了下易迅、淘寶、天貓這些電商網站,結果發現易迅也受到同樣的攻擊。看起來這次流量劫持的目的是將電商網站流量導給返利聯盟,通過返利聯盟獲得當前用戶成交金額的返利。
基本確認運營商有問題,但是無法確認是運營商官方故意的還是遭到黑客攻擊或者是內部人士偷偷搞的。
攻擊源定位
來看看當時的路由結果:

如果按初始TTL值為255來算,HTTP包到達本機后為252,推算出經過了3(255-252)個路由,出問題的地方就在第4個路由附近,也就是這里的119.145.220.86(屬于深圳電信)。
當然了,雖然基本可以確認是第四個路由附近的問題(筆者連續幾天抓包,偽造的HTTP響應包TTL值一直是252),但是不排除設備故意構造一個初始TTL值(比如設置為254)來增加追查難度,為了嚴謹的治學態度及避免被攻擊者迷惑,所以證據要坐實了。
定位比較簡單,既然攻擊設備是旁路偵聽數據包,可以推測它是基于包而非狀態的,我們構造被偵聽的數據包(也就是直接發出訪問京東首頁的HTTP請求TCP包,不需要三次握手)多次發送,TTL值從1開始遞增,精確地傳遞數據包到每一個路徑上,直到出現偽造響應——沒有問題的位置是不會有響應的,第一個出現偽造響應的位置就是出問題的位置。
這個時候就需要一個數據包構造工具了,基于Python的Scapy或者Windows下的XCAP都行。
于是一路發過去,TTL值等于4的時候偽造的響應包出現了——確認就是第四跳路由出問題了,同時119.145.55.14回復了Time-to-live Exceeded的ICMP包。
有了充分證據,于是整理了一個圖文并茂的文檔通過騰訊安全應急響應中心向深圳電信報障。
一天后得到運營商答復:“經核查,深圳本地沒有進行推送,經網上查詢有木馬或病毒會導致此現象,非電信網內問題,請進行殺毒后再測試,謝謝”。
不過從當天晚上起,我再在ADSL環境測試,就沒有發現這種流量劫持現象了。
攻防之道
鏈路劫持對企業和用戶都是很麻煩的,影響用戶體驗,還泄漏敏感信息,而且還是分地域的,檢測和防御起來也相對困難。
鏈路劫持已經被某些人運用的爐火純青。比如近期業界發現部分區域的百度聯盟廣告腳本被植入惡意JavaScript去DDoS攻擊GitHub。
騰訊歷史上也遇到過多起鏈路劫持攻擊,目的性很強,大部分是插廣告(少部分是釣魚和掛馬),攻擊手法各種各樣,有運營商的區域DNS劫持和鏈路劫持、運營商區域DNS Server遭到緩存投毒攻擊(利用CVE-2007-2926,非常經典)、開發商在路由軟件中植入劫持代碼、CDN與源通信遭到ARP攻擊、用戶PC本地木馬。當然,這些目前都已經解決了,也在持續監測中。
為了對抗鏈路劫持,很多騰訊業務也都使用了HTTPS或者私有協議,比如QQ Web登錄、QQ郵箱、理財通、Web微信、微信公眾平臺等。
DNS劫持攻擊相對容易檢測和防護。
檢測方面,用分布的點去進行DNS查詢即可,發現運營商DNS結果不對就可以推動修復。
防護方面,一種方案是使用DNSSEC(DNS Security Extensions);騰訊、114DNS還研發了自己的方案——HttpDNS。HttpDNS不使用DNS協議而是通過HTTP協議從HttpDNS后端服務器獲取域名對應的IP。當然,類似的思路我們可以實現一堆了:HTTPSDNS、TCPDNS、UDPDNS、ICMPDNS……

鏈路劫持相對復雜。
檢測方面,如有客戶端,可以依靠客戶端進行檢測;如果沒有客戶端,就具體情況具體分析了,可以在網頁里用JavaScript檢測頁面元素,甚至可以在全國重要城市租用ADSL探測。
另外,在機房的流量監控設備里會發現異常:比如這個案例就會出現用戶接收了HTTP響應后沒有回應,然后URL中又帶了yiqifa.com的關鍵字重新訪問主頁的情況;再比如某些設備的HTTP阻斷會向服務器發特定的RST包(我見過發IP Id為8888的案例)。
防護方面,這個案例只是偽造數據包,并沒有實施阻斷,所以只要客戶端的安全軟件把疑似出問題的包(一次TCP會話中TTL值相差很大或者IPId突然跳變)攔截就可以防御。為了避免誤殺,可以攔截并休眠1秒,如果沒有同樣的數據包過來再放行。
有自己客戶端的可以走自己的私有協議,網站類就困難一些,部署HTTPS吧。百度主頁近期就使用了HTTPS,不過大部分用戶還是不習慣在瀏覽器里輸“https://”,所以還是存在被劫持的風險(類似的工具有SSLStrip)。當然了,對抗也會隨之升級的,比如這次發現的GMail證書偽造事件。
在HTTPS尚不能大規模普及的情況下,是否可以給用戶或者終端軟件提供一個規避鏈路劫持的安全服務呢?似乎是可以的。下圖是筆者構想的一個簡單的通過本地代理軟件加云服務的方式規避不安全ADSL鏈路的解決方案。

一些瀏覽器的云加速也客觀上實現了這個功能。對于安全性不確定的公共WiFi,也可以用類似的方法來規避風險。
后記
希望本文對你有幫助。