Spot Tuesday -> Venture Wednesday: Pwning Windows Ancillary Feature Chauffeur for WinSock (afd.sys) in 1 day

Patch Tuesday -> Exploit Wednesday: Pwning Windows Ancillary Function Driver for WinSock (afd.sys) in 24 Hours

‘Spot Tuesday, Venture Wednesday’ is an old cyberpunk proverb that describes the weaponization of susceptabilities the day after regular monthly safety and security spots end up being openly readily available. As safety and security enhances as well as manipulate reductions end up being extra innovative, the quantity of r & d called for to craft a weaponized manipulate has actually boosted. This is particularly appropriate for memory corruption susceptabilities.

Number 1 — Exploitation timeline

Nonetheless, with the enhancement of brand-new attributes (as well as memory-unsafe C code) in the Windows 11 bit, ripe brand-new strike surface areas can be presented. By focusing on this freshly presented code, we show that susceptabilities that can be trivially weaponized still happen regularly. In this post, we assess as well as manipulate a susceptability in the Windows Ancillary Feature Chauffeur for Winsock, afd.sys, for Regional Benefit Rise (LPE) on Windows 11. Though neither people had any kind of previous experience with this bit component, we had the ability to detect, recreate, as well as weaponize the susceptability in regarding a day. You can discover the manipulate code below.

Spot Diff as well as Source Evaluation

Based upon the information of CVE-2023-21768 released by the Microsoft Safety And Security Reaction Facility (MSRC), the susceptability exists within the Ancillary Feature Chauffeur (AFD), whose binary filename is afd.sys. The AFD component is the bit entrance factor for the Winsock API. Utilizing this info, we evaluated the motorist variation from December 2022 as well as contrasted it to the variation freshly launched in January 2023. These examples can be gotten separately from Winbindex without the lengthy procedure of removing adjustments from Microsoft spots. Both variations evaluated are revealed listed below.

  • AFD.sys / Windows 11 22H2 / 10.0.22621.608 (December 2022)
  • AFD.sys / Windows 11 22H2 / 10.0.22621.1105 (January 2023)

Ghidra was made use of to produce binary exports for both of these data so they might be contrasted in BinDiff. A summary of the matched features is revealed listed below.

Number 2 — Binary contrast of AFD.sys

Just one feature showed up to have actually been altered, afd!AfdNotifyRemoveIoCompletion. This considerably accelerated our evaluation of the susceptability. We after that contrasted both of the features. The screenshots listed below reveal the altered code pre- as well as post-patch when taking a look at the decompiled code in Binary Ninja.

Pre-patch, afd.sys variation 10.0.22621.608.

Number 3 — afd!AfdNotifyRemoveIoCompletion pre-patch

Post-patch, afd.sys variation 10.0.22621.1105.

Number 4 — afd!AfdNotifyRemoveIoCompletion post-patch

This adjustment revealed over is the only upgrade to the determined feature. Some fast evaluation revealed that a check is being done based upon PreviousMode. If PreviousMode is no (showing that the phone call stems from the bit) a worth is contacted a guideline defined by an area in an unidentified framework. If, on the various other hand, PreviousMode is not no after that ProbeForWrite is phoned call to make sure that the reminder laid out in the area is a legitimate address that stays within customer setting.

This check is missing out on in the pre-patch variation of the motorist. Given that the feature has a particular button declaration for PreviousMode, the presumption is that the programmer planned to include this check yet neglected (most of us do not have coffee in some cases ☕!).

From this upgrade, we can presume that an aggressor can reach this code course with a regulated worth at field_0x18 of the unidentified framework. If an aggressor has the ability to occupy this area with a bit address, after that it’s feasible to produce an approximate bit Write-Where primitive. Now, it is unclear what worth is being created, yet any kind of worth might possibly be made use of for a Neighborhood Benefit Rise primitive.

The feature model itself consists of both the PreviousMode worth as well as a guideline to the unidentified framework as the very first as well as 3rd debates specifically.

Number 5 — afd!AfdNotifyRemoveIoCompletion feature model

Reverse Design

We currently understand the area of the susceptability, yet not exactly how to set off the implementation of the at risk code course. We’ll do some reverse design prior to starting to deal with a Proof-of-Concept (PoC).

Initially, the at risk feature was cross-referenced to recognize where as well as exactly how it was made use of.

Number 6 — afd!AfdNotifyRemoveIoCompletion cross-references

A solitary phone call to the at risk feature is made in afd!AfdNotifySock.

We duplicate the procedure, searching for cross-references to AfdNotifySock. We discover no straight contact us to the feature, yet its address shows up over a table of feature reminders called AfdIrpCallDispatch.

Number 7 — afd!AfdIrpCallDispatch

This table consists of the send off regimens for the AFD motorist. Send off regimens are made use of to take care of demands from Win32 applications by calling DeviceIoControl. The control code for every feature is discovered in AfdIoctlTable.

Nonetheless, the reminder over is not within the AfdIrpCallDispatch table as we anticipated. From Steven Vittitoe’s Spy talk slides, we uncovered that there are really 2 send off tables for AFD. The 2nd being AfdImmediateCallDispatch. By determining the range in between the begin of this table as well as where the reminder to AfdNotifySock is saved, we can determine the index right into the AfdIoctlTable which reveals the control code for the feature is 0x12127.

Number 8 — afd!AfdIoctlTable

It’s worth keeping in mind that it’s the last input/output control (IOCTL) code in the table, showing that AfdNotifySock is most likely a brand-new send off feature that has actually been just recently included in the AFD motorist.

Now, we had a number of choices. We might turn around designer the matching Winsock API in a customer area to much better recognize exactly how the underlying bit feature was called, or turn around designer the bit code as well as call right into it straight. We didn’t really understand which Winsock feature represented AfdNotifySock, so we chose to do the last.

We stumbled upon some code released by x86matthew that executes outlet procedures by calling right into the AFD motorist straight, passing up the Winsock collection. This is fascinating from a stealth point of view, but also for our functions, it is a good theme to produce a deal with to a TCP outlet to make IOCTL demands to the AFD motorist. From there, we had the ability to get to the target feature, as shown by getting to a breakpoint embeded in WinDbg while bit debugging.

Number 9 — afd!AfdNotifySock breakpoint

Currently, refer back to the feature model for DeviceIoControl, where we call right into the AFD motorist from customer area. Among the criteria, lpInBuffer, is a customer setting barrier. As pointed out in the previous area, the susceptability takes place since the customer has the ability to pass an unvalidated reminder to the motorist within an unidentified information framework. This framework is come on straight from our customer setting application through the lpInBuffer specification. It’s entered AfdNotifySock as the 4th specification, as well as right into AfdNotifyRemoveIoCompletion as the 3rd specification.

Now, we don’t understand exactly how to occupy the information in lpInBuffer, which we’ll call AFD_NOTIFYSOCK_STRUCT, in order to pass the checks called for to get to the at risk code course in AfdNotifyRemoveIoCompletion. The rest of our reverse design procedure included adhering to the implementation circulation as well as analyzing exactly how to get to the at risk code.

Allow’s experience each of the checks.

The very first check we experience goes to the start of AfdNotifySock:

Number 10 — afd!AfdNotifySock dimension check

This check informs us that the dimension of the AFD_NOTIFYSOCK_STRUCT ought to amount to 0x30 bytes, or else the feature falls short with STATUS_INFO_LENGTH_MISMATCH.

The following check verifies worths in numerous areas in our framework:

Number 11 — afd!AfdNotifySock framework recognition

At the time we didn’t understand what any one of the areas represent, so we come on a 0x30 byte selection loaded with 0x41 bytes (AAAAAAAAA...).

The following check we experience seeks a contact us to ObReferenceObjectByHandle. This feature takes the very first area of our input framework as its very first debate.

Number 12 — afd!AfdNotifySock phone call nt!ObReferenceObjectByHandle

The phone call should return success in order to continue to the proper code implementation course, which implies that we should come on a legitimate take care of to an IoCompletionObject. There is no formally recorded method to produce a things of that kind through Win32 API. Nonetheless, after some looking, we discovered an undocumented NT feature NtCreateIoCompletion that got the job done.

Later, we get to a loophole whose counter was among the worths from our struct:

Number 13 — afd!AfdNotifySock loophole

This loophole inspected an area from our framework to validate it consisted of a legitimate customer setting reminder as well as duplicated information to it. The reminder is incremented after each version of the loophole. We filled out the reminders with legitimate addresses as well as established the counter to 1. From below, we had the ability to ultimately get to the at risk feature AfdNotifyRemoveIoCompletion.

Number 14 — afd!AfdNotifyRemoveIoCompletion phone call

As Soon As inside AfdNotifyRemoveIoCompletion, the very first check gets on one more area in our framework. It has to be non-zero. It’s after that increased by 0x20 as well as entered ProbeForWrite in addition to one more area in our struct as the reminder specification. From below we can complete the struct better with a legitimate customer setting reminder (pData2) as well as area dwLen = 1 (to ensure that the complete dimension passed to ProbeForWrite is equivalent 0x20), as well as the checks pass.

Number 15 — afd! Afd!AfdNotifyRemoveIoCompletion area check

Lastly, the last check to pass in the past getting to the target code is a contact us to IoRemoveCompletion which should return 0 (STATUS_SUCCESS).

This feature will certainly obstruct up until either:

  • A conclusion document appears for the IoCompletionObject specification
  • The timeout runs out, which is come on as a criterion of the feature

We regulate the timeout worth through our framework, yet just establishing a timeout of 0 is not enough for the feature to return success. In order for this feature to return without mistakes, there should go to the very least one conclusion document readily available. After some research study, we discovered the undocumented feature NtSetIoCompletion, which by hand increments the I/O pending counter on an IoCompletionObject. Calling this feature on the IoCompletionObject we produced earlier makes sure that the phone call to IoRemoveCompletion returns STATUS_SUCCESS.

Number 16 — afd!AfdNotifyRemoveIoCompletion check return nt!IoRemoveIoCompletion

Causing Approximate Write-Where

Since we can get to the at risk code, we can fill up the proper area in our framework with an approximate address to contact.  The worth that we contact the address originates from an integer whose reminder is entered the phone call to IoRemoveIoCompletion. IoRemoveIoCompletion establishes the worth of this integer to the return worth of a contact us to KeRemoveQueueEx.

Number 17 — nt!KeRemoveQueueEx return worth

Number 18 — nt!KeRemoveQueueEx return usage

In our evidence of idea, this compose worth is constantly equivalent to 0x1. We hypothesized that the return worth of KeRemoveQueueEx is the variety of products gotten rid of from the line, yet did not examine better. Now, we had the primitive we required as well as proceeded to ending up the manipulate chain. We later on verified that this assumption was proper, as well as the compose worth can be randomly incremented by extra contact us to NtSetIoCompletion on the IoCompletionObject.


With the capability to compose a taken care of worth (0x1) at an approximate bit address, we continued to transform this right into a complete approximate bit Read/Write. Since this susceptability impacts the most recent variations of Windows 11(22H2), we picked to utilize a Windows I/O ring things corruption to produce our primitive. Yarden Shafir has actually created a variety of exceptional messages on Windows I/O rings as well as additionally established as well as revealed the primitive that we leveraged in our manipulate chain. As for we realize this is the very first circumstances where this primitive has actually been made use of in a public manipulate.

When an I/O Ring is booted up by a customer 2 different frameworks are produced, one in customer area as well as one in bit area. These frameworks are revealed listed below.

The bit things maps to nt!_IORING_OBJECT as well as is revealed listed below.

Number 19 — nt!_IORING_OBJECT initialization

Keep in mind that the bit things has 2 areas, RegBuffersCount as well as RegBuffers, which are zeroed on initialization. The matter shows exactly how might I/O procedures can potentially be queued for the I/O ring. The various other specification is a guideline to a listing of the presently queued procedures.

On the customer area side, when calling kernelbase!CreateIoRing you return an I/O Ring take care of on success. This take care of is a guideline to an undocumented framework (HIORING). Our interpretation of this framework was gotten from the research study done by Yarden Shafir.

typedef struct _HIORING

    manage take care of;

    NT_IORING_INFO Details;

    ULONG IoRingKernelAcceptedVersion;

    PVOID RegBufferArray;

    ULONG BufferArraySize;

    PVOID Unidentified;

    ULONG FileHandlesCount;

    ULONG SubQueueHead;

    ULONG SubQueueTail;


If a susceptability, such as the one covered in this post, permits you to upgrade the RegBuffersCount as well as RegBuffers areas, after that it is feasible to utilize conventional I/O Ring APIs to review as well as compose bit memory.

As we saw above, we have the ability to utilize the susceptability to compose 0x1 at any kind of bit address that we such as. To establish the I/O ring primitive we can just set off the susceptability two times.

In the very first trigger we established the RegBufferCount to 0x1.


Number 20 — nt!_IORING_OBJECT very first time setting off the insect

As well as in the 2nd trigger we establish RegBuffers to an address that we can assign in customer area (like 0x0000000100000000).


Number 21 — nt!_IORING_OBJECT 2nd time setting off the insect

All that continues to be is to queue I/O procedures by composing reminders to created nt!_IOP_MC_BUFFER_ENTRY frameworks at the customer area address (0x100000000). The variety of access ought to amount to RegBuffersCount. This procedure is highlighted in the representation listed below.


Number 22 — Establishing customer area for I/O Ring bit R/W primitive

One such nt!_IOP_MC_BUFFER_ENTRY is displayed in the screenshot listed below. Keep in mind that the location of the procedure is a bit address (0xfffff8052831da20) which the dimension of the procedure, in this situation, is 0x8 bytes. It is not feasible to distinguish the framework if this is a read or compose procedure. The instructions of the procedure relies on which API was made use of to queue the I/O demand. Utilizing kernelbase!BuildIoRingReadFile causes an approximate bit compose as well as kernelbase!BuildIoRingWriteFile causes an approximate bit read.


Number 23 — Instance forged I/O Ring procedure

To execute an approximate compose, an I/O procedure is charged to review information from a data take care of as well as compose that information to a Bit address.


Number 24 — I/O Ring approximate compose

On the other hand, to execute an approximate read, an I/O procedure is charged to review information at a bit address as well as compose that information to a data take care of.


Number 25 – I/O Ring approximate read


With the primitive established all that continues to be is utilizing some conventional bit post-exploitation methods to leakage the token of a raised procedure like System (PID 4) as well as overwrite the token of a various procedure.


Exploitation In bush

After the general public launch of our manipulate code, a staff member from 360 Icesword Laboratory disclosed openly for the very first time, that they uncovered an example manipulating this susceptability in the wild (ITW) previously this year. The method made use of by the ITW example varied from ours. The aggressor causes the susceptability utilizing the matching Winsock API feature, ProcessSocketNotifications, rather than calling right into the afd.sys motorist straight, like in our manipulate.  

The main declaration from 360 Icesword Laboratory is as adheres to:  
“360 IceSword Laboratory concentrates on APT discovery as well as protection. Based upon our 0day susceptability radar system, we uncovered a make use of example of CVE-2023-21768 in the wild in January this year, which varies from the ventures revealed by @chompie1337 as well as @FuzzySec because it is manipulated with system devices as well as susceptability attributes. The manipulate is associated with NtSetIoCompletion as well as ProcessSocketNotifications, ProcessSocketNotifications obtains the variety of times NtSetIoCompletion is called, so we utilize this to transform the benefit matter.”  


Final Thought as well as Last Representations

You might discover that in some components of the reverse design our evaluation is shallow. It’s in some cases useful to just observe some appropriate state adjustments as well as deal with sections of the program as a black box, to prevent obtaining led down an unnecessary bunny opening. This permitted us to reverse a make use of rapidly, despite the fact that taking full advantage of the conclusion rate was not our objective.

In addition, we carried out a spot diffing evaluation of all the reported susceptabilities in afd.sys suggested as “Exploitation Most Likely”. Our evaluation exposed that all other than 2 of the susceptabilities were an outcome of incorrect recognition of reminders come on from customer setting. This reveals that having a historic understanding of previous susceptabilities, specifically within a particular target, can be productive for discovering brand-new susceptabilities. When the code base is broadened – the exact same blunders are most likely to be duplicated. Keep in mind, brand-new C code == brand-new pests 😀. As shown by the exploration of the abovementioned susceptability being manipulated in the wild, it is risk-free to state that enemies are very closely keeping track of brand-new code base enhancements also. 

The absence of assistance for Manager Setting Accessibility Security (SMAP) in the Windows bit leaves us with numerous choices to create brand-new data-only manipulate primitives. These primitives aren’t viable in various other running systems that sustain SMAP. For instance, think about CVE-2021-41073, a susceptability in Linux’s application of I/O Ring pre-registered barriers, (the exact same attribute we abuse in Windows for a R/W primitive). This susceptability can permit overwriting a bit reminder for a signed up barrier, yet it cannot be made use of to create an approximate R/W primitive since if the reminder is changed with a customer reminder, as well as the bit attempts to review or compose there, the system will certainly collapse.

In spite of best shots by Microsoft to kill beloved exploit primitives, there are bound to be brand-new primitives to be uncovered that take their area. We had the ability to manipulate the most recent variation of Windows 11 22H2 without coming across any kind of reductions or restrictions from Virtualization Based Safety attributes such as HVCI.


Leave a Reply

Your email address will not be published. Required fields are marked *