0ctf-ezdoor-复现分析
在学习opcache的时候,看到了这个题目,刚好有环境,就来复现一下,这个题目也让我学到了很多。
创建镜像:
docker build -t 0ctf-ezdoor .
启动容器:
docker run -itd -p 9010:80 --name 0ctf-ezdoor 0ctf-ezdoor
源码如下:
<?php error_reporting(0); $dir = 'sandbox/' . sha1($_SERVER['REMOTE_ADDR']) . '/'; //创建一个用户沙盒
if(!file_exists($dir)){
mkdir($dir);
} //每次访问页面不存在该目录时都将重新创建,
if(!file_exists($dir . "index.php")){
touch($dir . "index.php"); //如果index.php不存在,则直接用touch创建
}
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信息
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"];
if (preg_match("/[^a-zA-Z0-9.\/]/", $name) ||
stristr(pathinfo($name)["extension"], "h")) { //取文件的后缀并且过滤了h,
则所有php后缀都不能上传后面的stristr(pathinfo)是用来判断以“.”隔断后的字符串中是否含有“h”字符,在这里pathinfo是以字符串中最后一个“.”来进行隔断。
break;
}
move_uploaded_file($_FILES['file']['tmp_name'], $name);
$size = 0;
foreach (scandir($dir) as $file) {
if (in_array($file, [".", ".."])) {
continue;
}
$size += filesize($dir . $file);
}
if ($size > 100000) {
clear($dir);
}
break;
case 'shell':
ini_set("open_basedir", "/var/www/html/$dir:/var/www/html/flag");
include $dir . "index.php";
break;
default:
highlight_file(__FILE__);
break;
}
最终包含的是$dir."index.php",并且无法上传php后缀,最后有include,那么应该是包含shell,所以我们如果能够通过上传覆盖index.php,就能够getshell,然后根据给出的flag路径去读flag
此时首先读一下phpinfo,这个是个txt的phpinfo信息,并且里面删除了一些配置项, 在里面发现opcache是开启的,
预期解法:
opcache突破口
A网站的网页index.php具有缓存文件index.php.bin
而访问index.php的时候加载缓存index.php.bin
倘若这时候具有上传,我们可以覆盖index.php.bin
是不是就会加载我们的恶意文件了呢?
题目中虽然过滤php类型的结尾,但是却未过滤bin的结尾
通过opcache.file_cache可以看到opcache的存储路径信息在/tmp/cache下
执行docker exec -it bash_name bash 进入docker容器发现实际上目录是cache/systemid,就是每个用户都会有一个id,来鉴别的
所以我们的目的很明确,就是去覆盖此index.php.bin来上传我们自己的index.php.bin,那么当再次访问index.php.bin时实际上就是访问的我们的恶意index.php文件
所以首先要知道服务器缓存文件的目录,计算一下服务器端的systemid,利用https://github.com/GoSecure/php7-opcache-override,因为代码需要指定一个phpinfo的页面,但是其最终解析出来进行计算的一些配置项才是最重要的,因此找到目标服务器的这些配置项
php_version=7.0.28
zend_extension_id=API320151012,NTS
zend_bin_id由这两部分组成
即zend_bin_id=BIN_SIZEOF_CHAR48888
接下来利用公式计算一下就能得到:
systemid=7badddeddbd076fe8352e80d8ddf3e73
但是这个systemid计算出来的跟我在docker容器里面看到的名字不一样,这里查看一下php的版本,题目给的是7.0.28,但是此时我复现的时候从hub库拖过来的php7版本是7.0.33,因此这里计算systemid时要和题目的php版本一致,这里把php的版本改成7.0.33计算一下就行了,得到system_id为0b8bd94e9858e5d32d058dc0acf75014
和我docker是相符的,说明没问题,此时已经得到了服务器端的opcache路径,那么下一步就是通过上传去覆盖此index.php.bin
opcache文件生成
首先要在本地搭一个根目标服务器一样的环境,所以pull一个环境下来:
sudo docker pull php:7.0.-apache
然后通过镜像创建容器:
docker run -itd -p : --name php:7.0.-apache opcache
此时容器已经起来了,进入配置与服务器相同的路径
docker exec -it opcache bash
因为我们的index.php在用户的沙盒中,因此可以使用pwd先看看路径
可以看到路径为sandbox/fac849dc498b60000e200f3f2a2712b54da39b92/,所以首先新建一个文件夹吧,然后开一个index.php,先看看能不能成功
此时文件生成了,需要配置一下php.ini的opcache
直接从docker hub拉来的镜像我发现里面没有加载php.ini,但是看到加载php.ini的路径为/usr/loca/etc/php,所以去这个目录看看,
应该是给了两个ini,选定一个更名为php.ini让apache去加载,所以cp拷贝一份就行了,我配置了如下选项:
zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20151012/opcache.so //默认存在该扩展,只要把so文件引进来即可
opcache.file_cache => /tmp/cache => /tmp/cache
opcache.enable => On => On
opcache.validate_timestamps => On => On
opcache.file_cache_only => =>
然后重启一下apache,这里不能用service apache2 restart,容器会断掉,因为容器相当于一个cmd环境,重启自己会断,这里用reload重新加载一下配置文件,此时刷新phpinfo看看
opcache扩展也打开了,访问我们模拟环境的index.php试试生成bin文件:
此时,因为目标服务器timestamps为on,因此我们不仅要置换bin里面的systemid还要置换一下timestamps
运行以下代码就能获得最新的文件时间戳:
import requests
print requests.get('http://127.0.0.1:8585/index.php?action=time').content
print requests.get('http://127.0.0.1:8585/index.php?action=reset').content
print requests.get('http://127.0.0.1:8585/index.php?action=time').content
此时只要用010修改一些systemid和timestamps,直接使用https://github.com/GoSecure/php7-opcache-override中提供的模板文件来帮助我们解析bin文件,此时就能看到要修改的两个字段
修改以后保存,然后本地构造上传表单,进行上传,因为我们想要覆盖目标服务器的bin文件,那么路径必须与其相同才行,这里直接将$_GET['name']与沙盒路径拼接在了一起,没有对变量进行过滤
所以此时确定路径可以进行路径穿越,可以穿越到任意目录,所以可以直接通过systemid来构造路径为:
../../../../../tmp/cache/0b8bd94e9858e5d32d058dc0acf75014/var/www/html/sandbox/fac849dc498b60000e200f3f2a2712b54da39b92/index.php.bin
<html>
<body>
<form action="http://127.0.0.1:8585/?action=upload&name=../../../../../tmp/cache/0b8bd94e9858e5d32d058dc0acf75014/var/www/html/sandbox/fac849dc498b60000e200f3f2a2712b54da39b92/index.php.bin" method="post" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" value="upload" />
</form>
</body>
</html>
然后上传我们的bin文件,此时再访问action=shell,来触发index.php加载我们bin文件
由上图可以看到此时已经成功加载了我们的bin文件,我们继续读一下/var/www/html和/var/www/html/flag目录,可以看到服务器做了限制,只能读到flag目录有个奇怪的文件,可以读一读它
接下来读一下这个文件
将其base64解码以后存到本地的flag.php.bin文件中,拖到010进行分析,发现解析出来其systemid出现了错误,对比一下正常的bin文件发现其头部少了一个字节00
所以在其magic头部补充一个字节就行了,此时systemid还原正常,其它字段的值也正常了,接下来就要让bin文件还原成我们可以阅读的代码或者语言,做到这web部分结束,暂时不往下看了==
非预期解:
1.通过条件竞争
因为pathinfo会获取最后一个点之后的扩展,通过index.php/. 就可以绕过pathinfo,但是move_uploaded_file这个函数在调用stat检测到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); //然后删除目录
}
删除时,先删除目录中的文件,再删除目录,那么我们知道如果目录里面有文件调用rmdir将无法删除,所以我们可以给要删除的目录传递大量没用的文件,那么在还在scandir的for循环结束时,原有的正常的index.php
也被删除了,此时沙盒中有还有无用文件,不能删除此沙盒目录,因此我们可以再上传自己的index.php,然后以此来getshell
2.绕过php底层文件操作函数
x/../index.php/. 直接将路径修改为该路径,就可以覆盖原来的index.php,因为首先php调用tsrm_realpath去掉/.将其转换为一个标准路径,然后调用lstst获取文件属性,也就是判断文件存不存在,不存在将写文件,x/../index.php将绕过lstat让其认为index.php不存在所以重新写入,所以可以getshell
参考:
https://www.kingkk.com/2018/04/2018-0ctf-ezdoor%E5%88%86%E6%9E%90/#%E5%8F%A6%E4%B8%80%E7%A7%8D%E9%AA%9A%E6%93%8D%E4%BD%9C
https://www.cdxy.me/?p=790
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://lorexxar.cn/2016/05/27/opcache-jcfx/
http://wonderkun.cc/index.html/?p=626
https://skysec.top/2018/04/11/0ctf-ezdoor/#%E9%A2%84%E6%9C%9F%E8%A7%A3
http://elssm.top/2018/05/04/2018-0ctf-ezdoor%E5%A4%8D%E7%8E%B0/
https://altman.vip/2018/10/10/0ctf-Ezdoor/#%E6%89%A7%E8%A1%8C%E5%91%BD%E4%BB%A4
https://www.angelwhu.com/blog/?p=438
0ctf-ezdoor-复现分析的更多相关文章
- 路由器漏洞复现分析第三弹:DVRF INTRO题目分析
这个项目的目的是来帮助人们学习X86_64之外其他架构环境,同时还帮助人们探索路由器固件里面的奥秘. 本文通过练习DVRF 中INTRO 部分的题目来学习下MIPS 结构下的各种内存攻击. DVRF: ...
- CVE-2021-3129:Laravel远程代码漏洞复现分析
摘要:本文主要为大家带来CVE-2021-3129漏洞复现分析,为大家在日常工作中提供帮助. 本文分享自华为云社区<CVE-2021-3129 分析>,作者:Xuuuu . CVE-202 ...
- ref:spring-data-XMLBean XXE复现分析
ref:https://blog.spoock.com/2018/05/16/cve-2018-1259/ 漏洞信息 看pivotal发布的漏洞信息如下 通过发布的漏洞信息可以知道,漏洞组件是在XML ...
- 路由器漏洞复现分析第二弹:CNVD-2018-01084
1月17日,CNVD公开了D-LinkDIR 615/645/815 service.cgi远程命令执行漏洞(CNVD-2018-01084),freebuf上有前辈写了一篇漏洞复现和poc的文章(h ...
- Wordpress4.9.6 任意文件删除漏洞复现分析
第一章 漏洞简介及危害分析 1.1漏洞介绍 WordPress可以说是当今最受欢迎的(我想说没有之一)基于PHP的开源CMS,其目前的全球用户高达数百万,并拥有超过4600万次的超高下载量.它是一个开 ...
- CVE-2020-7961 Liferay Portal 复现分析
漏洞说明: Liferay是一个开源的Portal(认证)产品,提供对多个独立系统的内容集成,为企业信息.流程等的整合提供了一套完整的解决方案,和其他商业产品相比,Liferay有着很多优良的特性,而 ...
- java反序列化——apache-shiro复现分析
本文首发于“合天智汇”公众号 作者:Fortheone 看了好久的文章才开始分析调试java的cc链,这个链算是java反序列化漏洞里的基础了.分析调试的shiro也是直接使用了cc链.首先先了解一些 ...
- 追洞小组 | fastjson1.2.24复现+分析
出品|MS08067实验室(www.ms08067.com) 本文作者:爱吃芝士的小葵(Ms08067实验室追洞小组成员) 1.靶场搭建 2.漏洞复现 3.漏洞分析 4.漏洞修复 5.心得 靶场搭建 ...
- 泛微OA E-cology(CNVD-2019-32204)远程命令执行漏洞复现分析
漏洞复现 影响版本: E-cology 7.0 E-cology 8.0 E-cology 8.1 E-cology 9.0 直接在网站根目录后加入组件访问路径 /weaver/bsh.servl ...
- struts2漏洞复现分析合集
struts2漏洞复现合集 环境准备 tomcat安装 漏洞代码取自vulhub,使用idea进行远程调试 struts2远程调试 catalina.bat jpda start 开启debug模式, ...
随机推荐
- mysql 8.0.13开启远程连接 配置方式
1:linux登录mysql [root@localhost mysql]# mysql -u root -p Enter password: Welcome to the MySQL monitor ...
- git 操作实践
git操作: - git是一个用于帮助用户实现版本控制的软件 #首先创建项目 1. cd到项目文件目录 2. 鼠标右键点击 Git Bash Here 3. git init #在项目文件目录生成 . ...
- javaIO——BufferedReader效率测试实践
上一篇刚刚学习了 BufferedReader ,想着来验证一下 BufferedReader 的缓冲到底能带来多大的性能提升,于是拷贝了一个100M 左右的日志文件放到本地,测试一下使用 Buffe ...
- sql server 语句书写注意事项
1 Between在某些时候比IN 2 在必要是对全局或者局部临时表创建索引,有时能够提高速度,但不是一定会这样,因为索引也耗费大量的资源.他的创建同是实际表一样 3 尽量少用视图,它的效率低.对视 ...
- TensorFlow C++接口编译和使用
部分内容from: Tensorflow C++ 从训练到部署(1):环境搭建 在之前的编译中,已经编译好了tensorflow_pkg相关的wheel.现在有一个需求,需要按照C++的代码进行模型加 ...
- Delphi 执行线程对象
- 远程操控批量复制应用(scp/pssh/pscp.pssh/rsync/pslurp)
scp命令: scp [options] SRC... DEST/两种方式: scp [options] [user@]host:/sourcefile /destpath scp [options] ...
- SqlServer和Oralce保留几位小数以及当末尾小数为0也显示
需求描述:对数字类型值保留2位小数,当2位小数末尾出现0时也显示 SqlServer处理方法: 1.首先通过Round函数保留2位有效数字,多出的位数值变成0 2.通过Cast函数转成decimal( ...
- asterisk搭建goip
利用asterisk来搭建goip使用,步骤如下: 第一步:先需要搭建centos服务器并优化 搭建centos服务器就省略: 优化centos服务器,进行如下步骤: 关闭防火墙:systemctl ...
- SSH环境搭建之Hibernate环境搭建篇
SSH环境搭建之Hibernate环境搭建篇 搭建有两种方式: 1.使用IntelliJ IDEA或者MyEclipse的逆向工程(关系模型 -> 对象模型),我使用的是IntelliJ IDE ...