
Una simple prueba de concepto para WinRAR Path Traversal | RCE | CVE-2025-6218
Más información:
Vulnerabilidad de Ejecución Remota de Código por Directory Traversal en RARLAB WinRAR. Esta vulnerabilidad permite a atacantes remotos ejecutar código arbitrario en instalaciones afectadas de RARLAB WinRAR. Se requiere interacción del usuario para explotar esta vulnerabilidad, ya que la víctima debe visitar una página maliciosa o abrir un archivo malicioso.
La falla específica existe en el manejo de rutas de archivos dentro de archivos comprimidos. Una ruta de archivo manipulada puede hacer que el proceso atraviese directorios no deseados. Un atacante puede aprovechar esta vulnerabilidad para ejecutar código en el contexto del usuario actual. Fue ZDI-CAN-27198.
Publicado 2025-06-21 00:09:03 Actualizado 2025-06-23 20:16:22 Fuente Zero Day Initiative
Categoría de vulnerabilidad: Directory traversal | Ejecución de código
Una prueba de concepto muy mínima y simple para la vulnerabilidad de path traversal de WinRAR CVE-2025-6218. (También se incluye: mi conjunto de herramientas para jugar con el formato RAR para pruebas de vulnerabilidad)
La cadena de path traversal a RCE no está incluida en la POC, pero la escritura arbitraria de archivos a RCE en Windows es trivial.
Crear la prueba de concepto:
$ python3 cve-2025-6218.py
Si extrae este archivo, el test.txt se extraerá un nivel fuera del directorio actual.
El problema proviene de un conflicto específico entre cómo se sanean los espacios en blanco y cómo se escanean los path traversals en el ejecutable de WinRAR hasta la versión 7.11:
Una versión un poco simplificada y limpiada:
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;
}
}
//...
}
Después de 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) );
}
//...
}