Привет, Хабр!

Меня зовут Илья Ефимов, я аналитик-исследователь угроз кибербезопасности в компании R-Vision. Моя статья будет посвящена разбору уязвимости CVE-2023-38831 в архиваторе WinRAR. Эта уязвимость активно используется хакерами в атаках на отечественные компании. В отчете компании BI.ZONE фиксируется информация, что злоумышленники из групп Cobalt Werewolf, Mysterious Werewolf использовали данную уязвимость для доставки вредоносной полезной нагрузки. В этом случае уязвимость эксплуатировала вредоносный архив при доставке фишингового письма. Схожую информацию предоставляют исследователи из Positive Technologies, связав активность группировки ExCobalt с эксплуатацией CVE-2023-38831. Также фиксировались случаи эксплуатации данной уязвимости ВПО Agent Tesla и DarkMe. Стоит отметить, что по данным компании Kaspersky в 2024 году данная уязвимость занимает третье место по частоте эксплуатации атакующими в России и странах СНГ.

В своей статье я опишу, в чем заключается суть уязвимости, продемонстрирую её эксплуатацию, а также генерируемые события по активности. Затем я подробно опишу процесс детектирования уязвимости и определю основные артефакты с помощью R-Vision SIEM.

Описание уязвимости

В ОС Windows нельзя иметь два файла с одинаковым именем в одной директории. Также невозможно иметь файл и директорию с совпадающим именем (файл test.txt и директория test.txt). Но в архиваторах по типу WinRAR/7zip это возможно. В сжатом файле, несмотря на то, что есть файлы с одинаковым именем, они записываются в специальной структуре. Таким образом, в ZIP/RAR-файле может быть два объекта (файла/каталога) с одинаковым именем.

В этом и кроется CVE-2023-38831? Отчасти да, но есть еще один нюанс.

Итак, когда есть файл и каталог с одинаковым именем в архивном файле, и происходит открытие файла, дважды щелкнув по нему (целевому файлу), осуществляется извлечение всех файлов с тем же именем, что и целевой файл (в том числе, и файлы внутри директории с тем же именем). Все извлеченные файлы записываются во временный каталог по пути %tmp%. Это поведение WinRAR кажется странным, так как 7Zip не ведет себя подобным образом.

Проверка бреши в системе

На практике нельзя поместить два объекта с одинаковым именем в один архивный файл в WinRAR. В данном случае был использован 7Zip, чтобы создать zip-файл.

Для этого у нас есть директория, в которой содержатся файлы text1.txt и text2.txt. Размер и содержимое файлов разное:

Рисунок 1 - Создание тестовых файлов text1.txt и text2.txt
Рисунок 1 - Создание тестовых файлов text1.txt и text2.txt

Далее используется CLI 7Zip для создания и добавления файлов в архив test.zip:

Рисунок 2 - Занесение тестовых файлов text1.txt и text2.txt в архив test.zip
Рисунок 2 - Занесение тестовых файлов text1.txt и text2.txt в архив test.zip

Теперь у нас есть архив, содержащий два добавленных нами файла.

Рисунок 3 - Отображение содержимого архива test.zip в CLI
Рисунок 3 - Отображение содержимого архива test.zip в CLI

Далее переименуем файл text2.txt в text1.txt. Сделать это можно при помощи флага rn у 7Zip.

Рисунок 4 - Переименование файла text2.txt в text1.txt
Рисунок 4 - Переименование файла text2.txt в text1.txt

В итоге у нас получаются два файла с одинаковым именем в одном архиве. Этот архив можно открыть в т.ч. через WinRAR. Также можно заметить, что несмотря на одинаковое название, один файл пустой, второй имеет содержимое:

Рисунок 5 - Отображение архива test.zip в WinRAR
Рисунок 5 - Отображение архива test.zip в WinRAR

Теперь давайте откроем файл размером 4 байта внутри архива двойным нажатием мыши и посмотрим какой файл будет открыт:

Рисунок 6 - Открытие файла text1.txt в архиве
Рисунок 6 - Открытие файла text1.txt в архиве

Можно заметить, что WinRAR предлагает нам заменить существующий файл. Это означает, что там уже есть файл с таким именем, размер которого 0 байт (пустой файл). В случае если согласиться на замену файла, то пустой файл будет заменен на не пустой, и мы увидим содержимое файла:

Рисунок 7 - Содержимое непустого файла text1.txt
Рисунок 7 - Содержимое непустого файла text1.txt

Что произошло?

WinRAR сначала создает временную папку в директории %tmp%, а затем извлекает первый файл text1.txt. Теперь во временной директории у нас есть первый text1. Но после этого WinRAR также пытается извлечь второй text1.txt. Поскольку в Windows нельзя иметь два файла с одинаковым именем в одной директории, то WinRAR предлагает выбрать действие для этого нового файла. Если вы нажмете "Да", то второй файл перезапишет первый, и вы увидите содержимое второго файла. В WinRAR проверяются все имена файлов и каталогов в архиве с целевым файлом. Если одно из них имеет имя, совпадающее с именем файла, который нужно извлечь (целевой файл), функция возвращает 1, т.е. извлекает его тоже. При этом 7-Zip просто извлекает файл, который вы хотите открыть.

Рисунок 8 - Работа WinRAR по проверке имен файлов
Рисунок 8 - Работа WinRAR по проверке имен файлов

Функция на рисунке выше посимвольно сравнивает имена двух файлов, чтобы определить, равны ли они или нет. У нас есть два файла с одинаковым именем, оба называются text1.txt. Когда необходимо извлечь файл из архива, WinRAR проверяет имя целевого файла с именами всех объектов, существующих в архиве. Например, если у нас есть пять файлов в архиве, и мы хотим извлечь один из них, WinRAR проверяет имя этого файла с именами остальных четырех файлов.

Теперь, если имена этих файлов были одинаковыми, то функция проверяет еще одну вещь.

Предположим, что мы хотим извлечь fileA, и у нас есть еще один файл в архиве - fileB (имя которого совпадает с именем fileA). Также в архиве есть каталог dirA с именем, совпадающим с fileA в котором находится fileB (таким образом, имена dirA, fileA и fileB совпадают). Когда происходит нажатие на fileA, чтобы извлечь его, WinRAR проверяет, равно ли имя fileA какому-либо другому файлу или каталогу. Если имя файла совпадает с именем fileA, то оно добавляется в список извлечения. Также, если имя каталога dirA совпадает с именем fileA, то WinRAR проверяет файлы в этом каталоге с именем fileA. Если какой-либо из них совпадает, он также добавляется в список извлечения. Схема наглядно показана на рисунке:

Рисунок 9. Схема распаковки архива с файлом fileA и директорией dirA
Рисунок 9. Схема распаковки архива с файлом fileA и директорией dirA

Функция сначала проверяет имена файлов, а затем проверяет, содержит ли имя fileB символы \\ (является каталогом) или / (является концом файла). Если имена файлов совпадают или fileB является каталогом, функция возвращает 1, то есть продолжает извлечение. Таким образом, если у нас есть файл или каталог с именем, равным имени файла, который нужно извлечь, функция возвращает 1, и затем WinRAR также извлекает эти файлы.

Рисунок 10. Проверка является ли проверяемый файл директорией или нет
Рисунок 10. Проверка является ли проверяемый файл директорией или нет

Эксплуатация уязвимости

У нас есть файл, который является основным файлом, с пробелом " " в конце его имени. Также у нас есть каталог с тем же именем, что и у основного файла, и пробелом в конце его имени " ". Внутри каталога у нас есть еще один файл с тем же именем, что и у основного файла, и пробелом в конце его имени " ", а затем с расширением .cmd. Этот файл содержит полезную нагрузку.

Структура архива выглядит таким образом:

text.txt (D)  
--text.txt .cmd (F)  
text.txt (F)
Рисунок 11 - Отображение архива prodtest.zip в CLI
Рисунок 11 - Отображение архива prodtest.zip в CLI

Файл CMD вызывает калькулятор:

Рисунок 12 - Содержимое файла text1.txt .cmd
Рисунок 12 - Содержимое файла text1.txt .cmd

Теперь, при открытии архивного файла text1.txt (F), WinRAR сравнивает все файлы в архиве, чтобы найти файлы/каталоги с таким же именем, как text1.txt (F).

Поправка: в процессе тестирования можно заметить разные директории %tmp%, это связано с тем, что активность фиксировалась в рамках разных тестов.

Когда WinRAR сравнивает имя файла text1.txt (F) с именем каталога text1.txt (D), то выясняется, что они равны. Поэтому WinRAR продолжает проверять файлы внутри каталога и обнаруживает, что файл text1.txt. cmd (F) совпадает с целевым файлом, поэтому он добавляет его в список для извлечения.
Пример эксплуатации выглядит следующим образом:

Рисунок 13 - Эксплуатация уязвимости CVE-2023-38831
Рисунок 13 - Эксплуатация уязвимости CVE-2023-38831

При этом можно увидеть как происходит создание файлов, процесс WinRAR использует CreateFile API вызов для записи файлов во временную директорию.

Рисунок 14 - Вызов процессом WinRAR API-вызова CreateFileW с файлом text1.txt
Рисунок 14 - Вызов процессом WinRAR API-вызова CreateFileW с файлом text1.txt
Рисунок 15 - Вызов процессом WinRAR API-вызова CreateFileW с файлом text1.txt .cmd
Рисунок 15 - Вызов процессом WinRAR API-вызова CreateFileW с файлом text1.txt .cmd

Теперь наш список файлов из архива для извлечения выглядит следующим образом:

Рисунок 16 - Содержимое временной директории с извлекаемым содержимым
Рисунок 16 - Содержимое временной директории с извлекаемым содержимым

Также можно обратить внимание на сгенерированные события создания извлечённых файлов в %tmp% директории в Sysmon/Operational EventID 11(FileCreate):

Рисунок 17 - Событие создания файлов в R-Vision SIEM
Рисунок 17 - Событие создания файлов в R-Vision SIEM

Так как после открытия легитимного файла text1.txt за счет уязвимости также происходит открытие файла командной строки text1.txt .cmd, то в результате генерируются события Security EventID 4688(Process Creation) и Sysmon/Operational EventID 1(Process Creation):

Рисунок 18 - Событие создания процессов cmd.exe от WinRAR в R-Vision SIEM
Рисунок 18 - Событие создания процессов cmd.exe от WinRAR в R-Vision SIEM

Почему так происходит?

Для того чтобы понять, почему так происходит, обратимся к документации Microsoft:

  • Если файл сохраняется как Foo.txt, где первым символом является пустое пространство (пробел) ASCII (0x20), он будет сохранен в файловой системе как Foo.txt (без пробела).

  • Если файл сохраняется как Foo.txt , где конечные символы являются пространством ASCII (0x20), он будет сохранен в файловой системе как Foo.txt.

Исходя из описанного выше, можно сделать вывод, что при сохранении файла все лишние пробелы в конце имени файла должны убираться. Но теперь пойдем дальше и вспомним, что было после того как мы запустили файлы из архива.

WinRAR попытается открыть файл "text1.txt ", но WinRAR не знает как это сделать. Например, если наш целевой файл был файлом PDF, то WinRAR не знает с помощью какой программы это сделать или какое приложение используется для открытия текстовых файлов на конкретной системе Windows. В таких случаях приложения используют API Windows, такие как ShellExecuteExW.

Из документации Microsoft:

Функция ShellExecuteExW - выполняет операцию с указанным файлом.

ShellExecute — это функция Windows API, которая используется для выполнения различных операций, связанных с манипуляциями с файлами или взаимодействием с системой. Она выполняет указанный файл или операцию с помощью ассоциированного по умолчанию действия для конкретного расширения файла или приложения.

Рисунок 19 - Использование API вызова ShellExecuteEx
Рисунок 19 - Использование API вызова ShellExecuteEx

Функция принимает на вход аргумент SHELLEXECUTEINFO, которая обладает следующей структурой:

Рисунок 20 - Структура SHELLEXECUTEINFO
Рисунок 20 - Структура SHELLEXECUTEINFO

В данной структуре нас интересуют параметры lpVerb и lpFile. Из документации Microsoft на параметр IpVerb:

Тип: LPCTSTR

Строка, называемая глаголом, которая указывает выполняемое действие. Набор доступных команд зависит от конкретного файла или папки. Как правило, действия, доступные в контекстном меню объекта, являются доступными командами. Этот параметр может иметь значение NULL. В этом случае используется команда по умолчанию, если она доступна. В противном случае используется команда "open". Если глаголы не доступны, система использует первую команду, указанную в реестре. Если нет причин для ограничения действия определенной командой, передайте значение NULL, чтобы использовать вычисленное значение по умолчанию. Это необходимо в некоторых случаях, например при указании SEE_MASK_FLAG_NO_UI и создании пользовательского интерфейса "Открыть с помощью", если приложения не установлены.

Обычно используются следующие команды:

  • edit: запускает редактор и открывает документ для редактирования. Если lpFile не является файлом документа, функция завершится ошибкой.

  • explore: просматривает папку, указанную в lpFile.

  • find: инициирует поиск, начиная с указанного каталога.

  • open: открывает файл, указанный параметром lpFile . Файл может быть исполняемым файлом, файлом документа или папкой.

  • print: печатает файл документа, заданный lpFile. Если lpFile не является файлом документа, функция завершится ошибкой.

  • properties: отображает свойства файла или папки.

  • runas: запускает приложение от имени администратора. Контроль учетных записей (UAC) запрашивает у пользователя согласие на запуск приложения с повышенными привилегиями или ввод учетных данных учетной записи администратора, используемой для запуска приложения.

Описанный выше параметр очень важен. Он говорит, что если IpVerb параметр имеет значение NULL, то используется команда по умолчанию, если она доступна. В противном случае используется команда open.

Из документации Microsoft на параметр IpFile:

Адрес строки, заканчивающейся null, которая указывает имя файла или объекта, для которого ShellExecuteEx будет выполнять действие, указанное параметром lpVerb.

То есть параметр IpFile - это путь к файлу, используемый функцией ShellExecuteExW для осуществления действия из параметра IpVerb.

При этом если обратить внимание на параметры в WinRAR, то в функции ShellExecuteExW IpVerb равен NULL, при этом в параметре lpFile, где содержится путь к открываемому файлу, будет символ пробела (0x20) "text1.txt ", хотя ранее говорилось об обработке Windows пробелов в файлах. По сути вызов функции ShellExecuteExW с lpFile равным "text1.txt " и является уязвимостью, приводящей к запуску файла "text1.txt .cmd". На рисунке показаны содержимое переменных lpFile и lpVerb, можно увидеть, что идет обращение к "text1.txt ":

Рисунок 21 - Содержимое переменных при вызове ShellExecuteExW
Рисунок 21 - Содержимое переменных при вызове ShellExecuteExW

Как же происходит, что при вызове "text1.txt " запускается "text1.txt .cmd"? Как мы узнали ранее, из-за уязвимости в WinRAR, извлекается не только файл, который мы хотим извлечь, но и файлы, совпадающие по названию. Помимо этого, когда файлы попадают во временную директорию, механизмы Windows и WinRAR преобразуют файлы, убирая пробелы из конца их названия. Ниже приведена таблица преобразования:

Имя файла в архиве

Имя файла в %tmp% директории

"text.txt "

"text.txt"

"text.txt .cmd"

"text.txt .cmd"

Уязвимость кроется в том, что когда мы дважды нажимаем на файлы и они передаются в %tmp% директорию, при вызове ShellExecuteExW WinRAR передает туда неизмененные названия файлов. И, получается, что вызов идет к ShellExecuteExW("text.txt "), но так как файл в %tmp% был преобразован ("text.txt"), как было описано в документации, то обращение идет к подходящему по названию файлу - "text.txt .cmd". В этом и кроется уязвимость.

Более наглядный пример можно увидеть ниже, где мы запускаем "text.txt .cmd" без указания расширения .cmd:

Рисунок 22 - Запуск файла text.txt .cmd без указания расширения .cmd
Рисунок 22 - Запуск файла text.txt .cmd без указания расширения .cmd

Вывод по уязвимости

Исходя из анализа активности можно выделить две уязвимости:

 Первая уязвимость:

  1. По умолчанию, при распаковке файла из архива, WinRAR проходится по всему архиву в поисках совпадающих имен файлов/директорий. Например, если мы открываем файл "text.txt ", а при этом у нас есть директория "text.txt ", в которой находится файл "text.txt .cmd", то WinRAR будет воспринимать файлы "text.txt " и "text.txt .cmd" как идентичные.

  2. После этого все файлы, которые прошли валидацию помещаются в %tmp% директорию, откуда будет производиться запуск.

Вторая уязвимость:

WinRAR осуществляет проверку на наличие пробелов в конце файла, преобразуя их в нулевые символы (0x00) ("text.txt " -> "text.txt", "text.txt .cmd" -> "text.txt .cmd").

  1. В %tmp% архив передаются преобразованные файлы "text.txt", "text.txt .cmd".

  2. Уязвимость заключается в том, что после того как файлы оказываются в %tmp% директории при помощи API вызова ShellExecuteExW() происходит обращение к распакованному файлу "text.txt " (на который мы дважды нажимали изначально в архиве), но проблема в том, что после преобразований в %tmp% директории файл поменялся на "text.txt" (без пробела), а файлом с пробелом остается "text.txt .cmd".

  3. В результате чего происходит обращение функции ShellExecuteExW() к вредоносному файлу "text.txt .cmd"

Детектирование активности

В пакете экспертизы для R-Vision SIEM уже есть правило детектирующее эту активность при помощи правила «Запуск интерпретатора командной строки от WinRAR». Далее мы разберем его логику работы.

Рисунок 23 - Корреляционное событие сработавшего правила в R-Vision SIEM
Рисунок 23 - Корреляционное событие сработавшего правила в R-Vision SIEM

Часть детектирующей логики правила, где сработка происходит при создании процесса cmd.exe от родительского процесса winrar.exe:

filter: !vrl |
  .dvendor == "Microsoft" &&
  includes(["1", "4688"], .externalId)
  
aliases:
  cmd_exec:
    filter: !vrl |
      flag = false
      sproc = downcase(to_string(.sproc) ?? "-")
      dproc = downcase(to_string(.dproc) ?? "-")
      if ends_with(sproc, "\\winrar.exe") && ends_with(dproc, "\\cmd.exe"){
        flag = true
      }
      flag

Если описанный ранее детект является более общим, то правило R-Vision SIEM Эксплуатация уязвимости в WinRAR - CVE-2023-38831 позволяет выявить именно эксплуатацию CVE-2023-38831:

Рисунок 24 - Корреляционное событие сработавшего правила в R-Vision SIEM
Рисунок 24 - Корреляционное событие сработавшего правила в R-Vision SIEM

Часть детектирующей логики правила, где фильтруется событие создания файла во временной директории. При этом важно, чтобы файл имел два расширения и имел пробел между этими расширениями:

filter: !vrl |
  .dvendor == "Microsoft" &&
  .externalId == "11"
  
aliases:
  mal_file_create:
    filter: !vrl |
      flag = false
      filePath = downcase(to_string(.filePath) ?? "-")
      fileName = to_string(split(filePath, "\\\\")[-1])
      dproc = downcase(to_string(.dproc) ?? "-")
      if ends_with(dproc, "\\winrar.exe") &&
      contains(filePath, "\\\\appdata\\\\local\\\\temp\\\\rar$") &&
      match(fileName, r'\.[a-zA-Z0-9]{1,4}\s+\.(cmd|bat)$'){
        flag = true
      }
      flag

Заключение

Исходя из разбора, описанного выше можно выделить следующие рекомендации по защите от уязвимости CVE-2023-38831:

  • Установите обновление.
    Эта уязвимость затрагивает версию WinRAR до 6.23. Рекомендуется обновить WinRAR до последней версии. Регулярное обновление программного обеспечения, браузеров и устройств является важной практикой безопасности, которая поможет защитить ваши системы от известных уязвимостей и киберугроз.

  • Будьте внимательны.
    Всегда будьте осторожны при получении сообщений, которые просят вас перейти по ссылке или открыть вложение.

  • Скорректируйте настройки.
    Настройте технологии безопасности электронной почты, такие как SPF, DKIM и DMARC, чтобы аутентифицировать и проверять происхождение входящих сообщений.

  • Проводите мониторинг и анализ.
    Наличие правильного журналирования, видимости активов и мониторинга систем является важными компонентами надежной стратегии кибербезопасности. Эти меры предоставляют обзор сети и помогают выявлять аномалии, которые могут указывать на угрозу безопасности.

  • Следите за новыми трендами атак.
    Будьте в курсе новых тенденций, которые используют атакующие. Это поможет вам своевременно выявлять потенциальные риски.

Кроме того, использование таких решений безопасности, как R-Vision SIEM, поможет своевременно обнаружить эту активность и предотвратить дальнейшее развитие атаки, если будет эксплуатироваться уязвимость CVE-2023-38831.

Так, детектирующая логика в правилах R-Vision SIEM направлена на мониторинг событий создания процесса cmd.exe от процесса winrar.exe по событиям EventID 1 журнала Sysmon и EventID 4688 журнала Security (для правила «Запуск интерпретатора командной строки от WinRAR») и по событиям создания файла во временной директории с двойным расширением, где между расширениями будет пробел, эту активность можно отслеживать по событиям EventID 11 журнала Sysmon (для правила «Эксплуатация уязвимости в WinRAR — CVE-2023-38831»). Использование данных событий в правилах корреляции позволяет нам своевременно выявить эксплуатацию уязвимости.

Если у вас остались вопросы, я с радостью отвечу на них в комментариях!

Автор: Илья Ефимов, аналитик-исследователь угроз кибербезопасности R-Vision.

Комментарии (4)


  1. mayorovp
    17.09.2024 10:38

    Если файл сохраняется как Foo.txt , где конечные символы являются пространством ASCII (0x20), он будет сохранен в файловой системе как Foo.txt.

    Чем-чем? Пространством ASCII? Это точно не машинный перевод?


    1. avdx
      17.09.2024 10:38

      Так это же, судя по всему, цитата из документации с сайта microsoft. А там вся документация это и есть машинный перевод с английского.


  1. Tiriet
    17.09.2024 10:38
    +3

    использовали данную уязвимость для доставки вредоносной полезной нагрузки

    я так и не понял- вредоносной или полезной была нагрузка?


    1. CitizenOfDreams
      17.09.2024 10:38

      я так и не понял- вредоносной или полезной была нагрузка?

      Одно другого не исключает.