
Exploit pour la vulnérabilité zero-click d'Outlook 2019 CVE-2020-1349, utilisant des bugs d'analyse d'en-têtes MIME pour provoquer un débordement de tas et un contrôle EIP via l'écrasement de vftable.
Cette vulnérabilité se produit dans Outlook 2019 (16.0.12624.20424) installé sur Windows 10 1909 x64 coréen, page de codes 949.

Je n'ai pas pu contourner l'ASLR en utilisant cette vulnérabilité, mais j'ai écrit un exploit pour Outlook 2019 32 bits qui fait apparaître une calculatrice en utilisant l'adresse d'une bibliothèque système qui est fixée au démarrage. et cette vulnérabilité est une vulnérabilité zero-click. Si le compte d'un service de messagerie autre que le compte "outlook.com" est lié à Outlook 2019 via IMAP, il est déclenché par la simple réception d'un courrier.
v26 = IsDBCSLeadByte(*v13);
v12 = 0;
if ( v26 )
{
LODWORD(v5) = v5 - 1;
*v11++ = *v13++;
--v8;
}
LODWORD(v5) = v5 - 1;
*v11++ = *v13++;
--v8;
goto LABEL_51;
[OUTLMIME!CloseAllSockets+0x50804 Pseudo-code]
Le crash se produit, et la partie où la vulnérabilité existe est comme ci-dessus. Lorsque la chaîne de l'en-tête To ou From analysé est Multibyte, la variable comptant les chaînes restantes à analyser est diminuée de 2, et un dépassement d'entier inférieur se produit en diminuant la variable de 2 lorsque la variable est 1.
if ( v23 != '=' )
{
if ( v23 == 34 )
v15 = 6;
goto LABEL_48;
}
v15 = 1;
}
if ( v15 )
goto LABEL_40;
[OUTLMIME!CloseAllSockets+0x50804 Pseudo-code]
LABEL_40:
v24 = v13[v14];
if ( v24 )
{
if ( v5 == v14 )
goto LABEL_52;
if ( v8 != v14 )
{
v25 = IsDBCSLeadByte(v24);
v12 = 0;
if ( v25 )
++v14;
++v14;
}
}
goto LABEL_51;
}
[OUTLMIME!CloseAllSockets+0x50804 Pseudo-code]
LABEL_51:
if ( v5 <= v14 )
goto EXIT_0;
}
[OUTLMIME!CloseAllSockets+0x50804 Pseudo-code]
if ( v15 )
{
if ( v15 == 1 )
{
v15 = 2;
v21 = v13[v14];
v22 = v14 + 1;
if ( v21 != '?' )
v22 = v14;
if ( v21 != '?' )
v15 = v12;
v14 = v22;
}
[OUTLMIME!CloseAllSockets+0x50804 Pseudo-code]
else if ( v15 > 1 )
{
if ( v15 <= 3 )
{
v18 = v13[v14];
v19 = v14 + 1;
if ( v18 != '?' )
v19 = v14;
v14 = v19;
v20 = v15 + 1;
if ( v18 != '?' )
v20 = v15;
v15 = v20;
}
[OUTLMIME!CloseAllSockets+0x50804 Pseudo-code]
if ( v15 == 4 )
{
if ( v13[v14] == '?' )
v15 = 5;
LABEL_40:
v24 = v13[v14];
if ( v24 )
{
if ( v5 == v14 )
goto LABEL_52;
if ( v8 != v14 )
{
v25 = IsDBCSLeadByte(v24);
v12 = 0;
if ( v25 )
++v14;
++v14;
}
}
goto LABEL_51;
}
[OUTLMIME!CloseAllSockets+0x50804 Pseudo-code]
if ( v15 == 5 )
{
v16 = v14;
v17 = v14 + 1;
v30 = v13[v16];
if ( v30 == '=' )
{
*v11++ = 34;
--v8;
}
memcpy(v11, v13, v17);
v13 += v17;
v11 += v17;
LODWORD(v5) = v5 - v17;
v8 -= v17;
if ( v30 == '=' )
{
*v11++ = 34;
--v8;
}
v12 = 0;
v14 = 0;
v15 = 0;
goto LABEL_51;
}
[OUTLMIME!CloseAllSockets+0x50804 Pseudo-code]
else
{
v23 = v13[v14];
if ( v23 != '=' )
{
if ( v23 == '"' )
v15 = 6;
goto LABEL_48;
}
v15 = 1;
}
if ( v15 )
goto LABEL_40;
[OUTLMIME!CloseAllSockets+0x50804 Pseudo-code]
LABEL_48:
v26 = IsDBCSLeadByte(*v13);
v12 = 0;
if ( v26 )
{
LODWORD(v5) = v5 - 1;
*v11++ = *v13++;
--v8;
}
LODWORD(v5) = v5 - 1;
*v11++ = *v13++;
--v8;
goto LABEL_51;
[OUTLMIME!CloseAllSockets+0x50804 Pseudo-code]
Cependant, en déclenchant un débordement de tas (heap overflow) en utilisant le bug ci-dessus, je n'ai pas pu satisfaire la condition pour sortir à nouveau de la boucle, donc je n'ai pas pu effectuer l'écrasement partiel aussi longtemps que je le voulais. J'ai donc dû trouver une entrée qui satisfait une condition spécifique permettant de sortir de la boucle. Pour la même raison que ci-dessus, j'ai audité strictement la partie de code environnante, et au lieu de trouver la valeur d'entrée qui peut échapper à la boucle, j'ai trouvé le bug de tomber dans une boucle infinie sans incrémenter l'index ou écrire lors du traitement d'une chaîne spéciale.

Après avoir effectué un heap spray et un heap feng shui, le détournement d'EIP a été réussi en écrasant la vftable de l'objet en cours d'exécution dans un autre thread qui n'était pas pris dans une boucle infinie en utilisant le bug ci-dessus.