本文最后更新于:2023年8月25日 下午
                  
                
              
            
            
              
                
                [TOC]
[HarekazeCTF2019]Easy Notes-代码审计
登录之后有几个功能点,可以添加节点,然后使用Export导出

我们查看源码,
我们发现想要拿到flag的条件时$_SESSION['admin']=true

如果我们能够控制session文件,就可以拿到flag了

我们发现session存储的文件改为了:/var/www/tmp
重点看export.php:
| 12
 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
 
 | <?phprequire_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文件
| 12
 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为文件名:
