
随便起个名字,题目给了附件源码,进去看看

我不是 admin,看来是和名字叫什么没有关系,看看代码怎么检查的
# index.php
<?php
require_once('init.php');
if (!isset($_GET['page']) || empty($_GET['page'])) {
$page = 'home';
} else {
$page = $_GET['page'];
}
if (in_array($page, ['notes', 'note', 'add', 'delete'], true) && !is_logged_in()) {
redirect('/?page=home');
}
if (in_array($page, ['home', 'flag', 'notes', 'note', 'add', 'delete', 'login'], true)) {
include('includes/header.php');
include('pages/' . $page . '.php');
include('includes/footer.php');
} else {
redirect('/?page=home');
}
?>
# init.php
<?php
error_reporting(0);
require_once('config.php');
require_once('lib.php');
session_save_path(TEMP_DIR);
session_start();
# 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);
主要看这段,filename 先是用户名 + - + 随机的8位字符 + . + 文件类型,然后还检查了一下目录穿越,就直接拼接 TEMP_DIR
而 TEMP_DIR 这个目录是和 session文件保存在同一目录的,可以看 init.php,所以思路就是伪造 session 了
然后后面会把笔记的标题内容这些给 json,以 下标_标题.json 的名字返回

做个测试,发现确实是和我们分析的一样,用户名-随机字符.zip,然后里面的文件就是 下标_标题.json


{"title":"paidx0","body":"hello","id":"29ddacf5aeab78a251b1daf72d96e38f525a1bf1e26ea627418b0853df78e94d"}
现在 用户名、文件类型、标题、内容这些是可控的
我们知道 session文件 一般就是 sess_+ 大小写字母和下划线 组成,要伪造 session文件条件也都有
当 user = sess_ 、type = . 、title = |N;admin|b:1; 时,
filename经过检查就变成了 sess_abcdef13454531,type是点和前面的点正好构成两个点被删除掉


成功伪造了 session文件,替换掉 phpsessid ,我们就是 admin 了

本文深入探讨了一个PHP应用中的安全问题,涉及session路径操纵导致的权限提升。通过分析源码,揭示了如何利用用户可控的变量构造恶意session文件,从而伪装成管理员。关键步骤包括设置特定的用户名、文件类型和标题,绕过安全检查并创建伪装的session文件。此漏洞可能使攻击者获取非法权限,对系统安全构成威胁。
656

被折叠的 条评论
为什么被折叠?



