从一次失败的Getshell到成功的XSS:我的文件上传漏洞挖掘复盘笔记
从受限上传到XSS突破:一次文件上传漏洞的迂回战术
那天下午的阳光透过百叶窗斜斜地打在显示器上,我正百无聊赖地测试一个私人项目的"协助请求"功能。这个看似普通的表单里藏着一个附件上传点——正是这个不起眼的功能,后来让我经历了一次从挫败到惊喜的漏洞挖掘之旅。
1. 初探上传点:严格的白名单防御
第一次接触这个上传功能时,我像往常一样先上传了正常的图片文件。服务器返回的响应引起了我的注意:
{ "result": true, "message": "/UploadFiles/user123/2023/3021d74f18ddasdasd50abe934f.png", "code": 0 }关键发现是:上传的文件被存放在同源域名下。这意味着如果我能上传恶意文件,其危害程度将大大增加。
接下来是常规的模糊测试:
- 尝试上传.html文件 → 返回"不支持该文件类型"
- 测试.php、.asp等常见危险扩展 → 同样被拦截
- 使用Burp Intruder进行扩展名爆破 → 触发速率限制
经过多次尝试,确认了服务器的防御策略:
- 白名单机制:仅允许jpg、jpeg、png、gif四种扩展名
- 文件重命名:上传后自动生成随机文件名
- 基础过滤:拒绝包含特殊字符的文件名
2. 发现突破口:异常扩展名的玄机
就在准备放弃Getshell尝试时,一个偶然的发现改变了整个方向。我注意到服务器对扩展名的处理有个有趣特性:
badfile.''gif→ 上传成功badfile.foo''gif→ 上传失败
这说明服务器可能只检查最后一个点号后的扩展名,且允许扩展名中包含引号等特殊字符。于是构造了如下测试文件:
-----------------------------6683303835495 Content-Disposition: form-data; name="upload"; filename="xss.''gif" Content-Type: image/png GIF89a <html><script>alert('XSS');</script></html> -----------------------------6683303835495--服务器竟然接受了这个文件!虽然它有着.gif扩展名,但内容却是HTML代码。更关键的是,当用Edge浏览器访问时,弹窗出现了——存储型XSS漏洞就这样被触发了。
3. 技术原理深度解析
3.1 服务器端的校验逻辑
通过反复测试,我绘制了服务器的校验流程:
| 检查项 | 实现方式 | 可绕过性 |
|---|---|---|
| 扩展名校验 | 白名单匹配最后一个点号后的后缀 | 中(允许特殊字符) |
| 文件头校验 | 检查前4-8字节是否符合图片格式 | 高(可伪造) |
| 内容扫描 | 无深度内容检测 | 高 |
关键突破点在于:
- 伪造合法的图片文件头(如GIF89a)
- 利用异常扩展名(含特殊字符)
- 依赖浏览器特性实现最终利用
3.2 浏览器MIME嗅探差异
不同浏览器对这类文件的处理方式截然不同:
Chrome/Firefox:
- 严格检查完整文件头
- 对异常内容进行预处理
- 不会执行混在图片中的JS代码
Edge/IE:
- 存在MIME嗅探漏洞
- 根据内容而非声明类型解析文件
- 当检测到HTML标签时会以text/html方式渲染
// 典型利用代码结构 GIF89a <html> <script> // 可插入更复杂的攻击载荷 alert(document.cookie); </script> </html>4. 扩展攻击面:更多可能的利用方式
除了已发现的技巧,这类上传漏洞还有多种可能的利用姿势:
4.1 非常规扩展名利用
- 空格插入:如
exploit.j pg - 多重扩展:如
exploit.png.html - 特殊编码:如
exploit.%70%68%70
注意:这些方法需要根据具体服务器的解析逻辑进行调整,不是所有环境都适用
4.2 SVG文件的XSS潜力
如果服务器允许上传SVG图像,可以直接构造:
<svg xmlns="http://www.w3.org/2000/svg" onload="alert(document.domain)"/>SVG的XSS优势:
- 被当作合法图像格式
- 支持完整的JavaScript执行
- 在所有现代浏览器中都有效
4.3 结合其他漏洞提升危害
- CSP绕过:如果站点有宽松的CSP策略
- DOM型XSS:配合客户端漏洞实现组合攻击
- 权限提升:结合CSRF等漏洞扩大影响范围
5. 防御方案与实战建议
5.1 开发者防护措施
| 防护层 | 具体措施 | 有效性 |
|---|---|---|
| 输入验证 | 严格限制允许的字符集 | ★★★★☆ |
| 文件校验 | 检查完整文件内容而不仅是头部 | ★★★★★ |
| 存储隔离 | 将上传文件存放在不同域名下 | ★★★☆☆ |
| 输出编码 | 对所有动态内容进行适当编码 | ★★★★☆ |
5.2 渗透测试者的方法论
- 永不放弃:当主要攻击路径受阻时,寻找旁路
- 全面记录:详细记录每次测试的请求和响应
- 环境认知:了解各种浏览器和服务器特性的差异
- 工具组合:善用Burp、FuzzDB等工具提高效率
这次经历让我深刻体会到,漏洞挖掘往往不是直线前进的过程。那个下午看似失败的Getshell尝试,最终却因为对细节的观察和对浏览器特性的了解,演变成了一次成功的XSS发现。在安全测试中,灵活变通的思维和坚持不懈的态度,有时比掌握某个具体的技术点更为重要。
