作者:【騰訊安全平臺部】 lake2
公眾號:騰訊安全應急響應中心

前言

兩年興起的大型網絡攻防對抗比賽以實戰的方式進行,這個舉措非常好,以攻促防(“talk is cheap,show me the shell”),參賽大企業會更加關注實際的安全威脅并且想辦法緩解,客觀上也繁榮了安全行業,一時間相關的安全服務及安全產品暢銷,特別是有實時檢測和阻斷能力的IDS/IPS大放異彩。

于是,大企業紛紛采購部署IDS、IPS、WAF這些安全防護產品,壓縮了攻擊面,那就帶來兩個問題:

  1. 滲透測試這個方向還有沒有機會?也有滲透測試人員發的知乎熱帖[1]對未來提出困惑;

  2. 部署了IDS/IPS設備,在設備后端被防護著的系統的安全漏洞是否還要修復?不要急著回答,且看后文。

(以下字數約4000字,閱讀時長約10分鐘)

一. IDS/IPS防護原理及繞過思路

IDS工作在網絡層,旁路部署,通過抓取和分析網絡流量來發現攻擊;

IPS一般也是在網絡層旁路,可以理解為具備阻斷能力的IDS,是IDS的升級版(也有IDS檢測到攻擊通知阻斷設備執行阻斷動作的設備聯動模式),可以覆蓋網絡層和應用層;

WAF是在應用層防護Web攻擊的程序,一般是跟Web接入層對接,可旁路可串行,僅能覆蓋應用層,詳細的技術原理和實踐可參考TSRC博客的這篇文章[2]。

本文為闡述方便,統一把網絡層的旁路防護設備視為IPS。

安全專家們關于應用層WAF的繞過探討已經很多了[3],TSRC博客近期也會推出推出一篇WAF繞過的文章,所以本文就不落窠臼,我們下沉到網絡層來玩玩。

現在看來,IPS的旁路防護原理很簡單,其經典代表如開源的Snort,就是在網絡上分析流量,發現符合規則的流量則冒充服務端回包響應客戶端實現阻斷或者替換的目的,這是一種典型的鏈路劫持手法。常見的場景是封禁網站(如非法網站的封禁)、篡改網頁內容(運營商插廣告)、阻斷端口掃描和漏洞攻擊(IPS),實施鏈路劫持的人必須控制某段網絡。

用舊作《某電商網站流量劫持案例分析與思考》[4]里面的一幅圖來示意,攻擊者嗅探到符合特征的流量后即偽造響應,這里是偽造了HTTP響應(為了篡改頁面),如果只是阻斷的話就是偽造rst包干擾TCP握手過程或者連接。

為什么IPS多是旁路很少串行?超大流量下的串行處理對設備的性能是巨大的挑戰,你可以嘗試下,相信你會回來同意我的意見的。

因為IPS是旁路部署,所以只能通過發偽造包的方式來達到干擾雙方正常通信的目的,正常的包其實還是會到達客戶端和服務端,只不過相同序號的包操作系統已經處理過了,這些包會被認為是錯誤的包從而丟掉。

所以,從原理分析,繞過IPS可以從兩個方向著手:

  1. 檢測上,如果IPS在流量里檢測不到攻擊特征,則不會有后續動作;

  2. 阻斷上,正常包也會到達服務器,只是來晚了,如果有辦法讓偽造的包失效,則阻斷不會發生。

二. IPS繞過實例

常見的IPS阻斷場景有四種:

  1. 可以建立TCP連接,檢查客戶端發出的HTTP請求中的特征,如匹配則發rst阻斷或HTTP響應替換,用于域名封禁或Web攻擊防護;

  2. 不讓建立TCP連接,即客戶端發syn包時IPS直接回rst,同時后續如有ack包會雙向回rst阻斷,用于訪問控制或端口封禁;

  3. DNS查詢場景,偽造DNS響應,劫持網站域名用于封禁或者釣魚攻擊;

  4. UDP傳輸場景下,偽造ICMP響應,告知客戶端UDP端口不可達。

對于1,可以從兩方面入手:在應用層,一般利用IPS和Web Server對HTTP語法的理解差異;在網絡層,一般利用IPS和操作系統協議棧對TCP/IP的處理方式差異,后文會討論;

對于2,暴露面比較窄,繞過會困難一點,但也不是不可能;

對于3,換個DNS Server就行了,業界對DNS劫持也有很好的方案,這里不再贅述;

對于4,是阻斷UDP訪問,分析見后文。

下面按技術手法介紹一些常見的網絡層繞過手法,均實測過:

1、TCP分片

一些IPS是字節級逐包檢查的,并沒有實現TCP分片重組能力,那就把關鍵字拆到兩個TCP包里面就可以暗度陳倉。以下是Perl實現的TCP分片HTTP請求,關鍵字是“www.bad.com”,會拆分到兩個TCP包發出。

use IO::Socket;

$sock = new IO::Socket::INET (PeerAddr =>  '118.x.x.x',

                              PeerPort =>  'http(80)');

die "Couldn't create socket: $@" unless  $sock;

$sock->autoflush(1);

# ==========   case1  TCP frag bypass 

$sock->print("GET / HTTP/1.1\r\nHost: www.b");

sleep(4);

$sock->print("ad.com\r\n\r\n");

$document = join('', $sock->getlines());

print "\n$document\n";

看圖,TCP分片繞過,返回了200(如果不實施TCP分片,會返回302)。

慢!如果IPS實現了TCP分片重組怎么辦?

這個問題問得好,仔細看代碼,里面有個sleep,它并非是湊數的:有的IPS雖然有TCP分片重組能力,但是不會無限等待,會有個時間,超過這個時間就不會再檢查了,所以設置這個sleep的時間超過IPS的分片重組超時值而又沒有達到操作系統和Web Server的超時值,那就可以繞過。

2、IP分片

IP包也是支持分片的,原理類似,只是要構造IP包就需要用到Python下的組件Scapy,TCP三次握手后用Scapy的fragment函數按600字節一個拆分發送IP分片包(當然也可以把syn包也分片),代碼如下:

看看效果:

IP分片重組超時繞過的原理與TCP一樣,不多說。需要注意的是,TCP分片更通用,IP分片受到鏈路上網絡設備的影響,有可能中途會被網關重組或者丟棄,達不到預期效果。

大名鼎鼎的掃描器nmap有一個規避FW/IDS的功能就是利用IP分片進行端口掃描,參數是-f,可以用--mtu設置分片大小,最小的值是8,但是實測有些路由會丟棄MTU比較小的IP包。

3、程序bug / 性能問題

程序總是有bug的,特別是這種流量處理程序,會瞬間并發處理非常多的數據包,遇到各種特殊情況,稍微不注意就會產生異常。為了保障業務連續性,防護設備一定會在發生異常時保證業務連續性,所以制造異常包讓IPS響應不過來也是可以實現繞過的目的。以前我們的DDoS防護系統宙斯盾處理流量的時候,稍微考慮不周程序就core掉了,別說了,說多了都是淚。

測試某個IPS時,建立TCP連接后發送大量序號錯誤的ack包,然后再發送正確的包,結果IPS出現bug回了序號不對的rst包,產生了繞過。

還可以發送大量的無效包,消耗IPS性能,一旦IPS慢下來,他的包就會晚于正常包到達,也產生繞過的機會。

這種異常可以通過協議fuzz來發現[5],Scapy也是一個好的協議fuzz生成工具,可以一試。

另外,鏈路上很多網絡設備,各自處理TCP/IP協議的實現不一樣,也可能帶來繞過或者其他問題。比如現在操作系統判斷rst包會精確到序號,連在滑動窗口都不行,但是一些NAT設備仍然存在無視序號的rstblood問題。

4、偽造TCP狀態

在測試一個IPS的時候發現這是一個久經考驗的系統,前述各種方法繞過都失敗了,應用層各種繞也不行,居然連bug也fuzz不到,而且它還不是包過濾的,而是基于狀態跟蹤的 —— 簡單測試檢測模式,不建立TCP連接直接發HTTP請求,如果還有響應的IPS就是包過濾,反之則是狀態跟蹤。

結果成也蕭何敗也蕭何,它的破綻恰恰在狀態跟蹤上:

建立TCP連接后,我們可以發送一個定制TTL值的rst包,這個TTL值正好能夠經過IPS但不會到達服務端,IPS基于狀態跟蹤會認為這個TCP連接已斷開,后續的各種包都不會去檢測,但服務端不受影響會繼續等待ack包來。

經過測試這個當前環境里大概TTL設置為12左右rst包會路過IPS卻不會到達服務端,所以我們的關鍵代碼這樣寫:

完美繞過:

這個構造TTL值繞過的問題(我稱之為“fake-TTL”攻擊)可能是一些帶狀態跟蹤的網絡設備的通用問題。

5、阻止三次握手的缺陷

對于直接阻止TCP三次握手的情況,我們詳細來看看。

客戶端發起syn包,IPS冒充服務端給客戶端回rst,假裝端口關閉,但是實際上端口開放的話服務端的synack包是能到達客戶端的,只是同序號rst先到,后到的synack被操作系統丟棄。簡單,客戶端丟掉偽造的rst包,接受synack包,然后向服務端發ack包建立三次握手,這時候IPS會雙向回rst(如果你家IPS沒動作,我建議你考慮換一個牌子的IPS……)。

注意,你的ack包一定比IPS的rst先到服務端并被應用程序執行 —— 我們可以在這個ack包把所有的內容都發了,是一次性盲打,適用于一定場景的漏洞探測和利用。

如果想完美繞過,就得想辦法讓第二個rst失效;想完美防護,就得讓第一個rst生效。仔細研讀TCP/IP,具體情況具體分析了,或者試著fuzz一下。

6、IPv6

隨著IPv6的普及,會有越來越多的設備支持IPv6(過渡時期是IPv4/6雙棧),但是正在服役的IDS/IPS/WAF不一定支持,于是可以暢行無阻。

瀏覽器支持這樣的方式直接訪問IPv6地址:https://[IPv6地址]/xxxx

現在的Windows操作系統都默認支持IPv6,但Windows防火墻的規則可能還是只配了IPv4,使用IPv6地址就如入無人之境。以下演示機器的防火墻限制了IPv4的全部端口的訪問,用IPv6地址可以連通所有端口,登錄遠程桌面看看:

舉一反三,大家得檢查一下各種安全系統是否開啟了對IPv6的支持。

7、加密協議

IPS一般是不能解SSL流量的,所以也檢測不到SSL加密的流量,所以嘗試通過HTTPS訪問是繞過檢查的一種方法 —— 這個場景下,基于應用層的WAF的優勢就展現出來了。同理,HTTP/2、QUIC、WebSocket等新一代Web瀏覽協議也能規避IPS。

既然這些協議可以規避IPS,那就是可以通過服務端支持這些協議來防御鏈路劫持,既保護了通信過程不被篡改,又避免了黑客在網絡中竊取用戶敏感信息[5]。最佳實踐就是部署HTTPS來防止鏈路劫持,雖說繼續劫持HTTPS并非不可能,但是攻擊難度提高了幾個數量級。此次引起行業關注的github劫持事件,就是SSL證書不正確導致劫持被發現曝光的[6]。

8、阻斷UDP

UDP通信是無連接狀態的通信,阻斷起來更困難。

IPS通過向客戶端發送端口不可達(port unreachable)的ICMP包來實現UDP的阻斷。但是效果有限:首先是客戶端是否認可這個ICMP包,跟應用程序的代碼有關[8];另外,很可能這個ICMP包不能活著通過鏈路上的各種路由及防火墻。

三. 修復方案

知道了具體的技術手段,優化方案就比較容易推導出來了,讀者可以自行歸納一下,這就是“以攻促防”。當然,有問題不怕,怕的是不知道自己有問題、無視問題甚至拒絕正視問題。

后記

相信經過上文探討,前言里面的問題已經有了答案,根據縱深防御原則,不管有無防護設備,安全漏洞都要及時修復。

當然,本文并不是想表達IPS很多問題,而是告訴大家,安全是一個動態過程,防御不是永遠有效的,要不斷地運營優化,要關注安全防護系統自身的有效性,紅藍對抗的時候不要只關注滲透目標,還要關注整個安全防御體系。感謝宙斯盾的球頭人牛長一起測試這個代號“007”的項目,后面的流量分析就交給他來跟進。

最后老規矩,招人,基礎安全各個領域,特別是流量安全分析方向,有意向的同志可投遞簡歷。不提供聯系方式,你肯定能找到我的。

【附錄】

[1] 現在網站越來越難滲透了,滲透這個方向還有前途嗎

[2] WAF建設運營及AI應用實踐

[3] 全方位繞過軟WAF思路

[4] 某電商網站流量劫持案例分析與思考

[5] Fuzz漏洞挖掘漫談

[6] “流量劫持”整正竊取你的信息?!

[7] Github疑似遭中間人劫持,網友反饋訪問報證書錯誤

[8] 關于UDP接收ICMP端口不可達(port unreachable)


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1173/