
Une simple preuve de concept pour WinRAR Path Traversal | RCE | CVE-2025-6218
Plus d'informations :
Vulnérabilité d'exécution de code à distance par contournement de répertoire dans RARLAB WinRAR. Cette vulnérabilité permet à des attaquants distants d'exécuter du code arbitraire sur des installations affectées de RARLAB WinRAR. L'interaction de l'utilisateur est nécessaire pour exploiter cette vulnérabilité, car la cible doit visiter une page malveillante ou ouvrir un fichier malveillant.
Le défaut spécifique réside dans le traitement des chemins de fichiers dans les archives. Un chemin de fichier contrefait peut amener le processus à traverser des répertoires non prévus. Un attaquant peut exploiter cette vulnérabilité pour exécuter du code dans le contexte de l'utilisateur courant. Était ZDI-CAN-27198.
Publié le 2025-06-21 00:09:03 Mis à jour le 2025-06-23 20:16:22 Source Zero Day Initiative
Catégorie de vulnérabilité : Contournement de répertoire | Exécution de code
Une preuve de concept très minimale et simple pour la vulnérabilité de contournement de chemin CVE-2025-6218 WinRAR. (Inclus également : mon ensemble d'outils pour jouer avec le format RAR pour les tests de vulnérabilité)
La chaîne de contournement de chemin vers RCE n'est pas incluse dans la POC, mais l'écriture arbitraire de fichier vers RCE sur Windows est triviale.
Créer la preuve de concept :
$ python3 cve-2025-6218.py
Si vous extrayez cette archive, test.txt sera extrait un niveau au-dessus du répertoire actuel.
Le problème provient d'un conflit spécifique entre la manière dont les espaces sont nettoyés et dont les traversées de chemin sont analysées dans l'exécutable WinRAR jusqu'à la version 7.11 :
Une version un peu simplifiée et nettoyée :
void file_name_check(char *a1){
cur_filename = a1;
j = 0;
cur_pos = 0;
if ( *(a1 + 4) > 0 )
{
offset = 0;
while ( 1 )
{
if ( (cur_pos + 1) == cur_filename[2] )
goto BREAK;
str = cur_filename;
if ( cur_filename[3] > 7 )
str = *cur_filename;
if ( str[offset + 1] == '\\' || str[offset + 1] == '/' )
{
BREAK:
if ( cur_pos >= 0 )
break;
}
LOOP_START:
++cur_pos;
++offset;
if ( cur_pos >= *(cur_filename + 4) )
goto LABEL_47;
}
while ( 1 )
{
if ( str[offset] != '.' )
{
if ( str[offset] != ' ' )
goto LOOP_START;
}
if ( !cur_pos )
{
if ( str[offset] == ' ' )
{
str[offset] = '_';
goto LOOP_START;
}
}
if ( str[offset] == '.' )
{
if ( !cur_pos )
goto LOOP_START;
if ( str[offset - 1] == '\\' || str[offset - 1] == '/' )
goto LOOP_START;
if ( cur_pos == 2 )
{
if ( is_safe_character(cur_filename) )
goto LOOP_START;
}
else if ( cur_pos < 1 )
{
goto DELETE;
}
if ( str[offset - 1] == '.' )
{
if ( cur_pos == 1 )
goto LOOP_START;
if ( str[offset - 2] == '\\' || str[offset - 2] == '/' || cur_pos == 3 && is_safe_character(cur_filename) )
goto LOOP_START;
}
}
DELETE:
delete_char(cur_filename, cur_pos, 1u);
--offset;
if ( --cur_pos < 0 )
goto LOOP_START;
}
}
//...
}
Après 7.12 :
void __fastcall file_name_check(char **a1){
cur_filename = a1;
j = 0;
if ( *(a1 + 4) > 0 )
{
offset = 0;
fname_index = 1;
do
{
if ( fname_index == cur_filename[2] )
goto HANDLE_DIR_NEXT;
str = cur_filename;
if ( str[offset + 1] == '\\' || str[offset + 1] == '/' )
{
HANDLE_DIR_NEXT:
if ( offset >= 0 )
{
if ( str[offset] == '.' )
goto FILENAME_BEGINS;
if ( str[offset] == ' ' )
{
FILENAME_BEGINS:
if ( str[offset] != '.' )
goto CONT;
if ( offset )
{
if ( str[offset - 1] != '\\'
&& str[offset - 1] != '/'
&& (offset != 2 || !is_safe_character(cur_filename)) )
{
if ( str[offset - 1] != '.' )
goto CONT;
if ( offset != 1 )
{
if ( str[offset - 2] != '\\'
&& str[offset - 2] != '/'
&& (offset != 3 || !is_safe_character(cur_filename)) )
{
CONT:
str[offset] = '_';
}
}
}
}
}
}
}
++j;
++offset;
++fname_index;
}
while ( j < *(cur_filename + 4) );
}
//...
}