2012-04-09 53 views
1

爲什麼這段代碼是不安全的?爲什麼這個代碼是可被利用的?

#include <stdio.h> 
int main(int argc, char *argv[]) 
    { 
     printf(argv[1]); 
     printf("\n"); 
     return 0; 
    } 
+12

爲什麼我們應該爲您做作業? – 2012-04-09 21:12:42

+3

http://en.wikipedia.org/wiki/Uncontrolled_format_string – 2012-04-09 21:13:04

回答

5

printf將處理它的第一個參數,尋找的東西像%d%s

基於這些值,它將從堆棧中獲取更多數據並將其打印出來。

所以,如果有人叫你的程序:

a.out "%d %d %d %d %d %d %d %d %d %d %d %d" 

他們可以查看您的計算機的調用堆棧的一部分。

如果他們對格式說明符有更多的創造性,他們可能會轉儲一些重要的東西,比如信用卡號碼或密碼。

+1

用'%n'你甚至可以在內存中的任何地方寫入 – ouah 2012-04-09 21:16:13

+0

是的,我認爲它只打印%,因爲它打印了argv [1],就是這樣。 – 0x90 2012-04-09 21:17:58

+0

這是比較溫和的; '%n'會導致主動損壞(例如修改控制流)。 – 2012-04-09 21:18:24

4

考慮一下的printf控制的第一個參數(提示:printf不只是讀它的輸入參數)。

1

由於海報問一個例子是什麼呢%n

的方式printf格式字符串可以變化內存是使用%n選項;通過「明智地」使用格式寬度說明符可以獲得要寫入的特定值。作爲一個測試:

#include <stdio.h> 

int main(int argc, char **argv) 
{ 
    int *q = (int *)argv[0]; 
    printf("%1$300000d%5$n", 
     123,   // %1 - 1st param (formatted as '300000d') 
     0,   // %2 - 2nd param (unused) 
     0,   // %3 - 3rd param (unused) 
     0,   // %4 - 4th param (unused) 
     argv[0]); // %5 - 5th param (written to via 'n') 

    printf("\nNow *q == %d\n", *q); 

    return 0; 
} 

如果你運行這個,看看輸出的最後一行,它會打印Now *q == 300000(在Linux上測試)。

我使用printf()這裏的,而未知位置格式的語法% <POS> $ <FMT>),以顯示如何能夠跳過參數選擇修改哪一個,而無需使用任何的「無趣」的。

我會讓讀者進行實驗來找出printf()作爲printf(argv[1])這樣的調用的「參數」。答案取決於您的系統的calling conventions(或相關,ABI),並且對於32/64位Windows/Linux/MacOSX等不同。