
Paracosme es un exploit de corrupción de memoria remota de cero clics que compromete ICONICS Genesis64, el cual fue demostrado con éxito en el escenario durante la competencia Pwn2Own Miami 2022.
Paracosme es un exploit de corrupción de memoria que escribí para atacar la suite Genesis64 v10.97.1 creada por ICONICS y lograr la ejecución remota de código.
El exploit se demostró durante el concurso Pwn2Own 2022 Miami que tuvo lugar en la Conferencia S4x22. Puedes leer más al respecto en Compitiendo en Pwn2Own ICS 2022 Miami: Explotando una corrupción de memoria remota zero-click en ICONICS Genesis64.
El problema obtuvo una puntuación de 9.8 en CVSS y se le asignó CVE-2022-33318 / ZDI-22-1041. Se corrigió en Genesis64 10.97.2. También puedes leer el aviso ICSA-22-202-04, así como el documento técnico de ICONICS sobre las vulnerabilidades de seguridad de ICONICS Suite.
Puedes encontrar el código del exploit en src/paracosme.py, un PoC para provocar el crash / verificar si estás afectado en src/paracosme-poc.py, y el payload que se ejecuta en la máquina en src/payload.
La mejor manera de saber si estás afectado es activar Page Heap para GenBroker64.exe, reiniciar el servicio, adjuntar un depurador a GenBroker64.exe, ejecutar paracosme-poc.py contra tu servidor y deberías ver crashes como los siguientes:
Necesitas adjuntar un depurador al proceso objetivo para presenciar el crash; de lo contrario, la aplicación lo ignora.
El exploit solo se ha probado en Windows, pero también debería funcionar en plataformas Linux:
impacket con: pip3 install impacketsc config lanmanserver start=disabled y reiniciasmbserver.py (parte de los ejemplos de impacket) con: python src\smbserver.py -smb2support x binpython src\paracosme.py --target <ip>
Para más detalles, consulta Compitiendo en Pwn2Own ICS 2022 Miami: Explotando una corrupción de memoria remota zero-click en ICONICS Genesis64.
Paracosme explota un problema de use-after-free encontrado en el proceso GenBroker64 para lograr la ejecución remota de código en un sistema Windows 21H2 x64.
A grandes rasgos, el proceso GenBroker64 escucha en el puerto TCP 38080 y es capaz de deserializar varios paquetes después de que se haya realizado un handshake con un cliente. El problema que encontré está en el código que se encarga de leer un VARIANT desde el socket de red. Básicamente, un variant es un tipo y un valor. La función parece bien escrita a primera vista y se esfuerza por desempaquetar solo ciertos tipos. Así es como se ve:
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;
}
La función implementa por sí misma el desempaquetado de arrays, así como la lectura de tipos variant simples, pero si recibe algo que no es ninguno de esos dos, recae en el operator>> de la instancia del archive. Esta instancia de archive es un objeto proporcionado por el framework Microsoft Foundation Class que maneja la serialización y deserialización de varios objetos. Este código es en realidad de código abierto y puedes encontrarlo en C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\atlmfc\src\mfc\olevar.cpp, pero aquí está: