“!xxx%s%s%s%s%s%s%s%s”有什么特别之处?

“!xxx%s%s%s%s%s%s%s%s”有什么特别之处?

我被链接到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使用的格式字符串。告诉打印参数指向的字符串%sprintf如果未给出参数(如上所述,只有格式字符串),该函数将从堆栈中读取一些其他数据,并将它们作为指针跟随。可能访问未映射的内存并使进程崩溃。

在某种程度上,我认为该消息的措辞也暗示了这样的解决方案。如果您键入!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()

相关内容