在 PHP 中使用参数向量调用程序
Invoke a program using argument vector in PHP
PHP中用于执行外部程序的函数将单个整体命令字符串作为其参数。稍微不注意转义参数字符串可能会导致命令注入。
在PHP7.4到proc_open
中增加了参数向量特征,对于普通使用来说太复杂了。那么,有没有更简单的方法来调用带有参数向量的外部程序?
此方法仅限于 PHP 运行 POSIX 系统
system
、popen
等函数,无论是在 PHP 还是 C & POSIX 的上下文中,都决不会采用合成的命令字符串。所以设计这样一个函数的思考过程应该从一个常量值的命令字符串开始。
其次,PHP 确实提供了像 C 一样设置单个环境变量的功能(尽管之后不会取消设置),并且此功能在很大程度上不受注入相关攻击的影响。所以我们可以构建一个带环境变量的命令,assemble一个命令向量,然后调用exec
shell内置命令。
完整代码如下:
<?php
$spawncmd = <<<'EOF'
set --
n=0
while [ $n -lt $execargc ] ; do
eval "set -- \"$@\" \"$execarg$n\""
unset -v execarg$n
n=$((n+1))
done
unset -v execargc
exec "$@"
EOF;
// Invokes external program and return its output.
function spawn($args)
{
global $spawncmd;
putenv("execargc=".count($args));
for($i=0; $i<count($args); $i++)
putenv("execarg$i=".$args[$i]);
$ret = shell_exec($spawncmd);
putenv("execargc=");
for($i=0; $i<count($args); $i++)
putenv("execarg$i=");
return $ret;
}
// Invokes external program and return its exit status.
function catspawn($args)
{
global $spawncmd;
putenv("execargc=".count($args));
for($i=0; $i<count($args); $i++)
putenv("execarg$i=".$args[$i]);
$ret = null;
passthru($spawncmd, $ret);
putenv("execargc=");
for($i=0; $i<count($args); $i++)
putenv("execarg$i=");
return $ret;
}
// Argument vector version of popen.
function pspawn($args, $mode)
{
global $spawncmd;
putenv("execargc=".count($args));
for($i=0; $i<count($args); $i++)
putenv("execarg$i=".$args[$i]);
$ret = popen($spawncmd, $mode);
putenv("execargc=");
for($i=0; $i<count($args); $i++)
putenv("execarg$i=");
return $ret;
}
PHP中用于执行外部程序的函数将单个整体命令字符串作为其参数。稍微不注意转义参数字符串可能会导致命令注入。
在PHP7.4到proc_open
中增加了参数向量特征,对于普通使用来说太复杂了。那么,有没有更简单的方法来调用带有参数向量的外部程序?
此方法仅限于 PHP 运行 POSIX 系统
system
、popen
等函数,无论是在 PHP 还是 C & POSIX 的上下文中,都决不会采用合成的命令字符串。所以设计这样一个函数的思考过程应该从一个常量值的命令字符串开始。
其次,PHP 确实提供了像 C 一样设置单个环境变量的功能(尽管之后不会取消设置),并且此功能在很大程度上不受注入相关攻击的影响。所以我们可以构建一个带环境变量的命令,assemble一个命令向量,然后调用exec
shell内置命令。
完整代码如下:
<?php
$spawncmd = <<<'EOF'
set --
n=0
while [ $n -lt $execargc ] ; do
eval "set -- \"$@\" \"$execarg$n\""
unset -v execarg$n
n=$((n+1))
done
unset -v execargc
exec "$@"
EOF;
// Invokes external program and return its output.
function spawn($args)
{
global $spawncmd;
putenv("execargc=".count($args));
for($i=0; $i<count($args); $i++)
putenv("execarg$i=".$args[$i]);
$ret = shell_exec($spawncmd);
putenv("execargc=");
for($i=0; $i<count($args); $i++)
putenv("execarg$i=");
return $ret;
}
// Invokes external program and return its exit status.
function catspawn($args)
{
global $spawncmd;
putenv("execargc=".count($args));
for($i=0; $i<count($args); $i++)
putenv("execarg$i=".$args[$i]);
$ret = null;
passthru($spawncmd, $ret);
putenv("execargc=");
for($i=0; $i<count($args); $i++)
putenv("execarg$i=");
return $ret;
}
// Argument vector version of popen.
function pspawn($args, $mode)
{
global $spawncmd;
putenv("execargc=".count($args));
for($i=0; $i<count($args); $i++)
putenv("execarg$i=".$args[$i]);
$ret = popen($spawncmd, $mode);
putenv("execargc=");
for($i=0; $i<count($args); $i++)
putenv("execarg$i=");
return $ret;
}