【问题标题】:Executing shell command programmatically safely以编程方式安全地执行 shell 命令
【发布时间】:2021-08-04 13:18:56
【问题描述】:

可以通过调用执行shell命令的system函数来执行shell命令。

这显然不安全,因为有人可以滥用程序并执行攻击者特定的操作系统命令。

系统man page建议使用exec(3)函数:

不要使用特权程序(set-user-ID 或 set-group-ID 程序,或具有功能的程序),因为 某些环境变量的奇怪值可能用于 颠覆系统完整性。例如,可以操纵 PATH 以便以特权执行任意程序。使用 exec(3) 系列函数,而不是 execlp(3) 或 execvp(3)(也使用 PATH 环境变量来搜索 对于可执行文件)。

虽然我不太了解其中的区别。是的,权限可能会有所不同,但我们仍然执行 os 命令并且它仍然容易受到攻击,不是吗?我错过了什么吗?

如何安全地执行系统命令而不用担心会被滥用?

【问题讨论】:

  • 选项 1:你不能。选项 2:您知道程序应该安装在哪里,并在对 execv()execve() 的调用中安全地指定程序的完整路径名。如果你不知道程序应该安装在哪里,你可能会被卡住。
  • 如果我限制输入中的特殊字符怎么办?它会完全覆盖攻击者可能进行的注入吗?
  • ——哪些特殊字符?除非您将有效字符限制在允许的字符的限制列表中(例如,无重音的拉丁字母、数字、下划线以及点和斜线(但可能不包括破折号),否则您迟早可能会遇到问题。即便如此,也可能攻击者可以使用的技巧来搞砸事情。这部分取决于攻击者对程序运行的环境(尤其是环境变量)的控制程度。

标签: c security


【解决方案1】:

我们仍在执行 os 命令,它仍然很脆弱,不是吗?

想象一下下面的 C 程序(为了清楚起见,忽略所需的 C 错误处理):

char file[20];
fgets(file, sizeof(file), stdin);
file[strcspn(file, "\n")] = 0; // https://stackoverflow.com/questions/2693776/removing-trailing-newline-character-from-fgets-input
char cmd[200];
snprintf(cmd, sizeof(cmd), "touch %s", file);
system(cmd);

一切正常 - 一个创建文件的简单程序。但现在我运行程序并输入:

file; sudo rm -r /

那么会发生什么,file="file; sudo rm -r /" 然后cmd="touch file; sudo rm -r /" 和结果system 命令运行touch file 然后运行sudo rm -r / 删除所有文件并造成灾难性损坏。

相比之下:

execl("touch", "touch", file, NULL);

将始终只运行touch(在当前目录中),而touch 将只尝试触摸一个直接命名为file; sudo rm -rf / 的目录(因为尾随/)。 (但是PATH 可以被操纵,touch 可执行文件可以被替换,这就是为什么使用execv 而不是execl - 你的报价说明了这一点。

【讨论】:

  • 除非存在带有尾随空白的目录file; sudo rm -rf ,否则它将失败——因为尾随斜杠。此外,execl("touch", "touch", file, (char *)0); 提供了命令名和文件名——并且只执行./touch。您可能需要execl("/usr/bin/touch", "touch", file, (char *)0); 才能正确执行。
  • 所以总是使用 execv ?
  • @Wahalez:一般来说,execv()execve() 是明智的选择。 execl*() 函数需要一个参数列表,其中参数的数量在编译时是固定的,而 execv*() 函数使用由空指针终止的字符串参数数组,就像 argv 提供给 main() 一样。大多数情况下,您需要额外的灵活性——使用execv(argv[0], argv) 或类似的调用。有时,与安全相关的程序可能是其中之一,您不想要灵活性,也许使用 execl*() 函数是合适的。
  • @KamilCuk 除了这个,我什么都理解:and touch will only try to touch a directory (because of the trailing /) named literally file; sudo rm -rf /. 为什么是目录而不是文件?因为字符串中的 / ?
  • because of the / in the string ?touch dir/ - 那么dir 必须是一个目录。
猜你喜欢
  • 2013-01-26
  • 2014-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-21
  • 1970-01-01
  • 2016-10-28
  • 1970-01-01
相关资源
最近更新 更多