本文最后更新于:2023年8月25日 下午
[TOC]
[HarekazeCTF2019]Easy Notes-代码审计
登录之后有几个功能点,可以添加节点,然后使用Export
导出
我们查看源码,
我们发现想要拿到flag的条件时$_SESSION['admin']=true
如果我们能够控制session文件,就可以拿到flag了
我们发现session存储的文件改为了:/var/www/tmp
重点看export.php
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| <?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); $path = TEMP_DIR . '/' . $filename;
if ($type === 'tar') { $archive = new PharData($path); $archive->startBuffering(); } else { $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); $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);
|
这里可以看到,导出的文件也是写到/var/www/tmp
目录下面,所以我们可以尝试session伪造一下,伪造一个session文件
1 2 3
| $filename = get_user() . '-' . bin2hex(random_bytes(8)) . '.' . $type; $filename = str_replace('..', '', $filename); $path = TEMP_DIR . '/' . $filename;
|
get_user()
会获取用户名,bin2hex(random_bytes(8))
会生成16进制字符串,
如果我们用户名为sess_
,并且$type=.
,那么两个.
会被替换为空,所以最终文件名就符合session文件的格式了,session文件名可控
那么看一下session内容可控吗:
1
| $archive->addFromString("{$index}_{$title}.json", json_encode($note));
|
可控的
由于默认session_serialize_handler=php
,那么序列化规则为:
处理器 |
对应的存储格式 |
php |
键名 + 竖线 + 经过 serialize() 函数反序列处理的值 |
所以$_SESSION['admin']=true
需要满足:
但是由于我们导出的文件中有一些内容,防止被污染,我们需要这么写:
添加之后导出:
最后替换一下PHPSESSID
为文件名: