本文记录 PHP 代码审计的学习过程,教程为暗月 2015 版的 PHP 代码审计课程
1. 简介
-
PHP 执行系统命令可以使用以下几个函数
system、exec、passthru、``反引号、shell_exec、popen、proc_open、pcntl_exec
string system ( string $command [, int &$return_var ] ) string exec ( string $command [, array &$output [, int &$return_var ]] ) void passthru (string command, int &return_var) string shell_exec (string command) `` 反引号 resource popen ( string $command , string $mode ) resource proc_open ( string $cmd , array $descriptorspec , array &$pipes [, string $cwd [, array $env [, array $other_options ]]] ) void pcntl_exec ( string $path [, array $args [, array $envs ]] )
-
防御函数
当用户提供的数据传入此函数,使用 escapeshellarg() 或 escapeshellcmd() 来确保用户欺骗系统从而执行任意命令。
2. 系统命令执行函数示例
-
system() 函数
system函数可以用来执行一个外部的应用程序并将相应的执行结果输出,函数原型如下:
string system(string command, int &return_var)
<?php $action = $_GET['cmd']; echo "<pre>"; system($action); echo "<pre/>"; ?>
-
exec() 函数
Exec:exec函数可以用来执行一个外部的应用程序,函数原型如下:
string exec (string command, array &output, int &return_var)
<?php $action = $_GET['cmd']; echo "<pre>"; echo exec($action); echo "<pre/>"; ?>
-
passthru() 函数
passthru函数可以用来执行一个UNIX系统命令并显示原始的输出,当UNIX系统命令的输出是二进制的数据,并且需要直接返回值给浏览器时,需要使用passthru函数来替代system与exec函数。Passthru数原型如下:
void passthru (string command, int &return_var)
其中,command是要执行的命令,return_var存放执行命令后的状态值。
<?php $action = $_GET['cmd']; echo "<pre>"; passthru($action); echo "<pre/>"; ?>
-
shell_exec() 函数
执行shell命令并返回输出的字符串,函数原型如下:
string shell_exec (string command)
<?php $action = $_GET['cmd']; echo "<pre>"; echo shell_exec($action); echo "<pre/>"; ?>
-
反引号
与shell_exec功能相同,执行shell命令并返回输出的字符串。
<?php $action = $_GET['cmd']; echo "<pre>"; echo `$action`; echo "<pre/>"; ?>
-
popen() 函数
<?php $action = $_GET['cmd']; echo "<pre>"; echo popen($action,'r'); echo "<pre/>"; ?>
-
proc_popen() 函数
用于执行一个命令,并且打开用来输入/输出的文件指针。与popen()函数类似,但是 proc_open()提供了更加强大的控制程序执行的能力。
resource proc_open ( string $cmd , array KaTeX parse error: Expected 'EOF', got '&' at position 24: …orspec , array &̲pipes [, string $cwd [, array $env])
-
pcntl_exec() 函数
pcntl_exec函数在当前进程空间执行指定程序。当发生错误时返回 FALSE,没有错误时没有返回。
void pcntl_exec ( string $path [, array $args [, array $envs ]] )
其中,path必须是可执行二进制文件路径或一个在文件第一行指定了一个可执行文件路径标头的脚本;args是一个要传递给程序的参数的字符串数组;envs是一个要传递给程序作为环境变量的字符串数组。这个数组是 key => value格式的,key代表要传递的环境变量的名称,value代表该环境变量值。
3. 防御函数示例
当用户提供的数据传入此函数,使用escapeshellarg() 或escapeshellcmd() 来确保用户欺骗系统从而执行任意命令。
-
escapeshellarg() 函数
该函数把字符串转码为可以在shell命令里使用的参数。escapeshellarg()将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入shell函数,并且还是确保安全的。对于用户输入的部分参数就应该使用这个函数。可以用到php的安全中,会过滤掉arg中存在的一些特殊字符。在输入的参数中如果包含中文传递给escapeshellarg,会被过滤掉。
<?php $action = $_GET['cmd']; echo "<pre>"; echo shell_exec($action); echo "<pre/>"; ?> 执行 http://127.0.0.1/test.php?cmd=echo "123" >> 123.txt 有生成文件 123.txt
<?php $action = $_GET['cmd']; echo "<pre>"; echo shell_exec(escapeshellarg($action)); echo "<pre/>"; ?>
执行 http://127.0.0.1/test.php?cmd=echo “123” >> 123.txt 无生成文件
-
escapeshellcmd() 函数
除去字符串中的特殊符号,会转义命令中的所有shell元字符来完成工作
这些元字符包括:# & ;``,| * ? ~ < > ^ ( ) [ ] { } $ \
<?php $action = $_GET['cmd']; echo "<pre>"; echo shell_exec(escapeshellcmd($action)); echo "<pre/>"; ?>
-
DVWA 中使用的是 stripslashes() 函数
stripslashes() 函数删除由 addslashes() 函数添加的反斜杠。
提示:该函数可用于清理从数据库中或者从 HTML 表单中取回的数据实例: <?php echo stripslashes("Who\'s Bill Gates?"); ?>