.NET has done a lot of good things & some would argue has made development easier and faster letting us developers worry less about things like memory management and more about things like creating web applications, business applications web APIs. These are all good things, however somewhere in not having to worry about trivial issues like memory management, a skill set has been lost. With that lost skill set, the end result is a security gap, and the reasoning goes something like this:
- Security Analyst – "Sensitive information (PII) – is being stored in .NET Strings, insecurely"
- Developer – "That maybe true however that information only exists until the garbage collector runs, plus my strings are allocated on the stack right?"
- Security Analyst – ".NET Strings are objects and not allocated on the stack, they’re allocated on the process’s virtual memory heap, and you have no guarantee of when the garbage collector will run"
- Developer – "If they’re allocated in the virtual process memory, then I am safe, reading another process’s virtual memory isn’t that easy – Plus the garbage collector will clean it up"
- Security Analyst – "It’s insecure, reading the processes’ memory is easy, and even virtual managed memory can be exploited"
- Developer – "But the garbage collector will clean it, I don’t have time to do this I’ve got these other features to finish".
The reality is yes business features need to get finished and the security analyst should work with development not be a road block to development.
Exploiting Managed Memory is much easier then, most folks would think, let's consider how it’s done. If we consider the following code snippet:
void WorkerThread::WriteMemDmp(HANDLE hProc)
HANDLE hFile = CreateFile(L"C:\\Test\\Proc.dmp",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ,
0,
CREATE_ALWAYS,
0,
0);
if ( ( hFile != NULL ) && ( hFile != INVALID_HANDLE_VALUE ) )
{
if (!MiniDumpWriteDump( hProc, GetProcessId(hProc),hFile, MiniDumpWithFullMemory,0,0,0))
{
std::cout<< "Mini Dump Error:" << GetLastError() << std::endl;
}
}
FlushFileBuffers(hFile);
CloseHandle(hFile);
}
What this snippet does is it will create a Windows Mini Dump with full memory dumped out to a particular file in this case Proc.dmp. When the memory of the process is dumped out, any and all information contained in the managed memory heap is written to the disk. Congratulations! You've just succeeded in exploiting managed memory. The really cool thing about this function is that, it doesn't interrupt the process that has been dumped. That process will just continue on, allowing its memory to be dumped again and again. Anything stored in a normal .NET string is written to the dump file in plain text.
At this point, it's quite easy for the attacker to add some extra logic to their application to continue exploiting managed memory, said attacker could, upload the dump file to an FTP server or some other server on the Internet for further consumption. Reading and consuming a MiniDumpFile
isn't that difficult there are tools like WinDbg which will do it for you, however some difficulty may be encountered without the symbols, however as I said you don't really need them because all the information is written in plain text anyway. All one needs to do is scrape the binary text for normal looking strings and then apply some logic, extracting e-mail, user names, real names, phone numbers, credit card data can all be accomplished using a some RegEx string processing on the dump file to filter the junk from the actual data.
If you're thinking that well I work on a web application, using ASP.NET/MVC, I should be ok, the folks writing desktop applications need to worry about this one, could not be more wrong. When a browser makes a request via IIS for a web application, IIS allocates a worker process to handle the requests and processing of the request. Worker processes are allocated as w3wp.exe processes. The same code snippet above allows for creating a mini dump of these processes too, therefore all the information contained within these processes is exploitable and easily accessible, the one caveat is that by nature of being a web application, an attacker would need to find a way to install their "application" which creates a memory dump of a process on your server. This often does add a minor layer of complexity to the attacker however it's not impossible.
Big companies like Yahoo are being attacked as recently as Jan of 2014 by having malware installed on their servers, thus the attacker was able to defeat the security attempts of the IT infrastructure team and get their malware application launched on Yahoo's servers. Another example is Target, who was recently attacked with POS intrusion software. There are many other examples one only needs to search the web, however these two intrusions demonstrate that it's in fact possible for attackers to bypass IT security and install their custom applications.
So What Does This Mean?
The bottom line is that it's no longer acceptable for one department to rely on another department. Development teams cannot create insecure software, and rely on their colleagues in IT infrastructure to keep their web applications secure. If you're deploying a .NET desktop application, then security of your users is 100% your responsibility. .NET provides some security mechanisms for securing your data such as the way underutilized Secure String Class. In my opinion, when dealing with my secure data, or my PII there is no justification whatsoever for storing, using and moving the data around in a secure string and converting to a non-secure string just before the data needs to be presented to the user. Alternatively if development teams refuse to use SecureStrings
in their .NET code for whatever reason, then at the very least encrypting, NOT HASHING is a viable alternative. However, I've seen far too many instances where the data of a web application or a desktop/lite client application are stored in storage, encrypted, yet decrypted & stored in, insecure strings long before the data needs to be presented to the user, or without presenting the data to the user at all and my question is...
WHY?
Exploiting Managed Memory is easy, quick & simple to do, it's time that we developers, engineers, start taking security seriously & protecting our users. All of this being said, it should be noted that memory allocated in native application processes is not immune from the same trick. If using a native application, secure information should be protected using encryption or Windows DPAPI is a good alternative.
Someone suggested to me that, by the time someone has injected their code on your server, then it's too late. This is generally a good point to think about if someone does manage to get their code or application on your box, yes you've got a world of hurt coming your way. However, developers/engineers should always be thinking about security in defense, if someone does manage to get a malware like process on your box exploiting what I've shown, what will they find? Anything, something, lots of information? A little information? I am not suggesting this is needed to prevent people from attacking your box or getting their malware processes running and stealing your memory. I am advocating this, for when it does happen, that the attacker won't be able to find much and you'll protect your user's data, and that data will stay protected while you clean up and fix the issues.
When a bank robbery goes down, yes it's a bad thing and the robbers usually make off with a little bit of money. However! The bank mitigates the risk of loss, by not having a HUGE sum of money just sitting on the counter for anyone to steal. So too here, yes when someone does attack your server or application, there is a good chance they will steal some data, but if you're the bank, would you rather have 1,000$ stolen or 1,000,000$? As an engineer, would you rather have data from 10 of your users's stolen or 10,000,000 users?