BUUCTF [HarekazeCTF2019] Avatar Uploader 1

BUUCTF [HarekazeCTF2019] Avatar Uploader 1

考点:

  1. PNG文件上传
  2. finfo_file()函数原理
  3. getimagesize() 函数原理与绕过

启动环境:
在这里插入图片描述
化身上传者,首先提示登陆,题目名为上传,那么和登陆应该没什么联系,使用test用户进入:
在这里插入图片描述
来到文件上传功能,提示请上传一张小于256KB,小于256px*256pxPNG图片。

首先尝试上传符合规定的PNG文件:
在这里插入图片描述
上传成功后,得到回显:
在这里插入图片描述
更新了头像,尝试了一些上传后,没了思路,查阅大佬wp时,发现原题给出了源码。。。
题目源码:avatar_uploader_1

因为是上传题,主要查看其upload.php代码:

<?php
error_reporting(0);

require_once('config.php');
require_once('lib/util.php');
require_once('lib/session.php');

$session = new SecureClientSession(CLIENT_SESSION_ID, SECRET_KEY);

// check whether file is uploaded
if (!file_exists($_FILES['file']['tmp_name']) || !is_uploaded_file($_FILES['file']['tmp_name'])) {
  error('No file was uploaded.');
}

// check file size
if ($_FILES['file']['size'] > 256000) {
  error('Uploaded file is too large.');
}

// check file type
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$type = finfo_file($finfo, $_FILES['file']['tmp_name']);
finfo_close($finfo);
if (!in_array($type, ['image/png'])) {
  error('Uploaded file is not PNG format.');
}

// check file width/height
$size = getimagesize($_FILES['file']['tmp_name']);
if ($size[0] > 256 || $size[1] > 256) {
  error('Uploaded image is too large.');
}
if ($size[2] !== IMAGETYPE_PNG) {
  // I hope this never happens...
  error('What happened...? OK, the flag for part 1 is: <code>' . getenv('FLAG1') . '</code>');
}

// ok
$filename = bin2hex(random_bytes(4)) . '.png';
move_uploaded_file($_FILES['file']['tmp_name'], UPLOAD_DIR . '/' . $filename);

$session->set('avatar', $filename);
flash('info', 'Your avatar has been successfully updated!');
redirect('/');

在检查文件类型时,finfo_file()函数检测上传图片的类型是否是image/png
在检查文件长宽时,getimagesize() 函数用于获取图像大小及相关信息,成功将返回一个数组,但其后面还有:

if ($size[2] !== IMAGETYPE_PNG) {
  // I hope this never happens...
  error('What happened...? OK, the flag for part 1 is: <code>' . getenv('FLAG1') . '</code>');

索引2不是PNG,将输出part 1的flag

对于getimagesize() 函数返回的数组:

Array
(
    [0] => 290
    [1] => 69
    [2] => 3
    [3] => width="290" height="69"
    [bits] => 8
    [mime] => image/png
)

结果解释:

  • 索引 0 给出的是图像宽度的像素值
  • 索引 1 给出的是图像高度的像素值
  • 索引 2 给出的是图像的类型,返回的是数字,其中1 = GIF2 = JPG3 = PNG4 = SWF5 = PSD6 = BMP7 = TIFF(intel byte order)8 = TIFF(motorola byte order)9 = JPC10 = JP211 = JPX12 = JB213 = SWC14 = IFF15 = WBMP16 = XBM
  • 索引 3 给出的是一个宽度和高度的字符串,可以直接用于 HTML<image> 标签
  • 索引 bits 给出的是图像的每种颜色的位数,二进制格式
  • 索引 channels 给出的是图像的通道值,RGB 图像默认是 3
  • 索引 mime 给出的是图像的 MIME 信息,此信息可以用来在 HTTP Content-type 头信息中发送正确的信息,如:header("Content-type: image/jpeg");

为了获取到flag,我们需要绕过函数finfo_file()或函数getimagesize() 的验证
函数finfo_file()其主要是识别PNG文件十六进制下的第一行信息,若保留文件头信息,破坏掉文件长宽等其余信息,也就可以绕过getimagesize() 函数的检验
使用Hex Fiend将图片其余数据删掉,只保留文件头:
在这里插入图片描述
上传后,得到flag:
在这里插入图片描述

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值