House of Roman

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

Основна інформація

Це була дуже цікава техніка, яка дозволяла RCE без leaks через fake fastbins, unsorted_bin attack та relative overwrites. Однак вона була patched.

Застосовність у 2026

  • glibc window: Працює надійно на 2.23–2.27 (how2heap PoC тестував 2.23–2.25). Починаючи з 2.28, патч “additional checks for unsorted bin integrity” робить unsorted‑bin запис ненадійним, тож шанс успіху різко падає. З 2.34 і далі __malloc_hook/__free_hook були видалені, через що первісна ціль недоступна. Використовуйте це лише на старих libc (або custom build’ах, що зберігають hooks) або для CTF задач, що постачають стару libc.
  • Tcache era (≥2.26): Tcache “з’їсть” ваші 0x70 алокації і зупинить fastbin/unsorted примітиви. Вимкніть його (setenv("GLIBC_TUNABLES","glibc.malloc.tcache_count=0",1);) перед будь‑якою алокацією або заповніть кожен 0x70 tcache bin 7 frees, щоб його спорожнити.
  • Safe-linking: Застосовується до tcache/fastbin у ≥2.32, але House of Roman потребує лише partial pointer overwrite існуючої libc адреси вже присутньої в fd/bk, тож safe-linking тут не допомагає захиснику (атакувальник ніколи не фальсифікує новий вказівник). Справжніми перешкодами є видалення hook’ів і перевірки unsorted‑bin.

Код

Мета

  • RCE шляхом зловживання relative pointers

Вимоги

  • Змінювати вказівники fastbin та unsorted bin
  • Потрібно брутфорсити 12 біт випадковості (ймовірність успіху 0.02%)

Кроки атаки

Part 1: Fastbin Chunk points to __malloc_hook

Створіть кілька chunks:

  • fastbin_victim (0x60, offset 0): UAF chunk пізніше буде відредаговано, щоб вказувати на значення LibC.
  • chunk2 (0x80, offset 0x70): Для гарного вирівнювання
  • main_arena_use (0x80, offset 0x100)
  • relative_offset_heap (0x60, offset 0x190): відносний офсет на chunk ‘main_arena_use’

Потім free(main_arena_use), що помістить цей chunk в unsorted list і запише в fd та bk вказівники на main_arena + 0x68.

Тепер алокується новий chunk fake_libc_chunk(0x60), бо він міститиме в fd та bk вказівники на main_arena + 0x68.

Потім звільняються relative_offset_heap та fastbin_victim.

/*
Current heap layout:
0x0:   fastbin_victim       - size 0x70
0x70:  alignment_filler     - size 0x90
0x100: fake_libc_chunk      - size 0x70 (contains a fd ptr to main_arena + 0x68)
0x170: leftover_main        - size 0x20
0x190: relative_offset_heap - size 0x70

bin layout:
fastbin:  fastbin_victim -> relative_offset_heap
unsorted: leftover_main
*/
  • fastbin_victim має fd, що вказує на relative_offset_heap
  • relative_offset_heap — це зсув від fake_libc_chunk, який містить вказівник на main_arena + 0x68
  • Зміна останнього байта fastbin_victim.fd змушує fastbin_victim вказувати на main_arena + 0x68.

Для попередніх дій атакуючий повинен мати можливість змінювати вказівник fd у fastbin_victim.

Далі main_arena + 0x68 не надто цікавий, тож модифікуємо його, щоб вказівник вказував на __malloc_hook.

Зауважте, що __memalign_hook зазвичай починається з 0x7f і має нулі перед ним, тому його можна підробити як значення в 0x70 fast bin. Оскільки останні 4 біти адреси є random, існує 2^4=16 можливостей, щоб значення в кінці вказувало туди, що нас цікавить. Тому тут виконується BF attack, тож чанк виглядає так: 0x70: fastbin_victim -> fake_libc_chunk -> (__malloc_hook - 0x23).

(Для отримання додаткової інформації про решту байтів перегляньте пояснення в the how2heap example). Якщо brute force зазнає невдачі, програма просто падає (перезапускайте, поки не спрацює).

Потім виконуються 2 mallocs, щоб видалити 2 початкові fast bin chunks, і виділяється третій, щоб отримати чанк в __malloc_hook.

malloc(0x60);
malloc(0x60);
uint8_t* malloc_hook_chunk = malloc(0x60);

Part 2: Unsorted_bin attack

Для детальнішої інформації дивіться:

Unsorted Bin Attack

Але по суті це дозволяє записати main_arena + 0x68 у будь-яке місце, вказане в chunk->bk. Для атаки ми обираємо __malloc_hook. Потім, після його overwrite, ми використаємо relative overwrite, щоб вказати на one_gadget.

Для цього ми спочатку отримуємо chunk і поміщаємо його в unsorted bin:

uint8_t* unsorted_bin_ptr = malloc(0x80);
malloc(0x30); // Don't want to consolidate

puts("Put chunk into unsorted_bin\n");
// Free the chunk to create the UAF
free(unsorted_bin_ptr);

Використайте UAF у цьому чанку, щоб вказати unsorted_bin_ptr->bk на адресу __malloc_hook (we brute forced this previously).

Caution

Note that this attack corrupts the unsorted bin (hence small and large too). So we can only use allocations from the fast bin now (a more complex program might do other allocations and crash), and to trigger this we must alloc the same size or the program will crash.

Отже, щоб викликати запис main_arena + 0x68 у __malloc_hook після встановлення __malloc_hook у unsorted_bin_ptr->bk нам достатньо виконати: malloc(0x80)

Step 3: Set __malloc_hook to system

На кроці першому ми контролювали чанк, що містив __malloc_hook (в змінній malloc_hook_chunk), а на другому кроці нам вдалося записати туди main_arena + 0x68.

Тепер ми зловживаємо частковим перезаписом в malloc_hook_chunk, щоб використати адресу libc, яку записали туди (main_arena + 0x68), щоб вказати на адресу one_gadget.

Саме тут потрібно bruteforce 12 bits of randomness (more info in the how2heap example).

Нарешті, як тільки правильну адресу буде перезаписано, викличте malloc і запустіть one_gadget.

Modern tips & variants

  • Unsorted-bin hardening (2.28+): Додаткові перевірки цілісності для unsorted chunks (size sanity + list linkage) роблять класичний unsorted‑bin write крихким. Щоб пережити _int_malloc, потрібно зберегти консистентні fd/bk посилання та правдоподібні розміри, що зазвичай вимагає потужніших примітивів, ніж простий partial overwrite.
  • Hook removal (2.34+): Якщо __malloc_hook відсутній, адаптуйте примітив, щоб потрапити на будь-яку записувану GOT/global змінну, яку пізніше можна повторно використати (наприклад, перезаписати exit@GOT у non-PIE бінарниках), або зробіть pivot до стилю House of Pie top‑chunk hijack, щоб контролювати top замість хуку.
  • Any‑address fastbin alloc (romanking98 writeup): Друга частина показує, як відновити 0x71 freelist і використати unsorted‑bin write, щоб отримати fastbin allocation над __free_hook, потім помістити system("/bin/sh") і викликати його через free() на libc‑2.24 (pre-hook removal).

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