
A simple proof of concept for WinRAR Path Traversal | RCE | CVE-2025-6218
추가 정보:
RARLAB WinRAR 디렉토리 탐색 원격 코드 실행 취약점. 이 취약점은 원격 공격자가 영향을 받는 RARLAB WinRAR 설치에서 임의 코드를 실행할 수 있도록 합니다. 이 취약점을 악용하려면 사용자 상호작용이 필요하며, 대상이 악성 페이지를 방문하거나 악성 파일을 열어야 합니다.
구체적인 결함은 아카이브 파일 내의 파일 경로 처리에 존재합니다. 조작된 파일 경로로 인해 프로세스가 의도하지 않은 디렉토리로 트래버설될 수 있습니다. 공격자는 이 취약점을 악용하여 현재 사용자의 컨텍스트에서 코드를 실행할 수 있습니다. ZDI-CAN-27198이었습니다.
게시 2025-06-21 00:09:03 업데이트 2025-06-23 20:16:22 출처 Zero Day Initiative
취약점 카테고리: 디렉토리 탐색 | 코드 실행
CVE-2025-6218 WinRAR 경로 탐색 취약점에 대한 매우 최소한의 간단한 개념 증명입니다. (또한 포함: 취약점 테스트를 위해 RAR 형식을 가지고 놀기 위한 제 도구 모음)
POC에는 경로 탐색에서 RCE 체인은 포함되어 있지 않지만, Windows에서 임의 파일 쓰기로 RCE를 달성하는 것은 간단합니다.
개념 증명 생성:
$ python3 cve-2025-6218.py
이 아카이브를 추출하면 test.txt가 현재 디렉토리 밖의 한 단계 위에 추출됩니다.
이 문제는 WinRAR 실행 파일(버전 7.11까지)에서 공백이 어떻게 처리되고 경로 탐색이 어떻게 검사되는지 사이의 특정 충돌로 인해 발생합니다:
A bit simplified and cleaned up version:
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;
}
}
//...
}
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) );
}
//...
}