[HFCTF2020]BabyUpload session解析引擎

<?php
error_reporting(0);
session_save_path("/var/babyctf/");//session存放位置
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');//filter_input() 函数从脚本外部获取输入(post) 变量direction
$attr = filter_input(INPUT_POST, 'attr');//post 变量attr
$dir_path = "/var/babyctf/".$attr;//拼接路径$dir_path =/var/babyctf/$attr
if($attr==="private"){
    $dir_path .= "/".$_SESSION['username'];//$dir_path =/var/babyctf/private/$_SESSION['username']
}
if($direction === "upload"){
    try{
        if(!is_uploaded_file($_FILES['up_file']['tmp_name'])){//is_uploaded_file() 函数检查指定的文件是否是通过 HTTP POST 上传
            throw new RuntimeException('invalid upload');
        }//参数up_file
        $file_path = $dir_path."/".$_FILES['up_file']['name'];//$file_path =/var/babyctf/$attr/$_FILES['up_file']['name']
        $file_path .= "_".hash_file("sha256",$_FILES['up_file']['tmp_name']);
        //$file_path =/var/babyctf/$attr/$_FILES['up_file']['name']_文件名的sha256
        if(preg_match('/(\.\.\/|\.\.\\\\)/', $file_path)){// ../ ..\\限制目录穿越
            throw new RuntimeException('invalid file path');
        }
        @mkdir($dir_path, 0700, TRUE);//创建目录/var/babyctf/$attr/
        if(move_uploaded_file($_FILES['up_file']['tmp_name'],$file_path)){
            $upload_result = "uploaded";//文件上传到$file_path下 P31
        }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'));//读取文件名 post传入filename
        $file_path = $dir_path."/".$filename;//$dir_path =/var/babyctf/$attr/$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、session中的username参数要为admin

2、在 /var/babyctf/success.txt存在

在代码审查中可以得到的信息点:

一共有四个参数 direction attr filename up_file
1
direction为upload的时候为上传文件状态
attr传入的值拼接为路径$dir_path = "/var/babyctf/".$attr
并且中间有一个mkdir函数创建目录 @mkdir($dir_path, 0700, TRUE) 代表我们当前所在的目录由$attr参数决定
文件名会被修改为
$file_path =/var/babyctf/$attr/$_FILES['up_file']['name']_文件名的sha256
也就是文件名后面加一个 _ 和文件的msha256值
up_file是我们上传文件的参数,可以利用postman工具上传我们所需的文件

2
direction为download的时候为读取文件状态
filename参数控制文件名,可以根据前面上传后的加密来破解文件名
路径如$dir_path =/var/babyctf/$attr/$filename
如果文件存在,会输出文件内容

在php中,session文件默认的存储文件名是sess_PHPSESSID,于是我们可以利用donwnload先看一下原先的session文件里面有什么,经过分析可以知道$attr参数我们可以暂时设置为空,因为目前感觉跟我们的操作没多大关系

attr=&direction=download&filename=sess_609f6cd6a2922894f3843927cb598f65

可以发现有一个不可见字符,不同的php引擎,session的存储方式不一样

php_binary:存储方式是,键名的长度对应的ASCII字符+键名+经过serialize()函数序列化处理的值
php:存储方式是,键名+竖线+经过serialize()函数序列处理的值
php_serialize(php>5.5.4):存储方式是,经过serialize()函数序列化处理的值

 可以知道我们这题的php引擎为php_binary,于是取伪造session文件

<?php
ini_set('session.serialize_handler','php_binary');
session_save_path('D:\Phpstorm\file\[HFCTF2020]BabyUpload');
session_start();

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

为了方便文件名的计算,这边建议把文件名改为sess方便我们后面的计算

 格式没有错误(这里不要以为是usernames,只是凑在一起了,键名username+serialize的值,s是字符的意思)

然后利用postman工具利用参数up_file参数传入sess文件(我们就不用在burp上构造文件信息了)

记得将方法改为POST,我开始一直方法没改,GET传入一直出不来…………

 上传是否成功我们可以利用之前的查看办法去看,但是这里我们要先知道该session文件sha256后的值

echo hash_file('sha256','D:\Phpstorm\file\[HFCTF2020]BabyUpload\sess');
//432b8b09e30c4a75986b719d1312b63a69f1b833ab602c9ad5f0299d1d76a5a4

于是我们改一下filename即可

 现在session文件成功伪造,目的就是如何上传success.txt文件,因为前面的分析可以知道文件名最后还要加_以及sha256加密,于是这个方法行不通

if($_SESSION['username'] ==='admin')
{
    $filename='/var/babyctf/success.txt';
    if(file_exists($filename)){
        safe_delete($filename);
        die($flag);
    }
}

查一下file_exists有什么漏洞

目录!我们可以利用att参数创建一个success.txt文件夹,然后将sess传入success目录下,因为后面有个mkdir获取的还是我们的session文件的值,但是这个文件判断是在babyctf目录下!

bingo!!!赶紧试试

去浏览器将自己的phpsession改为我们之前那个sha256的文件名,以此欺骗我们是admin

,即可获取flag 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值