CTF之文件上传——你知道我在你的服务器上放了什么吗

admin 2026-04-25 04:37:15 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文详细分析了CTF竞赛中文件上传漏洞的攻防技术,系统阐述了漏洞成因(如路径截断、过滤不严、解析漏洞)及多种绕过手法(客户端验证绕过、黑名单/白名单绕过、Apache/IIS解析特性利用),并通过一道《从0到1:CTFer成长之路》实战题目演示了利用空字节截断和Zip路径穿越上传WebShell的全过程,最终成功获取flag。 综合评分: 88 文章分类: CTF,WEB安全,漏洞分析,实战经验,安全工具


(二)服务器验证绕过

修改Content-Type头

虽然这是在服务端进行的验证,但其可靠性并不高。服务器通过检查HTTP请求头中的Content-Type字段来判断文件类型。攻击者可以通过Burp Suite拦截请求,将恶意文件的Content-Type(如application/octet-stream)修改为合法的图片类型,例如image/gifimage/jpeg,从而绕过检测。更高级的技巧是,在恶意脚本文件的开头添加图片文件的“幻数”,例如在PHP木马前添加GIF89a,使其在文件头校验时也能伪装成一张正常的GIF图片。

黑名单过滤

黑名单过滤是一种“堵”的策略,即列出所有不允许上传的文件后缀。然而,这种方法存在天然的缺陷:无法穷尽所有可能的可执行后缀。以一份常见的黑名单为例,它可能只禁止了.php.asp.jsp等后缀。攻击者可以尝试上传.php3.php4.phtml.cer.cdx等同样能被服务器解析执行的后缀。此外,还可以利用一些特殊技巧进行绕过,例如:

  • 大小写绕过

    :在Windows系统下,.PHP.PhP.php是等效的。

  • 双写绕过

    :如果服务器采用字符串替换的方式过滤,如将php替换为空,那么上传pphphp,经过一次替换后就会变成php

  • 特殊字符绕过

    :在文件名末尾添加空格或点(.),如.php..php[空格],Windows系统在保存文件时会自动去除末尾的空格和点。

白名单过滤

白名单过滤是一种“疏”的策略,只允许指定的、安全的文件后缀(如.jpg.png.gif)上传。这是目前公认最安全的文件上传防御方式之一,在实战中极大地增加了攻击难度。

然而,在CTF竞赛或某些特定场景下,出题人往往会留一个文件包含的点给我们,如果网站同时存在文件包含漏洞,攻击者仍有一线生机。攻击者可以先将包含恶意代码的“图片马”以合法后缀(如.jpg)上传,然后利用文件包含漏洞,将这个图片文件当作PHP脚本进行包含和执行。

Apache文件解析缺陷

Apache服务器在处理文件后缀时,存在一些历史遗留的解析特性,可被攻击者利用。

  • 多后缀解析

    :Apache在解析文件名时,会从右向左寻找它“认识”的后缀。例如,对于一个名为shell.php.123的文件,如果Apache不认识.123这个后缀,它会继续向前查找,直到发现.php,便会将其作为PHP脚本执行。这使得攻击者可以通过构造恶意文件.php.非法后缀的形式绕过检查。

  • .htaccess文件攻击

    .htaccess是Apache的分布式配置文件。如果服务器允许上传此文件,攻击者可以上传一个自定义的.htaccess文件,在其中配置规则,强制让Apache将特定后缀(如.jpg)的文件当作PHP脚本来解析。这样一来,即使上传的是图片格式,也能成功执行其中的恶意代码。

IIS6解析漏洞

老旧的IIS6.0服务器存在的解析漏洞至今仍在一些未升级的系统中构成威胁。

  • 文件名解析漏洞

    :利用分号(;)进行截断。在IIS6.0中,image.asp;.jpg这样的文件名会被解析为image.asp。分号后面的内容被忽略,从而使一个看似是JPG的图片文件被当作ASP脚本执行。

  • 目录名解析漏洞

    :如果攻击者能够在服务器上创建一个名为shell.asp/的目录(注意后缀是/),那么该目录下的任何文件,无论其后缀是什么(如test.jpg),都会被IIS6.0当作ASP文件来解析和执行。

三、题目练习

(一)《从0到1:CTFer成长之路》书籍配套题目

  1. 打开题目环境,发现是一个文件上传题目,下面给出的源代码如下:
<?php
header("Content-Type:text/html; charset=utf-8");
// 每5分钟会清除一次目录下上传的文件
require_once('pclzip.lib.php');

if(!$_FILES){

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;echo&nbsp;'

&nbsp; &nbsp;&nbsp;;

&nbsp; &nbsp;&nbsp;show_source(__FILE__);
}else{
&nbsp; &nbsp;&nbsp;$file&nbsp;=&nbsp;$_FILES['file'];

&nbsp; &nbsp;&nbsp;if(!$file){
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;exit("请勿上传空文件");
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;$name&nbsp;=&nbsp;$file['name'];

&nbsp; &nbsp;&nbsp;$dir&nbsp;=&nbsp;'upload/';
&nbsp; &nbsp;&nbsp;$ext&nbsp;=&nbsp;strtolower(substr(strrchr($name,&nbsp;'.'),&nbsp;1));
&nbsp; &nbsp;&nbsp;$path&nbsp;=&nbsp;$dir.$name;

&nbsp; &nbsp;&nbsp;function&nbsp;check_dir($dir){
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;$handle&nbsp;=&nbsp;opendir($dir);
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;while(($f&nbsp;=&nbsp;readdir($handle)) !==&nbsp;false){
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if(!in_array($f,&nbsp;array('.',&nbsp;'..'))){
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if(is_dir($dir.$f)){
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;check_dir($dir.$f.'/');
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}else{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;$ext&nbsp;=&nbsp;strtolower(substr(strrchr($f,&nbsp;'.'),&nbsp;1));
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if(!in_array($ext,&nbsp;array('jpg',&nbsp;'gif',&nbsp;'png'))){
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;unlink($dir.$f);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;if(!is_dir($dir)){
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;mkdir($dir);
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;$temp_dir&nbsp;=&nbsp;$dir.md5(time().&nbsp;rand(1000,9999));
&nbsp; &nbsp;&nbsp;if(!is_dir($temp_dir)){
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;mkdir($temp_dir);
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;if(in_array($ext,&nbsp;array('zip',&nbsp;'jpg',&nbsp;'gif',&nbsp;'png'))){
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if($ext&nbsp;==&nbsp;'zip'){
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;$archive&nbsp;=&nbsp;new&nbsp;PclZip($file['tmp_name']);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;foreach($archive->listContent()&nbsp;as&nbsp;$value){
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;$filename&nbsp;=&nbsp;$value["filename"];
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if(preg_match('/\.php$/',&nbsp;$filename)){
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;exit("压缩包内不允许含有php文件!");
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;($archive->extract(PCLZIP_OPT_PATH,&nbsp;$temp_dir, PCLZIP_OPT_REPLACE_NEWER) ==&nbsp;0) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;check_dir($dir);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;exit("解压失败");
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;check_dir($dir);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;exit('上传成功!');
&nbsp; &nbsp; &nbsp; &nbsp; }else{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;move_uploaded_file($file['tmp_name'],&nbsp;$temp_dir.'/'.$file['name']);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;check_dir($dir);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;exit('上传成功!');
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }else{
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;exit('仅允许上传zip、jpg、gif、png文件!');
&nbsp; &nbsp; }
}
  1. 尝试选择一个jpg文件,上传成功。
  2. 建立木马php脚本,内容如下:
<?php
fputs(fopen('../hack.php','w'),'');
?>
  1. 尝试上传php,提示:仅允许上传zip、jpg、gif、png文件!
  2. 那只好尝试burpsuite拦截了,打开burpsuite,选择proxy选项卡,点击open browser打开内置浏览器,输入容器地址,然后选择php文件上传,好,burpsuite已经拦截到了。

  • 提示上传成功!,但访问提示404
  • 换个方式来,既然代码中提到要删除不合规文件,那么我们就将文件放到其他文件目录下,先将php改名为123456789.php.jpg,压缩到zip文件中,方便后续修改。
  • 使用二进制编辑器,例如ghex工具,打开zip文件,将其中最后一行的123456789改为/../../89
  • 上传文件,提示上传成功
  • 访问文件,即域名/89.php.jpg,得到flag为n1book{ThisIsUpLoadToPicfl4g}

  • 免责声明:

    本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

    任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

    本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

    本文转载自:书中自有代码来 书中自有代码来 书中自有代码来《CTF之文件上传——你知道我在你的服务器上放了什么吗》

    评论:0   参与:  0