{"id":7947,"date":"2017-06-14T08:40:02","date_gmt":"2017-06-14T16:40:02","guid":{"rendered":"http:\/\/www.palada.net\/index.php\/2017\/06\/14\/news-1728\/"},"modified":"2017-06-14T08:40:02","modified_gmt":"2017-06-14T16:40:02","slug":"news-1728","status":"publish","type":"post","link":"http:\/\/www.palada.net\/index.php\/2017\/06\/14\/news-1728\/","title":{"rendered":"WINS Server Remote Memory Corruption Vulnerability in Microsoft Windows Server"},"content":{"rendered":"<p><strong>Credit to Author: Honggang Ren| Date: Wed, 14 Jun 2017 16:19:29 +0000<\/strong><\/p>\n<div class=\"entry\">\n<h2>Summary<\/h2>\n<p align=\"left\">In December 2016, FortiGuard Labs discovered and reported a WINS Server remote memory corruption vulnerability in Microsoft Windows Server. In June of 2017, Microsoft replied to FortiGuard Labs, saying, &quot;a fix would require a complete overhaul of the code to be considered comprehensive. The functionality provided by WINS was replaced by DNS and Microsoft has advised customers to migrate away from it.&quot; That is, Microsoft will not be patching this vulnerability due to the amount of work that would be required. Instead, Microsoft is recommending that users replace WINS with DNS.<\/p>\n<p align=\"left\">This vulnerability affects Windows Server 2008, 2012, and 2016 versions. The vulnerability exists because a remote memory corruption is triggered when handling malformed WINS packets.<\/p>\n<p align=\"left\">In this blog, I want to share the details of this vulnerability.<\/p>\n<h2>Reproducing the Vulnerability<\/h2>\n<p align=\"left\">To reproduce this vulnerability, follow the steps below.<\/p>\n<ol>\n<li align=\"left\">Install &quot;WINS Server&quot; in &quot;Server Manager&quot; on an affected version of the Windows Server. For this case, we are using Windows Server 2016. Follow the &quot;Server Manager&quot; install wizard, then check the option &quot;WINS Server.&quot; See the screenshot in Figure 1.<\/li>\n<\/ol>\n<p align=\"center\" style=\"margin-left:.25in;\"><img decoding=\"async\" alt=\"\" center=\"\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/WINS001.png\" style=\"width: 75%; \/&gt;&lt;\/p&gt;    &lt;p align=\" \/>Figure 1. Installing WINS Server service<\/p>\n<ol>\n<li align=\"left\" value=\"2\">Open &quot;Control Panel&quot; -&gt; &quot;Administrative Tools&quot; -&gt; &quot;WINS.&quot; Then navigate to &quot;WINS&quot; -&gt; &quot;Replication Partners,&quot; right click &quot;Replication Partners,&quot; and choose &quot;New Replication Partner.&quot; See the screenshot in Figure&nbsp;<\/li>\n<\/ol>\n<p align=\"center\" style=\"margin-left:.25in;\"><img decoding=\"async\" alt=\"\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/WINS002.png\" style=\"width: 624px; height: 444px;\" \/><\/p>\n<p align=\"center\">Figure 2. Creating WINS Replication Partner<\/p>\n<ol>\n<li align=\"left\" value=\"3\">In the popup dialog, input the WINS server IP address and click OK. Please note, the WINS server IP address must be the attacker&rsquo;s host IP address. In my test, the IP address is 10.0.0.1. See the screenshot in Figure 3.<\/li>\n<\/ol>\n<p align=\"center\" style=\"margin-left:.25in;\"><img decoding=\"async\" alt=\"\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/WINS003.png\" \/><\/p>\n<p align=\"center\">Figure 3. Inputting the WINS Server IP address<\/p>\n<ol>\n<li align=\"left\" value=\"4\">On another machine, such as Windows 7 x64 (its IP address must be the WINS server IP address you input in step 3), run the PoC in CLI, like &quot;trigger_poc.py&quot;. After the packet is sent, you can see that the WINS Server service on Windows Server 2016 stops working or the process automatically restarts with a new pid. You can continue running the PoC until the WINS Server service stops working due to a remote memory corruption. Figure 4 shows the capture of the attack packets.<\/li>\n<\/ol>\n<p align=\"center\" style=\"margin-left:.25in;\"><img decoding=\"async\" alt=\"\" center=\"\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/WINS004.png\" style=\"width: 75%;  \/&gt;&lt;\/p&gt;    &lt;p align=\" \/>Figure 4. The capture of the attack packets<\/p>\n<h2>Analysis<\/h2>\n<p align=\"left\">This vulnerability exists because Windows Server doesn&rsquo;t properly deal with multiple pending WINS-Replication sessions. So let&rsquo;s take a look at the packet capture first. See Figure 5.<\/p>\n<p align=\"center\"><img decoding=\"async\" alt=\"\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/WINS005.png\" style=\"width: 75%;\" \/><\/p>\n<p align=\"center\">Figure 5. The data in the attack packet<\/p>\n<p align=\"left\">The vulnerability is triggered when dealing with multiple (&gt;3) pending WINS-Replication sessions with replication command WREPL_REPL_UPDATE2 (0x00000005). It results in &ldquo;int 29h&rdquo; with error code 0xC0000409. See Figure 6.<\/p>\n<p align=\"center\"><img decoding=\"async\" alt=\"\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/WINS006.png\" style=\"width: 709px; height: 421px;\" \/><\/p>\n<p align=\"center\">Figure 6. &ldquo;int 29h&rdquo; with error code 0xC0000409<\/p>\n<p align=\"left\">The &ldquo;int 29h&rdquo; is the New Security Assertion found in Windows 8 or newer versions. It has many assertion items. Here, the assertion checks the following condition in pseudo code: <span style=\"color:#FF0000;\">corrupted list pointers<\/span>.<\/p>\n<blockquote>\n<pre align=\"left\">      if (((Entry-&gt;Flink)-&gt;Blink) != Entry)        {            mov ecx,3            int 29h    }<\/pre>\n<\/blockquote>\n<p align=\"left\">When we establish multiple pending WINS-Replication sessions, the list pointers become corrupted. The root cause is that the same buffer is deallocated to the list pool multiple times. See the following code:<\/p>\n<blockquote>\n<pre align=\"left\">  .text:00007FF7F87E35D4 DeallocEnt      proc near      ; CODE XREF: CommAssocDeallocAssoc+2Ap    .text:00007FF7F87E35D4                                         ; CommAssocDeallocDlg+2Ap    .text:00007FF7F87E35D4                                         ; DATA XREF: ...    .text:00007FF7F87E35D4    .text:00007FF7F87E35D4 arg_0           = qword ptr  8    .text:00007FF7F87E35D4 arg_8           = qword ptr  10h    .text:00007FF7F87E35D4 arg_10          = qword ptr  18h    .text:00007FF7F87E35D4 arg_20          = qword ptr  28h    .text:00007FF7F87E35D4 arg_28          = qword ptr  30h    .text:00007FF7F87E35D4    .text:00007FF7F87E35D4                 mov     [rsp+arg_0], rbx    .text:00007FF7F87E35D9                 mov     [rsp+arg_8], rsi    .text:00007FF7F87E35DE                 mov     [rsp+arg_10], r8    .text:00007FF7F87E35E3                 push    rdi    .text:00007FF7F87E35E4                 sub     rsp, 20h    .text:00007FF7F87E35E8                 mov     rbx, r9    .text:00007FF7F87E35EB                 mov     rsi, r8    .text:00007FF7F87E35EE                 mov     rdi, rdx  ---&gt; <span style=\"color:#FF0000;\">rdi points to the head of the list (rdx, named entry A here) which equals sAssocQueHd global variable<\/span>    .text:00007FF7F87E35F1                 mov     rcx, r8         ; lpCriticalSection    .text:00007FF7F87E35F4                 call    cs:__imp_EnterCriticalSection    .text:00007FF7F87E35FA                 nop    .text:00007FF7F87E35FB                 inc     dword ptr [rbx]    .text:00007FF7F87E35FD                 mov     eax, [rbx]    .text:00007FF7F87E35FF                 mov     rbx, [rsp+28h+arg_20] ; ---&gt; <span style=\"color:#FF0000;\">rbx points to the entry B, which will be deallocated<\/span>    .text:00007FF7F87E3604                 mov     [rbx+10h], eax    .text:00007FF7F87E3607                 mov     rax, [rdi+8]    .text:00007FF7F87E360B                 cmp     [rax], rdi    .text:00007FF7F87E360E                 jz      short loc_7FF7F87E3617    .text:00007FF7F87E3610                 mov     ecx, 3    .text:00007FF7F87E3615                 int     29h             ; Win8: RtlFailFast(ecx)    .text:00007FF7F87E3617    .text:00007FF7F87E3617 loc_7FF7F87E3617:                       ; CODE XREF: DeallocEnt+3Aj    .text:00007FF7F87E3617                 mov     [rbx], rdi     ---&gt; <span style=\"color:#FF0000;\">entry B&rsquo;s Blink points to entry A  <\/span>  .text:00007FF7F87E361A                 mov     [rbx+8], rax   ---&gt; <span style=\"color:#FF0000;\">entry B&rsquo;s Flink points to entry C<\/span>    .text:00007FF7F87E361E                 mov     [rax], rbx    ----&gt;   <span style=\"color:#FF0000;\">set entry C&rsquo;s Blink to entry B<\/span>    .text:00007FF7F87E3621                 mov     [rdi+8], rbx  ----&gt;   <span style=\"color:#FF0000;\">set entry A&rsquo;s Flink to entry B<\/span>    .text:00007FF7F87E3625                 mov     rdi, [rsp+28h+arg_28]    .text:00007FF7F87E362A                 cmp     dword ptr [rdi], 64h    ...<\/pre>\n<\/blockquote>\n<p align=\"left\">In the above list, the Flink pointer points to the next entry in the list, and the Blink pointer points to the previous entry in the list.<\/p>\n<p align=\"left\">In the PoC, after session 1,2,3 send two packets and stay in the pending state (the session is not terminated by a TCP reset packet), the deallocate function will be first called with the entry B pointer, for example, 0x1f11306ff70. The entry A (ListHead) always equals the sAssocQueHd global variable. The assignment is done in the parent function. So after entry B is deallocated, entry C doesn&rsquo;t exist in the first deallocation. The entry relationship is shown in following chart.<\/p>\n<p align=\"left\"><img decoding=\"async\" alt=\"\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/WINS007.png\" style=\"width: 702px; height: 302px;\" \/><\/p>\n<p align=\"left\">Then the deallocate function will be called the second time with entry B pointer, which still equals 0x1f11306ff70. Entry A (ListHead) equals the sAssocQueHd global variable. So after entry B is deallocated, no new entry is added. The entry relationship is shown in the following chart.<\/p>\n<p align=\"left\"><img decoding=\"async\" alt=\"\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/WINS008.png\" style=\"width: 745px; height: 327px;\" \/><\/p>\n<p align=\"left\">As you can clearly see, after the deallocate function is called twice, both the Flink and Blink of List Element Entry B point to themselves. This results in the list error.<\/p>\n<p align=\"left\">Then the deallocate function will be called the third time. So <span style=\"color:#FF0000;\">&ldquo;int 29h&rdquo; is triggered due to the corrupted list pointer check.<\/span><\/p>\n<blockquote>\n<pre align=\"left\">      if (((Entry-&gt;Flink)-&gt;Blink) != Entry)        {            mov ecx,3            int 29h    }<\/pre>\n<\/blockquote>\n<p align=\"left\">The object pointer is set to the same pointer when dealing with Assoc_Ctx of WREPL_REPL_UPDATE2 packet in the following function:<\/p>\n<blockquote>\n<pre align=\"left\">  .text:00007FF7F87E0190 ProcTcpMsg      proc near               ; CODE XREF: MonTcp+4C5p    .text:00007FF7F87E0190               ; DATA XREF: .pdata:00007FF7F88077D4o    .text:00007FF7F87E0190    ......    .text:00007FF7F87E0284 loc_7FF7F87E0284:                  ; CODE XREF: ProcTcpMsg+EDj    .text:00007FF7F87E0284                 mov     ecx, [r15+4]    ---&gt; <span style=\"color:#FF0000;\">netlong here was obtained from the second packet (Wirehark parses it as &quot;WINS-Replication WREPL_REPL_UPDATE2&quot;), &quot;Assoc_Ctx&quot;=&quot;00 00 00 3f&quot;.<\/span>    .text:00007FF7F87E0288           call    cs:__imp_ntohl    .text:00007FF7F87E028E           mov     esi, eax        ---&gt; <span style=\"color:#FF0000;\">here esi=0x3f<\/span>    .text:00007FF7F87E0290           mov     ecx, [r15+8]    ; netlong    ......    .text:00007FF7F87E0382 loc_7FF7F87E0382:                       ; CODE XREF: ProcTcpMsg+1EAj    .text:00007FF7F87E0382           lea     ecx, [rsi-1]    .text:00007FF7F87E0385           mov     rax, qword ptr cs:xmmword_7FF7F8804D28    .text:00007FF7F87E038C           mov     rbx, [rax+rcx*8] ; ---&gt; <span style=\"color:#FF0000;\">here rbx = poi(7FF7F8804D28)+0x3e*8, because rcx is obtained from Assoc_Ctx=0x3f -1<\/span>    .text:00007FF7F87E0390           xor     esi, esi<\/pre>\n<\/blockquote>\n<p align=\"left\">From the above code snippet you can see that once the object pointer <span style=\"color:#FF0000;\">poi(poi(7FF7F8804D28)+0x3e*8<\/span> is obtained, the final target pointer (the previously passed entry B pointer) is determinate in the first deallocate function call. It is assigned to entry B pointer. In the second and third deallocate function calls, the final target pointer (entry B pointer) keeps same. In my test, it is 000001f1`1306ff70. This causes the list corruption.<\/p>\n<p align=\"left\">Note: poi is a function of getting the value of the address.<\/p>\n<p align=\"left\">In summary, the vulnerability is caused by multiple (&gt;3) pending WINS-Replication sessions with the replication command WREPL_REPL_UPDATE2 (this is the key to triggering this vulnerability.) The result is that the same list entry is deallocated multiple times, which causes remote memory corruption.<\/p>\n<h2>Mitigation<\/h2>\n<p align=\"left\">All users of vulnerable Microsoft Windows Server are encouraged to migrate away from the WINS server immediately. Additionally, organizations that have deployed Fortinet IPS solutions are already protected from this vulnerability with the signature MS.Windows.WINS.Server.Remote.Memory.Corruption.<\/p>\n<\/div<br \/><a href=\"https:\/\/blog.fortinet.com\/2017\/06\/14\/wins-server-remote-memory-corruption-vulnerability-in-microsoft-windows-server\" target=\"bwo\" >https:\/\/blog.fortinet.com\/feed<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p><img decoding=\"async\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/WINS001.png\"\/><\/p>\n<p><strong>Credit to Author: Honggang Ren| Date: Wed, 14 Jun 2017 16:19:29 +0000<\/strong><\/p>\n<p>Summary    In December 2016, FortiGuard Labs discovered and reported a WINS Server remote memory corruption vulnerability in Microsoft Windows Server. In June of 2017, Microsoft replied to FortiGuard Labs, saying, &quot;a fix would require a complete overhaul of the code to be considered comprehensive. The functionality provided by WINS was replaced by DNS and Microsoft has advised customers to migrate away from it.&quot; That is, Microsoft will not be patching this vulnerability due to the amount of work that would be required. Instead, Microsoft&#8230;<\/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-7947","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\/7947","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=7947"}],"version-history":[{"count":0,"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/posts\/7947\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/media?parent=7947"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/categories?post=7947"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/tags?post=7947"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}