[HFCTF2020]BabyUpload

[HFCTF2020]BabyUpload

直接给了源码

<?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;
}
?>

获取flag的思路很明确了

1.通过file_exists('/var/babyctf/success.txt')校验

2.admin身份

这里提供了上传和下载功能并且目录和session存放目录相同,因此我们可以自己上次sess文件伪造sess。upload方法中对上传的文件名进行了一些修改,在后面加上_+sha256值,刚好session文件名格式就是sess_+phpsessid。首先我们先利用下载功能查看服务器储存session的格式,提交参数direction=download&attr=.&filename=sess_+phpsessid,可以看到现有的session文件内容为usernames:5:"guest";,在burp中我们可以看到最前面是一个0x08字符,因此得知服务器生成session文件的处理器为php_binary,因此在本地生成一个session文件。

<?php
session_save_path("C:/xampp/ctf/var/babyctf/");
ini_set('session.serialize_handler', 'php_binary');
session_start();

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

得到一个session文件,并且身份为admin,我们修改这个文件名为sess,然后计算其sha256值。上传这个文件即可伪造session,根据题目源码,服务器在储存文件时在文件名后加上了_+sha256,因此我们上次的sess文件在服务器端名为sess_432b8b09e30c4a75986b719d1312b63a69f1b833ab602c9ad5f0299d1d76a5a4。然后我们用432b8b09e30c4a75986b719d1312b63a69f1b833ab602c9ad5f0299d1d76a5a4作为phpsessid,即可实现伪造admin的身份。这里上传时还有一个attr参数,我们可以设置这个参数为.或者不设。

admin身份伪造成功后再尝试上次success.txt文件。这里使用的函数为file_exists()函数,这个函数可以判断一个文件或目录是否存在。因此我们可以令attr=success.txt,这样可以创造一个名为success.txt的目录。然后就可以直接get访问获取flag。

如果这里php版本小于5.3.4,还可以上传一个名为success.txt%00的文件。这样可以截断后面添加的部分,也能够通过file_exists()函数校验。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。