初遇緩衝區溢位(Stack Buffer Overflow)攻擊
那天晚上,某種業務有好幾個服務端進程在短時間內崩潰了。
同事上去看了,發現都是在處理來自同一個地方東莞的同一個IP地址過來的請求時發生core dump。
恩,詭異,當時我們先跟營運同事聯絡,在該業務的幾個伺服器上 臨時緊急禁掉該IP的串連。
我也上去看了,用GDB查看core檔案。看了trace back基本上知道,都是在處理某個類型的訊息請求時出的問題。再查看了一下當時的一些臨時變數,然後明白了。
接收到用戶端發來的這種類型的請求訊息後,進入處理函數。 服務端會根據請求訊息中的一個欄位 ,做某種計算,計算的結果放到一個函數中聲明的長度為100的數組。
計算的結果的長度和請求訊息中的欄位的長度有關,請求訊息中的資料越長,計算結果越長。
調試器中顯示,當時計算結果有576個位元組,顯然長度為100位元組的數組裝不下(正常用戶端發的都不會超過這個長度), 導致棧空間被胡寫....
這不就是經常聽說的緩衝區溢位攻擊嗎? 只要它重寫了該函數本次調用的返回地址,就可以返回後執行攻擊者的代碼。而服務端進程基本都以root許可權運行,所以這樣攻擊者可以做很多事情。
不過還好,正因為緩衝區溢位很經典,C/C++先驅們也有了一些對策。GCC編譯器做了Stack-Smashing Protector 機制,在單位元組數組後插入一些金絲雀(Canary, 因為大家在礦井作業時,會用金絲雀來預警,如果金絲雀死了,那證明有毒氣),如果canary被改掉,在函數執行完成返回之前會檢查一下Canary,發現被篡改則不再繼續執行,中止程式,避免執行攻擊者的代碼。
所以我們的程式出現這個log:
“*** stack smashing detected ***
並且進程崩潰掉了,證明GCC的保護起作用了。緩衝區溢位攻擊沒有得逞。
GCC編譯器的Stack-Smashing Protector 機制由編譯選項-fstack-protector(或-fstack-protector-all)來開啟,在那之前我們並沒有刻意增加這個編譯選項,幸好Ubuntu
linux預設是開啟-fstack-protector選項的。
http://soc.if.usp.br/doc/gcc-4.1-doc/gcc.html:
On Ubuntu the default is -fstack-protector, to
turn it off use -fno-stack-protector.
事後,增加簡單的長度檢查就可以修複這個問題。因為這個代碼來自服務區比較公用的一個基本庫,所以我猜測其他和用戶端直接連接的服務端進程也存在類似問題。雖然郵件抄送給大佬,不過沒引起重視,不久之後其他組果然也發現類似問題.....
其實,平時在代碼中有訪問數組的地方,可以多考慮邊界檢查,從編程規範上預防類似問題。
-------------------------------------------------------------------------------------------------
更多博文請訂閱RSS,更多微博請關注@千裡孤行Nerd