
Paracosme è uno sfruttamento di corruzione della memoria remota zero-click che compromette ICONICS Genesis64, dimostrato con successo sul palco durante la competizione Pwn2Own Miami 2022.
Paracosme è un exploit di corruzione della memoria che ho scritto per colpire la suite Genesis64 v10.97.1 prodotta da ICONICS e ottenere l'esecuzione di codice in remoto.
L'exploit è stato dimostrato durante il concorso Pwn2Own 2022 Miami che si è svolto alla S4x22 Conference. Puoi leggere l'articolo Competere al Pwn2Own ICS 2022 Miami: sfruttare una corruzione di memoria remota zero-click in ICONICS Genesis64.
Il problema ha ottenuto un punteggio di 9.8 sul CVSS e gli sono stati assegnati CVE-2022-33318 / ZDI-22-1041. È stato corretto in Genesis64 10.97.2. Puoi anche leggere l'avviso ICSA-22-202-04 e il whitepaper di ICONICS sulle vulnerabilità di sicurezza della suite ICONICS.
Puoi trovare il codice dell'exploit in src/paracosme.py, una PoC per innescare il crash / verificare se sei interessato in src/paracosme-poc.py, e il payload eseguito sulla macchina in src/payload.
Il modo migliore per sapere se sei interessato è abilitare Page Heap per GenBroker64.exe, riavviare il servizio, collegare un debugger a GenBroker64.exe, eseguire paracosme-poc.py contro il tuo server e dovresti vedere crash come quello sotto:
Devi collegare un debugger al processo target per osservare il crash, altrimenti l'applicazione lo ignora.
L'exploit è stato testato solo su Windows ma dovrebbe funzionare anche su piattaforme Linux:
impacket con: pip3 install impacketsc config lanmanserver start=disabled e riavviasmbserver.py (parte degli esempi di impacket) con: python src\smbserver.py -smb2support x binpython src\paracosme.py --target <ip>
Per maggiori dettagli, fai riferimento a Competere al Pwn2Own ICS 2022 Miami: sfruttare una corruzione di memoria remota zero-click in ICONICS Genesis64.
Paracosme sfrutta un problema use-after-free trovato nel processo GenBroker64 per ottenere l'esecuzione di codice in remoto su un sistema Windows 21H2 x64.
Ad alto livello, il processo GenBroker64 ascolta sulla porta TCP 38080 ed è in grado di deserializzare vari pacchetti dopo aver effettuato un handshake con un client. Il problema che ho trovato è nel codice che gestisce la lettura di un VARIANT dal socket di rete. In pratica una variant è un tipo e un valore. La funzione sembra ben scritta a prima vista e si sforza di decomprimere solo certi tipi. Ecco come appare:
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 funzione implementa da sé l'unpacking degli array, oltre alla lettura di semplici tipi variant, ma se riceve qualcosa che non rientra in questi due casi, ripiega sull'operator>> dell'istanza dell'archivio. Questa istanza dell'archivio è un oggetto fornito dal framework Microsoft Foundation Class che gestisce la serializzazione e la deserializzazione di vari oggetti. Questo codice è in realtà open-source e puoi trovarlo in C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\atlmfc\src\mfc\olevar.cpp, ma eccolo qui: