Linux · Linux kernel · Security

Stack buffer overflow protection 學習筆記 – Stack canaries mechanism in User space

緩衝區溢位 (Stack buffer overflow) 是傳統且常見的資訊安全攻擊手法. 主要透過程式漏洞造成輸入緩衝區溢位, 從而破壞原本程式執行、並取得系統的控制權.

而透過 buffer overflow 攻擊手法 [1] 以及攻擊範例 [2] 的相關資訊可瞭解如何使用 buffer overflow 來蓋掉 return address 內的資料以執行 shell code, 最終得到系統最高權限.

Stack buffer overflow 防護機制

可透過下列幾種方法來避免或降低 stack buffer overflow 造成的系統安全危害

  • KALSR & ALSR (Address space Layout Randomization) [15][16]
  • Executable Stack Protection  [17]
  • Position Independent Executables [18]
  • Fortify Source [19]
  • Stack Canaries [4][9][11][12]

√ Stack Canaries

stack canaries 又稱為 stack protector, 此方法會在程式中加入 “canary value”. 之所以會稱之為金絲雀 (canary) 是因為早期煤礦工人常會在工作時發生急性一氧化碳(煤氣)中毒事件. 但以前沒有先進裝備來偵測一氧化碳(煤氣), 所以煤礦工人都會帶金絲雀 (canary) 進去礦坑工作. 原因是金絲雀對一氧化碳(煤氣)非常敏感, 些許煤氣就會讓金絲雀啼叫甚至死亡. 因此礦工會將金絲雀放在礦坑中作為是否需要逃生的依據.

同理可知, 若我們先在程式中加入 “canary value”, 若 buffer overflow 異常情況發生, 則會修改 “canary value”. 所以我們可透過檢查 “canary value” 是否遭修改來決定程式是否繼續往下執行或者中止結束.

2017-09-20_173104.png

1. User space stack protector

在 user space 底下可使用 toolchain 來達到 stack protector 的目的. 以 gcc 7.1 為例, 共支援 4 種類型

fstack-protector

  • 在使用到動態配置記憶體 (alloc) 或者 buffer > 8 bytes 的函數時加入以及檢查 canary 值

fstack-protector-all

  • 對所有 function 都加入以及檢查 canary 值

fstack-protector-strong (gcc 版本需 >= 4.9)

  • 除了 -fstack-protector 的條件外, 符合下列條件皆會加入以及檢查 canary 值

1. 若 local 變數位址用來賦值或者當作函式參數

2. local 變數為陣列類型, 或者 union 內含陣列

               3. 以 register 類型宣告的 local 變數

fstack-protector-explicit

  • 只對以 __attribute__((stack_protect)) 宣告的 function 加入以及檢查 canary 值

> e.g.  __attribute__((stack_protect)) test()

-fno-stack-protector 

  • 不啟用 stack protector

√ 運作原理剖析

以下列明顯有漏洞的程式為例

圖片3.png

在 32-bit 作業系統環境下使用 gcc 7.1 的編譯結果如下:

2017-09-20_175639.png

note : 若在 64-bit 作業系統下則會差 8 bytes

由上表可知, 若啟用 stack protector 選項, 編譯器會做一些處理以至讓 binary 增加大小.

讓 binary 增加的部分, 勢必就是 Stack protector 施展魔法之處. 我們來看究竟在 binary 發生甚麼事

readelf -s hello-stack-protector
  • 讀取 binary symbol table, 可以發現 binary 被 gcc 插入兩個 glibc 函式, 分別位於 [20]以及 [21] 用來處理 overflow 時的行為

2017-09-20_182035.png

那甚麼時候會執行 __stack_chk_fail_locak 呢?  我們可以使用 objdump 工具來反組譯 binary 以獲得更多訊息

objdump -d hello-stack-protector
  • 我們可以看到, 裡面將 %gs:0x14 的值 (canary value) 放進暫存器, 然後存放到 address (ebp –0xc) 的地方, 以進行防護

2017-09-20_182129.png

  • #60c 執行 strcpy 後, 會將 address (ebp –0xc) 的 canary值取出, 並和 %gs:0x14 裡的值做比較
  • 若比較結果一樣 (jump equal) 則跳到 #62a, 如果canary的值不一致, 代表偵測到 overflow, 執行 #625 的__stack_chk_fail.
  • %gs:0x14 的值為 kernel space所賦予之亂數, 詳情可參考 [22]

2017-09-20_182155.png


心得:

Security 和 Performance 往往是天秤的兩端, 設計時要好好考慮選用適當的防護手法. 不過一般而言, 都會建議預設使用 fstack-protector-strong  來編譯程式

 


References:

[1]: https://en.wikipedia.org/wiki/Stack_buffer_overflow#Exploiting_stack_buffer_overflows

[2]: https://dhavalkapil.com/blogs/Shellcode-Injection/

[3]: https://en.wikipedia.org/wiki/Buffer_overflow_protection

[4]: https://en.wikipedia.org/wiki/Stack_buffer_overflow#Stack_canaries

[5]: https://en.wikipedia.org/wiki/Sentinel_species#Historical_examples

[6]: https://www.win.tue.nl/~aeb/linux/hh/protection.html

[7]: https://www.phoronix.com/scan.php?page=news_item&px=KASLR-Default-Linux-4.12

[8]: https://my.oschina.net/macwe/blog/610357

[9]: https://hardenedlinux.github.io/2016/11/27/canary.html

[10]: https://gcc.gnu.org/onlinedocs/gcc-4.9.3/gcc/Optimize-Options.html

[11]: http://wiki.osdev.org/Stack_Smashing_Protector

[12]: https://lwn.net/Articles/584225/

[13]: https://gcc.gnu.org/ml/gcc-patches/2012-06/msg00974.html

[14]: http://www.madhur.co.in/blog/2011/08/06/protbufferoverflow.html

[15]: https://en.wikipedia.org/wiki/Address_space_layout_randomization

[16]: https://lwn.net/Articles/569635/

[17]: https://en.wikipedia.org/wiki/Executable_space_protection

[18]: https://en.wikipedia.org/wiki/Position-independent_code#Position-independent_executables

[19]: https://access.redhat.com/blogs/766093/posts/1976213

[20]: https://sourceware.org/git/?p=glibc.git;a=blob;f=debug/stack_chk_fail_local.c;h=eb0a759c4bc94d472504dea8759040c47f64efda;hb=HEAD

[21]: https://sourceware.org/git/?p=glibc.git;a=blob;f=debug/stack_chk_fail.c;h=9ab9bc7cebf7ed21a13af29c860ae683ea0d29e6;hb=HEAD

[22]: http://elixir.free-electrons.com/linux/latest/source/arch/x86/include/asm/stackprotector.h

發表迴響