Переведено для xss.pro
Оригинал: https://blog.doyensec.com/2025/01/09/cspt-file-upload.html
09 Jan 2025 - Posted by Maxence Schmitt
Посмотреть вложение 1750175245754.png
В моей предыдущей статье я продемонстрировал, как файл JSON может использоваться в качестве гаджета для обхода пути на стороне клиента (Client-Side Path Traversal) с целью подделки межсайтовых запросов (Cross-Site Request Forgery). Этот пример был простым, поскольку не было никаких ограничений на загрузку файлов. Однако реальные приложения часто накладывают ограничения на загрузку файлов с целями безопасности.
В этой статье мы рассмотрим, как обойти некоторые из этих механизмов, чтобы достичь той же цели. Мы поговорим о распространенных методах проверки файлов и о том, как их можно обойти.
Наш файл гаджета должен соответствовать этим ограничениям, чтобы его можно было анализировать как JSON.
Различные приложения проверяют файлы, используя библиотеки или инструменты, предназначенные для определения типа MIME файла, структуры файла или магических байтов. Творческий подход к созданию файлов, которые соответствуют этим условиям, поможет нам обмануть эти проверки и обойти ограничения.
Давайте рассмотрим, как можно обойти различные механизмы загрузки файлов, чтобы полезные нагрузки JSON оставались допустимыми для CSPT, удовлетворяя при этом требования формата файла, например, PDF или изображения.
Мы можем обернуть заголовок PDF в первые 1024 байта объекта JSON. Это будет допустимый файл JSON, рассматриваемый библиотекой как PDF. Это позволяет нам обмануть библиотеку, заставив ее принять загрузку как допустимый PDF, при этом браузер все еще может анализировать ее как JSON. Вот пример:
Если заголовок
Вот пример:
Хотя этот PDF файл не будет отображаться в последних средствах просмотра PDF, он будет доступен pdflib для чтения и пройдет проверки загрузки файла.
Мы видим ограничение на количество байтов для чтения. Мы можем использовать это ограничение в своих интересах, дополняя файл пробельными (whitespace) символами (например, пробелами или табуляциями) до тех пор, пока файл не превысит ограничение. В таком случае функция
Например, мы можем создать такой файл:
При загрузке команда file не сможет проанализировать эту большую структуру JSON, что заставит ее вернуться к обычному обнаружению файла и обрабатывать файл как PDF.
https://github.com/sindresorhus/file-type/blob/v19.6.0/core.js#L358C1-L363C1
Поскольку у нас есть контроль над начальными байтами, мы можем создать допустимый файл JSON. Мы можем подготовить объект JSON, который размещает магические байты (
Этот файл пройдет проверку типа файла для изображений, но при этом по-прежнему будет содержать данные JSON, которые можно использовать для CSPT.
Все эти примеры и файлы были опубликованы на нашей CSPTPlayground. Ресурс содержит не только CSPT2CSRF, но и другие примеры, такие как гаджет JSONP или Open Redirect. Это результат обратной связи, полученной от Исиры Адитьи (@isira_adithya) и Джастина Гарднера (@Rhynorater). Большое спасибо!
Оригинал: https://blog.doyensec.com/2025/01/09/cspt-file-upload.html
09 Jan 2025 - Posted by Maxence Schmitt
Посмотреть вложение 1750175245754.png
В моей предыдущей статье я продемонстрировал, как файл JSON может использоваться в качестве гаджета для обхода пути на стороне клиента (Client-Side Path Traversal) с целью подделки межсайтовых запросов (Cross-Site Request Forgery). Этот пример был простым, поскольку не было никаких ограничений на загрузку файлов. Однако реальные приложения часто накладывают ограничения на загрузку файлов с целями безопасности.
В этой статье мы рассмотрим, как обойти некоторые из этих механизмов, чтобы достичь той же цели. Мы поговорим о распространенных методах проверки файлов и о том, как их можно обойти.
Ограничение
В большинстве сценариев файл гаджета будет проанализирован на клиентской стороне с помощьюJSON.parse. Это означает, что наш файл должен быть допустимыми входными данными для JSON.parse. Если мы посмотрим на реализацию V8, допустимые входные данные JSON:- строка
- число
- true
- false
- null
- массив
- объект
- ’ ‘
- ‘\t’
- ‘\r’
- ‘\n’
Наш файл гаджета должен соответствовать этим ограничениям, чтобы его можно было анализировать как JSON.
Различные приложения проверяют файлы, используя библиотеки или инструменты, предназначенные для определения типа MIME файла, структуры файла или магических байтов. Творческий подход к созданию файлов, которые соответствуют этим условиям, поможет нам обмануть эти проверки и обойти ограничения.
Давайте рассмотрим, как можно обойти различные механизмы загрузки файлов, чтобы полезные нагрузки JSON оставались допустимыми для CSPT, удовлетворяя при этом требования формата файла, например, 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, это магическое число не обязательно должно быть в самом начале файла.Мы можем обернуть заголовок PDF в первые 1024 байта объекта JSON. Это будет допустимый файл 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 = null
try {
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), который все еще будет соответствовать структуре JSON, требуемой для CSPT. Хитрость заключается в замене символов%0A (перевод строки) между определениями объектов PDF на пробел %20. Это позволит файлу распознаваться как допустимый PDF для pdflib, но при этом интерпретироваться как 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.
Код:
async function checkFileCommand(binaryFile) {
//Write a temporary file
const tmpobj = tmp.fileSync();
fs.writeSync(tmpobj.fd, binaryFile);
fs.closeSync(tmpobj.fd);
// Exec file command
output = 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=value
Set various parameter limits.
Name Default Explanation
bytes 1048576 max number of bytes to read from file
elf_notes 256 max ELF notes processed
elf_phnum 2048 max ELF program sections processed
elf_shnum 32768 max ELF sections processed
encoding 65536 max number of bytes for encoding evaluation
indir 50 recursion limit for indirect magic
name 60 use count limit for name/use magic
regex 8192 length limit for regex searches
Мы видим ограничение на количество байтов для чтения. Мы можем использовать это ограничение в своих интересах, дополняя файл пробельными (whitespace) символами (например, пробелами или табуляциями) до тех пор, пока файл не превысит ограничение. В таком случае функция
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 <..A LOT OF SPACES..> "}При загрузке команда 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?"}Этот файл пройдет проверку типа файла для изображений, но при этом по-прежнему будет содержать данные JSON, которые можно использовать для CSPT.
Заключение
Обход ограничений на загрузку файлов — не новая информация, но мы хотели поделиться некоторыми методами, которые мы использовали в прошлые годы для загрузки гаджетов JSON при наличии ограничений на загрузку файлов. Нашей целью было применение CSPT2CSRF или любых других эксплойтов (XSS и т. д.), но наши методы можно использовать и в других контекстах. Не стесняйтесь изучать сторонний исходный код, чтобы понять, как все это работает.Все эти примеры и файлы были опубликованы на нашей CSPTPlayground. Ресурс содержит не только CSPT2CSRF, но и другие примеры, такие как гаджет JSONP или Open Redirect. Это результат обратной связи, полученной от Исиры Адитьи (@isira_adithya) и Джастина Гарднера (@Rhynorater). Большое спасибо!