
Paracosme é um exploit de corrupção de memória remota zero-clique que compromete o ICONICS Genesis64, demonstrado com sucesso no palco durante a competição Pwn2Own Miami 2022.
Paracosme é um exploit de corrupção de memória que escrevi para atingir o pacote Genesis64 v10.97.1 feito pela ICONICS para alcançar execução remota de código.
O exploit foi demonstrado durante o concurso Pwn2Own 2022 Miami que ocorreu na Conferência S4x22. Você pode ler sobre isso em Competindo no Pwn2Own ICS 2022 Miami: Explorando uma corrupção de memória remota zero click no ICONICS Genesis64.
O problema obteve 9.8 no CVSS e foi atribuído a CVE-2022-33318 / ZDI-22-1041. Foi corrigido e foi corrigido no Genesis64 10.97.2. Você também pode ler o aviso ICSA-22-202-04, bem como o whitepaper da ICONICS sobre Vulnerabilidades de Segurança do ICONICS Suite.
Você pode encontrar o código do exploit em src/paracosme.py, um PoC para acionar o crash / verificar se você está afetado em src/paracosme-poc.py, e o payload executado na máquina em src/payload.
A melhor maneira de saber se você foi afetado é ativar o Page Heap para GenBroker64.exe, reiniciar o serviço, anexar um depurador ao GenBroker64.exe, executar paracosme-poc.py contra o seu servidor e você deve ver crashes como os abaixo:
Você precisa anexar um depurador ao processo de destino para observar o crash; caso contrário, o aplicativo o ignora.
O exploit foi testado apenas no Windows, mas também deve funcionar em plataformas Linux:
impacket com: pip3 install impacketsc config lanmanserver start=disabled e reiniciesmbserver.py (parte dos exemplos do impacket) com: python src\smbserver.py -smb2support x binpython src\paracosme.py --target <ip>
Para mais detalhes, consulte Competindo no Pwn2Own ICS 2022 Miami: Explorando uma corrupção de memória remota zero click no ICONICS Genesis64.
O Paracosme explora um problema de use-after-free encontrado no processo GenBroker64 para alcançar execução remota de código em um sistema Windows 21H2 x64.
Em um nível alto, o processo GenBroker64 escuta na porta TCP 38080 e é capaz de desserializar vários pacotes depois que um handshake é feito com um cliente. O problema que encontrei está no código que lida com a leitura de um VARIANT do socket da rede. Basicamente, uma variant é um tipo e um valor. A função parece bem escrita à primeira vista e se esforça para descompactar apenas determinados tipos. É assim que ela se parece:
bool CheckVariantType(VARTYPE VarType) {
if((VarType & 0x2FFF) != VarType) {
return false;
}
switch(VarType & 0xFFF) {
case VT_EMPTY:
case VT_NULL:
case VT_I2:
case VT_I4:
case VT_R4:
case VT_R8:
case VT_CY:
case VT_DATE:
case VT_BSTR:
case VT_ERROR:
case VT_BOOL:
case VT_VARIANT:
case VT_I1:
case VT_UI1:
case VT_UI2:
case VT_UI4:
case VT_I8:
case VT_UI8:
case VT_INT:
case VT_UINT:
case VT_HRESULT:
case VT_FILETIME:
return true;
break;
default:
return false;
}
}
size_t VariantTypeToSize(VARTYPE VarType) {
switch(VarType) {
case VT_I1: return 1;
case VT_UI2: return 2;
case VT_UI4:
case VT_INT:
case VT_UINT:
case VT_HRESULT:
return 4;
case VT_I8:
case VT_UI8:
case VT_FILETIME:
return 8;
default:
return 0;
}
}
void Utils::ReadVariant(tagVARIANT *Variant, Archive_t *Archive, int Level) {
TRY {
return ReadVariant_((CArchive *)Archive, (COleVariant *)Variant);
} CATCH_ALL(e) {
VariantClear(Variant);
}
}
HRESULT Utils::ReadVariant_(tagVARIANT *Variant, Archive_t *Archive, int Level) {
VARTYPE VarType = Archive.ReadUint16();
if((VarType & VT_ARRAY) != 0) {
// Special logic to unpack arrays..
return ..;
}
Size = VariantTypeToSize(VarType);
if (Size) {
Variant->vt = VarType;
return Archive.ReadInto(&Variant->decVal.8, Size);
}
if(!CheckVariantType(VarType)) {
// ...
throw Something();
}
return Archive >> Variant;
}
A função implementa ela mesma a descompactação de arrays, bem como a leitura de tipos variant simples, mas, se estiver recebendo algo que não é nenhum desses dois, ela recorre ao operator>> da instância do archive. Essa instância do archive é um objeto fornecido pelo framework Microsoft Foundation Class, que lida com a serialização e desserialização de vários objetos. Esse código é na verdade open-source e você pode encontrá-lo em C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\atlmfc\src\mfc\olevar.cpp, mas aqui está ele: