Summary
Applications must store sensitive data such as passwords or cryptographic values in system memory in order to properly operate. However, secrets may be stored in memory that is accessible to an attacker or swapped out of memory and into swaps files. During this attack, the attacker sniffs the different types of memory available, including random access memory (RAM), virtual memory, dump files, and swap files in an attempt to recover sensitive information such as passwords or cryptographic keys.
It is recommended that you follow these steps in order to test for this bug:
- Step 1: Understand attack scenarios
- Step 2: Analyze causes and countermeasures
- Step 3: Start testing and exploring
- Step 4: Execute additional testing
Step 1: Understand Attack Scenarios
First, it is necessary to properly understand the types of temporary memory related to this vulnerability:
- RAM - physical memory that stores data used by running processes.
- Virtual memory - logical address space given by the system to each running process. It gets copied into random access memory and swapped out to swap files by the operating system.
- Swap files - RAM’s auxiliary storage. The operating system performs paging to swap the contents of RAM in and out of swap files.
- Memory dumps - Memory dumps are snapshots of a process’s virtual memory; they are created by the system when the process crashes.
Note that permanent storage of user files, databases, and the Windows registry is outside of the scope of this vulnerability. Permanent memory can be protected using permissions and relate to information disclosure attacks.
Memory sniffing bugs commonly relate to local attacks requiring access to the target computer. Once the attacker is logged in, he uses a tool to recover sensitive data such as passwords or keys from temporary memory.
In detail:
- Attacker logs in to target machine.*
- Attacker uses a script or tool to search memory for sensitive data. The attack ends if sensitive data is recovered is an unhashed/unencrypted form.
- If sensitive data is hashed or encrypted, the attacker uses a cryptographic attack to recover sensitive data in plain-text.
* Variations of this attack focus on capturing sensitive information without access to the target machine. For instance, forensic research shows that the contents of a computer’s RAM can be retrieved through a FireWire cable [i]. Furthermore, recent discoveries indicate that sensitive information from DRAM chips can be restored by removing them after the computer has been turned off.
Step 2: Analyze Causes and Countermeasures
The next step in testing for memory sniffing is to understand what causes this vulnerability and how to countermeasure it.
Clearing data structures containing sensitive information
A classic approach to protect against memory sniffing attacks is to clear data structures, such as arrays, used to temporarily store sensitive information. For instance, the code below is insecure:
void GetData(char *MFAddr) {
char pwd[64];
if (GetPasswordFromUser(pwd, sizeof(pwd))) {
if (ConnectToMainframe(MFAddr, pwd)) {
// Interaction with mainframe
}
}
}
The function GetPasswordFromUser copies a password provided by the user to the pwd character array. The application then returns from the function without cleaning the password from memory. To mitigate this attack, developers are encouraged to set the memory contents to zero after the process is done with the structure used to store it:
void GetData(char *MFAddr) {
char pwd[64];
if (GetPasswordFromUser(pwd, sizeof(pwd))) {
if (ConnectToMainframe(MFAddr, pwd)) {
// Interaction with mainframe
}
}
memset(pwd, 0, sizeof(pwd));
}
However, it is extremely important to know that memset might not work as intended if compiler optimizations are on. Make sure to turn off compiler optimizations if protecting your code using memset as shown above. For more information, refer to OWASP’s Insecure Compiler Optimization [ii].
Another way of clearing out memory is by traversing the array and setting each element to zero:
void erase_string(char *s) {
while(*s) { *s++ = 0; }
}
This technique is recommended, because it doesn’t depend on compiler optimizations or knowledge of the array’s size. To properly secure your application, it is suggested that you add similar zeroing-out techniques after returning from function calls that deal with sensitive data and also in every destructor of classes that deal with secrets such as passwords and cryptographic elements.
Locking sensitive memory
Zeroing out sensitive memory is an effective technique to keep sensitive data in virtual memory (and consequently in RAM and swap files) as briefly as possible. However, this data might still get swapped by the operating system’s paging system into swap files before the application has a chance to clean it, increasing the risk of harm from a memory sniffing attack.
It is possible to mitigate this condition by locking virtual address pages from being swapped. This can be achieved in the UNIX platforms by using mlock as below [iii]:
#include <sys/mman.h>
void *locking_alloc(size_t numbytes) {
static short have_warned = 0;
void *mem = malloc(numbytes);
if(mlock(mem, numbytes) && !have_warned) {
/* We probably do not have permission.
* Sometimes, it might not be possible to lock enough memory.
*/
fprintf(stderr, "Warning: Using insecure memory!\n");
have_warned = 1;
}
return mem;
}
In Windows, the Win32 API VirtualLock is used for the same purpose.
Disable the creation of dump files
An attacker might execute a memory sniffing attack by crashing an application and accessing the core dumps created by the system upon the crash. Any sensitive data loaded by the application into any data structure will appear in dump files for the attacker to leverage. To mitigate this condition, processes must disable the creation of dump files right from the start. This is achieved using the setrlimit API both in UNIX and Windows platforms [iv]:
char pwd[MAX_PWD_LEN];
if(setrlimit(RLIMIT_CORE, 0) != 0) {
/* deal with error */
}
fgets(pwd, MAX_PWD_LEN, stdin);
Additional countermeasures
Additional defenses against memory sniffing attacks include deleting the page file on reboot or shutdown (this can be done by setting a registry value in Windows), and using forensic tools to scrub all different types of system memory. In addition, research is moving towards encrypting the contents of RAM and swap files and storing the encryption key in hardware.
Step 3: Start Testing and Exploring
Now that you understand the basic theory behind memory sniffing attacks, it is necessary to execute practical test cases to check if your application is vulnerable. If you have implemented countermeasures, it is important to execute these tests before and after adding the countermeasures to test their effectiveness.
Test for sensitive data in RAM
In Windows platforms, follow these steps to create a record of physical memory in a text file:
- Log into a Windows host running the application under test.
- Download and install ManTech’s Memory DD (https://sourceforge.net/projects/mdd/).
- Open command prompt with administrative privileges.
- Run mdd as follows: mdd_1.3.exe -o c:\ram.txt -v
- Once mdd finishes executing, read output file ram.txt for sensitive information.
Expected results: ram.txt must not show any sensitive data.
Test for sensitive data in virtual memory
The best way to search your application’s virtual memory for secrets is to use a debugger to create a dump of the virtual memory space at any given time:
- Log into a Windows host running the application under test.
- Download and run user-mode Windows debugging windbg.
- Attach windbg to the application under test.
- Break into the debugger and specify the option to create a full dump for the application’s virtual memory: .dump /f c:\dump.txt
Expected results: dump.txt must not show any sensitive data.
Test for sensitive data in swap files
In Windows, swap files are stored in the pagefile:
- Log into a Windows host running the application under test.
- Find pagefile. It is named pagefile.sys and is usually on the root drive of the Windows partition (i.e. c:\pagefile.sys).
- Open read-only copy of a file.
- Search for sensitive information in pagefile.
Expected results: pagefile must not show sensitive information.
Test for sensitive data in dump files
Follow these steps test for sensitive information in dump files:
- Log into a Windows host running the application under test.
- Find the dump files (in Windows, this is indicated in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CrashControl).
- Open a dump file and search for sensitive information.
- Repeat for each of the dump files
Expected results: dump files must not show sensitive information.
Step 4: Execute Additional Testing
If the sensitive data cannot be easily recognized, you must do additional testing. During each of the tests above, the attacker needs to interpret the output. Running each of the tools creates an output file with a large quantity of data that is irrelevant to the test. A good way to find secrets is running a command such strings on the output file [v] in order to display all character arrays in the file:
C:\Documents and Settings\All Users\Documents\DrWatson>strings user.dmp
12
…
kernel32.dll
RASAPI32
C:\WINNT\tracing
C:\Documents and Settings\Administrator\My Documents\PGP\pubring.pkr
C:\Documents and Settings\Administrator\My Documents\PGP\secring.skr
& !
IN PGP MESSAGE-----
Version: PGP 7.1
qANQR1DBwU4DSL6Q3OHRwOYQB/9pKnnhZGQRFwykWzBO1EWkzW336QOkUaHj0aVj
P1MgxDWQWi3kZpOfGnDg6kbQriWBiIgD/z8p5xGN+WcksytlLJv8OxvTGMepx7u8
h5aVRXZd8YPM+h5ROpbnNw+SiT/w9oCy/ChWeiCHV1swQSzwBHx2Ye+yxO70Moxc
...
frAG3nM7kOnChQp4jxhv2J0p7fL1vteI9EGbcimC9QCVBwC1U++mQIqbTyIw5gWK
Io11yl8P+wKjcHsLfi2hTE+NIRb+VORWhVoCDHgNKV1nSFNTK0LEnvz84OFyRc1z
-----END PGP MESSAGE-----
<pgppassphrase!>
…
Hex editors and similar low-level file processing tools must be used to identify sensitive data. Additional techniques include performing dictionary or linear searches. For example, in Linux refer to Cryptographic Key Recovery from Linux Memory Dumps [vi].
Conclusion
Memory sniffing attacks aim at recovering sensitive data in system memory, including virtual memory, RAM, and swap files.In order to properly test for this bug, it is necessary to understand the anatomy of the attack scenario as well as why it is caused and how to protect against it.Then, you must use a set of available tools to check for it in your application by making records of the different types of memory and searching them for sensitive data.
[i] Hit by a Bus: Physical Access Attacks with Firewire. Adam Boileau.
[ii] Insecure Compiler Optimization. OWASP. http://www.owasp.org/index.php/Insecure_Compiler_Optimization
[iii] Protecting sensitive data in memory. John Viega. CGI Security. http://www.cgisecurity.com/lib/protecting-sensitive-data.html
[iv] VOID MSC14-A. Protect memory when working with sensitive data. Alex Volkovitsky CERT.
[v] Practical Approaches to Recovering Encrypted Digital Evidence. Eoghan Casey. http://www.utica.edu/academic/institutes/ecii/publications/articles/A04AF2FB-BD97-C28C-7F9F4349043FD3A9.pdf
[vi] Cryptographic Key Recovery from Linux Memory Dumps. Torbjörn Pettersson. http://events.ccc.de/camp/2007/Fahrplan/attachments/1300-Cryptokey_forensics_A.pdf