【问题标题】:Is it possible to restrict what commands php can pass through exec at an OS level?是否可以在操作系统级别限制 php 可以通过 exec 传递的命令?
【发布时间】:2013-03-13 03:15:16
【问题描述】:

我目前在 CentOS 机器上托管 Drupal 6 站点。 Drupal (CMS) 配置包含几十个第三方模块,它们不应该是forked 作为一般的最佳编码实践。但是,其中一些模块使用php exec 命令才能正常运行。

该站点允许管理员通过 UI 配置在任何页面中嵌入 php 代码 sn-ps,前提是他们有权访问 php 代码输入格式。我需要让管理员可以使用这种输入格式,因为有几个节点(页面)和面板窗格使用小型、无害的 php 代码 sn-ps,例如将特定表单嵌入到内容区域中。

问题是,如果有人要入侵管理员帐户,那么他们可以在站点上运行任意 php 代码,从而通过 php 的 execpassthru 等运行 shell 命令。有什么办法,从操作系统级别,以限制 php 可以将哪些 shell 命令传递给机器?这可以通过从php限制某些程序的文件权限来完成吗?

注意:我不能使用 php.ini disable_functions 指令,因为在许多情况下我仍然需要 exec 才能正常运行,其中模块使用某些 shell 命令,例如视频编码,例如。

【问题讨论】:

  • 在运行这些 php sn-ps 的代码中,您可以检查它们传递的命令类型,并且可以使用要排除的命令的黑名单(阻止运行)。一般来说,我不会授予用户(甚至管理员)在我的服务器上运行 PHP 代码而不检查该代码的权利。希望有帮助
  • @HasTaiar - 感谢您抽出宝贵时间在这里发表评论。由于您无法拦截exec 命令,是否总是有办法绕过检查传递的命令?例如动态创建的字符串$a = 'comm'; $b = 'mand'; exec($a . $b);
  • 可能有点矫枉过正,我不知道具体如何配置,但你有研究过 SELinux 吗?
  • @Koterpillar - 感谢您提供该资源。我一定会看看的。

标签: php drupal command-line centos exec


【解决方案1】:

如果您的管理员帐户被黑客入侵,您就完蛋了。你试图减少厄运,但这不会奏效。

禁用 exec()

这只是能够调用系统的所有函数的一小部分。还有更多,例如passthru()shell_exec()popen()proc_open()、反引号运算符等等。不会有帮助的。

限制可用的可执行文件

仅当攻击者无法携带自己的可执行文件时才会起作用。但是file_put_contents() 将能够将可执行文件写入硬盘,然后可以调用它。也无济于事。

PHP 本身不会造成任何伤害,不是吗?

错了。通过exec() 在服务器上执行操作似乎是最好的主意,但 PHP 本身功能强大,足以对您的服务器以及与之连接的任何东西造成严重破坏。

我认为唯一真正的解决方案是:

不要让您的管理员帐户被黑客入侵。

如果他们被黑客入侵,可以立即知道。能够将攻击追溯到管理员。能够知道攻击者对您的机器做了什么,以便您可以撤消它。一个非常重要的部分是您实现了一个审计跟踪记录器,它将其数据保存在不同的机器上。

而且您可能首先对谁可以以管理员身份登录实施更严格的限制。例如,如果您确定某个管理员总是使用其本地 ISP 的 IP 范围工作,则可能不需要允许整个世界的 IP 范围登录。至少,按铃并通知其他人,如果这不是预期的(除非您在中国经营:-)),从中国登录正在进行中。

并且有两个因素身份验证。您可以使用额外的登录代码向电话号码发送短信。或者,您可以通过实施 Google 或 Facebook 身份验证来完全外包登录。这些参与者已经拥有支持这一点的基础设施。

此外,您对内部工作的抵抗力更高。人们确实比雇主的登录更重视他们的个人社交网络登录。获取某人的 facebook 密码平均需要 30 美元,但公司登录已经共享 8 美元。去图...

【讨论】:

  • 我在网上找到了英国研究的参考资料:thedrum.com/news/2012/04/09/…
  • 感谢您的详细解释。我发现这个答案是经过深思熟虑的,尽管它不一定解决问题的操作系统特定部分。
【解决方案2】:

回答您的问题:理论上,如果您使用 PHP 可以运行命令的极其受限的帐户创建用户帐户,您可以调整您的安装以更安全。然而,真正的问题是管理员用户能够执行任意命令。如果发生这种情况,您将面临更大的问题。

这里真正的解决方案是:

  • 从 Drupal 中提交和运行任意代码的能力是一个重大风险,您可以通过不这样做来降低风险。我强烈建议重新设计那些“无害”的代码,因为它们会导致妥协;任意代码执行只是一种利用方式,还有很多其他需要担心的。
  • 需要运行 shell 命令的模块也是严重的安全漏洞。在某些情况下,我已经能够对执行命令的模块进行 fork/patch 或替换为不执行命令的模块,但在某些情况下(例如视频编码),这是无法避免的。在这种情况下,我会设置一个非常受限的后端服务,前端可以与之通信。这将您的关注点分开,让 Drupal 去做它原本打算做的事情:管理和提供内容。

【讨论】:

    【解决方案3】:

    这不在操作系统级别,但在 Drupal 核心内部有一个名为 PHP 的模块。您可以使用它作为基础并创建一个自定义模块来扩展此模块的功能,然后只需启用此模块而不是 Drupal 6 核心模块。然而,最大的问题在于禁用 Drupal 6 核心模块,然后启用新模块。我会在开发安装上对其进行测试,以确保没有删除以前的内容并且新模块正确解析存储的 PHP 输入。应该没问题,因为模块安装只有一个禁用钩子警告,针对现在以纯文本显示的 PHP 内容。

    至于扩展核心模块,它是一个非常简单的启动模块。您可以在允许或不允许执行的命令列表中硬编码。然后,您可以根据此列表检查带有已解析变量的 exec 语句,并执行任何适当的操作。与简单地阻塞在操作系统级别的程序本身相比,这并不是完美的匹配,但总比没有好。要对列表进行硬编码,您只需修改模块文件底部的 php_filter 挂钩,然后在执行 drupal_eval 之前进行测试。

    您还可以将此模块扩展为可在 Drupal 管理界面中进行配置,以创建该列表,而不是对其进行硬编码。希望这个想法有所帮助。

    【讨论】:

    • 嗨,Shawn,这通常是我用来扩展模块的方法。但是,我如何能够确定任何 php 代码 sn-p 将运行的确切值?对某些命令运行 exec 应该是可以的,但对于其他命令则不行。例如,如果 php 代码 sn-p 类似于 $a = 'ex'; $b = 'ex'; $c = 'comm'; $d = 'and'; $e = $a . $b; $e($c . $d);,我怎么知道有人在运行不安全的命令
    • 最终,你有一个 exec("这里的命令没有未解析的变量");。您希望在此阶段针对允许/不允许的操作系统命令列表进行一些正则表达式匹配。确定命令有效后,通过 drupal_eval 完成发送。这绝不是最好的答案...因为如果您不将 exec 中的命令与与命令同名的实际合法文本匹配,但实际上并未作为命令运行,则可能会导致问题。
    【解决方案4】:

    另一种方法:

    我们认为我们需要创建一个测试用户,该用户只能访问系统,以便对网络上的另一台机器执行 telnet。由于我们只需要运行 telnet,因此需要限制标准 bash 会话中可用的其他命令。让我们一步一步配置一切。

    1) 我们创建用户测试

    这将是系统的普通用户,我们作为普通用户也应该如此。唯一的特点是我们更改了该用户的外壳。默认通常是/bin/bash,我们将设置/bin/rbash。 rbash 实际上是 bash 的一个副本,但它确实是一个“受限制的 bash”。

    shell> adduser --shell /bin/test rbash
    

    2) 我们创建文件。 bash_profile

    我们必须在已创建的用户家中创建此文件,并且我们要为其应用权限。文件内容如下,

    if [-f ~/.bashrc]; then
        . ~/.bashrc
    fi
    
    PATH = $HOME/apps
    export PATH
    

    3)我们避免改变

    创建文件后,我们将阻止任何人对文件进行更改。

    shell> chattr +i /home/test/.bash_profile
    

    4) 我们创建apps目录并安装程序'access'

    现在,一旦您完成所有设置,只需创建应用程序并在其中创建一个链接,指向您希望用户拥有权限的程序。应用内的所有程序,用户都可以运行,但是不行。

    shell> mkdir apps
    shell> ln-s /usr/bin/telnet /home/test/apps/
    

    5) 我们发现可行

    现在您可以访问系统并验证它是否正常工作。

    shell> ssh test@remote
    test@remote password:
    
    shell@remote> ls
    -rbash: ls: command not found
    shell@remote> cd
    -rbash: cd: command not found
    shell@remote> telnet
    telnet>
    

    【讨论】:

      【解决方案5】:

      团队:

      这是我的方法.....

      我创建了一个包含已接受命令列表的小脚本,并根据命令控制执行以避免出现问题。我不确定它是否在问题的范围内。示例代码在 Windows 中有命令,但您也可以在 Linux 中使用它...

      <?php
      ini_set('display_errors',1); 
      error_reporting(E_ALL);
      
      function executeCommand($my_command){
          $commandExclusions = array ('format', 'del');
      
          if (in_array(strtolower($my_command),$commandExclusions)) {
              echo "Sorry, <strong>".$my_command." </strong> command is not allowed";
              exit();
          }
          else{
              echo exec($my_command, $result, $errorCode);
              implode("n", $result);
          }
      }
      echo "<h3>Is it possible to restrict what commands php can pass through exec at an OS level?</h3><br>";
      echo "********************************<br>";
      //test of an accepted command
      echo "test of an accepted command:<br>";
      executeCommand("dir");
      echo "<br>********************************<br>";
      echo "test of an unaccepted command:<br>";
      //test of an unaccepted command
      executeCommand("format");
      echo "<br>********************************<br>";
      ?>
      

      输出:

      是否可以在操作系统级别限制 php 可以通过 exec 传递的命令?


      测试接受的命令: 117 Dir(s) 11,937,468,416 字节空闲


      测试未接受的命令: 抱歉,不允许使用格式化命令

      【讨论】:

      • 嗨 Joel,如果我可以控制所有第三方模块,这种方法会起作用,但是其中许多已经在调用像 exec() 这样的不安全函数,我不会更改(分叉)那些模块。
      • 如果有人闯入并在里面注入他自己的带有 exec() 的 PHP 脚本,这将无济于事。
      猜你喜欢
      • 2010-12-31
      • 2015-02-17
      • 2023-04-08
      • 1970-01-01
      • 2013-07-23
      • 1970-01-01
      • 1970-01-01
      • 2016-10-27
      • 1970-01-01
      相关资源
      最近更新 更多