Out-of-bounds write in ntfs!PageUpdateAnalysis
More in General
- We helped Apple fix a vulnerability in the kernel of its operating systems
We helped Apple fix a vulnerability in the kernel of its operating systems PT ESC expert…
- Your Zimbra server is at risk
Recently, our PT ESC IR team encountered a new attack by ransomware groups on Zimbra mail…
- VMkatz: a hidden threat to virtual infrastructure 🫣
In 2026, a tool called VMkatz was published. In terms of functionality, it resembles the widely…
- ⚠️ Enabled Wi-Fi debugging — got Mamont
⚠️ Turned on Wi-Fi debugging — got Mamont In early May, a vulnerability CVE-2026-0073 was discovered…
- Dirty Frag 🐧
Dirty Frag 🐧💥 A week after the widely discussed Copy.Fail, researcher v4bel disclosed a new privilege…
| BDU | PT | CVE |
|---|---|---|
| 2025-12465 | 2026-2690 | 2026-20840 |
Summary
A heap buffer overflow vulnerability exists in the ntfs!PageUpdateAnalysis function of the Microsoft Windows NTFS driver. A specially crafted NTFS volume can cause an out-of-bounds write into kernel NonPagedPoolNx memory during log recovery. An attacker can trigger this vulnerability by causing an affected Windows system to mount a volume containing malicious $LogFile records. The resulting kernel memory corruption may lead to denial of service, privilege escalation, or arbitrary kernel code execution.
Confirmed Vulnerable Versions
ntfs.sys.10.0.22621.5037
Product URLs
Microsoft Windows — https://www.microsoft.com/windows
CWE
CWE-787 — Out-of-bounds Write
Details
NTFS is the primary file system used by Microsoft Windows. Its metadata journal, $LogFile, contains records used to restore file system consistency after interrupted operations.
ntfs!AnalysisPass implements the analysis phase of NTFS restart recovery, preceding the redo and undo phases. It scans log records from the most recent checkpoint and reconstructs recovery state, including transaction and dirty page tables. These tables track outstanding transactions and metadata pages whose updates may not have reached disk, allowing subsequent recovery phases to determine which operations require replay or rollback.
ntfs!PageUpdateAnalysis processes page-update records during this analysis phase. The mount stack context is:
0: kd> k
# Child-SP RetAddr Call Site
00 ffffcd8a`59bc5e08 fffff804`27ae0f6f Ntfs!PageUpdateAnalysis
01 ffffcd8a`59bc5e10 fffff804`27b45000 Ntfs!AnalysisPass+0x22b
02 ffffcd8a`59bc5f30 fffff804`27acc3be Ntfs!NtfsRestartVolume+0xbc
03 ffffcd8a`59bc60a0 fffff804`27ac9f86 Ntfs!NtfsMountVolume+0x1816
04 ffffcd8a`59bc67e0 fffff804`2793e639 Ntfs!NtfsCommonFileSystemControl+0xb6
05 ffffcd8a`59bc68c0 fffff804`9478b7ec Ntfs!NtfsFspDispatch+0x619
06 ffffcd8a`59bc6a10 fffff804`94931afa nt!ExpWorkerThread+0x5ec
07 ffffcd8a`59bc6bf0 fffff804`94b4ef84 nt!PspSystemThreadStartup+0x5a
08 ffffcd8a`59bc6c40 00000000`00000000 nt!KiStartSystemThread+0x34
NTFS stores dirty page entries in a flat RESTART_TABLE allocation in NonPagedPoolNx. Each entry contains an array of logical cluster numbers (LCNs), with capacity determined by the entry size:
DIRTY_PAGE_ENTRY (simplified):
+0x00 AllocatedMarker DWORD (-1 indicates an in-use entry)
+0x04 TargetAttribute USHORT
+0x08 LengthOfTransfer ULONG
+0x0C LcnsToFollow ULONG
+0x10 StartingVcn 8-byte virtual cluster number
+0x18 OldestLsn 8-byte log sequence number
+0x20 LcnsForPage[] Array of 8-byte LCN values
Table allocation is performed during ntfs!InitializeRestartState when DirtyPageTable is loaded from the image.
In ntfs!PageUpdateAnalysis, after ntfs!FindDirtyPage returns an existing entry, ntfs!PageUpdateAnalysis copies LCN values from the incoming log record into that entry.
// ntfs!PageUpdateAnalysis
if ( !FindDirtyPage(a4, (unsigned __int16)CurrentLogRecord->TargetAttribute, CurrentLogRecord->TargetVcn, &v20) ) {
... // entry not found
}
while ( 1 ) {
result = (unsigned __int16)CurrentLogRecord->LcnsToFollow;
if ( v8 >= (unsigned int)result ) // v8 is i
break;
v20->LcnsForPage[LODWORD(CurrentLogRecord->TargetVcn) + v8 - LODWORD(v20->Vcn)] = CurrentLogRecord->LcnsForPage[v8];
++v8;
}
return result;
The analyzed binary contains the following code corresponding to the decompiled listing that you can see above:
1c025844c cmp esi, eax
1c025844e jnb loc_1C025846F
1c0258455 mov rdx, [rsp+...] ; DirtyPage entry
1c025845a sub ecx, [rdx+10h] ; subtract StartingVcn, low 32 bits
1c025845d add ecx, [r13+18h] ; add TargetVcn, low 32 bits
1c0258461 mov rax, [r13+r8*8+20h] ; LogRecord->LcnsForPage[i]
1c0258466 mov [rdx+rcx*8+20h], rax ; unchecked destination write
1c025846b inc esi
1c025846d jmp short loc_1C0258447
The effective destination index is calculated using 32-bit arithmetic:
Index = i + TargetVcn - StartingVcn
ntfs!FindDirtyPage matches an entry when StartingVcn <= TargetVcn < StartingVcn + LcnsToFollow:
char __fastcall FindDirtyPage(
My_RESTART_POINTERS *a1,
int TargetAttribute,
signed __int64 Vcn,
My_DIRTY_PAGE_ENTRY **DirtyPage)
{
My_DIRTY_PAGE_ENTRY *i; // rax
__int64 v9; // rdx
if ( !a1->Table )
return 0;
for ( i = (My_DIRTY_PAGE_ENTRY *)NtfsGetFirstRestartTable(a1);
;
i = (My_DIRTY_PAGE_ENTRY *)NtfsGetNextRestartTable((__int64)a1, (__int64)i) )
{
if ( !i )
{
*DirtyPage = 0LL;
return 0;
}
if ( i->TargetAttribute == TargetAttribute )
{
v9 = i->Vcn; // v9 is a starting VCN
if ( Vcn >= v9 && Vcn < v9 + (unsigned int)i->LcnsToFollow )
break;
}
}
*DirtyPage = i;
return 1;
}
This establishes that the starting cluster lies within the entry, but does not establish that the complete incoming range fits. For TargetVcn = StartingVcn + k, the loop writes to indices k through k + LcnsToFollow - 1. The array overflows when:
k + LcnsToFollow > ClustersPerPage
The resize check in ntfs!PageUpdateAnalysis only considers whether LcnsToFollow > ClustersPerPage. It does not account for the destination offset k. Consequently, a record whose LCN count fits the nominal capacity can still overflow the destination array.
// ntfs!PageUpdateAnalysis
...
if ( Table ) {
ClustersPerPage = (((unsigned __int64)(unsigned __int16)Table->EntrySize - 40) >> 3) + 1;
}
else {
ClustersPerPage = a2->ClustersPerPage;
NtfsInitializeRestartTable(8 * ClustersPerPage + 32, 0x20u, a2->RestartVersion >= 2u, 0, a4);
}
LcnsToFollow = (unsigned __int16)CurrentLogRecord->LcnsToFollow;
if ( LcnsToFollow > ClustersPerPage ) {
ClustersPerPage = (unsigned __int16)CurrentLogRecord->LcnsToFollow;
NtfsInitializeRestartTable(
8 * LcnsToFollow + 32,
(unsigned __int16)a4->Table->NumberEntries,
a2->RestartVersion >= 2u,
0,
&Resource); // resize
...
}
...
No destination bounds check precedes the write, either in the ntfs!PageUpdateAnalysis function or in ntfs!InitializeRestartState. Incidentally, ntfs!InitializeRestartState accepts DirtyPageTable data as is when the MajorVersion of $LogFile is not zero.
// ntfs!InitializeRestartState
...
if ( RestartArea->DirtyPageTableLength )
{
restarted = (My_RESTART_TABLE *)ReadRestartTable(
IrpContext,
Vcb,
RestartArea->DirtyPageTableLsn,
&Leb,
&RestartAreaLength);
ExAcquireResourceExclusiveLite(&DirtyPageTable->Resource, 1u);
v80 = 1;
Table = DirtyPageTable->Table;
if ( RestartArea->MajorVersion ) // MajorVersion check
{
ExFreePoolWithTag(DirtyPageTable->Table, 0);
DirtyPageTable->Table = 0;
v26 = RestartAreaLength;
v27 = (My_RESTART_TABLE *)ExAllocatePoolWithTag((POOL_TYPE)528, RestartAreaLength, 'RFtN');
DirtyPageTable->Table = v27;
memmove(v27, restarted, v26); // data from image has been accepted here
DirtyPageTable->Table->field_A = DirtyPageTable->Table->NumberAllocated;
ExAcquireResourceExclusiveLite(&DirtyPageTable->Resource, 1u);
v80 = 1;
LODWORD(restarted) = 0;
}
else
{
...
}
...
}
Proof of Concept
When the crafted volume is mounted, NTFS performs the following operations:
ntfs!InitializeRestartStatereads the serializedDirtyPageTablefrom$LogFile.- Because the restart area has a nonzero
MajorVersion, the complete table is copied into a newly allocatedNonPagedPoolNxbuffer. ntfs!AnalysisPassbegins scanning at the crafted checkpoint.- The next record is the crafted
UpdateResidentValuerecord. - The incoming
LcnsToFollowvalue is 8, equal toClustersPerPage, so the table-resizing path is not taken. ntfs!PageUpdateAnalysiscallsntfs!FindDirtyPagewithTargetAttribute = 0x18andTargetVcn = 7.ntfs!FindDirtyPageselects slot 31 because its range is[0, 8)and therefore contains VCN 7.- The vulnerable copy writes the eight supplied LCN values beginning at destination index seven.
The PoC crafts restart area uses MajorVersion = 2. This causes Ntfs!InitializeRestartState to allocate a buffer for the serialized DirtyPageTable and copy the table from the image without rebuilding its entries.
The PoC creates a RESTART_TABLE with the following properties:
EntrySize = 0x60
NumberEntries = 32
NumberAllocated = 32
Each entry contains eight LCN slots:
EntrySize = 0x20 + 8 * sizeof(LCN)
= 0x20 + 8 * 8
= 0x60
All 32 entries are marked as allocated, preventing ntfs!PageUpdateAnalysis from selecting or creating a free slot. Entries zero through 30 use distinct VCN ranges that do not match the triggering record. The final entry, slot 31, is configured as follows:
AllocatedMarker = 0xffffffff
TargetAttribute = 0x18
LengthOfTransfer = 0x1000
StartingVcn = 0
LcnsToFollow = 8
LcnsForPage = {1, 2, 3, 4, 5, 6, 7, 8}
Because slot 31 is the final entry, data written beyond its LCN array also extends beyond the complete RESTART_TABLE allocation. The table allocation has the following size:
sizeof(RESTART_TABLE) + NumberEntries * EntrySize
= 0x18 + 32 * 0x60
= 0xc18 (3096 bytes)
On the snippet below you may see how DirtyPageTable is initialized in runtime as well as part of data corresponded to layout described above.
0: kd> p
rax=0000000000000001 rbx=ffffe180efdf0200 rcx=ffffe180efdefaa8
rdx=0000000000000000 rsi=ffff8f8d3514b7c8 rdi=ffffe180efdeff90
rip=fffff80628a95792 rsp=ffffe180efdefb70 rbp=ffffe180efdf08f0
r8=ffff8f8d385def01 r9=ffff8f8d385deae0 r10=0000000000000000
r11=ffffe180efdefb68 r12=ffffe180efdefe00 r13=0000000000000000
r14=0000000000000001 r15=ffff8f8d357c81b0
iopl=0 nv up ei pl zr na pe nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00040246
Ntfs!InitializeRestartState+0x51e:
fffff806`28a95792 4539542438 cmp dword ptr [r12+38h],r10d ds:002b:ffffe180`efdefe38=00000c18
...
1: kd> p
rax=0000000000000000 rbx=0000000000000c18 rcx=0000000000000210
rdx=0000000000000c18 rsi=ffff8f8d3514b7c8 rdi=ffffe180efdeff90
rip=fffff80628a95942 rsp=ffffe180efdefb70 rbp=ffffe180efdf08f0
r8=000000005246744e r9=0000000000000000 r10=0000000000000000
r11=0000000000000001 r12=ffffe180efdefe00 r13=ffffcd0fd11c0158
r14=0000000000000001 r15=ffff8f8d357c81b0
iopl=0 nv up ei pl zr na pe nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00040246
Ntfs!InitializeRestartState+0x6ce:
fffff806`28a95942 48ff158f0ae7ff call qword ptr [Ntfs!_imp_ExAllocatePoolWithTag (fffff806`289063d8)]
...
1: kd> p
rax=ffff8f8d385d03e0 rbx=0000000000000c18 rcx=ffff8f8d385d03e0
rdx=ffffcd0fd11c0158 rsi=ffff8f8d3514b7c8 rdi=ffffe180efdeff90
rip=fffff80628a9595e rsp=ffffe180efdefb70 rbp=ffffe180efdf08f0
r8=0000000000000c18 r9=0000000000000080 r10=0000000000000000
r11=ffffe180efdefae0 r12=ffffe180efdefe00 r13=ffffcd0fd11c0158
r14=0000000000000001 r15=ffff8f8d357c81b0
iopl=0 nv up ei ng nz na pe nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00040286
Ntfs!InitializeRestartState+0x6ea:
fffff806`28a9595e e8ddf1e1ff call Ntfs!memcpy (fffff806`288b4b40)
1: kd> db ffffcd0fd11c0158
ffffcd0f`d11c0158 60 00 20 00 20 00 00 00-00 00 00 00 00 00 00 00 `. . ...........
ffffcd0f`d11c0168 00 00 00 00 00 00 00 00-ff ff ff ff 18 00 00 00 ................
ffffcd0f`d11c0178 00 10 00 00 08 00 00 00-00 10 00 00 00 00 00 00 ................
ffffcd0f`d11c0188 2b 94 a8 00 00 00 00 00-01 00 00 00 00 00 00 00 +...............
ffffcd0f`d11c0198 02 00 00 00 00 00 00 00-03 00 00 00 00 00 00 00 ................
ffffcd0f`d11c01a8 04 00 00 00 00 00 00 00-05 00 00 00 00 00 00 00 ................
ffffcd0f`d11c01b8 06 00 00 00 00 00 00 00-07 00 00 00 00 00 00 00 ................
ffffcd0f`d11c01c8 08 00 00 00 00 00 00 00-ff ff ff ff 18 00 00 00 ................
The triggering record uses the UpdateResidentValue redo operation, which is dispatched to ntfs!PageUpdateAnalysis:
RedoOperation = 0x07
UndoOperation = 0x02
TargetAttribute = 0x18
TargetVcn = 7
LcnsToFollow = 8
ClientDataLength = 0x60
1: kd> p
rax=ffff8f8d356279e8 rbx=0000000000a8942b rcx=0000000000000000
rdx=ffff8f8d356279e8 rsi=ffff8f8d357c85d8 rdi=00000000000000e0
rip=fffff80628a30f1c rsp=ffffe180efdefe10 rbp=ffffe180efdf08f0
r8=ffffffffffffff01 r9=ffff8f8d35625000 r10=0000000000000001
r11=ffff8f8d356279b8 r12=ffffe180efdeff90 r13=ffff8f8d357c81b0
r14=ffff8f8d3514b7c8 r15=ffffcd0fd11ca188
iopl=0 nv up ei pl nz na po nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00040202
Ntfs!AnalysisPass+0x1d8:
fffff806`28a30f1c 410fb70f movzx ecx,word ptr [r15] ds:002b:ffffcd0f`d11ca188=0007
1: kd> p
rax=ffff8f8d356279e8 rbx=0000000000a8942b rcx=0000000000000007
rdx=ffff8f8d356279e8 rsi=ffff8f8d357c85d8 rdi=00000000000000e0
rip=fffff80628a30f20 rsp=ffffe180efdefe10 rbp=ffffe180efdf08f0
r8=ffffffffffffff01 r9=ffff8f8d35625000 r10=0000000000000001
r11=ffff8f8d356279b8 r12=ffffe180efdeff90 r13=ffff8f8d357c81b0
r14=ffff8f8d3514b7c8 r15=ffffcd0fd11ca188
iopl=0 nv up ei pl nz na po nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00040202
Ntfs!AnalysisPass+0x1dc:
fffff806`28a30f20 83f912 cmp ecx,12h
... // some optimized switch-case related code is here
0: kd> p
rax=ffff8f8d356279e8 rbx=0000000000a8942b rcx=ffff8f8d3514b7c8
rdx=ffff8f8d357c81b0 rsi=ffff8f8d357c85d8 rdi=00000000000000e0
rip=fffff80628a30f6a rsp=ffffe180efdefe10 rbp=ffffe180efdf08f0
r8=0000000000a8942b r9=ffffe180efdeff90 r10=0000000000000001
r11=ffff8f8d356279b8 r12=ffffe180efdeff90 r13=ffff8f8d357c81b0
r14=ffff8f8d3514b7c8 r15=ffffcd0fd11ca188
iopl=0 nv up ei pl zr na pe nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00040246
Ntfs!AnalysisPass+0x226:
fffff806`28a30f6a e8f1080000 call Ntfs!PageUpdateAnalysis (fffff806`28a31860)
The destination indices are calculated as follows:
Index = i + TargetVcn - StartingVcn = i + 7 - 0 = i + 7
For i = 0..7, the resulting indices are:
7, 8, 9, 10, 11, 12, 13, 14
Index seven is the final valid element. Indices eight through fourteen are outside the entry:
Because the selected entry is slot 31, these seven LCN values extend 56 bytes beyond the end of the complete 3096 byte restart-table allocation.
1: kd> p
rax=0000000000000008 rbx=0000000000a8942b rcx=0000000000000008
rdx=0000000000000001 rsi=0000000000000002 rdi=0000000000000008
rip=fffff80628a3198f rsp=ffffe180efdefc90 rbp=ffffe180efdf08f0
r8=00000000385d03e0 r9=00000000385d03e0 r10=ffff8f8d385d0f98
r11=0000000000000007 r12=0000000000000018 r13=ffffcd0fd11ca188
r14=ffff8f8d385d03e0 r15=ffffe180efdeff90
iopl=0 nv up ei ng nz ac pe cy
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00040297
Ntfs!PageUpdateAnalysis+0x12f:
fffff806`28a3198f 8bd6 mov edx,esi
1: kd> p
rax=0000000000000008 rbx=0000000000a8942b rcx=0000000000000008
rdx=0000000000000002 rsi=0000000000000002 rdi=0000000000000008
rip=fffff80628a31991 rsp=ffffe180efdefc90 rbp=ffffe180efdf08f0
r8=00000000385d03e0 r9=00000000385d03e0 r10=ffff8f8d385d0f98
r11=0000000000000007 r12=0000000000000018 r13=ffffcd0fd11ca188
r14=ffff8f8d385d03e0 r15=ffffe180efdeff90
iopl=0 nv up ei ng nz ac pe cy
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00040297
Ntfs!PageUpdateAnalysis+0x131:
fffff806`28a31991 8bce mov ecx,esi
1: kd> p
rax=0000000000000008 rbx=0000000000a8942b rcx=0000000000000002
rdx=0000000000000002 rsi=0000000000000002 rdi=0000000000000008
rip=fffff80628a31993 rsp=ffffe180efdefc90 rbp=ffffe180efdf08f0
r8=00000000385d03e0 r9=00000000385d03e0 r10=ffff8f8d385d0f98
r11=0000000000000007 r12=0000000000000018 r13=ffffcd0fd11ca188
r14=ffff8f8d385d03e0 r15=ffffe180efdeff90
iopl=0 nv up ei ng nz ac pe cy
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00040297
Ntfs!PageUpdateAnalysis+0x133:
fffff806`28a31993 412b4a10 sub ecx,dword ptr [r10+10h] ds:002b:ffff8f8d`385d0fa8=00000000 // StartingVCN
1: kd> p
rax=0000000000000008 rbx=0000000000a8942b rcx=0000000000000002
rdx=0000000000000002 rsi=0000000000000002 rdi=0000000000000008
rip=fffff80628a31997 rsp=ffffe180efdefc90 rbp=ffffe180efdf08f0
r8=00000000385d03e0 r9=00000000385d03e0 r10=ffff8f8d385d0f98
r11=0000000000000007 r12=0000000000000018 r13=ffffcd0fd11ca188
r14=ffff8f8d385d03e0 r15=ffffe180efdeff90
iopl=0 nv up ei pl nz na po nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00040202
Ntfs!PageUpdateAnalysis+0x137: // actually it is i (index) + TargetVCN
fffff806`28a31997 41034d18 add ecx,dword ptr [r13+18h] ds:002b:ffffcd0f`d11ca1a0=00000007 // TargetVCN
1: kd> p
rax=0000000000000008 rbx=0000000000a8942b rcx=0000000000000009
rdx=0000000000000002 rsi=0000000000000002 rdi=0000000000000008
rip=fffff80628a3199b rsp=ffffe180efdefc90 rbp=ffffe180efdf08f0
r8=00000000385d03e0 r9=00000000385d03e0 r10=ffff8f8d385d0f98
r11=0000000000000007 r12=0000000000000018 r13=ffffcd0fd11ca188
r14=ffff8f8d385d03e0 r15=ffffe180efdeff90
iopl=0 nv up ei pl nz na pe nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00040206
Ntfs!PageUpdateAnalysis+0x13b: // read data that comes from image
fffff806`28a3199b 498b44d520 mov rax,qword ptr [r13+rdx*8+20h] ds:002b:ffffcd0f`d11ca1b8=4141414100000002
1: kd> p
rax=4141414100000002 rbx=0000000000a8942b rcx=0000000000000009 // rcx is i (index)
rdx=0000000000000002 rsi=0000000000000002 rdi=0000000000000008
rip=fffff80628a319a0 rsp=ffffe180efdefc90 rbp=ffffe180efdf08f0
r8=00000000385d03e0 r9=00000000385d03e0 r10=ffff8f8d385d0f98
r11=0000000000000007 r12=0000000000000018 r13=ffffcd0fd11ca188
r14=ffff8f8d385d03e0 r15=ffffe180efdeff90
iopl=0 nv up ei pl nz na pe nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00040206
Ntfs!PageUpdateAnalysis+0x140:
fffff806`28a319a0 498944ca20 mov qword ptr [r10+rcx*8+20h],rax ds:002b:ffff8f8d`385d1000=????????????????
Mounting the generated VHD on a system using the affected ntfs.sys reaches the unchecked write in Ntfs!PageUpdateAnalysis:
1: kd> !analyze -v -force
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************
PAGE_FAULT_IN_NONPAGED_AREA (50)
Invalid system memory was referenced. This cannot be protected by try-except.
Typically the address is just plain bad or it is pointing at freed memory.
Arguments:
Arg1: ffff8f8d385d1000, memory referenced.
Arg2: 0000000000000002, X64: bit 0 set if the fault was due to a not-present PTE.
bit 1 is set if the fault was due to a write, clear if a read.
bit 3 is set if the processor decided the fault was due to a corrupted PTE.
bit 4 is set if the fault was due to attempted execute of a no-execute PTE.
- ARM64: bit 1 is set if the fault was due to a write, clear if a read.
bit 3 is set if the fault was due to attempted execute of a no-execute PTE.
Arg3: fffff80628a319a0, If non-zero, the instruction address which referenced the bad memory
address.
Arg4: 0000000000000002, (reserved)
Debugging Details:
------------------
KEY_VALUES_STRING: 1
Key : AV.PTE
Value: Invalid
Key : AV.Page.Virtual
Value: 0xffff8f8d385d0000
Key : AV.Type
Value: Write
Key : Analysis.CPU.mSec
Value: 4500
Key : Analysis.Elapsed.mSec
Value: 9710
Key : Analysis.IO.Other.Mb
Value: 14
Key : Analysis.IO.Read.Mb
Value: 15
Key : Analysis.IO.Write.Mb
Value: 201
Key : Analysis.Init.CPU.mSec
Value: 97484
Key : Analysis.Init.Elapsed.mSec
Value: 11291658
Key : Analysis.Memory.CommitPeak.Mb
Value: 265
Key : Analysis.Version.DbgEng
Value: 10.0.29617.1000
Key : Analysis.Version.Description
Value: 10.2604.29.1 amd64fre
Key : Analysis.Version.Ext
Value: 1.2604.29.1
Key : Bugcheck.Code.KiBugCheckData
Value: 0x50
Key : Bugcheck.Code.LegacyAPI
Value: 0x50
Key : Bugcheck.Code.TargetModel
Value: 0x50
Key : Failure.Bucket
Value: AV_VRF_Ntfs!PageUpdateAnalysis
Key : Failure.Exception.IP.Address
Value: 0xfffff80628a319a0
Key : Failure.Exception.IP.Module
Value: Ntfs
Key : Failure.Exception.IP.Offset
Value: 0x1d19a0
Key : Failure.Hash
Value: {9d54520b-212c-9f3b-ad4b-052c7a9e7f7e}
Key : Faulting.IP.Type
Value: Paged
Key : Hypervisor.Enlightenments.Value
Value: 1113060
Key : Hypervisor.Enlightenments.ValueHex
Value: 0x10fbe4
Key : Hypervisor.Flags.AnyHypervisorPresent
Value: 1
Key : Hypervisor.Flags.ApicEnlightened
Value: 0
Key : Hypervisor.Flags.ApicVirtualizationAvailable
Value: 0
Key : Hypervisor.Flags.AsyncMemoryHint
Value: 0
Key : Hypervisor.Flags.CoreSchedulerRequested
Value: 0
Key : Hypervisor.Flags.CpuManager
Value: 0
Key : Hypervisor.Flags.DeprecateAutoEoi
Value: 1
Key : Hypervisor.Flags.DynamicCpuDisabled
Value: 1
Key : Hypervisor.Flags.Epf
Value: 0
Key : Hypervisor.Flags.ExtendedProcessorMasks
Value: 1
Key : Hypervisor.Flags.HardwareMbecAvailable
Value: 0
Key : Hypervisor.Flags.MaxBankNumber
Value: 0
Key : Hypervisor.Flags.MemoryZeroingControl
Value: 0
Key : Hypervisor.Flags.NoExtendedRangeFlush
Value: 0
Key : Hypervisor.Flags.NoNonArchCoreSharing
Value: 0
Key : Hypervisor.Flags.Phase0InitDone
Value: 1
Key : Hypervisor.Flags.PowerSchedulerQos
Value: 0
Key : Hypervisor.Flags.RootScheduler
Value: 0
Key : Hypervisor.Flags.SynicAvailable
Value: 1
Key : Hypervisor.Flags.UseQpcBias
Value: 0
Key : Hypervisor.Flags.Value
Value: 528572
Key : Hypervisor.Flags.ValueHex
Value: 0x810bc
Key : Hypervisor.Flags.VpAssistPage
Value: 1
Key : Hypervisor.Flags.VsmAvailable
Value: 0
Key : Hypervisor.RootFlags.AccessStats
Value: 0
Key : Hypervisor.RootFlags.CrashdumpEnlightened
Value: 0
Key : Hypervisor.RootFlags.CreateVirtualProcessor
Value: 0
Key : Hypervisor.RootFlags.DisableHyperthreading
Value: 0
Key : Hypervisor.RootFlags.HostTimelineSync
Value: 0
Key : Hypervisor.RootFlags.HypervisorDebuggingEnabled
Value: 0
Key : Hypervisor.RootFlags.IsHyperV
Value: 0
Key : Hypervisor.RootFlags.LivedumpEnlightened
Value: 0
Key : Hypervisor.RootFlags.MapDeviceInterrupt
Value: 0
Key : Hypervisor.RootFlags.MceEnlightened
Value: 0
Key : Hypervisor.RootFlags.Nested
Value: 0
Key : Hypervisor.RootFlags.StartLogicalProcessor
Value: 0
Key : Hypervisor.RootFlags.Value
Value: 0
Key : Hypervisor.RootFlags.ValueHex
Value: 0x0
Key : SecureKernel.HalpHvciEnabled
Value: 0
Key : WER.OS.Branch
Value: ge_release
Key : WER.OS.Version
Value: 10.0.26100.1
BUGCHECK_CODE: 50
BUGCHECK_P1: ffff8f8d385d1000
BUGCHECK_P2: 2
BUGCHECK_P3: fffff80628a319a0
BUGCHECK_P4: 2
FAULTING_THREAD: ffff8f8d2e595040
EXCEPTION_PARAMETER1: 0000000000000001
EXCEPTION_PARAMETER2: ffff8f8d385d1000
WRITE_ADDRESS: ffff8f8d385d1000 Special pool
MM_INTERNAL_CODE: 2
PROCESS_NAME: System
IP_IN_PAGED_CODE:
Ntfs!PageUpdateAnalysis+140
fffff806`28a319a0 498944ca20 mov qword ptr [r10+rcx*8+20h],rax
The following exploitation is trivial.
Disclosure Timeline
- September 23, 2025 The vendor was notified of the vulnerability and provided with a technical report.
- September 25, 2025 The vendor completed its internal triage and confirmed the vulnerability. Preliminary timelines for the fix and advisory were provided.
- September 26, 2025 The vendor was notified of the planned public disclosure.
- January 13, 2026 Security updates were released and the advisory was published.
More in General
- We helped Apple fix a vulnerability in the kernel of its operating systems
We helped Apple fix a vulnerability in the kernel of its operating systems PT ESC expert…
- Your Zimbra server is at risk
Recently, our PT ESC IR team encountered a new attack by ransomware groups on Zimbra mail…
- VMkatz: a hidden threat to virtual infrastructure 🫣
In 2026, a tool called VMkatz was published. In terms of functionality, it resembles the widely…
- ⚠️ Enabled Wi-Fi debugging — got Mamont
⚠️ Turned on Wi-Fi debugging — got Mamont In early May, a vulnerability CVE-2026-0073 was discovered…
- Dirty Frag 🐧
Dirty Frag 🐧💥 A week after the widely discussed Copy.Fail, researcher v4bel disclosed a new privilege…







