自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

解讀Linux安全機(jī)制之棧溢出保護(hù)

開發(fā) 開發(fā)工具
今天我們講一講有關(guān)Linux安全機(jī)制之棧溢出保護(hù)的內(nèi)容。

[[181356]]

一、概述

棧溢出保護(hù)是一種緩沖區(qū)溢出攻擊緩解手段,當(dāng)函數(shù)存在緩沖區(qū)溢出攻擊漏洞時,攻擊者可以覆蓋棧上的返回地址來讓shellcode能夠得到執(zhí)行。當(dāng)啟用棧保護(hù)后,函數(shù)開始執(zhí)行的時候會先往棧里插入cookie信息,當(dāng)函數(shù)真正返回的時候會驗(yàn)證cookie信息是否合法,如果不合法就停止程序運(yùn)行。攻擊者在覆蓋返回地址的時候往往也會將cookie信息給覆蓋掉,導(dǎo)致棧保護(hù)檢查失敗而阻止shellcode的執(zhí)行。在Linux中我們將cookie信息稱為canary(以下統(tǒng)一使用canary)。

gcc在4.2版本中添加了-fstack-protector和-fstack-protector-all編譯參數(shù)以支持棧保護(hù)功能,4.9新增了-fstack-protector-strong編譯參數(shù)讓保護(hù)的范圍更廣。以下是-fstack-protector和-fstack-protector-strong的區(qū)別:

-fstack-protector和-fstack-protector-strong的區(qū)別

Linux系統(tǒng)中存在著三種類型的棧:

  • 應(yīng)用程序棧:工作在Ring3,由應(yīng)用程序來維護(hù);
  • 內(nèi)核進(jìn)程上下文棧:工作在Ring0,由內(nèi)核在創(chuàng)建線程的時候創(chuàng)建;
  • 內(nèi)核中斷上下文棧:工作在Ring0,在內(nèi)核初始化的時候給每個CPU核心創(chuàng)建一個。

二、 應(yīng)用程序棧保護(hù)

1. 棧保護(hù)工作原理

下面是一個包含棧溢出的例子:

  1. /* test.c */ 
  2.  
  3. #include <stdio.h> 
  4.  
  5. #include <string.h> 
  6.  
  7. int main(int argc, char **argv) 
  8.  
  9.  
  10.     char buf[16]; 
  11.  
  12.     scanf("%s", buf); 
  13.  
  14.     printf("%s\n", buf); 
  15.  
  16.     return 0; 
  17.  

我們先禁用棧保護(hù)功能看看執(zhí)行的結(jié)果

  1. [root@localhost stackp]# gcc -o test test.c -fno-stack-protector 
  2.  
  3. [root@localhost stackp]# python -c "print 'A'*24" | ./test 
  4.  
  5. AAAAAAAAAAAAAAAAAAAAAAAA 
  6.  
  7. Segmentation fault   <- RIP腐敗,導(dǎo)致異常 

當(dāng)返回地址被覆蓋后產(chǎn)生了一個段錯誤,因?yàn)楝F(xiàn)在的返回地址已經(jīng)無效了,所以現(xiàn)在執(zhí)行的是CPU的異常處理流程。我們打開棧保護(hù)后再看看結(jié)果:

  1. [root@localhost stackp]# gcc -o test test.c -fstack-protector 
  2.  
  3. [root@localhost stackp]# python -c "print 'A'*25" | ./test 
  4.  
  5. AAAAAAAAAAAAAAAAAAAAAAAAA 
  6.  
  7. *** stack smashing detected ***: ./test terminated  

這時觸發(fā)的就不是段錯誤了,而是棧保護(hù)的處理流程,我們反匯編看看做了哪些事情:

  1. 0000000000400610 <main>
  2.  
  3.   400610:       55                      push   %rbp 
  4.  
  5.   400611:       48 89 e5                mov    %rsp,%rbp 
  6.  
  7.   400614:       48 83 ec 30             sub    $0x30,%rsp 
  8.  
  9.   400618:       89 7d dc                mov    %edi,-0x24(%rbp) 
  10.  
  11.   40061b:       48 89 75 d0             mov    %rsi,-0x30(%rbp) 
  12.  
  13.   40061f:       64 48 8b 04 25 28 00    mov    %fs:0x28,%rax  <- 插入canary值 
  14.  
  15.   400626:       00 00 
  16.  
  17.   400628:       48 89 45 f8             mov    %rax,-0x8(%rbp) 
  18.  
  19.   40062c:       31 c0                   xor    %eax,%eax 
  20.  
  21.   40062e:       48 8d 45 e0             lea    -0x20(%rbp),%rax 
  22.  
  23.   400632:       48 89 c6                mov    %rax,%rsi 
  24.  
  25.   400635:       bf 00 07 40 00          mov    $0x400700,%edi 
  26.  
  27.   40063a:       b8 00 00 00 00          mov    $0x0,%eax 
  28.  
  29.   40063f:       e8 cc fe ff ff          callq  400510 <__isoc99_scanf@plt> 
  30.  
  31.   400644:       48 8d 45 e0             lea    -0x20(%rbp),%rax 
  32.  
  33.   400648:       48 89 c7                mov    %rax,%rdi 
  34.  
  35.   40064b:       e8 80 fe ff ff          callq  4004d0 <puts@plt> 
  36.  
  37.   400650:       b8 00 00 00 00          mov    $0x0,%eax 
  38.  
  39.   400655:       48 8b 55 f8             mov    -0x8(%rbp),%rdx  <- 檢查canary值 
  40.  
  41.   400659:       64 48 33 14 25 28 00    xor    %fs:0x28,%rdx 
  42.  
  43.   400660:       00 00 
  44.  
  45.   400662:       74 05                   je     400669 <main+0x59> # 0x400669 
  46.  
  47.   400664:       e8 77 fe ff ff          callq  4004e0 <__stack_chk_fail@plt> 
  48.  
  49.   400669:       c9                      leaveq 
  50.  
  51.   40066a:       c3                      retq 

 

我們看到函數(shù)開頭(地址:0x40061f)處gcc編譯時在棧幀的返回地址和臨時變量之間插入了一個canary值,該值是從%fs:0x28里取的,棧幀的布局如下:

  1. stack: 
  2.  
  3. | ......          | 
  4.  
  5. | orig_return     | 
  6.  
  7. | orig_rbp        |  <- %rbp 
  8.  
  9. | canary          |  <- -0x8(%rpb), 既 %fs:0x28 
  10.  
  11. | local variables | 
  12.  
  13. |                 |  <- %rsp 

在函數(shù)即將返回時(地址:0x400655)檢查棧中的值是否和原來的相等,如果不相等就調(diào)用glibc的_stackchk_fail函數(shù),并終止進(jìn)程。

2. canary值的產(chǎn)生

這里以x64平臺為例,canary是從%fs:0x28偏移位置獲取的,%fs寄存器被glibc定義為存放tls信息的,我們需要查看glibc的源代碼:

  1. typedef struct 
  2.  
  3.  
  4.   void *tcb;        /* Pointer to the TCB.  Not necessarily the 
  5.  
  6.                thread descriptor used by libpthread.  */ 
  7.  
  8.   dtv_t *dtv; 
  9.  
  10.   void *self;       /* Pointer to the thread descriptor.  */ 
  11.  
  12.   int multiple_threads; 
  13.  
  14.   int gscope_flag; 
  15.  
  16.   uintptr_t sysinfo; 
  17.  
  18.   uintptr_t stack_guard;   <- canary值,偏移位置0x28處 
  19.  
  20.   uintptr_t pointer_guard; 
  21.  
  22.   ...... 
  23.  
  24. } tcbhead_t; 

結(jié)構(gòu)體tcbheadt就是用來描述tls的也就是%fs寄存器指向的位置,其中+0x28偏移位置的成員變量stackguard就是canary值。另外通過strace ./test看到在進(jìn)程加載的過程中會調(diào)用arch_prctl系統(tǒng)調(diào)用來設(shè)置%fs的值,

  1. root@localhost stackp]# strace ./test 
  2.  
  3. execve("./test", ["./test"], [/* 24 vars */]) = 0 
  4.  
  5. ...... 
  6.  
  7. arch_prctl(ARCH_SET_FS, 0x7f985a041740) = 0 
  8.  
  9. ...... 

產(chǎn)生canary值的代碼在glibc的dlmain和_libcstart_main函數(shù)中:

  1.   /* Set up the stack checker's canary.  */ 
  2.  
  3.   uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random); 
  4.  
  5. # ifdef THREAD_SET_STACK_GUARD 
  6.  
  7.   THREAD_SET_STACK_GUARD (stack_chk_guard); 
  8.  
  9. # else 
  10.  
  11.   __stack_chk_guard = stack_chk_guard; 
  12.  
  13. # endif 

dlrandom是一個隨機(jī)數(shù),它由dlsysdepstart函數(shù)從內(nèi)核獲取的。dlsetupstackchkguard函數(shù)負(fù)責(zé)生成canary值,THREADSETSTACK_GUARD宏將canary設(shè)置到%fs:0x28位置。

在應(yīng)用程序棧保護(hù)中,進(jìn)程的%fs寄存器是由glibc來管理的,并不涉及到內(nèi)核提供的功能。

3. x32應(yīng)用程序棧保護(hù)

解讀完了x64的實(shí)現(xiàn),我們來看看x32下面的情況,我們還是使用上面例子的代碼在x32的機(jī)器上編譯,得到下面的代碼:

  1. 08048464 <main>
  2.  
  3.  ...... 
  4.  
  5.  8048474:    65 a1 14 00 00 00      mov   %gs:0x14,%eax  # 插入canary值 
  6.  
  7.  804847a:    89 44 24 3c            mov   %eax,0x3c(%esp) 
  8.  
  9.  ...... 
  10.  
  11.  80484aa:    65 33 15 14 00 00 00   xor   %gs:0x14,%edx  # 檢查canary值 
  12.  
  13.  80484b1:    74 05                  je    80484b8 <main+0x54> # 0x80484b8 
  14.  
  15.  80484b3:    e8 c0 fe ff ff         call  8048378 <__stack_chk_fail@plt> 
  16.  
  17.  80484b8:    c9                     leave 
  18.  
  19.  80484b9:    c3                     ret 

 

責(zé)任編輯:趙寧寧 來源: 51CTO專欄
相關(guān)推薦

2009-07-24 17:35:24

2017-06-11 14:37:00

2013-07-15 10:15:28

2011-04-06 16:51:59

Windows Ser數(shù)據(jù)安全

2010-04-17 19:20:26

2009-07-03 18:59:02

2020-05-26 18:50:46

JVMAttachJava

2024-02-27 17:30:11

2021-09-01 13:51:06

網(wǎng)絡(luò)安全法基礎(chǔ)設(shè)施安全網(wǎng)絡(luò)安全

2019-01-11 09:00:00

2009-10-21 14:36:53

漏洞補(bǔ)丁

2019-01-28 18:05:04

2019-02-13 13:31:42

2022-01-03 00:15:06

安全網(wǎng)絡(luò)物聯(lián)網(wǎng)

2012-11-30 11:08:57

2021-12-21 06:07:10

網(wǎng)絡(luò)安全網(wǎng)絡(luò)攻擊網(wǎng)絡(luò)威脅

2022-05-19 07:09:29

機(jī)制沙箱安全JVM

2023-03-20 10:09:13

2017-03-10 09:28:58

2022-02-22 09:33:38

LIFO數(shù)據(jù)結(jié)構(gòu)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號