{"id":18302,"date":"2022-02-16T11:40:01","date_gmt":"2022-02-16T19:40:01","guid":{"rendered":"http:\/\/www.palada.net\/index.php\/2022\/02\/16\/news-12035\/"},"modified":"2022-02-16T11:40:01","modified_gmt":"2022-02-16T19:40:01","slug":"news-12035","status":"publish","type":"post","link":"http:\/\/www.palada.net\/index.php\/2022\/02\/16\/news-12035\/","title":{"rendered":"Analysis of Microsoft CVE-2022-21907"},"content":{"rendered":"<div class=\"aem-Grid aem-Grid--12 aem-Grid--default--12\">\n<div class=\"raw-import aem-GridColumn aem-GridColumn--default--12\">\n<div class=\"text-container\"><\/div>\n<\/p><\/div>\n<div class=\"cmp cmp-text aem-GridColumn aem-GridColumn--default--12\">\n<h2><a href=\"https:\/\/www.fortinet.com\/fortiguard\/labs.html?utm_source=blog&amp;utm_medium=campaign&amp;utm_campaign=FortiGuardLabs\">FortiGuard Labs<\/a>\u00a0Research<\/h2>\n<p><b>Affected Platforms:<\/b> Windows Server 2022, Windows Server 2019, Windows 10<br \/> <b>Impacted Users:<\/b> Any organization with affected Windows system<br \/> <b>Impact:<\/b> Denial of service to affected systems<br \/> <b>Severity Level: <\/b>High <\/p>\n<p>On January 11<sup>th<\/sup>, 2022 Microsoft released a patch for CVE-2022-21907 as part of Microsoft\u2019s Patch Tuesday. CVE-2022-21907 attracted special attentions from industry insiders due to the claim that the vulnerability is worm-able. In this analysis we will look at the cause of the vulnerability and how attackers can exploit it.<\/p>\n<p>CVE-2022-21907 is a remote code execution vulnerability in Windows\u2019 Internet Information Services (IIS) component. More specifically, it affects the kernel module inside http.sys that handles most of the IIS core operations. At a minimum, the vulnerability can lead to denial of service conditions on the victim\u2019s machine by crashing the operating system. It might also be possible to combine this vulnerability with another vulnerability to enable remote code execution.<\/p>\n<p>We used Windows 2022 Server 10.0.20348.143 as the base of our analysis. IIS is also present on Windows 10. We also looked at the Windows 10 (2H 2021) http.sys and confirmed that the same vulnerable code path exists. However, since IIS is not enabled by default on Windows 10, the chance of Windows 10 systems being exploited is significantly less.<\/p>\n<p>First, we performed a binary differential between the vulnerable http.sys and the patched http.sys (10.0.20348.469). The program Bindiff compared the two binary files and highlighted the functions that have been modified. While a few functions were heavily modified, we were interested in two particular functions\u2014http!UlpAllocateFastTracker() and http!UlFastSendHttpResponse() .<\/p>\n<p>(As an aside, we did our initial analysis on Windows 10 http.sys, and these two functions are the only ones patched on Windows 10.)<\/p>\n<p>In http!UlpAllocateFastTracker(), we see the following differences:<\/p>\n<\/p><\/div>\n<div class=\"cmp cmp-image aem-GridColumn--default--none aem-GridColumn aem-GridColumn--default--6 aem-GridColumn--offset--default--3\">               <noscript data-cmp-image=\"{&#34;smartImages&#34;:[],&#34;smartSizes&#34;:[],&#34;lazyEnabled&#34;:true}\">             <img decoding=\"async\" src=\"\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\/_jcr_content\/root\/responsivegrid\/image.img.png\/1644952203164\/mstimg1.png\" alt=\"Image depicts the differences between the original (top) and the patched function (bottom)\"\/>         <\/noscript>          <span class=\"cmp-image--title\">Figure 1: Differences between the original (top) and the patched function (bottom)<\/span>         <\/div>\n<div class=\"cmp cmp-text aem-GridColumn aem-GridColumn--default--12\">\n<p>One curious thing to note is that memset() is called twice to zero out the buffer: once for a hardcoded first 0x1e0 bytes of the buffer, and the other starting at 0x2e for 0x50 bytes.<\/p>\n<\/p><\/div>\n<div class=\"cmp cmp-image aem-GridColumn--default--none aem-GridColumn aem-GridColumn--default--8 aem-GridColumn--offset--default--2\">               <noscript data-cmp-image=\"{&#34;smartImages&#34;:[],&#34;smartSizes&#34;:[],&#34;lazyEnabled&#34;:true}\">             <img decoding=\"async\" src=\"\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\/_jcr_content\/root\/responsivegrid\/image_1072390868.img.png\/1644952265175\/msftimg2.png\" alt=\"Figure 2: memset(value = 0, size=0x1e0)\"\/>         <\/noscript>          <span class=\"cmp-image--title\">Figure 2: memset(value = 0, size=0x1e0)<\/span>         <\/div>\n<div class=\"cmp cmp-text aem-GridColumn aem-GridColumn--default--12\">\n<p class=\"cq-text-placeholder-ipe\" data-emptytext=\"Text\">\n<\/p><\/div>\n<div class=\"cmp cmp-image aem-GridColumn--default--none aem-GridColumn aem-GridColumn--default--6 aem-GridColumn--offset--default--3\">               <noscript data-cmp-image=\"{&#34;smartImages&#34;:[],&#34;smartSizes&#34;:[],&#34;lazyEnabled&#34;:true}\">             <img decoding=\"async\" src=\"\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\/_jcr_content\/root\/responsivegrid\/image_735049753.img.png\/1644952351181\/msftimg3.png\" alt=\"Figure 3: memset(value = 0, size=0x50)\"\/>         <\/noscript>          <span class=\"cmp-image--title\">Figure 3: memset(value = 0, size=0x50)<\/span>         <\/div>\n<div class=\"cmp cmp-text aem-GridColumn aem-GridColumn--default--12\">\n<p>The difference between these two memset() calls is that memset(0x1e0) is for a freshly allocated buffer from nt!ExAllocatePool3(), and memset(0x50) is for buffers from both nt!ExAllocatePool3() and ExpInterlockedPopEntrySList(). (Internally, it uses a Windows single-linked list structure LIST_ENTRY, basically reusing previously allocated buffers.)<\/p>\n<p>If we only look at the modifications to http!UlpAllocateFastTracker(), we can deduce that the non-zero entries in the buffer (let\u2019s call it a Tracker) might cause some unpleasant side effects. Furthermore, since the buffer can be allocated directly from nt!ExAllocatePool3(), if the system is experiencing memory pressure it\u2019s possible to spray attacker-controlled data into the memory and have the attacker-controlled data show up in the newly-minted Tracker buffer.<\/p>\n<p>The fact that memset() is called twice to the same Tracker buffer is also curious. Apparently, the developer felt that it was necessary to zero-out a particular segment of the Tracker (from 0x2E-0x7E), even if the buffer was retrieved from a LookAside link list (where the initial allocation would have already zeroed out all the attacker-controlled data). This means that whatever non-zero value that triggers the bug, it should be inside the 0x2e-0x7e part of the Tracker structure.<\/p>\n<p>At this point, we have a few ideas we can try. First, we need to know under what conditions http!UlpAllocateFastTracker() would be called. This turns out to be very easy to determine. A single command in Ghidra (Find References to UlpAllocateFastTracker) or IDA (Jump to xref) both show that only one function in http.sys could call UlpAllocateFastTracker().<\/p>\n<\/p><\/div>\n<div class=\"cmp cmp-image aem-GridColumn--default--none aem-GridColumn aem-GridColumn--default--8 aem-GridColumn--offset--default--2\">               <noscript data-cmp-image=\"{&#34;smartImages&#34;:[],&#34;smartSizes&#34;:[],&#34;lazyEnabled&#34;:true}\">             <img decoding=\"async\" src=\"\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\/_jcr_content\/root\/responsivegrid\/image_252362756.img.png\/1644952392617\/msftimg4.png\" alt=\"Figure 4: Two calls to http!UlpAllocateFastTacker()\"\/>         <\/noscript>          <span class=\"cmp-image--title\">Figure 4: Two calls to http!UlpAllocateFastTacker()<\/span>         <\/div>\n<div class=\"cmp cmp-text aem-GridColumn aem-GridColumn--default--12\">\n<p>After writing some python scripts blasting HTTP requests to IIS, we determined that http!UlFastSendHttpResponse() does what its name suggests\u2014the function is responsible for sending an http response back to the client. The Tracker object we saw earlier is a structure that keeps track of various states and pointers related to that response. When we snoop around, we can even find the response data in one of the pointers.<\/p>\n<\/p><\/div>\n<div class=\"cmp cmp-image aem-GridColumn--default--none aem-GridColumn aem-GridColumn--default--8 aem-GridColumn--offset--default--2\">               <noscript data-cmp-image=\"{&#34;smartImages&#34;:[],&#34;smartSizes&#34;:[],&#34;lazyEnabled&#34;:true}\">             <img decoding=\"async\" src=\"\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\/_jcr_content\/root\/responsivegrid\/image_1120797061.img.png\/1644952505991\/mstimg5.png\" alt=\"Figure 5: A Tracker object and the corresponding response data\"\/>         <\/noscript>          <span class=\"cmp-image--title\">Figure 5: A Tracker object and the corresponding response data<\/span>         <\/div>\n<div class=\"cmp cmp-text aem-GridColumn aem-GridColumn--default--12\">\n<p>After we determined how to access the initialization code, we decided to \u2018help\u2019 the exploit by pre-writing a non-zero value to Tracker. Using Windbg, pykd and some python scripting, we managed to inject pre-determined values into the part of Tracker that are likely to be affected before http!UlpAllocateFastTracker() returns.<\/p>\n<p>Sadly, no matter how much we ran our \u2018fuzzer\u2019, the test system remained stable and responsive. We did, however, noticed that most of the calls to http!UlpAllocateFastTracker() were from UlFastSendHttpResponse+0x2F0 (&gt;90%), and only a few allocation calls were made from UlpAllocateFastTracker+0xe99. We did a bindiff on http!UlFastSendHttpResponse() on Windows 10\u2019s http.sys and there\u2019s a gigantic code change.<\/p>\n<\/p><\/div>\n<div class=\"cmp cmp-image aem-GridColumn--default--none aem-GridColumn aem-GridColumn--default--10 aem-GridColumn--offset--default--1\">               <noscript data-cmp-image=\"{&#34;smartImages&#34;:[],&#34;smartSizes&#34;:[],&#34;lazyEnabled&#34;:true}\">             <img decoding=\"async\" src=\"\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\/_jcr_content\/root\/responsivegrid\/image_847554548.img.png\/1644952627976\/msft6.png\" alt=\"Figure 6: Comparison between the patched http!UlFastSendHttpResponse() and the original http!UlFastSendHttpResponse()\"\/>         <\/noscript>          <span class=\"cmp-image--title\">Figure 6: Comparison between the patched http!UlFastSendHttpResponse() and the original http!UlFastSendHttpResponse()<\/span>         <\/div>\n<div class=\"cmp cmp-text aem-GridColumn aem-GridColumn--default--12\">\n<p>At this point we were unable to trigger the crash so we took to Twitter to look for a POC.<\/p>\n<h3>The Crash<\/h3>\n<p>Armed with a new PoC, we resumed our analysis (this time on the Windows 2022 Server) and we soon discovered the cause of the crash that was being patched.<\/p>\n<p>The crash happens at the end of the clean up phrase of http!UlFastSendHttpResponse(), with a call to nt!MmUnampLockedPages() that tries to access invalid memory.<\/p>\n<\/p><\/div>\n<div class=\"cmp cmp-image aem-GridColumn--default--none aem-GridColumn aem-GridColumn--default--10 aem-GridColumn--offset--default--1\">               <noscript data-cmp-image=\"{&#34;smartImages&#34;:[],&#34;smartSizes&#34;:[],&#34;lazyEnabled&#34;:true}\">             <img decoding=\"async\" src=\"\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\/_jcr_content\/root\/responsivegrid\/image_701986347.img.png\/1644952665545\/img7.png\" alt=\"Figure 7: A stack trace of the crash\"\/>         <\/noscript>          <span class=\"cmp-image--title\">Figure 7: A stack trace of the crash<\/span>         <\/div>\n<div class=\"cmp cmp-text aem-GridColumn aem-GridColumn--default--12\">\n<p>According to Microsoft, nt!MmUnmapLockedPages() is a Windows kernel routine that releases a mapping between a virtual memory address and a physical memory address. The mapping is described by a kernel structure called the Memory Descriptor List (MDL).<\/p>\n<\/p><\/div>\n<div class=\"cmp cmp-image aem-GridColumn--default--none aem-GridColumn aem-GridColumn--default--6 aem-GridColumn--offset--default--3\">               <noscript data-cmp-image=\"{&#34;smartImages&#34;:[],&#34;smartSizes&#34;:[],&#34;lazyEnabled&#34;:true}\">             <img decoding=\"async\" src=\"\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\/_jcr_content\/root\/responsivegrid\/image_1402197922.img.png\/1644952732081\/img8.png\" alt=\"Figure 8: Function signature of MmUnmapLockedPages()\"\/>         <\/noscript>          <span class=\"cmp-image--title\">Figure 8: Function signature of MmUnmapLockedPages()<\/span>         <\/div>\n<div class=\"cmp cmp-text aem-GridColumn aem-GridColumn--default--12\">\n<p>When we set a breakpoint on the call to nt!MmUnmapLockedPages() we started to see all sorts of invalid memory addresses being passed in as the BaseAddress (virtual memory address).<\/p>\n<\/p><\/div>\n<div class=\"cmp cmp-image aem-GridColumn--default--none aem-GridColumn aem-GridColumn--default--8 aem-GridColumn--offset--default--2\">               <noscript data-cmp-image=\"{&#34;smartImages&#34;:[],&#34;smartSizes&#34;:[],&#34;lazyEnabled&#34;:true}\">             <img decoding=\"async\" src=\"\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\/_jcr_content\/root\/responsivegrid\/image_905287819.img.png\/1644952775219\/img9.png\" alt=\"Figure 9: Invalid arguments for MmUnmapLockedPages()\"\/>         <\/noscript>          <span class=\"cmp-image--title\">Figure 9: Invalid arguments for MmUnmapLockedPages()<\/span>         <\/div>\n<div class=\"cmp cmp-text aem-GridColumn aem-GridColumn--default--12\">\n<p>But now the question became, what did the PoC do differently to trigger the vulnerability? To get to the bottom of this, we needed to decompile http!UlFastSendHttpResponse() and look at the code.<\/p>\n<\/p><\/div>\n<div class=\"cmp cmp-image aem-GridColumn--default--none aem-GridColumn aem-GridColumn--default--6 aem-GridColumn--offset--default--3\">               <noscript data-cmp-image=\"{&#34;smartImages&#34;:[],&#34;smartSizes&#34;:[],&#34;lazyEnabled&#34;:true}\">             <img decoding=\"async\" src=\"\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\/_jcr_content\/root\/responsivegrid\/image_322882344.img.png\/1644952817827\/img10.png\" alt=\"Figure 10: Decompiled vulnerable code\"\/>         <\/noscript>          <span class=\"cmp-image--title\">Figure 10: Decompiled vulnerable code<\/span>         <\/div>\n<div class=\"cmp cmp-text aem-GridColumn aem-GridColumn--default--12\">\n<p>We were able to immediately make some guesses. We could see that the pointer v19 is freed by UlpFreeFastTracker(). This told us that v19 is the pointer to the Tracker buffer. Indeed, when we scrolled up and checked the two calls to http!UlpAllocateFastTracker(), we could see that v19 is the return value from that function.<\/p>\n<\/p><\/div>\n<div class=\"cmp cmp-image aem-GridColumn--default--none aem-GridColumn aem-GridColumn--default--10 aem-GridColumn--offset--default--1\">               <noscript data-cmp-image=\"{&#34;smartImages&#34;:[],&#34;smartSizes&#34;:[],&#34;lazyEnabled&#34;:true}\">             <img decoding=\"async\" src=\"\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\/_jcr_content\/root\/responsivegrid\/image_780356552.img.png\/1644952880200\/img11pt1.png\" alt=\"http!UlpAllocateFastTracker\"\/>         <\/noscript>                   <\/div>\n<div class=\"cmp cmp-image aem-GridColumn--default--none aem-GridColumn aem-GridColumn--default--10 aem-GridColumn--offset--default--1\">               <noscript data-cmp-image=\"{&#34;smartImages&#34;:[],&#34;smartSizes&#34;:[],&#34;lazyEnabled&#34;:true}\">             <img decoding=\"async\" src=\"\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\/_jcr_content\/root\/responsivegrid\/image_2123119300.img.png\/1644952901730\/img11pt2.png\" alt=\"Figure 11: v19 as the returned Tracker object\"\/>         <\/noscript>          <span class=\"cmp-image--title\">Figure 11: v19 as the returned Tracker object<\/span>         <\/div>\n<div class=\"cmp cmp-text aem-GridColumn aem-GridColumn--default--12\">\n<p>At the same time, we knew the second argument for MmUnmapLockedPages() is the MDL struct. If we check the definition of MDL (http.sys uses an internal struct definition of MDL, but it\u2019s the same as the kernel\u2019s), we could see that the 0x00a field is the MdlFlags, and that the routine checked to see if the flag\u2019s 0<sup>th<\/sup> bit is 1. Finally, the 0x018 (24 in decimal) field is the MappedSystemVa.<\/p>\n<\/p><\/div>\n<div class=\"cmp cmp-image aem-GridColumn--default--none aem-GridColumn aem-GridColumn--offset--default--4 aem-GridColumn--default--4\">               <noscript data-cmp-image=\"{&#34;smartImages&#34;:[],&#34;smartSizes&#34;:[],&#34;lazyEnabled&#34;:true}\">             <img decoding=\"async\" src=\"\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\/_jcr_content\/root\/responsivegrid\/image_1590522868.img.png\/1644952945733\/img12.png\" alt=\"Figure 12: MDL definition\"\/>         <\/noscript>          <span class=\"cmp-image--title\">Figure 12: MDL definition<\/span>         <\/div>\n<div class=\"cmp cmp-text aem-GridColumn aem-GridColumn--default--12\">\n<p>As an aside, according to wdm.h from Windows SDK, 0x0001 is MDL_MAPPED_TO_SYSTEM_VA, ie. the memory mapping described by this MDL is valid.<\/p>\n<\/p><\/div>\n<div class=\"cmp cmp-image aem-GridColumn--default--none aem-GridColumn aem-GridColumn--default--6 aem-GridColumn--offset--default--3\">               <noscript data-cmp-image=\"{&#34;smartImages&#34;:[],&#34;smartSizes&#34;:[],&#34;lazyEnabled&#34;:true}\">             <img decoding=\"async\" src=\"\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\/_jcr_content\/root\/responsivegrid\/image_2008716285.img.png\/1644952992210\/img13.png\" alt=\"Figure 13: MdlFlags bit field definition from Windows SDK\"\/>         <\/noscript>          <span class=\"cmp-image--title\">Figure 13: MdlFlags bit field definition from Windows SDK<\/span>         <\/div>\n<div class=\"cmp cmp-text aem-GridColumn aem-GridColumn--default--12\">\n<p>With these two pieces of information, we were able to construct the pseudo-code-<\/p>\n<\/p><\/div>\n<div class=\"cmp cmp-image aem-GridColumn--default--none aem-GridColumn aem-GridColumn--default--8 aem-GridColumn--offset--default--2\">               <noscript data-cmp-image=\"{&#34;smartImages&#34;:[],&#34;smartSizes&#34;:[],&#34;lazyEnabled&#34;:true}\">             <img decoding=\"async\" src=\"\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\/_jcr_content\/root\/responsivegrid\/image_2118852005.img.png\/1644953963920\/img14.png\" alt=\"Pseudo-code of vulnerable code\"\/>         <\/noscript>          <span class=\"cmp-image--title\">Figure 14: Pseudo-code of vulnerable code. The analysis will call Tracker-&gt;80 as \u2018some_mdl\u2019 from now on.<\/span>         <\/div>\n<div class=\"cmp cmp-text aem-GridColumn aem-GridColumn--default--12\">\n<p>So, looking back at our initial guess, it was pretty good. We guessed that Tracker\u2019s 0x2e-0x7e needed to be non-zero, and indeed, the 0x50 pointer does have to be non-zero for this if statement to go through.<\/p>\n<p>So now, we have four new questions, ranked from the most to the least obvious:<\/p>\n<ol>\n<li>Can we control the \u2018some_mdl\u2019 MDL struct data?<\/li>\n<li>What is Tracker-&gt;member_0x50?<\/li>\n<li>Why can the PoC reach this code when our driver couldn\u2019t?<\/li>\n<li>Is remote code execution possible? <\/li>\n<\/ol>\n<h3>Can we control the \u2018some_mdl\u2019 MDL struct data?<\/h3>\n<p>It turns out that, yes, the attacker does have control of the bytes in the MDL in certain situations! We went back to http!UlpAllocateFastTracker() and stepped through every single line of instruction, and while there are multiple MDL pointers in Tracker, the MDL at offset 0x80 is never initialized. The allocation routine simply picks sequential memory spaces after Tracker\u2019s struct location and has the Tracker\u2019s MDL pointers point to these addresses. This makes sense, as when nt!ExAllocatePool3() is called, the bytes requested are much larger than the deduced size of the Tracker struct (Remember that the patched memset() only writes 0s to the first 0x1e0 of the buffer.)<\/p>\n<\/p><\/div>\n<div class=\"cmp cmp-image aem-GridColumn--default--none aem-GridColumn aem-GridColumn--default--8 aem-GridColumn--offset--default--2\">               <noscript data-cmp-image=\"{&#34;smartImages&#34;:[],&#34;smartSizes&#34;:[],&#34;lazyEnabled&#34;:true}\">             <img decoding=\"async\" src=\"\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\/_jcr_content\/root\/responsivegrid\/image_1498335358.img.png\/1644953089280\/igm15.png\" alt=\"Figure 15: nt!ExAllocatePool3() allocated 0xc85 bytes of buffer\"\/>         <\/noscript>          <span class=\"cmp-image--title\">Figure 15: nt!ExAllocatePool3() allocated 0xc85 bytes of buffer<\/span>         <\/div>\n<div class=\"cmp cmp-text aem-GridColumn aem-GridColumn--default--12\">\n<p class=\"cq-text-placeholder-ipe\" data-emptytext=\"Text\">\n<\/p><\/div>\n<div class=\"cmp cmp-image aem-GridColumn--default--none aem-GridColumn aem-GridColumn--default--6 aem-GridColumn--offset--default--3\">               <noscript data-cmp-image=\"{&#34;smartImages&#34;:[],&#34;smartSizes&#34;:[],&#34;lazyEnabled&#34;:true}\">             <img decoding=\"async\" src=\"\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\/_jcr_content\/root\/responsivegrid\/image_313051480.img.png\/1644953124422\/img16.png\" alt=\"Figure 16: http!UlInitializeFastTrackerPool() assigning addresses to Tracker pointers\"\/>         <\/noscript>          <span class=\"cmp-image--title\">Figure 16: http!UlInitializeFastTrackerPool() assigning addresses to Tracker pointers<\/span>         <\/div>\n<div class=\"cmp cmp-text aem-GridColumn aem-GridColumn--default--12\">\n<p>We know that 0x68, 0x70, 0x88, and 0x80 are all MDL pointers (via IDA heuristics), but only 0x68 is initialized with MmBuildMdlForNonPagedPool() in the initialization routine.<\/p>\n<\/p><\/div>\n<div class=\"cmp cmp-image aem-GridColumn--default--none aem-GridColumn aem-GridColumn--default--6 aem-GridColumn--offset--default--3\">               <noscript data-cmp-image=\"{&#34;smartImages&#34;:[],&#34;smartSizes&#34;:[],&#34;lazyEnabled&#34;:true}\">             <img decoding=\"async\" src=\"\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\/_jcr_content\/root\/responsivegrid\/image_31768170.img.png\/1644953165207\/img17.png\" alt=\"Figure 17: Tracker->0x68 pointer being initialized as a valid MDL object&#8221;\/>         <\/noscript>          <span class=\"cmp-image--title\">Figure 17: Tracker-&gt;0x68 pointer being initialized as a valid MDL object<\/span>         <\/div>\n<div class=\"cmp cmp-text aem-GridColumn aem-GridColumn--default--12\">\n<p>Once control is returned to http!UlFastSendHttpResponse(), additional MDLs are eventually initialized. However, the PoC discovered a code path where the initialization is skipped, with disastrous consequences.<\/p>\n<h3>What is Tracker-&gt;member_0x50?<\/h3>\n<p>We tried to dive deeper into the code to figure out what member_0x50 does, but the object is created outside of http!UlFastSendHttpResponse(), and was passed-by-reference to the routine as a pointer argument.<\/p>\n<p>Since the code assumes that if member_0x50 is valid then some_mdl should also be valid, perhaps the MDL\u2019s memory range is the backing storage for member_0x50, and both elements should be valid (or be invalid) together.<\/p>\n<p>During our testing, however, the argument that leads to member_0x50 is always null with both our driver and the PoC. We decided to leave it at that.<\/p>\n<h3>Why can the PoC reach this code when our driver couldn\u2019t?<\/h3>\n<p>As mentioned before, we need the execution to take a path that would not initialize some_mdl. The PoC takes advantage of this by sending identical malformed HTTP packets in quick succession.<\/p>\n<p>There are two calls to http!UlpAllocateFastTracker(). The first call is used more than 90% of the time. Once the Tracker structure is allocated, http!UlFastSendHttpResponse() takes over and continues the struct initialization process. Most importantly, during the process the member_0x50 element is zero-ed out, thus ensuring the bug would never be executed during normal execution.<\/p>\n<\/p><\/div>\n<div class=\"cmp cmp-image aem-GridColumn--default--none aem-GridColumn aem-GridColumn--default--6 aem-GridColumn--offset--default--3\">               <noscript data-cmp-image=\"{&#34;smartImages&#34;:[],&#34;smartSizes&#34;:[],&#34;lazyEnabled&#34;:true}\">             <img decoding=\"async\" src=\"\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\/_jcr_content\/root\/responsivegrid\/image_331427076.img.png\/1644953202817\/img18.png\" alt=\"Figure 18: member_0x50 pointer is zeroed out\"\/>         <\/noscript>          <span class=\"cmp-image--title\">Figure 18: member_0x50 pointer is zeroed out<\/span>         <\/div>\n<div class=\"cmp cmp-text aem-GridColumn aem-GridColumn--default--12\">\n<p>However, when IIS receives multiple malformed packets in quick succession, a different code path is taken. According to our code analysis, IIS eventually abandons its (our guess) caching mechanisms. In particular, while the first call to http!UlpAllocateFastTracker() still happens, the allocated Tracker structure is quickly deallocated.<\/p>\n<p>We are not sure why, but during the first call, a single value at Tracker-&gt;0x148 changes from 0x14 (in previous calls) to 0x0, which causes the new Tracker structure to be deallocated, and a call to http!UlpAllocateFastTracker() is made with a different second argument.<\/p>\n<\/p><\/div>\n<div class=\"cmp cmp-image aem-GridColumn--default--none aem-GridColumn aem-GridColumn--default--8 aem-GridColumn--offset--default--2\">               <noscript data-cmp-image=\"{&#34;smartImages&#34;:[],&#34;smartSizes&#34;:[],&#34;lazyEnabled&#34;:true}\">             <img decoding=\"async\" src=\"\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\/_jcr_content\/root\/responsivegrid\/image_1512783592.img.png\/1644953271486\/img19.png\" alt=\"Figure 19: First call, 0x200\"\/>         <\/noscript>          <span class=\"cmp-image--title\">Figure 19: First call, 0x200<\/span>         <\/div>\n<div class=\"cmp cmp-text aem-GridColumn aem-GridColumn--default--12\">\n<p class=\"cq-text-placeholder-ipe\" data-emptytext=\"Text\">\n<\/p><\/div>\n<div class=\"cmp cmp-image aem-GridColumn--default--none aem-GridColumn aem-GridColumn--default--8 aem-GridColumn--offset--default--2\">               <noscript data-cmp-image=\"{&#34;smartImages&#34;:[],&#34;smartSizes&#34;:[],&#34;lazyEnabled&#34;:true}\">             <img decoding=\"async\" src=\"\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\/_jcr_content\/root\/responsivegrid\/image_1066796303.img.png\/1644953375339\/img20.png\" alt=\"Figure 20: Second call, 0x0\"\/>         <\/noscript>          <span class=\"cmp-image--title\">Figure 20: Second call, 0x0<\/span>         <\/div>\n<div class=\"cmp cmp-text aem-GridColumn aem-GridColumn--default--12\">\n<p>\u00a0(By the way, judging from the code and the PDB (program database), two other variables \u201cUlH3ExtraHeaderCount\u201d and \u201c_UX_DUO_COLLECTION\u201d are used to determine the value. If anyone knows what these variables do, please let us know.)<\/p>\n<p>After the second allocation, a call is made to http!UlGenerateFixedHeaders(). However, the call is cut short. The sixth argument to http!UlGenerateFixedHeaders()\u2014the same 0x0 (normally 0x200) variable as the allocation call, causes an early check fail, resulting in an error code 0xC000000D and a quick return.<\/p>\n<\/p><\/div>\n<div class=\"cmp cmp-image aem-GridColumn--default--none aem-GridColumn aem-GridColumn--offset--default--4 aem-GridColumn--default--4\">               <noscript data-cmp-image=\"{&#34;smartImages&#34;:[],&#34;smartSizes&#34;:[],&#34;lazyEnabled&#34;:true}\">             <img decoding=\"async\" src=\"\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\/_jcr_content\/root\/responsivegrid\/image_708800947.img.png\/1644953416453\/img21.png\" alt=\"Figure 21: The 0x0 value in the argument makes http!UlGenerateFixedHeaders() returns with an error\"\/>         <\/noscript>          <span class=\"cmp-image--title\">Figure 21: The 0x0 value in the argument makes http!UlGenerateFixedHeaders() returns with an error<\/span>         <\/div>\n<div class=\"cmp cmp-text aem-GridColumn aem-GridColumn--default--12\">\n<p>After the routine returns with the error code, the execution skips most of the http!UlFastSendHttpResponse() and goes straight to cleanup phrase. As part of the cleanup, the vulnerable call to nt!MmUnmapLockedPages() is made, and the system crashes.<\/p>\n<p>As we said earlier, a malformed HTTP packet is needed to trigger this bug. We then wondered if other forms of malformed HTTP packets would also work. To our surprise, almost all our test samples would crash the system. This poses a serious issue as there are potentially many ways to attack the victim system.<\/p>\n<h3>Is remote code execution possible?<\/h3>\n<p>Since we have control of mapping any attacker-controlled memory, there is a risk of remote code execution. Constructing such a remote code execution, however, would require more research into what the Tracker fields do. The attacker would need to spray the memory with fake MDLs and fake Tracker pointers (this might require another vulnerability that leaks the kernel address info) or take advantage of the fact that there are other fields in Tracker that are also not initialized properly.<\/p>\n<p>We tried to combine the PoC with our driver program to spray the kernel memory with attacker-controlled data. However, the probability of the sprayed content being reallocated again and showing up in the vulnerable code is rather low; A successful remote code execution chain might require a more accurate way to spray the memory.<\/p>\n<p>Based on this analysis, we at FortiGuard have modified our IPS signatures to account for potential malicious traffic.<\/p>\n<h3>Conclusion<\/h3>\n<p>Due to the claim that the CVE is wormable, initially there was concerns that CVE-2022-21907 could potentially have a high impact. However, the combination that IIS is seldom enable on Windows 10, and the fact that the attacker does not have a direct way to create read or write primitives into kernel memory, lessen the risk somewhat.<\/p>\n<h3>Fortinet Protections<\/h3>\n<p>ForiGuard IPS protects against all known exploits associated with the CVE with the following signature:<\/p>\n<p>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 MS.Windows.HTTP.Protocol.Stack.CVE-2022-21907.Code.Execution<\/p>\n<p>However, due to the unpredictable nature of malformed HTTP packets, we strongly urge organizations to apply the corresponding patches as quickly as possible to avoid service disruption. FortiGuard Labs will continue to monitor the CVE and apply new countermeasures when necessary.<\/p>\n<h3>Appendix:<\/h3>\n<p><a href=\"https:\/\/msrc.microsoft.com\/update-guide\/vulnerability\/CVE-2022-21907\" target=\"_blank\">https:\/\/msrc.microsoft.com\/update-guide\/vulnerability\/CVE-2022-21907<\/a><\/p>\n<p><a href=\"https:\/\/twitter.com\/wdormann\/status\/1488148028317917186\" target=\"_blank\">https:\/\/twitter.com\/wdormann\/status\/1488148028317917186<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/en-us\/windows-hardware\/drivers\/ddi\/wdm\/nf-wdm-mmunmaplockedpages\" target=\"_blank\">https:\/\/docs.microsoft.com\/en-us\/windows-hardware\/drivers\/ddi\/wdm\/nf-wdm-mmunmaplockedpages<\/a><\/p>\n<\/p><\/div>\n<div class=\"raw-import aem-GridColumn aem-GridColumn--default--12\">\n<div class=\"text-container\">\n<div id=\"om-qbkzwxxbiv83f0ol5a2d-holder\"><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<p><a href=\"https:\/\/www.fortinet.com\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\" target=\"bwo\" >http:\/\/feeds.feedburner.com\/fortinet\/blog\/threat-research<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p><img decoding=\"async\" src=\"\/blog\/threat-research\/analysis-of-microsoft-cve-2022-21907\/_jcr_content\/root\/responsivegrid\/image.img.png\/1644952203164\/mstimg1.png\"\/><br \/>Microsoft released a patch for CVE-2022-21907 as part of Microsoft\u2019s Patch Tuesday. In this blog,  FortiGuard Labs researchers analyze the cause of the vulnerability and how attackers can exploit it.<\/p>\n","protected":false},"author":4,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"colormag_page_container_layout":"default_layout","colormag_page_sidebar_layout":"default_layout","footnotes":""},"categories":[10424,10378],"tags":[],"class_list":["post-18302","post","type-post","status-publish","format-standard","hentry","category-fortinet","category-security"],"_links":{"self":[{"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/posts\/18302","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/comments?post=18302"}],"version-history":[{"count":0,"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/posts\/18302\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/media?parent=18302"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/categories?post=18302"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/tags?post=18302"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}