2011-09-08 246 views
18

我試圖執行一個非常簡單的緩衝區溢出攻擊。我幾乎是這個新手。因此,如果這個問題是愚蠢的,請原諒我:-)緩衝區溢出攻擊

代碼:

#include<stdio.h> 
#include<stdlib.h> 

int i, n; 

void confused(int i) 
{ 
printf("**Who called me? Why am I here?? *** %x\n ", i); 
} 

void shell_call(char *c) 
{ 
printf(" ***Now calling \"%s\" shell command *** \n", c); 
system(c); 
} 

void victim_func() 
{ 
int a[4]; 
printf("Enter n: "); scanf("%d",&n); 
printf("~~~~~~~~~~~~~ values and address of n locations ~~~~~~~~~~"); 
for (i = 0;i <n ;i++) 
    printf ("\n a[%d] = %x, address = %x", i, a[i], &a[i]); 
printf("\nEnter %d HEX Values \n", n); 

// Buffer Overflow vulnerability HERE! 

for (i=0;i<n;i++) scanf("%x",&a[i]); 
    printf("Done reading junk numbers\n"); 
} 

int main() 
{ 
victim_func(); 
printf(「\n done」); 
return 0; 
} 

當我使用objdump的獲取函數的地址,我有以下幾點:

main(): 0x804854d 
Address of main() where printf() is called: 0x8048563 
victim_func(): 0x8048455 
confused(): 0x8048414 

現在,我想要的是從victim_func()跳到函數'confused()',通過溢出緩衝區,並覆蓋返回地址到confused()的地址。我想從confused()返回到main中的printf()語句,並正常退出。所以,我提供以下輸入

Enter n: 7 
Enter 7 HEX values: 
1 
2 
3 
4 
5 
8048414 (This is to jump to confused) 
8048563 (this is to jump to printf() in main) 

雖然,「完成」從printf語句的程序打印,它跳回到victim_func(),並打印「輸入n:」

我在做什麼錯誤?任何幫助將不勝感激! PS:我不確定我是否把問題提出來了。請讓我知道,如果需要更多的信息。

+5

其實,這是在學校的任務! – Ashwin

+0

如果這真的是功課,請標記爲這樣。 – NPE

+7

@VJo我認爲這是一項偉大的教育任務 - 我很想親自嘗試:它需要深入理解並直接試驗代碼的彙編器實現。白帽子也需要掌握這些想法。 – Elemental

回答

8

緩衝區溢出攻擊比這個複雜得多。首先,您需要了解彙編程序才能執行此操作。在反彙編程序和函數後,您需要在執行該函數時確定堆棧佈局。 這是一個使用visual studio的緩衝區溢出示例,但原理是一樣的。

#include "stdafx.h" 
#include <math.h> 

volatile double test; 

double function3() 
{ 
    test++; 
    return exp(test); 
} 

double function2() 
{ 
    return log(test); 
} 

double function1() 
{ 
    int a[5] = {0};   
    a[7] = (int)&function3; 
    return exp(function2()); 

} 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
    double a = function1(); 
    test = a; 
    return a; 
} 

由於反彙編,我們知道函數1在函數保存堆棧幀指針之前被分配。之後的值是函數1應完成的返回地址。

00401090 55    push  ebp <- we save the stack pointer 
00401091 8B EC   mov   ebp,esp 
00401093 83 EC 1C   sub   esp,1Ch <- save space to allocate a[5] 
00401096 B8 CC CC CC CC mov   eax,0CCCCCCCCh 
0040109B 89 45 E4   mov   dword ptr [ebp-1Ch],eax <- crt debug init a[5] 
0040109E 89 45 E8   mov   dword ptr [ebp-18h],eax 
004010A1 89 45 EC   mov   dword ptr [ebp-14h],eax 
004010A4 89 45 F0   mov   dword ptr [ebp-10h],eax 
004010A7 89 45 F4   mov   dword ptr [ebp-0Ch],eax 
004010AA 89 45 F8   mov   dword ptr [ebp-8],eax 
004010AD 89 45 FC   mov   dword ptr [ebp-4],eax 

由此看來,如果我們重寫[7]不同的地址,該函數將返回不主要,但與任何地址,我們在寫我們可以得出一個[7]。

希望這會有所幫助。

+0

非常感謝患者的解釋。這就是我卡住的地方!爲什麼我們需要分配1Ch的單詞,來存儲數組的5個單詞?您能否詳細說明堆棧結構? – Ashwin

+0

而且,這是我拆解主要程序的一大塊。 '0x0804855b :\t子$爲0x4,%esp' '0x0804855e :\t呼叫0x8048455 '' 0x08048563 :\t MOVL $ 0x804872e,(%ESP)'' 0x0804856a :\t呼叫0x8048364 <[email protected]>' 所以,我從困惑中返回到0x8048563處的main()。將返回地址放在正確的內存位置沒有問題。並且,main()通過打印「完成」來恢復。但在這一點上,它返回到victim_func()並打印「輸入n:」這是我不明白。 – Ashwin

1

首先,我認爲你不應該在你的示例輸入中輸入數字5。你的數組被聲明爲[4],因此元素索引爲0-3 - 所以你的攻擊輸入對我來說似乎是錯誤的。

它還在我看來,你的程序的讀者要對架構的幾個事情:

  • sizof(INT)==的sizeof(內存地址)
  • 的環境中生長和機制的方向堆棧實現

如果其中一個假設是不真實的,它永遠不會工作。

這似乎是一項非常艱苦的工作任務。

緩衝區溢出攻擊的例子比改變代碼的控制流更簡單。例如,您可能可以覆蓋應該受保護的另一條數據(如安全設置)

+2

超出數組範圍的索引正是這種攻擊的工作原理。而這種攻擊總是非常依賴平臺;它們取決於堆棧的佈局,通常涉及一些彙編程序。通常的解決方案是將機器代碼放在緩衝區中,然後用緩衝區的地址替換堆棧上的返回地址。 –

0

您沒有向我們展示程序的輸出,其地址爲a [i ]。我懷疑編譯器正在做什麼,比如將堆棧上的數據對齊到16位。它可能比您預期的要更進一步。現在

1

,我要的是跳轉到從victim_func'混淆()()的函數通過溢出緩衝區那裏,改寫返回地址的地址混淆()...

在現代Linux平臺上,您還需要確保關閉兩個安全功能以進行測試。首先在NX堆棧中,其次是堆棧保護器。

要關閉NX-棧,使用-Wl,z,execstack(相對於-Wl,z,noexecstack)。要關閉堆疊保護器,請使用-fno-stack-protector(而不是-fstack-protector-fstack-protector-all)。

您可能需要關閉第三個保護。該保護是FORTIFY_SOURCE。 FORTIFY_SOURCE使用高風險函數的「更安全」變體,如memcpystrcpy。編譯器在推導出目標緩衝區大小時使用更安全的變體。如果副本超出目標緩衝區大小,則該程序將調用abort()。要禁用FORTIFY_SOURCE,請使用-U_FORTIFY_SOURCE-D_FORTIFY_SOURCE=0編譯該程序。

安全功能默認打開,因爲過去有太多問題。一般而言,它是一件好事,因爲它可以阻止許多問題(如正在試驗的問題)。