BUUCTF刷题记录[HFCTF2020]BabyUpload——涉及session反序列化

BUUCTF刷题记录[HFCTF2020]BabyUpload——涉及session反序列化

BUUCTF刷题记录[HFCTF2020]BabyUpload——涉及session反序列化

BUUCTF刷题记录[HFCTF2020]BabyUpload——涉及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;
}
?>

         开始解答:

        根据上半部分代码,我们可以分析出,如果需要输出flag,则需要满足以下两个条件:第一:$_SESSION['username'] ==='admin'  第二:存在/var/babyctf/success.txt

error_reporting(0);//报错不提示
session_save_path("/var/babyctf/");//session存储的位置
session_start();//session开始
require_once "/flag";//包含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';
}
// 此模块,如果$_SESSION['username'] ==='admin'  并且存在/var/babyctf/success.txt 输出flag,程序结束,
//         否则,$_SESSION['username'] ='guest'

         根据下半部分代码,我们可以分析出,主要是介绍了两个函数:一个是upload,一个是download。

$dir_path = "/var/babyctf/".$attr; //设置路径为/var/babyctf/$attr
if($attr==="private"){
    $dir_path .= "/".$_SESSION['username'];//路径为/var/babyctf/$attr/$_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'];//路径为/var/babyctf/$attr/$_SESSION['username']/.$_FILES['up_file']['name']
        $file_path .= "_".hash_file("sha256",$_FILES['up_file']['tmp_name']);//路径为/var/babyctf/$attr/$_SESSION['username']/.$_FILES['up_file']['name']_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'));//basename返回路径下的文件名,即返回filename
        $file_path = $dir_path."/".$filename;//路径为/var/babyctf/$attr/$_SESSION['username']/$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文件内容里面是什么格式,那么我们需要分析下载功能所需参数,首先$direction === "download",还需要传递一个filename,那么session的文件名格式,我们可以自己查看自身php中的tmp文件夹发现,php的session默认存储文件名都是sess_+PHPSESSID这种格式,通过F12找到自身phpsessid

BUUCTF刷题记录[HFCTF2020]BabyUpload——涉及session反序列化

        到此为止,我们找到了filrname的值,即需要下载的2个参数已经找到,direction =download,filename=sess_f063a1296a5c959d3bee459c33f242df,在通过hackbar进行传递参数,注意是POST传递:

BUUCTF刷题记录[HFCTF2020]BabyUpload——涉及session反序列化

        传递后,页面左下角刷新出:usernames:5:"guest"; 

右键源代码:

BUUCTF刷题记录[HFCTF2020]BabyUpload——涉及session反序列化
我们查询资料可知:

php:存储方式是,键名+竖线+经过serialize()函数序列处理的值

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

php_serialize(php>5.5.4):存储方式是,经过serialize()函数序列化处理的值

第一种,php类型生成的session文件为:    ykingh|s:3:"123";

第二种,php_binary类型生成的session文件为:ykinghs:3:"123";

第三种,php_serialize类型生成的session文件为:a:1:{s:6:"ykingh";s:3:"123";}

 由此可见,返回的usernames:5:"guest";没有竖线,又无{},因此我们可以判断这里session处理器为php_binary,那么我们可以在本地利用php_binary生成我们要伪造的session文件。首先进行php.ini修改,让本地的php环境支持php_binary

BUUCTF刷题记录[HFCTF2020]BabyUpload——涉及session反序列化

 在本地编写sess的生成文件,代码如下:

 <?php
session_start();//session开始
if(isset($_GET['name']))
    $_SESSION['username']=$_GET['name'];
?>

 运行以上代码,生成如下图:

BUUCTF刷题记录[HFCTF2020]BabyUpload——涉及session反序列化

        由文件上传代码分析可得,我们需要修改这个文件名为sess,然后计算其sha256值。

BUUCTF刷题记录[HFCTF2020]BabyUpload——涉及session反序列化

        由此可得该文件内容哈希值为:432b8b09e30c4a75986b719d1312b63a69f1b833ab602c9ad5f0299d1d76a5a4

        根据题目源码,服务器在储存文件时在文件名后加上了_+sha256,因此我们上次的sess文件在服务器端名为sess_432b8b09e30c4a75986b719d1312b63a69f1b833ab602c9ad5f0299d1d76a5a4。然后我们查看上传文件需要的参数,direction=upload,attr可为空,

         现在根据源代码,编写上传代码,因为我们需要上传我们的admin的sess文件:


<form action="http://0beb395b-65d0-4163-90d0-7ddeb1ecb427.node4.buuoj.cn:81/" method="post" enctype="multipart/form-data">
  file: <input type="file" name="up_file"/><br> 
  <input type="submit" value="Send"/>
  <input type="text" name="direction" value="upload"/><br>
  <input type="text" name="attr" value=""/><br>
</form>

         构造如下payload,查看是否上传成功,如下图,admin信息已经上传成功

BUUCTF刷题记录[HFCTF2020]BabyUpload——涉及session反序列化

        现在我们还需要满足 $filename='/var/babyctf/success.txt';此时上传文件为如下图:

BUUCTF刷题记录[HFCTF2020]BabyUpload——涉及session反序列化

        上传成功后,路径问题已经解决,现在需要满足$_SESSION['username'] ==='admin',admin文件我们也已经上传,此时只需要在hackbar中或者bp中改变我们的cookie值,就会让网站认为我们是admin,如下图:

BUUCTF刷题记录[HFCTF2020]BabyUpload——涉及session反序列化

则输出
flag{b47727e4-e979-470b-a57f-f0d91340703f}

 最后附上代码当中的一些注释便于理解:

 <?php
error_reporting(0);//报错不提示
session_save_path("/var/babyctf/");//session存储的位置
session_start();//session开始
require_once "/flag";//包含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';
}
// 此模块,如果$_SESSION['username'] ==='admin'  并且存在/var/babyctf/success.txt 输出flag,程序结束,
//         否则,$_SESSION['username'] ='guest'
$direction = filter_input(INPUT_POST, 'direction');
$attr = filter_input(INPUT_POST, 'attr');
// 通过filter_input方法以POST的传参方式传输两个属性,分别是direction和attr
$dir_path = "/var/babyctf/".$attr; //设置路径为/var/babyctf/$attr
if($attr==="private"){
    $dir_path .= "/".$_SESSION['username'];//路径为/var/babyctf/$attr/$_SESSION['username'],如果$attr==="private"
}
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'];//路径为/var/babyctf/$attr/$_SESSION['username']/.$_FILES['up_file']['name']
        $file_path .= "_".hash_file("sha256",$_FILES['up_file']['tmp_name']);//路径为/var/babyctf/$attr/$_SESSION['username']/.$_FILES['up_file']['name']_hash_file("sha256",$_FILES['up_file']['tmp_name'])
        //hash_file这个函数为:给指定文件的 内容 生成哈希值,注意是内容
        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'));//basename返回路径下的文件名,即返回filename
        $file_path = $dir_path."/".$filename;//路径为/var/babyctf/$attr/$_SESSION['username']/$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;
}
?>
                       

点击阅读全文

上一篇 2023年 6月 12日 am10:15
下一篇 2023年 6月 12日 am10:16