Skip to content

VirtualBox E1000 integer underflow heap overflow (ACPI write primitive)

Emüle Intel E1000 NIC'inde bir VirtualBox guest-to-host escape: e1kFallbackAddToFrame'deki (TCP-segmentation yolu) bir integer underflow, bir host heap overflow verir; bu EEPROM üzerinden bir write primitive'e ve ACPI SMBus state'i üzerinden bir read primitive'e dönüştürülür.

Mechanism

Note

VirtualBox, host VBoxHeadless/VirtualBox process'i içinde Intel 82540EM (E1000) NIC'ini emüle eder. Guest, bir packet'i tanımlayan descriptor'lar postalayarak transmit'i sürer; TCP segmentation (TSE) etkinken device, segment'leri bir host buffer'ında yeniden birleştirir. Isolation invariant'ı, o buffer'a giden running offset'in buffer içinde kalmasıdır. e1kFallbackAddToFrame() kalan alanı cb = u16MaxPktLen - pThis->u16TxPktLen olarak hesaplar. Context+data descriptor'ları, halihazırda biriken u16TxPktLen (küçültülmüş) u16MaxPktLen'i aşacak şekilde hazırlanırsa, çıkarma işlemi ~0xFFFFFFFF'e underflow eder, ardından gelen cb > u20DTALEN kontrolünü atlatır ve e1kFallbackAddSegment'in PDMDevHlpPhysRead ile buffer'ın tuttuğundan çok daha fazla byte okumasına izin verir — bir host heap out-of-bounds write'ı; guest→host sınırını aşar ve NAT modunda guest ring-3'ten erişilebilir.

Walkthrough

Public referans: MorteNoir'ın virtualbox_e1000_0day'i (VirtualBox ≤ 5.2.20'yi etkiler; CVE-2017-10235 / CVE-2019-2722 ile ilişkili). Kavramsal, zaten-public yol:

  1. Underflow'u tetikle beş-descriptor'lık bir dizilim ile [context_1, data_2, data_3, context_4, data_5]:
  2. context_1 max segment size'ı 0x3010 ayarlar; data_2+data_3, u16TxPktLen'e 0x10 byte biriktirir, data_3 end-of-packet'i ayarlar (e1kLocateTxPacket'ten erken return).
  3. context_4 max segment size'ı 0xF'e küçültür; data_5 (0x4188 byte) 0xF - 0x10'u underflow ettirir.
  4. Aşırı büyük cb şuraya ulaşır:
    PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), PhysAddr,
                      pThis->aTxPacketFallback + pThis->u16TxPktLen, u16Len);
    
    ki aTxPacketFallback[0x3FA0]'ı bitişik EEPROM93C46'ya taşırır.
  5. Write primitive: EEPROM alanlarını (m_fWriteEnabled, m_u16Addr, m_u16Word) bozmak, storeWord()'ün kontrollü bir 16-bit değeri kontrollü bir heap offset'inde yazmasını sağlar (m_au16Data[u32Addr] = u16Value).
  6. Read primitive: write, ACPIState::u8SMBusBlkIdx'i hedef alır ve guest I/O port 0x4107 üzerinden okunan 32-byte au8SMBusBlkDat'ı taşırarak ASLR'ı atlatmak için VBoxDD.so pointer'ları sızdırır.
  7. Loopback etkinken aynı underflow, e1kHandleRxPacket'in stack buffer'ı rxPacket[E1K_MAX_RX_PKT_SIZE]'a (0x4000) de ulaşır; bir host process spawn eden ve VM'i temizce sürdüren bir ROP chain için kaydedilmiş bir return address'i üzerine yazar.

Warning

Bug sınıfı için dokümante edilmiş, public ve patch'lenmiş bir sorun. Kesin ROP/host offset'leri atlanmıştır; bu kavramsal chain'dir.

Detection

  • Host tarafı: E1000 TX aktivitesiyle korele VirtualBox/VBoxHeadless crash'leri veya beklenmedik child process'ler; ASAN build'leri e1kFallbackAddToFrame/e1kHandleRxPacket'teki OOB'yi işaretler.
  • Davranışsal: max-segment-size'ı halihazırda biriken length'in altına küçülten TSE descriptor dizilimleri gönderen bir guest, gerçek bir NIC driver için anormaldir.

Mitigation

  • Oracle'ın VirtualBox fix'ini uygula (CVE-2017-10235 / CVE-2019-2722); çıkarma işleminden önce u16MaxPktLen ile u16TxPktLen'i validate eder.
  • Mümkün olduğunda E1000 yerine paravirtualized virtio-net adapter'ını kullan, ya da güvenilmez guest'lere açılan NIC emülasyonunu kısıtla.
  • Defense-in-depth: VM process'ini deprivileged/sandboxed çalıştır.

References

  • MorteNoir, "VirtualBox E1000 Guest-to-Host Escape" (README): https://github.com/MorteNoir1/virtualbox_e1000_0day/blob/master/README.md
  • STAR Labs — (CVE-2019-2722) Oracle VirtualBox e1000 Integer Underflow: https://starlabs.sg/advisories/19/19-2722/