
我被連結到Unix 仇恨者手冊並偶然發現(頁149):
主題:相關 Unix bug
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
?- 為什麼這會使外殼崩潰?
- 您如何(相當容易地)重寫 shell 的有問題的部分以避免出現此問題?
純粹出於好奇,誰能解釋一下問題是什麼?毫不奇怪,在 Google 上搜尋該字串並沒有幫助。搜尋訊息中的其他引用只給了我該訊息的其他副本,但沒有解釋。
答案1
我不想去挖掘25年前的貝殼的來源,但是
它可能是一個格式字串漏洞。
如果 shell 包含如下程式碼
printf(str);
其中str
是從使用者輸入中獲取的一些字串,該字串的內容將是printf
使用的格式字串。告訴列印參數指向的字串%s
。printf
如果未給出參數(如上所述,只有格式字串),則函數將從堆疊中讀取一些其他數據,並將它們作為指標跟隨。可能存取未映射的記憶體並使進程崩潰。
在某種程度上,我認為該訊息的措辭也暗示了這樣的解決方案。如果您鍵入!xxx
,shell 明顯會列印錯誤訊息,例如!xxx: event not found
。從那裡開始,嘗試 print 並不是一個大的飛躍!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
看起來它可能是尋找符合歷史事件的函數:它遍歷被呼叫的連結struct Hist
清單Histlist
。如果沒有找到任何東西,它就會seterr2(cp, ": Event not found");
呼叫noev()
.cp
這裡看起來是在歷史記錄中搜尋的字串。
seterr2()
將變數設定err
為參數的串聯,並在, in 中的幾個地方err
使用if (err) error(err);
process()
sh.c
。最後,error()
(在sh.err.c
)包含一個經典的格式字串漏洞:if (s) printf(s, arg), printf(".\n");
在其他一些地方,error()
是用參數呼叫的,例如error("Unknown user: %s", gpath + 1);
,所以顯然這個想法是第一個參數error()
可能是格式字串。
如果我說我完全理解歷史替換函數,那我是不誠實的。它幾乎是 C 中未註釋的手動字串%
處理。!%
findev()