Небезпечні виправлення релокацій у завантажувачах ассетів

Tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks

Чому релокації ассетів важливі

Багато застарілих ігрових движків (Granny 3D, Gamebryo тощо) завантажують складні ассети шляхом:

  1. Розбору заголовка і таблиці секцій.
  2. Виділення одного heap-буфера на секцію.
  3. Побудови SectionArray, який зберігає базовий вказівник кожної секції.
  4. Застосування таблиць релокацій, щоб вказівники, вбудовані у дані секцій, були виправлені на правильну цільову секцію + зсув.

Коли обробник релокацій сліпо довіряє метаданим, контрольованим атакувальником, кожна релокація стає потенційним примітивом довільного читання/запису. У Anno 1404: Venice, granny2.dll містить наступну допоміжну функцію:

`GrannyGRNFixUp_0` (trimmed) ```c int *__cdecl GrannyGRNFixUp_0(DWORD RelocationCount, Relocation *PointerFixupArray, int *SectionArray, char *destination) { while (RelocationCount--) { int target_base = SectionArray[PointerFixupArray->SectionNumber]; // unchecked index int *patch_site = (int *)(destination + PointerFixupArray->SectionOffset); // unchecked offset *patch_site = target_base ; if (target_base) *patch_site = target_base + PointerFixupArray->Offset; ++PointerFixupArray; } return SectionArray; } ```

SectionNumber ніколи не перевіряється в межах діапазону, а SectionOffset ніколи не валідується щодо поточного розміру секції. Створення записів релокації з від’ємними зсувами або занадто великими індексами дозволяє вийти за межі секції, якою ви керуєте, і перезаписати метадані аллокатора, такі як масив вказівників секцій.

Етап 1 – Запис у зворотному напрямку в метадані завантажувача

Мета — змусити таблицю релокацій section 0 перезаписати записи SectionContentArray (яка віддзеркалює SectionArray і зберігається безпосередньо перед першим буфером секції). Оскільки власний аллокатор Granny додає попередньо 0x1F байтів, а NT heap додає власний заголовок розміром 0x10 байтів плюс вирівнювання, атакуючий може препорахувати відстань між початком першої секції (destination) і масивом вказівників секцій.

У протестованій збірці примусове виділення завантажувачем структури GrannyFile точно розміром 0x4000 bytes змушує масиви вказівників секцій опинитися безпосередньо перед першим буфером секції. Розв’язання

0x20 (header) + 0x20 (section descriptors)
+ n * 1 (section types) + n * 1 (flags)
+ n * 4 (pointer table) = 0x4000

дає n = 2720 секцій. Запис релокації з SectionOffset = -0x3FF0 ( 0x4000 - 0x20 - 0x20 + 0x30 ) тепер резольвиться в SectionContentArray[1], хоча призначена секція думає, що вона патчує внутрішні покажчики.

Stage 2 – Детермінований макет heap у Windows 10

Windows 10 NT Heap маршрутизує алокації ≤ RtlpLargestLfhBlock (0x4000) у рандомізований LFH, а більші — до детермінованого backend allocator. Тримаючи метадані GrannyFile трохи вище цього порогу (використовуючи трюк з 2720 секціями) і попередньо завантаживши кілька зловмисних .gr2 asset-ів, ви можете зробити так, щоб:

  • Allocation #1 (metadata + section pointer arrays) опинилася в чанку бекенду >0x4000.
  • Allocation #2 (section 0 contents) виявилася відразу після allocation #1.
  • Allocation #3 (section 1 contents) опинилася відразу після allocation #2, даючи передбачувану ціль для наступних релокацій.

Process Monitor підтвердив, що assets стрімляться за потребою, тому повторні запити crafted units/buildings достатні, щоб «підготувати» макет heap без звернення до executable image.

Stage 3 – Перетворення примітиву в RCE

  1. Corrupt SectionContentArray[1]. Таблиця релокацій секції 0 перезаписує її, використовуючи зсув -0x3FF0. Вкажіть її на будь-яку записувану область, якою ви керуєте (наприклад, дані пізніших секцій).
  2. Recycle the corrupted pointer. Таблиця релокацій секції 1 тепер трактує SectionNumber = 1 як будь-який інжектований вами покажчик. Обробник записує SectionArray[1] + Offset у destination + SectionOffset, даючи вам довільний 4-байтовий запис для кожного запису релокації.
  3. Hit reliable dispatchers. В Anno 1404 ціллю вибору були allocator callbacks з granny2.dll (немає ASLR, DEP відключено). Перезапис функціонального покажчика, який granny2.dll використовує для наступного виклику Malloc/Free, негайно відхиляє виконання на код під контролем атакуючого, завантажений із троянізованого asset-а.

Оскільки і granny2.dll, і інжектовані буфери .gr2 перебувають за стабільними адресами, коли ASLR/DEP вимкнені, атака зводиться до побудови невеликого ROP chain або сирого shellcode і вказування callback-а на нього.

Практичний чекліст

  • Шукайте asset loaders, які підтримують SectionArray / relocation tables.
  • Diff relocation handlers на предмет відсутніх перевірок меж для індексів/зрушень.
  • Виміряйте заголовки аллокатора, додані як обгорткою аллокатора гри, так і самим OS heap, щоб точно обчислити зворотні зсуви.
  • Примусьте детерміноване розміщення, шляхом:
    • надування метаданих (багато порожніх секцій) до тих пір, поки розмір алокації не перевищить RtlpLargestLfhBlock;
    • повторного завантаження зловмисного asset-а, щоб заповнити дірки бекенду.
  • Використовуйте двоступеневу таблицю релокацій (спочатку для перенаправлення SectionArray, потім для розпилення записів) і перезапишіть функціональні покажчики, які спрацюють під час нормального рендерингу (allocator callbacks, virtual tables, animation dispatchers тощо).

Після того як ви отримаєте arbitrary file write (наприклад, через path traversal у передачі збережень для multiplayer), перепакування RDA архівів із crafted .gr2 дає чистий вектор доставки, який автоматично декомпресується віддаленими клієнтами.

References

Tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks