Ale*_*nov 4 history csh historical-unix
我链接到The Unix-Haters Handbook并偶然发现(第 149 页):
主题:相关的 Unix 错误
1991 年 10 月 11 日
W4115x 同学——
当我们讨论激活记录、参数传递和调用约定时,您是否知道键入:
Run Code Online (Sandbox Code Playgroud)!xxx%s%s%s%s%s%s%s%s
任何 C-shell 都会导致它立即崩溃?你知道为什么吗?
需要思考的问题:
- 当您键入时,shell 会做什么
!xxx
?- 当您输入时,它必须对您的输入做什么
!xxx%s%s%s%s%s%s%s%s
?- 为什么这会导致外壳崩溃?
- 你怎么能(相当容易地)重写 shell 的有问题的部分,以免出现这个问题?
纯粹出于好奇,谁能解释一下问题出在哪里?不出所料,在 Google 上搜索字符串并没有帮助。从消息中搜索其他引文只会给我消息的其他副本,但没有解释。
我不想挖掘 25 年前贝壳的来源,但是
它可能是格式字符串漏洞。
如果外壳包含类似的代码
printf(str);
Run Code Online (Sandbox Code Playgroud)
哪里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
作为参数串联,并且err
被用作if (err) error(err);
在几个的地方process()
,在sh.c
。最后,error()
(in sh.err.c
)包含一个经典的格式字符串漏洞:if (s) printf(s, arg), printf(".\n");
在其他一些地方,error()
用一个参数调用,比如error("Unknown user: %s", gpath + 1);
,所以很明显,这个想法是第一个参数error()
可能是一个格式字符串。
如果我说我完全理解历史替换功能,我不会说实话。它几乎是 C%
中未注释的手动字符串处理。在历史替换中确实具有特殊含义,但我只能看到它在第一个字符(如!%
)或之后findev()
被调用时被特殊处理。