绕过文件上传限制实现客户端路径遍历漏洞利用的技术解析

news/2025/9/19 12:06:06/文章来源:https://www.cnblogs.com/qife122/p/19100522

绕过文件上传限制实现客户端路径遍历漏洞利用

在我之前的博客文章中,我演示了如何利用JSON文件作为客户端路径遍历(CSPT)的小工具来执行跨站请求伪造(CSRF)。那个例子很简单,因为没有强制执行文件上传限制。然而,现实世界的应用程序通常会对文件上传施加限制以确保安全。

在这篇文章中,我们将探讨如何绕过其中一些机制来实现相同的目标。我们将介绍常见的文件验证方法以及如何颠覆这些方法。

约束条件

在大多数场景中,小工具文件将在前端使用JSON.parse进行解析。这意味着我们的文件必须是JSON.parse的有效输入。

如果我们查看V8实现,有效的JSON输入包括:

  • 字符串
  • 数字
  • true
  • false
  • null
  • 数组
  • 对象

解析器会跳过起始的空白字符,例如:

  • ' '
  • '\t'
  • '\r'
  • '\n'

此外,JSON对象(键或值)中的控制字符和双引号会破坏JSON结构,必须进行转义。

我们的小工具文件必须遵循这些限制才能被解析为JSON。

不同的应用程序使用设计用于检测文件MIME类型、文件结构或魔数字节的库或工具来验证文件。通过创造性地制作满足这些条件的文件,我们可以欺骗这些验证并绕过限制。

让我们探讨如何绕过各种文件上传机制,以维护用于CSPT的有效JSON负载,同时满足文件格式要求,如PDF或图像。

绕过PDF检查以上传JSON文件

许多上传机制中的基本检查涉及验证文件的MIME类型。这通常通过Content-Type头或检查文件本身来完成。然而,通过操纵文件的结构或头信息,通常可以绕过这些检查。

绕过mmmagic验证

mmmagic库通常用于Node.js应用程序中,基于Magic数据库检测文件类型。

可以使用以下代码验证PDF文件:

async function checkMMMagic(binaryFile) {var magic = new Magic(mmm.MAGIC_MIME_TYPE);const detectAsync = (binaryFile) => {return new Promise((resolve, reject) => {magic.detect.call(magic, binaryFile, (error, result) => {if (error) {reject(error);} else {resolve(result);}});});};const result = await detectAsync(binaryFile);const isValid = (result === 'application/pdf')if (!isValid) {throw new Error('mmmagic: File is not a PDF : ' + result);}
}

技术方法:

该库检查%PDF魔数字节。它使用此处定义的Magic检测规则。然而,根据PDF规范,这个魔数字节不需要位于文件的最开头。

我们可以在JSON对象的前1024字节内包装一个PDF头。这将是一个有效的JSON文件,但被该库视为PDF。这使我们能够欺骗库接受上传为有效PDF,同时仍然允许浏览器将其解析为JSON。以下是一个示例:

{ "id" : "../CSPT_PAYLOAD", "%PDF": "1.4" }

只要%PDF头出现在前1024字节内,mmmagic库就会接受此文件作为PDF,但它仍然可以在客户端解析为JSON。

绕过pdflib验证

pdflib库需要的不仅仅是%PDF头。它可用于验证整体PDF结构。

async function checkPdfLib(binaryFile) {let pdfDoc = nulltry {pdfDoc = await PDFDocument.load(binaryFile);} catch (error) {throw new Error('pdflib: Not a valid PDF')}if (pdfDoc.getPageCount() == 0) {throw new Error('pdflib: PDF doesn\'t have a page');}
}

技术方法:

为了绕过这一点,我们可以创建一个有效的PDF(对于pdflib),同时仍然符合CSPT所需的JSON结构。

技巧是将PDF对象定义之间的%0A(换行符)字符替换为空格%20。这允许文件被识别为pdflib的有效PDF,但仍然可以解释为JSON。xref表不需要修复,因为我们的目标不是显示PDF,而是通过上传验证。

以下是一个示例:

{"_id":"../../../../CSPT?","bypass":"%PDF-1.3 1 0 obj <<   /Pages 2 0 R   /Type /Catalog >> endobj 2 0 obj <<   /Count 1   /Kids [     3 0 R   ]   /Type /Pages >> endobj 3 0 obj <<   /Contents 4 0 R   /MediaBox [ 0 0 200 200 ]   /Parent 2 0 R   /Resources <<     /Font << /F1 5 0 R >>   >>   /Type /Page >> endobj 4 0 obj <<   /Length 50 >> stream BT   /F1 10 Tf   20 100 Td   (CSPT) Tj ET endstream endobj 5 0 obj <<   /Type /Font   /Subtype /Type1   /BaseFont /Helvetica >> endobj xref 0 6 0000000000 65535 f 0000000009 00000 n 0000000062 00000 n 0000000133 00000 n 0000000277 00000 n 0000000370 00000 n trailer <<   /Size 6   /Root 1 0 R >> startxref 447 %%EOF "}

虽然此PDF在最近的PDF查看器中不会渲染,但它将被pdflib读取并通过文件上传检查。

绕过file命令验证

在某些环境中,使用file命令或基于file的库来检测文件类型。

async function checkFileCommand(binaryFile) {//Write a temporary fileconst tmpobj = tmp.fileSync();fs.writeSync(tmpobj.fd, binaryFile);fs.closeSync(tmpobj.fd);// Exec file commandoutput = execFileSync('file', ["-b", "--mime-type", tmpobj.name])const isValid = (output.toString() === 'application/pdf\n')if (!isValid) {throw new Error(`content - type: File is not a PDF : ${output}`);}tmpobj.removeCallback();
}

技术方法:

与mmmagic的区别在于,在检查魔数字节之前,它会尝试将文件解析为JSON。如果成功,该文件将被视为JSON,并且不会执行其他检查。因此我们不能使用与mmmagic相同的技巧。然而,file命令对其可以处理的文件大小有已知限制。这是man file命令的摘录。

     -P, --parameter name=valueSet various parameter limits.Name         Default    Explanationbytes        1048576    max number of bytes to read from fileelf_notes    256        max ELF notes processedelf_phnum    2048       max ELF program sections processedelf_shnum    32768      max ELF sections processedencoding     65536      max number of bytes for encoding evaluationindir        50         recursion limit for indirect magicname         60         use count limit for name/use magicregex        8192       length limit for regex searches

我们可以看到读取字节数的限制。我们可以通过用空白字符(如空格或制表符)填充文件直到超过解析限制来利用此限制。一旦达到限制,file_is_json函数将失败,文件将被分类为不同的文件类型(例如PDF)。

例如,我们可以创建这样的文件:

{"_id": "../../../../CSPT?","bypass": "%PDF-1.3 1 0 obj <<   /Pages 2 0 R   /Type /Catalog >> endobj 2 0 obj <<   /Count 1   /Kids [     3 0 R   ]   /Type /Pages >> endobj 3 0 obj <<   /Contents 4 0 R   /MediaBox [ 0 0 200 200 ]   /Parent 2 0 R   /Resources <<     /Font << /F1 5 0 R >>   >>   /Type /Page >> endobj 4 0 obj <<   /Length 50 >> stream BT   /F1 10 Tf   20 100 Td   (CSPT) Tj ET endstream endobj 5 0 obj <<   /Type /Font   /Subtype /Type1   /BaseFont /Helvetica >> endobj xref 0 6 0000000000 65535 f 0000000009 00000 n 0000000062 00000 n 0000000133 00000 n 0000000277 00000 n 0000000370 00000 n trailer <<   /Size 6   /Root 1 0 R >> startxref 447 %%EOF <..大量空格..> "

上传时,file命令将无法解析这个大型JSON结构,导致它回退到正常的文件检测并将文件视为PDF。

使用WEBP格式绕过图像上传的文件类型限制

图像上传通常使用像file-type这样的库来验证文件格式。以下代码尝试确保上传的文件是图像。

const checkFileType = async (binary) => {const { fileTypeFromBuffer } = await fileType();const type = await fileTypeFromBuffer(binary);const result = type.mime;const isValid = result.startsWith('image/');if (!isValid) {throw new Error('file-type: File is not an image : ' + result);}
};

技术方法:

有时,这些库会在预定义的偏移量检查特定的魔数字节。在此示例中,file-type检查魔数字节是否出现在偏移量8处:

https://github.com/sindresorhus/file-type/blob/v19.6.0/core.js#L358C1-L363C1

if (this.checkString('WEBP', {offset: 8})) {return {ext: 'webp',mime: 'image/webp',};
}

由于我们控制起始字节,我们可以构建一个有效的JSON文件。我们可以制作一个JSON对象,将魔数字节(WEBP)放在正确的偏移量处,允许文件通过验证作为图像,同时仍然是有效的JSON对象。以下是一个示例:

{"aaa":"WEBP","_id":"../../../../CSPT?"}

此文件将通过file-type的图像检查,同时仍然包含可用于CSPT的JSON数据。

结论

绕过文件上传限制并不是什么新鲜事,但我们想分享一些过去几年中在实施文件上传限制时上传JSON小工具的方法。我们使用它们来执行CSPT2CSRF或任何其他漏洞利用(XSS等),但它们也可以应用于其他上下文。不要犹豫,深入研究第三方源代码以了解其工作原理。

所有这些示例和文件都已包含在我们的CSPTPlayground中。该游乐场不仅包括CSPT2CSRF,还包括其他示例,如JSONP小工具或开放重定向。这是基于Isira Adithya(@isira_adithya)和Justin Gardner(@Rhynorater)收到的反馈构建的。非常感谢!

更多信息

如果您想了解更多关于我们其他研究的信息,请查看我们的博客,在X(@doyensec)上关注我们,或者随时通过info@doyensec.com与我们联系,以获取有关我们如何帮助您的组织"构建安全"的更多信息。
更多精彩内容 请关注我的个人公众号 公众号(办公AI智能小助手)
公众号二维码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/907756.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

事件总线之初步学习

第一步:创建一个eventBus.js 文件名可根据个人爱好取名即可; 内容:import Vue from vue const eventBus = new Vue(); export default eventBus;第二步:使用import EventBus from @/common/eventBus;//监听全局事…

PolarFire SoC QSPI 代码编写 测试

PolarFire SoC QSPI 代码编写 测试1、 首先 将 QSPI 基地址 改为 SC-QSPI 基地址 0x37020100 原因如下: PolarFire FPGA and PolarFire SoC FPGA Programming User Guide MSS connects to the system controller QS…

Markdown Day04

常用DOS命令 ##查看当前目录下所有文件dir ##切换目录cd change directory ##cd..回到上一个 ##清理屏幕cls ##退出exit ##查看电脑IP,ipconfig ##打开应用 calc notepad mspaint ##ping 命令 ping www.baidu.com #…

C++中类的内存存储

目录类类对象的非虚成员函数类的成员变量空类对象具有虚函数的类对象 类 类本身不会存储在内存中,类实例化的对象才会保存在内存中。但是使用 sizeof 计算类大小时能得到结果,这是因为 sizeof 会在编译时就得到类型信…

PyTorch 优化器(Optimizer)

优化器(Optimizer)是深度学习训练过程中用于更新模型参数的核心组件。在训练神经网络时,我们需要通过反向传播计算损失函数相对于模型参数的梯度,然后使用优化器根据这些梯度来更新参数,以最小化损失函数。PyTorc…

实用指南:域名市场中,如何确认域名的价值

实用指南:域名市场中,如何确认域名的价值pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "…

初步了解Neo4j

1. 是什么? Neo4j 是一个原生图数据库。它与我们熟悉的关系型数据库(如 MySQL, PostgreSQL)和 NoSQL 数据库(如 MongoDB)有根本性的不同,因为它专门为存储和查询数据之间的关系而设计。 它的核心哲学是:“关系即…

多模态和语音 AI 年度收官大会,把握 2026 技术风向标!

如果今年只参加一场多模态和语音 AI 大会,来 Convo AI & RTE2025 就够了。你是否好奇:1⃣从端到端语音模型和全双工技术,未来音频还将有哪些突破方向?2⃣如何挖掘端侧 AI 潜能,定义下一代智能硬件终端?3⃣从…

做题

P4159 [SCOI2009] 迷路 矩阵快速幂优化递推。 首先最暴力的想法,设 $ f_{i,j} $ 在 $ j $ 时刻,到达点 $ i $ 的种类数。 枚举时间和 $ i $,然后 $ f_{i,j} = \sum\limits_{k=1}^n {f_{k,j-w[i][k]}} $。 时间很大,…

解码C语言函数

一、函数基本概念 1.1 函数定义 概念:把一个功能的实现流程封装起来,使用户留下接口进行调用 作用:参数创建该功能进行封装操作,返回值即通过功能显示的产出 1.2 函数组成要素返回值类型:根据函数功能而定,需要在…

Pod自动重启困难排查:JDK 17 EA版本G1GC Bug导致的应用崩溃

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

SchemaStore

Hello World本文来自博客园,作者:南宫影,转载请注明原文链接:https://www.cnblogs.com/nangongying/p/19100468

XSS攻击防御

目录背景和价值为什么需要输出编码?不同场景下的编码方式(白话版)1. 最常见场景:内容显示在HTML标签里(比如<div>、<span>中)2. 特殊场景:内容显示在HTML标签的属性里(比如value、href中)3. 特殊…

imes开发部署

一.git地址下载源码 二.后端设置 1.增加配置文件:ktg-admin/src/main/resources/application-test.yml2.临时修改代码:ktg-mes/src/main/java/com/ktg/mes/task/MesTask.java,如图注释2行。 3.快捷键Ctrl+Alt+Shif…

思维题做题记录-1

CF2600左右有趣的思维题做题记录-1 CF1458C. Latin Square 考虑将原矩阵写成 \(n\times n\) 个限制形如 \((i,j,a_{i,j})\),那么所有操作就是对这些限制进行的修改:对于 UD 操作相当于将限制改为 \((i\mp 1,j,a_{i,j…

如何在极短时间内通透一个大型开源项目

如何在极短时间内通透一个大型开源项目前言 在现代软件开发中,快速理解和掌握大型开源项目是一项至关重要的技能。无论是参与开源贡献、技术选型,还是学习先进架构模式,都需要我们具备高效解读项目的能力。本文将以…

LCT学习笔记

LCT学习笔记从例题开始: P3690 【模板】动态树(LCT) 对于一棵静态的树,常见方法是树剖然后走链,但是在动态的情况下常见的重链或长链就会很慢,因为修改连边情况后就不满足性质了 引入一个新的方法:实链剖分,对…

Visual Studio 2026 Insiders 重磅发布:AI 深度集成、性能飞跃、全新设计

近日,微软正式发布 Visual Studio 2026 Insiders!这是迄今为止 Visual StudioE 极具跨越式的一次升级。新版本不仅将 AI 深度融入开发工作流,还带来了企业级性能的显著提升,以及更轻盈、现代的界面设计,全面提升开…

《刚刚问世》系列初窥篇-Java+Playwright自动化测试-29- 操作单选和多选按钮 - 下篇(详细教程) - 北京

1.简介 我们可能会遇到一直测试单选和复选按钮的测试场景,如果就十几道选择题,那就手工点击,马上完事,但是如果是让你测试题库呢?那不得那鼠标点击冒烟了,手指点到抽筋了。尤其是做教育类的软件测试,这些就是家…