VirtualBox Slirp NAT Packet Heap Exploitation

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

TL;DR

  • VirtualBox постачається зі сильно модифікованим форком Slirp, буфери пакетів (mbufs) якого розміщуються в кастомному зональному аллокаторі з вбудованими метаданими та callback-ами через вказівники на функції (pfFini, pfDtor).
  • Гість може перезаписати довірений m->m_len значенням довжини IP-заголовка, контрольованим атакуючим, що руйнує всі подальші перевірки меж і дає і infoleak, і overwrite-примітиви.
  • Зловживаючи UDP-пакетами з контрольною сумою 0 і завеликою ip_len, гість може exfiltrate хвости mbuf і метадані сусідніх чанків, щоб дізнатися адреси heap і zone.
  • Надання зіпсованих IP-опцій примушує ip_stripoptions() виконати memcpy() занадто багато даних на місці, тому атакуючий може перезаписати заголовок struct item наступного mbuf і вказати його поле zone на повністю контрольовані дані.
  • Звільнення пошкодженого mbuf викликає zone->pfFini() з аргументами, наданими атакуючим; спрямування його на memcpy@plt дає довільний примітив копіювання/запису, який можна спрямувати на GOT entries або інші контрольні дані всередині non-PIE бінарника VirtualBox.

Packet allocator anatomy

VirtualBox виділяє кожен вхідний Ethernet-кадр із зони, пов’язаної з інтерфейсом, яка має ім’я zone_clust. Кожен 0x800-байтовий фрагмент даних передує вбудований заголовок:

struct item {
uint32_t magic;      // 0xdead0001
void    *zone;       // uma_zone_t pointer with callbacks
uint32_t ref_count;
LIST_ENTRY(item) list; // freelist / used list links
};

Коли mbuf звільняється, стек викликів m_freem -> ... -> slirp_uma_free() покладається на inline-заголовок:

  1. uma_zfree_arg() перераховує item = (struct item *)mem - 1 і повинен перевіряти item->zone, але Assert() виключено в релізних збірках.
  2. slirp_uma_free() завантажує zone = item->zone та безумовно виконує zone->pfFini(zone->pData, data_ptr, zone->size) а потім zone->pfDtor(...).

Отже, будь-який write-what-where у заголовку mbuf перетворюється на керований непрямий виклик під час free().

Infoleak via m->m_len override

На початку ip_input() VirtualBox додав:

if (m->m_len != RT_N2H_U16(ip->ip_len))
m->m_len = RT_N2H_U16(ip->ip_len);

Оскільки присвоєння відбувається до перевірки IP-заголовка, гість може рекламувати будь-яку довжину до 0xffff. Решта стеку (ICMP, UDP, обробники фрагментації тощо) вважає m->m_len довіреним і використовує його для визначення, скільки байтів копіювати з mbuf.

Використовуйте UDP-пакети з контрольною сумою 0 (що означає “без checksum”). NAT fast-path пересилає m->m_len байт без перевірки цілісності payload, тож збільшення ip_len змушує Slirp читати поза реальним буфером і повертати heap residues гостю або співпрацюючому зовнішньому хелперу за NAT. Оскільки розмір чунку — 2048 байт, leak може включати:

  • Наступний mbuf’овий inline struct item, що відкриває порядок freelist і реальний вказівник zone.
  • Heap cookies, такі як поля magic, які допомагають сформувати валідні заголовки при пізніших корупціях.

Overwriting neighbouring chunk headers with IP options

Ту ж підроблену довжину можна перетворити на примітив перезапису, змусивши пакет пройти через ip_stripoptions() (запускається коли IP-заголовок має options і payload — UDP/TCP). Хелпер обчислює довжину копіювання з m->m_len, а потім викликає memcpy() щоб зсунути transport header поверх видалених options:

  1. Подайте довгий ip_len, щоб обчислена довжина переміщення виходила за межі поточного mbuf.
  2. Включіть невелику кількість IP options, щоб Slirp зайшов у шлях strip.
  3. Коли виконається memcpy(), воно читає з наступного mbuf і записує поверх payload поточного mbuf та inline header, пошкоджуючи magic, zone, ref_count тощо.

Оскільки аллокатор тримає пакети з того ж інтерфейсу суміжними в freelist, цей overflow детерміністично вражає наступний чанк після помірного heap grooming.

Forging uma_zone_t to hijack pfFini

Як тільки суміжний struct item стає коруптним, експлойт рухається так:

  1. Використайте влиті heap-адреси щоб побудувати підробну структуру uma_zone всередині mbuf повністю контрольованого гостем. Заповніть:
  • pfFini з PLT-entry для memcpy().
  • pData вказівником бажаного місця призначення (наприклад GOT entry, vtable slot, function pointer array).
  • size кількістю байтів для копіювання.
  • Опційно: pfDtor як виклик другого етапу (наприклад, щоб викликати щойно записаний вказівник функції).
  1. Перезапишіть поле zone цільового mbuf вказівником на підроблену структуру; відрегулюйте вказівники list так, щоб облік freelist лишався достатньо консистентним, щоб уникнути крашів.
  2. Звільніть mbuf. slirp_uma_free() тепер виконує memcpy(dest=pData, src=item_data, n=size), поки mbuf ще містить дані, контрольовані гостем, що дає arbitrary write.

Оскільки Linux VirtualBox-бінарник нерелокований (non-PIE), PLT-адреси для memcpy і system фіксовані і можуть використовуватись напряму. Гість також може розмістити рядки типу /bin/sh всередині іншого mbuf, що залишиться у посиланні коли захоплений виклик виконається.

Heap grooming via fragmentation

Slirp’s per-interface zone має глибину 3072 chunks і спочатку вирізана як суміжний масив, чей freelist обходиться від високих адрес вниз. Детерміновану суміжність можна досягти шляхом:

  • Flooding the NAT великою кількістю IP_MF fragments постійного розміру, щоб код реасемблі створював передбачувані послідовності mbuf.
  • Рециркуляції конкретних чункiв шляхом відправки фрагментів, які time out, змушуючи frees повертатися у freelist у LIFO-порядку.
  • Використовуючи знання прогону freelist, щоб розмістити майбутню жертву mbuf безпосередньо після mbuf, який нестиме IP options overflow.

Цей grooming гарантує, що overflow влучає у цільовий struct item і що підроблена uma_zone лишається в межах leak-примітива.

From arbitrary write to host code execution

З memcpy-on-free примітивом:

  1. Скопіюйте керований атакуючим рядок /bin/sh та буфер команд у стабільний mbuf.
  2. Використайте примітив щоб перезаписати GOT entry або indirect callsite (наприклад вказівник функції в стані NAT device) PLT-entry від system().
  3. Спровокуйте виклик, що було перезаписано. Оскільки VirtualBox запускає NAT device всередині хост-процесу, payload виконається з привілеями користувача, що запускає VirtualBox, дозволяючи guest-to-host escape.

Альтернативні payload’и включають вкорінення мініатюрного ROP-chain у heap-пам’яті та копіювання його адреси у часто викликаний callback, або перенаправлення pfFini/pfDtor прямо на ланцюжок гаджетів для повторних записів.

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