This is a friendly warning that your web-browser does not currently protecting your privacy and/or security as well as you might want. Click on this message to see more information about the issue(s) that were detected. June 21st, 2016 Magic values in 32-bit processes and 64-bit OS-es

Magic values in 32-bit processes on 64-bit OS-es

Software components such as memory managers often use magic values to mark memory as having a certain state. These magic values can be used during debugging to determine the state of the memory, and have often (but not always) been chosen to coincide with addresses that fall outside of the user-land address space on 32-bit versions of the Operating System. This can help detect vulnerabilities by causing an access violation when such magic value is used as a pointer as well as mitigate exploitation of such vulnerabilities by making it impossible to have this "poisoned" pointer refer allocated memory under the attacker's control.

For instance, Microsoft's C++ debugging runtime library initializes stack memory to 0x­CCCCCCCC. When an uninitialized object pointer is used to read the value of a property or call a method of the object, this reliably causes an access violation on 32-bit versions of Microsoft Windows and prevents an easy path to exploitation.

The Wikipedia article on magic values has a list containing some of the values and when they are used. You will notice how all of the values used on Windows have their high bit set (i.e. >= 0x80000000). As explain earlier, this is because on 32-bit versions of Windows these addresses cannot be used to allocate memory in user-land by default. Windows does have a /3GB switch that allows you to change the upper limit for user-land memory to 0x­C0000000, but AFAIK this is not used very often and still excludes a large number of magic values.

Magic values on 64-bit OS-es

On 64-bit architectures, there is no need to reserve part of the 32-bit address space for kernel memory. Consequently, a 32-bit applications running on 64-bit versions of Windows is able to allocate memory in almost the entire 32-bit address range. This allows 32-bit applications to allocate more memory, including at all addresses that these magic values can reference. Ever since their introduction over 10 years ago, Javascript heap-sprays in web-browsers in particular offers an attacker the ability to finely control memory allocations and their content for use in exploits.

Proof-of-Concept

Last year I stumbled upon two different bugs in two different web browsers where a magic value was used to mark memory, and subsequently used as a pointer. Using Javascript, it was possible to allocate memory at the address based on the magic values the web browsers were using and store information at this location to exploit both of these two vulnerabilities. These issues have both been address, so I can discuss them in more detail here.

CVE-2014-1592 Firefox xul.dll!ns­Html5Tree­Operation use of poisoned memory

Mozilla 1088635 covers a bug in Firefox that could it to use data from a freed and "poisoned" object through specially crafted HTML, which resulted in access violations around address 0x5a5a5a5a on x86 systems. The memory used to back the object was marked with this magic value after it was freed. Because this magic value resulted in an address can be allocated even on 32-bit versions of Windows, I suggested in Mozilla 1182002 that the value get updated with something that makes it a little harder to exploit. This and other reasons for changing the magic values, led to magic values being changed to 0xe4e4e4e4 for uninitialized memory and 0xe5e5e5e5 for freed memory.

Repro

<script>
  window.onload = function() {
    o­Menu­Element = document.create­Element("MENU");
    document.open();
    document.insert­Before(o­Menu­Element, null);
    document.write("<script></"+"script>\n");
  };
</script>

Description

The repro caused the ns­Html5Tree­Operation's m­One member object to be freed. The freed memory was not immediately released, but poisoned by filling it with "z" (0x5a). A pointer to the freed object is kept in m­One and continued to be used. The repro caused xul!ns­Html5Tree­Operation::Perform to pass the node member of m­One to xul!ns­Html5Tree­Operation::Append­Text as a pointer to an object, but because the pointer's value was 0x5a5a5a5a, this caused an access violation.

Exploit

It should have been fairly straightforward to exploit this issue using a run-of-the-mill heap-spray when the magic value was still 0x5a5a5a5a. but after the magic value was changed to the new, higher values, the issue can no longer be exploited on 32-bit versions of Windows, as memory cannot be allocated at addresses starting with 0xe4 or 0xe5 on 32-bit versions of Windows.

verifier!AVrf­Debug­Page­Heap­Allocate incorrect memory initialization a.k.a Google Chrome use of uninitialized FLS pointer

In August last year, I found what appear to be a thread-safety vulnerability in Google Chrome when handling audio data, that could lead to use of an uninitialized pointer. This issue is only visible when running Chrome with page heap enabled, as the memory used to store the pointer appears to be set to 0x00000000 after allocation when page heap is not enabled. This means this NULL pointer will not be used by the code to reference memory. However, when running Chrome with page heap enabled, the pointer will be initialized to 0x­D0D0D0D0 and gets used in code that allows at least freeing of arbitrary memory pointers.

Repro

<!doctype html>
<html><head>
<script>
  new Audio­Context("notification").decode­Audio­Data(
    new Array­Buffer(1),
    function(){},
    function(){}
  );
  location.reload();
</script></head></html>

Description

The repro triggers a race condition in the Audio­Output­Device thread, where the thread is terminated before a pointer to fiber local storage (FLS) is initialized.

When the thread is terminated and the FLS pointer is not NULL, the FLS pointer is passed to msvcrt!_freefls, which assumes it points to a structure with some more pointers. For a number of pointer in the structure, it calls msvcrt!free if they are not NULL.

Exploit

An attacker could use a heap spray to allocate memory around address 0x­D0D0D0D0 and have the uninitialized pointer point to whatever data is useful. When the msvcrt!_freefls function is called, it will process that attacker supplied data.

Chromium 525288 Po­C.html <!DOCTYPE html> <head> <script type="text/javascript"> function element­Load­Callback() { var o­Element = window.event.target; set­Timeout(function() { document.body.remove­Child(o­Element); document.body.offset­Top; document.body.append­Child(o­Element); }, Math.random() * 500); } window.onload = function() { for (var u = 0; u < 20; u++) { var o­IFrame = document.body.append­Child(document.create­Element("iframe")); o­IFrame.onload = element­Load­Callback; o­IFrame.src = "repro.mp3"; // This can be an empty file. o­IFrame.width = o­IFrame.height = 10; } } set­Timeout(function() { location.reload(); }, 5000); </script> </head> <body> </body> </html>

The above code allocates a Uint32Array that is so large it will only fit in the (assumed) unused area above 0x80000000. This causes it to be reliably allocated at address 0x80004000. Using this array, a pointer at 0x­D0D0D0D0 + 0x24 is set to 0x­DEADBEEF. When msvcrt!_freefls is called with the uninitialized FLS pointer, it will check if the pointer at 0x24 is not NULL and call msvcrt!free to free the memory it points to. This leads to an attempt to free memory at address 0x­DEADBEEF, which should result in a crash.

verifier!AVrf­Debug­Page­Heap­Allocate incorrect memory initialization

After doing a more thorough analysis, Ricky Zhou explained to me in the Chromium bug that the issue is not in Chromium, but in verifier.dll. This DLL is used to implement page heap on Windows. The problem is that in verifier!AVrf­Debug­Page­Heap­Allocate, the HEAP_­ZERO_­MEMORY flag is sometimes ignored, which in this case caused the memory to get initialized with the wrong value. I reported this issue to Microsoft at the end of October last year and after getting the MSRC case number 31596, I did not hear back from them again until after I reached out again when I was writing this blog. Microsoft informed me that they consider this attack scenario too limited to warrant a security updated.

Mitigating this type of attack

While working on these issues, I realized that this type of attack is easy to mitigate by making sure the magic values point to memory that has been reserved and marked inaccessible. That way there is no risk of an attacker allocating the memory with data under his/her control for use in an exploit: whenever the application would attempt to access memory using a magic value as a pointer, this would reliably cause an access violation.

Having a memory allocation at the various addresses represented by common magic values fragments the address space, reducing the largest possible continuous allocation and the total amount of memory available to the application. But most 32-bit applications do not depend on being able to allocate such large chunks of memory for normal operations, as this is impossible on 32-bit versions of Windows. Regardless, should one want to prevent this fragmentation, and at the same time organize the magic values to be more coherent and intuitive to developers, it might be useful to create an API that can be used to generate the magic values, and have the generated values be more similar, closer together and/or located at either edge of the free memory above address 0x80000000. It might make particular sense to use addresses towards the higher end (0x­FFxxxxxx) as adding a large enough offset to overflow the 32-bit address would have a large chance of resulting in a NULL pointer; which would still cause an access violation.

Such a "magic value API" could implement this mitigation during start-up of a process, and reserve a chunk of the address space for use with magic values. The API then allows the application to request magic values which would be sequential addresses at the start of the reserved memory region, so that when an offset gets added to them, the resulting address would still be very likely to fall within in. This API would provide different 32-bit magic values, which may not always be desired, for instance in the case of the Firefox memory allocator, which fills memory with one specific byte, repeated over and over. The API could therefore also allow the application to request a byte, at which point the API would find an address consisting of the same four bytes and reserve it before returning it. This would increase memory fragmentation, but not by much (assuming the number of magic values needed is in the order of two or three, as is the case with Firefox).

I have suggested adding mitigations such as this API to MSRC and they responded in November 2015 that they forwarded it to the Windows team for their consideration.

Obviously, this type of mitigation may be of interest to authors of security software that aims to mitigate exploitation of 0-day: it should be possible to:

  1. actively reserve memory regions referenced by such pointers to prevent allocation by an exploit. The additional address space fragmentation should not be a problem for most applications, but I have no data to back this up, so you might want to:
  2. analyze various binaries for their use of magic values, and actively reserve only those memory regions referenced by such pointers. If that still causes problems in some applications, you could:
  3. white-/black-list applications for this mitigation.
© Copyright 2019 by Sky­Lined. Last updated on September 9th, 2019. Creative Commons License This work is licensed under a Creative Commons Attribution-Non‑Commercial 4.0 International License. If you find this web-site useful and would like to make a donation, you can send bitcoin to 183yyxa9s1s1f7JBp­PHPmz­Q346y91Rx5DX.