History

“!xxx%s%s%s%s%s%s%s%s”有什麼特別之處?

  • April 26, 2017

我被連結到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.cerror()sh.err.cif (s) printf(s, arg), printf(".\n");

在其他一些地方,error()用一個參數呼叫,比如error("Unknown user: %s", gpath + 1);,所以很明顯這個想法是第一個參數error()可能是一個格式字元串。

如果我說我完全理解歷史替換功能,我不會說實話。它在 C 中幾乎是未註釋的手動字元串處理。%在歷史替換中確實具有特殊含義,但我只能看到它在第一個字元(如!%)或之後findev()被呼叫時被特別處理。

引用自:https://unix.stackexchange.com/questions/361170