【问题标题】:Is this specific path concatenation in Perl code exploitable?Perl 代码中的这种特定路径连接是否可利用?
【发布时间】:2010-12-16 14:09:07
【问题描述】:

假设攻击者控制变量$untrusted_user_supplied_path。下面的 Perl 代码可以利用吗?

my $untrusted_user_supplied_path = ...
if ($untrusted_user_supplied_path =~ /\.\./) {
  die("Tries to escape homedir.");
}
my $base_path = "/home/username/";
my $full_path = "${base_path}${untrusted_user_supplied_path}";
if (-e $full_path) {
  open(FILE, "<", $full_path) || die("File not accessible.");
  while (<FILE>) {
    # present the content to the user
  }
  close(FILE);
}

如果攻击者可以选择$untrusted_user_supplied_path 的值以便他/她可以读取驻留在不是$base_path 子目录的目录中的文件(比如/etc/passwd )?

您可以假设代码在 Linux 下运行。此外,您可以假设将文件呈现给用户的代码中没有引入其他缺陷。

请注意,问题是关于代码是否是 可利用,而不是如何使代码更安全。有无数 使代码更安全的方法(想想chroot等)但那是 超出了这个问题的范围。如果你在你的答案中说明 相信代码是否可利用。当然,请 提供支持性论据。

【问题讨论】:

  • 这个问题其实和 Perl 没有任何关系,而是和文件系统安全以及如何指定目录路径有关。
  • 那么,我认为链接应该是您唯一关心的问题。
  • 为什么会被如此多地否决? (目前:-3)
  • 我看不出有什么理由不赞成这一点。 +1
  • OP 似乎对回答他问题的人很刻薄。无论是否合适,这几乎总是会让你投反对票。我个人很想将此作为“不是一个真正的问题”来结束,但由于人们正在回答它,我想这是一个真正的问题。

标签: regex linux perl security filesystems


【解决方案1】:

您是在询问您的代码是否可被利用。是的。所有代码都是可利用的。你可能不认为这是因为你认为你已经涵盖了你能想到的情况,但对方通常会找到你没有想到的情况。但是,我总是说所有的枪都上膛了。

安全不仅仅是代码。您必须考虑它运行它的环境,用户在运行您的代码之前还可以做什么,等等。

如果您真的担心此代码可能会发生什么,请创建一个风险矩阵。从您担心的部分开始,并列出所有假设。例如,在您的情况下,您可以从:

  • /home/username 是我认为的目录(即不是挂载点、符号链接、假用户等)
  • 提供的路径是我期望的并且允许存在的路径
  • 路径是常规文件(例如,不是特殊设备)
  • 路径具有特定的所有者、组或模式
  • 我正在运行 perl 我想我是(在查找可执行文件时没有路径攻击)
  • PERL5LIBPERL5OPT-I 没有预先加载模块加载路径(在查找模块时没有路径攻击)

等等等等。一旦你建立了所有的假设,你就可以通过锁定这些案例来确保它们是有效的。您还可以找到他们的所有假设,并锁定这些假设,等等。 Perl 的taint checking 将帮助解决其中的一些问题(我在Mastering Perl 中更深入地讨论了它)。

成功的攻击通常是间接的。例如,我在一家非常富有和偏执的银行中负责保护一些数据。我们做了我们能做的所有计算机工作,我的一位同事在闲聊中问他们在我们安装服务器之前是如何完成任务的。他们说,“哦,数据在某某办公桌上的活页夹上”。尽管我们付出了所有的工作、他们的薪水以及每个人的时间和精力,但无论我们对服务器做了什么,内部任何想要数据的人都可以毫不犹豫地离开。

既然您已经有了风险矩阵,那么您就可以开始培养自己的风险承受能力了。没有什么是完美的,你可以工作到宇宙的热死,把一切都锁起来。您不是完美无缺,而是满足于您愿意为代码的每个部分承担多少风险。您会弄清楚如果某个部分受到损害会发生什么,以及这将花费您多少(以美元、声誉等为单位),并弄清楚对您(或您的雇主)有价值的工作。您所做的工作刚好低于您的风险承受能力。

问题是,即使是最优秀的人也会错过一些东西。安全上的小漏洞可能看起来并不那么重要,但如果你把足够多的放在一起,你最终可以引导自己进入一个可利用的情况。安全是整体的。

【讨论】:

  • 感谢布赖恩的回答!像往常一样写得很好。我真的很喜欢你的 perl 答案。
【解决方案2】:

如果 homedir 中存在指向外部某个地方的符号链接,那么您仍然有麻烦。

【讨论】:

    【解决方案3】:

    在我看来这很合理,虽然你的测试有点苛刻。您可能需要考虑更换:

    /\.\./
    

    与:

    m{/\.\./}
    

    允许访问包含两个点的文件和目录。它仍然不允许像 dir1/../dir2/filename 这样复杂但可能有效的访问,尽管您可能不会太担心这一点。

    【讨论】:

    • 蒂姆,感谢您的回答。我将其解析为“不,该代码不可利用”——对吗? :-)
    • 我不会准备那么自信,但我会对这段代码感到满意,直到有人能指出我错过的问题。 :-)
    • 实际上,很大程度上取决于您如何“读取文件 $full_path”以及您是否仔细阅读。除了其他检查,考虑使用污染检查perldoc.perl.org/5.8.8/perlsec.htmlopenperldoc.perl.org/5.8.8/functions/open.html的树形参数形式
    • 注意Windows下三点也是目录遍历。
    • 你看,这就是我担心的那种评论。 :-)
    【解决方案4】:

    我要违反你的家规,建议你这样做:

    use Cwd;
    my $full_path = "${canonical_base_path}${untrusted_user_supplied_path}";
    my $canonical_full_path = abs_path($full_path);
    if (substr($canonical_full_path, 0, length($base_path)) != $base_path) {
          die("Tries to escape homedir.");
    }
    

    这应该是防水的。不过,它确实要求 $base_path 是规范的。

    【讨论】:

    • 对不起,但这不是对所提问题的回答。如果我问“如何改进此代码”,那么我会将您的消息标记为正确答案。
    • 你的!=不应该是ne吗?
    • 什么数学比较? $base_path 是“/home/username”。代码试图确保 $base_path 位于字符串的开头(尽管使用 index(...) == 0 更容易和更清晰)。
    • 恐怕我的 perl 生锈了。我主要做 shell 脚本,其中 != 用于字符串,-ne 用于数字 - 如果它在 perl 中是相反的,那么是的,那应该是 -ne。
    【解决方案5】:

    它是否可利用取决于将文件呈现给用户的代码。该代码中不必有“缺陷”,而是有机会做您没有想到的事情。

    【讨论】:

    • 您可以假设将文件呈现给用户的代码中没有引入其他缺陷。鉴于这个假设,你的答案是什么?
    • 其实不是“瑕疵”的问题。
    • 问题很清楚,这不是答案。
    • 它并没有你想象的那么简单。
    • “你可以假设没有额外的缺陷”我听说过很多次,它总是意味着“其他一切都非常不安全,我们将希望寄托在这一行代码上。 "
    猜你喜欢
    • 2020-04-19
    • 1970-01-01
    • 1970-01-01
    • 2014-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多