Skip to content
KitploitKITPLOIT
ИнструментыБлог
Log in
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
vbox_cve_2017_10235 — [CVE-2017-10235] Описание и PoC переполнения буфера устройства E1000 в VirtualBox | Kitploit
Инструменты/GitHubGitHub/fundacion-sadosky/vbox_cve_2017_10235
Безопасность встроенных системАнализ уязвимостейЭксплуатацияФаззингАппаратная БезопасностьЭксплуатация Бинарных Файлов
GitHubfundacion-sadosky/vbox_cve_2017_10235

vbox_cve_2017_10235

[CVE-2017-10235] Описание и PoC переполнения буфера устройства E1000 в VirtualBox

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться
Репозиторий
365138 лет назадПроверено Kitploit

CVE-2017-10235: Переполнение буфера устройства E1000 VirtualBox

Введение

В следующем документе описывается ошибка, обнаруженная в VirtualBox v5.1.22 (исправлена в v5.1.24) в компоненте эмуляции гостевого устройства DevE1000 (Эмуляция контроллера Ethernet Intel 82540EM), в функции e1kFallbackAddToFrame, что приводит к переполнению буфера на хосте, когда гостевая ОС находится под контролем злоумышленника.

Ошибка была признана Oracle в CPU за июль 2017 года с присвоенным CVE-2017-10235.

Уязвимость была подтверждена как на хосте с Linux (Ubuntu 16.04), так и на хосте с Windows (v8.1) при запуске гостевой Linux (также Ubuntu 16.04), но уязвимость может быть воспроизведена во многих различных комбинациях хоста и гостя. Во всех сценариях предполагается конфигурация сети по умолчанию: только один сетевой адаптер подключенный к NAT типа Intel PRO/1000 MT Desktop (82540EM).

Поскольку управляющие структуры (включая указатели на функции) могут быть перезаписаны данными, контролируемыми злоумышленником, можно с уверенностью предположить, что во многих сценариях может быть достигнуто удаленное выполнение кода. Oracle присвоила этой ошибке низкий балл CVSS, посчитав, что она имеет риск конфиденциальности None и целостности Low, что, по нашему мнению, не отражает полный потенциал компрометации этой ошибки (объяснение возможности RCE приведено ниже).

Описание и эксплуатация ошибки

Код VirtualBox, реализующий эмуляцию [контроллера Ethernet Intel 82540EM][intel_manual] (в файле [src/VBox/Devices/Network/DevE1000.cpp][DevE1000_cpp]), в функции [e1kFallbackAddToFrame][e1kFallbackAddToFrame], реализует аппаратную сегментацию 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);

Эта функция правильно проверяет, что максимальная длина TX-пакета (u16MaxPktLen) ниже стандартного максимума в 16288 байт (E1K_MAX_TX_PKT_SIZE), но делает это в виде макроса Assert, который будет отключен в релизной сборке, фактически делая проверку бесполезной для конечного пользователя. Это можно сравнить с аналогичной функцией [e1kAddToFrame][e1kAddToFrame], которая выполняет проверку с помощью явного if вместо 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;
   }

Различие между использованием обычной функции (e1kAddToFrame) и резервной (e1kFallbackAddToFrame) определяется в e1kXmitDesc() и зависит от двух факторов: флаг TSE должен быть включен в дескрипторах данных/контекста (управляется ОС в гостевой машине) и флаг GSO должен быть выключен. Последний зависит от многих факторов, поэтому существует много способов его отключить, но самый удобный — включить режим loopback, который настраивается через регистр управления приемом (биты RCTL.LBM), также управляемый гостевой ОС.

Включение режима loopback приведет к тому, что функция [e1kXmitAllocBuf][e1kXmitAllocBuf] будет использовать буфер aTxPacketFallback (Буфер пакетов передачи, используемый для резервного режима TSE и loopback) для размещения PDM scatter/gather буфера, с упомянутой длиной 16288 байт (E1K_MAX_TX_PKT_SIZE), и сигнализировать, что GSO будет отключен (путем установки NULL в 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);
}

Это приведет к тому, что вызов функции e1kXmitIsGsoBuf (внутри [e1kXmitDesc][e1kXmitDesc]) вернет False, и при включенном TSE в дескрипторе данных поток выполнения пойдет в [e1kFallbackAddToFrame][e1kFallbackAddToFrame_call] (вместо более безопасной функции e1kAddToFrame с правильной проверкой).


/*
 * 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);
}

Внутри e1kFallbackAddToFrame, при отключенной в релизной сборке вышеупомянутой проверке, MSS может быть произвольно большим (до 64K минус HDRLEN), что позволяет передать произвольно большое DTALEN в [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);

Функция [e1kFallbackAddSegment][e1kFallbackAddSegment] будет использовать это значение (теперь как аргумент u16Len) для копирования из гостевой памяти в буфер aTxPacketFallback в памяти хоста (через PDMDevHlpPhysRead) без дополнительных проверок этой длины, что вызовет переполнение буфера (емкость буфера 16288 байт при размере памяти до 64К).


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

Возможное RCE

Скачать инструмент