声明:
以下多内容来自暗月师傅我是通过他的教程来学习记录的,如有侵权联系删除。
一道反序列化的CTF题分享_ctf反序列化题目_Mr.95的博客-CSDN博客
一些其他大佬的wp参考:php_反序列化_1 | dayu’s blog (killdayu.com)
序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。
序列化_toString
1. 序列化简介
本质上serialize()和unserialize()在php内部的实现上是没有漏洞的,漏洞的主要产生是由于应用程序在处理对象,魔术函数以及序列化相关问题时导致的。
当传给unserialize()的参数可控时,那么用户就可以注入精心构造的payload当进行反序列化的时候就有可能会触发对象中的一些魔术方法,造成意想不到的危害。
1. __toString介绍
__toString() 是魔术方法的一种,具体用途是当一个对象被当作字符串对待的时候,会触发这个魔术方法以下说明摘自PHP官方手册
public string __toString ( void )
__toString() 方法用于一个类被当成字符串时应怎样回应。例如 echo $obj; 应该显示些什么。此方法必须返回一个字符串,否则将发出一条 E_RECOVERABLE_ERROR 级别的致命错误。
Warning
不能在 __toString() 方法中抛出异常。这么做会导致致命错误。
2 简单示例
<?php
// Declare a simple class
class TestClass
{
public $foo;
public function __construct($foo)
{
$this->foo = \$foo;
}
public function __toString() {
return $this->foo;
}
}
$class = new TestClass('Hello');
echo $class;
?>
上面我们通过调试就能发现,当echo输出的时候,,会自动调用__toString
3.CTF实例
<?php
Class readme{
public function __toString()
{
return highlight_file('Readme.txt', true).highlight_file($this->source, true);//高亮显示
}
}
if(isset($_GET['source'])){
$s = new readme(); //实例化一个对象
$s->source = __FILE__; //传入当前文件名,根据Readme.txt输出的提示/flag可知这题要做那么传入的文件名应该是'flag'
echo $s; //输出当前文件内容
exit;
}
//$todos = [];
if(isset($_COOKIE['todos'])){
$c = $_COOKIE['todos'];
$h = substr($c, 0, 32); //截取0-32位字符
$m = substr($c, 32); //截取32位以后的字符
if(md5($m) === $h){
//全等于才会反序列化
$todos = unserialize($m);
}
}
if(isset($_POST['text'])){
//不过这里我们好像用不到post
$todo = $_POST['text'];
$todos[] = $todo; //将post获取到的参数赋值给数组,注意如果上面的反序列化通过了这个数组就原本不是空的
$m = serialize($todos); //序列化
$h = md5($m);
setcookie('todos', $h.$m);
header('Location: '.$_SERVER['REQUEST_URI']);
exit;
}
?>
<html>
<head>
</head>
<h1>Readme</h1>
<a href="?source"><h2>Check Code</h2></a>
<ul>
<?php foreach($todos as $todo):?> //遍历取todos赋值给todo
<li><?=$todo?></li> //相当于<?php echo $todo?>
<?php endforeach;?>
</ul>
<form method="post" href=".">
<textarea name="text"></textarea>
<input type="submit" value="store">
</form>
highlight_file() 函数对文件进行语法高亮显示。
PHP 支持一个错误控制运算符:@。当将其放置在一个 PHP 表达式之前,该表达式可能产生的任何错误信息都被忽略掉。
strpos() 函数查找字符串在另一字符串中第一次出现的位置
php中ereg()函数和eregi()函数-字符串对比解析函数
·松散比较:使用两个等号 == 比较,只比较值,不比较类型。
·严格比较:用三个等号 === 比较,除了比较值,也比较类型
setcookie() 函数向客户端发送一个 HTTP cookie
header() 函数向客户端发送原始的 HTTP 报头。
$_SERVER[“REQUEST_URI”]函数:
预定义服务器变量的一种,所有$_SERVER开头的都叫做预定义服务器变量 REQUEST_URI的作用是取得当前URI,也就是除域名外后面的完整的地址路径
$_SERVER[“REQUEST_URI”]函数-CSDN博客
通过上面的注释和分析我们可以知道,post好像用不到了,我们需要构造一段序列化的cookie信息payload,传入让他执行反序列化。
可以发现当执行到这一段的时候会触发_toString方法,而todo的参数已经是被我们改成了反序列化后的参数。
<?php foreach($todos as $todo):?> //遍历取todos赋值给todo
<li><?