“!xxx%s%s%s%s%s%s%s%s”有什麼特別之處?
我被連結到The Unix-Haters Handbook並偶然發現(第 149 頁):
主題:相關的 Unix 錯誤
1991 年 10 月 11 日
W4115x 同學們——
當我們討論啟動記錄、參數傳遞和呼叫約定時,您是否知道鍵入:
!xxx%s%s%s%s%s%s%s%s
到任何 C-shell 會導致它立即崩潰?你知道為什麼嗎?
需要思考的問題:
- 當您鍵入時,shell 會做什麼
!xxx
?- 輸入時它必須對您的輸入做什麼
!xxx%s%s%s%s%s%s%s%s
?- 為什麼這會使外殼崩潰?
- 你怎麼能(相當容易地)重寫外殼的有問題的部分,以免出現這個問題?
純粹出於好奇,誰能解釋一下是什麼問題?不出所料,在 Google 上搜尋該字元串並沒有幫助。搜尋消息中的其他引用只給了我消息的其他副本,但沒有解釋。
我不想探勘 25 歲貝殼的來源,但是
這可能是一個格式字元串漏洞。
如果外殼包含類似的程式碼
printf(str);
其中
str
是從使用者輸入中獲取的一些字元串,字元串的內容將是使用的格式字元串printf
。的%s
告訴printf
列印一個參數指向的字元串。如果沒有給出參數(如上所述,只有格式字元串),該函式將從堆棧中讀取一些其他數據,並將它們作為指針跟隨。可能訪問未映射的記憶體並使程序崩潰。在某種程度上,我認為消息的措辭也暗示了這樣的解決方案。如果您鍵入
!xxx
,shell 顯然會列印一條錯誤消息,例如!xxx: event not found
. 從那裡開始,嘗試也列印並不是一個大的飛躍!xxx%s%s%s%s%s%s%s%s: event not found
,這意味著格式字元串漏洞。我不應該有,但我在這裡查看了原始碼(
4.3BSD-Tahoe/usr/src/bin/csh
日期是 1988 年)。
findev(cp, anyarg)
看起來它可能是查找匹配歷史事件的函式:它遍歷被呼叫sh.lex.c
的鍊錶。如果它沒有找到任何東西,它會呼叫through 。這裡看起來是歷史中正在搜尋的字元串。struct Hist``Histlist``seterr2(cp, ": Event not found");``noev()``cp
seterr2()
將變數設置為err
參數的串聯,並err
在,if (err) error(err);
in 的幾個地方使用。最後,(in ) 包含一個經典的格式字元串漏洞:process()
sh.c
error()
sh.err.c
if (s) printf(s, arg), printf(".\n");
在其他一些地方,
error()
用一個參數呼叫,比如error("Unknown user: %s", gpath + 1);
,所以很明顯這個想法是第一個參數error()
可能是一個格式字元串。如果我說我完全理解歷史替換功能,我不會說實話。它在 C 中幾乎是未註釋的手動字元串處理。
%
在歷史替換中確實具有特殊含義,但我只能看到它在第一個字元(如!%
)或之後findev()
被呼叫時被特別處理。