2014-01-30 86 views
2

看看這個脆弱的片段:什麼導致這種格式字符串攻擊?

int main(int argc, char **argv) { 
    printf(argv[1], "bla"); 
    return 0; 
} 

沒有優化的編譯它導致

./test "asd" 
asd 

./test "asd %s" 
asd bla 

./test "asd %0\$s" 
asd %0$s 

./test "asd %45\$s" 
asd XDG_VTNR=7 <-- What the... 

嗯,其實它似乎像 「%(數量)\ $ S」 試圖解釋(數字)作爲一個字符串的第三個參數,向上看堆棧,並且我遇到了我的環境變量。在任何地方使用這種格式字符串,特別是使用奇怪的「\ $」?我找不到任何參考。

最後,編譯與優化啓用它會導致:

*** invalid %N$ use detected *** 
asd zsh: abort  ./test "asd %46\$s" 

我從來沒見過這樣的錯誤。它從何而來?

(我使用的Gentoo Linux/GCC 4.8.2/glibc的2.18)

+0

我還在調試時爲什麼在我測試的程序的輸出中出現字符'X'(而不是'argv [2]'中的最後一個字符)。它與argv [2](緊接着'argv [2]''終止'NUL'字符後面]連續出現。 '(gdb)p sp1 = argv [2] + 4' =>'$ 11 = 0x7fffffffe4a7「XDG_VTNR = 1」'。所以它顯然是在只讀部分。 –

+0

有趣的是,我發現'argv'的是,如果我檢查與'argv [1]'('argv [1] + strlen(argv [1])'')連續的內存,它確實是'argv [2]',但'argv [2]'(最後一個參數)是一個環境變量'「XDG_VTNR = 1」'的連續內存與argv [3]不同,它顯然是一個空指針終止列表。 'argv [4]',* whatever *,確實包含了這個內存,並在argv結束後繼續下去,顯示出大量的環境變量。 –

回答

5

當然,這是mentioned in the manual page像你期望的那樣。它似乎來自單一Unix規範(即不是C99)。

它用於國際化,當你需要根據各種信息的順序調換以適應翻譯。數爲一個參數的索引:

人們也可以明確地指定通過寫"%m$"代替'%'"*m$"代替'*',其中十進制整數m表示哪個參數被採用,在每個在需要的參數的地方,在所期望的參數的自變量列表中的位置,被索引從1

因此,在一個更明智的程序開始,此:

printf("%2$d %1$d", 1, 2); 

個打印

2 1 

這有可能是與優化層樓高啓用使編譯器執行的代碼更重量級的分析,使之能「知道」更多的實際參數列表,並生成一個更好的錯誤。

+0

好吧....好的。採取的點。尼斯的行爲;-)當我啓用優化時,我的錯誤呢? – rralf

+1

@rralf:錯誤很可能來自您的stdlib printf實現 - 當它看到'%N $'格式以確保它不是不合理時,它會進行一些理智的檢查。至於爲什麼只有在開啓優化時才觸發,這是一個謎。 –