PoC Archive PoC Archive
Critical CVE-2026-33824 unpatched

Windows ikeext.dll IKEv2 Double-Free Remote Kernel Exploit — CVE-2026-33824

by EpSiLoNPoInTOrI · 2026-07-05

Severity
Critical
CVE
CVE-2026-33824
Category
network
Affected product
Windows IKEv2 IPsec driver (ikeext.dll)
Affected versions
Windows builds where ikeext.dll matches the exploit's hardcoded offsets (build-specific; not dynamically resolved in this PoC)
Disclosed
2026-07-05
Patch status
unpatched

Metadata

FieldValue
Date Added2026-07-05
Last Updated2026-06
Author / ResearcherEpSiLoNPoInTOrI
CVE / AdvisoryCVE-2026-33824
Categorynetwork
SeverityCritical
CVSS ScoreNot specified in source
StatusWeaponized
Tagsikev2, windows-kernel, double-free, ikeext, rop-chain, heap-grooming, reverse-shell, anti-debug, packet-fragmentation
RelatedN/A

Affected Target

FieldValue
Software / SystemWindows IKEv2 IPsec driver (ikeext.dll)
Versions AffectedWindows builds where ikeext.dll matches the exploit’s hardcoded offsets (build-specific; not dynamically resolved in this PoC)
Language / PlatformC/C++, targeting Windows kernel-mode IKEv2 service over UDP/500
Authentication RequiredNo
Network Access RequiredYes

Summary

This repository is an in-progress C/C++ exploit prototype targeting a double-free vulnerability in Windows’ ikeext.dll, the kernel driver that handles IKEv2 IPsec negotiation over UDP port 500. The exploit constructs and sends fragmented (SKF) IKEv2 packets to trigger the double-free, then performs multi-threaded heap grooming to gain control over freed memory, builds a ROP chain from gadgets scanned out of loaded modules, and stages a payload intended to obtain arbitrary read/write and ultimately code execution, with a reverse-shell listener on port 4444 as the intended final payload delivery mechanism. The author’s own README explicitly states the project is unfinished and not fully functional — several referenced functions (AMSI/Defender/ETW bypass, environment checks, shell listener start/stop) may be incomplete, offsets are hardcoded to a specific Windows build with no dynamic resolution, and the ROP chain/shellcode staging is not fully wired together. The codebase also includes a heavy, self-described obfuscation layer (a custom bytecode VM, control-flow mangling, anti-debug thread, fake PE section signatures for VMProtect/Denuvo/etc., dynamic API resolution) that is part of the exploit’s own anti-analysis design rather than anything hidden or injected — the repo’s included correct_code.py/corriger.txt are the author’s own notes/scripts for fixing compilation issues and adding missing constants (e.g. OBFUSCATION_KEY3) in this obfuscation layer.


Vulnerability Details

Root Cause

A double-free condition in ikeext.dll’s IKEv2 payload-handling code path (referenced offset g_IkeextProcessIkePayload), reachable by sending crafted/fragmented IKEv2 SA negotiation packets over UDP/500, which the exploit combines with heap grooming to gain a controlled reallocation into the freed chunk.

Attack Vector

  1. Attacker sends UDP packets to port 500 on a target running the vulnerable Windows IKEv2 service to confirm reachability.
  2. Attacker constructs IKEv2 SA/Proposal/Transform/Nonce/Key-Exchange payloads, fragmented via SKF (SKF_FRAGMENTS), crafted to trigger the double-free in ikeext.dll’s payload handler.
  3. Multiple threads perform heap grooming (fixed-size chunk allocation/free cycles) to control what reallocates into the freed region.
  4. A ROP chain — built from gadgets located via a byte-signature scanner in loaded modules, chained with VirtualProtect/CFG-disable/stack-pivot gadgets — is used to gain arbitrary memory read/write and stage shellcode.
  5. On success, the exploit intends to trigger a reverse shell callback to the attacker on TCP port 4444 (not fully wired end-to-end per the author’s own notes).

Impact

If completed and functional against a matching build, this would constitute unauthenticated remote code execution in Windows kernel context via the IKEv2/IPsec stack — a critical, wormable-class network vulnerability. As shipped, the author describes the exploit as not fully functional/finished, with hardcoded build-specific offsets and incomplete payload wiring.


Environment / Lab Setup

Target:   Windows host with ikeext.dll (IKEv2 IPsec service) reachable on UDP/500, matching the hardcoded offsets in IkEv2.cpp
Attacker: Windows/MSVC build toolchain (project depends on runassys/ headers not included here), ws2_32/iphlpapi/bcrypt/Version libs; listener on TCP/4444 for the intended reverse shell

Proof of Concept

PoC Script

See IkEv2.cpp in this folder (author’s own build-fix notes in correct_code.py and corriger.txt are included as-is for completeness).

1
IkEv2.exe <target-ip> [port]

When run against a matching target, the binary probes reachability over UDP, sends the crafted fragmented IKEv2 packets to trigger the double-free, performs heap grooming and ROP-chain-based exploitation, and is intended to spawn a reverse shell back to the attacker on port 4444; per the author’s README this end-to-end chain is not fully functional in the current state, and several supporting functions (AMSI/Defender/ETW bypass, environment detection, listener start/stop) may be incomplete or build-dependent.


Detection & Indicators of Compromise

Signs of compromise:

  • Crash or restart of the IKEv2/IPsec service (ikeext.dll/associated service process) correlating with bursts of fragmented IKEv2 packets from an external host.
  • Unexpected outbound TCP connections on port 4444 from a host running the IPsec/IKEv2 service.
  • Presence of unrecognized PE binaries with spoofed protector section names (.vmp0, UPX0, .enigma1, .winlice, etc.) that do not correspond to any actually-applied packer.

Remediation

ActionDetail
Primary fixNo vendor patch confirmed as of 2026-07-05 — monitor Microsoft’s advisory channel for CVE-2026-33824 and apply the corresponding Windows update once released.
Interim mitigationRestrict/firewall UDP/500 (IKEv2) exposure to trusted networks only, disable the IPsec/IKEv2 service on hosts that do not require it, and monitor for anomalous fragmented IKEv2 traffic and unexpected outbound connections on non-standard ports (e.g. 4444).

References


Notes

Mirrored from https://github.com/EpSiLoNPoInTOrI/IKEV2-POC on 2026-07-05. This is a weaponized, advanced Windows kernel exploit (shellcode + reverse shell, with the repo’s own obfuscation/anti-debug/API-hooking layer, including OBFUSCATION_KEY3 and related constants defined in its own correct_code.py). It has been manually reviewed by the archive maintainer and found to contain no hidden malware — the obfuscation is the exploit’s own self-described anti-analysis design, not injected malicious content — but it remains advanced/dangerous, incomplete-per-author-notes code. Review thoroughly before use; do not run casually.

correct_code.py
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#!/usr/bin/env python3
"""
Script pour corriger le code IKEV2-POC selon les spécifications :
1. Corriger la structure IKE_TRANSFORM_PAYLOAD selon RFC 4306
2. Définir OBFUSCATION_KEY3 et autres constantes manquantes
3. Ajouter la sélection user/kernel mode
4. Corriger les erreurs de compilation pour Visual Studio
"""

import re

def corriger_fichier(input_file, output_file):
    with open(input_file, 'r', encoding='utf-8', errors='ignore') as f:
        content = f.read()
    
    # Correction 1: Ajouter la configuration du mode au début
    content = re.sub(
        r'#define _WIN32_WINNT 0x0A00\n#define WINVER 0x0A00\n#define\s+1\s+.*\n\n\n#include <Windows\.h>',
        '''#define _WIN32_WINNT 0x0A00
#define WINVER 0x0A00

// ============================================================================
// CONFIGURATION DU MODE (USER ou KERNEL)
// ============================================================================
// Décommentez la ligne correspondante pour choisir le mode
//#define USER_MODE 1
#define KERNEL_MODE 1

#include <Windows.h>''',
        content,
        count=1
    )
    
    # Correction 2: Ajouter les inclusions nécessaires
    content = re.sub(
        r'#include <iostream>\n\n// ============================================================================',
        '''#include <iostream>

// Inclusions pour le mode User
#include <Winsock2.h>
#include <Ws2tcpip.h>
#include <iphlpapi.h>
#include <bcrypt.h>
#include <wincrypt.h>

// Inclusions pour le mode Kernel
#ifdef KERNEL_MODE
#include <ntddk.h>
#include <ntifs.h>
#include <wdm.h>
#endif

// Déclarations des types et fonctions NT pour éviter les erreurs de compilation
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif

typedef LONG NTSTATUS;
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS 0x00000000
#endif

typedef enum _PROCESSINFOCLASS {
    ProcessBasicInformation = 0,
    ProcessDebugPort = 7,
    ProcessWow64Information = 26,
    ProcessImageFileName = 27,
    ProcessBreakOnTermination = 29
} PROCESSINFOCLASS;

// Déclaration de PROCESS_DEBUG_PORT
typedef struct _PROCESS_DEBUG_PORT {
    HANDLE DebugPort;
} PROCESS_DEBUG_PORT;

// ============================================================================''',
        content,
        count=1
    )
    
    # Correction 3: Définir OBFUSCATION_KEY3 et OBFUSCATION_KEY4
    content = re.sub(
        r'#define OBFUSCATION_KEY1 \(uint8_t\)\(GetTickCount\(\) & 0xFF\)\n#define OBFUSCATION_KEY2 \(uint8_t\)\(\(GetTickCount\(\) >> 8\) & 0xFF\)\n#define RANDOMIZATION_SEED',
        '''// Clés d'obfuscation - CORRIGÉ: Ajout de OBFUSCATION_KEY3 et OBFUSCATION_KEY4
#define OBFUSCATION_KEY1 (uint8_t)(GetTickCount() & 0xFF)
#define OBFUSCATION_KEY2 (uint8_t)((GetTickCount() >> 8) & 0xFF)
#define OBFUSCATION_KEY3 (uint8_t)((GetTickCount() >> 16) & 0xFF)
#define OBFUSCATION_KEY4 (uint8_t)((GetTickCount() >> 24) & 0xFF)
#define RANDOMIZATION_SEED''',
        content,
        count=1
    )
    
    # Correction 4: Ajouter les constantes manquantes DDOS_EXTRA_SIZE et SKF_DDOS_EXTRA_SIZE
    content = re.sub(
        r'#define MAX_CHUNK_SIZE 0x10000\n#define MALFORMED_DATA_SIZE 2048\n#define SKF_FRAGMENTS 4',
        '''#define MAX_CHUNK_SIZE 0x10000
#define MALFORMED_DATA_SIZE 2048
#define DDOS_EXTRA_SIZE 512  // CORRIGÉ: Ajout de la constante manquante
#define SKF_DDOS_EXTRA_SIZE 256  // CORRIGÉ: Ajout de la constante manquante
#define SKF_FRAGMENTS 4''',
        content,
        count=1
    )
    
    # Correction 5: Corriger la structure IKE_TRANSFORM_PAYLOAD selon RFC 4306
    content = re.sub(
        r'typedef struct _IKE_TRANSFORM_PAYLOAD \{\s*uint8_t next_payload;\s*uint8_t critical;\s*uint16_t length;\s*uint8_t transform_type;\s*uint8_t reserved1;\s*uint8_t reserved2;\s*uint16_t transform_id;\s*uint8_t reserved3;\s*uint8_t attributes_len;\s*\} IKE_TRANSFORM_PAYLOAD;',
        '''// Structure corrigée selon RFC 4306 Section 3.3.2
typedef struct _IKE_TRANSFORM_PAYLOAD {
    uint8_t next_payload;    // Next Payload (1 octet)
    uint8_t reserved1;       // Réservé (1 octet) - RFC 4306
    uint16_t length;         // Longueur totale (2 octets)
    uint8_t transform_type;   // Type de transform (1 octet)
    uint8_t reserved2;       // Réservé (1 octet) - RFC 4306
    uint16_t transform_id;    // Identifiant du transform (2 octets)
} IKE_TRANSFORM_PAYLOAD;''',
        content,
        count=1
    )
    
    # Correction 6: Supprimer la ligne problématique "#define  1"
    content = re.sub(r'#define\s+1\s+.*\n', '', content)
    
    # Correction 7: Supprimer les lignes vides en trop au début
    content = re.sub(r'\n\n\n+', '\n\n', content)
    
    # Correction 8: Ajouter les pragma comment pour les bibliothèques à la fin
    if '#pragma comment(lib,' not in content:
        content = content.rstrip() + '''

// ============================================================================
// LINKER DIRECTIVES - Bibliothèques nécessaires pour Visual Studio
// ============================================================================
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "bcrypt.lib")
#pragma comment(lib, "crypt32.lib")
#pragma comment(lib, "Wtsapi32.lib")
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "wininet.lib")
#pragma comment(lib, "Vssapi.lib")
'''
    
    with open(output_file, 'w', encoding='utf-8') as f:
        f.write(content)
    
    print(f"Fichier corrigé sauvegardé dans {output_file}")

if __name__ == '__main__':
    corriger_fichier('IkEv2.cpp', 'IkEv2_corrige.cpp')