
VirtualBox 7.2.20 - Alta - Local - Estouro de heap - HGCM SSM cParms wrap
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · vbox-hgcm-ssm-cparms
Classe: Heap overflow Alcance: Local (host)
Oracle VM VirtualBox OSS 7.2.20 (f2792cf44) - Oracle
O HGCM em tempo real ainda recusa cParms > 32. O carregamento de estado salvo não. vmmdevR3HgcmLoadState lê cParms do .sav sem o limite VMMDEV_MAX_HGCM_PARMS, depois dimensiona o comando com uint32_t cbCmd. Com cParms = 0x4000000, esse produto sofre wrap para sizeof(VBOXHGCMCMD) (~120). O primeiro armazenamento de enmType já é uma escrita de 4 bytes além do bloco.
Um usuário do host que restaura um estado salvo hostil causa overflow no heap do processo da VM. Um guest não consegue plantar isso via Save.
| ID | ainda sem CVE |
| Classe | Heap overflow (escrita OOB no processo da VM; não é escape do kernel do host) |
| Alcance | Local (host) (UI:R restauração de estado salvo / snapshot) |
| CWE | CWE-190, CWE-787 |
| CVSS | Alto: 7.8 CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H |
| Produto | VirtualBox OSS |
| Afetado | 7.2.20 (f2792cf44f663989818507e36d3db5f978523c5e) |
| Autenticação | usuário do host restaura uma VM salva, snapshot ou .sav |
| Licença | GNU Affero GPL v3.0 |
| Lab | apenas 127.0.0.1. Harness de código-fonte. Sem boot do VirtualBox, sem parsing de .sav. |
Entregar ao operador uma pasta de VM cujo estado salvo carrega uma chamada HGCM do VMMDev pendente. Ele clica em Iniciar em uma VM salva, restaura um snapshot ou adota o .sav. A restauração do console percorre SSMR3 até vmmdevR3LoadExec e então vmmdevR3HgcmLoadState. Isso é UI:R. O resíduo é o parser, não uma hiperchamada do guest.
O VMMDev vem ativado por padrão. Sem 3D. Sem Guest Additions. Sem VRDP. Não é PUEL.
| Etapa | Onde | O que concede |
|---|---|---|
| Restauração | UI do host / VBoxManage startvm em uma VM salva | O usuário do host abre o .sav hostil. Esse é o único clique necessário. |
| Unidade SSM | VMMDev vmmdevR3HgcmLoadState (VMMDevHGCM.cpp:2043-2091) | SSMGetU32 em cParms sem o limite VMMDEV_MAX_HGCM_PARMS (32). |
| Wrap da alocação | vmmdevR3HgcmCmdAlloc (VMMDevHGCM.cpp:376-381) | uint32_t cbCmd = sizeof(VBOXHGCMCMD) + cParms * (40+24). cParms = 0x4000000 sofre wrap para ~120. RTMemAllocZ desse tamanho tem sucesso dentro do orçamento do heap. |
| Primeiro armazenamento | loop de carregamento paGuestParms[i].enmType (VMMDevHGCM.cpp:2085-2091) | paGuestParms é pCmd + sizeof(VBOXHGCMCMD), que já é o fim da alocação após o wrap. O primeiro dword de tipo é uma escrita OOB de 4 bytes. O stream só precisa do cabeçalho CALL mais um tipo de parâmetro. Não precisa de 67 milhões de registros. |
| Tipo | Proveniência | O que o atacante obtém |
|---|---|---|
| Recon | nenhuma | Os bytes de overflow são escolhidos pelo sav. Isto não é um vazamento. O conteúdo do heap não é devolvido ao ficheiro. |
| Integridade | provado em laboratório | cParms=0x4000000 faz wrap de uint32_t cbCmd para 120. Um único store enmType com i=0 destrói um canary 0xA5. canary0=56424f58 é o prefixo VBOX de VBOX-HGCM-SSM-CPARMS-WITNESS. O controlo cParms=2 deixa o canary intacto. |
| Integridade | inferido | Registos de parâmetros adicionais controlados pelo sav (dword de tipo mais campos de 32/64 bits ou descritores de ponteiro) escrevem linearmente a partir do RTMemAllocZ de ~120 bytes em VirtualBoxVM / VBoxHeadless. Trata-se de uma primitiva de escrita no processo da VM, da mesma classe que o memcorr de migração do QEMU. Este pacote não demonstra controlo do instruction pointer. |
| Disponibilidade | inferido | Crash do VBoxVM se a destruição não for convertida numa escrita controlada. O harness é uma destruição de canary, não um crash do processo VirtualBox. |
vmmdevR3HgcmCallAlloc em execução continua a rejeitar cParms > 32 (VMMDevHGCM.cpp:921-926). Um guest não consegue plantar o wrap através de um Save legítimo.VMMDEV_MAX_HGCM_PARMS 32, VMMDEV_MAX_HGCM_DATA_SIZE 128MiB).offValue / cbValue na conclusão é uma segunda escrita no heap do host apenas se os clientes HGCM restaurarem no mesmo sav. Não é este laboratório.Host-user / host-kernel completos ainda requerem um resíduo de hardening. Combinar esta destruição com o bypass público do IDispatch é descartado.
Fixe o VirtualBox/virtualbox na tag v7.2.20 peel f2792cf44. O HGCM em execução foi a primeira leitura porque a CVE-2013-5892 era desta classe: wrap do tamanho dos argumentos para VBOXHGCMCMD. O caminho em execução ainda tem o limite:
ASSERT_GUEST_STMT_RETURN( cParms <= (cbHGCMCall - sizeof(VMMDevHGCMCall)) / cbHGCMParmStruct
&& cParms <= VMMDEV_MAX_HGCM_PARMS,
LogRelMax(50, ("VMMDev: request packet with invalid number of HGCM parameters: ...")),
VERR_INVALID_PARAMETER);
O Load não. vmmdevR3HgcmLoadState recebe cParms do sav e chama o mesmo alocador:
const uint32_t cbCmd = sizeof(VBOXHGCMCMD) + cParms * (sizeof(VBOXHGCMGUESTPARM) + sizeof(VBOXHGCMSVCPARM))
+ (enmCmdType == VBOXHGCMCMDTYPE_CONNECT ? sizeof(HGCMServiceLocation) : 0);
AssertCompile comentários neste pin colocam CMD em 120, guestparm em 40, svcparm em 24. cParms = 0x4000000 faz o produto de 64 bits 0x100000000 + 120. O armazenamento em uint32_t mantém 120. Então:
for (i = 0; i < cParms; ++i)
{
VBOXHGCMGUESTPARM * const pGuestParm = &pCmd->u.call.paGuestParms[i];
rc = pHlp->pfnSSMGetU32(pSSM, &u32);
pGuestParm->enmType = (HGCMFunctionParameterType)u32;
paGuestParms fica em pCmd + sizeof(VBOXHGCMCMD). Após o wrap, esse é o fim da alocação. O primeiro store já está fora dos limites (OOB).
Caminhos errados já registrados: tratar o HGCM ativo como o resíduo (ele ainda limita a 32); percorrer 67 milhões de stores no harness (o primeiro dword é a prova); afirmar que um guest pode plantar isso através do Save; inflar o heap smash do processo da VM para escape do kernel do host; encadear IDispatch público.
Teatro: um reverse shell, um parser de .sav, inicializar o VirtualBox. O oráculo é o wrap mais um smash de canário de VBOX-HGCM-SSM-CPARMS-WITNESS.
cd lab
./run.sh
Ou a partir da raiz do pacote:
python3 vbox-hgcm-ssm-cparms-Abraxas-Labs.py