Description
Windows Server 2025 introduced optional 32KiB ESE database pages for Active Directory (NTDS.dit). When the "Database 32k pages" forest-level feature is enabled, libesedb fails to correctly parse the database.
Reference: Microsoft: Database 32k pages for Active Directory
Issue 1: Page tag count (available_page_tag) is misread
In the 32KiB page format, the available_page_tag field (uint16) uses a new layout:
- Upper 4 bits:
ctagReserved (reserved bits, should be masked out)
- Lower 12 bits: actual number of page tags
libesedb_page_header_read_data() reads all 16 bits as the tag count. On 32KiB pages this inflates the count, causing out-of-bounds page tag reads and garbage data.
Affected file: libesedb/libesedb_page_header.c (line ~241)
Suggested fix: Mask the upper 4 bits when page_size >= 32768:
if( io_handle->page_size >= 32768 )
{
page_header->available_page_tag &= 0x0fff;
}
Issue 2: Leaf page walk encounters non-leaf pages
In libesedb_page_tree_get_get_first_leaf_page_number() (backward walk) and libesedb_page_tree_get_number_of_leaf_values() (forward walk), the code does not check whether a page in the leaf chain is actually a leaf page. In 32KiB databases, some pages referenced in the chain may be zeroed or non-leaf pages, causing "not a leaf page" errors or incorrect record counts.
Affected file: libesedb/libesedb_page_tree.c (two locations)
Suggested fix: Check LIBESEDB_PAGE_FLAG_IS_LEAF before processing each page and break if the flag is not set.
Environment
- Windows Server 2025 with "Database 32k pages" feature enabled
- NTDS.dit extracted via
ntdsutil IFM
- libesedb version: 20230824
Verification
With both fixes applied, the following was confirmed:
- 8KiB (WS2019) NTDS.dit: 14 tables, 7008 datatable records, 13904 link_table records — no regression
- 32KiB (WS2025) NTDS.dit: 14 tables, 7029 datatable records, 485 link_table records — parsed correctly
I have a patch ready and can submit a PR if you are interested.
Description
Windows Server 2025 introduced optional 32KiB ESE database pages for Active Directory (NTDS.dit). When the "Database 32k pages" forest-level feature is enabled, libesedb fails to correctly parse the database.
Reference: Microsoft: Database 32k pages for Active Directory
Issue 1: Page tag count (available_page_tag) is misread
In the 32KiB page format, the
available_page_tagfield (uint16) uses a new layout:ctagReserved(reserved bits, should be masked out)libesedb_page_header_read_data()reads all 16 bits as the tag count. On 32KiB pages this inflates the count, causing out-of-bounds page tag reads and garbage data.Affected file:
libesedb/libesedb_page_header.c(line ~241)Suggested fix: Mask the upper 4 bits when
page_size >= 32768:Issue 2: Leaf page walk encounters non-leaf pages
In
libesedb_page_tree_get_get_first_leaf_page_number()(backward walk) andlibesedb_page_tree_get_number_of_leaf_values()(forward walk), the code does not check whether a page in the leaf chain is actually a leaf page. In 32KiB databases, some pages referenced in the chain may be zeroed or non-leaf pages, causing "not a leaf page" errors or incorrect record counts.Affected file:
libesedb/libesedb_page_tree.c(two locations)Suggested fix: Check
LIBESEDB_PAGE_FLAG_IS_LEAFbefore processing each page andbreakif the flag is not set.Environment
ntdsutilIFMVerification
With both fixes applied, the following was confirmed:
I have a patch ready and can submit a PR if you are interested.