Dirty COW – CVE-2016-5195

Introduction:

A privilege escalation vulnerability in Linux Kernel has been discovered by Phil Pester. The bug has been in existence since version 2.6.22 which was released in 2007 and has been fixed on Oct 18  2016. The bug allows an unprivileged authenticated local user to gain write access to read only memory mappings. A number of PoC’s have been disclosed that show how the bug is exploited in different ways (PoC for Android OS is also present).

When a file, which exists in the physical memory is mapped within a processes memory space, it is considered to be a byte-for-byte correlation, this allows the process to treat the mapping as if it were the physical memory. The mapped file can be either shared with other processes , where updates to the mapping are visible to other processes or set as private which creates a copy-on-write mapping.

Copy-on-write is a resource management technique and is implemented in various scenarios. If a resource is duplicated but not modified, it is not necessary to create a new resource. This we will reduce the number of unmodified copies. In lay man terms different processes refer the same mapped file as long as the contents of the file are not modified. If a change occurs a new copy of the file is created for that process, this reduces memory consumption.

The vulnerability exists as a race condition in the way the Linux Kernel memory management handles duplication due to Copy-On-Write for private read only memory mappings. The exploits encountered in the wild rely on racing write operation on /proc/self/mem and ‘madvise‘ system call on a mmapped file (Target file).

As per the Linux kernel commit logs this vulnerability was documented during a fix for ‘get_user_pages‘ but its practical implications were not guaranteed. But the recent entries show that this race condition is easier to trigger. In this article we will focus more on the race condition between write operation on /proc/self/mem and ‘madvise‘ system call. /proc is virtual file system used by the kernel to keep track of run-time system information. Each of the sub directories within the /proc represents a process ID and the files within them contain its state, configuration and memory stats.

The PoC for the vulnerability  is available here. The PoC takes two arguments the name of the target file and the content to be written. Basically we have two threads, first making the ‘madvise’  system call on a loop.

madvise() system call for mapped target file
madvise() system call for mapped target file

The second performing a write operation on the mapped file by directly referencing its address in the /proc/self/mem.

write operation on the mapped file
write operation on the mapped file

The madvise() system call is used by application to advice the kernel on how it will use the mapped or shared memory within its memory space. This will help the kernel to use the appropriate read-ahead and caching mechanism. If we observe we use MADV_DONTNEED flag, this informs the kernel that the application is finished with the address space for now and can be freed. However, if any access operations are encountered, the kernel will repopulate the contents of the memory pages based on the latest contents of the mmaped file. This is the crux of the exploit on one hand we are telling the kernel that we are finished with the memory pages and can be flushed and on the hand we are continuously writing to the memory pages of the same mapped file. This will cause the kernel to reload a new copy of the original file through mapping.

Most of the time the kernel will be able to handle this scenario, however if the concurrent operations are repeated enough number of times a break in the copy on write cycle occurs. Which will result in the application to be able to write to the read only file.

Exploit:
We will demonstrate the exploit on an un-patched Ubuntu 16.04 LTS with kernel version 4.4.0-21.

Kernel Version
Kernel Version

Next we are going to create a file owned by the root user account.

Creating root owned file
Creating root owned file

Executing PoC:

PoC execution
PoC execution

We can see in the image above, the contents of the root owned file is being overwritten by unprivileged user account.

Fix:
A new internal flag ‘FOLL_COW’ was introduced in ‘include/linux/mm.h‘ to fix the issue, the FOLL_COW flag is used in conjunction with the pte dirty flag to validate the completion of copy on write operation. Previously the kernel relied on the FOLL_WRITE flag. The details about this fix can be found here.

Conclusion:
We request our customer to scan using the following QID’s

QID Title
169351  OpenSuSE Security Update for kernel (openSUSE-SU-2016:2649-1)
169343  OpenSuSE Security Update for the Linux Kernel (openSUSE-SU-2016:2625-1)
256077  CentOS Security Update for kernel (CESA-2016:2124)
256076  CentOS Security Update for kernel (CESA-2016:2105)
236134  Red Hat Update for kernel (RHSA-2016:2128) (Dirty Cow)
236133  Red Hat Update for kernel (RHSA-2016:2124) (Dirty Cow)
236132  Red Hat Update for kernel (RHSA-2016:2120) (Dirty Cow)
157280  Oracle Enterprise Linux Security Update for kernel (ELSA-2016-2124) (Dirty Cow)
157279  Oracle Enterprise Linux Security Update for kernel (ELSA-2016-2105) (Dirty Cow)
236130  Red Hat Update for kernel (RHSA-2016:2118) (Dirty Cow)
236129  Red Hat Update for kernel-rt (RHSA-2016:2110) (Dirty Cow)
236128  Red Hat Update for kernel-rt (RHSA-2016:2107) (Dirty Cow)
236127  Red Hat Update for kernel (RHSA-2016:2106) (Dirty Cow)
236126  Red Hat Update for kernel (RHSA-2016:2105) (Dirty Cow)
256075  CentOS Security Update for kernel (CESA-2016:2098) (Dirty Cow)
169314  SUSE Enterprise Linux Security Update for the Linux Kernel (SUSE-SU-2016:2592-1) (Dirty Cow)
169312  SUSE Enterprise Linux Security Update for the Linux Kernel (SUSE-SU-2016:2585-1) (Dirty Cow)
169287  OpenSuSE Security Update for the Linux Kernel (openSUSE-SU-2016:2584-1) (Dirty Cow)
169286  OpenSuSE Security Update for the Linux Kernel (openSUSE-SU-2016:2583-1) (Dirty Cow)
370172  Linux Kernel Privilege Escalation Vulnerability (Dirty Cow)
276206  Fedora Security Update for kernel (FEDORA-2016-db4b75b352) (Dirty Cow)
276205  Fedora Security Update for kernel (FEDORA-2016-c3558808cd) (Dirty Cow)
276204  Fedora Security Update for kernel (FEDORA-2016-c8a0c7eece) (Dirty Cow)
175865  Debian Security Update for linux (DSA 3696-1) (Dirty Cow)
157278  Oracle Enterprise Linux Security Update for kernel (ELSA-2016-2098) (Dirty Cow)
236124  Red Hat Update for kernel (RHSA-2016:2098) (Dirty Cow)
350912  Amazon Linux Security Advisory for kernel: ALAS-2016-757 (Dirty Cow)
196605  Ubuntu Security Notification for Linux Vulnerability (USN-3107-1) (Dirty Cow)
196604  Ubuntu Security Notification for Linux Vulnerability (USN-3106-1) (Dirty Cow)
196603  Ubuntu Security Notification for Linux Vulnerability (USN-3105-1) (Dirty Cow)
196602  Ubuntu Security Notification for Linux Vulnerability (USN-3104-1) (Dirty Cow)
155355  Oracle Enterprise Linux Security Update for Unbreakable Enterprise kernel (ELSA-2016-3633)


References:
RedHat has provided a shell script to detect if the OS is vulnerable or not it also checks for the presence of the corresponding patch.

CVE-2016-5195
DirtyCow-VulnerabilityDetails
Linux Kernel Commit Logs
/proc

Leave a Reply

Your email address will not be published. Required fields are marked *