private static EaBuffer CreateDummyEaBuffer() { EaBuffer ea = new EaBuffer(); ea.AddEntry("GARBAGE", new byte[16], EaBufferEntryFlags.NeedEa); return(ea); }
static CheckResult CheckDevice(string name, bool writable, EaBuffer ea_buffer) { CheckResult result = new CheckResult(name, NtStatus.STATUS_INVALID_PARAMETER, FileDeviceType.UNKNOWN); try { using (var imp = NtToken.Impersonate(_pid, _identify_only ? SecurityImpersonationLevel.Identification : SecurityImpersonationLevel.Impersonation)) { FileAccessRights access_mask = FileAccessRights.GenericRead; if (writable) { access_mask |= FileAccessRights.GenericWrite; } FileOpenOptions opts = _open_as_dir ? FileOpenOptions.DirectoryFile : FileOpenOptions.NonDirectoryFile; using (NtFile file = NtFile.Create(name, null, access_mask, NtApiDotNet.FileAttributes.Normal, FileShareMode.All, opts, FileDisposition.Open, ea_buffer)) { result = new CheckResult(name, NtStatus.STATUS_SUCCESS, file.DeviceType); } } } catch (NtException ex) { result = new CheckResult(name, ex.Status, FileDeviceType.UNKNOWN); } return(result); }
private protected override void RunAccessCheck(IEnumerable <TokenEntry> tokens) { HashSet <string> devices = new HashSet <string>(StringComparer.OrdinalIgnoreCase); foreach (string path in Path) { using (var result = OpenDirectory(path, null)) { if (result.IsSuccess) { FindDevicesInDirectory(result.Result, devices, MaxDepth ?? int.MaxValue); } else { // If failed, it might be an absolute path so just add it. devices.Add(path); } } } if (devices.Count > 0) { AccessMask access_rights = _file_type.MapGenericRights(AccessRights); EaBuffer ea_buffer = CheckEaBuffer ? (EaBuffer ?? CreateDummyEaBuffer()) : null; List <string> namespace_paths = new List <string>(NamespacePath ?? new[] { "XYZ" }); foreach (var entry in tokens) { foreach (string path in devices) { if (CheckDevice()) { CheckAccessUnderImpersonation(entry, path, false, access_rights, OpenOptions, ea_buffer); } if (CheckNamespace()) { foreach (string namespace_path in namespace_paths) { CheckAccessUnderImpersonation(entry, path + @"\" + namespace_path, true, access_rights, OpenOptions, ea_buffer); } } } } } else { WriteWarning("Couldn't find any devices to check"); } }
static NtSection RemapFileAsRW() { string base_path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "luafv_" + Guid.NewGuid()); Console.WriteLine("Base Path: {0}", base_path); DirectorySecurity dir_sd = new DirectorySecurity(); Directory.CreateDirectory(base_path); string target_path = NtFileUtils.DosFileNameToNt(Path.Combine(base_path, "dummy.txt")); string license_file = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "license.rtf"); Console.WriteLine("Trying to map {0} R/W", license_file); NtFile.CreateHardlink(NtFileUtils.DosFileNameToNt(license_file), target_path); using (var oplock_file = NtFile.Open(target_path, null, FileAccessRights.ReadAttributes, FileShareMode.All, FileOpenOptions.NonDirectoryFile)) { var oplock = oplock_file.RequestOplockAsync(OplockLevelCache.Read | OplockLevelCache.Write, RequestOplockInputFlag.Request); Console.WriteLine("Started oplock"); SetVirtualization(true); Console.WriteLine("Opening file"); using (var file = NtFile.Open(target_path, null, FileAccessRights.GenericRead | FileAccessRights.GenericWrite, FileShareMode.All, FileOpenOptions.NonDirectoryFile | FileOpenOptions.CompleteIfOplocked)) { SetVirtualization(false); Console.WriteLine("{0} {1}", NtProcess.Current.ProcessId, file.Handle.DangerousGetHandle()); Console.WriteLine("{0} {1}", file.FullPath, file.GrantedAccess); CreateVirtualStoreFile(target_path, GetDummyBuffer()); var async_read = file.ReadAsync(1, 0); if (!oplock.Wait(10000)) { throw new Exception("Oplock Timed Out"); } Console.WriteLine("Oplock Fired"); EaBuffer ea = new EaBuffer(); ea.AddEntry("Hello", new byte[16], EaBufferEntryFlags.None); // Set EA to force the delayed virtualization to complete without triggering oplock. Console.WriteLine("Setting EA"); file.SetEa(ea); Console.WriteLine("File now {0}", file.FullPath); oplock_file.Close(); Console.WriteLine("Closed oplock_file"); if (!async_read.Wait(10000)) { throw new Exception("Async Read Timed Out"); } Console.WriteLine("Read Complete"); return NtSection.Create(null, SectionAccessRights.MaximumAllowed, null, MemoryAllocationProtect.ReadWrite, SectionAttributes.Commit, file); } } }
private protected override void RunAccessCheck(IEnumerable <TokenEntry> tokens) { var devices = new Dictionary <string, SecurityDescriptorEntry>(StringComparer.OrdinalIgnoreCase); foreach (string path in Path) { using (var result = OpenDirectory(path, null)) { if (result.IsSuccess) { FindDevicesInDirectory(result.Result, devices, MaxDepth ?? int.MaxValue); } else { // If failed, it might be an absolute path so just add it. if (!devices.ContainsKey(path)) { devices.Add(path, GetSecurityDescriptor(path)); } } } } if (devices.Count > 0) { AccessMask access_rights = _file_type.MapGenericRights(Access); EaBuffer ea_buffer = CheckEaBuffer ? (EaBuffer ?? CreateDummyEaBuffer()) : null; List <string> namespace_paths = new List <string>(NamespacePath ?? new[] { "XYZ" }); foreach (var entry in tokens) { foreach (var pair in devices) { if (CheckDevice()) { if (pair.Value != null) { AccessMask granted_access = NtSecurity.GetMaximumAccess(pair.Value.SecurityDescriptor, entry.Token, _file_type.GenericMapping); if (IsAccessGranted(granted_access, access_rights)) { WriteObject(new DeviceAccessCheckResult(pair.Key, false, pair.Value.DeviceType, pair.Value.Characteristics, granted_access, pair.Value.SecurityDescriptor, entry.Information)); } } else { if (!NoImpersonation) { CheckAccessUnderImpersonation(entry, pair.Key, false, access_rights, OpenOptions, ea_buffer); } } } if (CheckNamespace() && !NoImpersonation) { foreach (string namespace_path in namespace_paths) { CheckAccessUnderImpersonation(entry, pair.Key + @"\" + namespace_path, true, access_rights, OpenOptions, ea_buffer); } } } } } else { WriteWarning("Couldn't find any devices to check"); } }
private void CheckAccessUnderImpersonation(TokenEntry token, string path, bool namespace_path, AccessMask access_rights, FileOpenOptions open_options, EaBuffer ea_buffer) { using (var result = OpenUnderImpersonation(token, path, open_options, ea_buffer)) { if (result.IsSuccess) { if (IsAccessGranted(result.Result.GrantedAccessMask, access_rights)) { var sd = result.Result.GetSecurityDescriptor(SecurityInformation.AllBasic, false); WriteObject(new DeviceAccessCheckResult(path, namespace_path, GetDeviceType(result.Result), GetDeviceCharacteristics(result.Result), result.Result.GrantedAccess, sd.IsSuccess ? sd.Result : null, token.Information)); } } else { WriteWarning($"Opening {path} failed: {result.Status}"); } } }
private static NtResult <NtFile> OpenUnderImpersonation(TokenEntry token, string path, FileOpenOptions open_options, EaBuffer ea_buffer) { using (var obja = new ObjectAttributes(path, AttributeFlags.CaseInsensitive)) { return(token.Token.RunUnderImpersonate(() => NtFile.Create(obja, FileAccessRights.MaximumAllowed, FileAttributes.None, FileShareMode.None, open_options, FileDisposition.Open, ea_buffer, false))); } }
static void Main(string[] args) { bool show_help = false; bool map_to_symlink = false; bool readable = false; bool ea_buffer = false; string suffix = "XYZ"; string namelist = null; _pid = Process.GetCurrentProcess().Id; try { OptionSet opts = new OptionSet() { { "r", "Recursive tree directory listing", v => _recursive = v != null }, { "l", "Try and map device names to a symlink", v => map_to_symlink = v != null }, { "p|pid=", "Specify a PID of a process to impersonate when checking", v => _pid = int.Parse(v.Trim()) }, { "suffix=", "Specify the suffix for the namespace search", v => suffix = v }, { "namelist=", "Specify a text file with a list of names", v => namelist = v }, { "ea", "Try and show only devices with accept an EA buffer", v => ea_buffer = v != null }, { "e", "Display errors when trying devices, ignores Access Denied", v => _show_errors = v != null }, { "i", "Use an identify level token when impersonating", v => _identify_only = v != null }, { "d", "Try opening devices as directories rather than files", v => _open_as_dir = v != null }, { "f", "Filter out devices which could be opened direct and via namespace", v => _filter_direct = v != null }, { "readonly", "Show devices which can be opened for read access instead of write", v => readable = v != null }, { "h|help", "show this message and exit", v => show_help = v != null }, }; List <string> names = opts.Parse(args); if (namelist != null) { names.AddRange(File.ReadAllLines(namelist)); } if (names.Count == 0 || show_help) { ShowHelp(opts); } else { List <string> device_objs; if (_recursive) { device_objs = FindDeviceObjects(names); } else { device_objs = names; } if (device_objs.Count > 0) { EaBuffer ea = null; if (ea_buffer) { ea = new EaBuffer(); ea.AddEntry("GARBAGE", new byte[16], EaBufferEntryFlags.NeedEa); } IEnumerable <CheckResult> write_normal = device_objs.Select(n => CheckDevice(n, !readable, ea)); IEnumerable <CheckResult> write_namespace = device_objs.Select(n => CheckDevice(n + "\\" + suffix, !readable, ea)); Dictionary <string, string> symlinks = FindSymlinks(); if (ea_buffer) { _show_errors = true; write_normal = write_normal.Where(e => e.Status == NtStatus.STATUS_INVALID_PARAMETER); write_namespace = write_namespace.Where(e => e.Status == NtStatus.STATUS_INVALID_PARAMETER); } if (_filter_direct) { Console.WriteLine("Namespace Only"); HashSet <string> normal = new HashSet <string>(write_normal.Where(r => r.Status.IsSuccess()).Select(r => r.Path), StringComparer.OrdinalIgnoreCase); DumpList(write_namespace.Where(r => !normal.Contains(r.Path)), map_to_symlink, symlinks); } else { Console.WriteLine("{0} Access", readable ? "Read" : "Write"); DumpList(write_normal, map_to_symlink, symlinks); Console.WriteLine(); Console.WriteLine("{0} Access with Namespace", readable ? "Read" : "Write"); DumpList(write_namespace, map_to_symlink, symlinks); } } else { Console.WriteLine("No device names specified"); } } } catch (Exception ex) { Console.WriteLine(ex.Message); } }
private void CheckAccessUnderImpersonation(TokenEntry token, string path, AccessMask access_rights, FileOpenOptions open_options, EaBuffer ea_buffer) { using (var result = OpenUnderImpersonation(token, path, open_options, ea_buffer)) { if (result.IsSuccess) { if (IsAccessGranted(result.Result.GrantedAccessMask, access_rights)) { WriteAccessCheckResult(path, "Device", result.Result.GrantedAccess, _file_type.GenericMapping, String.Empty, _file_type.AccessRightsType, token.Information); } } else { WriteWarning(String.Format("Opening {0} failed: {1}", path, result.Status)); } } }