文件上传小总结

前端校验

前端校验即客户端校验,一般在前端对文件名检验一次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
var file_arr = ['jpg', 'png', 'txt'];
function checkfile(filename){
var pos = filename.indexof('.');
var file_ext = filename.substr(pos+1);
for(int i=0; i<arr.length; i++){
if(file_arr == file_ext)
return true;
}
retun false
}
</script>
<form action="login.php" enctype="multipart/form-data">
<input type="file" name="upload" onchange=checkfile(this.value)/>
</form>

这种情况下,我们可以直接在本地删除掉 onchange 事件,或者先上传一个符合条件的文件,然后再用 burp 抓包改包

后端校验

后端校验,一般会校验文件的后缀,文件的 MIME,文件头,文件内容等,校验方式一般有黑名单和白名单

黑名单

一般校验后缀使用黑名单的方式:

假设漏洞代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
$filename = $_FILE['file']['filename']
$path = '/xxxxxx/'.$filname;
$arr = ['.php', '.html', '.php5', 'php4', 'php2', 'phtml','phtm'...]
$file_ext = strstr($filename, '.');
if(in_array($filename, $arr)){
die("Not allow...")
}else{
if(move_uploaded_file($_FILE['file']['tmp_name'], $path)){
echo "Upload success..."
}
}
?>

绕过方法:

  1. 大小写绕过

    上面的代码没有对大小写进行检验,当我们上传 1.PHP 时可以上传成功

    修补:

    1
    $file_ext = strtolower(strstr($filename, '.'));

    将文件后置转换成小写

  2. 空格绕过

    可以看到上面的代码,没有去除原文件后缀的空格,所以我们可以上传文件名为”1.php “进行绕过,这是因为php 解析文件名的时候会自动去掉后面的空格

    修补:

    1
    $file_ext = trim($file_ext);
  3. ‘.’ 绕过

    漏洞代码没有对文件后缀的 . 进行处理,在 windows 系统中,会自动去除文件后缀中的点,所以我们可以上传文件名为 “1.php.”,后端取出的文件名就为 “.php.”,即可绕过

    修补:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $len = strlen($file_ext);
    $ext = '';
    for($i=1; $i<$len; $i++){
    if($file_ext[i] != '.'){
    $ext += $file_ext[i];
    }else{
    break;
    }
    }
    $file_ext = $ext;

    删除文件后缀的所有点

  4. ::$DATA 绕过

    同样在 windows 下,创建文件时如果后缀中有 ::$DATA,就会直接删掉这个字段

    所以我们可以上传文件绕过黑名单检测,上传文件:1.php::$DATA

    修补:

    1
    2
    3
    if(preg_match(/::DATA/i, $filename)){
    $file_ext = substr($file_ext,0,str_len($file_ext)-6);
    }
  5. 寻找漏网之鱼

    fuzz 没被黑名单过滤的文件,比如上传 .htaccess 文件

    1
    <FilesMatch "sec.jpg"> SetHandler application/x-httpd-php </FilesMatch>
  6. 双写绕过

    有些代码过滤逻辑是这样的:

    1
    2
    $pattern = "/php|htm|htaccess.../i"
    $file_ext = preg_replace($pattern, '', $file_ext);

    这时候上传文件 1.pphphp 即可绕过

白名单

  1. 对 MIME 的检测一般用的是白名单的方式,比如

    1
    2
    3
    4
    5
    if($_FILE['file']['type']=='image/jpeg' || $_FILE['file']['type']=='image/png'){
    ....
    }else{
    die("Type not allowed....");
    }

    绕过这种只要 burp 抓包改掉 content-type 即可,由于用户发过来的包中 content-type 并不真实,所以,尽量不要依靠这种方式做检验

  2. 自定义文件上传的路径

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $upfodler = $_GET['fodler'];
    $file_name = $_FILE['file']['name'];
    $file_ext = explode($file_name, '.')[1];
    $arr = array('png', 'jpg', 'gif');
    if(in_array($file_ext, $arr)){
    $path = $upfodler.$file_name;
    if(move_uploaded_file($_FILE['file']['tmp_name'], $path)){
    echo "upload success..."
    }
    }

    由于这里得到文件最终路劲的方法是直接拼接,给了我们进行 00 截断的可能性。

    利用手段:

    1
    2
    3
    folder = /var/www/html/1.php%00

    上传的文件名为:1.jpg

    所以,1.jpg可以绕过后缀的检测,而 move_uploaded_file 时,可以将临时文件的内容写到 1.php,达到了绕过的功能

  3. 文件幻数和文件信息检测

    一般来说用图片马即可绕过常见的 getimagesize 和 phpexif 函数

    制作图片马:

    1
    copy normal.jpg /b + shell.php /a webshell.jpg

图片渲染

一次渲染:只要在图片的空白处注入代码即可

二次渲染:对比 GD库处理后的图片,在处理前后没有发生变化的地方注入代码

条件竞争

比如如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if(isset($_POST['submit'])){
$ext_arr = array('jpg','png','gif');
$file_name = $_FILES['upload_file']['name'];
$temp_file = $_FILES['upload_file']['tmp_name'];
$file_ext = substr($file_name,strrpos($file_name,".")+1);
$upload_file = UPLOAD_PATH . '/' . $file_name;

if(move_uploaded_file($temp_file, $upload_file)){
if(in_array($file_ext,$ext_arr)){
$img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
rename($upload_file, $img_path);
$is_upload = true;
}else{
$msg = "只允许上传.jpg|.png|.gif类型文件!";
unlink($upload_file);
}
}else{
$msg = '上传出错!';
}
}

先 move_uploaded_file 且move_uploaded_file时还没有对文件重命名,再 unlink,给了我们时间去访问 webshell

文件上传的两要素:1. 上传点 2. 文件存储路径,如果文件存储路径不存在的话,那么就找这个文件在网页中的输出点

Contents
  1. 1. 前端校验
  2. 2. 后端校验
    1. 2.1. 黑名单
    2. 2.2. 白名单
    3. 2.3. 图片渲染
    4. 2.4. 条件竞争
|