在 c++ 中,所有 system() 调用都存在安全风险吗?

Are ALL system() calls a security risk in c++?

本文关键字:安全 存在 调用 c++ 所有 system      更新时间:2023-10-16

这个(system()称之为邪恶吗?)线程中的帖子说:

程序的权限由其生成的程序继承。如果你的应用程序曾经以特权用户的身份运行,那么人们所要做的就是用你掏出的东西的名字来放置他们自己的程序,然后可以执行任意代码(这意味着你永远不应该运行使用系统作为root或setuid根的程序)。

但是system("PAUSE")system("CLS")外壳到操作系统,那么如果黑客只外壳到硬盘驱动器上的特定安全位置,它怎么可能干预呢?

显式刷新(通过使用 fflush 或 _flushall)或在调用系统之前关闭任何流是否可以消除所有风险?

最初的问题引用的是POSIX而不是Windows。这里没有COMSPEC(有SHELLsystem()故意不使用它);然而,/bin/sh完全、完全脆弱。

假设/opt/vuln/program 看起来完全无害system("/bin/ls");,对吧?不!

$ PATH=. IFS='/ ' /opt/vuln/program

这将在当前目录中运行名为bin的程序。哎呀。防御这种事情是如此困难,应该留给极端专家,比如写sudo的人。消毒环境非常困难。

所以你可能会想system()api 有什么用。我实际上不知道为什么创建它,但是如果您想做一个像ftp这样的功能,其中 !command 在 shell 中本地执行,您可以... else if (terminalline[0] == '!') system(terminalline+1); else ...由于无论如何它都是完全不安全的,因此没有必要使其安全。当然,一个真正现代的用例不会这样做,因为system()不看$SHELL但哦,好吧。

system 函数将命令传递给命令解释器,命令解释器将字符串作为操作系统命令执行。 系统使用 COMSPEC 和 PATH 环境变量来定位命令解释器文件 CMD.exe。如果命令为 NULL,则该函数仅检查命令解释器是否存在。

在调用系统之前,必须显式刷新(使用 fflush 或 _flushall)或关闭任何流。

https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/system-wsystem

如果有任何疑问,这里是 MS 实现的实际片段(非常简单明了):

// omitted for brevity
argv[1] = _T("/c");
argv[2] = (_TSCHAR *) command;
argv[3] = NULL;
/* If there is a COMSPEC defined, try spawning the shell */
/* Do not try to spawn the null string */
if (argv[0])
{
// calls spawnve on value of COMSPEC vairable, if present
// omitted for brevity
}
/* No COMSPEC so set argv[0] to what COMSPEC should be. */
argv[0] = _T("cmd.exe");
/* Let the _spawnvpe routine do the path search and spawn. */
retval = (int)_tspawnvpe(_P_WAIT,argv[0],argv,NULL);
// clean-up part omitted

至于担心_tspawnvpe实际上可能在做什么,答案是:没什么神奇的。spawnvpe和朋友的确切调用顺序如下(因为任何拥有许可版本的 MSVC 的人都可以通过检查spanwnvpe.c源文件轻松学习):

  1. 对参数进行一些健全性检查
  2. 尝试对传递的文件名调用_tspawnve。 如果文件名表示可执行文件的绝对路径或相对于当前工作目录的有效路径,则spawnve成功。没有进行进一步的检查 - 所以是的,如果当前目录中存在名为cmd.exe的文件,它将首先在讨论system()调用的上下文中调用。
  3. 在循环中:使用 '_getpath() 获取下一个路径元素
    1. 将文件名追加到 path 元素
    2. 将结果路径传递给spwanvpe,检查是否成功

就是这样。不涉及特殊技巧/检查。