1. 程式人生 > >Linux (x86) Exploit 開發系列教程之三(Off-By-One 漏洞 (基於棧))

Linux (x86) Exploit 開發系列教程之三(Off-By-One 漏洞 (基於棧))

字符串長度 教程 緩沖 實現 長度 溢出 att 測試 div

(1)原理:

將源字符串復制到目標緩沖區可能會導致off by one。當源字符串長度等於目標緩沖區長度時,單個NULL字節將被復制到目標緩沖區上方。這裏由於目標緩沖區位於堆棧中,所以單個NULL字節可以覆蓋存儲在堆棧中的調用者的EBP的最低有效位(LSB),這可能導致任意的代碼執行。

(2)漏洞代碼

#include <stdio.h>
#include <string.h>
void foo(char* arg);
void bar(char* arg);
void foo(char* arg) {
 bar(arg); /* [1] */
}
void bar(char* arg) {
 char buf[256];
 strcpy(buf, arg); /* [2] */
}
int main(int argc, char *argv[]) {
 if(strlen(argv[1])>256) { /* [3] */
  printf("Attempted Buffer Overflow\n");
  fflush(stdout);
  return -1;
 }
 foo(argv[1]); /* [4] */
 return 0;
}

編譯文件

技術分享圖片

(2)漏洞代碼的第[2]行是可能發生off by one溢出的地方。目標緩沖區長度為256,因此長度為256字節的源字符串可能導致任意代碼執行。如果調用者的EBP位於目標緩沖區之上,則在strcpy之後,單個NULL字節將覆蓋調用者EBP的LSB。反匯編漏洞代碼並繪制它的堆棧布局

gdb-peda$ disassemble main
Dump of assembler code for function main:
   0x08048497 <+0>:	push   ebp
   0x08048498 <+1>:	mov    ebp,esp
   0x0804849a <+3>:	push   edi
   0x0804849b <+4>:	sub    esp,0x8
   0x0804849e <+7>:	mov    eax,DWORD PTR [ebp+0xc]
   0x080484a1 <+10>:	add    eax,0x4
   0x080484a4 <+13>:	mov    eax,DWORD PTR [eax]
   0x080484a6 <+15>:	mov    DWORD PTR [ebp-0x8],0xffffffff
   0x080484ad <+22>:	mov    edx,eax
   0x080484af <+24>:	mov    eax,0x0
   0x080484b4 <+29>:	mov    ecx,DWORD PTR [ebp-0x8]
   0x080484b7 <+32>:	mov    edi,edx
   0x080484b9 <+34>:	repnz scas al,BYTE PTR es:[edi]
   0x080484bb <+36>:	mov    eax,ecx
   0x080484bd <+38>:	not    eax
   0x080484bf <+40>:	sub    eax,0x1
   0x080484c2 <+43>:	cmp    eax,0x100
   0x080484c7 <+48>:	jbe    0x80484e9 <main+82>
   0x080484c9 <+50>:	mov    DWORD PTR [esp],0x80485e0
   0x080484d0 <+57>:	call   0x8048380 <[email protected]>
   0x080484d5 <+62>:	mov    eax,ds:0x804a020
   0x080484da <+67>:	mov    DWORD PTR [esp],eax
   0x080484dd <+70>:	call   0x8048360 <[email protected]>
   0x080484e2 <+75>:	mov    eax,0xffffffff
   0x080484e7 <+80>:	jmp    0x80484fe <main+103>
   0x080484e9 <+82>:	mov    eax,DWORD PTR [ebp+0xc]
   0x080484ec <+85>:	add    eax,0x4
   0x080484ef <+88>:	mov    eax,DWORD PTR [eax]
   0x080484f1 <+90>:	mov    DWORD PTR [esp],eax
   0x080484f4 <+93>:	call   0x8048464 <foo>
   0x080484f9 <+98>:	mov    eax,0x0
   0x080484fe <+103>:	add    esp,0x8
   0x08048501 <+106>:	pop    edi
   0x08048502 <+107>:	pop    ebp
   0x08048503 <+108>:	ret    
End of assembler dump.
gdb-peda$ disassemble foo
Dump of assembler code for function foo:
0x08048464 <+0>: push ebp
0x08048465 <+1>: mov ebp,esp
0x08048467 <+3>: sub esp,0x4
0x0804846a <+6>: mov eax,DWORD PTR [ebp+0x8]
0x0804846d <+9>: mov DWORD PTR [esp],eax
0x08048470 <+12>: call 0x8048477 <bar>
0x08048475 <+17>: leave
0x08048476 <+18>: ret
End of assembler dump.
gdb-peda$ disassemble bar
Dump of assembler code for function bar:
0x08048477 <+0>: push ebp
0x08048478 <+1>: mov ebp,esp
0x0804847a <+3>: sub esp,0x108
0x08048480 <+9>: mov eax,DWORD PTR [ebp+0x8]
0x08048483 <+12>: mov DWORD PTR [esp+0x4],eax
0x08048487 <+16>: lea eax,[ebp-0x100]
0x0804848d <+22>: mov DWORD PTR [esp],eax
0x08048490 <+25>: call 0x8048370 <[email protected]>
0x08048495 <+30>: leave
0x08048496 <+31>: ret
End of assembler dump.

技術分享圖片

(3)256字節的用戶輸入,用空字節可以覆蓋foo的EBP的LSB。所以當foo的存儲在目標緩沖區“buf”之上的EBP被一個NULL字節所覆蓋時,ebp從0xbffff2d8變為0xbffff200。從堆棧布局我們可以看到堆棧位置0xbffff200是目標緩沖區“buf”的一部分,由於用戶輸入被復制到該目標緩沖區,攻擊者可以控制這個堆棧位置(0xbffff200),因此他控制指令指針(eip )使用他可以實現任意代碼執行。

測試:可覆蓋返回地址。

技術分享圖片

(4)嘗試找出ret_addr的值。

將斷點下在Breakpoint 2, 0x08048495 in bar ()處。運行查看內存情況

技術分享圖片

技術分享圖片

可以看到EBP 的值從0xbffff158被覆蓋成0xbffff100。EIP指向的是0xbffff104地址。EIP所指地址與buf之間需要填充172個A。

技術分享圖片

嘗試找出ret_addr的地址。

技術分享圖片技術分享圖片

(5)攻擊代碼

技術分享圖片

不知道為何,嘗試運行攻擊代碼失敗了。但是直接在調試界面輸入,可以獲得普通用戶的shell權限。

技術分享圖片

Linux (x86) Exploit 開發系列教程之三(Off-By-One 漏洞 (基於棧))