PhP 执行 Linux Shell 命令

PhP 可以执行一些简单的 Shell 命令,下面是一个带白名单的 Shell 命令执行 Demo,返回 JSON。

核心为 exec 函数,注意对外部命令进行转义。

Shell.class.php

<?
/**
 * Linux shell in php
 *
 * @author YanWen <i@yanwen.email>
 * @date 2018-04-22
 */

/**
 * @class Shell
 */
class Shell
{
  protected $config = [
    'white_host' => [
      # valid host name
      'localhost',
      'localhost:8888',
    ],
    'white_ip' => [
      # valid remote ip
      '::1',
      '127.0.0.1',
    ],
    'valid_pattern' => [
      # reg exps of legal commands
      '@.*@i',
    ]
  ];

  private $command;

  private $output_arr;
  private $returned_val;

  function __construct(array $config = null)
  {
    $this->config = $config ? $config : $this->config;
  }

  # private
  /**
   * @return
   */
  private function is_valid()
  {
    $host_filter = array_filter($this->config['white_host'], function (string $host) {
      return $_SERVER['HTTP_HOST'] === $host;
    });

    $ip_filter = array_filter($this->config['white_ip'], function (string $ip) {
      return $_SERVER['REMOTE_ADDR'] === $ip;
    });

    $pattern_filter = preg_filter($this->config['valid_pattern'], null, [ $this->command ]);

    return !!(sizeof($host_filter) and sizeof($ip_filter) and sizeof($pattern_filter));
  }

  /**
   *
   */
  private function exec()
  {
    # split command
    $command_as_list = preg_split('@s+@', $this->command, 2);

    # escape and exec
    exec(
      escapeshellcmd($command_as_list[0]) . ' ' . (
        sizeof($command_as_list) === 1 ? '' :  escapeshellarg($command_as_list[1])
      ),
      $this->output_arr,
      $this->returned_val
    );
  }

  # protected
  /**
   * Determine whether exec request is legal, execute the command if it is legal
   *
   * @param {string} $command
   * @throw Exception
   */
  protected function run(string $command)
  {
    $this->command = $command;

    if (!$this->is_valid()) throw new Exception('Command is illegal or the ip/host is not allowd.');

    $this->exec();
  }

  /**
   * response json
   *
   * @param {string} $command
   * @return {json}
   */
  public function response(string $command)
  {
    try {
      $this->run($command);

      return json_encode([
        'status'  => 0,                    # NOTE: 0 means ok
        'message' => 'ok',
        'data'    => [
          'return' => $this->returned_val,
          'output' => $this->output_arr
        ]
      ]);
    } catch (Exception | Error $e) {
      return json_encode([
        'status'  => 1,                    # NOTE: 1 means error
        'message' => $e,
        'data'    => null
      ]);
    }
  }

}

?>

index.php

<?
/**
 *
 * send -> GET/ {cmd: ...}
 * recv <- {
 *    status:
 *    message:
 *    data: {
 *      return:
 *      output:
 *    }
 * }
 */

require_once './shell.class.php';

header('Content-type: application/json');

$command = $_POST['sh'] or die();
$shell = new Shell();
echo $shell->response($command);

?>

curl 测试:

curl -X POST -i 'http://localhost:8888/' --data sh=ls

响应:

HTTP/1.1 200 OK
Host: localhost:8888
Date: Sun, 22 Apr 2018 04:57:56 +0000
Connection: close
X-Powered-By: PHP/7.1.16
Content-type: application/json

{"status":0,"message":"ok","data":{"return":0,"output":["index.php","shell.class.php"]}}

作者: YanWen

Web 开发者

发表评论

Fill in your details below or click an icon to log in:

WordPress.com 徽标

You are commenting using your WordPress.com account. Log Out /  更改 )

Google photo

You are commenting using your Google account. Log Out /  更改 )

Twitter picture

You are commenting using your Twitter account. Log Out /  更改 )

Facebook photo

You are commenting using your Facebook account. Log Out /  更改 )

Connecting to %s