Skip to content
KitploitKITPLOIT
StrumentiExploitsBlog
Log in
Invia
StrumentiExploitsBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
vbox_cve_2017_10235 — [CVE-2017-10235] Descrizione e PoC del Buffer Overflow del dispositivo VirtualBox E1000 | Kitploit
Strumenti/GitHubGitHub/fundacion-sadosky/vbox_cve_2017_10235
Sicurezza Sistemi EmbeddedAnalisi delle VulnerabilitàExploitFuzzingSicurezza HardwareBinary Exploitation
GitHubfundacion-sadosky/vbox_cve_2017_10235

vbox_cve_2017_10235

[CVE-2017-10235] Descrizione e PoC del Buffer Overflow del dispositivo VirtualBox E1000

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi
Vedi Repository
365138 anni faRevisionato da Kitploit

CVE-2017-10235: Overflow del buffer nel dispositivo E1000 di VirtualBox

Introduzione

Il seguente documento descrive un bug trovato in VirtualBox v5.1.22 (ora corretto in v5.1.24), nel componente di emulazione del dispositivo guest DevE1000 (Emulazione del controller Ethernet Intel 82540EM), nella funzione e1kFallbackAddToFrame, che porta a un overflow del buffer nell'host quando il sistema operativo guest è controllato da un attaccante.

Il bug è stato riconosciuto da Oracle nel CPU di Luglio 2017 con il rilascio di CVE-2017-10235.

La vulnerabilità è stata corroborata sia con un host Linux (Ubuntu 16.04) che Windows (v8.1) con un guest Linux (anch'esso Ubuntu 16.04), ma la vulnerabilità potrebbe essere innescata in molte combinazioni host/guest diverse. In tutti gli scenari si assume la configurazione di rete predefinita: solo un adattatore di rete collegato a NAT di tipo Intel PRO/1000 MT Desktop (82540EM).

Poiché le strutture di controllo (inclusi i puntatori a funzione) possono essere sovrascritte con dati controllati dall'attaccante, è lecito presumere che l'esecuzione di codice remoto possa essere ottenuta in molti scenari. Oracle ha assegnato un punteggio CVSS basso a questo bug perché riteneva che avesse un rischio di riservatezza None e di integrità Low, cosa che a nostro avviso non riflette il pieno potenziale compromettente di questo bug (una spiegazione della possibilità di RCE è fornita di seguito).

Descrizione del bug e sfruttamento

Il codice di VirtualBox che implementa l'emulazione del [Controller Ethernet Intel 82540EM][intel_manual] (in [src/VBox/Devices/Network/DevE1000.cpp][DevE1000_cpp]), nella funzione [e1kFallbackAddToFrame][e1kFallbackAddToFrame], implementa la segmentazione hardware TCP:


static int e1kFallbackAddToFrame(PE1KSTATE pThis, E1KTXDESC *pDesc,
                                bool fOnWorkerThread)
{
#ifdef VBOX_STRICT
   PPDMSCATTERGATHER pTxSg = pThis->CTX_SUFF(pTxSg);
   Assert(e1kGetDescType(pDesc) == E1K_DTYP_DATA);
   Assert(pDesc->data.cmd.fTSE);
   Assert(!e1kXmitIsGsoBuf(pTxSg));
#endif

   uint16_t u16MaxPktLen = pThis->contextTSE.dw3.u8HDRLEN +
                           pThis->contextTSE.dw3.u16MSS;
   Assert(u16MaxPktLen != 0);
   Assert(u16MaxPktLen < E1K_MAX_TX_PKT_SIZE);

Questa funzione controlla correttamente che la lunghezza massima del pacchetto TX (u16MaxPktLen) sia inferiore al massimo standard di 16288 byte (E1K_MAX_TX_PKT_SIZE), ma lo fa sotto forma di una macro Assert che sarà disabilitata in una build di rilascio, rendendo di fatto il controllo inutile per l'utente finale. Ciò può essere confrontato con la funzione analoga [e1kAddToFrame][e1kAddToFrame], che impone il controllo con un esplicito if invece dell'Assert:


static bool e1kAddToFrame(PE1KSTATE pThis, RTGCPHYS PhysAddr,
                         uint32_t cbFragment)
{
   PPDMSCATTERGATHER   pTxSg    = pThis->CTX_SUFF(pTxSg);
   bool const          fGso     = e1kXmitIsGsoBuf(pTxSg);
   uint32_t const      cbNewPkt = cbFragment + pThis->u16TxPktLen;

   if (RT_UNLIKELY( !fGso && cbNewPkt > E1K_MAX_TX_PKT_SIZE ))
   {
       E1kLog(("%s Transmit packet is too large: %u > %u(max)\n",
               pThis->szPrf, cbNewPkt, E1K_MAX_TX_PKT_SIZE));
       return false;
   }

La differenza tra l'uso della funzione normale (e1kAddToFrame) e quella di fallback (e1kFallbackAddToFrame) viene decisa in e1kXmitDesc() e dipende da due fattori: che il flag TSE sia abilitato nei descrittori di dati/contesto (controllati dal sistema operativo utilizzando la macchina guest) e che il flag GSO sia disabilitato. Quest'ultimo dipende da molti fattori, e quindi ci sono molti modi per disabilitarlo, ma il più conveniente è abilitare la modalità loopback, che viene configurata tramite il Registro di Controllo Ricezione (nei bit RCTL.LBM), anch'esso controllato dal sistema operativo guest.

Abilitare la modalità loopback farà sì che la funzione [e1kXmitAllocBuf][e1kXmitAllocBuf] utilizzi il buffer aTxPacketFallback (Buffer del pacchetto di trasmissione utilizzato per il fallback TSE e il loopback) per l'allocazione del buffer PDM scatter/gather, con la lunghezza menzionata di 16288 byte (E1K_MAX_TX_PKT_SIZE), e per segnalare che GSO sarà disabilitato (impostando un NULL in pvUser).


if (RT_LIKELY(GET_BITS(RCTL, LBM) != RCTL_LBM_TCVR))
{

  ...

}
else
{
 /* Crea un loopback utilizzando il buffer di fallback e SG preallocato. */
 AssertCompileMemberSize(E1KSTATE, uTxFallback.Sg, 8 * sizeof(size_t));
 pSg = &pThis->uTxFallback.Sg;
 pSg->fFlags      = PDMSCATTERGATHER_FLAGS_MAGIC |
                    PDMSCATTERGATHER_FLAGS_OWNER_3;
 pSg->cbUsed      = 0;
 pSg->cbAvailable = 0;
 pSg->pvAllocator = pThis;
 pSg->pvUser      = NULL; /* Nessun GSO qui. */
 pSg->cSegs       = 1;
 pSg->aSegs[0].pvSeg = pThis->aTxPacketFallback;
 pSg->aSegs[0].cbSeg = sizeof(pThis->aTxPacketFallback);
}

Ciò farà sì che la chiamata alla funzione e1kXmitIsGsoBuf (all'interno di [e1kXmitDesc][e1kXmitDesc]) restituisca False e, con il TSE abilitato nel descrittore dati, il flusso di esecuzione andrà a [e1kFallbackAddToFrame][e1kFallbackAddToFrame_call] (invece della funzione più sicura e1kAddToFrame con il controllo corretto).


/*
 * Aggiunge i dati del descrittore al frame. Se il frame è completo,
 * lo trasmette e reimposta il campo u16TxPktLen.
 */
if (e1kXmitIsGsoBuf(pThis->CTX_SUFF(pTxSg)))
{

  ...

}
else if (!pDesc->data.cmd.fTSE)
{

  ...

}
else
{
    STAM_COUNTER_INC(&pThis->StatTxPathFallback);
    rc = e1kFallbackAddToFrame(pThis, pDesc, fOnWorkerThread);
}

All'interno di e1kFallbackAddToFrame, con il suddetto controllo disabilitato in una build di rilascio, il MSS può essere impostato arbitrariamente grande (fino a 64K meno HDRLEN), permettendo quindi di passare un DTALEN arbitrariamente grande a [e1kFallbackAddSegment][e1kFallbackAddSegment_call]:


/*
 * Ricava i segmenti.
 */
int rc;
do
{
 /* Calcola quanti byte ci restano in questo segmento TCP */
 uint32_t cb = u16MaxPktLen - pThis->u16TxPktLen;
 if (cb > pDesc->data.cmd.u20DTALEN)
 {
     /* Questo descrittore si adatta completamente al segmento corrente */
     cb = pDesc->data.cmd.u20DTALEN;
     rc = e1kFallbackAddSegment(pThis, pDesc->data.u64BufAddr, cb,
                 pDesc->data.cmd.fEOP /*fSend*/, fOnWorkerThread);

La funzione [e1kFallbackAddSegment][e1kFallbackAddSegment] utilizzerà questo valore (ora come argomento u16Len) per copiare dalla memoria guest nel buffer aTxPacketFallback nella memoria host (attraverso PDMDevHlpPhysRead) senza ulteriori controlli su questa lunghezza, causando quindi il buffer overflow (di un buffer con capacità di 16288 byte con una dimensione di memoria fino a 64K).


static int e1kFallbackAddSegment(PE1KSTATE pThis, RTGCPHYS PhysAddr,
                   uint16_t u16Len, bool fSend, bool fOnWorkerThread)
{
    int rc = VINF_SUCCESS;
    /* Intestazione TCP in trasmissione */
    struct E1kTcpHeader *pTcpHdr = (struct E1kTcpHeader *)
            (pThis->aTxPacketFallback + pThis->contextTSE.tu.u8CSS);
    /* Intestazione IP in trasmissione */
    struct E1kIpHeader *pIpHdr = (struct E1kIpHeader *)
            (pThis->aTxPacketFallback + pThis->contextTSE.ip.u8CSS);

    E1kLog3(("%s e1kFallbackAddSegment: Length=%x, remaining payload=%x,
             header=%x, send=%RTbool\n", pThis->szPrf, u16Len,
             pThis->u32PayRemain, pThis->u16HdrRemain, fSend));
    Assert(pThis->u32PayRemain + pThis->u16HdrRemain > 0);

    PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), PhysAddr,
                      pThis->aTxPacketFallback + pThis->u16TxPktLen, u16Len);

Possibile RCE

Scarica lo strumento