• CVE-2023-32019 – a bit more info from the researcher

    Home » Forums » Cyber Security Information and Advisories » Cyber Security for Business users » CVE-2023-32019 – a bit more info from the researcher

    Author
    Topic
    #2577309

    Background:  KB5028407: How to manage the vulnerability associated with CVE-2023-32019 – Microsoft Support
    CVE-2023-32019 – Security Update Guide – Microsoft – Windows Kernel Information Disclosure Vulnerability

    There has been little to no info about CVE-2023-32019 other than a cryptic KB indicating that the change would be implemented over time and that if we did the manual registry change there would be a “breaking change” with NO details about what we’re supposed to look for.

    The registry changes are almost but not quite PER OS so that you have to apply a different reg key depending on the OS you are protecting.

    As an aside there is a helpful post here of what can be done to push this out

    Managing the Registry Settings for CVE-2023-32019 (KB5028407) | AJF8729

    In googling around I find that there is little info about this (this is actually a good thing considering there is no good side effect info out there and we’re coming up two months after the patch was released) but this NVD – CVE-2023-32019 (nist.gov) indicates that it’s been recently updated and points to Windows Kernel KTM Registry Transactions Non-Atomic Outcomes ˜ Packet Storm (packetstormsecurity.com)  Downloading this to a standalone PC and unzipping it there is an advisory-info.text file which includes the information below:

    Windows Kernel KTM registry transactions may have non-atomic outcomes

    Since Windows Vista, the Windows operating system supports Transacted Registry (sometimes abbreviated as TxR) with the help of a dedicated kernel subsystem called the Kernel Transaction Manager (KTM). Thanks to this feature, user-mode applications may operate on the registry in a transacted way, through a combination of KTM-specific (CreateTransaction, CommitTransaction, RollbackTransaction) and dedicated registry functions (RegCreateKeyTransacted, RegOpenKeyTransacted, RegDeleteKeyTransacted). The point of the transactions is typical: to bundle a number of operations together and guarantee that either none of them (in case of a rollback) or all of them are applied (in case of a successful commit). Atomicity lies at the foundation of reliable transaction systems, and it is our impression that it is also guaranteed for registry transactions, based on the available documentation.

    However, due to some design problems in how transactions are implemented in the registry, it is possible for a low-privileged local attacker to force a non-atomic (i.e. partial success) outcome of a transaction used by another high-privileged process in the system (a system service, or a program run by an administrator). Furthermore, while the transaction is only partially committed, the client is wrongly informed that the commit has fully succeeded (i.e. CommitTransaction returns TRUE), which in our opinion breaks the API contract and may cause further bugs in the privileged process, by creating a discrepancy between the expected and actual state of the registry. Given that the registry is a shared, securable resource used to store secrets, configuration and other sensitive information, we assess that the issue has security implications (e.g. by preventing a restrictive security descriptor from being set on a registry key), and may potentially lead to information disclosure or even local privilege escalation.

    In the sections below, we discuss the implementation details of KTM-based TxR, the design issues we have identified, and their impact on system security.

    ========== A primer on registry OOM conditions ==========

    The underlying primitive that enables many potential attacks on the Windows registry is the ability to trigger out-of-memory (OOM) conditions. We collectively refer to such situations as OOMs, but they are not only limited to exhausting the virtual/physical memory address space, but also include the limitations of the hive space, which has much stricter constraints. By causing internal registry allocation functions (e.g. HvAllocateCell, HvReallocateCell, CmpAllocate) to fail, it is possible to get the kernel to execute error handling code paths that are otherwise rarely exercised. While in theory every such code path should restore the registry to a consistent state, as this report shows, that is not always the case.

    We have found two ways to trigger OOMs in the Windows registry code. The first one is to fill the hive that we are targeting up to its size limit, which is 2 GiB. This can be achieved by creating a large number of long values in a key that the user has write-access to. When filling up the ‘volatile’ hive storage space, this consumes 2 GiB of memory; for the ‘stable’ storage, it also entails writing that much data to disk. Once this is achieved, the hive becomes virtually non-writable for any of its clients, which for global hives (such as HKLM\\SOFTWARE or HKLM\\SYSTEM) means all system users and services – at least until the long values are not deleted.

    As noted in the previous paragraph, a single world-writable key within a hive is sufficient to allow anyone in the system to fill up that hive completely. And indeed, such keys with permissive access rights do exist in the two most popular system hives in a default installation, for example:

    1. For HKLM\\SOFTWARE: HKLM\\SOFTWARE\\Microsoft\\DRM

    2. For HKLM\\SYSTEM: HKLM\\SYSTEM\\CurrentControlSet\\Control\\Network\\NetworkLocationWizard

    We find this to be an inherent weakness of the Windows registry implementation, as it trivially enables a local DoS by globally blocking write access to important system hives for everyone in the system. It could also potentially serve as a side channel to try to leak the time and size of operations performed by other users of the hive. Lastly, as we’ll see in the next section, it is also useful for breaking KTM registry transactions.

    The second way to trigger registry OOMs is through the global registry quota. This is the maximum number of bytes that can be allocated for all active hives at any point of the system runtime. It is enforced by the internal CmpClaimGlobalQuota function, as called by CmpAllocate and a few other routines. At any point in time, the current registry-related memory consumption is stored in the CmpGlobalQuotaUsed global variable, while the maximum allowed quota is in CmpGlobalQuotaAllowed. The quota is generally determined by two functions: CmpInitGlobalQuotaAllowed and CmpUpdateGlobalQuotaAllowed. According to our analysis and some manual experimentation, the quota is set to one-third of the paged pool size (MmSizeOfPagedPoolInBytes), but also has a lower bound of 16 MiB and an upper bound of 4 GiB.

    In practice, this means that the sum of all hives loaded in the system at the same time is capped at 4 GiB. Such a limit is probably sufficient for normal system operation, but in adverse conditions, a local attacker can for example load or dynamically create two maxed-out 2 GiB hives (which can be app hives, too) and reach the global quota. This again effectively blocks the ability to write to registry by other users (including loading new ones, e.g. the ntuser.dat hive when logging in), but in this case not to just one hive, but all of them loaded in the system. This technique can also be used to interfere with the commit phase of other users’ KTM transactions.

    ========== KTM transaction design problems ==========

    The most important registry operations that can be performed within a transaction are to create/delete/rename a key, to set/delete a value, and to set a security descriptor. In order to make use of transactions, a client program creates a transaction with a CreateTransaction API call, opens one or more keys transactionally via RegCreateKeyTransacted/RegOpenKeyTransacted, performs the desired operations on the keys with standard registry APIs (with the exception of deletion which has its own dedicated function), and finally calls CommitTransaction() to have all of the changes collectively applied. Here, we are primarily interested in what happens in the kernel during the last call.

    Internally, the kernel registers the CmKtmNotification callback function for every hive that has KTM transactions enabled (typically every hive other than app hives). KTM then invokes the callback for every enlistment being part of the committed transaction, first with a TRANSACTION_NOTIFY_PREPARE and then a TRANSACTION_NOTIFY_COMMIT notification type. The ‘Prepare’ phase is handled by the CmpTransMgrPrepare function, while the ‘Commit’ phase is implemented in CmpTransMgrCommit. It is important to note that the two phases exist in accordance with the KTM design, but the Configuration Manager (internal name for the registry subsystem) doesn’t seem to use their full potential. Instead, all of the heavy lifting is done during the ‘Commit’ phase, by the following set of functions:

    +– CmpTransMgrCommit

    |

    +-+– CmpTransMgrCommitUoW

    |

    +-+– CmpCommitAddKeyUoW

    +– CmpCommitDeleteKeyUoW

    +– CmpCommitRenameKeyUoW

    +– CmpCommitSetValueKeyUoW

    +– CmpCommitDeleteValueKeyUoW

    +– CmpCommitSetSecurityUoW

    We now get to the interesting part: each of the individual CmpCommit* functions may plausibly fail, mostly in case of OOM conditions (allocating a new key node fails, extending a key index to accommodate a new key fails, etc.). Ideally, in such a situation, all of the previously committed operations would be rolled back to return the registry to the original state, and an error would be returned to the client. However with the current implementation, this is impossible: all the changes made by the CmpCommit* routines are applied persistently, and there is no information saved that would make it possible to revert them. The kernel is in a tough spot, since it cannot roll the transaction back (there is no framework for it in the current design), and it cannot roll it forward – because that has just failed. So how does the kernel handle the problem?

    As it turns out, it chooses a creative third option: it tells KTM (and therefore the user-mode caller of CommitTransaction) that the commit has succeeded, while in fact it schedules a special worker function (CmpLazyCommitWorker) to try to commit the remaining pending operations 30 seconds later. If that fails, the timer is restarted, and an attempt is made another 30 seconds later. If some operations keep failing to commit, this process may continue indefinitely – i.e. until the next system reboot. But in the meantime, CommitTransaction() in the caller returns TRUE and the client program may assume that the transaction as a whole was committed. According to our testing there is no way for the process to know about the partial commit success, other than by further operating on registry and finding out that some keys/values have not been updated as declared by the system.

    In addition to presenting the caller with untrue information about the outcome of the transaction, leaving it in a half-committed state is also bad for the consistency of the hive and for system stability. Some areas of registry-related code don’t expect a situation where some transacted operations have completed and are globally visible, but the transaction itself hasn’t been fully cleaned up (e.g. by CmpTransMgrFreeVolatileData). Some examples of the problems that may arise are listed below:

    1. If a half-committed transaction is active on a user hive (ntuser.dat), and the user tries to sign out, the User Profile Service (profsvc) hangs, because the NtUnloadKey system call hangs while trying to unmount the hive.

    2. For new keys that are added via UoWAddThisKey and successfully committed, but the rest of the transaction fails, they are in a weird state: they are already globally visible (TransKCBOwner is NULL), but any attempt to operate on them (create a subkey, set a value, etc.) hangs, because the kernel tries to roll back any pending transactions on the key before proceeding, but cannot do it while the lazy commit worker is active.

    3. Similarly, for keys that are successfully transactionally renamed via UoWRenameNewSubKey, but the rest of the transaction fails, they are also in a weird state: the key with the old name is already destroyed, but the key with the new name is not globally visible yet (TransKCBOwner is still non-NULL). This means that the renamed key becomes \”hidden\” for as long as the transaction is not fully committed, because even though it exists, it cannot be opened by any callers outside the transaction.

    ========== KTM transaction recovery code ==========

    There is a significant amount of code in the kernel dedicated to recovering KTM transactions on reboot, if they might have been in the middle of being committed when execution was interrupted: mainly the CmpRmAnalysisPhase, CmpRmReDoPhase, CmpRmUnDoPhase routines and nested functions called by them. This code executes whenever a hive (other than an app hive) is loaded in the system, and its logic is to read serialized information about the pending registry operations from the log file via CLFS, re-create them against fresh transactions using standard registry syscalls such as ZwDeleteKey or ZwSetValueKey, and then attempt to commit the transactions through the standard CmpTransMgrPrepare/CmpTransMgrCommit call sequence.

    In this case, the problem of non-atomic transaction outcomes exists too: again if any of the specific operation handlers (CmpCommit*) fail, then the entire commit process is aborted and the registry is left with only the subset of operations that have succeeded so far. The only difference here is that the lazy commit worker is not scheduled – the remainder of the transaction is simply discarded.

    Interestingly, when we tried to perform an end-to-end test of the KTM transaction recovery feature, we were unable to get it to work even in legitimate scenarios with normal log records. In every case, the problem would manifest itself in the \”ReDoPhase\”, as all registry syscalls used in the CmpDoReDo* functions (ZwCreateKey, ZwDeleteValueKey, ZwSetSecurityObject and so on) would return the STATUS_INVALID_TRANSACTION error code. As a result, the transaction is almost immediately aborted and none of the operations saved in the transaction log file are rolled forward.

    To understand the cause of the behavior, let’s briefly discuss transaction states. In Windows, registry transaction state is represented by the three least significant bits of the _CM_TRANS.TransState field, which can either be Active (TransState == 0), or any variation of the Prepared/Aborted/Committed flags (Prepared=1, Aborted=2, Committed=4).

    Now, when analyzing each transaction loaded from disk, the CmpRmAnalysisPhase function requires that for a transaction to be recovered, it has to be exactly in the Prepared state (_CM_TRANS.TransState == 1). This makes sense because this is the only state in which it is possible that execution was interrupted in the middle of committing the transaction. However, later on the kernel reuses the same _CM_TRANS object to re-create the original state of the transaction by re-enlisting each pending operation. And so every call to ZwCreateKey, ZwDeleteValueKey etc. eventually ends up in the internal CmpTransEnlistUowInCmTrans function, which requires the transaction to be in the Active state (_CM_TRANS.TransState == 0), otherwise it fails with STATUS_INVALID_TRANSACTION. This also makes sense because it shouldn’t be possible to enlist new operations in a transaction that has already started to be committed.

    While both of these conditions are logical in isolation, they also contradict each other and break the transaction recovery process. The core of the problem seems to be the reuse of the same transaction object with its TransState restored from logs, without clearing the Prepared bit first. We’ve done some historical analysis to determine if there was a specific point in time when this feature broke, and found that the TransState check in CmpTransEnlistUowInCmTrans was added in Windows 10 1607 in 2016, along with a number of other registry-related changes (e.g. the introduction of lightweight transactions). That’s when the recovery stopped working according to our testing, while it still worked in the previous version Windows 10 1511 released in 2015.

    Please take this part of the report with a grain of salt, as it is still possible that we’re making some mistake in testing, and the transaction recovery does indeed work under some circumstances. But we suggest to look into this further, and on the off-chance that the mechanism really doesn’t work, maybe it could be an argument for eliminating this local attack surface entirely from the kernel.

    ========== Proof of Concept ==========

    We have developed a proof-of-concept demonstration that consists of two programs:

    1) A privileged one that runs with administrative rights, to simulate a real application or system service that uses KTM transactions for security-sensitive registry operations (NonAtomicKTM_Admin).

    2) The proof-of-concept exploit itself that is fine-tuned to attack the above example and trigger a partial transaction commit (NonAtomicKTM_User).

    This is sufficient to reproduce the vulnerability and to show its potential security implications. To carry out a realistic attack, an attacker would need to identify a privileged system component or a third-party application that relies on registry transactions for its security guarantees, and develop an exploit tailored to that target.

    The NonAtomicKTM_Admin program performs the following list of steps in the scope of a single KTM transaction:

    1) Creates a HKLM\\Software\\Test key.

    2) Sets a value named \”Value\” with the string \”SECRET\” in that key.

    3) Creates a nested HKLM\\Software\\Test\\SubKey key.

    4) Sets a custom security descriptor on the new HKLM\\Software\\Test key to only allow Administrators any kind of access to it.

    In turn, the NonAtomicKTM_User program creates a number of very long values in the world-writable HKLM\\Software\\Microsoft\\DRM key, in order to fill up the storage space of the HKLM\\Software hive completely. It then creates a small gap (free cell) big enough to accommodate operations #1 and #2 during the commit phase, but small enough to cause operation #3 to fail. This consequently means that operation #4 will not be committed either, and the partial success leaves the contents of \”Value\” readable to all users in the system, whereas normally it should either not exist or be accessible to administrators only.

    Here’s the list of steps needed to reproduce the bug:

    1) Prepare a test Windows instance (Windows 11 with the February 2023 update in our case) with a normal user and an admin account.

    2) Run NonAtomicKTM_User with \”1\” in the first argument as the normal user. This will pre-arrange the state of the HKLM\\Software hive by exhausting most of its space.

    3) Run NonAtomicKTM_Admin with admin rights, to have the program perform the privileged, transacted registry operations. If it terminates without any output, that means that it thinks the transaction has succeeded.

    4) Run NonAtomicKTM_User with \”2\” in the first argument as the normal user. If the attack was successful, it should enumerate and print out the value under the HKLM\\Software\\Test key.

    The HKLM\\Software\\Test key can also be manually inspected in Regedit as the normal user, to confirm that it is indeed readable. The outcome can be compared with the result of starting NonAtomicKTM_Admin without running NonAtomicKTM_User first, in which case the transaction is fully committed and the key is restricted as expected.

    This bug is subject to a 90-day disclosure deadline. If a fix for this issue is made available to users before the end of the 90-day deadline, this bug report will become public 30 days after the fix was made available. Otherwise, this bug report will become public at the deadline. The scheduled deadline is 2023-06-05.

    Related CVE Numbers: CVE-2023-32019.

     

    Researcher is https://research.google/people/MateuszJurczyk/

    “Mateusz is a big fan of memory corruption. His main areas of interest are client software security, vulnerability exploitation and mitigation techniques, and operating system kernel internals.”

    Susan Bradley Patch Lady/Prudent patcher

    4 users thanked author for this post.
    Viewing 7 reply threads
    Author
    Replies
    • #2577349

      The researcher seems very specialized in Kernel <> Registry vulnerabilities
      https://packetstormsecurity.com/files/author/11978/

      1 user thanked author for this post.
    • #2577356

      A very specific attack for what is hopefully a very limited number of programs, so most “normal” users are unlikely to be affected.
      You are still more likely to lose data / money through a phishing attack.

      cheers, Paul

    • #2577357

      Wow. Thanks for this.

      I always wondered why they didn’t use ESE for the registry database. Doing database ACID properly is hard.

      Although when it was introduced, those systems were seriously underpowered and that might be the reason right there…

    • #2577554

      This attack requires an “authenticated user (attacker)”.  This poses an extremely low risk for home users / small business users.  If you have an authenticated criminal on your system, you have a lot more to worry about than this vulnerability.

    • #2578991

      Microsoft makes potentially-breaking Windows kernel patch default after an earlier warning

      ..Speaking of security updates, this month’s Patch enables a kernel security vulnerability fix by default, something Microsoft had cautioned back in June that it could potentially break something on your system, though it didn’t really go into much detail about it. The support page for the issue has been updated with the following message now:

      IMPORTANT The resolution described in this article introduces a potential breaking change. Therefore, we are releasing the change disabled by default with the option to enable it. We recommend that you validate this resolution in your environment. Then, as soon as it is validated, enable the resolution as soon as possible.

      NOTE The resolution described in this article has now been released enabled by default.

      […]

      IMPORTANT The resolution described in this article has been released enabled by default. To apply the enabled by default resolution, install the Windows update that is dated on or after August 8, 2023. No further user action is required.

      Here is a summary of the vulnerability as provided by Microsoft. The flaw, a Windows kernel information disclosure vulnerability is tracked under ID “CVE-2023-32019”:

      Summary

      An authenticated user (attacker) could cause an information disclosure vulnerability in Windows Kernel. This vulnerability does not require administrator or other elevated privileges.

      The attacker who successfully exploits this vulnerability could view heap memory from a privileged process that is running on the server.

      Successful exploitation of this vulnerability requires an attacker to coordinate the attack with another privileged process that is run by another user in the system.

      You can find the support document on Microsoft’s site under KB5028407.

      3 users thanked author for this post.
    • #2580142

      no need to apply those reg keys anymore. they’re included in the August 2023 & later updates as the protections from CVE-2023-32019 are enabled by default.

      • #2580156

        With no details about the “breaking change”

        Susan Bradley Patch Lady/Prudent patcher

        1 user thanked author for this post.
    • #2582551

      You have got to be kidding me.

      Its not me :-), its Microsoft.

    • #2582643

      recently from Neowin – Microsoft explains why it pushed buggy Windows kernel patch after an earlier warning

      https://www.neowin.net/news/microsoft-explains-why-it-pushed-buggy-windows-kernel-patch-after-an-earlier-warning/

      read it, Alex5723 & Susan

      that Neowin article also writes the following:

      However, since we reported this news, Microsoft has once again updated its bulletin and has removed the portion that warned users of the kernel issue. That’s because the tech giant now feels confident stating that the potentially-breaking Windows kernel patch is problematic no more. The company assures this after having run “multiple investigations and tests” wherein “no issues were found”.

    Viewing 7 reply threads
    Reply To: CVE-2023-32019 – a bit more info from the researcher

    You can use BBCodes to format your content.
    Your account can't use all available BBCodes, they will be stripped before saving.

    Your information: