安全地访问由环境variables标识的目录中的文件?

任何人都可以指向一些代码来处理文件访问的安全性,通过一个环境variables指定的path(特别是Unix和它的变体),但Windows解决scheme也是有趣的吗?

这是一个很长的问题 – 我不确定它是否适合SO范式。

考虑这种情况:

背景:

  • 软件包PQR可以安装在用户select的位置。
  • 环境variables$ PQRHOME用于标识安装目录。
  • 默认情况下,$ PQRHOME下的所有程序和文件都属于一个特殊的组pqrgrp。
  • 同样,$ PQRHOME下的所有程序和文件属于特殊用户pqrusr,或者属于root用户(以及那些是SUID根程序)。
  • 一些程序是SUID pqrusr; 更多的程序是SGID pqrgrp。
  • 大多数目录归pqrusr所有,属于pqrgrp; 一些可以属于其他组,并且这些组的成员通过软件获得额外的权限。
  • 许多特权可执行文件必须由不是pqrgrp成员的人员运行; 程序必须validation用户被允许通过不直接涉及这个问题的奥术规则运行它。
  • 启动后,一些特权程序必须保留其提升的特权,因为它们是长期运行的守护进程,可能代表许多用户在其整个生命周期中运行。
  • 由于种种原因,程序无权将目录更改为$ PQRHOME。

目前的检查:

  • 程序目前检查$ PQRHOME及其下的关键目录是否安全(由pqrusr拥有,属于pqrgrp,没有公共写权限)。
  • 之后,程序通过环境variables的全部值访问$ PQRHOME下的文件。
  • 特别是,G11N和L10N是通过访问“安全”目录中的文件,并从这些目录中的文件中读取printf()等格式string,使用从$ PQRHOME派生的完整path名加上已知的子结构例如,$ PQRHOME / g11n / en_us / messages.l10n)。

假定$ PQRHOME的'as installed'值是/ opt / pqr。

已知的攻击:

  • 攻击者设置PQRHOME = / home / attacker / pqr。
  • 这实际上是/ opt / pqr的符号链接,所以当其中一个PQR程序调用pqr-victim,检查目录时,它具有正确的权限。
  • 在安全检查成功完成之后,攻击者立即改变符号链接,使其指向/ home / attacker / bogus-pqr,这明显处于攻击者的控制之下。
  • 当pqr-victim现在在所谓的安全目录下访问一个文件时,会发生可怕的事情。

鉴于PQR目前的行为如上所述,并且是一个大型的软件包(数十万行代码,十多年来发展到各种编码标准,无论如何都经常被忽略),您将使用什么技术来修复问题?

已知的选项包括:

  1. 更改所有的格式化调用,使用函数来检查格式string的实际参数,并使用一个额外的参数来指示传递给函数的实际types。 (这是非常棘手的问题,由于需要更改格式化操作的数量,所以很容易出错,但是如果检查function本身就很好,那么效果很好。)
  2. build立PQRHOME的直接path并validation它的安全性(下面的细节),如果不安全则拒绝启动,之后使用直接path而不是$ PQRHOME的值(当它们不同时)。 (这要求使用$ PQRHOME的所有文件操作不使用getenv()的值,而是使用映射的path。例如,这需要软件确定/ home / attacker / pqr是/ opt / pqr的符号链接,那么到/ opt / pqr的path是安全的,此后,无论何时文件被引用为$ PQRHOME / some / thing,所使用的名称将是/ opt / pqr / some / thing,而不是/ home / attacker / pqr / some /东西,这是一个庞大的代码库 – 不是微不足道的。
  3. 确保$ PQRHOME上的所有目录(即使通过符号链接进行跟踪)都是安全的(下面再详细介绍),如果有任何不安全的情况,软件会拒绝启动。
  4. 硬编码到软件安装位置的path。 (PQR不会起作用;如果没有其他的话,它就会进行testing,对于用户来说,这意味着他们只能安装一个版本,升级等需要并行运行,这对PQR来说是行不通的。

build议的安全path标准:

  • 对于每个目录,所有者必须是可信的。 ( 原理:所有者可以随时更改权限,因此必须信任所有者不要随意进行更改,以免破坏软件的安全性。
  • 对于每个目录,组必须没有写权限(因此组的成员不能修改目录内容),或者该组必须是可信的。 ( 理由:如果小组成员可以修改目录,那么他们可以破坏软件的安全,所以他们必须不能改变它,否则他们必须被信任而不能改变它。
  • 对于每个目录,“他人”必须对该目录没有写权限。
  • 默认情况下,可以信任用户root,bin,sys和pqrusr(其中bin和sys存在)。
  • 默认情况下,GID = 0的组(可以称为root,wheel或system),bin,sys和pqrgrp都是可信的。 此外,拥有根目录(在MacOS X上称为admin)的组可以被信任。

POSIX函数realpath()提供了一个映射服务,它将/ home / attacker / pqr映射到/ opt / pqr; 它不会执行安全检查,但只需要在已解决的path上完成。

那么,以这些背景为基础,是否有任何已知的软件会经历模糊的旋转以确保其安全? 这是过分偏执吗? (如果是这样,为什么 – 你确定吗?)

编辑:

感谢各种意见。

@ S.Lott:攻击(在问题中概述)意味着至less有一个setuid root程序可以使用(非特权)用户select的格式string,并且至less可以使程序崩溃,因此最有可能获取一个root shell。 幸运的是,它需要本地shell访问。 这不是一个远程攻击。 它需要一个不可忽视的数量的知识才能到达那里,但我认为假设专业知识不是“在那里”是不明智的。

所以,我所描述的是一个“格式化string漏洞”,已知的攻击path包括伪造程序,所以尽pipe它认为它正在访问安全的消息文件,但实际上它会使用消息文件(包含格式string)在用户的控制下,不在软件的控制下。

如果您在解析其真实路径并检查其安全性后为$PQRHOME写入新值,则选项2将起作用。 这样你的代码很少需要改变。

就保持setuid特权而言,如果你可以做某种特权分离,这将有所帮助,这样任何涉及真实用户输入的操作都会在真实的uid下运行。 然后特权进程和真实用户进程使用socketpair或类似的东西进行交谈。

好吧,这听起来是偏执的,但是如果是的话,取决于你的应用程序在哪个系统上运行,以及攻击者可以造成哪些破坏。

所以,如果你的用户基础可能是敌对的,如果损害可能很高,我会去选项4,但修改如下,以消除其缺点。

让我引用两个相关的东西:

1)

程序目前检查$ PQRHOME及其下的关键目录是否安全(由pqrusr拥有,属于pqrgrp,没有公共写权限)。

2)

之后,程序通过环境变量的全部值访问$ PQRHOME下的文件。

您不需要实际硬编码完整路径,您可以硬编码从1)中提到的“程序”到2)文件所在路径中的相对路径。

问题来控制:

a)您必须确保在可执行文件路径和文件路径之间没有任何“攻击者可访问”(例如,符号链接)

b)你必须确保可执行文件以可靠的方式检查自己的路径,但是在我所知道的所有Unix中,这不应该是一个问题(但是我不知道他们是谁,我也不知道windows在所有)。


在第三条评论之后编辑:

如果你的操作系统支持/ proc,syslink / proc / $ {pid} / exe是解决问题的最好方法。b)


睡觉后编辑:

安装过程是否安全? 如果是这样,你可以创建(在安装时)包装脚本。 这个脚本应该是可执行的,但不可写(也可能不可读)。 它会将$ PQRHOME env var设置为“安全”值,然后调用您的实际程序(最终可能还会做其他有用的事情)。 由于在UNIX中,正在运行的进程的环境除了运行的进程之外不能被其他任何东西改变,所以你是安全的(当然,在进程启动之前 ,环境可以被父进程改变)。 不过,我不知道这种方法是否可以在Windows中使用。