Skip to content
KitploitKITPLOIT
OutilsBlog
Log in
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

FluxContactConfidentialité© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
vbox_cve_2017_10235 — [CVE-2017-10235] Description et PoC du débordement de tampon du périphérique E1000 de VirtualBox | Kitploit
Outils/GitHubGitHub/fundacion-sadosky/vbox_cve_2017_10235
Sécurité des Systèmes EmbarquésAnalyse des VulnérabilitésExploitationFuzzingSécurité MatérielleExploitation de Binaires
GitHubfundacion-sadosky/vbox_cve_2017_10235

vbox_cve_2017_10235

[CVE-2017-10235] Description et PoC du débordement de tampon du périphérique E1000 de VirtualBox

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager
Voir le dépôt
36513il y a 8 ansVérifié par Kitploit

CVE-2017-10235 : débordement de tampon du périphérique E1000 de VirtualBox

Introduction

Le document suivant détaille un bogue trouvé dans VirtualBox v5.1.22 (corrigé dans v5.1.24), dans le composant d'émulation de périphérique invité DevE1000 (émulation du contrôleur Ethernet Intel 82540EM), dans la fonction e1kFallbackAddToFrame, qui conduit à un débordement de tampon dans l'hôte lorsque le système d'exploitation invité est contrôlé par un attaquant.

Le bogue a été reconnu par Oracle dans le CPU de juillet 2017 avec le CVE-2017-10235 émis.

La vulnérabilité a été corroborée à la fois avec un hôte Linux (Ubuntu 16.04) et un hôte Windows (v8.1) exécutant un invité Linux (également Ubuntu 16.04), mais la vulnérabilité pourrait être déclenchée dans de nombreuses combinaisons hôte/invité différentes.

Dans tous les scénarios, la configuration réseau par défaut est supposée : une seule carte réseau attachée au NAT de type Intel PRO/1000 MT Desktop (82540EM).

Étant donné que les structures de contrôle (y compris les pointeurs de fonction) peuvent être écrasées avec des données contrôlées par l'attaquant, il est raisonnable de supposer qu'une exécution de code à distance pourrait être atteinte dans de nombreux scénarios.

Oracle a attribué un score CVSS faible à ce bogue car il considérait qu'il présentait un risque de confidentialité None et une intégrité Low, ce qui, selon nous, ne reflète pas le potentiel de compromission complet de ce bogue (une explication de la possibilité d'une RCE est donnée ci-dessous).

Description du bogue et exploitation

Le code de VirtualBox qui implémente l'émulation du [contrôleur Ethernet Intel 82540EM][intel_manual] (dans [src/VBox/Devices/Network/DevE1000.cpp][DevE1000_cpp]), dans la fonction [e1kFallbackAddToFrame][e1kFallbackAddToFrame], implémente la segmentation TCP matérielle :


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);

Cette fonction vérifie correctement que la longueur maximale du paquet TX (u16MaxPktLen) est inférieure au maximum standard de 16288 octets (E1K_MAX_TX_PKT_SIZE), mais elle le fait sous la forme d'une macro Assert qui sera désactivée dans une compilation release, rendant ainsi la vérification inutile pour l'utilisateur final.

Cela contraste avec la fonction analogue [e1kAddToFrame][e1kAddToFrame], qui applique la vérification avec un if explicite au lieu du 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 différence entre l'utilisation de la fonction normale (e1kAddToFrame) et de la fonction de repli (e1kFallbackAddToFrame) est décidée dans e1kXmitDesc() et dépend de deux facteurs : que le drapeau TSE soit activé dans les descripteurs de données/contexte (contrôlés par le système d'exploitation de la machine invitée) et que le drapeau GSO soit désactivé.

Ce dernier dépend de nombreux facteurs, et il existe donc de nombreuses façons de le désactiver, mais la plus pratique est d'activer le mode bouclage, configuré via le registre de contrôle de réception (dans les bits RCTL.LBM), également contrôlé par le système d'exploitation invité.

L'activation du mode bouclage fera utiliser par la fonction [e1kXmitAllocBuf][e1kXmitAllocBuf] le tampon aTxPacketFallback (tampon de paquets de transmission utilisé pour le repli TSE et le bouclage) pour l'allocation du tampon PDM scatter/gather, avec la longueur mentionnée de 16288 octets (E1K_MAX_TX_PKT_SIZE), et signalera que le GSO sera désactivé (en définissant un NULL dans pvUser).


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

  ...

}
else
{
 /* Create a loopback using the fallback buffer and preallocated SG. */
 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; /* No GSO here. */
 pSg->cSegs       = 1;
 pSg->aSegs[0].pvSeg = pThis->aTxPacketFallback;
 pSg->aSegs[0].cbSeg = sizeof(pThis->aTxPacketFallback);
}

Cela fera retourner False à la fonction e1kXmitIsGsoBuf (appelée dans [e1kXmitDesc][e1kXmitDesc]) et, avec le TSE activé dans le descripteur de données, le flux d'exécution ira vers [e1kFallbackAddToFrame][e1kFallbackAddToFrame_call] (au lieu de la fonction plus sûre e1kAddToFrame avec la vérification correcte).


/*
 * Add the descriptor data to the frame.  If the frame is complete,
 * transmit it and reset the u16TxPktLen field.
 */
if (e1kXmitIsGsoBuf(pThis->CTX_SUFF(pTxSg)))
{

  ...

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

  ...

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

Dans e1kFallbackAddToFrame, avec la vérification susmentionnée désactivée dans une compilation release, le MSS peut être défini arbitrairement grand (jusqu'à 64K moins le HDRLEN), permettant ainsi de passer un DTALEN arbitrairement grand à [e1kFallbackAddSegment][e1kFallbackAddSegment_call] :


/*
* Carve out segments.
*/
int rc;
do
{
 /* Calculate how many bytes we have left in this TCP segment */
 uint32_t cb = u16MaxPktLen - pThis->u16TxPktLen;
 if (cb > pDesc->data.cmd.u20DTALEN)
 {
     /* This descriptor fits completely into current segment */
     cb = pDesc->data.cmd.u20DTALEN;
     rc = e1kFallbackAddSegment(pThis, pDesc->data.u64BufAddr, cb,
                 pDesc->data.cmd.fEOP /*fSend*/, fOnWorkerThread);

La fonction [e1kFallbackAddSegment][e1kFallbackAddSegment] utilisera cette valeur (maintenant comme argument u16Len) pour copier depuis la mémoire invitée vers le tampon aTxPacketFallback dans la mémoire hôte (via PDMDevHlpPhysRead) sans autre vérification de cette longueur, provoquant ainsi le débordement de tampon (d'un tampon d'une capacité de 16288 octets avec une taille mémoire allant jusqu'à 64K).


static int e1kFallbackAddSegment(PE1KSTATE pThis, RTGCPHYS PhysAddr,
                   uint16_t u16Len, bool fSend, bool fOnWorkerThread)
{
    int rc = VINF_SUCCESS;
    /* TCP header being transmitted */
    struct E1kTcpHeader *pTcpHdr = (struct E1kTcpHeader *)
            (pThis->aTxPacketFallback + pThis->contextTSE.tu.u8CSS);
    /* IP header being transmitted */
    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);
Télécharger l’outil