[CISCN 2020] easyphp

题目给出的源码如下:


    //题目环境:php:7.4.8-apache
    $pid = pcntl_fork();
    if ($pid == -1) {
        die('could not fork');
    }else if ($pid){
        $r=pcntl_wait($status);
        if(!pcntl_wifexited($status)){
            phpinfo();
        }
    }else{
        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]);
        }
        posix_kill(posix_getpid(), SIGUSR1);
    } 
pcntl_fork
(PHP 4 >= 4.1.0, PHP 5, PHP 7)

pcntl_fork: 在当前进程当前位置产生分支(子进程)。fork是创建了一个子进程,父进程和子进程 都从fork的位置开始向下继续执行,不同的是父进程执行过程中,得到的fork返回值为子进程号,而子进程得到的是0。

说明
pcntl_fork ( void ) : int
pcntl_fork()函数创建一个子进程,这个子进程仅PID(进程号) 和PPID(父进程号)与其父进程不同。

返回值
成功时,在父进程执行线程内返回产生的子进程的PID,在子进程执行线程内返回0。失败时,在父进程上下文返回-1,不会创建子进程,并且会引发一个PHP错误。
pcntl_wait
(PHP 5, PHP 7)

pcntl_wait:  等待或返回fork的子进程状态

说明:pcntl_wait(int &$status [, int $options = 0 ]):int

wait函数刮起当前进程的执行直到一个子进程退出或接收到一个信号要求中断当前进程或调用一个信号处理函数。 如果一个子进程在调用此函数时已经退出(俗称僵尸进程),此函数立刻返回。子进程使用的所有系统资源将 被释放


pcntl_waitpid
(PHP 4 >= 4.1.0, PHP 5, PHP 7)

pcntl_waitpid: 等待或返回fork的子进程状态
说明: pcntl_waitpid ( int $pid , int &$status [, int $options = 0 ] ) : int

挂起当前进程的执行直到参数pid指定的进程号的进程退出, 或接收到一个信号要求中断当前进程或调用一个信号处理函数

pcntl_waitpid()返回退出的子进程进程号,发生错误时返回-1,如果提供了WNOHANG作为option(wait3可用的系统)并且没有可用子进程时返回0
pcntl_wifexited
(PHP 4 >= 4.1.0, PHP 5, PHP 7)

pcntl_wifexited:  检查子进程状态代码是否代表一个正常的退出

说明: pcntl_wifexited ( int $status ) : bool
当子进程状态代码代表正常退出时返回 TRUE ,其他情况返回 FALSE

一开始以为是,call_user_func_array()的代码命令执行,但是后面参数多了两个flasetrue控制死了,无法构成命令执行,后来想到flag可能存在phpinfo当中,就先想办法构造执行phpinfo,只需要构造pcntl_waitpid()返回异常即可,使用pcntl_wait()或者pcntl_waitpid()获取子进程状态,没有参数就可导致状态异常,即输出phpinfo()

call_user_func_array()第一个参数使用call_user_func调用pcntl_wait()或者pcntl_waitpid()

payload:
?a=call_user_func&b=pcntl_wait
?a=call_user_func&b=pcntl_waitpid

[CISCN 2020] easyphp_第1张图片
[CISCN 2020] easyphp_第2张图片

你可能感兴趣的:(CTF_WEB_Writeup,CISCN2020,easyphp)