3

这是我的计算机安全课的作业,所以我不需要具体的答案,但我想要一些建议或至少是大致的方向,因为我已经绕了一段时间了。

基本上,我们有一个任务,我们得到了一个简单的 cgi 应用程序(用 perl 编写),它在某个地方存在一个漏洞,允许用户查看他们不应该查看的私有文件,如 /etc/shadow。我们基本上必须证明我们可以攻击它并查看 /etc/shadow 文件。该应用程序是一个备忘录查看程序,可让用户编写和阅读备忘录。

现在,我对 Perl 很陌生。很久以前,我确实将它用于非常简单的网络内容一两次,但这实际上是基础知识。

有问题的代码

#!/usr/bin/perl -w

use CGI qw(:standard);
use CGI::Carp qw(fatalsToBrowser);
use strict;

my %labels; # global of pretty labels for memo pathnames

# glob through the homedirs for an array of paths to memos sorted by date
sub list_memo_selector {
        my @memos = </home/*/memo/*>; # all regular users
        push (@memos, </root/memo/*>); # special memos from root
        foreach (@memos) {
                $_ =~ m#^.+/([^/]+)$#; # regex extract filename
                my $temp = $1;
                $temp =~ s/_/ /g; # convert _ to " "
                $labels{$_} = $temp; # assign pretty label name
        }
        print popup_menu(-name=>'memo', -values=>\@memos, -labels=>\%labels);
        print submit("Read memo");
}

print header();
print "<html><head><title></title></head><body>\n";

print h1("FrobozzCo Memo Distribution Website");
print h4("Got Memo?");
print hr();

print p('Select a memo from the popup menu below and click the "Read memo" button.');
print p("<form method='post' name='main'>\n");

if (!param('memo')) {
        list_memo_selector();
} else { # there is a memo selected
        list_memo_selector();
        my $memo = param('memo');
        my $author = "root";
        my @stat = stat $memo;
        my $date = localtime $stat[9];
        if ($memo =~ m#^/home/([^/]+)/.*$#) {
                $author = $1;
        }
        print "<hr>\n";
        print "<blockquote>";
        print '<table border=1><tr><td>';
        print "<center><b>$labels{$memo}</b></center>";
        print '</td></tr>';
        print "<tr><td>\n<p>";
        print "<b>Author:</b> $author<br />\n";
        print "<b>Subject:</b> $labels{$memo}<br />";
        print "<b>Date:</b> $date<br />\n";
        print "\n</p></td></tr>\n";
        print "<tr><td><p>&nbsp;</p>\n";
        print "<blockquote><p>\n";

        open (MEMO, $memo);

        foreach (<MEMO>) {
                $_ =~ s#\n$#</p><p>#; # HTMLize newlines for formatting
                print "$_\n";
        }
        print "</p></blockquote>\n";
        print '<p>&nbsp;</p></td></tr></table>';
        print "</blockquote>";
        print "<hr>\n";
}


print h2("To publish a memo:");
print <<TEXT;

<ol>
<li>Create a directory named 'memo' in your home directory.</li>
<li>Edit text files in that directory.</li>
<li>Save the file using underscores (_) for spaces, e.g. "free_lunch".</li>
</ol>

TEXT

print p('To remove your memo from publication, simply delete the file from tme memo directory.');

print "</form>\n";
print "</body></html>";

我认为关键是程序调用 open(MEMO, $memo) 而不检查用户的输入,所以如果你可以将它指向 /etc/shadow 程序只会打印出影子文件。

问题是,目前它只列出来自 home/*/memo 或 /root/memo 的文件。我一直在试图弄清楚如何指向其他地方。我认为这与我们可以创建自己的备忘录(通过在我们的 homedir 中创建一个名为 memo 的目录)这一事实有关。但是我不太清楚我需要在备忘录中放什么才能让程序打开 /etc/shadow 。

有谁知道我是在正确的轨道上还是完全错过了另一个明显的错误?

4

1 回答 1

4

你错过了明显的错误。

创建一个弹出菜单来指定一个memo值,但没有强制用户只指定一个预填充的值。他们可以指定任何东西。

甚至没有强制执行 POST 请求方法,因此编辑 URL 中的表单参数就足以指定一个值:

http://www.yourdomain.com/form.cgi?memo=/etc/naughty/boy

验证

为了避免攻击,必须通过以下任一方式验证数据是否在我们预期的值范围内:

  1. 重用用于填充 popup_menu 和比较的值。
  2. 使用正则表达式匹配预期格式。

最不可能引入新错误的是重用原始值。这是因为很容易使正则表达式不够严格。例如,允许将 updir..包含在某处的路径中。

此外,open调用时应该使用 3 参数形式以及词法文件句柄。我们不想让用户指定打开文件的模式。

open my $fh, '<', $memo or die "Can't open $memo: $!";
于 2014-05-15T00:01:09.190 回答