【问题标题】:How does one provide IPC::Run with an argument set by user input that contains embedded whitespace如何为 IPC::Run 提供由用户输入设置的包含嵌入式空格的参数
【发布时间】:2017-03-08 00:26:23
【问题描述】:

centos-6.8 perl, v5.10.1 (*) 为 x86_64-linux-thread-multi 构建

这个问题来自这个Where is the shell command called which invokes OpenSSL commands?。简而言之,我正在破解一个非常古老的 Perl 脚本,用于维护内部私有 PKI,以便默认签名哈希和密钥大小满足当前浏览器的要求。

我有这些sn-ps的代码:

. . .    
$args->{keypass} = $self->getPassword("Private key password",1)
  unless $args->{keypass};    
$self->warn("# Password argument: $args->{keypass}\n") if $ENV{CSPDEBUG};
my $cmd = "-out $args->{keyfile} $args->{keysize}";
$cmd = "-des3 -passout pass:$args->{keypass} ".$cmd if defined($args->{keypass});
$self->{openssl}->cmd('genrsa',$cmd,$args);
. . .
$self->{openssl}->cmd('req',"-x509 $common_args -new -out $cacert",$args);
. . .
use IPC::Run qw( start pump finish timeout new_appender new_chunker);
. . .
sub cmd
  {
    my $self = shift;
    my $cmd = shift;
    my $cmdline = shift;
    my $args = shift;
    my $conf;
    my $cfgcmd;
. . .
    $self->{_handle}->pump while length ${$self->{_in}};
. . .

如果用户提供的密码参数值不包含空格,则此代码将按需要执行。如果它确实包含嵌入的空白,则代码会静默失败。如果传递给 keypass 的参数与开始和结束单引号连接,则代码同样会静默失败。在这两种失败情况下,脚本仍然报告成功。

为什么?

无论用户输入是否包含空格,都需要进行哪些更改才能使此代码正常工作?

【问题讨论】:

  • 让我正确地回答问题,您正试图消除密码字段中的任何空格以确保其正常工作?或者专门让它工作,即使密码中有空格?
  • @user2082599 来自上一个问题和这里的描述,我相信密码可能包含空格。如果是这样,程序将失败,因为空格在命令行参数中丢失了。并且引用它不起作用。
  • @James 您能否突出显示哪个参数是密码?我不清楚。
  • @simbabque:我很确定是$args->{keypass}
  • 顺便说一句,注意在命令行上传递密码通常被认为是不安全的:如果任何不受信任的用户可以在同一台服务器上运行代码(即使在非特权帐户下),他们只需运行即可看到密码ps axopenssl manual 注意到了这一点,并警告 pass:“只能在安全性不重要的情况下使用。”

标签: perl openssl centos6


【解决方案1】:

要回答你的字面问题,让我quote the IPC::Run manual

"run()start()harness() 都可以将线束规范作为输入。线束规范可以是要传递给系统外壳 [...] 的单个字符串,也可以是命令列表, io 操作,和/或要执行的计时器/超时。”

为了防止 shell 解析命令参数(当参数包含空格时,这会导致事情中断),您不应将它们作为单个字符串传递,而应作为对包含每个单独参数的数组的引用作为单个字符串,如下所示:

my @cmd = ("-out", $args->{keyfile}, $args->{keysize});
unshift @cmd, ("-des3", "-passout", "pass:$args->{keypass}") if defined $args->{keypass};
# ...
my $h = start ["openssl", "genrsa", @cmd], \$in, \$out;  # or something equivalent

(您发布的代码似乎是通过一些自定义接口层使用 IPC::Run;由于您没有向我们展示该层的确切外观,因此我已将其替换为对 IPC 的简单调用: :Run::start。)


在任何情况下,请注意在命令行上传递密码通常被认为是不安全的:如果任何不受信任的用户可以在同一台服务器上运行代码(即使在非特权帐户下),他们只需运行 ps ax 就可以看到密码. openssl manual 注意到了这一点,并警告 pass:<i>password</i>“只能在安全性不重要的情况下使用。”

更安全的选择是send the password over a separate file descriptor。方便的是,IPC::Run 使这变得非常简单:

my @cmd = ("-out", $args->{keyfile}, $args->{keysize});
unshift @cmd, ("-des3", "-passout", "fd:3") if defined $args->{keypass};
# ...
my $h = start ["openssl", "genrsa", @cmd], '<', \$in, '>', \$out, '3<', \$args->{keypass};

这里,密码通过文件描述符 3 传递;如果您需要传递多个密码,您可以使用文件描述符 4、5 等。 (描述符 0、1 和 2 是 stdin、stdout 和 stderr。)

免责声明:这显然是所有未经测试的代码。我不是 IPC::Run 方面的专家,所以我可能犯了一些愚蠢的命令语法错误或其他错误。使用前请彻底测试!

【讨论】:

  • 我遇到的困难是这一切对我来说都很陌生。我正在破解一个非常古老的第三方脚本,该脚本是用一种我只粗略了解的语言编写的;并且其原作者已经继续并放弃了它。我需要对密钥大小的默认值进行一些小的更改,并更改签名哈希算法以满足当前的期望。对我来说不幸的是,我偶然发现了这个问题,我想得到一个合适的解决方案。简单的解决方法是不要使用带有空格的密码短语。但这似乎是错误的。
  • @JamesB.Byrne:不幸的是,您需要修改的一些部分在您的问题中用. . . 替换的代码中。具体来说,大概有一个 IPC::Run start() 调用在那里您需要修改以获取数组引用而不是字符串。这可能至少需要对 Perl 有基本的了解。如果你没有这些,你的选择基本上是 1) 拿一本好的 Perl 入门书并学习,2) 找一个比你了解更多 Perl 的人,或者 3) 放弃,记录错误并继续前进。
  • 首先我需要建立我们的替代 PKI。目前看来这不会是一个问题,因为我似乎已经克服或避开了我遇到的障碍。在我找到时间之前,不可能重写代码以将整个程序从字符串参数切换到数组参数,而这种资源供应很少。我可以直接使用 openssl 更改密钥上的密码短语,这会给出所需的结果并避免重新编程脚本——这个过程无疑会发现其他缺陷。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-10
  • 1970-01-01
  • 2022-12-21
  • 2020-06-18
  • 1970-01-01
  • 2020-12-30
相关资源
最近更新 更多