3

Some time ago I read about various security recommendations for C/C++. After that I started thinking if they apply to .NET I found some answers but not all so here are my questions.

It is a recommended to use HeapAlloc method instead of VirtualAlloc to allocate memory. There are 2 potential problems with VirtualAlloc that I'm aware of. Firstly, prior to Windows 8, addresses allocated by this function are not randomized by ASLR (Address Space Layout Randomization). Secondly, VirtualAlloc allow one to allocate memory using fixed base address what is also not suggested because makes writing exploits easier. For details see also this article.

The question is how new operator works under the hood? Does it use HeapAlloc, VirtualAlloc or maybe something else?

It is also suggested to not use directly function pointers but to obfuscate and de-obfuscate them when needed by using EncodePointer/DecodePointer functions. It is a concept somehow similar to ASRL. The goal of this technique is to make it difficult to predict a pointer value and override it so that it will point some malicious code. We have delegates in .NET however I think that under the hood .NET must use function pointers at some point.

The question is if addresses of functions pointers used internally by .NET are being obfuscated?

Michał Komorowski
  • 6,198
  • 1
  • 20
  • 24

2 Answers2

3

Details are fairly obscure, I don't spend a lot of time looking for ways to attack .NET processes :) What I know is in place:

  • .NET assemblies have the /DYNAMICBASE option turned on, same one that native programs use to enable ASLR.
  • .NET assemblies have the /HIGHENTROPYVA option turned on by default. The C# compiler exposes the /highentropyva compiler option to control this.
  • The CLR allocates exclusively with VirtualAlloc(). It implements its own brand of ASLR by randomizing the addresses of an appdomain's loader heap (jitted code, statics, types, etc) and the GC heap segments. This occurs for every single run of the program. The thread stacks are randomized too, probably because of the previous options.
  • Exception filters are located with a table lookup, not pointers on the stack. Same as /SAFESEH
  • The native code in a .NET program (jitter, CLR, CRT) has /GS turned on since .NET 4.0, detects stack smashing attempts.

No EncodePointer() calls, I doubt that they could work. I never heard of a successful attack against a .NET program, it is a pretty tall order to infect managed code with malicious data. But who knows. There have been a fairly large number of security updates over the years so somebody figured out something :)

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
2

All of this only applies to you if you are using unsafe code or PInvoke (which also requires full trust). For safe managed code this issue does not apply because the CLR is specified in such a way that you cannot break memory safety. Therefore, there is nothing to exploit that can be prevented by randomizing addresses. Addresses are not exposed in safe managed code (in any usable way).

Managed code new (as opposed to native new) uses the managed heap. Heap memory is fetched from the OS by using VirtualAlloc. I don't know whether it's location is randomized. Not every new invocation causes a new OS allocation. Many objects fit into one OS allocation.

delegate is indeed a function pointer under the hood. It is not obfuscated (presumably for performance reasons). Most delegates point to jitted code on the code heap which, presumably, is allocated using VirtualAlloc (or loaded via LoadLibrary when NGEN is in use).

.NET assumes that your process is not being "hacked" by an attacker being able to write arbitrary bytes. If that is the case all security guarantees are out of the window.

Therefore, I find the issues that you raise not particularly concerning. This is a question of security in depth which is good to have but not required.

usr
  • 168,620
  • 35
  • 240
  • 369
  • I find your comments to be extremely naïve in regards to security. .NET assumes you aren't being attacked? There are many ways to write or read arbitrary bytes from memory. A classic example was the "Shatter Attack" which used Windows Edit controls to post messages which would cause your own program to attack itself internally. This has been fixed in Vista and later, but .NET is still supported on Windows 2003, for instance... – Erik Funkenbusch Apr 09 '15 at 09:40
  • .NET can't do anything against attacks such as the shatter attack. There's only defense in depth (which is a good thing but never enough). And safe managed code cannot in any way read or write arbitrary bytes. In this answer I differentiate clearly between what's true for safe code and what's true for unsafe code. If you disagree comment more specifically. – usr Apr 09 '15 at 09:42
  • I think you're inadvertently being misleading with that statement. Since no .NET code is an island.. It has to call framework and library functions, many of which are unsafe underneath. For instance, there have been flaws in jpeg image compression libraries, and zip compression libraries that have caused buffer overflow vulnerabilities, and there are cve's of buffer overflow exploits for .net framework functions. Does it matter if the code I write can't read or write arbitrary bytes if the code it depends on can? – Erik Funkenbusch Apr 09 '15 at 09:49
  • Those are all valid exploits but there's only defense in depth that .NET can do against this. What is your point actually? That defense in depth is important? True, but what .NET can do against arbitrary memory writes by an attacker is extremely limited. – usr Apr 09 '15 at 09:52
  • You mean, besides following the guidelines that Microsoft has established that the question is referring to, but doesn't do? I would hope Roslyn and RyuJIT is better about this. – Erik Funkenbusch Apr 09 '15 at 09:53