CVE-2026-33824:WindowsIKEv2中的远程代码执行漏洞

admin 2026-04-27 05:07:07 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: CVE-2026-33824是WindowsIKEv2服务中的双重释放漏洞,由于IKEv2片段重组过程中对安全域供应商IDblob指针处理不当导致。攻击者可通过发送特制的IKESAINIT和分段IKE_AUTH消息触发双重释放,最终在IKEEXT服务(SYSTEM权限)中实现远程代码执行。用户应及时安装微软官方补丁以修复此高危漏洞。 综合评分: 85 文章分类: 漏洞分析,网络安全,应用安全,漏洞预警,应急响应


cover_image

CVE-2026-33824:Windows IKEv2 中的远程代码执行漏洞

Ots安全

2026年4月25日 17:47 广东

在小说阅读器读本章

去阅读

威胁简报

恶意软件

漏洞攻击

在TrendAI Research Services的一份漏洞报告中,TrendAI Research团队的Richard Chen和Lucas Miller详细介绍了Windows Internet Key Exchange (IKE)服务中一个最近已修复的双重释放漏洞。该漏洞最初由 微软的WARP & MORSE团队发现。成功利用该漏洞可能导致IKEEXT服务崩溃,甚至可能执行任意代码。以下是他们关于CVE-2026-33824的报告节选,并做了少量修改。

Windows Internet Key Exchange (IKEv2) 服务中报告了一个双重释放漏洞。该漏洞是由于处理密钥片段时出现错误造成的。

未经身份验证的远程攻击者可以通过向目标服务器发送精心构造的数据包来利用此漏洞。成功利用此漏洞可能导致 IKEEXT 服务崩溃,甚至可能执行任意代码。

漏洞

微软Windows操作系统包含服务器和桌面组件,并配有易于使用的图形用户界面。所有当前受支持的Windows版本都包含Internet密钥交换协议扩展,以支持虚拟专用网络(VPN)功能。

Windows 的 VPN 功能可加密主机之间的通信。ISAKMP 是 IPsec 主机用于建立安全关联的协商协议。它使用Internet 密钥交换 (IKE) 协议来协商加密通信的密钥。IKE 有两个版本:IKEv1 和 IKEv2。IKE 版本 1 (IKEv1) 和版本 2 (IKEv2) 消息的一般格式如下:

Field Length (Bytes) Description
-----------------------------------------------------------------------
IKE SA Initiator's SPI 8 Initiator's random ID (IKE Security Association)
IKE SA Responder's SPI 8 Responder's random ID (IKE Security Association)
Next Payload 1            Type of payload immediately after the header
Version 1            IKE version in use
Exchange Type 1            Type of exchange being used (e.g., IKE SA INIT \x22)
retransmission
Flags 1            Specifies options for the message
Message ID 4            Used to control the retransmission
Length 4            Length of IKE header + payload in Bytes (n+28)
Payloads n Payloads

有效载荷的类型由前一个有效载荷的“下一个有效载荷”标头或标头中的“下一个有效载荷”字段(在第一个有效载荷的情况下)决定。

Field Length (Bytes) Description
-----------------------------------------------------------------------------
Next Payload 1           Identifies what the next payload typeis in the packet.
Critical+Reserved 1           Can beleft zero.
Payload Length 2           Length of the current payload (m+4)
Payload Specific Data m           Data specific to the payload type

IKEv2 支持RFC 7383中定义的消息分片。当 IKEv2 消息超过路径 MTU 时,它们可能会被拆分为多个加密分片有效载荷。本报告重点关注加密分片 (SKF) 有效载荷(类型 0x35)。SKF 有效载荷格式定义如下:

Field Length (Bytes) Description
-----------------------------------------------------------------------------
Next Payload 1          Identifies what the next payload type is in the packet.
Critical+Reserved 1          Can be left zero.
Payload Length 2          Length of the current payload (n+8)
Fragment Number              2          Position ofthis fragment
Total Fragments 2          Total number of fragments
Initialization Vector var        IV for the encrypted fragment
Encrypted Data var        Encrypted fragment payload data
Integrity Check Value var        ICV (integrity checksum)

当 IKEv2 实现接收到数据片段时,它会将每个片段插入到一个有序列表中,并在接收到所有片段后重新组装这些片段。在 Windows 实现中,该函数IkeReinjectReassembledPacket()负责执行此重新组装操作。

Windows IKE 扩展库 (ikeext.dll) 中存在双重释放漏洞。该漏洞是由于在 IKEv2 片段重组过程中对堆分配的 blob 指针的所有权处理不当造成的。在 IKE_SA_INIT 交换期间,安全域供应商 ID 有效负载会导致IkeHandleSecurityRealmVendorId()分配一个 blob 并将其存储在偏移量为 0x208 的 MMSA(主模式安全关联)结构中。当片段化的 IKE_AUTH 消息被完全重组时,IkeReinjectReassembledPacket偏移量为 0x178 到 0x21F 的 MMSA 字段(包括偏移量为 0x208 的 blob 指针)会被复制到一个本地栈结构中。然后,该结构会被传递给另一个函数IkeQueueRecvRequest,该函数会将其浅复制到一个堆分配的工作项中。虽然IkeQueueRecvRequest对结构体中偏移量 0x10 处的重组缓冲区进行了深拷贝,但偏移量 0xC8 处的 Security Realm blob 指针仍然是浅拷贝,与 MMSA+0x208 处的原始数据存在别名。

当线程池处理排队的工作项时,IkeDestroyPacketContext会检查偏移量为 0xC8 的 blob 指针,并调用 WfpMemFreefree() 函数释放它(第一次释放)。此时,MMSA 结构仍然持有指向偏移量为 0x208 的同一分配的原始指针。随后,当 MMSA 被清理时IkeCleanupMMNegotiation,SA 引用计数会通过 free() 函数递减,IkeDerefMMSA最终触发free() IkeFreeMMSA 函数释放 MMSA 偏移量为 0x208 的 blob 指针——该分配此前已被 free() 函数释放IkeDestroyPacketContext(第二次释放)。

远程未经身份验证的攻击者可以通过向目标服务器发送精心构造的 IKE_SA_INIT 消息,后跟两个或多个包含无效 IKE_AUTH 消息的加密片段 (SKF) 有效载荷来利用此漏洞。片段重组路径将浅拷贝 blob 指针,随后的 MMSA 清理操作将触发双重释放。成功利用此漏洞可能导致在 IKEEXT 服务 (SYSTEM) 的安全上下文中执行任意代码。

源代码详解

以下代码片段取自 IKEEXT.DLL 文件版本 10.0.20348.2849,并使用 IDA Pro 版本 8.3 进行反编译。TrendAI 添加的注释已突出显示。

__int64 IkeReinjectReassembledPacket{
    void *pFragList, __int64 pMMSA, __int64 *pFragContext, __int64 pMMSACtx}
{
    IKE_RECV_CONTEXT recvCtx;
    memset(&recvCtx, 0, 0xF0);
    dwReassembledSize = 0;
    status = WfpMemAlloc(pFragList->dwTotalSize);
    if ( !status ) {
        // Copy of fragment context fields (0xA8 bytes)
        recvCtx.sourceAddr = pFragContext[0]; // +0x00: source address
        [ ...address and metadata fields copied via SSE moves... ]
        recvCtx.destAddr = pFragContext[3]; // +0x30: dest address
        [ ...continued... ]
        recvCtx.pRealmBlobData_VULN = pFragContext[9]; // +0x90: SHALLOW COPY of blob ptr
        recvCtx.pMMSACtxData = pFragContext[20]; // +0xA0: MMSA context
        // Reassemble fragments into a single contiguous buffer
        pCurEntry = pFragList->pHead;
        pReassembledBuf = recvCtx.pReassembledBuf;
        while ( pCurEntry != pFragList ) {
            status = WfpUINT32Add(dwReassembledSize, pCurEntry->dwDataSize, &tmp);
            if ( status )
                goto cleanup;
            memcpy(pReassembledBuf + dwReassembledSize, pCurEntry->pData,
                   pCurEntry->dwDataSize);
            dwReassembledSize += pCurEntry->dwDataSize;
            pCurEntry = pCurEntry->pFlink;
        }
        [ ...IKEv2 header fixup omitted for readability... ]
        // Re-queue reassembled packet for IKEv2 processing
        status = IkeQueueRecvRequest(&recvCtx, 1);
    }
cleanup:
    WfpMemFree(&recvCtx.pReassembledBuf);
    // FREE #1 PATH: ClearFragList iterates the fragment list
    ClearFragList(pFragList);
    if ( status )
        WfpReportError(status, "IkeReinjectReassembledPacket");
    return status;
}
__int64 IkeQueueRecvRequest(__int64 pRecvCtx, int a2)
{
    status = WfpMemAlloc(0xF0); // Allocate heap work item
    if ( status )
        goto error;
    pWorkItem = pWorkItemAlloc;
    // Shallow copy of entire IKE_RECV_CONTEXT (0xF0 bytes) into heap
    // work item.
    *(OWORD *)pWorkItem = *(OWORD *)pRecvCtx; // +0x00
    *(OWORD *)(pWorkItem + 1) = *(OWORD *)(pRecvCtx + 1); // +0x10
    [ ...14 more 16-byte copies... ]
    *(OWORD *)(pWorkItem + 14) = *(OWORD *)(pRecvCtx + 14);// +0xE0
    // Deep-copy the reassembly buffer (offset +0x10)
    status = WfpMemAlloc(*(DWORD *)(pRecvCtx + 24));
    [ ...memcpy of reassembly buffer... ]
    // Queue for thread pool processing
    IkeQueueWorkItem(IkeHandleRecvRequest, pWorkItem);
    [ ... ]
}
__int64 ClearFragList(void *pFragList)
{
    pEntry = *(IKE_FRAG_ENTRY **)pFragList;
    while ( pEntry != pFragList ) {
        pNext = pEntry->pFlink;
        FreeFragEntry(pEntry); // Free each fragment entry and its data
        pEntry = pNext;
    }
    pFragList->pTail = pFragList; // Reset list to empty
    pFragList->pHead = pFragList;
    pFragList->dwCount = 0;
    return0;
}
voidFreeFragEntry(IKE_FRAG_ENTRY *pFragEntry)
{
    if ( pFragEntry ) {
        WfpMemFree(&pFragEntry->pData); // FREE #1: frees blob data at entry+0x20
        WfpMemFree(pFragEntry); // Free the entry structure itself
    }
}
voidIkeCleanupMMNegotiation(LPCRITICAL_SECTION pMMSA, ...)
{
    [ ...truncated for readability... ]
    pFilterToSA = *(pMMSA + 1136);
    if ( pFilterToSA ) {
        *(pMMSA + 1136) = 0;
        RtlRemoveEntryHashTable(&gIkeExtGlobals[62].LockCount, pFilterToSA, 0);
        WfpMemFree(&pFilterToSA);
    }
    [ ...truncated for readability... ]
    IkeMoveMMNToZombieList(pMMSA);
}
__int64 IkeFreeMMSA(__int64 pMMSA)
{
    TraceLogHelper("IkeFreeMMSA", 1);
    // FREE #2: Free Security Realm blob at MMSA offset +0x208
    if ( *(pMMSA + 520) ) {
        *(DWORD *)(pMMSA + 512) = 0;
        WfpMemFree(pMMSA + 520);
    }
    // Free FilterToSA entry at MMSA+0x470
    pFilterToSA = *(pMMSA + 1136);
    if ( pFilterToSA ) {
        *(pMMSA + 1136) = 0;
        RtlRemoveEntryHashTable(&gIkeExtGlobals[62].LockCount, pFilterToSA, 0);
        WfpMemFree(&pFilterToSA);
    }
    [ ...truncated for readability... ]
}

检测指导

为了检测利用此漏洞的攻击,检测设备必须监控和解析 UDP 端口 500 和 4500 上的流量。IKE 通用格式、有效载荷字段和加密分片 (SKF) 有效载荷格式如上所示。

检测设备应监控所有入站 IKE 流量。检测需要关联同一 IKE 会话中的两个数据包:一个是携带 Microsoft 安全域供应商 ID 的 IKE_SA_INIT 请求,另一个是分片的 IKE_AUTH 请求。单独来看,这两个数据包都不是恶意的;必须从同一来源按顺序观察到它们。

  • IKE_SA_INIT

在UDP有效载荷的第17个字节偏移处,设备应检查三字节序列20 22 08,该序列对应于IKEv2版本标识符(0x20)、IKE_SA_INIT交换类型(0x22)和发起方标志(0x08)。然后,设备应扫描数据包的剩余部分,查找16字节序列68 6a 8c bd fe 63 4b 40 51 46 fb 2b af 33 e9 e8,该序列是Microsoft安全域供应商ID。如果满足这两个条件,设备应遵循以下指南。

  • IKE_AUTH

对于来自同一源的后续数据包,设备应检查UDP有效载荷偏移量16至23处的字节。在偏移量16处,该四字节序列35 20 23 08标识加密分片有效载荷(SKF,类型0x35)、IKEv2版本(0x20)、IKE_AUTH交换类型(0x23)和发起方标志(0x08)。如果找到该序列,检测设备应检查偏移量20处并查找该四字节序列00 00 00 01。如果找到,则应将该流量视为恶意流量;很可能正在进行利用此漏洞的攻击。

注释

• 所有多字节值均应视为大端字节序。

• 检测端口 4500 上的流量时,IKE 数据包前面会添加一个 4 字节的非 ESP 标记(\x00\x00\x00\x00),将所有 IKE 头部内容偏移量移 4 个字节。

结论

微软已在 2026 年 4 月的版本更新中修复了此漏洞。他们指出,在补丁测试和部署期间,有两种缓解措施可以防止漏洞被利用。

· 阻止不使用 IKE 的系统通过 UDP 端口 500 和 4500 进行入站流量。

· 对于需要 IKE 的系统,配置防火墙规则,仅允许来自已知对等地址的入站流量通过 UDP 端口 500 和 4500。

一旦应用安全补丁,这些缓解措施可能会被移除。彻底修复此漏洞的唯一方法是应用供应商提供的更新。

END

公众号内容都来自国外平台-所有文章可通过点击阅读原文到达原文地址或参考地址

排版 编辑 | Ots 小安

采集 翻译 | Ots Ai牛马

公众号 | AnQuan7 (Ots安全)


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:Ots安全 《CVE-2026-33824:Windows IKEv2 中的远程代码执行漏洞》

评论:0   参与:  0