[HarekazeCTF2019]Easy Notes
源码
https://github.com/TeamHarekaze/HarekazeCTF2019-challenges/tree/master/easy_notes/server
知识点
解题步骤:
看到flag.php
<section>
<h2>Get flag</h2>
<p>
<?php
if (is_admin()) {
echo "Congratulations! The flag is: <code>" . getenv('FLAG') . "</code>";
} else {
echo "You are not an admin :(";
}
?>
</p>
</section>
is_admin()
function is_admin() {
if (!isset($_SESSION['admin'])) {
return false;
}
return $_SESSION['admin'] === true;
}
然后看export.php
<?php
require_once('init.php');
if (!is_logged_in()) {
redirect('/?page=home');
}
$notes = get_notes();
if (!isset($_GET['type']) || empty($_GET['type'])) {
$type = 'zip';
} else {
$type = $_GET['type'];
}
$filename = get_user() . '-' . bin2hex(random_bytes(8)) . '.' . $type;
$filename = str_replace('..', '', $filename); // avoid path traversal
$path = TEMP_DIR . '/' . $filename;
if ($type === 'tar') {
$archive = new PharData($path);
$archive->startBuffering();
} else {
// use zip as default
$archive = new ZipArchive();
$archive->open($path, ZIPARCHIVE::CREATE | ZipArchive::OVERWRITE);
}
for ($index = 0; $index < count($notes); $index++) {
$note = $notes[$index];
$title = $note['title'];
$title = preg_replace('/[^!-~]/', '-', $title);
$title = preg_replace('#[/\\?*.]#', '-', $title); // delete suspicious characters
$archive->addFromString("{$index}_{$title}.json", json_encode($note));
}//写入文件
if ($type === 'tar') {
$archive->stopBuffering();
} else {
$archive->close();
}
header('Content-Disposition: attachment; filename="' . $filename . '";');
header('Content-Length: ' . filesize($path));
header('Content-Type: application/zip');
readfile($path);
这里将note的标题写入文件中, init.php有保存目录
<?php
error_reporting(0);
require_once('config.php');
require_once('lib.php');
session_save_path(TEMP_DIR);
session_start();
可以发现, note文件和session文件在同一目录下, 那么可以进行session伪造
1.创建名为sess_的用户
- Ubuntu默认安装的PHP中session.serialize_handler默认设置为php,而这种引擎特点是即可使用|作为键值隔离符。利用|即可将序列化字符串拼接
那么可以将title写为:|N;admin|b:1;
这样,反序列化的结果就为admin=(bool)true, 前面的垃圾字符不在is_admin()的检测范围内
3.然后用export Notes将title写入, 要抓包, 将type改为'.'
这样, 在请求时, filename末尾有.., 会被下面的过滤变为空, 这样就构造了假的session文件
4.将phpsession改为文件名去掉sess_的值即可伪造session, 然后getflag即可