├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── Seatbelt.sln └── Seatbelt ├── Commands ├── Browser │ ├── ChromiumBookmarksCommand.cs │ ├── ChromiumHistoryCommand.cs │ ├── ChromiumPresenceCommand.cs │ ├── FirefoxHistoryCommand.cs │ ├── FirefoxPresenceCommand.cs │ ├── InternetExplorerFavoritesCommand.cs │ ├── InternetExplorerTabCommand.cs │ └── InternetExplorerTypedURLsCommand.cs ├── CommandBase.cs ├── CommandDTOBase.cs ├── CommandGroup.cs ├── CommandOutputTypeAttribute.cs ├── ErrorDTO.cs ├── HostDTO.cs ├── Misc │ ├── CloudCredentialsCommand.cs │ ├── DirectoryListCommand.cs │ ├── FileInfoCommand.cs │ ├── InterestingFilesCommand.cs │ └── SearchIndexCommand.cs ├── Products │ ├── CloudSyncProviderCommand.cs │ ├── FileZillaCommand.cs │ ├── InstalledProductsCommand.cs │ ├── KeePass.cs │ ├── LAPSCommand.cs │ ├── MTPuTTYCommand.cs │ ├── McAfeeConfigsCommand.cs │ ├── McAfeeSiteListCommand.cs │ ├── OfficeMRUsCommand.cs │ ├── OneNoteCommand.cs │ ├── OracleSQLDeveloperCommand.cs │ ├── OutlookDownloadsCommand.cs │ ├── PuttyHostKeysCommand.cs │ ├── PuttySessionsCommand.cs │ ├── RemoteDesktopConnectionManagerCommand.cs │ ├── SccmClientCommand.cs │ ├── SlackDownloadsCommand.cs │ ├── SlackPresenceCommand.cs │ ├── SlackWorkspacesCommand.cs │ ├── SuperPuttyCommand.cs │ ├── SysmonCommand.cs │ └── WsusClientCommand.cs ├── Template.cs ├── VerboseDTO.cs ├── WarningDTO.cs └── Windows │ ├── AMSIProvidersCommand.cs │ ├── ARPTableCommand.cs │ ├── AntiVirusCommand.cs │ ├── AppLockerCommand.cs │ ├── AuditPoliciesCommand.cs │ ├── AuditPolicyRegistryCommand.cs │ ├── AutoRunsCommand.cs │ ├── AzureADCmd.cs │ ├── CertificateThumbprints.cs │ ├── Certificates.cs │ ├── CredEnumCommand.cs │ ├── CredentialGuardCommand.cs │ ├── DNSCacheCommand.cs │ ├── DotNetCommand.cs │ ├── DpapiMasterKeysCommand.cs │ ├── EnvironmentPathCommand.cs │ ├── EnvironmentVariableCommand.cs │ ├── EventLogs │ ├── ExplicitLogonEvents │ │ ├── ExplicitLogonEventsCommand.cs │ │ ├── ExplicitLogonEventsCommandDTO.cs │ │ └── ExplicitLogonEventsTextFormatter.cs │ ├── LogonEventsCommand.cs │ ├── PowerShellEventsCommand.cs │ ├── PoweredOnEventsCommand.cs │ ├── ProcessCreationEventsCommand.cs │ └── SysmonEventsCommand.cs │ ├── ExplorerMRUsCommand.cs │ ├── ExplorerRunCommandCommand.cs │ ├── HotfixesCommand.cs │ ├── IdleTimeCommand.cs │ ├── InterestingProcessesCommand.cs │ ├── InternetSettingsCommand.cs │ ├── LastShutdownCommand.cs │ ├── LocalGPOCommand.cs │ ├── LocalGroupMembershipCommand.cs │ ├── LocalSecurityAuthorityCommand.cs │ ├── LocalUserCommand.cs │ ├── LogonSessionsCommand.cs │ ├── MappedDrivesCommand.cs │ ├── MicrosoftUpdatesCommand.cs │ ├── NamedPipesCommand.cs │ ├── NetworkProfilesCommand.cs │ ├── NetworkSharesCommand.cs │ ├── NtlmSettingsCommand.cs │ ├── OSInfoCommand.cs │ ├── OptionalFeaturesCommand.cs │ ├── PSSessionSettingsCommand.cs │ ├── PowerShellCommand.cs │ ├── PowerShellHistory.cs │ ├── PrintersCommand.cs │ ├── ProcessOwnersCommand.cs │ ├── ProcessesCommand.cs │ ├── RDPSavedConnectionCommand.cs │ ├── RDPSessionsCommand.cs │ ├── RDPSettingsCommand.cs │ ├── RPCMappedEndpointsCommand.cs │ ├── RecycleBinCommand.cs │ ├── RegistryValueCommand.cs │ ├── ScheduledTasksCommand.cs │ ├── SecureBootCommand.cs │ ├── SecurityPackagesCommand.cs │ ├── SecurityPackagesCredentialsCommand.cs │ ├── ServicesCommand.cs │ ├── TCPConnectionsCommand.cs │ ├── TokenGroupCommand.cs │ ├── TokenPrivilegesCommand.cs │ ├── UDPConnectionsCommand.cs │ ├── UserAccountControlCommand.cs │ ├── UserRightAssignmentsCommand.cs │ ├── WMICommand.cs │ ├── WMIEventConsumerCommand.cs │ ├── WMIEventFilterCommand.cs │ ├── WMIFilterToConsumerBindingCommand.cs │ ├── WifiProfileCommand.cs │ ├── WindowsAutoLogonCommand.cs │ ├── WindowsCredentialFileCommand.cs │ ├── WindowsDefenderCommand.cs │ ├── WindowsEventForwardingCommand.cs │ ├── WindowsFirewallCommand.cs │ └── WindowsVaultCommand.cs ├── Interop ├── Advapi32.cs ├── COM.cs ├── Iphlpapi.cs ├── Kernel32.cs ├── Mpr.cs ├── Netapi32.cs ├── Ntdll.cs ├── Rpcrt4.cs ├── SecBuffer.cs ├── SecBufferDesc.cs ├── Secur32.cs ├── Shell32.cs ├── Shlwapi.cs ├── User32.cs ├── VaultCli.cs ├── Win32Error.cs ├── Wlanapi.cs └── Wtsapi32.cs ├── Output ├── Formatters │ ├── DefaultTextFormatter.cs │ └── TextFormatterBase.cs ├── Sinks │ ├── IOutputSink.cs │ ├── JsonFileOutputSink.cs │ ├── JsonStringOutputSink.cs │ └── TextOutputSink.cs └── TextWriters │ ├── ConsoleTextWriter.cs │ ├── FileTextWriter.cs │ └── ITextWriter.cs ├── Program.cs ├── Properties └── AssemblyInfo.cs ├── Runtime.cs ├── Seatbelt.cs ├── Seatbelt.csproj ├── SeatbeltArgumentParser.cs ├── SeatbeltOptions.cs ├── Util ├── ExtensionMethods.cs ├── FileUtil.cs ├── LsaWrapper.cs ├── MiscUtil.cs ├── RegistryUtil.cs ├── SecurityUtil.cs └── WMIUtil.cs └── app.config /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | This is a bug tracker. If you need help using the tool, make sure you've read the detailed [README](https://github.com/GhostPack/Seatbelt/blob/master/README.md). If something is not in the README that you think would be beneficial, please submit bug requesting the information or, even better, submit a pull request. 14 | 15 | If you are running multiple commands or a command group and Seatbelt is crashing before it finishes, consider writing output to a file (`Seatbelt.exe -outputFile=out.txt`) so we can determine the last command that executed before it failed. 16 | 17 | **To Reproduce** 18 | Steps to reproduce the behavior. Please include any applicable artifacts that we could use to replicate the issue(e.g. files, registry keys, screenshots, etc.) 19 | 1. 20 | 2. 21 | 3. 22 | 4. 23 | 24 | **Expected behavior** 25 | A clear and concise description of what you expected to happen. 26 | 27 | **Observed behavior** 28 | A description of what Seatbelt did that you did not expect it to. 29 | 30 | **Software versions (where applicable)** 31 | - OS (open `cmd.exe` and type `ver`) 32 | - If it concerns a specific product. please include the product's version number or PE file version information(`Seatbelt.exe "fileinfo C:\path\to\product.exe"`) 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | 19 | For Seatbelt enumeration command requests, please include example registry keys, file, shell commands, etc. that could be used as test cases. 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vs 2 | *.user 3 | [Dd]ebug/ 4 | [Rr]elease/ 5 | [Bb]in/ 6 | [Oo]bj/ 7 | -------------------------------------------------------------------------------- /Seatbelt.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28010.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Seatbelt", "Seatbelt\Seatbelt.csproj", "{AEC32155-D589-4150-8FE7-2900DF4554C8}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {AEC32155-D589-4150-8FE7-2900DF4554C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {AEC32155-D589-4150-8FE7-2900DF4554C8}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {AEC32155-D589-4150-8FE7-2900DF4554C8}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {AEC32155-D589-4150-8FE7-2900DF4554C8}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {582494D9-B9F0-40F9-B7B3-4483685E6732} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Browser/InternetExplorerFavoritesCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using Seatbelt.Output.Formatters; 5 | using Seatbelt.Output.TextWriters; 6 | 7 | 8 | namespace Seatbelt.Commands.Browser 9 | { 10 | internal class InternetExplorerFavoritesCommand : CommandBase 11 | { 12 | public override string Command => "IEFavorites"; 13 | public override string Description => "Internet Explorer favorites"; 14 | public override CommandGroup[] Group => new[] { CommandGroup.User }; 15 | public override bool SupportRemote => true; 16 | public Runtime ThisRunTime; 17 | 18 | 19 | public InternetExplorerFavoritesCommand(Runtime runtime) : base(runtime) 20 | { 21 | ThisRunTime = runtime; 22 | } 23 | 24 | public override IEnumerable Execute(string[] args) 25 | { 26 | var dirs = ThisRunTime.GetDirectories("\\Users\\"); 27 | 28 | foreach (var dir in dirs) 29 | { 30 | var parts = dir.Split('\\'); 31 | var userName = parts[parts.Length - 1]; 32 | if (dir.EndsWith("Public") || dir.EndsWith("Default") || dir.EndsWith("Default User") || 33 | dir.EndsWith("All Users")) 34 | { 35 | continue; 36 | } 37 | 38 | var userFavoritesPath = $"{dir}\\Favorites\\"; 39 | if (!Directory.Exists(userFavoritesPath)) 40 | { 41 | continue; 42 | } 43 | 44 | var bookmarkPaths = Directory.GetFiles(userFavoritesPath, "*.url", SearchOption.AllDirectories); 45 | if (bookmarkPaths.Length == 0) 46 | { 47 | continue; 48 | } 49 | 50 | var favorites = new List(); 51 | 52 | foreach (var bookmarkPath in bookmarkPaths) 53 | { 54 | using var rdr = new StreamReader(bookmarkPath); 55 | string line; 56 | var url = ""; 57 | 58 | while ((line = rdr.ReadLine()) != null) 59 | { 60 | if (!line.StartsWith("URL=", StringComparison.InvariantCultureIgnoreCase)) 61 | { 62 | continue; 63 | } 64 | 65 | if (line.Length > 4) 66 | { 67 | url = line.Substring(4); 68 | } 69 | 70 | break; 71 | } 72 | 73 | favorites.Add(url.Trim()); 74 | } 75 | 76 | yield return new InternetExplorerFavoritesDTO( 77 | userName, 78 | favorites 79 | ); 80 | } 81 | } 82 | 83 | internal class InternetExplorerFavoritesDTO : CommandDTOBase 84 | { 85 | public InternetExplorerFavoritesDTO(string userName, List favorites) 86 | { 87 | UserName = userName; 88 | Favorites = favorites; 89 | } 90 | public string UserName { get; } 91 | public List Favorites { get; } 92 | } 93 | 94 | [CommandOutputType(typeof(InternetExplorerFavoritesDTO))] 95 | internal class InternetExplorerFavoritesFormatter : TextFormatterBase 96 | { 97 | public InternetExplorerFavoritesFormatter(ITextWriter writer) : base(writer) 98 | { 99 | } 100 | 101 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 102 | { 103 | var dto = (InternetExplorerFavoritesDTO)result; 104 | 105 | WriteLine($"Favorites ({dto.UserName}):\n"); 106 | 107 | foreach (var favorite in dto.Favorites) 108 | { 109 | WriteLine($" {favorite}"); 110 | } 111 | WriteLine(); 112 | } 113 | } 114 | } 115 | } -------------------------------------------------------------------------------- /Seatbelt/Commands/Browser/InternetExplorerTabCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using System.Runtime.InteropServices; 5 | using System.Text.RegularExpressions; 6 | 7 | 8 | namespace Seatbelt.Commands.Browser 9 | { 10 | internal class InternetExplorerTabCommand : CommandBase 11 | { 12 | public override string Command => "IETabs"; 13 | public override string Description => "Open Internet Explorer tabs"; 14 | public override CommandGroup[] Group => new[] { CommandGroup.User }; 15 | public override bool SupportRemote => false; // don't think this is possible... 16 | 17 | public InternetExplorerTabCommand(Runtime runtime) : base(runtime) 18 | { 19 | } 20 | 21 | public override IEnumerable Execute(string[] args) 22 | { 23 | // Lists currently open Internet Explorer tabs, via COM 24 | // Notes: 25 | // https://searchcode.com/codesearch/view/9859954/ 26 | // https://gist.github.com/yizhang82/a1268d3ea7295a8a1496e01d60ada816 27 | 28 | // Shell.Application COM GUID 29 | var shell = Type.GetTypeFromProgID("Shell.Application"); 30 | 31 | // actually instantiate the Shell.Application COM object 32 | var shellObj = Activator.CreateInstance(shell); 33 | 34 | // grab all the current windows 35 | var windows = shellObj.GetType().InvokeMember("Windows", BindingFlags.InvokeMethod, null, shellObj, null); 36 | 37 | // grab the open tab count 38 | var openTabs = windows.GetType().InvokeMember("Count", BindingFlags.GetProperty, null, windows, null); 39 | var openTabsCount = int.Parse(openTabs.ToString()); 40 | 41 | for (var i = 0; i < openTabsCount; i++) 42 | { 43 | // grab the acutal tab 44 | object? item = windows.GetType().InvokeMember("Item", BindingFlags.InvokeMethod, null, windows, new object[] { i }); 45 | string locationName = "", locationUrl = ""; 46 | 47 | try 48 | { 49 | // extract the tab properties 50 | locationName = (string)item.GetType().InvokeMember("LocationName", BindingFlags.GetProperty, null, item, null); 51 | locationUrl = (string)item.GetType().InvokeMember("LocationUrl", BindingFlags.GetProperty, null, item, null); 52 | 53 | Marshal.ReleaseComObject(item); 54 | item = null; 55 | } 56 | catch { } 57 | 58 | // ensure we have a site address 59 | if (Regex.IsMatch(locationUrl, @"(^https?://.+)|(^ftp://)")) 60 | { 61 | yield return new InternetExplorerTabsDTO( 62 | locationName, 63 | locationUrl 64 | ); 65 | } 66 | } 67 | 68 | Marshal.ReleaseComObject(windows); 69 | Marshal.ReleaseComObject(shellObj); 70 | } 71 | 72 | internal class InternetExplorerTabsDTO : CommandDTOBase 73 | { 74 | public InternetExplorerTabsDTO(string locationName, string locationUrl) 75 | { 76 | LocationName = locationName; 77 | LocationUrl = locationUrl; 78 | } 79 | public string LocationName { get; } 80 | public string LocationUrl { get; } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Browser/InternetExplorerTypedURLsCommand.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32; 2 | using System; 3 | using System.Collections.Generic; 4 | using Seatbelt.Output.Formatters; 5 | using Seatbelt.Output.TextWriters; 6 | 7 | 8 | namespace Seatbelt.Commands.Browser 9 | { 10 | class TypedUrl 11 | { 12 | public TypedUrl(DateTime time, string url) 13 | { 14 | Time = time; 15 | Url = url; 16 | } 17 | public DateTime Time { get; } 18 | public string Url { get; } 19 | } 20 | 21 | internal class InternetExplorerTypedUrlsCommand : CommandBase 22 | { 23 | public override string Command => "IEUrls"; 24 | public override string Description => "Internet Explorer typed URLs (last 7 days, argument == last X days)"; 25 | public override CommandGroup[] Group => new[] { CommandGroup.User }; 26 | public override bool SupportRemote => true; 27 | public Runtime ThisRunTime; 28 | 29 | public InternetExplorerTypedUrlsCommand(Runtime runtime) : base(runtime) 30 | { 31 | ThisRunTime = runtime; 32 | } 33 | 34 | public override IEnumerable Execute(string[] args) 35 | { 36 | // lists Internet explorer history (last 7 days by default) 37 | var lastDays = 7; 38 | 39 | if (!Runtime.FilterResults) 40 | { 41 | lastDays = 90; 42 | } 43 | 44 | if (args.Length >= 1) 45 | { 46 | if (!int.TryParse(args[0], out lastDays)) 47 | { 48 | throw new ArgumentException("Argument is not an integer"); 49 | } 50 | } 51 | 52 | var startTime = DateTime.Now.AddDays(-lastDays); 53 | 54 | WriteHost($"Internet Explorer typed URLs for the last {lastDays} days\n"); 55 | 56 | var SIDs = ThisRunTime.GetUserSIDs(); 57 | 58 | foreach (var sid in SIDs) 59 | { 60 | if (!sid.StartsWith("S-1-5") || sid.EndsWith("_Classes")) 61 | { 62 | continue; 63 | } 64 | 65 | var settings = ThisRunTime.GetValues(RegistryHive.Users, $"{sid}\\SOFTWARE\\Microsoft\\Internet Explorer\\TypedURLs"); 66 | if ((settings == null) || (settings.Count <= 1)) 67 | { 68 | continue; 69 | } 70 | 71 | var URLs = new List(); 72 | 73 | foreach (var kvp in settings) 74 | { 75 | var timeBytes = ThisRunTime.GetBinaryValue(RegistryHive.Users, $"{sid}\\SOFTWARE\\Microsoft\\Internet Explorer\\TypedURLsTime", kvp.Key.Trim()); 76 | 77 | if (timeBytes == null) 78 | continue; 79 | 80 | var timeLong = BitConverter.ToInt64(timeBytes, 0); 81 | var urlTime = DateTime.FromFileTime(timeLong); 82 | if (urlTime > startTime) 83 | { 84 | URLs.Add(new TypedUrl( 85 | urlTime, 86 | kvp.Value.ToString().Trim() 87 | )); 88 | } 89 | } 90 | 91 | yield return new InternetExplorerTypedURLsDTO( 92 | sid, 93 | URLs 94 | ); 95 | } 96 | } 97 | 98 | internal class InternetExplorerTypedURLsDTO : CommandDTOBase 99 | { 100 | public InternetExplorerTypedURLsDTO(string sid, List urls) 101 | { 102 | Sid = sid; 103 | Urls = urls; 104 | } 105 | public string Sid { get; } 106 | public List Urls { get; } 107 | } 108 | 109 | [CommandOutputType(typeof(InternetExplorerTypedURLsDTO))] 110 | internal class InternetExplorerTypedURLsFormatter : TextFormatterBase 111 | { 112 | public InternetExplorerTypedURLsFormatter(ITextWriter writer) : base(writer) 113 | { 114 | } 115 | 116 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 117 | { 118 | var dto = (InternetExplorerTypedURLsDTO)result; 119 | 120 | WriteLine("\n {0}", dto.Sid); 121 | 122 | foreach (var url in dto.Urls) 123 | { 124 | WriteLine($" {url.Time,-23} : {url.Url}"); 125 | } 126 | WriteLine(); 127 | } 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /Seatbelt/Commands/CommandBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Seatbelt.Commands 5 | { 6 | internal abstract class CommandBase 7 | { 8 | public abstract string Command { get; } 9 | public virtual string CommandVersion { get; set; } 10 | public abstract string Description { get; } 11 | public abstract CommandGroup[] Group { get; } 12 | public abstract bool SupportRemote { get; } 13 | 14 | public Runtime Runtime { get; set; } 15 | 16 | protected CommandBase(Runtime runtime) 17 | { 18 | CommandVersion = "1.0"; 19 | Runtime = runtime; 20 | } 21 | 22 | public abstract IEnumerable Execute(string[] args); 23 | 24 | 25 | 26 | public void WriteOutput(CommandDTOBase dto) => throw new NotImplementedException(); 27 | 28 | public void WriteVerbose(string message) => Runtime.OutputSink.WriteVerbose(message); 29 | 30 | public void WriteWarning(string message) => Runtime.OutputSink.WriteWarning(message); 31 | 32 | public void WriteError(string message) => Runtime.OutputSink.WriteError(message); 33 | 34 | public void WriteHost(string format = "", params object[] args) => Runtime.OutputSink.WriteHost(string.Format(format, args)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Seatbelt/Commands/CommandDTOBase.cs: -------------------------------------------------------------------------------- 1 | namespace Seatbelt.Commands 2 | { 3 | public class CommandDTOBase 4 | { 5 | private string CommandVersion { get; set; } 6 | 7 | protected CommandDTOBase() 8 | { 9 | CommandVersion = ""; 10 | } 11 | 12 | public void SetCommandVersion(string commandVersion) 13 | { 14 | CommandVersion = commandVersion; 15 | } 16 | 17 | public string GetCommandVersion() 18 | { 19 | return CommandVersion; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Seatbelt/Commands/CommandGroup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Seatbelt.Commands 7 | { 8 | [Flags] 9 | public enum CommandGroup 10 | { 11 | All, 12 | User, 13 | System, 14 | Slack, 15 | Chromium, 16 | Remote, 17 | Misc, 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Seatbelt/Commands/CommandOutputTypeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Seatbelt.Commands 4 | { 5 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 6 | class CommandOutputTypeAttribute : Attribute 7 | { 8 | public Type Type { get; set; } 9 | 10 | public CommandOutputTypeAttribute(Type outputDTO) 11 | { 12 | if (!typeof(CommandDTOBase).IsAssignableFrom(outputDTO)) 13 | { 14 | throw new Exception($"CommandOutputTypeAttribute: the specified output DTO({outputDTO}) does not inherit from CommandDTOBase"); 15 | } 16 | 17 | Type = outputDTO; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Seatbelt/Commands/ErrorDTO.cs: -------------------------------------------------------------------------------- 1 | using Seatbelt.Output.Formatters; 2 | using Seatbelt.Output.TextWriters; 3 | 4 | namespace Seatbelt.Commands 5 | { 6 | internal class ErrorDTO : CommandDTOBase 7 | { 8 | public ErrorDTO(string message) 9 | { 10 | Message = message; 11 | } 12 | 13 | public string Message { get; } 14 | } 15 | 16 | [CommandOutputType(typeof(ErrorDTO))] 17 | internal class ErrorTextFormatter : TextFormatterBase 18 | { 19 | public ErrorTextFormatter(ITextWriter writer) : base(writer) 20 | { 21 | } 22 | 23 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 24 | { 25 | var dto = (ErrorDTO)result; 26 | WriteLine("ERROR: " + dto.Message); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Seatbelt/Commands/HostDTO.cs: -------------------------------------------------------------------------------- 1 | using Seatbelt.Output.Formatters; 2 | using Seatbelt.Output.TextWriters; 3 | 4 | namespace Seatbelt.Commands 5 | { 6 | internal class HostDTO : CommandDTOBase 7 | { 8 | public HostDTO(string message) 9 | { 10 | Message = message; 11 | } 12 | 13 | public string Message { get; } 14 | } 15 | 16 | [CommandOutputType(typeof(HostDTO))] 17 | internal class HostTextFormatter : TextFormatterBase 18 | { 19 | public HostTextFormatter(ITextWriter writer) : base(writer) 20 | { 21 | } 22 | 23 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 24 | { 25 | var dto = (HostDTO)result; 26 | WriteLine(dto.Message); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Products/InstalledProductsCommand.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | 6 | namespace Seatbelt.Commands.Windows 7 | { 8 | internal class InstalledProductsCommand : CommandBase 9 | { 10 | public override string Command => "InstalledProducts"; 11 | public override string Description => "Installed products via the registry"; 12 | public override CommandGroup[] Group => new[] { CommandGroup.Misc }; 13 | public override bool SupportRemote => true; 14 | public Runtime ThisRunTime; 15 | 16 | public InstalledProductsCommand(Runtime runtime) : base(runtime) 17 | { 18 | ThisRunTime = runtime; 19 | } 20 | 21 | public override IEnumerable Execute(string[] args) 22 | { 23 | string[] productKeys = { @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\", @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" }; 24 | 25 | foreach (var productKey in productKeys) 26 | { 27 | var architecture = "x86"; 28 | if (productKey.Equals(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall")) 29 | { 30 | architecture = "x64"; 31 | } 32 | 33 | var subkeyNames = ThisRunTime.GetSubkeyNames(RegistryHive.LocalMachine, productKey) ?? new string[] { }; 34 | foreach(var subkeyName in subkeyNames) 35 | { 36 | var DisplayName = ThisRunTime.GetStringValue(RegistryHive.LocalMachine, $"{productKey}\\{subkeyName}", "DisplayName"); 37 | var DisplayVersion = ThisRunTime.GetStringValue(RegistryHive.LocalMachine, $"{productKey}\\{subkeyName}", "DisplayVersion"); 38 | var Publisher = ThisRunTime.GetStringValue(RegistryHive.LocalMachine, $"{productKey}\\{subkeyName}", "Publisher"); 39 | var InstallDateStr = ThisRunTime.GetStringValue(RegistryHive.LocalMachine, $"{productKey}\\{subkeyName}", "InstallDateStr"); 40 | var InstallDate = new DateTime(); 41 | 42 | if (InstallDateStr != null && !String.IsNullOrEmpty(InstallDateStr)) 43 | { 44 | try 45 | { 46 | var year = InstallDateStr.Substring(0, 4); 47 | var month = InstallDateStr.Substring(4, 2); 48 | var day = InstallDateStr.Substring(6, 2); 49 | var date = $"{year}-{month}-{day}"; 50 | InstallDate = DateTime.Parse(date); 51 | } 52 | catch { } 53 | } 54 | 55 | if (DisplayName != null && !String.IsNullOrEmpty(DisplayName)) 56 | { 57 | yield return new InstalledProductsDTO( 58 | DisplayName, 59 | DisplayVersion, 60 | Publisher, 61 | InstallDate, 62 | architecture 63 | ); 64 | } 65 | } 66 | } 67 | } 68 | 69 | internal class InstalledProductsDTO : CommandDTOBase 70 | { 71 | public InstalledProductsDTO(string displayName, string? displayVersion, string? publisher, DateTime installDate, string architecture) 72 | { 73 | DisplayName = displayName; 74 | DisplayVersion = displayVersion; 75 | Publisher = publisher; 76 | InstallDate = installDate; 77 | Architecture = architecture; 78 | } 79 | public string DisplayName { get; } 80 | 81 | public string? DisplayVersion { get; } 82 | 83 | public string? Publisher { get; } 84 | 85 | public DateTime InstallDate { get; } 86 | 87 | public string Architecture { get; } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Products/KeePass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using Seatbelt.Util; 5 | 6 | namespace Seatbelt.Commands 7 | { 8 | internal class KeePassCommand : CommandBase 9 | { 10 | public override string Command => "KeePass"; 11 | public override string Description => "Finds KeePass configuration files"; 12 | public override CommandGroup[] Group => new[] { CommandGroup.User, CommandGroup.Remote }; 13 | public override bool SupportRemote => true; 14 | public Runtime ThisRunTime; 15 | 16 | public KeePassCommand(Runtime runtime) : base(runtime) 17 | { 18 | ThisRunTime = runtime; 19 | } 20 | 21 | public override IEnumerable Execute(string[] args) 22 | { 23 | var dirs = ThisRunTime.GetDirectories("\\Users\\"); 24 | 25 | foreach (var dir in dirs) 26 | { 27 | if (dir.EndsWith("Public") || dir.EndsWith("Default") || dir.EndsWith("Default User") || dir.EndsWith("All Users")) 28 | continue; 29 | 30 | if(File.Exists($"{dir}\\AppData\\Roaming\\KeePass\\KeePass.config.xml")) 31 | { 32 | string foundFile = $"{dir}\\AppData\\Roaming\\KeePass\\KeePass.config.xml"; 33 | var lastAccessed = File.GetLastAccessTime(foundFile); 34 | var lastModified = File.GetLastWriteTime(foundFile); 35 | var size = new FileInfo(foundFile).Length; 36 | 37 | yield return new KeePassDTO() 38 | { 39 | FileName = foundFile, 40 | MasterKeyGuid = "", 41 | LastAccessed = lastAccessed, 42 | LastModified = lastModified, 43 | Size = size 44 | }; 45 | } 46 | if (File.Exists($"{dir}\\AppData\\Roaming\\KeePass\\ProtectedUserKey.bin")) 47 | { 48 | string foundFile = $"{dir}\\AppData\\Roaming\\KeePass\\ProtectedUserKey.bin"; 49 | var lastAccessed = File.GetLastAccessTime(foundFile); 50 | var lastModified = File.GetLastWriteTime(foundFile); 51 | var size = new FileInfo(foundFile).Length; 52 | 53 | byte[] blobBytes = File.ReadAllBytes(foundFile); 54 | var offset = 24; 55 | var guidMasterKeyBytes = new byte[16]; 56 | Array.Copy(blobBytes, offset, guidMasterKeyBytes, 0, 16); 57 | var guidMasterKey = new Guid(guidMasterKeyBytes); 58 | var guidString = $"{{{guidMasterKey}}}"; 59 | 60 | yield return new KeePassDTO() 61 | { 62 | FileName = foundFile, 63 | LastAccessed = lastAccessed, 64 | LastModified = lastModified, 65 | MasterKeyGuid = guidString, 66 | Size = size 67 | }; 68 | } 69 | } 70 | } 71 | 72 | internal class KeePassDTO : CommandDTOBase 73 | { 74 | public string? FileName { get; set; } 75 | public string? MasterKeyGuid { get; set; } 76 | public DateTime? LastAccessed { get; set; } 77 | public DateTime? LastModified { get; set; } 78 | public long? Size { get; set; } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Products/McAfeeConfigsCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using Seatbelt.Util; 5 | 6 | namespace Seatbelt.Commands 7 | { 8 | internal class McAfeeConfigsCommand : CommandBase 9 | { 10 | public override string Command => "McAfeeConfigs"; 11 | public override string Description => "Finds McAfee configuration files"; 12 | public override CommandGroup[] Group => new[] { CommandGroup.System }; 13 | public override bool SupportRemote => false; // TODO when remote file searching is worked out... though it might take a while 14 | 15 | public McAfeeConfigsCommand(Runtime runtime) : base(runtime) 16 | { 17 | } 18 | 19 | public override IEnumerable Execute(string[] args) 20 | { 21 | // if -full is passed, or any argument is passed, recursively search common locations for configuration files 22 | if (!Runtime.FilterResults || (args.Length == 1)) 23 | { 24 | string[] paths = { @"C:\Program Files\", @"C:\Program Files (x86)\", @"C:\ProgramData\", @"C:\Documents and Settings\", @"C:\Users\" }; 25 | foreach (string path in paths) 26 | { 27 | foreach (string foundFile in MiscUtil.GetFileList(@"ma.db|SiteMgr.xml|SiteList.xml", path)) 28 | { 29 | var lastAccessed = File.GetLastAccessTime(foundFile); 30 | var lastModified = File.GetLastWriteTime(foundFile); 31 | var size = new FileInfo(foundFile).Length; 32 | 33 | yield return new McAfeeConfigsDTO() 34 | { 35 | FileName = foundFile, 36 | LastAccessed = lastAccessed, 37 | LastModified = lastModified, 38 | Size = size 39 | }; 40 | } 41 | } 42 | } 43 | else 44 | { 45 | string[] paths = { $"{Environment.GetEnvironmentVariable("SystemDrive")}\\Users\\All Users\\McAfee\\Agent\\DB\\ma.db", 46 | $"{Environment.GetEnvironmentVariable("SystemDrive")}\\ProgramData\\McAfee\\Agent\\DB\\ma.db"}; 47 | 48 | foreach (string path in paths) 49 | { 50 | if (File.Exists(path)) 51 | { 52 | var lastAccessed = File.GetLastAccessTime(path); 53 | var lastModified = File.GetLastWriteTime(path); 54 | var size = new FileInfo(path).Length; 55 | 56 | yield return new McAfeeConfigsDTO() 57 | { 58 | FileName = path, 59 | LastAccessed = lastAccessed, 60 | LastModified = lastModified, 61 | Size = size 62 | }; 63 | } 64 | } 65 | } 66 | } 67 | 68 | internal class McAfeeConfigsDTO : CommandDTOBase 69 | { 70 | public string? FileName { get; set; } 71 | public DateTime? LastAccessed { get; set; } 72 | public DateTime? LastModified { get; set; } 73 | public long? Size { get; set; } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Products/OneNoteCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Web.Script.Serialization; 5 | using Seatbelt.Output.Formatters; 6 | using Seatbelt.Output.TextWriters; 7 | 8 | 9 | namespace Seatbelt.Commands.Products 10 | { 11 | 12 | internal class OneNoteCommand : CommandBase 13 | { 14 | public override string Command => "OneNote"; 15 | public override string Description => "List OneNote backup files"; 16 | public override CommandGroup[] Group => new[] { CommandGroup.User }; 17 | public override bool SupportRemote => false; 18 | 19 | public Runtime ThisRunTime; 20 | 21 | public OneNoteCommand(Runtime runtime) : base(runtime) 22 | { 23 | ThisRunTime = runtime; 24 | } 25 | 26 | public override IEnumerable Execute(string[] args) 27 | { 28 | var dirs = ThisRunTime.GetDirectories("\\Users\\"); 29 | 30 | foreach (var dir in dirs) 31 | { 32 | var parts = dir.Split('\\'); 33 | var userName = parts[parts.Length - 1]; 34 | 35 | if (dir.EndsWith("Public") || dir.EndsWith("Default") || dir.EndsWith("Default User") || 36 | dir.EndsWith("All Users")) 37 | { 38 | continue; 39 | } 40 | 41 | var userOneNoteBasePath = $"{dir}\\AppData\\Local\\Microsoft\\OneNote"; 42 | var resultFiles = new List(); 43 | 44 | if (Directory.Exists(userOneNoteBasePath)) 45 | { 46 | var oneNoteFiles = Directory.GetFiles(userOneNoteBasePath, "*.one", SearchOption.AllDirectories); 47 | resultFiles.AddRange(oneNoteFiles); 48 | } 49 | 50 | yield return new OneNoteDTO( 51 | userName, 52 | resultFiles 53 | ); 54 | } 55 | } 56 | 57 | internal class OneNoteDTO : CommandDTOBase 58 | { 59 | public OneNoteDTO(string userName, List files) 60 | { 61 | UserName = userName; 62 | Files = files; 63 | } 64 | 65 | public string UserName { get; } 66 | public List Files { get; } 67 | } 68 | 69 | [CommandOutputType(typeof(OneNoteDTO))] 70 | internal class OneNoteFormatter : TextFormatterBase 71 | { 72 | public OneNoteFormatter(ITextWriter writer) : base(writer) 73 | { 74 | } 75 | 76 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 77 | { 78 | var dto = (OneNoteDTO)result; 79 | 80 | WriteLine($"\n OneNote files ({dto.UserName}):\n"); 81 | 82 | foreach (var file in dto.Files) 83 | { 84 | WriteLine($" {file}"); 85 | } 86 | WriteLine(); 87 | } 88 | } 89 | 90 | } 91 | } -------------------------------------------------------------------------------- /Seatbelt/Commands/Products/OracleSQLDeveloperCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using Seatbelt.Util; 5 | 6 | namespace Seatbelt.Commands 7 | { 8 | internal class OracleSQLDeveloperCommand : CommandBase 9 | { 10 | public override string Command => "OracleSQLDeveloper"; 11 | public override string Description => "Finds Oracle SQLDeveloper connections.xml files"; 12 | public override CommandGroup[] Group => new[] { CommandGroup.User }; 13 | public override bool SupportRemote => false; 14 | 15 | // NOTE: to decrypt, use https://pypi.org/project/sqldeveloperpassworddecryptor/ 16 | 17 | public OracleSQLDeveloperCommand(Runtime runtime) : base(runtime) 18 | { 19 | } 20 | 21 | public override IEnumerable Execute(string[] args) 22 | { 23 | var userFolder = $"{Environment.GetEnvironmentVariable("SystemDrive")}\\Users\\"; 24 | var dirs = Directory.GetDirectories(userFolder); 25 | 26 | foreach (var dir in dirs) 27 | { 28 | if (dir.EndsWith("Public") || dir.EndsWith("Default") || dir.EndsWith("Default User") || dir.EndsWith("All Users")) 29 | continue; 30 | 31 | foreach (string foundFile in MiscUtil.GetFileList(@"connections.xml", $"{dir}\\AppData\\Roaming\\SQL Developer\\")) 32 | { 33 | var lastAccessed = File.GetLastAccessTime(foundFile); 34 | var lastModified = File.GetLastWriteTime(foundFile); 35 | var size = new FileInfo(foundFile).Length; 36 | 37 | yield return new OracleConnectionsDTO() 38 | { 39 | FileName = foundFile, 40 | LastAccessed = lastAccessed, 41 | LastModified = lastModified, 42 | Size = size 43 | }; 44 | } 45 | } 46 | } 47 | 48 | internal class OracleConnectionsDTO : CommandDTOBase 49 | { 50 | public string? FileName { get; set; } 51 | public DateTime? LastAccessed { get; set; } 52 | public DateTime? LastModified { get; set; } 53 | public long? Size { get; set; } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Products/OutlookDownloadsCommand.cs: -------------------------------------------------------------------------------- 1 | #nullable disable 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using Seatbelt.Output.TextWriters; 6 | using Seatbelt.Output.Formatters; 7 | 8 | 9 | namespace Seatbelt.Commands.Windows 10 | { 11 | class OutlookDownload 12 | { 13 | public string FileName { get; set; } 14 | 15 | public DateTime LastAccessed { get; set; } 16 | 17 | public DateTime LastModified { get; set; } 18 | } 19 | 20 | internal class OutlookDownloadsCommand : CommandBase 21 | { 22 | public override string Command => "OutlookDownloads"; 23 | public override string Description => "List files downloaded by Outlook"; 24 | public override CommandGroup[] Group => new[] { CommandGroup.Misc }; 25 | public override bool SupportRemote => true; 26 | public Runtime ThisRunTime; 27 | 28 | public OutlookDownloadsCommand(Runtime runtime) : base(runtime) 29 | { 30 | ThisRunTime = runtime; 31 | } 32 | 33 | public override IEnumerable Execute(string[] args) 34 | { 35 | var dirs = ThisRunTime.GetDirectories("\\Users\\"); 36 | 37 | foreach (var dir in dirs) 38 | { 39 | if (dir.EndsWith("Public") || dir.EndsWith("Default") || dir.EndsWith("Default User") || dir.EndsWith("All Users")) 40 | { 41 | continue; 42 | } 43 | 44 | var userOutlookBasePath = $"{dir}\\AppData\\Local\\Microsoft\\Windows\\INetCache\\Content.Outlook\\"; 45 | if (!Directory.Exists(userOutlookBasePath)) 46 | { 47 | continue; 48 | } 49 | 50 | var directories = Directory.GetDirectories(userOutlookBasePath); 51 | foreach (var directory in directories) 52 | { 53 | var files = Directory.GetFiles(directory); 54 | 55 | var Downloads = new List(); 56 | 57 | foreach (var file in files) 58 | { 59 | var download = new OutlookDownload(); 60 | download.FileName = Path.GetFileName(file); 61 | download.LastAccessed = File.GetLastAccessTime(file); 62 | download.LastModified = File.GetLastAccessTime(file); 63 | Downloads.Add(download); 64 | } 65 | 66 | yield return new OutlookDownloadsDTO() 67 | { 68 | Folder = $"{directory}", 69 | Downloads = Downloads 70 | }; 71 | } 72 | } 73 | } 74 | 75 | internal class OutlookDownloadsDTO : CommandDTOBase 76 | { 77 | public string Folder { get; set; } 78 | public List Downloads { get; set; } 79 | } 80 | 81 | [CommandOutputType(typeof(OutlookDownloadsDTO))] 82 | internal class OutlookDownloadsFormatter : TextFormatterBase 83 | { 84 | public OutlookDownloadsFormatter(ITextWriter writer) : base(writer) 85 | { 86 | } 87 | 88 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 89 | { 90 | var dto = (OutlookDownloadsDTO)result; 91 | 92 | WriteLine(" Folder : {0}\n", dto.Folder); 93 | WriteLine($" LastAccessed LastModified FileName"); 94 | WriteLine($" ------------ ------------ --------"); 95 | 96 | foreach (var download in dto.Downloads) 97 | { 98 | WriteLine(" {0,-22} {1,-22} {2}", download.LastAccessed, download.LastModified, download.FileName); 99 | } 100 | 101 | WriteLine(); 102 | } 103 | } 104 | } 105 | } 106 | #nullable enable -------------------------------------------------------------------------------- /Seatbelt/Commands/Products/PuttyHostKeysCommand.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32; 2 | using System.Collections.Generic; 3 | using Seatbelt.Output.TextWriters; 4 | using Seatbelt.Output.Formatters; 5 | 6 | 7 | namespace Seatbelt.Commands 8 | { 9 | internal class PuttyHostKeysCommand : CommandBase 10 | { 11 | public override string Command => "PuttyHostKeys"; 12 | public override string Description => "Saved Putty SSH host keys"; 13 | public override CommandGroup[] Group => new[] { CommandGroup.User, CommandGroup.Remote }; 14 | public override bool SupportRemote => true; 15 | public Runtime ThisRunTime; 16 | 17 | public PuttyHostKeysCommand(Runtime runtime) : base(runtime) 18 | { 19 | ThisRunTime = runtime; 20 | } 21 | 22 | public override IEnumerable Execute(string[] args) 23 | { 24 | var SIDs = ThisRunTime.GetUserSIDs(); 25 | 26 | foreach (var sid in SIDs) 27 | { 28 | if (!sid.StartsWith("S-1-5") || sid.EndsWith("_Classes")) 29 | { 30 | continue; 31 | } 32 | 33 | var hostKeys = ThisRunTime.GetValues(RegistryHive.Users, $"{sid}\\Software\\SimonTatham\\PuTTY\\SshHostKeys\\"); 34 | if (hostKeys == null || hostKeys.Count == 0) 35 | { 36 | continue; 37 | } 38 | 39 | var keys = new List(); 40 | 41 | foreach (var kvp in hostKeys) 42 | { 43 | keys.Add($"{kvp.Key}"); 44 | } 45 | 46 | yield return new PuttyHostKeysDTO( 47 | sid, 48 | keys 49 | ); 50 | } 51 | } 52 | 53 | internal class PuttyHostKeysDTO : CommandDTOBase 54 | { 55 | public PuttyHostKeysDTO(string sid, List hostKeys) 56 | { 57 | Sid = sid; 58 | HostKeys = hostKeys; 59 | } 60 | public string Sid { get; } 61 | public List HostKeys { get; } 62 | } 63 | 64 | [CommandOutputType(typeof(PuttyHostKeysDTO))] 65 | internal class PuttyHostKeysFormatter : TextFormatterBase 66 | { 67 | public PuttyHostKeysFormatter(ITextWriter writer) : base(writer) 68 | { 69 | } 70 | 71 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 72 | { 73 | var dto = (PuttyHostKeysDTO)result; 74 | 75 | WriteLine(" {0} :", dto.Sid); 76 | 77 | foreach (var hostKey in dto.HostKeys) 78 | { 79 | WriteLine($" {hostKey}"); 80 | } 81 | WriteLine(); 82 | } 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Products/PuttySessionsCommand.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32; 2 | using System.Collections.Generic; 3 | using Seatbelt.Output.TextWriters; 4 | using Seatbelt.Output.Formatters; 5 | 6 | namespace Seatbelt.Commands 7 | { 8 | internal class PuttySessionsCommand : CommandBase 9 | { 10 | public override string Command => "PuttySessions"; 11 | public override string Description => "Saved Putty configuration (interesting fields) and SSH host keys"; 12 | public override CommandGroup[] Group => new[] { CommandGroup.User, CommandGroup.Remote }; 13 | public override bool SupportRemote => true; 14 | public Runtime ThisRunTime; 15 | 16 | public PuttySessionsCommand(Runtime runtime) : base(runtime) 17 | { 18 | ThisRunTime = runtime; 19 | } 20 | 21 | public override IEnumerable Execute(string[] args) 22 | { 23 | var SIDs = ThisRunTime.GetUserSIDs(); 24 | foreach (var sid in SIDs) 25 | { 26 | if (!sid.StartsWith("S-1-5") || sid.EndsWith("_Classes")) 27 | { 28 | continue; 29 | } 30 | 31 | var subKeys = ThisRunTime.GetSubkeyNames(RegistryHive.Users, $"{sid}\\Software\\SimonTatham\\PuTTY\\Sessions\\"); 32 | if (subKeys == null) 33 | continue; 34 | 35 | var Sessions = new List>(); 36 | 37 | foreach (var sessionName in subKeys) 38 | { 39 | var Settings = new Dictionary 40 | { 41 | ["SessionName"] = sessionName 42 | }; 43 | 44 | string[] keys = 45 | { 46 | "HostName", 47 | "UserName", 48 | "PublicKeyFile", 49 | "PortForwardings", 50 | "ConnectionSharing", 51 | "AgentFwd" 52 | }; 53 | 54 | foreach (var key in keys) 55 | { 56 | #nullable disable 57 | var result = ThisRunTime.GetStringValue(RegistryHive.Users, $"{sid}\\Software\\SimonTatham\\PuTTY\\Sessions\\{sessionName}", key); 58 | if (!string.IsNullOrEmpty(result)) 59 | { 60 | Settings[key] = result; 61 | } 62 | #nullable enable 63 | } 64 | 65 | Sessions.Add(Settings); 66 | } 67 | 68 | if (Sessions.Count != 0) 69 | { 70 | yield return new PuttySessionsDTO( 71 | sid, 72 | Sessions 73 | ); 74 | } 75 | } 76 | } 77 | 78 | internal class PuttySessionsDTO : CommandDTOBase 79 | { 80 | public PuttySessionsDTO(string sid, List> sessions) 81 | { 82 | Sid = sid; 83 | Sessions = sessions; 84 | } 85 | public string Sid { get; } 86 | 87 | public List> Sessions { get; } 88 | } 89 | 90 | [CommandOutputType(typeof(PuttySessionsDTO))] 91 | internal class ExplorerRunCommandFormatter : TextFormatterBase 92 | { 93 | public ExplorerRunCommandFormatter(ITextWriter writer) : base(writer) 94 | { 95 | } 96 | 97 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 98 | { 99 | var dto = (PuttySessionsDTO)result; 100 | 101 | WriteLine(" {0} :\n", dto.Sid); 102 | 103 | foreach (var session in dto.Sessions) 104 | { 105 | WriteLine(" {0,-20} : {1}", "SessionName", session["SessionName"]); 106 | 107 | foreach (var key in session.Keys) 108 | { 109 | if(!key.Equals("SessionName")) 110 | { 111 | WriteLine(" {0,-20} : {1}", key, session[key]); 112 | } 113 | } 114 | WriteLine(); 115 | } 116 | WriteLine(); 117 | } 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Products/RemoteDesktopConnectionManagerCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Xml; 5 | using Seatbelt.Output.TextWriters; 6 | using Seatbelt.Output.Formatters; 7 | 8 | 9 | namespace Seatbelt.Commands 10 | { 11 | internal class RemoteDesktopConnectionManagerCommand : CommandBase 12 | { 13 | public override string Command => "RDCManFiles"; 14 | public override string Description => "Windows Remote Desktop Connection Manager settings files"; 15 | public override CommandGroup[] Group => new[] { CommandGroup.User }; 16 | public override bool SupportRemote => false; 17 | public Runtime ThisRunTime; 18 | 19 | public RemoteDesktopConnectionManagerCommand(Runtime runtime) : base(runtime) 20 | { 21 | ThisRunTime = runtime; 22 | } 23 | 24 | public override IEnumerable Execute(string[] args) 25 | { 26 | var dirs = ThisRunTime.GetDirectories("\\Users\\"); 27 | 28 | var found = false; 29 | 30 | foreach (var dir in dirs) 31 | { 32 | if (dir.EndsWith("Public") || dir.EndsWith("Default") || dir.EndsWith("Default User") || dir.EndsWith("All Users")) 33 | continue; 34 | 35 | var userRDManFile = $"{dir}\\AppData\\Local\\Microsoft\\Remote Desktop Connection Manager\\RDCMan.settings"; 36 | if (!File.Exists(userRDManFile)) 37 | continue; 38 | 39 | // TODO: for remote triage, need to translate local paths to remote paths effectively 40 | 41 | var xmlDoc = new XmlDocument(); 42 | xmlDoc.Load(userRDManFile); 43 | 44 | // grab the recent RDG files 45 | var filesToOpen = xmlDoc.GetElementsByTagName("FilesToOpen"); 46 | var items = filesToOpen[0].ChildNodes; 47 | 48 | var lastAccessed = File.GetLastAccessTime(userRDManFile); 49 | var lastModified = File.GetLastWriteTime(userRDManFile); 50 | 51 | var rdgFiles = new List(); 52 | 53 | foreach (XmlNode rdgFile in items) 54 | { 55 | found = true; 56 | rdgFiles.Add(rdgFile.InnerText); 57 | } 58 | 59 | yield return new RemoteDesktopConnectionManagerDTO( 60 | userRDManFile, 61 | lastAccessed, 62 | lastModified, 63 | rdgFiles 64 | ); 65 | } 66 | 67 | if (found) 68 | { 69 | WriteHost(" [*] You can use SharpDPAPI or the Mimikatz \"dpapi::rdg\" module to decrypt any found .rdg files"); 70 | } 71 | } 72 | 73 | internal class RemoteDesktopConnectionManagerDTO : CommandDTOBase 74 | { 75 | public RemoteDesktopConnectionManagerDTO(string fileName, DateTime lastAccessed, DateTime lastModified, List rdgFiles) 76 | { 77 | FileName = fileName; 78 | LastAccessed = lastAccessed; 79 | LastModified = lastModified; 80 | RdgFiles = rdgFiles; 81 | } 82 | public string FileName { get; } 83 | 84 | public DateTime LastAccessed { get; } 85 | 86 | public DateTime LastModified { get; } 87 | 88 | public List RdgFiles { get; } 89 | } 90 | 91 | 92 | [CommandOutputType(typeof(RemoteDesktopConnectionManagerDTO))] 93 | internal class RemoteDesktopConnectionManagerFormatter : TextFormatterBase 94 | { 95 | public RemoteDesktopConnectionManagerFormatter(ITextWriter writer) : base(writer) 96 | { 97 | } 98 | 99 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 100 | { 101 | var dto = (RemoteDesktopConnectionManagerDTO)result; 102 | 103 | WriteLine(" RDCManFile : {0}", dto.FileName); 104 | WriteLine(" Accessed : {0}", dto.LastAccessed); 105 | WriteLine(" Modified : {0}", dto.LastModified); 106 | 107 | foreach(var rdgFile in dto.RdgFiles) 108 | { 109 | WriteLine(" .RDG File : {0}", rdgFile); 110 | } 111 | 112 | WriteLine(); 113 | } 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Products/SccmClientCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Microsoft.Win32; 3 | 4 | namespace Seatbelt.Commands 5 | { 6 | internal class SccmClientCommand : CommandBase 7 | { 8 | public override string Command => "SCCM"; 9 | public override string Description => "System Center Configuration Manager (SCCM) settings, if applicable"; 10 | public override CommandGroup[] Group => new[] { CommandGroup.System }; 11 | public override bool SupportRemote => true; 12 | public Runtime ThisRunTime; 13 | 14 | public SccmClientCommand(Runtime runtime) : base(runtime) 15 | { 16 | ThisRunTime = runtime; 17 | } 18 | 19 | public override IEnumerable Execute(string[] args) 20 | { 21 | yield return new SccmClientDTO( 22 | ThisRunTime.GetStringValue(RegistryHive.LocalMachine, @"SOFTWARE\Microsoft\CCMSetup", "LastValidMP"), 23 | ThisRunTime.GetStringValue(RegistryHive.LocalMachine, @"SOFTWARE\Microsoft\SMS\Mobile Client", "AssignedSiteCode"), 24 | ThisRunTime.GetStringValue(RegistryHive.LocalMachine, @"SOFTWARE\Microsoft\SMS\Mobile Client", "ProductVersion"), 25 | ThisRunTime.GetStringValue(RegistryHive.LocalMachine, @"SOFTWARE\Microsoft\SMS\Mobile Client", "LastSuccessfulInstallParams") // Sometimes contains the fallback server's hostname 26 | ); 27 | } 28 | } 29 | 30 | internal class SccmClientDTO : CommandDTOBase 31 | { 32 | public SccmClientDTO(string? server, string? siteCode, string? productVersion, string? lastSuccessfulInstallParams) 33 | { 34 | Server = server; 35 | SiteCode = siteCode; 36 | ProductVersion = productVersion; 37 | LastSuccessfulInstallParams = lastSuccessfulInstallParams; 38 | } 39 | public string? Server { get; } 40 | public string? SiteCode { get; } 41 | public string? ProductVersion { get; } 42 | public string? LastSuccessfulInstallParams { get; } 43 | } 44 | } -------------------------------------------------------------------------------- /Seatbelt/Commands/Products/WsusClientCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Microsoft.Win32; 3 | 4 | namespace Seatbelt.Commands 5 | { 6 | internal class WsusClientCommand : CommandBase 7 | { 8 | public override string Command => "WSUS"; 9 | public override string Description => "Windows Server Update Services (WSUS) settings, if applicable"; 10 | public override CommandGroup[] Group => new[] {CommandGroup.System}; 11 | public override bool SupportRemote => true; 12 | public Runtime ThisRunTime; 13 | 14 | public WsusClientCommand(Runtime runtime) : base(runtime) 15 | { 16 | ThisRunTime = runtime; 17 | } 18 | 19 | public override IEnumerable Execute(string[] args) 20 | { 21 | yield return new WsusClientDTO( 22 | (ThisRunTime.GetDwordValue(RegistryHive.LocalMachine, @"SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU", "UseWUServer") == 1), 23 | ThisRunTime.GetStringValue(RegistryHive.LocalMachine, @"SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate", "WUServer"), 24 | ThisRunTime.GetStringValue(RegistryHive.LocalMachine, @"SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate", "UpdateServiceUrlAlternate"), 25 | ThisRunTime.GetStringValue(RegistryHive.LocalMachine, @"SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate", "WUStatusServer") 26 | ); 27 | } 28 | } 29 | 30 | internal class WsusClientDTO : CommandDTOBase 31 | { 32 | public WsusClientDTO(bool? useWuServer, string? server, string? alternateServer, string? statisticsServer) 33 | { 34 | UseWUServer = useWuServer; 35 | Server = server; 36 | AlternateServer = alternateServer; 37 | StatisticsServer = statisticsServer; 38 | } 39 | public bool? UseWUServer { get; set; } 40 | public string? Server { get; set; } 41 | public string? AlternateServer { get; set; } 42 | public string? StatisticsServer { get; set; } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Seatbelt/Commands/VerboseDTO.cs: -------------------------------------------------------------------------------- 1 |  2 | using Seatbelt.Output.Formatters; 3 | using Seatbelt.Output.TextWriters; 4 | 5 | namespace Seatbelt.Commands 6 | { 7 | class VerboseDTO : CommandDTOBase 8 | { 9 | public VerboseDTO(string message) 10 | { 11 | Message = message; 12 | } 13 | 14 | public string Message { get; } 15 | } 16 | 17 | [CommandOutputType(typeof(VerboseDTO))] 18 | internal class VerboseTextFormatter : TextFormatterBase 19 | { 20 | public VerboseTextFormatter(ITextWriter writer) : base(writer) 21 | { 22 | } 23 | 24 | public override void FormatResult(CommandBase? command, CommandDTOBase dto, bool filterResults) 25 | { 26 | //WriteLine("VERBOSE: " + ((VerboseDTO)dto).Message); 27 | WriteLine(((VerboseDTO)dto).Message); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Seatbelt/Commands/WarningDTO.cs: -------------------------------------------------------------------------------- 1 |  2 | using Seatbelt.Output.Formatters; 3 | using Seatbelt.Output.TextWriters; 4 | 5 | namespace Seatbelt.Commands 6 | { 7 | class WarningDTO : CommandDTOBase 8 | { 9 | public WarningDTO(string message) 10 | { 11 | Message = message; 12 | } 13 | 14 | public string Message { get; } 15 | } 16 | 17 | [CommandOutputType(typeof(WarningDTO))] 18 | internal class WarningTextFormatter : TextFormatterBase 19 | { 20 | public WarningTextFormatter(ITextWriter writer) : base(writer) 21 | { 22 | } 23 | 24 | public override void FormatResult(CommandBase? command, CommandDTOBase dto, bool filterResults) 25 | { 26 | WriteLine("WARNING: " + ((WarningDTO)dto).Message); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/AMSIProvidersCommand.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32; 2 | using System.Collections.Generic; 3 | 4 | namespace Seatbelt.Commands.Windows 5 | { 6 | internal class AMSIProviderCommand : CommandBase 7 | { 8 | public override string Command => "AMSIProviders"; 9 | public override string Description => "Providers registered for AMSI"; 10 | public override CommandGroup[] Group => new[] { CommandGroup.System, CommandGroup.Remote }; 11 | public override bool SupportRemote => true; 12 | public Runtime ThisRunTime; 13 | 14 | public AMSIProviderCommand(Runtime runtime) : base(runtime) 15 | { 16 | ThisRunTime = runtime; 17 | } 18 | 19 | public override IEnumerable Execute(string[] args) 20 | { 21 | var providers = ThisRunTime.GetSubkeyNames(RegistryHive.LocalMachine, @"SOFTWARE\Microsoft\AMSI\Providers") ?? new string[] {}; 22 | foreach (var provider in providers) 23 | { 24 | var ProviderPath = ThisRunTime.GetStringValue(RegistryHive.LocalMachine, $"SOFTWARE\\Classes\\CLSID\\{provider}\\InprocServer32", ""); 25 | 26 | yield return new AMSIProviderDTO( 27 | provider, 28 | ProviderPath 29 | ); 30 | } 31 | } 32 | 33 | internal class AMSIProviderDTO : CommandDTOBase 34 | { 35 | public AMSIProviderDTO(string guid, string? providerPath) 36 | { 37 | GUID = guid; 38 | ProviderPath = providerPath; 39 | } 40 | public string GUID { get; set; } 41 | public string? ProviderPath { get; set; } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/AntiVirusCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Seatbelt.Interop; 4 | 5 | namespace Seatbelt.Commands.Windows 6 | { 7 | internal class AntiVirusCommand : CommandBase 8 | { 9 | public override string Command => "AntiVirus"; 10 | public override string Description => "Registered antivirus (via WMI)"; 11 | public override CommandGroup[] Group => new[] { CommandGroup.System, CommandGroup.Remote }; 12 | public override bool SupportRemote => true; 13 | public Runtime ThisRunTime; 14 | 15 | public AntiVirusCommand(Runtime runtime) : base(runtime) 16 | { 17 | ThisRunTime = runtime; 18 | } 19 | 20 | public override IEnumerable Execute(string[] args) 21 | { 22 | if (String.IsNullOrEmpty(ThisRunTime.ComputerName) && Shlwapi.IsWindowsServer()) 23 | { 24 | WriteHost("Cannot enumerate antivirus. root\\SecurityCenter2 WMI namespace is not available on Windows Servers"); 25 | yield break; 26 | } 27 | 28 | // lists installed VA products via WMI (the AntiVirusProduct class) 29 | 30 | var AVResults = new List(); 31 | 32 | try 33 | { 34 | var wmiData = ThisRunTime.GetManagementObjectSearcher(@"root\SecurityCenter2", "SELECT * FROM AntiVirusProduct"); 35 | var data = wmiData.Get(); 36 | 37 | foreach (var virusChecker in data) 38 | { 39 | AVResults.Add(new AntiVirusDTO( 40 | virusChecker["displayName"], 41 | virusChecker["pathToSignedProductExe"], 42 | virusChecker["pathToSignedReportingExe"] 43 | )); 44 | } 45 | } 46 | catch { } 47 | 48 | foreach(var AVResult in AVResults) 49 | { 50 | yield return AVResult; 51 | } 52 | } 53 | } 54 | 55 | internal class AntiVirusDTO : CommandDTOBase 56 | { 57 | public AntiVirusDTO(object engine, object productExe, object reportingExe) 58 | { 59 | Engine = engine; 60 | ProductEXE = productExe; 61 | ReportingEXE = reportingExe; 62 | } 63 | public object Engine { get; } 64 | public object ProductEXE { get; } 65 | public object ReportingEXE { get; } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/AuditPolicyRegistryCommand.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32; 2 | using System.Collections.Generic; 3 | using Seatbelt.Output.TextWriters; 4 | using Seatbelt.Output.Formatters; 5 | 6 | 7 | namespace Seatbelt.Commands.Windows 8 | { 9 | // TODO: If elevated, pull with Windows Audit Policy/Advanced Audit policy 10 | internal class AuditPolicyRegistryCommand : CommandBase 11 | { 12 | public override string Command => "AuditPolicyRegistry"; 13 | public override string Description => "Audit settings via the registry"; 14 | public override CommandGroup[] Group => new[] {CommandGroup.System, CommandGroup.Remote}; 15 | public override bool SupportRemote => true; 16 | public Runtime ThisRunTime; 17 | 18 | public AuditPolicyRegistryCommand(Runtime runtime) : base(runtime) 19 | { 20 | ThisRunTime = runtime; 21 | } 22 | 23 | public override IEnumerable Execute(string[] args) 24 | { 25 | // TODO: Expand the audit policy enumeration 26 | var settings = ThisRunTime.GetValues(RegistryHive.LocalMachine, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\\Audit"); 27 | 28 | if (settings == null) 29 | yield break; 30 | 31 | foreach (var kvp in settings) 32 | { 33 | if (kvp.Value.GetType().IsArray && (kvp.Value.GetType().GetElementType()?.ToString() == "System.String")) 34 | { 35 | var result = string.Join(",", (string[])kvp.Value); 36 | yield return new AuditPolicyDTO( 37 | kvp.Key, 38 | result 39 | ); 40 | } 41 | else 42 | { 43 | yield return new AuditPolicyDTO( 44 | kvp.Key, 45 | $"{kvp.Value}" 46 | ); 47 | } 48 | } 49 | } 50 | 51 | internal class AuditPolicyDTO : CommandDTOBase 52 | { 53 | public AuditPolicyDTO(string key, string value) 54 | { 55 | Key = key; 56 | Value = value; 57 | } 58 | public string Key { get; } 59 | public string Value { get; } 60 | } 61 | 62 | 63 | [CommandOutputType(typeof(AuditPolicyDTO))] 64 | internal class AuditPolicyTextFormatter : TextFormatterBase 65 | { 66 | public AuditPolicyTextFormatter(ITextWriter writer) : base(writer) 67 | { 68 | } 69 | 70 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 71 | { 72 | var dto = (AuditPolicyDTO)result; 73 | 74 | WriteLine(" {0,-30} : {1}", dto.Key, dto.Value); 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/AutoRunsCommand.cs: -------------------------------------------------------------------------------- 1 | #nullable disable 2 | using Microsoft.Win32; 3 | using System.Collections.Generic; 4 | using Seatbelt.Output.TextWriters; 5 | using Seatbelt.Output.Formatters; 6 | 7 | 8 | namespace Seatbelt.Commands.Windows 9 | { 10 | internal class AutoRunsCommand : CommandBase 11 | { 12 | public override string Command => "AutoRuns"; 13 | public override string Description => "Auto run executables/scripts/programs"; 14 | public override CommandGroup[] Group => new[] {CommandGroup.System}; 15 | public override bool SupportRemote => true; 16 | public Runtime ThisRunTime; 17 | 18 | public AutoRunsCommand(Runtime runtime) : base(runtime) 19 | { 20 | ThisRunTime = runtime; 21 | } 22 | 23 | public override IEnumerable Execute(string[] args) 24 | { 25 | //WriteHost("Registry Autoruns"); 26 | 27 | string[] autorunLocations = new string[] { 28 | "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", 29 | "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce", 30 | "SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Run", 31 | "SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\RunOnce", 32 | "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunService", 33 | "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnceService", 34 | "SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\RunService", 35 | "SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\RunOnceService" 36 | }; 37 | 38 | foreach (string autorunLocation in autorunLocations) 39 | { 40 | var settings = ThisRunTime.GetValues(RegistryHive.LocalMachine, autorunLocation); 41 | 42 | if ((settings != null) && (settings.Count != 0)) 43 | { 44 | AutoRunDTO entry = new AutoRunDTO(); 45 | 46 | entry.Key = System.String.Format("HKLM:\\{0}", autorunLocation); 47 | entry.Entries = new List(); 48 | 49 | foreach (KeyValuePair kvp in settings) 50 | { 51 | entry.Entries.Add(kvp.Value.ToString()); 52 | } 53 | 54 | yield return entry; 55 | } 56 | } 57 | } 58 | 59 | internal class AutoRunDTO : CommandDTOBase 60 | { 61 | public string Key { get; set; } 62 | public List Entries { get; set; } 63 | } 64 | 65 | [CommandOutputType(typeof(AutoRunDTO))] 66 | internal class AutoRunTextFormatter : TextFormatterBase 67 | { 68 | public AutoRunTextFormatter(ITextWriter writer) : base(writer) 69 | { 70 | } 71 | 72 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 73 | { 74 | var dto = (AutoRunDTO)result; 75 | 76 | WriteLine("\n {0} :", dto.Key); 77 | foreach (string entry in dto.Entries) 78 | { 79 | WriteLine(" {0}", entry); 80 | } 81 | } 82 | } 83 | } 84 | } 85 | #nullable enable -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/CertificateThumbprints.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Security.Cryptography.X509Certificates; 4 | using Seatbelt.Output.Formatters; 5 | using Seatbelt.Output.TextWriters; 6 | 7 | namespace Seatbelt.Commands 8 | { 9 | internal class CertificateThumbprintCommand : CommandBase 10 | { 11 | public override string Command => "CertificateThumbprints"; 12 | public override string Description => "Finds thumbprints for all certificate store certs on the system"; 13 | public override CommandGroup[] Group => new[] { CommandGroup.User, CommandGroup.System }; 14 | public override bool SupportRemote => false; 15 | 16 | public CertificateThumbprintCommand(Runtime runtime) : base(runtime) 17 | { 18 | } 19 | 20 | public override IEnumerable Execute(string[] args) 21 | { 22 | foreach (var storeName in new Enum[] { StoreName.Root, StoreName.CertificateAuthority, StoreName.AuthRoot, StoreName.TrustedPeople, StoreName.TrustedPublisher }) 23 | { 24 | foreach (var storeLocation in new Enum[] { StoreLocation.CurrentUser, StoreLocation.LocalMachine }) 25 | { 26 | var store = new X509Store((StoreName)storeName, (StoreLocation)storeLocation); 27 | store.Open(OpenFlags.ReadOnly); 28 | 29 | foreach (var certificate in store.Certificates) 30 | { 31 | if (!Runtime.FilterResults || (Runtime.FilterResults && (DateTime.Compare(certificate.NotAfter, DateTime.Now) >= 0))) 32 | { 33 | yield return new CertificateThumbprintDTO() 34 | { 35 | StoreName = $"{storeName}", 36 | StoreLocation = $"{storeLocation}", 37 | SimpleName = certificate.GetNameInfo(X509NameType.SimpleName, false), 38 | Thumbprint = certificate.Thumbprint, 39 | ExpiryDate = certificate.NotAfter, 40 | }; 41 | } 42 | } 43 | } 44 | } 45 | } 46 | 47 | internal class CertificateThumbprintDTO : CommandDTOBase 48 | { 49 | public string? StoreName { get; set; } 50 | public string? StoreLocation { get; set; } 51 | public string? SimpleName { get; set; } 52 | public string? Thumbprint { get; set; } 53 | public DateTime? ExpiryDate { get; set; } 54 | } 55 | 56 | [CommandOutputType(typeof(CertificateThumbprintDTO))] 57 | internal class CertificateThumbprintFormatter : TextFormatterBase 58 | { 59 | public CertificateThumbprintFormatter(ITextWriter writer) : base(writer) 60 | { 61 | } 62 | 63 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 64 | { 65 | var dto = (CertificateThumbprintDTO)result; 66 | WriteLine($"{dto.StoreLocation}\\{dto.StoreName} - {dto.Thumbprint} ({dto.SimpleName}) {dto.ExpiryDate}"); 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/CredentialGuardCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Seatbelt.Output.Formatters; 4 | using Seatbelt.Output.TextWriters; 5 | using System.Management; 6 | using System; 7 | 8 | namespace Seatbelt.Commands 9 | { 10 | enum VBS 11 | { 12 | NOT_ENABLED = 0, 13 | ENABLED_NOT_RUNNING = 1, 14 | ENABLED_AND_RUNNING = 2 15 | } 16 | 17 | internal class CredentialGuardCommand : CommandBase 18 | { 19 | public override string Command => "CredGuard"; 20 | public override string Description => "CredentialGuard configuration"; 21 | public override CommandGroup[] Group => new[] {CommandGroup.System}; 22 | public override bool SupportRemote => true; 23 | public Runtime ThisRunTime; 24 | 25 | 26 | public CredentialGuardCommand(Runtime runtime) : base(runtime) 27 | { 28 | ThisRunTime = runtime; 29 | } 30 | 31 | public override IEnumerable Execute(string[] args) 32 | { 33 | // adapted from @chrismaddalena's PR (https://github.com/GhostPack/Seatbelt/pull/22/files) 34 | 35 | // settings reference - https://www.tenforums.com/tutorials/68926-verify-if-device-guard-enabled-disabled-windows-10-a.html 36 | 37 | ManagementObjectCollection? data = null; 38 | try 39 | { 40 | var wmiData = ThisRunTime.GetManagementObjectSearcher(@"root\Microsoft\Windows\DeviceGuard", "SELECT * FROM Win32_DeviceGuard"); 41 | data = wmiData.Get(); 42 | } 43 | catch (ManagementException ex) when (ex.ErrorCode == ManagementStatus.InvalidNamespace) 44 | { 45 | WriteError(string.Format(" [X] 'Win32_DeviceGuard' WMI class unavailable", ex.Message)); 46 | } 47 | catch (Exception ex) 48 | { 49 | WriteError(ex.ToString()); 50 | } 51 | 52 | if (data == null) 53 | { 54 | yield break; 55 | } 56 | 57 | foreach (var result in data) 58 | { 59 | // reference: 60 | // https://github.com/GhostPack/Seatbelt/blob/f47c342150e70e96669017bbec258e27227ba1ef/Seatbelt/Program.cs#L1754-L1766 61 | 62 | var configCheck = (int[])result.GetPropertyValue("SecurityServicesConfigured"); 63 | var serviceCheck = (int[])result.GetPropertyValue("SecurityServicesRunning"); 64 | 65 | var vbsSetting = (VBS)0; 66 | var configured = false; 67 | var running = false; 68 | 69 | uint? vbs = (uint)result.GetPropertyValue("VirtualizationBasedSecurityStatus"); 70 | if(vbs != null) 71 | { 72 | vbsSetting = (VBS)vbs; 73 | } 74 | 75 | if(configCheck.Contains(1)) 76 | { 77 | configured = true; 78 | } 79 | 80 | if (serviceCheck.Contains(1)) 81 | { 82 | running = true; 83 | } 84 | 85 | yield return new CredGuardDTO() 86 | { 87 | VirtualizationBasedSecurityStatus = vbsSetting, 88 | Configured = configured, 89 | Running = running 90 | }; 91 | } 92 | } 93 | 94 | class CredGuardDTO : CommandDTOBase 95 | { 96 | public VBS VirtualizationBasedSecurityStatus { get; set; } 97 | 98 | public bool Configured { get; set; } 99 | 100 | public bool Running { get; set; } 101 | } 102 | 103 | [CommandOutputType(typeof(CredGuardDTO))] 104 | internal class CredentialGuardFormatter : TextFormatterBase 105 | { 106 | public CredentialGuardFormatter(ITextWriter writer) : base(writer) 107 | { 108 | } 109 | 110 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 111 | { 112 | var dto = (CredGuardDTO)result; 113 | 114 | 115 | } 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/DNSCacheCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Management; 4 | 5 | 6 | namespace Seatbelt.Commands.Windows 7 | { 8 | internal class DNSCacheCommand : CommandBase 9 | { 10 | public override string Command => "DNSCache"; 11 | public override string Description => "DNS cache entries (via WMI)"; 12 | public override CommandGroup[] Group => new[] {CommandGroup.System, CommandGroup.Remote}; 13 | public override bool SupportRemote => true; 14 | public Runtime ThisRunTime; 15 | 16 | public DNSCacheCommand(Runtime runtime) : base(runtime) 17 | { 18 | ThisRunTime = runtime; 19 | } 20 | 21 | public override IEnumerable Execute(string[] args) 22 | { 23 | ManagementObjectCollection? data = null; 24 | 25 | // lists the local DNS cache via WMI (MSFT_DNSClientCache class) 26 | try 27 | { 28 | var wmiData = ThisRunTime.GetManagementObjectSearcher(@"root\standardcimv2", "SELECT * FROM MSFT_DNSClientCache"); 29 | data = wmiData.Get(); 30 | } 31 | catch (ManagementException ex) when (ex.ErrorCode == ManagementStatus.InvalidNamespace) 32 | { 33 | WriteError(string.Format(" [X] 'MSFT_DNSClientCache' WMI class unavailable (minimum supported versions of Windows: 8/2012)", ex.Message)); 34 | } 35 | catch (Exception ex) 36 | { 37 | WriteError(ex.ToString()); 38 | } 39 | 40 | if (data == null) 41 | { 42 | yield break; 43 | } 44 | 45 | foreach (var o in data) 46 | { 47 | var result = (ManagementObject) o; 48 | yield return new DNSCacheDTO( 49 | result["Entry"], 50 | result["Name"], 51 | result["Data"] 52 | ); 53 | } 54 | 55 | data.Dispose(); 56 | } 57 | } 58 | 59 | internal class DNSCacheDTO : CommandDTOBase 60 | { 61 | public DNSCacheDTO(object entry, object name, object data) 62 | { 63 | Entry = entry; 64 | Name = name; 65 | Data = data; 66 | } 67 | public object Entry { get; set; } 68 | public object Name { get; set; } 69 | public object Data { get; set; } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/EnvironmentPathCommand.cs: -------------------------------------------------------------------------------- 1 | #nullable disable 2 | using System; 3 | using System.Security.AccessControl; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | 7 | namespace Seatbelt.Commands.Windows 8 | { 9 | internal class EnvironmentPathCommand : CommandBase 10 | { 11 | public override string Command => "EnvironmentPath"; 12 | public override string Description => "Current environment %PATH$ folders and SDDL information"; 13 | public override CommandGroup[] Group => new[] {CommandGroup.System}; 14 | public override bool SupportRemote => false; // doesn't make sense to implement as we have "EnvironmentVariables" for remote hosts 15 | 16 | public EnvironmentPathCommand(Runtime runtime) : base(runtime) 17 | { 18 | } 19 | 20 | public override IEnumerable Execute(string[] args) 21 | { 22 | var pathString = Environment.GetEnvironmentVariable("Path"); 23 | var paths = pathString.Split(';'); 24 | 25 | foreach(var path in paths) 26 | { 27 | var SDDL = ""; 28 | 29 | if(!String.IsNullOrEmpty(path.Trim())) 30 | { 31 | try 32 | { 33 | var security = Directory.GetAccessControl(path, AccessControlSections.Owner | AccessControlSections.Access); 34 | SDDL = security.GetSecurityDescriptorSddlForm(AccessControlSections.Owner | AccessControlSections.Access); 35 | } 36 | catch 37 | { 38 | // eat it 39 | } 40 | 41 | yield return new EnvironmentPathDTO() 42 | { 43 | Name = path.Trim(), 44 | SDDL = SDDL 45 | }; 46 | } 47 | } 48 | } 49 | 50 | internal class EnvironmentPathDTO : CommandDTOBase 51 | { 52 | public string Name { get; set; } 53 | public string SDDL { get; set; } 54 | } 55 | } 56 | } 57 | #nullable enable -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/EnvironmentVariableCommand.cs: -------------------------------------------------------------------------------- 1 | #nullable disable 2 | using Microsoft.Win32; 3 | using Seatbelt.Util; 4 | using System; 5 | using System.Collections.Generic; 6 | using Seatbelt.Output.TextWriters; 7 | using Seatbelt.Output.Formatters; 8 | 9 | 10 | namespace Seatbelt.Commands.Windows 11 | { 12 | internal class EnvironmentVariableCommand : CommandBase 13 | { 14 | public override string Command => "EnvironmentVariables"; 15 | public override string Description => "Current environment variables"; 16 | public override CommandGroup[] Group => new[] {CommandGroup.System, CommandGroup.Remote}; 17 | public override bool SupportRemote => true; 18 | public Runtime ThisRunTime; 19 | 20 | public EnvironmentVariableCommand(Runtime runtime) : base(runtime) 21 | { 22 | ThisRunTime = runtime; 23 | } 24 | 25 | public override IEnumerable Execute(string[] args) 26 | { 27 | var envVariables = new List(); 28 | 29 | try 30 | { 31 | var wmiData = ThisRunTime.GetManagementObjectSearcher(@"root\cimv2", "Select UserName,Name,VariableValue from win32_environment"); 32 | var data = wmiData.Get(); 33 | 34 | foreach (var envVariable in data) 35 | { 36 | envVariables.Add(new EnvironmentVariableDTO( 37 | envVariable["UserName"], 38 | envVariable["Name"], 39 | envVariable["VariableValue"] 40 | )); 41 | } 42 | } 43 | catch { } 44 | 45 | foreach (var envVariable in envVariables) 46 | { 47 | yield return envVariable; 48 | } 49 | 50 | } 51 | 52 | internal class EnvironmentVariableDTO : CommandDTOBase 53 | { 54 | public EnvironmentVariableDTO(object userName, object name, object value) 55 | { 56 | UserName = userName.ToString(); 57 | Name = name.ToString(); 58 | Value = value.ToString(); 59 | } 60 | public string UserName { get; set; } 61 | public string Name { get; set; } 62 | public string Value { get; set; } 63 | } 64 | 65 | 66 | [CommandOutputType(typeof(EnvironmentVariableDTO))] 67 | internal class EnvironmentVariableFormatter : TextFormatterBase 68 | { 69 | public EnvironmentVariableFormatter(ITextWriter writer) : base(writer) 70 | { 71 | } 72 | 73 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 74 | { 75 | var dto = (EnvironmentVariableDTO)result; 76 | 77 | WriteLine(" {0,-35}{1,-35}{2}", dto.UserName, dto.Name, dto.Value); 78 | } 79 | } 80 | } 81 | } 82 | #nullable enable -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/EventLogs/ExplicitLogonEvents/ExplicitLogonEventsCommandDTO.cs: -------------------------------------------------------------------------------- 1 | #nullable disable 2 | using System; 3 | 4 | namespace Seatbelt.Commands.Windows.EventLogs.ExplicitLogonEvents 5 | { 6 | internal class ExplicitLogonEventsDTO : CommandDTOBase 7 | { 8 | public string SubjectUser { get; set; } 9 | public string SubjectDomain { get; set; } 10 | public string TargetUser { get; set; } 11 | public string TargetDomain { get; set; } 12 | public string Process { get; set; } 13 | public string IpAddress { get; set; } 14 | public DateTime? TimeCreatedUtc { get; set; } 15 | } 16 | } 17 | #nullable enable 18 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/EventLogs/ExplicitLogonEvents/ExplicitLogonEventsTextFormatter.cs: -------------------------------------------------------------------------------- 1 | using Seatbelt.Output.Formatters; 2 | using Seatbelt.Output.TextWriters; 3 | using System.Collections.Generic; 4 | 5 | namespace Seatbelt.Commands.Windows.EventLogs.ExplicitLogonEvents 6 | { 7 | [CommandOutputType(typeof(ExplicitLogonEventsDTO))] 8 | internal class ExplicitLogonEventsTextFormatter : TextFormatterBase 9 | { 10 | private readonly Dictionary> events = new Dictionary>(); 11 | 12 | public ExplicitLogonEventsTextFormatter(ITextWriter writer) : base(writer) 13 | { 14 | } 15 | 16 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 17 | { 18 | var dto = (ExplicitLogonEventsDTO)result; 19 | 20 | var targetUser = dto.TargetDomain + "\\" + dto.TargetUser; 21 | var subjectUser = dto.SubjectDomain + "\\" + dto.SubjectUser; 22 | var uniqueCredKey = $"{targetUser},{dto.Process},{subjectUser},{dto.IpAddress}"; 23 | 24 | WriteLine($"{dto.TimeCreatedUtc?.ToLocalTime().ToString("MM/dd/yyyy hh:mm tt")},{uniqueCredKey}"); 25 | 26 | //if (events.TryGetValue(uniqueCredKey, out _) == false) 27 | //{ 28 | // events[uniqueCredKey] = new List 29 | // { 30 | // dto.TimeCreated.ToString() 31 | // }; 32 | //} 33 | //else 34 | //{ 35 | // events[uniqueCredKey].Add(dto.TimeCreated.ToString()); 36 | //} 37 | 38 | 39 | //foreach (string key in events.Keys) 40 | //{ 41 | // WriteLine("\n\n --- " + key + " ---"); 42 | // var dates = events[key].ToArray(); 43 | // for (int i = 0; i < dates.Length; i++) 44 | // { 45 | // if (i % 4 == 0) 46 | // { 47 | // Write("\n "); 48 | // } 49 | 50 | // Write(dates[i].PadRight(24)); 51 | // } 52 | 53 | // Write("\n"); 54 | 55 | 56 | //WriteLine("\n\n --- " + key + " ---"); 57 | //var dates = events[key].ToArray(); 58 | 59 | //for (var i = 0; i < dates.Length; i++) 60 | //{ 61 | // if (i % 4 == 0) 62 | // { 63 | // WriteHost("\n "); 64 | // } 65 | 66 | // WriteHost(dates[i]); 67 | 68 | // if (i != dates.Length - 1) 69 | // { 70 | // WriteHost(", "); 71 | // } 72 | //} 73 | 74 | //WriteLine(); 75 | //} 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/EventLogs/ProcessCreationEventsCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.Eventing.Reader; 4 | using System.Text.RegularExpressions; 5 | using Seatbelt.Output.Formatters; 6 | using Seatbelt.Output.TextWriters; 7 | using Seatbelt.Util; 8 | 9 | 10 | namespace Seatbelt.Commands.Windows.EventLogs 11 | { 12 | internal class ProcessCreationEventsCommand : CommandBase 13 | { 14 | public override string Command => "ProcessCreationEvents"; 15 | public override string Description => "Process creation logs (4688) with sensitive data."; 16 | public override CommandGroup[] Group => new[] { CommandGroup.Misc }; 17 | public override bool SupportRemote => true; 18 | public Runtime ThisRunTime; 19 | 20 | public ProcessCreationEventsCommand(Runtime runtime) : base(runtime) 21 | { 22 | ThisRunTime = runtime; 23 | } 24 | 25 | public override IEnumerable Execute(string[] args) 26 | { 27 | if (!SecurityUtil.IsHighIntegrity() && !ThisRunTime.ISRemote()) 28 | { 29 | WriteError("Unable to collect. Must be an administrator."); 30 | yield break; 31 | } 32 | 33 | WriteVerbose($"Searching process creation logs (EID 4688) for sensitive data."); 34 | WriteVerbose($"Format: Date(Local time),User,Command line.\n"); 35 | 36 | // Get our "sensitive" cmdline regexes from a common helper function. 37 | var processCmdLineRegex = MiscUtil.GetProcessCmdLineRegex(); 38 | 39 | if (args.Length >= 1) 40 | { 41 | string allArgs = String.Join(" ", args); 42 | processCmdLineRegex = new Regex[] { new Regex(allArgs, RegexOptions.IgnoreCase & RegexOptions.Multiline) }; 43 | } 44 | 45 | var query = $"*[System/EventID=4688]"; 46 | var logReader = ThisRunTime.GetEventLogReader("Security", query); 47 | 48 | for (var eventDetail = logReader.ReadEvent(); eventDetail != null; eventDetail = logReader.ReadEvent()) 49 | { 50 | var user = eventDetail.Properties[1].Value.ToString().Trim(); 51 | var commandLine = eventDetail.Properties[8].Value.ToString().Trim(); 52 | 53 | foreach (var reg in processCmdLineRegex) 54 | { 55 | var m = reg.Match(commandLine); 56 | if (m.Success) 57 | { 58 | yield return new ProcessCreationEventDTO( 59 | eventDetail.TimeCreated?.ToUniversalTime(), 60 | eventDetail.Id, 61 | user, 62 | commandLine 63 | ); 64 | } 65 | } 66 | } 67 | } 68 | } 69 | 70 | internal class ProcessCreationEventDTO : CommandDTOBase 71 | { 72 | public ProcessCreationEventDTO(DateTime? timeCreatedUtc, int eventId, string user, string match) 73 | { 74 | TimeCreatedUtc = timeCreatedUtc; 75 | EventID = eventId; 76 | User = user; 77 | Match = match; 78 | } 79 | public DateTime? TimeCreatedUtc { get; set; } 80 | public int EventID { get; set; } 81 | public string User { get; set; } 82 | public string Match { get; set; } 83 | } 84 | 85 | [CommandOutputType(typeof(ProcessCreationEventDTO))] 86 | internal class ProcessCreationEventTextFormatter : TextFormatterBase 87 | { 88 | public ProcessCreationEventTextFormatter(ITextWriter writer) : base(writer) 89 | { 90 | } 91 | 92 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 93 | { 94 | var dto = (ProcessCreationEventDTO)result; 95 | 96 | WriteLine($" {dto.TimeCreatedUtc?.ToLocalTime(),-22} {dto.User,-30} {dto.Match}"); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/EventLogs/SysmonEventsCommand.cs: -------------------------------------------------------------------------------- 1 | #nullable disable 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics.Eventing.Reader; 5 | using System.Text.RegularExpressions; 6 | using Seatbelt.Util; 7 | 8 | 9 | namespace Seatbelt.Commands.Windows.EventLogs 10 | { 11 | internal class SysmonEventCommand : CommandBase 12 | { 13 | public override string Command => "SysmonEvents"; 14 | public override string Description => "Sysmon process creation logs (1) with sensitive data."; 15 | public override CommandGroup[] Group => new[] { CommandGroup.Misc }; 16 | public override bool SupportRemote => true; 17 | public Runtime ThisRunTime; 18 | 19 | public SysmonEventCommand(Runtime runtime) : base(runtime) 20 | { 21 | ThisRunTime = runtime; 22 | } 23 | 24 | public override IEnumerable Execute(string[] args) 25 | { 26 | if (!SecurityUtil.IsHighIntegrity() && !ThisRunTime.ISRemote()) 27 | { 28 | WriteError("Unable to collect. Must be an administrator."); 29 | yield break; 30 | } 31 | 32 | WriteVerbose($"Searching Sysmon process creation logs (Sysmon ID 1) for sensitive data.\n"); 33 | 34 | // Get our "sensitive" cmdline regexes from a common helper function. 35 | Regex[] processCmdLineRegex = MiscUtil.GetProcessCmdLineRegex(); 36 | 37 | if (args.Length >= 1) 38 | { 39 | string allArgs = String.Join(" ", args); 40 | processCmdLineRegex = new Regex[] { new Regex(allArgs, RegexOptions.IgnoreCase & RegexOptions.Multiline) }; 41 | } 42 | 43 | var query = "*[System/EventID=1]"; 44 | EventLogReader logReader = null; 45 | try 46 | { 47 | logReader = ThisRunTime.GetEventLogReader("Microsoft-Windows-Sysmon/Operational", query); 48 | } 49 | catch 50 | { 51 | WriteError("Unable to query Sysmon event logs, Sysmon likely not installed."); 52 | yield break; 53 | } 54 | 55 | var i = 0; 56 | 57 | for (var eventDetail = logReader.ReadEvent(); eventDetail != null; eventDetail = logReader.ReadEvent()) 58 | { 59 | ++i; 60 | var commandLine = eventDetail.Properties[10].Value.ToString().Trim(); 61 | if (commandLine != "") 62 | { 63 | foreach (var reg in processCmdLineRegex) 64 | { 65 | var m = reg.Match(commandLine); 66 | if (m.Success) 67 | { 68 | var userName = eventDetail.Properties[12].Value.ToString().Trim(); 69 | yield return new SysmonEventDTO() 70 | { 71 | TimeCreated = eventDetail.TimeCreated, 72 | EventID = eventDetail.Id, 73 | UserName = userName, 74 | Match = m.Value 75 | }; 76 | } 77 | } 78 | } 79 | } 80 | } 81 | } 82 | 83 | internal class SysmonEventDTO : CommandDTOBase 84 | { 85 | public DateTime? TimeCreated { get; set; } 86 | public int EventID { get; set; } 87 | public string UserName { get; set; } 88 | public string Match { get; set; } 89 | } 90 | } 91 | #nullable enable -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/ExplorerRunCommandCommand.cs: -------------------------------------------------------------------------------- 1 | #nullable disable 2 | using Microsoft.Win32; 3 | using System.Collections.Generic; 4 | using Seatbelt.Output.TextWriters; 5 | using Seatbelt.Output.Formatters; 6 | 7 | namespace Seatbelt.Commands.Windows 8 | { 9 | class ExplorerRunCommand 10 | { 11 | public string Key { get; set; } 12 | public string Value { get; set; } 13 | } 14 | 15 | internal class ExplorerRunCommandCommand : CommandBase 16 | { 17 | public override string Command => "ExplorerRunCommands"; 18 | public override string Description => "Recent Explorer \"run\" commands"; 19 | public override CommandGroup[] Group => new[] { CommandGroup.User, CommandGroup.Remote }; 20 | public override bool SupportRemote => true; 21 | public Runtime ThisRunTime; 22 | 23 | public ExplorerRunCommandCommand(Runtime runtime) : base(runtime) 24 | { 25 | ThisRunTime = runtime; 26 | } 27 | 28 | public override IEnumerable Execute(string[] args) 29 | { 30 | // lists recently run commands via the RunMRU registry key 31 | 32 | var SIDs = ThisRunTime.GetUserSIDs(); 33 | 34 | foreach (var sid in SIDs) 35 | { 36 | if (!sid.StartsWith("S-1-5") || sid.EndsWith("_Classes")) 37 | { 38 | continue; 39 | } 40 | 41 | var recentCommands = ThisRunTime.GetValues(RegistryHive.Users, $"{sid}\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU"); 42 | if ((recentCommands == null) || (recentCommands.Count == 0)) 43 | { 44 | continue; 45 | } 46 | 47 | var commands = new List(); 48 | 49 | foreach (var kvp in recentCommands) 50 | { 51 | var command = new ExplorerRunCommand(); 52 | command.Key = kvp.Key; 53 | command.Value = $"{kvp.Value}"; 54 | commands.Add(command); 55 | } 56 | 57 | yield return new ExplorerRunCommandDTO( 58 | sid, 59 | commands 60 | ); 61 | } 62 | } 63 | 64 | internal class ExplorerRunCommandDTO : CommandDTOBase 65 | { 66 | public ExplorerRunCommandDTO(string sid, List commands) 67 | { 68 | Sid = sid; 69 | Commands = commands; 70 | } 71 | public string Sid { get; set; } 72 | public List Commands { get; set; } 73 | } 74 | 75 | [CommandOutputType(typeof(ExplorerRunCommandDTO))] 76 | internal class ExplorerRunCommandFormatter : TextFormatterBase 77 | { 78 | public ExplorerRunCommandFormatter(ITextWriter writer) : base(writer) 79 | { 80 | } 81 | 82 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 83 | { 84 | var dto = (ExplorerRunCommandDTO)result; 85 | 86 | WriteLine("\n {0} :", dto.Sid); 87 | 88 | foreach (var runCommand in dto.Commands) 89 | { 90 | WriteLine(" {0,-10} : {1}", runCommand.Key, runCommand.Value); 91 | } 92 | } 93 | } 94 | } 95 | } 96 | #nullable enable -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/HotfixesCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Seatbelt.Output.Formatters; 4 | using Seatbelt.Output.TextWriters; 5 | 6 | namespace Seatbelt.Commands.Windows 7 | { 8 | internal class HotfixCommand : CommandBase 9 | { 10 | public override string Command => "Hotfixes"; 11 | public override string Description => "Installed hotfixes (via WMI)"; 12 | public override CommandGroup[] Group => new[] { CommandGroup.System, CommandGroup.Remote }; 13 | public override bool SupportRemote => true; 14 | public Runtime ThisRunTime; 15 | 16 | public HotfixCommand(Runtime runtime) : base(runtime) 17 | { 18 | ThisRunTime = runtime; 19 | } 20 | 21 | public override IEnumerable Execute(string[] args) 22 | { 23 | // Lists installed hotfixes via WMI (the Win32_QuickFixEngineering class) 24 | // This is similar to PowerShell's Get-Hotfix 25 | // Note: This class returns only the updates supplied by Component Based Servicing (CBS). 26 | // Updates supplied by Microsoft Windows Installer (MSI) or the Windows update site (https://update.microsoft.com) are not returned. 27 | // Translation: this only shows (usually) _Windows_ updates, not all _Microsoft_ updates. For that use the "MicrosoftUpdates" command. 28 | 29 | WriteHost("Enumerating Windows Hotfixes. For *all* Microsoft updates, use the 'MicrosoftUpdates' command.\r\n"); 30 | 31 | var wmiData = ThisRunTime.GetManagementObjectSearcher(@"root\cimv2", "SELECT * FROM Win32_QuickFixEngineering"); 32 | var data = wmiData.Get(); 33 | foreach (var hotfix in data) 34 | { 35 | DateTime? InstalledOn; 36 | try 37 | { 38 | InstalledOn = Convert.ToDateTime(hotfix["InstalledOn"].ToString()).ToUniversalTime(); 39 | } 40 | catch 41 | { 42 | InstalledOn = null; 43 | } 44 | yield return new HotfixDTO( 45 | hotfix["HotFixID"].ToString(), 46 | InstalledOn, 47 | hotfix["Description"].ToString(), 48 | hotfix["InstalledBy"].ToString() 49 | ); 50 | } 51 | } 52 | } 53 | 54 | internal class HotfixDTO : CommandDTOBase 55 | { 56 | public HotfixDTO(string hotFixID, DateTime? installedOnUTC, string description, string installedBy) 57 | { 58 | HotFixID = hotFixID; 59 | InstalledOnUTC = installedOnUTC; 60 | Description = description; 61 | InstalledBy = installedBy; 62 | } 63 | public string HotFixID { get; set; } 64 | public DateTime? InstalledOnUTC { get; set; } 65 | public string Description { get; set; } 66 | public string InstalledBy { get; set; } 67 | } 68 | 69 | [CommandOutputType(typeof(HotfixDTO))] 70 | internal class HotfixTextFormatter : TextFormatterBase 71 | { 72 | public HotfixTextFormatter(ITextWriter writer) : base(writer) 73 | { 74 | } 75 | 76 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 77 | { 78 | var dto = (HotfixDTO)result; 79 | 80 | WriteLine($" {dto.HotFixID,-10} {dto.InstalledOnUTC?.ToLocalTime(),-22} {dto.Description,-30} {dto.InstalledBy}"); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/IdleTimeCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Runtime.InteropServices; 5 | using static Seatbelt.Interop.User32; 6 | using Seatbelt.Output.Formatters; 7 | using Seatbelt.Output.TextWriters; 8 | 9 | 10 | namespace Seatbelt.Commands.Windows 11 | { 12 | internal class IdleTimeCommand : CommandBase 13 | { 14 | public override string Command => "IdleTime"; 15 | public override string Description => "Returns the number of seconds since the current user's last input."; 16 | public override CommandGroup[] Group => new[] { CommandGroup.User }; 17 | public override bool SupportRemote => false; // not possible 18 | 19 | 20 | public IdleTimeCommand(Runtime runtime) : base(runtime) 21 | { 22 | } 23 | 24 | public override IEnumerable Execute(string[] args) 25 | { 26 | var lastInputInfo = new LastInputInfo(); 27 | lastInputInfo.Size = (uint)Marshal.SizeOf(lastInputInfo); 28 | 29 | if (GetLastInputInfo(ref lastInputInfo)) 30 | { 31 | var currentUser = System.Security.Principal.WindowsIdentity.GetCurrent().Name; 32 | yield return new IdleTimeDTO( 33 | currentUser, 34 | ((uint) Environment.TickCount - lastInputInfo.Time) 35 | ); 36 | } 37 | else 38 | { 39 | throw new Win32Exception(Marshal.GetLastWin32Error()); 40 | } 41 | } 42 | } 43 | 44 | internal class IdleTimeDTO : CommandDTOBase 45 | { 46 | public IdleTimeDTO(string currentUser, uint milliseconds) 47 | { 48 | CurrentUser = currentUser; 49 | Milliseconds = milliseconds; 50 | } 51 | public string CurrentUser { get; } 52 | 53 | public uint Milliseconds { get; } 54 | } 55 | 56 | [CommandOutputType(typeof(IdleTimeDTO))] 57 | internal class IdleTimeFormatter : TextFormatterBase 58 | { 59 | public IdleTimeFormatter(ITextWriter writer) : base(writer) 60 | { 61 | } 62 | 63 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 64 | { 65 | var dto = (IdleTimeDTO)result; 66 | 67 | var t = TimeSpan.FromMilliseconds(dto.Milliseconds); 68 | var idleTime = string.Format("{0:D2}h:{1:D2}m:{2:D2}s:{3:D3}ms", 69 | t.Hours, 70 | t.Minutes, 71 | t.Seconds, 72 | t.Milliseconds); 73 | 74 | WriteLine($" CurrentUser : {dto.CurrentUser}"); 75 | WriteLine($" Idletime : {idleTime} ({dto.Milliseconds} milliseconds)\n"); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/LastShutdownCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.Win32; 4 | 5 | 6 | namespace Seatbelt.Commands.Windows 7 | { 8 | internal class LastShutdownCommand : CommandBase 9 | { 10 | public override string Command => "LastShutdown"; 11 | public override string Description => "Returns the DateTime of the last system shutdown (via the registry)."; 12 | public override CommandGroup[] Group => new[] { CommandGroup.System, CommandGroup.Remote }; 13 | public override bool SupportRemote => true; 14 | public Runtime ThisRunTime; 15 | 16 | public LastShutdownCommand(Runtime runtime) : base(runtime) 17 | { 18 | ThisRunTime = runtime; 19 | } 20 | 21 | public override IEnumerable Execute(string[] args) 22 | { 23 | var shutdownBytes = ThisRunTime.GetBinaryValue(RegistryHive.LocalMachine, "SYSTEM\\ControlSet001\\Control\\Windows", "ShutdownTime"); 24 | if (shutdownBytes != null) 25 | { 26 | var shutdownInt = BitConverter.ToInt64(shutdownBytes, 0); 27 | var shutdownTime = DateTime.FromFileTime(shutdownInt); 28 | 29 | yield return new LastShutdownDTO() 30 | { 31 | LastShutdown = shutdownTime 32 | }; 33 | } 34 | } 35 | } 36 | 37 | internal class LastShutdownDTO : CommandDTOBase 38 | { 39 | public DateTime LastShutdown { get; set; } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/LocalGroupMembershipCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Seatbelt.Output.Formatters; 5 | using Seatbelt.Output.TextWriters; 6 | using static Seatbelt.Interop.Netapi32; 7 | 8 | 9 | namespace Seatbelt.Commands.Windows 10 | { 11 | internal class LocalGroupMembershipCommand : CommandBase 12 | { 13 | public override string Command => "LocalGroups"; 14 | public override string Description => "Non-empty local groups, \"-full\" displays all groups (argument == computername to enumerate)"; 15 | public override CommandGroup[] Group => new[] {CommandGroup.System, CommandGroup.Remote}; 16 | public override bool SupportRemote => true; 17 | public Runtime ThisRunTime; 18 | 19 | public LocalGroupMembershipCommand(Runtime runtime) : base(runtime) 20 | { 21 | ThisRunTime = runtime; 22 | } 23 | 24 | public override IEnumerable Execute(string[] args) 25 | { 26 | // takes an optional remote computername as an argument, otherwise defaults to the localhost 27 | 28 | string? computerName = null; 29 | if(!String.IsNullOrEmpty(ThisRunTime.ComputerName)) 30 | { 31 | computerName = ThisRunTime.ComputerName; 32 | } 33 | else if (args.Length >= 1) 34 | { 35 | computerName = args[0]; 36 | } 37 | 38 | // adapted from https://stackoverflow.com/questions/33935825/pinvoke-netlocalgroupgetmembers-runs-into-fatalexecutionengineerror/33939889#33939889 39 | 40 | WriteHost(Runtime.FilterResults ? "Non-empty Local Groups (and memberships)\n\n" : "All Local Groups (and memberships)\n\n"); 41 | 42 | foreach(var group in GetLocalGroups(computerName)) 43 | { 44 | var members = GetLocalGroupMembers(computerName, group.name)?.ToList(); 45 | if (members != null && members.Any()) 46 | { 47 | yield return new LocalGroupMembershipDTO( 48 | computerName ?? Environment.MachineName, 49 | group.name, 50 | group.comment, 51 | members 52 | ); 53 | } 54 | } 55 | } 56 | } 57 | 58 | internal class LocalGroupMembershipDTO : CommandDTOBase 59 | { 60 | public LocalGroupMembershipDTO(string computerName, string groupName, string groupComment, IEnumerable members) 61 | { 62 | ComputerName = computerName; 63 | GroupName = groupName; 64 | GroupComment = groupComment; 65 | Members = members; 66 | } 67 | 68 | public string ComputerName { get; } 69 | public string GroupName { get; } 70 | public string GroupComment { get; } 71 | public IEnumerable Members { get; } 72 | } 73 | 74 | [CommandOutputType(typeof(LocalGroupMembershipDTO))] 75 | internal class LocalGroupMembershipTextFormatter : TextFormatterBase 76 | { 77 | public LocalGroupMembershipTextFormatter(ITextWriter writer) : base(writer) 78 | { 79 | } 80 | 81 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 82 | { 83 | 84 | if (result == null) 85 | { 86 | return; 87 | } 88 | 89 | var dto = (LocalGroupMembershipDTO)result; 90 | WriteLine(" ** {0}\\{1} ** ({2})\n", dto.ComputerName, dto.GroupName, dto.GroupComment); 91 | 92 | if (dto.Members != null) 93 | { 94 | foreach (var member in dto.Members) 95 | { 96 | WriteLine($" {member.Class,-15} {member.Domain + "\\" + member.User,-40} {member.Sid}"); 97 | } 98 | } 99 | 100 | WriteLine(); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/LocalSecurityAuthorityCommand.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32; 2 | using System.Collections.Generic; 3 | using System.Text.RegularExpressions; 4 | using Seatbelt.Output.TextWriters; 5 | using Seatbelt.Output.Formatters; 6 | 7 | 8 | namespace Seatbelt.Commands.Windows 9 | { 10 | internal class LocalSecurityAuthorityCommand : CommandBase 11 | { 12 | public override string Command => "LSASettings"; 13 | public override string Description => "LSA settings (including auth packages)"; 14 | public override CommandGroup[] Group => new[] { CommandGroup.System, CommandGroup.Remote }; 15 | public override bool SupportRemote => true; 16 | public Runtime ThisRunTime; 17 | 18 | public LocalSecurityAuthorityCommand(Runtime runtime) : base(runtime) 19 | { 20 | ThisRunTime = runtime; 21 | } 22 | 23 | public override IEnumerable Execute(string[] args) 24 | { 25 | var settings = ThisRunTime.GetValues(RegistryHive.LocalMachine, "SYSTEM\\CurrentControlSet\\Control\\Lsa"); 26 | 27 | if ((settings != null) && (settings.Count != 0)) 28 | { 29 | foreach (var kvp in settings) 30 | { 31 | if (kvp.Value.GetType().IsArray && (kvp.Value.GetType().GetElementType().ToString() == "System.String")) 32 | { 33 | var result = string.Join(",", (string[])kvp.Value); 34 | 35 | yield return new LocalSecurityAuthorityDTO(kvp.Key, result); 36 | } 37 | else if (kvp.Value.GetType().IsArray && (kvp.Value.GetType().GetElementType().ToString() == "System.Byte")) 38 | { 39 | var result = System.BitConverter.ToString((byte[])kvp.Value); 40 | yield return new LocalSecurityAuthorityDTO(kvp.Key, result); 41 | } 42 | else 43 | { 44 | yield return new LocalSecurityAuthorityDTO(kvp.Key, kvp.Value.ToString()); 45 | } 46 | } 47 | } 48 | } 49 | 50 | internal class LocalSecurityAuthorityDTO : CommandDTOBase 51 | { 52 | public LocalSecurityAuthorityDTO(string key, string value) 53 | { 54 | Key = key; 55 | Value = value; 56 | } 57 | public string Key { get; } 58 | public string Value { get; } 59 | } 60 | 61 | [CommandOutputType(typeof(LocalSecurityAuthorityDTO))] 62 | internal class LocalSecurityAuthorityFormatter : TextFormatterBase 63 | { 64 | public LocalSecurityAuthorityFormatter(ITextWriter writer) : base(writer) 65 | { 66 | } 67 | 68 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 69 | { 70 | var dto = (LocalSecurityAuthorityDTO)result; 71 | 72 | WriteLine(" {0,-30} : {1}", dto.Key, dto.Value); 73 | 74 | if (Regex.IsMatch(dto.Key, "Security Packages") && Regex.IsMatch(dto.Value, @".*wdigest.*")) 75 | { 76 | WriteLine(" [*] WDigest is enabled - plaintext password extraction is possible!"); 77 | } 78 | 79 | if (dto.Key.Equals("RunAsPPL", System.StringComparison.InvariantCultureIgnoreCase) && dto.Value == "1") 80 | { 81 | WriteLine(" [*] LSASS Protected Mode is enabled! You will not be able to access lsass.exe's memory easily."); 82 | } 83 | 84 | if (dto.Key.Equals("DisableRestrictedAdmin", System.StringComparison.InvariantCultureIgnoreCase) && dto.Value == "0") 85 | { 86 | WriteLine(" [*] RDP Restricted Admin Mode is enabled! You can use pass-the-hash to access RDP on this system."); 87 | } 88 | 89 | if (dto.Key.Equals("TokenLeakDetectDelaySecs", System.StringComparison.InvariantCultureIgnoreCase)) 90 | { 91 | WriteLine($" [*] TokenLeakDetectDelaySecs is set to '{dto.Value}' - logon sessions will be cleared after this number of seconds!"); 92 | } 93 | } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/LocalUserCommand.cs: -------------------------------------------------------------------------------- 1 | #nullable disable 2 | using System; 3 | using System.Collections.Generic; 4 | using static Seatbelt.Interop.Netapi32; 5 | 6 | 7 | namespace Seatbelt.Commands.Windows 8 | { 9 | internal class LocalUserCommand : CommandBase 10 | { 11 | public override string Command => "LocalUsers"; 12 | public override string Description => "Local users, whether they're active/disabled, and pwd last set (argument == computername to enumerate)"; 13 | public override CommandGroup[] Group => new[] {CommandGroup.System, CommandGroup.Remote}; 14 | public override bool SupportRemote => true; 15 | public Runtime ThisRunTime; 16 | 17 | public LocalUserCommand(Runtime runtime) : base(runtime) 18 | { 19 | ThisRunTime = runtime; 20 | } 21 | 22 | public override IEnumerable Execute(string[] args) 23 | { 24 | // takes an optional remote computername as an argument, otherwise defaults to the localhost 25 | 26 | string computerName = null; 27 | 28 | if (!String.IsNullOrEmpty(ThisRunTime.ComputerName)) 29 | { 30 | computerName = ThisRunTime.ComputerName; 31 | } 32 | else if (args.Length == 1) 33 | { 34 | computerName = args[0]; 35 | } 36 | 37 | // adapted from https://stackoverflow.com/questions/33935825/pinvoke-netlocalgroupgetmembers-runs-into-fatalexecutionengineerror/33939889#33939889 38 | foreach(var localUser in GetLocalUsers(computerName)) 39 | { 40 | var enabled = ((localUser.flags >> 1) & 1) == 0; 41 | var pwdLastSet = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); 42 | var lastLogon = new DateTime(1970, 1, 1, 0, 0, 0); 43 | 44 | if (localUser.passwordAge != 0) 45 | { 46 | pwdLastSet = DateTime.Now.AddSeconds(-localUser.passwordAge); 47 | } 48 | 49 | if(localUser.last_logon != 0) 50 | { 51 | lastLogon = lastLogon.AddSeconds(localUser.last_logon).ToLocalTime(); 52 | } 53 | 54 | yield return new LocalUserDTO( 55 | computerName ?? "localhost", 56 | localUser.name, 57 | enabled, 58 | localUser.user_id, 59 | (Priv)localUser.priv, 60 | localUser.comment, 61 | pwdLastSet, 62 | lastLogon, 63 | localUser.num_logons 64 | ); 65 | } 66 | } 67 | } 68 | 69 | internal class LocalUserDTO : CommandDTOBase 70 | { 71 | public LocalUserDTO(string computerName, string userName, bool enabled, uint rid, Priv userType, string comment, DateTime pwdLastSet, DateTime lastLogon, uint numLogins) 72 | { 73 | ComputerName = computerName; 74 | UserName = userName; 75 | Enabled = enabled; 76 | Rid = rid; 77 | UserType = userType; 78 | Comment = comment; 79 | PwdLastSet = pwdLastSet; 80 | LastLogon = lastLogon; 81 | NumLogins = numLogins; 82 | } 83 | public string ComputerName { get; } 84 | public string UserName { get; } 85 | public bool Enabled { get; } 86 | public uint Rid { get; } 87 | public Priv UserType { get; } 88 | public string Comment { get; } 89 | public DateTime PwdLastSet { get; } 90 | public DateTime LastLogon { get; } 91 | public uint NumLogins { get; } 92 | } 93 | } 94 | #nullable enable -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/MappedDrivesCommand.cs: -------------------------------------------------------------------------------- 1 | #nullable disable 2 | using System.Collections.Generic; 3 | using System.Management; 4 | 5 | 6 | namespace Seatbelt.Commands.Windows 7 | { 8 | internal class MappedDrivesCommand : CommandBase 9 | { 10 | public override string Command => "MappedDrives"; 11 | public override string Description => "Users' mapped drives (via WMI)"; 12 | public override CommandGroup[] Group => new[] { CommandGroup.User, CommandGroup.Remote }; 13 | public override bool SupportRemote => true; 14 | public Runtime ThisRunTime; 15 | 16 | public MappedDrivesCommand(Runtime runtime) : base(runtime) 17 | { 18 | ThisRunTime = runtime; 19 | } 20 | 21 | public override IEnumerable Execute(string[] args) 22 | { 23 | var wmiData = ThisRunTime.GetManagementObjectSearcher(@"root\cimv2", "SELECT * FROM win32_networkconnection"); 24 | var data = wmiData.Get(); 25 | 26 | WriteHost("Mapped Drives (via WMI)\n"); 27 | 28 | foreach (ManagementObject result in data) 29 | { 30 | yield return new MappedDrivesDTO() 31 | { 32 | LocalName = result["LocalName"].ToString(), 33 | RemoteName = result["RemoteName"].ToString(), 34 | RemotePath = result["RemotePath"].ToString(), 35 | Status = result["Status"].ToString(), 36 | ConnectionState = result["ConnectionState"].ToString(), 37 | Persistent = result["Persistent"].ToString(), 38 | UserName = result["UserName"].ToString(), 39 | Description = result["Description"].ToString() 40 | }; 41 | } 42 | } 43 | } 44 | 45 | internal class MappedDrivesDTO : CommandDTOBase 46 | { 47 | public string LocalName { get; set; } 48 | public string RemoteName { get; set; } 49 | public string RemotePath { get; set; } 50 | public string Status { get; set; } 51 | public string ConnectionState { get; set; } 52 | public string Persistent { get; set; } 53 | public string UserName { get; set; } 54 | public string Description { get; set; } 55 | } 56 | } 57 | #nullable enable -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/NetworkSharesCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Management; 3 | 4 | 5 | namespace Seatbelt.Commands.Windows 6 | { 7 | internal class NetworkSharesCommand : CommandBase 8 | { 9 | public override string Command => "NetworkShares"; 10 | public override string Description => "Network shares exposed by the machine (via WMI)"; 11 | public override CommandGroup[] Group => new[] { CommandGroup.System, CommandGroup.Remote }; 12 | public override bool SupportRemote => true; 13 | public Runtime ThisRunTime; 14 | 15 | public NetworkSharesCommand(Runtime runtime) : base(runtime) 16 | { 17 | ThisRunTime = runtime; 18 | } 19 | 20 | public override IEnumerable Execute(string[] args) 21 | { 22 | // lists current network shares for this system via WMI 23 | var wmiData = ThisRunTime.GetManagementObjectSearcher(@"root\cimv2", "SELECT * FROM Win32_Share"); 24 | using var data = wmiData.Get(); 25 | 26 | foreach (ManagementObject result in data) 27 | { 28 | yield return new NetworkShareDTO( 29 | result["Name"], 30 | result["Path"], 31 | result["Description"], 32 | (uint)result["type"] 33 | ); 34 | } 35 | } 36 | } 37 | 38 | internal class NetworkShareDTO : CommandDTOBase 39 | { 40 | public NetworkShareDTO(object name, object path, object description, uint type) 41 | { 42 | var typeDict = new Dictionary() 43 | { 44 | { 0, "Disk Drive" }, 45 | { 1, "Print Queue" }, 46 | { 2, "Device " }, 47 | { 3, "IPC" }, 48 | { 2147483648, "Disk Drive Admin" }, 49 | { 2147483649, "Print Queue Admin" }, 50 | { 2147483650, "Device Admin" }, 51 | { 2147483651, "IPC Admin" }, 52 | }; 53 | Name = name; 54 | Path = path; 55 | Description = description; 56 | Type = typeDict[type]; 57 | } 58 | public object Name { get; } 59 | public object Path { get; } 60 | public object Description { get; } 61 | public object Type { get; } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/OptionalFeaturesCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Seatbelt.Interop; 5 | using Seatbelt.Output.Formatters; 6 | using Seatbelt.Output.TextWriters; 7 | 8 | namespace Seatbelt.Commands.Windows 9 | { 10 | internal class OptionalFeaturesCommand : CommandBase 11 | { 12 | public override string Command => "OptionalFeatures"; 13 | public override string Description => "List Optional Features/Roles (via WMI)"; 14 | public override CommandGroup[] Group => new[] { CommandGroup.System, CommandGroup.Remote }; 15 | public override bool SupportRemote => true; 16 | public Runtime ThisRunTime; 17 | 18 | public OptionalFeaturesCommand(Runtime runtime) : base(runtime) 19 | { 20 | ThisRunTime = runtime; 21 | } 22 | 23 | public override IEnumerable Execute(string[] args) 24 | { 25 | var results = new List(); 26 | var wmiData = ThisRunTime.GetManagementObjectSearcher(@"root\cimv2", "SELECT Name,Caption,InstallState FROM Win32_OptionalFeature"); 27 | var featureList = wmiData.Get(); 28 | 29 | WriteHost("{0,-8} {1,-50} {2}", "State", "Name", "Caption"); 30 | 31 | foreach (var feature in featureList) 32 | { 33 | var state = (OptionalFeatureState)Enum.Parse(typeof(OptionalFeatureState), feature["InstallState"].ToString()); 34 | 35 | if(Runtime.FilterResults && state != OptionalFeatureState.Enabled) 36 | continue; 37 | 38 | results.Add(new OptionalFeaturesCommandDTO( 39 | feature["Name"].ToString(), 40 | feature["Caption"].ToString(), 41 | state)); 42 | } 43 | 44 | foreach (var result in results.OrderBy(r => r.Name)) 45 | { 46 | yield return result; 47 | } 48 | } 49 | } 50 | 51 | internal class OptionalFeaturesCommandDTO : CommandDTOBase 52 | { 53 | public OptionalFeaturesCommandDTO(string name, string caption, OptionalFeatureState state) 54 | { 55 | Name = name; 56 | Caption = caption; 57 | State = state; 58 | } 59 | public string Name { get; } 60 | public string Caption { get; } 61 | public OptionalFeatureState State { get; } 62 | } 63 | 64 | internal enum OptionalFeatureState 65 | { 66 | Enabled = 1, 67 | Disabled = 2, 68 | Absent = 3, 69 | Unknown = 4 70 | } 71 | 72 | [CommandOutputType(typeof(OptionalFeaturesCommandDTO))] 73 | internal class OptionalFeatureTextFormatter : TextFormatterBase 74 | { 75 | public OptionalFeatureTextFormatter(ITextWriter writer) : base(writer) 76 | { 77 | } 78 | 79 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 80 | { 81 | var dto = (OptionalFeaturesCommandDTO)result; 82 | WriteLine("{0,-8} {1,-50} {2}", dto.State, dto.Name, dto.Caption); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/PSSessionSettingsCommand.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32; 2 | using Seatbelt.Output.Formatters; 3 | using Seatbelt.Output.TextWriters; 4 | using Seatbelt.Util; 5 | using System.Xml; 6 | using System.Collections.Generic; 7 | using System.Security.AccessControl; 8 | 9 | namespace Seatbelt.Commands.Windows 10 | { 11 | class PluginAccess 12 | { 13 | public PluginAccess(string principal, string sid, string permission) 14 | { 15 | Principal = principal; 16 | Sid = sid; 17 | Permission = permission; 18 | } 19 | public string Principal { get; } 20 | public string Sid { get; } 21 | public string Permission { get; } 22 | } 23 | 24 | internal class PSSessionSettingsCommand : CommandBase 25 | { 26 | public override string Command => "PSSessionSettings"; 27 | public override string Description => "Enumerates PS Session Settings from the registry"; 28 | public override CommandGroup[] Group => new[] {CommandGroup.System, CommandGroup.Remote}; 29 | public override bool SupportRemote => true; 30 | public Runtime ThisRunTime; 31 | 32 | public PSSessionSettingsCommand(Runtime runtime) : base(runtime) 33 | { 34 | ThisRunTime = runtime; 35 | } 36 | 37 | public override IEnumerable Execute(string[] args) 38 | { 39 | if (!SecurityUtil.IsHighIntegrity() && !ThisRunTime.ISRemote()) 40 | { 41 | WriteError("Unable to collect. Must be an administrator."); 42 | yield break; 43 | } 44 | 45 | var plugins = new[] { "Microsoft.PowerShell", "Microsoft.PowerShell.Workflow", "Microsoft.PowerShell32" }; 46 | foreach (var plugin in plugins) 47 | { 48 | var config = ThisRunTime.GetStringValue(RegistryHive.LocalMachine, 49 | $"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WSMAN\\Plugin\\{plugin}", "ConfigXML"); 50 | 51 | if(config == null) continue;; 52 | 53 | var access = new List(); 54 | 55 | var xmlDoc = new XmlDocument(); 56 | xmlDoc.LoadXml(config); 57 | var security = xmlDoc.GetElementsByTagName("Security"); 58 | 59 | if (security.Count <= 0) 60 | continue; 61 | 62 | foreach (XmlAttribute attr in security[0].Attributes) 63 | { 64 | if (attr.Name != "Sddl") 65 | continue; 66 | 67 | var desc = new RawSecurityDescriptor(attr.Value); 68 | foreach (QualifiedAce ace in desc.DiscretionaryAcl) 69 | { 70 | var principal = ace.SecurityIdentifier.Translate(typeof(System.Security.Principal.NTAccount)).ToString(); 71 | var accessStr = ace.AceQualifier.ToString(); 72 | 73 | access.Add(new PluginAccess( 74 | principal, 75 | ace.SecurityIdentifier.ToString(), 76 | accessStr 77 | )); 78 | } 79 | } 80 | 81 | yield return new PSSessionSettingsDTO( 82 | plugin, 83 | access 84 | ); 85 | } 86 | } 87 | } 88 | 89 | internal class PSSessionSettingsDTO : CommandDTOBase 90 | { 91 | public PSSessionSettingsDTO(string plugin, List permission) 92 | { 93 | Plugin = plugin; 94 | Permission = permission; 95 | } 96 | public string Plugin { get; } 97 | public List Permission { get; } 98 | } 99 | 100 | [CommandOutputType(typeof(PSSessionSettingsDTO))] 101 | internal class PSSessionSettingsFormatter : TextFormatterBase 102 | { 103 | public PSSessionSettingsFormatter(ITextWriter writer) : base(writer) 104 | { 105 | } 106 | 107 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 108 | { 109 | var dto = (PSSessionSettingsDTO)result; 110 | 111 | WriteLine(" Name : {0}", dto.Plugin); 112 | 113 | foreach (var access in dto.Permission) 114 | { 115 | WriteLine(" {0,-35} {1,-22}", access.Principal, access.Permission); 116 | } 117 | 118 | WriteLine(); 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/PrintersCommand.cs: -------------------------------------------------------------------------------- 1 | #nullable disable 2 | using System.Collections.Generic; 3 | using System.Management; 4 | using Seatbelt.Util; 5 | 6 | 7 | namespace Seatbelt.Commands.Windows 8 | { 9 | internal class PrintersCommand : CommandBase 10 | { 11 | public override string Command => "Printers"; 12 | public override string Description => "Installed Printers (via WMI)"; 13 | public override CommandGroup[] Group => new[] { CommandGroup.Misc }; 14 | public override bool SupportRemote => false; // could if it wasn't for the SDDL 15 | 16 | public PrintersCommand(Runtime runtime) : base(runtime) 17 | { 18 | } 19 | 20 | public override IEnumerable Execute(string[] args) 21 | { 22 | // lists installed printers via WMI (the Win32_Printer class) 23 | var printerQuery = new ManagementObjectSearcher("SELECT * from Win32_Printer"); 24 | foreach (var printer in printerQuery.Get()) 25 | { 26 | var isDefault = (bool)printer.GetPropertyValue("Default"); 27 | var isNetworkPrinter = (bool)printer.GetPropertyValue("Network"); 28 | string printerSDDL = null; 29 | var printerName = $"{printer.GetPropertyValue("Name")}"; 30 | 31 | try 32 | { 33 | var info = SecurityUtil.GetSecurityInfos(printerName, Interop.Advapi32.SE_OBJECT_TYPE.SE_PRINTER); 34 | printerSDDL = info.SDDL; 35 | } 36 | catch 37 | { 38 | // eat it 39 | } 40 | 41 | yield return new InstalledPrintersDTO( 42 | printerName, 43 | $"{printer.GetPropertyValue("Status")}", 44 | printerSDDL, 45 | isDefault, 46 | isNetworkPrinter 47 | ); 48 | } 49 | } 50 | } 51 | 52 | internal class InstalledPrintersDTO : CommandDTOBase 53 | { 54 | public InstalledPrintersDTO(string name, string status, string sddl, bool isDefault, bool isNetworkPrinter) 55 | { 56 | Name = name; 57 | Status = status; 58 | Sddl = sddl; 59 | IsDefault = isDefault; 60 | IsNetworkPrinter = isNetworkPrinter; 61 | } 62 | public string Name { get; } 63 | public string Status { get; } 64 | public string Sddl { get; } 65 | public bool IsDefault { get; } 66 | public bool IsNetworkPrinter { get; } 67 | } 68 | } 69 | #nullable enable -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/ProcessOwnersCommand.cs: -------------------------------------------------------------------------------- 1 | #nullable disable 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Management; 5 | using Seatbelt.Output.TextWriters; 6 | using Seatbelt.Output.Formatters; 7 | 8 | 9 | namespace Seatbelt.Commands.Windows 10 | { 11 | internal class ProcessesOwnerCommand : CommandBase 12 | { 13 | public override string Command => "ProcessOwners"; 14 | public override string Description => "Running non-session 0 process list with owners. For remote use."; 15 | public override CommandGroup[] Group => new[] { CommandGroup.Misc, CommandGroup.Remote }; 16 | public override bool SupportRemote => true; 17 | public Runtime ThisRunTime; 18 | 19 | public ProcessesOwnerCommand(Runtime runtime) : base(runtime) 20 | { 21 | ThisRunTime = runtime; 22 | } 23 | 24 | public override IEnumerable Execute(string[] args) 25 | { 26 | var wmiData = ThisRunTime.GetManagementObjectSearcher(@"Root\CIMV2", "SELECT * FROM Win32_Process WHERE SessionID != 0"); 27 | var retObjectCollection = wmiData.Get(); 28 | 29 | foreach (ManagementObject Process in retObjectCollection) 30 | { 31 | var OwnerInfo = new string[2]; 32 | 33 | try 34 | { 35 | Process.InvokeMethod("GetOwner", (object[])OwnerInfo); 36 | } 37 | catch { } 38 | var owner = ""; 39 | 40 | if (OwnerInfo[0] != null) 41 | { 42 | owner = String.Format("{0}\\{1}", OwnerInfo[1], OwnerInfo[0]); 43 | 44 | yield return new ProcessesOwnerDTO() 45 | { 46 | ProcessName = Process["Name"], 47 | ProcessID = Process["ProcessId"], 48 | Owner = owner 49 | }; 50 | } 51 | } 52 | } 53 | 54 | } 55 | 56 | internal class ProcessesOwnerDTO : CommandDTOBase 57 | { 58 | public object ProcessName { get; set; } 59 | 60 | public object ProcessID { get; set; } 61 | 62 | public object Owner { get; set; } 63 | 64 | } 65 | 66 | [CommandOutputType(typeof(ProcessesOwnerDTO))] 67 | internal class ProcessOwnerFormatter : TextFormatterBase 68 | { 69 | public ProcessOwnerFormatter(ITextWriter writer) : base(writer) 70 | { 71 | } 72 | 73 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 74 | { 75 | var dto = (ProcessesOwnerDTO)result; 76 | WriteLine(" {0,-50} {1,-10} {2}", dto.ProcessName, dto.ProcessID, dto.Owner); 77 | } 78 | } 79 | } 80 | #nullable enable -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/RDPSavedConnectionCommand.cs: -------------------------------------------------------------------------------- 1 | #nullable disable 2 | using Microsoft.Win32; 3 | using System.Collections.Generic; 4 | using Seatbelt.Output.TextWriters; 5 | using Seatbelt.Output.Formatters; 6 | 7 | 8 | namespace Seatbelt.Commands.Windows 9 | { 10 | class RDPConnection 11 | { 12 | public string RemoteHost { get; set; } 13 | public string UserNameHint { get; set; } 14 | } 15 | 16 | internal class RDPSavedConnectionCommand : CommandBase 17 | { 18 | public override string Command => "RDPSavedConnections"; 19 | public override string Description => "Saved RDP connections stored in the registry"; 20 | public override CommandGroup[] Group => new[] { CommandGroup.User, CommandGroup.Remote }; 21 | public override bool SupportRemote => true; 22 | public Runtime ThisRunTime; 23 | 24 | public RDPSavedConnectionCommand(Runtime runtime) : base(runtime) 25 | { 26 | ThisRunTime = runtime; 27 | } 28 | 29 | public override IEnumerable Execute(string[] args) 30 | { 31 | var SIDs = ThisRunTime.GetUserSIDs(); 32 | //shows saved RDP connections, including username hints (if present) 33 | foreach (var sid in SIDs) 34 | { 35 | if (!sid.StartsWith("S-1-5") || sid.EndsWith("_Classes")) 36 | { 37 | continue; 38 | } 39 | 40 | var subkeys = ThisRunTime.GetSubkeyNames(RegistryHive.Users, $"{sid}\\Software\\Microsoft\\Terminal Server Client\\Servers"); 41 | if (subkeys == null) 42 | { 43 | continue; 44 | } 45 | 46 | if (subkeys.Length <= 0) 47 | { 48 | continue; 49 | } 50 | 51 | var connections = new List(); 52 | 53 | foreach (var host in subkeys) 54 | { 55 | var usernameHint = ThisRunTime.GetStringValue(RegistryHive.Users, 56 | $"{sid}\\Software\\Microsoft\\Terminal Server Client\\Servers\\{host}", "UsernameHint"); 57 | 58 | var connection = new RDPConnection(); 59 | connection.RemoteHost = host; 60 | connection.UserNameHint = usernameHint; 61 | connections.Add(connection); 62 | } 63 | 64 | yield return new RDPSavedConnectionDTO() 65 | { 66 | SID = sid, 67 | Connections = connections 68 | }; 69 | } 70 | 71 | yield break; 72 | } 73 | 74 | internal class RDPSavedConnectionDTO : CommandDTOBase 75 | { 76 | public string SID { get; set; } 77 | public List Connections { get; set; } 78 | } 79 | 80 | [CommandOutputType(typeof(RDPSavedConnectionDTO))] 81 | internal class RDPSavedConnectionCommandFormatter : TextFormatterBase 82 | { 83 | public RDPSavedConnectionCommandFormatter(ITextWriter writer) : base(writer) 84 | { 85 | } 86 | 87 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 88 | { 89 | var dto = (RDPSavedConnectionDTO)result; 90 | 91 | if (dto.Connections.Count > 0) 92 | { 93 | WriteLine("Saved RDP Connection Information ({0})\n", dto.SID); 94 | 95 | WriteLine(" RemoteHost UsernameHint"); 96 | WriteLine(" ---------- ------------"); 97 | 98 | foreach (var connection in dto.Connections) 99 | { 100 | WriteLine($" {connection.RemoteHost.PadRight(35)}{connection.UserNameHint}"); 101 | } 102 | WriteLine(); 103 | } 104 | } 105 | } 106 | } 107 | } 108 | #nullable enable -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/RecycleBinCommand.cs: -------------------------------------------------------------------------------- 1 | #nullable disable 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Reflection; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace Seatbelt.Commands.Windows 8 | { 9 | internal class RecycleBinCommand : CommandBase 10 | { 11 | public override string Command => "RecycleBin"; 12 | public override string Description => "Items in the Recycle Bin deleted in the last 30 days - only works from a user context!"; 13 | public override CommandGroup[] Group => new[] { CommandGroup.Misc }; 14 | public override bool SupportRemote => false; // not possible 15 | 16 | public RecycleBinCommand(Runtime runtime) : base(runtime) 17 | { 18 | } 19 | 20 | public override IEnumerable Execute(string[] args) 21 | { 22 | // lists recently deleted files (needs to be run from a user context!) 23 | 24 | // Reference: https://stackoverflow.com/questions/18071412/list-filenames-in-the-recyclebin-with-c-sharp-without-using-any-external-files 25 | WriteHost("Recycle Bin Files Within the last 30 Days\n"); 26 | 27 | var lastDays = 30; 28 | 29 | var startTime = DateTime.Now.AddDays(-lastDays); 30 | 31 | // Shell COM object GUID 32 | var shell = Type.GetTypeFromProgID("Shell.Application"); 33 | var shellObj = Activator.CreateInstance(shell); 34 | 35 | // namespace for recycle bin == 10 - https://msdn.microsoft.com/en-us/library/windows/desktop/bb762494(v=vs.85).aspx 36 | var recycle = shellObj.GetType().InvokeMember("Namespace", BindingFlags.InvokeMethod, null, shellObj, new object[] { 10 }); 37 | // grab all the deletes items 38 | var items = recycle.GetType().InvokeMember("Items", BindingFlags.InvokeMethod, null, recycle, null); 39 | // grab the number of deleted items 40 | var count = items.GetType().InvokeMember("Count", BindingFlags.GetProperty, null, items, null); 41 | var deletedCount = int.Parse(count.ToString()); 42 | 43 | // iterate through each item 44 | for (var i = 0; i < deletedCount; i++) 45 | { 46 | // grab the specific deleted item 47 | var item = items.GetType().InvokeMember("Item", BindingFlags.InvokeMethod, null, items, new object[] { i }); 48 | var DateDeleted = item.GetType().InvokeMember("ExtendedProperty", BindingFlags.InvokeMethod, null, item, new object[] { "System.Recycle.DateDeleted" }); 49 | var modifiedDate = DateTime.Parse(DateDeleted.ToString()); 50 | if (modifiedDate > startTime) 51 | { 52 | // additional extended properties from https://blogs.msdn.microsoft.com/oldnewthing/20140421-00/?p=1183 53 | var Name = item.GetType().InvokeMember("Name", BindingFlags.GetProperty, null, item, null); 54 | var Path = item.GetType().InvokeMember("Path", BindingFlags.GetProperty, null, item, null); 55 | var Size = item.GetType().InvokeMember("Size", BindingFlags.GetProperty, null, item, null); 56 | var DeletedFrom = item.GetType().InvokeMember("ExtendedProperty", BindingFlags.InvokeMethod, null, item, new object[] { "System.Recycle.DeletedFrom" }); 57 | 58 | yield return new RecycleBinDTO() 59 | { 60 | Name = Name.ToString(), 61 | Path = Path.ToString(), 62 | Size = (int)Size, 63 | DeletedFrom = DeletedFrom.ToString(), 64 | DateDeleted = (DateTime)DateDeleted 65 | }; 66 | } 67 | 68 | Marshal.ReleaseComObject(item); 69 | item = null; 70 | } 71 | 72 | Marshal.ReleaseComObject(recycle); 73 | recycle = null; 74 | Marshal.ReleaseComObject(shellObj); 75 | shellObj = null; 76 | } 77 | 78 | internal class RecycleBinDTO : CommandDTOBase 79 | { 80 | public string Name { get; set; } 81 | 82 | public string Path { get; set; } 83 | 84 | public int Size { get; set; } 85 | 86 | public string DeletedFrom { get; set; } 87 | 88 | public DateTime DateDeleted { get; set; } 89 | } 90 | } 91 | } 92 | #nullable enable -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/SecureBootCommand.cs: -------------------------------------------------------------------------------- 1 | #if DEBUG 2 | using Microsoft.Win32; 3 | using System.Collections.Generic; 4 | 5 | 6 | namespace Seatbelt.Commands.Windows 7 | { 8 | internal class SecureBootCommand : CommandBase 9 | { 10 | public override string Command => "SecureBoot"; 11 | public override string Description => "Secure Boot configuration"; 12 | public override CommandGroup[] Group => new[] {CommandGroup.System, CommandGroup.Remote}; 13 | public override bool SupportRemote => true; 14 | public Runtime ThisRunTime; 15 | 16 | public SecureBootCommand(Runtime runtime) : base(runtime) 17 | { 18 | ThisRunTime = runtime; 19 | } 20 | 21 | public override IEnumerable Execute(string[] args) 22 | { 23 | var uefiSecureBootState = ThisRunTime.GetDwordValue(RegistryHive.LocalMachine, @"SYSTEM\CurrentControlSet\Control\SecureBoot\State", @"UEFISecureBootEnabled"); 24 | if (uefiSecureBootState == null) 25 | yield break; // Exit the function and don't return anything 26 | 27 | var policyPublisher = ThisRunTime.GetStringValue(RegistryHive.LocalMachine, @"SYSTEM\CurrentControlSet\Control\SecureBoot\State", @"PolicyPublisher"); 28 | var policyVersion = ThisRunTime.GetStringValue(RegistryHive.LocalMachine, @"SYSTEM\CurrentControlSet\Control\SecureBoot\State", @"PolicyVersion"); 29 | 30 | yield return new SecureBootDTO( 31 | uefiSecureBootState == 1 ? true : false, 32 | policyPublisher, 33 | policyVersion 34 | ); 35 | } 36 | 37 | internal class SecureBootDTO : CommandDTOBase 38 | { 39 | public SecureBootDTO(bool enabled, string? publisher, string? version) 40 | { 41 | Enabled = enabled; 42 | Publisher = publisher; 43 | Version = version; 44 | } 45 | public bool Enabled { get; } 46 | public string? Publisher { get; } 47 | public string? Version { get; } 48 | } 49 | } 50 | } 51 | #endif -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/SecurityPackagesCommand.cs: -------------------------------------------------------------------------------- 1 | #nullable disable 2 | using System; 3 | using System.Collections.Generic; 4 | using static Seatbelt.Interop.Secur32; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace Seatbelt.Commands.Windows 8 | { 9 | internal class SecurityPackagesCommand : CommandBase 10 | { 11 | public override string Command => "SecurityPackages"; 12 | public override string Description => "Enumerates the security packages currently available using EnumerateSecurityPackagesA()"; 13 | public override CommandGroup[] Group => new[] {CommandGroup.Misc}; 14 | public override bool SupportRemote => false; // not possible 15 | 16 | public SecurityPackagesCommand(Runtime runtime) : base(runtime) 17 | { 18 | } 19 | 20 | public override IEnumerable Execute(string[] args) 21 | { 22 | // this code was partially adapted from Chris Haas' post at https://stackoverflow.com/a/5941873 23 | 24 | WriteHost("Security Packages\n\n"); 25 | 26 | var securityPackages = new List(); 27 | 28 | var ret = EnumerateSecurityPackages(out var pcPackages, out var ppPackageInfo); 29 | 30 | var ppPackageInfoItr = ppPackageInfo; 31 | 32 | for (ulong i = 0; i < pcPackages; i++) 33 | { 34 | var packageInfo = (SecPkgInfo)Marshal.PtrToStructure(ppPackageInfoItr, typeof(SecPkgInfo)); 35 | 36 | var securityPackage = new SecurityPackagesDTO() 37 | { 38 | Name = packageInfo.Name.ToString(), 39 | Comment = packageInfo.Comment.ToString(), 40 | Capabilities = packageInfo.fCapabilities, 41 | MaxToken = packageInfo.cbMaxToken, 42 | RPCID = packageInfo.wRPCID, 43 | Version = packageInfo.wVersion 44 | }; 45 | 46 | securityPackages.Add(securityPackage); 47 | 48 | ppPackageInfoItr = (IntPtr)((long)ppPackageInfoItr.ToInt64() + Marshal.SizeOf(typeof(SecPkgInfo))); 49 | } 50 | 51 | foreach (var securityPackage in securityPackages) 52 | { 53 | yield return securityPackage; 54 | } 55 | 56 | FreeContextBuffer(ppPackageInfo); 57 | } 58 | 59 | internal class SecurityPackagesDTO : CommandDTOBase 60 | { 61 | public string Name { get; set; } 62 | public string Comment { get; set; } 63 | public SECPKG_FLAGS Capabilities { get; set; } 64 | public uint MaxToken { get; set; } 65 | public short RPCID { get; set; } 66 | public short Version { get; set; } 67 | } 68 | } 69 | } 70 | #nullable enable -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/TokenGroupCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Security.Principal; 3 | using Seatbelt.Output.Formatters; 4 | using Seatbelt.Output.TextWriters; 5 | 6 | 7 | namespace Seatbelt.Commands.Windows 8 | { 9 | internal class TokenGroupCommand : CommandBase 10 | { 11 | public override string Command => "TokenGroups"; 12 | public override string Description => "The current token's local and domain groups"; 13 | public override CommandGroup[] Group => new[] { CommandGroup.User }; 14 | public override bool SupportRemote => false; 15 | 16 | public TokenGroupCommand(Runtime runtime) : base(runtime) 17 | { 18 | } 19 | 20 | public override IEnumerable Execute(string[] args) 21 | { 22 | WriteHost("Current Token's Groups\n"); 23 | 24 | var wi = WindowsIdentity.GetCurrent(); 25 | 26 | foreach (var group in wi.Groups) 27 | { 28 | var groupName = ""; 29 | 30 | try 31 | { 32 | groupName = group.Translate(typeof(NTAccount)).ToString(); 33 | } 34 | catch { } 35 | 36 | yield return new TokenGroupsDTO( 37 | $"{(SecurityIdentifier)group}", 38 | groupName 39 | ); 40 | } 41 | } 42 | } 43 | 44 | internal class TokenGroupsDTO : CommandDTOBase 45 | { 46 | public TokenGroupsDTO(string groupSid, string groupName) 47 | { 48 | GroupSID = groupSid; 49 | GroupName = groupName; 50 | } 51 | 52 | //public System.Security.Principal.SecurityIdentifier GroupSID { get; set; } 53 | public string GroupSID { get; set; } 54 | public string GroupName { get; set; } 55 | } 56 | 57 | [CommandOutputType(typeof(TokenGroupsDTO))] 58 | internal class TokenGroupsTextFormatter : TextFormatterBase 59 | { 60 | public TokenGroupsTextFormatter(ITextWriter writer) : base(writer) 61 | { 62 | } 63 | 64 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 65 | { 66 | var dto = (TokenGroupsDTO)result; 67 | 68 | WriteLine(" {0,-40} {1}", dto.GroupName, dto.GroupSID); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/TokenPrivilegesCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime.InteropServices; 4 | using System.Security.Principal; 5 | using static Seatbelt.Interop.Advapi32; 6 | using static Seatbelt.Interop.Secur32; 7 | using Seatbelt.Output.Formatters; 8 | using Seatbelt.Output.TextWriters; 9 | 10 | 11 | namespace Seatbelt.Commands.Windows 12 | { 13 | // TODO: Most privileges are disabled by default. Better to move this to SharpUp? 14 | internal class TokenPrivilegesCommand : CommandBase 15 | { 16 | public override string Command => "TokenPrivileges"; 17 | public override string Description => "Currently enabled token privileges (e.g. SeDebugPrivilege/etc.)"; 18 | public override CommandGroup[] Group => new[] {CommandGroup.System}; 19 | public override bool SupportRemote => false; 20 | 21 | public TokenPrivilegesCommand(Runtime runtime) : base(runtime) 22 | { 23 | } 24 | 25 | public override IEnumerable Execute(string[] args) 26 | { 27 | // Returns all privileges that the current process/user possesses 28 | // adapted from https://stackoverflow.com/questions/4349743/setting-size-of-token-privileges-luid-and-attributes-array-returned-by-gettokeni 29 | 30 | WriteHost("Current Token's Privileges\n"); 31 | 32 | var TokenInfLength = 0; 33 | var ThisHandle = WindowsIdentity.GetCurrent().Token; 34 | GetTokenInformation(ThisHandle, TOKEN_INFORMATION_CLASS.TokenPrivileges, IntPtr.Zero, TokenInfLength, out TokenInfLength); 35 | var TokenInformation = Marshal.AllocHGlobal(TokenInfLength); 36 | if (GetTokenInformation(WindowsIdentity.GetCurrent().Token, TOKEN_INFORMATION_CLASS.TokenPrivileges, TokenInformation, TokenInfLength, out TokenInfLength)) 37 | { 38 | var ThisPrivilegeSet = (TOKEN_PRIVILEGES)Marshal.PtrToStructure(TokenInformation, typeof(TOKEN_PRIVILEGES)); 39 | for (var index = 0; index < ThisPrivilegeSet.PrivilegeCount; index++) 40 | { 41 | var laa = ThisPrivilegeSet.Privileges[index]; 42 | var StrBuilder = new System.Text.StringBuilder(); 43 | var luidNameLen = 0; 44 | var luidPointer = Marshal.AllocHGlobal(Marshal.SizeOf(laa.Luid)); 45 | Marshal.StructureToPtr(laa.Luid, luidPointer, true); 46 | LookupPrivilegeName(null, luidPointer, null, ref luidNameLen); 47 | StrBuilder.EnsureCapacity(luidNameLen + 1); 48 | if (LookupPrivilegeName(null, luidPointer, StrBuilder, ref luidNameLen)) 49 | { 50 | var strPrivilege = StrBuilder.ToString(); 51 | var strAttributes = String.Format("{0}", (LuidAttributes)laa.Attributes); 52 | Marshal.FreeHGlobal(luidPointer); 53 | 54 | yield return new TokenPrivilegesDTO( 55 | strPrivilege, 56 | strAttributes 57 | ); 58 | } 59 | 60 | } 61 | } 62 | } 63 | } 64 | 65 | internal class TokenPrivilegesDTO : CommandDTOBase 66 | { 67 | public TokenPrivilegesDTO(string privilege, string attributes) 68 | { 69 | Privilege = privilege; 70 | Attributes = attributes; 71 | } 72 | 73 | public string Privilege { get; set; } 74 | public string Attributes { get; set; } 75 | } 76 | 77 | [CommandOutputType(typeof(TokenPrivilegesDTO))] 78 | internal class TokenPrivilegesTextFormatter : TextFormatterBase 79 | { 80 | public TokenPrivilegesTextFormatter(ITextWriter writer) : base(writer) 81 | { 82 | } 83 | 84 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 85 | { 86 | var dto = (TokenPrivilegesDTO)result; 87 | 88 | WriteLine(" {0,43}: {1}", dto.Privilege, dto.Attributes); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/WMICommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Management; 5 | using Seatbelt.Output.Formatters; 6 | using Seatbelt.Output.TextWriters; 7 | using System.Collections.Specialized; 8 | using System.Linq; 9 | using System.Text; 10 | 11 | 12 | namespace Seatbelt.Commands.Windows 13 | { 14 | internal class WMICommand : CommandBase 15 | { 16 | public override string Command => "WMI"; 17 | public override string Description => "Runs a specified WMI query"; 18 | public override CommandGroup[] Group => new[] { CommandGroup.System }; 19 | public override bool SupportRemote => true; 20 | public Runtime ThisRunTime; 21 | 22 | public WMICommand(Runtime runtime) : base(runtime) 23 | { 24 | ThisRunTime = runtime; 25 | } 26 | 27 | public override IEnumerable Execute(string[] args) 28 | { 29 | var wmiQuery = "Select * from Win32_ComputerSystem"; 30 | var wmiNamespace = @"root\cimv2"; 31 | 32 | if (args.Length == 1) 33 | { 34 | wmiQuery = args[0]; 35 | } 36 | else if (args.Length == 2) 37 | { 38 | wmiNamespace = args[0]; 39 | wmiQuery = args[1]; 40 | } 41 | 42 | var results = new List(); 43 | 44 | using (var searcher = ThisRunTime.GetManagementObjectSearcher(wmiNamespace, wmiQuery)) 45 | { 46 | using var items = searcher.Get(); 47 | 48 | foreach (ManagementObject result in items) 49 | { 50 | var properties = new OrderedDictionary(); 51 | 52 | foreach (var prop in result.Properties) 53 | { 54 | properties.Add(prop.Name, prop.Value); 55 | } 56 | 57 | results.Add(properties); 58 | } 59 | } 60 | 61 | yield return new WMIDTO( 62 | results 63 | ); 64 | } 65 | } 66 | 67 | internal class WMIDTO : CommandDTOBase 68 | { 69 | public WMIDTO(List results) 70 | { 71 | QueryResults = results; 72 | } 73 | public List QueryResults { get; } 74 | } 75 | 76 | [CommandOutputType(typeof(WMIDTO))] 77 | internal class WMIFormatter : TextFormatterBase 78 | { 79 | public WMIFormatter(ITextWriter writer) : base(writer) 80 | { 81 | } 82 | 83 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 84 | { 85 | var dto = (WMIDTO)result; 86 | foreach (var resultEntry in dto.QueryResults) 87 | { 88 | var enumerator = resultEntry.GetEnumerator(); 89 | 90 | while (enumerator.MoveNext()) 91 | { 92 | var value = enumerator.Value; 93 | if (value == null) 94 | { 95 | continue; 96 | } 97 | 98 | var valueType = value.GetType(); 99 | var valueName = enumerator.Key?.ToString(); 100 | 101 | if (valueType.IsArray) 102 | { 103 | WriteArrayValue(valueType, valueName, value); 104 | } 105 | else 106 | { 107 | WriteLine(" {0,-30}: {1}", valueName, value); 108 | } 109 | } 110 | WriteLine(); 111 | } 112 | } 113 | 114 | private void WriteArrayValue(Type valueType, string? valueName, object value) 115 | { 116 | var elemType = valueType.GetElementType(); 117 | 118 | var name = $"{valueName}({valueType.Name})"; 119 | 120 | if (elemType == typeof(string)) 121 | { 122 | WriteLine($" {name,-30}:"); 123 | foreach (var s in (string[]) value) 124 | { 125 | WriteLine($" {s}"); 126 | } 127 | } 128 | else 129 | { 130 | IEnumerable s = ((IEnumerable) value).Cast() 131 | .Select(x => x.ToString()) 132 | .ToArray(); 133 | 134 | var v = string.Join(",", (string[]) s); 135 | 136 | WriteLine($" {name,-30}: {v}"); 137 | } 138 | } 139 | } 140 | } -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/WMIEventConsumerCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Management; 3 | using System.Security.Principal; 4 | using Seatbelt.Output.Formatters; 5 | using Seatbelt.Output.TextWriters; 6 | 7 | 8 | namespace Seatbelt.Commands.Windows 9 | { 10 | internal class WMIEventConsumerCommand : CommandBase 11 | { 12 | public override string Command => "WMIEventConsumer"; 13 | public override string Description => "Lists WMI Event Consumers"; 14 | public override CommandGroup[] Group => new[] {CommandGroup.System}; 15 | public override bool SupportRemote => false; // TODO: remote 16 | 17 | public WMIEventConsumerCommand(Runtime runtime) : base(runtime) 18 | { 19 | } 20 | 21 | public override IEnumerable Execute(string[] args) 22 | { 23 | // recurse and get members of the '__EventConsumer' SuperClass 24 | var opt = new EnumerationOptions(); 25 | opt.EnumerateDeep = true; 26 | 27 | var EventConsumerClass = new ManagementClass(@"\\.\ROOT\Subscription:__EventConsumer"); 28 | // https://wutils.com/wmi/root/subscription/commandlineeventconsumer/cs-samples.html 29 | 30 | foreach (ManagementObject EventConsumer in EventConsumerClass.GetInstances(opt)) 31 | { 32 | var systemprops = EventConsumer.SystemProperties; 33 | var ConsumerType = $"{systemprops["__CLASS"].Value}"; 34 | 35 | var sidBytes = (byte[])EventConsumer["CreatorSID"]; 36 | var creatorSid = new SecurityIdentifier(sidBytes, 0); 37 | 38 | var properties = new Dictionary(); 39 | 40 | foreach (var prop in EventConsumer.Properties) 41 | { 42 | if(!prop.Name.Equals("CreatorSID")) 43 | { 44 | properties[prop.Name] = prop.Value; 45 | } 46 | } 47 | 48 | yield return new WMIEventConsumerDTO( 49 | $"{EventConsumer["Name"]}", 50 | creatorSid, 51 | ConsumerType, 52 | properties 53 | ); 54 | } 55 | } 56 | } 57 | 58 | internal class WMIEventConsumerDTO : CommandDTOBase 59 | { 60 | public WMIEventConsumerDTO(object name, object consumerType, object creatorSid, object properties) 61 | { 62 | Name = name; 63 | ConsumerType = consumerType; 64 | CreatorSid = creatorSid; 65 | Properties = properties; 66 | } 67 | public object Name { get; } 68 | 69 | public object ConsumerType { get; } 70 | 71 | public object CreatorSid { get; } 72 | 73 | public object Properties { get; } 74 | } 75 | 76 | [CommandOutputType(typeof(WMIEventConsumerDTO))] 77 | internal class WMIEventConsumeFormatter : TextFormatterBase 78 | { 79 | public WMIEventConsumeFormatter(ITextWriter writer) : base(writer) 80 | { 81 | } 82 | 83 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 84 | { 85 | var dto = (WMIEventConsumerDTO)result; 86 | 87 | WriteLine(" {0,-30} : {1}", "Name", dto.Name); 88 | WriteLine(" {0,-30} : {1}", "ConsumerType", dto.ConsumerType); 89 | WriteLine(" {0,-30} : {1}", "CreatorSID", dto.CreatorSid); 90 | foreach(var kvp in (Dictionary)dto.Properties) 91 | { 92 | WriteLine(" {0,-30} : {1}", kvp.Key, kvp.Value); 93 | } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/WMIEventFilterCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Management; 3 | using System.Security.Principal; 4 | 5 | namespace Seatbelt.Commands.Windows 6 | { 7 | internal class WmiEventFilterCommand : CommandBase 8 | { 9 | public override string Command => "WMIEventFilter"; 10 | public override string Description => "Lists WMI Event Filters"; 11 | public override CommandGroup[] Group => new[] {CommandGroup.System}; 12 | public override bool SupportRemote => false; // TODO: remote 13 | 14 | public WmiEventFilterCommand(Runtime runtime) : base(runtime) 15 | { 16 | } 17 | 18 | public override IEnumerable Execute(string[] args) 19 | { 20 | var EventFilterClass = new ManagementClass(@"\\.\ROOT\Subscription:__EventFilter"); 21 | 22 | foreach (ManagementObject EventFilter in EventFilterClass.GetInstances()) 23 | { 24 | var sidBytes = (byte[])EventFilter["CreatorSID"]; 25 | var creatorSid = new SecurityIdentifier(sidBytes, 0); 26 | 27 | yield return new WmiEventFilterDTO( 28 | EventFilter["Name"], 29 | EventFilter["__NAMESPACE"], 30 | EventFilter["EventNamespace"], 31 | EventFilter["Query"], 32 | EventFilter["QueryLanguage"], 33 | EventFilter["EventAccess"], 34 | creatorSid 35 | ); 36 | } 37 | 38 | } 39 | } 40 | 41 | internal class WmiEventFilterDTO : CommandDTOBase 42 | { 43 | public WmiEventFilterDTO(object name, object ns, object eventNamespace, object query, object queryLanguage, object eventAccess, object creatorSid) 44 | { 45 | Name = name; 46 | Namespace = ns; 47 | EventNamespace = eventNamespace; 48 | Query = query; 49 | QueryLanguage = queryLanguage; 50 | EventAccess = eventAccess; 51 | CreatorSid = creatorSid; 52 | } 53 | public object Name { get; } 54 | public object Namespace { get; } 55 | public object EventNamespace { get; } 56 | public object Query { get; } 57 | public object QueryLanguage { get; } 58 | public object EventAccess { get; } 59 | public object CreatorSid { get; } 60 | } 61 | } -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/WMIFilterToConsumerBindingCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Management; 3 | using System.Security.Principal; 4 | 5 | namespace Seatbelt.Commands.Windows 6 | { 7 | internal class WMIFilterToConsumerBindingCommand : CommandBase 8 | { 9 | public override string Command => "WMIFilterBinding"; 10 | public override string Description => "Lists WMI Filter to Consumer Bindings"; 11 | public override CommandGroup[] Group => new[] {CommandGroup.System}; 12 | public override bool SupportRemote => false; // TODO: remote 13 | 14 | public WMIFilterToConsumerBindingCommand(Runtime runtime) : base(runtime) 15 | { 16 | } 17 | 18 | public override IEnumerable Execute(string[] args) 19 | { 20 | var BindingrClass = new ManagementClass(@"\\.\ROOT\Subscription:__FilterToConsumerBinding"); 21 | 22 | foreach (ManagementObject Binding in BindingrClass.GetInstances()) 23 | { 24 | var sidBytes = (byte[])Binding["CreatorSID"]; 25 | var CreatorSID = new SecurityIdentifier(sidBytes, 0); 26 | 27 | yield return new WMIFilterToConsumerBindingDTO( 28 | Binding["Filter"], 29 | Binding["Consumer"], 30 | CreatorSID 31 | ); 32 | } 33 | } 34 | } 35 | 36 | internal class WMIFilterToConsumerBindingDTO : CommandDTOBase 37 | { 38 | public WMIFilterToConsumerBindingDTO(object consumer, object filter, object creatorSid) 39 | { 40 | Consumer = consumer; 41 | Filter = filter; 42 | CreatorSID = creatorSid; 43 | } 44 | public object Consumer { get; } 45 | 46 | public object Filter { get; } 47 | 48 | public object CreatorSID { get; } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/WindowsAutoLogonCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Microsoft.Win32; 3 | 4 | namespace Seatbelt.Commands.Windows 5 | { 6 | internal class WindowsAutoLogonCommand : CommandBase 7 | { 8 | public override string Command => "WindowsAutoLogon"; 9 | public override string Description => "Registry autologon information"; 10 | public override CommandGroup[] Group => new[] {CommandGroup.System}; 11 | public Runtime ThisRunTime; 12 | public override bool SupportRemote => true; 13 | 14 | public WindowsAutoLogonCommand(Runtime runtime) : base(runtime) 15 | { 16 | ThisRunTime = runtime; 17 | } 18 | 19 | public override IEnumerable Execute(string[] args) 20 | { 21 | var winlogonPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"; 22 | var strDefaultDomainName = ThisRunTime.GetStringValue(RegistryHive.LocalMachine, winlogonPath, "DefaultDomainName"); 23 | 24 | var strDefaultUserName = ThisRunTime.GetStringValue(RegistryHive.LocalMachine, winlogonPath, "DefaultUserName"); 25 | 26 | var strDefaultPassword = ThisRunTime.GetStringValue(RegistryHive.LocalMachine, winlogonPath, "DefaultPassword"); 27 | 28 | var strAltDefaultDomainName = ThisRunTime.GetStringValue(RegistryHive.LocalMachine, winlogonPath, "AltDefaultDomainName"); 29 | 30 | var strAltDefaultUserName = ThisRunTime.GetStringValue(RegistryHive.LocalMachine, winlogonPath, "AltDefaultUserName"); 31 | 32 | var strAltDefaultPassword = ThisRunTime.GetStringValue(RegistryHive.LocalMachine, winlogonPath, "AltDefaultPassword"); 33 | 34 | yield return new WindowsAutoLogonDTO( 35 | strDefaultDomainName, 36 | strDefaultUserName, 37 | strDefaultPassword, 38 | strAltDefaultDomainName, 39 | strAltDefaultUserName, 40 | strAltDefaultPassword 41 | ); 42 | } 43 | 44 | internal class WindowsAutoLogonDTO : CommandDTOBase 45 | { 46 | public WindowsAutoLogonDTO(string? defaultDomainName, string? defaultUserName, string? defaultPassword, string? altDefaultDomainName, string? altDefaultUserName, string? altDefaultPassword) 47 | { 48 | DefaultDomainName = defaultDomainName; 49 | DefaultUserName = defaultUserName; 50 | DefaultPassword = defaultPassword; 51 | AltDefaultDomainName = altDefaultDomainName; 52 | AltDefaultUserName = altDefaultUserName; 53 | AltDefaultPassword = altDefaultPassword; 54 | } 55 | public string? DefaultDomainName { get; } 56 | public string? DefaultUserName { get; } 57 | public string? DefaultPassword { get; } 58 | public string? AltDefaultDomainName { get; } 59 | public string? AltDefaultUserName { get; } 60 | public string? AltDefaultPassword { get; } 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /Seatbelt/Commands/Windows/WindowsEventForwardingCommand.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32; 2 | using System.Collections.Generic; 3 | using Seatbelt.Output.TextWriters; 4 | using Seatbelt.Output.Formatters; 5 | 6 | 7 | namespace Seatbelt.Commands.Windows 8 | { 9 | internal class WindowsEventForwardingCommand : CommandBase 10 | { 11 | public override string Command => "WindowsEventForwarding"; 12 | public override string Description => "Windows Event Forwarding (WEF) settings via the registry"; 13 | public override CommandGroup[] Group => new[] { CommandGroup.System, CommandGroup.Remote }; 14 | public override bool SupportRemote => true; 15 | public Runtime ThisRunTime; 16 | 17 | public WindowsEventForwardingCommand(Runtime runtime) : base(runtime) 18 | { 19 | ThisRunTime = runtime; 20 | } 21 | 22 | public override IEnumerable Execute(string[] args) 23 | { 24 | 25 | var settings = ThisRunTime.GetValues(RegistryHive.LocalMachine, "Software\\Policies\\Microsoft\\Windows\\EventLog\\EventForwarding\\SubscriptionManager"); 26 | 27 | if (settings != null) 28 | { 29 | foreach (var kvp in settings) 30 | { 31 | if (kvp.Value.GetType().IsArray && (kvp.Value.GetType().GetElementType().ToString() == "System.String")) 32 | { 33 | var result = string.Join(",", (string[])kvp.Value); 34 | WriteHost(" {0,-30} : {1}", kvp.Key, result); 35 | yield return new WindowsEventForwardingDTO(kvp.Key, result); 36 | } 37 | else 38 | { 39 | WriteHost(" {0,-30} : {1}", kvp.Key, kvp.Value); 40 | yield return new WindowsEventForwardingDTO(kvp.Key, kvp.Value.ToString()); 41 | } 42 | } 43 | } 44 | } 45 | 46 | internal class WindowsEventForwardingDTO : CommandDTOBase 47 | { 48 | public WindowsEventForwardingDTO(string key, string value) 49 | { 50 | Key = key; 51 | Value = value; 52 | } 53 | public string Key { get; } 54 | public string Value { get; } 55 | } 56 | 57 | [CommandOutputType(typeof(WindowsEventForwardingDTO))] 58 | internal class WindowsEventForwardingFormatter : TextFormatterBase 59 | { 60 | public WindowsEventForwardingFormatter(ITextWriter writer) : base(writer) 61 | { 62 | } 63 | 64 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 65 | { 66 | var dto = (WindowsEventForwardingDTO)result; 67 | 68 | WriteLine(" {0,-30} : {1}", dto.Key, dto.Value); 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Seatbelt/Interop/COM.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Seatbelt.Interop 4 | { 5 | internal class COM 6 | { 7 | [Flags] 8 | public enum FirewallProfiles : int 9 | { 10 | DOMAIN = 1, 11 | PRIVATE = 2, 12 | PUBLIC = 4, 13 | ALL = 2147483647 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Seatbelt/Interop/Kernel32.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace Seatbelt.Interop 5 | { 6 | internal class Kernel32 7 | { 8 | [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)] 9 | [return: MarshalAs(UnmanagedType.Bool)] 10 | public static extern bool IsWow64Process( 11 | [In] IntPtr hProcess, 12 | [Out] out bool wow64Process 13 | ); 14 | 15 | [DllImport("kernel32.dll", SetLastError = true)] 16 | [return: MarshalAs(UnmanagedType.Bool)] 17 | public static extern bool CloseHandle(IntPtr hObject); 18 | 19 | [DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)] 20 | public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count); 21 | 22 | [DllImport("kernel32.dll")] 23 | public static extern IntPtr LocalAlloc(uint uFlags, uint uBytes); 24 | 25 | [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 26 | public static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData); 27 | 28 | [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 29 | public static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA 30 | lpFindFileData); 31 | 32 | [DllImport("kernel32.dll", SetLastError = true)] 33 | public static extern IntPtr OpenProcess( 34 | ProcessAccess processAccess, 35 | bool bInheritHandle, 36 | int processId); 37 | 38 | [DllImport("kernel32.dll", SetLastError = true)] 39 | public static extern bool FindClose(IntPtr hFindFile); 40 | 41 | [DllImport("kernel32.dll")] 42 | public static extern int GetLastError(); 43 | 44 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 45 | public struct WIN32_FIND_DATA 46 | { 47 | public uint dwFileAttributes; 48 | public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime; 49 | public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime; 50 | public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime; 51 | public uint nFileSizeHigh; 52 | public uint nFileSizeLow; 53 | public uint dwReserved0; 54 | public uint dwReserved1; 55 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] 56 | public string cFileName; 57 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] 58 | public string cAlternateFileName; 59 | } 60 | 61 | [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 62 | public static extern IntPtr CreateFile( 63 | [MarshalAs(UnmanagedType.LPTStr)] string filename, 64 | [MarshalAs(UnmanagedType.U4)] System.IO.FileAccess access, 65 | [MarshalAs(UnmanagedType.U4)] System.IO.FileShare share, 66 | IntPtr securityAttributes, 67 | [MarshalAs(UnmanagedType.U4)] System.IO.FileMode creationDisposition, 68 | [MarshalAs(UnmanagedType.U4)] System.IO.FileAttributes flagsAndAttributes, 69 | IntPtr templateFile); 70 | 71 | [DllImport("kernel32.dll", SetLastError = true)] 72 | public static extern bool GetNamedPipeServerProcessId(IntPtr hPipe, out int ProcessId); 73 | 74 | [DllImport("kernel32.dll", SetLastError = true)] 75 | public static extern bool GetNamedPipeServerSessionId(IntPtr hPipe, out int ProcessId); 76 | 77 | [DllImport("kernel32.dll")] 78 | public static extern IntPtr GetConsoleWindow(); 79 | 80 | 81 | [Flags] 82 | public enum ProcessAccess 83 | { 84 | AllAccess = 0x001FFFFF, 85 | Terminate = 0x00000001, 86 | CreateThread = 0x00000002, 87 | VirtualMemoryOperation = 0x00000008, 88 | VirtualMemoryRead = 0x00000010, 89 | VirtualMemoryWrite = 0x00000020, 90 | DuplicateHandle = 0x00000040, 91 | CreateProcess = 0x000000080, 92 | SetQuota = 0x00000100, 93 | SetInformation = 0x00000200, 94 | QueryInformation = 0x00000400, 95 | QueryLimitedInformation = 0x00001000, 96 | Synchronize = 0x00100000 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Seatbelt/Interop/Mpr.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using System.Text; 3 | 4 | namespace Seatbelt.Interop 5 | { 6 | public class Mpr 7 | { 8 | [DllImport("mpr.dll", CharSet = CharSet.Unicode, SetLastError = true)] 9 | public static extern int WNetGetConnection( 10 | [MarshalAs(UnmanagedType.LPTStr)] string localName, 11 | [MarshalAs(UnmanagedType.LPTStr)] StringBuilder remoteName, 12 | ref int length 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Seatbelt/Interop/Ntdll.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Runtime.InteropServices; 5 | 6 | 7 | namespace Seatbelt.Interop 8 | { 9 | internal class Ntdll 10 | { 11 | #region Function Definitions 12 | [DllImport("ntdll.dll", SetLastError = true)] 13 | public static extern int NtQueryInformationProcess( 14 | IntPtr processHandle, 15 | PROCESSINFOCLASS processInformationClass, 16 | ref PsProtection processInformation, 17 | int processInformationLength, 18 | out int returnLength); 19 | } 20 | #endregion 21 | 22 | #region Enum Definitions 23 | [Flags] 24 | public enum PROCESSINFOCLASS 25 | { 26 | ProcessProtectionInformation = 0x3D, 27 | } 28 | [StructLayout(LayoutKind.Sequential)] 29 | public struct PsProtection 30 | { 31 | public PsProtectedType Type; 32 | public PsProtectedSigner Signer; 33 | public PsProtectedAudit Audit; 34 | } 35 | [Flags] 36 | public enum PsProtectedType 37 | { 38 | PsProtectedTypeNone = 0x0, 39 | PsProtectedTypeProtectedLight = 0x1, 40 | PsProtectedTypeProtected = 0x2, 41 | PsProtectedTypeMax = 0x3, 42 | } 43 | [Flags] 44 | public enum PsProtectedSigner 45 | { 46 | PsProtectedSignerNone = 0x0, 47 | PsProtectedSignerAuthenticode = 0x1, 48 | PsProtectedSignerCodeGen = 0x2, 49 | PsProtectedSignerAntimalware = 0x3, 50 | PsProtectedSignerLsa = 0x4, 51 | PsProtectedSignerWindows = 0x5, 52 | PsProtectedSignerWinTcb = 0x6, 53 | PsProtectedSignerMax = 0x7, 54 | } 55 | 56 | public enum PsProtectedAudit 57 | { 58 | None = 0x0 59 | } 60 | 61 | [Flags] 62 | public enum ProtectionValueName 63 | { 64 | PsProtectedTypeNone = 0, 65 | PsProtectedSignerAuthenticodeLight = 11, 66 | PsProtectedSignerCodeGenLight = 21, 67 | PsProtectedSignerAntimalwareLight = 31, 68 | PsProtectedSignerLsaLight = 41, 69 | PsProtectedSignerWindowsLight = 51, 70 | PsProtectedSignerWinTcbLight = 61, 71 | PsProtectedSignerMaxLight = 71, 72 | PsProtectedSignerAuthenticode = 12, 73 | PsProtectedSignerCodeGen = 22, 74 | PsProtectedSignerAntimalware = 32, 75 | PsProtectedSignerLsa = 42, 76 | PsProtectedSignerWindows = 52, 77 | PsProtectedSignerWinTcb = 62, 78 | PsProtectedSignerMax = 72, 79 | PsProtectedSignerAuthenticodeMax = 13, 80 | PsProtectedSignerCodeGenMax = 23, 81 | PsProtectedSignerAntimalwareMax = 33, 82 | PsProtectedSignerLsaMax = 43, 83 | PsProtectedSignerWindowsMax = 53, 84 | PsProtectedSignerWinTcbMax = 63, 85 | PsProtectedSignerMaxMax = 73 86 | } 87 | #endregion 88 | } 89 | 90 | 91 | -------------------------------------------------------------------------------- /Seatbelt/Interop/SecBuffer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace Seatbelt.Interop 5 | { 6 | // From https://github.com/mono/linux-packaging-mono/blob/d356d2b7db91d62b80a61eeb6fbc70a402ac3cac/external/corefx/src/System.Data.SqlClient/tests/Tools/TDS/TDS.EndPoint/SSPI/SecBufferType.cs 7 | [StructLayout(LayoutKind.Sequential)] 8 | public struct SecBuffer : IDisposable 9 | { 10 | public int BufferSize; 11 | public int BufferType; 12 | public IntPtr BufferPtr; 13 | 14 | /// 15 | /// Initialization constructor that allocates a new security buffer 16 | /// 17 | /// Size of the buffer to allocate 18 | internal SecBuffer(int bufferSize) 19 | { 20 | // Save buffer size 21 | BufferSize = bufferSize; 22 | 23 | // Set buffer type (2 = Token) 24 | BufferType = 2; 25 | 26 | // Allocate buffer 27 | BufferPtr = Marshal.AllocHGlobal(bufferSize); 28 | } 29 | 30 | /// 31 | /// Initialization constructor for existing buffer 32 | /// 33 | /// Data 34 | internal SecBuffer(byte[] buffer) 35 | { 36 | // Save buffer size 37 | BufferSize = buffer.Length; 38 | 39 | // Set buffer type (2 = Token) 40 | BufferType = 2; 41 | 42 | // Allocate unmanaged memory for the buffer 43 | BufferPtr = Marshal.AllocHGlobal(BufferSize); 44 | 45 | 46 | try 47 | { 48 | // Copy data into the unmanaged memory 49 | Marshal.Copy(buffer, 0, BufferPtr, BufferSize); 50 | } 51 | catch (Exception) 52 | { 53 | // Dispose object 54 | Dispose(); 55 | 56 | // Re-throw exception 57 | throw; 58 | } 59 | } 60 | 61 | /// 62 | /// Extract raw byte data from the security buffer 63 | /// 64 | internal byte[] ToArray() 65 | { 66 | // Check if we have a security buffer 67 | if (BufferPtr == IntPtr.Zero) 68 | { 69 | return new byte[] {}; 70 | } 71 | 72 | // Allocate byte buffer 73 | var buffer = new byte[BufferSize]; 74 | 75 | // Copy data from the native space 76 | Marshal.Copy(BufferPtr, buffer, 0, BufferSize); 77 | 78 | return buffer; 79 | } 80 | 81 | /// 82 | /// Dispose security buffer 83 | /// 84 | public void Dispose() 85 | { 86 | // Check buffer pointer validity 87 | if (BufferPtr != IntPtr.Zero) 88 | { 89 | // Release memory associated with it 90 | Marshal.FreeHGlobal(BufferPtr); 91 | 92 | // Reset buffer pointer 93 | BufferPtr = IntPtr.Zero; 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Seatbelt/Interop/Shell32.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace Seatbelt.Interop 5 | { 6 | internal class Shell32 7 | { 8 | [DllImport("shell32.dll", SetLastError = true)] 9 | private static extern IntPtr CommandLineToArgvW( 10 | [MarshalAs(UnmanagedType.LPWStr)] string lpCmdLine, out int pNumArgs); 11 | 12 | public static string[] CommandLineToArgs(string commandLine) 13 | { 14 | var argv = CommandLineToArgvW(commandLine, out var argc); 15 | if (argv == IntPtr.Zero) 16 | throw new System.ComponentModel.Win32Exception(); 17 | try 18 | { 19 | var args = new string[argc]; 20 | for (var i = 0; i < args.Length; i++) 21 | { 22 | var p = Marshal.ReadIntPtr(argv, i * IntPtr.Size); 23 | args[i] = Marshal.PtrToStringUni(p); 24 | } 25 | 26 | return args; 27 | } 28 | finally 29 | { 30 | Marshal.FreeHGlobal(argv); 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Seatbelt/Interop/Shlwapi.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace Seatbelt.Interop 4 | { 5 | class Shlwapi 6 | { 7 | public static bool IsWindowsServer() 8 | { 9 | return IsOS(OS_ANYSERVER); 10 | } 11 | 12 | const int OS_ANYSERVER = 29; 13 | 14 | [DllImport("shlwapi.dll", SetLastError = true, EntryPoint = "#437")] 15 | private static extern bool IsOS(int os); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Seatbelt/Interop/User32.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace Seatbelt.Interop 4 | { 5 | internal class User32 6 | { 7 | [DllImport("User32.dll")] 8 | public static extern bool GetLastInputInfo(ref LastInputInfo lastInputInfo); 9 | 10 | [DllImport("user32.dll")] 11 | public static extern bool SetProcessDPIAware(); 12 | 13 | internal struct LastInputInfo 14 | { 15 | public uint Size; 16 | public uint Time; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Seatbelt/Interop/VaultCli.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace Seatbelt 5 | { 6 | public static class VaultCli 7 | { 8 | // pulled directly from @djhohnstein's SharpWeb project: https://github.com/djhohnstein/SharpWeb/blob/master/Edge/SharpEdge.cs 9 | public enum VAULT_ELEMENT_TYPE : int 10 | { 11 | Undefined = -1, 12 | Boolean = 0, 13 | Short = 1, 14 | UnsignedShort = 2, 15 | Int = 3, 16 | UnsignedInt = 4, 17 | Double = 5, 18 | Guid = 6, 19 | String = 7, 20 | ByteArray = 8, 21 | TimeStamp = 9, 22 | ProtectedArray = 10, 23 | Attribute = 11, 24 | Sid = 12, 25 | Last = 13 26 | } 27 | 28 | public enum VAULT_SCHEMA_ELEMENT_ID : int 29 | { 30 | Illegal = 0, 31 | Resource = 1, 32 | Identity = 2, 33 | Authenticator = 3, 34 | Tag = 4, 35 | PackageSid = 5, 36 | AppStart = 100, 37 | AppEnd = 10000 38 | } 39 | 40 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 41 | public struct VAULT_ITEM_WIN8 42 | { 43 | public Guid SchemaId; 44 | public IntPtr pszCredentialFriendlyName; 45 | public IntPtr pResourceElement; 46 | public IntPtr pIdentityElement; 47 | public IntPtr pAuthenticatorElement; 48 | public IntPtr pPackageSid; 49 | public ulong LastModified; 50 | public uint dwFlags; 51 | public uint dwPropertiesCount; 52 | public IntPtr pPropertyElements; 53 | } 54 | 55 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 56 | public struct VAULT_ITEM_WIN7 57 | { 58 | public Guid SchemaId; 59 | public IntPtr pszCredentialFriendlyName; 60 | public IntPtr pResourceElement; 61 | public IntPtr pIdentityElement; 62 | public IntPtr pAuthenticatorElement; 63 | public ulong LastModified; 64 | public uint dwFlags; 65 | public uint dwPropertiesCount; 66 | public IntPtr pPropertyElements; 67 | } 68 | 69 | [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)] 70 | public struct VAULT_ITEM_ELEMENT 71 | { 72 | [FieldOffset(0)] 73 | public VAULT_SCHEMA_ELEMENT_ID SchemaElementId; 74 | [FieldOffset(8)] 75 | public VAULT_ELEMENT_TYPE Type; 76 | //[FieldOffset(16)] 77 | //public Guid Guid; 78 | } 79 | 80 | //typedef struct _VAULT_BYTE_BUFFER 81 | //{ 82 | // DWORD Length; 83 | // PBYTE Value; 84 | //} 85 | //VAULT_BYTE_BUFFER, *PVAULT_BYTE_BUFFER; 86 | [StructLayout(LayoutKind.Sequential)] 87 | public struct VAULT_BYTE_ARRAY 88 | { 89 | public int Length; 90 | public IntPtr pData; 91 | } 92 | 93 | [DllImport("vaultcli.dll")] 94 | public static extern int VaultOpenVault(ref Guid vaultGuid, uint offset, ref IntPtr vaultHandle); 95 | 96 | [DllImport("vaultcli.dll")] 97 | public static extern int VaultCloseVault(ref IntPtr vaultHandle); 98 | 99 | [DllImport("vaultcli.dll")] 100 | public static extern int VaultFree(ref IntPtr vaultHandle); 101 | 102 | [DllImport("vaultcli.dll")] 103 | public static extern int VaultEnumerateVaults(int offset, ref int vaultCount, ref IntPtr vaultGuid); 104 | 105 | [DllImport("vaultcli.dll")] 106 | public static extern int VaultEnumerateItems(IntPtr vaultHandle, int chunkSize, ref int vaultItemCount, ref IntPtr vaultItem); 107 | 108 | [DllImport("vaultcli.dll", EntryPoint = "VaultGetItem")] 109 | public static extern int VaultGetItem_WIN8(IntPtr vaultHandle, ref Guid schemaId, IntPtr pResourceElement, IntPtr pIdentityElement, IntPtr pPackageSid, IntPtr zero, int arg6, ref IntPtr passwordVaultPtr); 110 | 111 | [DllImport("vaultcli.dll", EntryPoint = "VaultGetItem")] 112 | public static extern int VaultGetItem_WIN7(IntPtr vaultHandle, ref Guid schemaId, IntPtr pResourceElement, IntPtr pIdentityElement, IntPtr zero, int arg5, ref IntPtr passwordVaultPtr); 113 | 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /Seatbelt/Interop/Win32Error.cs: -------------------------------------------------------------------------------- 1 | namespace Seatbelt.Interop 2 | { 3 | // Defined at https://msdn.microsoft.com/en-us/library/cc231199.aspx 4 | // Only list error codes that are actually used in our code 5 | internal class Win32Error 6 | { 7 | public const int InvalidHandle = -1; 8 | public const int Success = 0; 9 | public const int NERR_Success = 0; 10 | public const int AccessDenied = 0x0000005; 11 | public const int NotEnoughMemory = 0x00000008; 12 | public const int InsufficientBuffer = 0x0000007A; 13 | public const int MoreData = 0x00000EA; 14 | public const int NoSuchAlias = 0x0000560; 15 | public const int RpcServerUnavailable = 0x0006BA; 16 | public const int NERR_GroupNotFound = 0x00008AC; 17 | public const int NERR_InvalidComputer = 0x000092F; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Seatbelt/Output/Formatters/DefaultTextFormatter.cs: -------------------------------------------------------------------------------- 1 | using Seatbelt.Commands; 2 | using Seatbelt.Output.TextWriters; 3 | 4 | namespace Seatbelt.Output.Formatters 5 | { 6 | // If a command doesn't customize its output text, then this will be called 7 | internal class DefaultTextFormatter : TextFormatterBase 8 | { 9 | public DefaultTextFormatter(ITextWriter writer) : base(writer) 10 | { 11 | } 12 | 13 | public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) 14 | { 15 | if (result == null) 16 | { 17 | return; 18 | } 19 | 20 | var type = result.GetType(); 21 | 22 | foreach (var p in type.GetProperties()) 23 | { 24 | if (p.PropertyType.IsArray) 25 | { 26 | var value = (object[])p.GetValue(result, null); 27 | Write($" {p.Name,-30} : "); 28 | for (var i = 0; i < value.Length; i++) 29 | { 30 | Write(value[i].ToString()); 31 | if (value.Length-1 != i) 32 | { 33 | Write(", "); 34 | } 35 | } 36 | WriteLine(); 37 | } 38 | else 39 | { 40 | var value = p.GetValue(result, null); 41 | WriteLine(" {0,-30} : {1}", p.Name, value); 42 | } 43 | } 44 | 45 | WriteLine(); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /Seatbelt/Output/Formatters/TextFormatterBase.cs: -------------------------------------------------------------------------------- 1 | using Seatbelt.Commands; 2 | using Seatbelt.Output.TextWriters; 3 | 4 | // Individual commands can impelement this this class if they want to format textual output in a certain way 5 | namespace Seatbelt.Output.Formatters 6 | { 7 | internal abstract class TextFormatterBase 8 | { 9 | private readonly ITextWriter _textWriter; 10 | 11 | protected TextFormatterBase(ITextWriter sink) 12 | { 13 | _textWriter = sink; 14 | } 15 | 16 | // Children implement this method to customize the command's string output 17 | public abstract void FormatResult(CommandBase? command, CommandDTOBase results, bool filterResults); 18 | 19 | protected void Write(string str) => _textWriter.Write(str); 20 | protected void WriteLine() => _textWriter.WriteLine(); 21 | protected void WriteLine(string str) => _textWriter.WriteLine(str); 22 | protected void WriteLine(string format, params object?[] args) => _textWriter.WriteLine(format, args); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Seatbelt/Output/Sinks/IOutputSink.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Seatbelt.Commands; 3 | 4 | namespace Seatbelt.Output.Sinks 5 | { 6 | internal interface IOutputSink : IDisposable 7 | { 8 | void WriteOutput(CommandDTOBase dto); 9 | void WriteHost(string message); 10 | void WriteVerbose(string message); 11 | void WriteWarning(string message); 12 | void WriteError(string message); 13 | string GetOutput(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Seatbelt/Output/Sinks/JsonFileOutputSink.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Web.Script.Serialization; 4 | using Seatbelt.Commands; 5 | 6 | namespace Seatbelt.Output.Sinks 7 | { 8 | // Any sinks that output text to a location should inherit from this class 9 | internal class JsonFileOutputSink : IOutputSink 10 | { 11 | private StreamWriter _stream; 12 | private JavaScriptSerializer _json = new JavaScriptSerializer(); 13 | 14 | public JsonFileOutputSink(string file, bool filterResults) 15 | { 16 | if (File.Exists(file)) 17 | { 18 | File.Delete(file); 19 | } 20 | 21 | _stream = File.CreateText(file); 22 | _stream.AutoFlush = true; 23 | } 24 | 25 | public void WriteOutput(CommandDTOBase dto) 26 | { 27 | //var obj = dtoCollection?.FirstOrDefault(); 28 | if (dto == null) 29 | { 30 | return; 31 | } 32 | 33 | // If the dto has a custom output sink, use it. Otherwise, use the default output sink 34 | var dtoType = dto.GetType(); 35 | 36 | var obj = new 37 | { 38 | Type = dtoType.ToString(), 39 | Data = dto 40 | }; 41 | 42 | string jsonStr; 43 | try 44 | { 45 | jsonStr = _json.Serialize(obj); 46 | } 47 | catch(Exception e) 48 | { 49 | jsonStr = _json.Serialize(new 50 | { 51 | Type = typeof(ErrorDTO).ToString(), 52 | Data = _json.Serialize(new ErrorDTO(e.ToString())) 53 | }); 54 | } 55 | 56 | _stream.WriteLine(jsonStr); 57 | } 58 | 59 | public void WriteVerbose(string message) => WriteOutput(new VerboseDTO(message)); 60 | 61 | public void WriteWarning(string message) => WriteOutput(new WarningDTO(message)); 62 | 63 | public void WriteError(string message) => WriteOutput(new ErrorDTO(message)); 64 | 65 | public void WriteHost(string message) => WriteOutput(new HostDTO(message)); 66 | 67 | public string GetOutput() 68 | { 69 | return ""; 70 | } 71 | 72 | public void Dispose() 73 | { 74 | _stream.Dispose(); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Seatbelt/Output/Sinks/JsonStringOutputSink.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Web.Script.Serialization; 4 | using Seatbelt.Commands; 5 | 6 | namespace Seatbelt.Output.Sinks 7 | { 8 | // Any sinks that output text to a location should inherit from this class 9 | internal class JsonStringOutputSink : IOutputSink 10 | { 11 | private StreamWriter _streamWriter; 12 | private MemoryStream _stream; 13 | private JavaScriptSerializer _json = new JavaScriptSerializer(); 14 | 15 | public JsonStringOutputSink(string file, bool filterResults) 16 | { 17 | _stream = new MemoryStream(); 18 | _streamWriter = new StreamWriter(_stream); 19 | _streamWriter.AutoFlush = true; 20 | } 21 | 22 | public void WriteOutput(CommandDTOBase dto) 23 | { 24 | //var obj = dtoCollection?.FirstOrDefault(); 25 | if (dto == null) 26 | { 27 | return; 28 | } 29 | 30 | // If the dto has a custom output sink, use it. Otherwise, use the default output sink 31 | var dtoType = dto.GetType(); 32 | if (dtoType == typeof(HostDTO)) return; 33 | 34 | var obj = new 35 | { 36 | Type = dtoType.ToString(), 37 | CommandVersion = dto.GetCommandVersion(), 38 | Data = dto 39 | }; 40 | 41 | string jsonStr; 42 | try 43 | { 44 | jsonStr = _json.Serialize(obj); 45 | } 46 | catch(Exception e) 47 | { 48 | jsonStr = _json.Serialize(new 49 | { 50 | Type = typeof(ErrorDTO).ToString(), 51 | Data = _json.Serialize(new ErrorDTO(e.ToString())) 52 | }); 53 | } 54 | 55 | _streamWriter.WriteLine(jsonStr); 56 | } 57 | 58 | public void WriteVerbose(string message) => WriteOutput(new VerboseDTO(message)); 59 | 60 | public void WriteWarning(string message) => WriteOutput(new WarningDTO(message)); 61 | 62 | public void WriteError(string message) => WriteOutput(new ErrorDTO(message)); 63 | 64 | public void WriteHost(string message) => WriteOutput(new HostDTO(message)); 65 | 66 | public string GetOutput() 67 | { 68 | _stream.Flush(); 69 | _streamWriter.Flush(); 70 | _stream.Position = 0; 71 | StreamReader sr = new StreamReader(_stream); 72 | return sr.ReadToEnd(); 73 | } 74 | 75 | public void Dispose() 76 | { 77 | _streamWriter.Dispose(); 78 | _stream.Dispose(); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Seatbelt/Output/Sinks/TextOutputSink.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using Seatbelt.Commands; 6 | using Seatbelt.Output.Formatters; 7 | using Seatbelt.Output.TextWriters; 8 | 9 | namespace Seatbelt.Output.Sinks 10 | { 11 | // Any sinks that output text to a location should inherit from this class 12 | internal class TextOutputSink : IOutputSink 13 | { 14 | private readonly Dictionary _customSinks = new Dictionary(); 15 | private readonly TextFormatterBase _defaultTextSink; 16 | 17 | private readonly ITextWriter _textWriter; 18 | private readonly bool _filterResults; 19 | 20 | public TextOutputSink(ITextWriter writer, bool filterResults) 21 | { 22 | _textWriter = writer; 23 | _filterResults = filterResults; 24 | 25 | // If a command doesn't customize its output, the default text outputter will be used 26 | _defaultTextSink = new DefaultTextFormatter(_textWriter); 27 | InitializeCustomTextFormatters(); 28 | } 29 | 30 | private static Assembly MyAssemblyResolveEventHandler(object sender, ResolveEventArgs args) 31 | { 32 | return System.Reflection.Assembly.GetExecutingAssembly(); 33 | } 34 | 35 | private void InitializeCustomTextFormatters() 36 | { 37 | var currentAssembly = Assembly.GetExecutingAssembly(); 38 | 39 | AppDomain currentDomain = AppDomain.CurrentDomain; 40 | currentDomain.AssemblyResolve += new ResolveEventHandler(MyAssemblyResolveEventHandler); 41 | 42 | foreach (var formatter in currentAssembly.GetTypes().Where(t => typeof(TextFormatterBase).IsAssignableFrom(t))) 43 | { 44 | var attributes = Attribute.GetCustomAttributes(formatter); 45 | 46 | foreach (var t in attributes) 47 | { 48 | if (!(t is CommandOutputTypeAttribute)) continue; 49 | 50 | var outputTypeAttr = (CommandOutputTypeAttribute) t; 51 | 52 | if (_customSinks.ContainsKey(outputTypeAttr.Type)) 53 | { 54 | throw new Exception($"Custom sink {outputTypeAttr.Type} already assigned to {_customSinks[outputTypeAttr.Type]}. Could not associate DTO with the another formatter({formatter})"); 55 | } 56 | 57 | _customSinks.Add(outputTypeAttr.Type, (TextFormatterBase)Activator.CreateInstance(formatter, new object[] { _textWriter })); 58 | break; 59 | } 60 | } 61 | 62 | } 63 | 64 | public void WriteOutput(CommandDTOBase dto) 65 | { 66 | //var obj = dtoCollection?.FirstOrDefault(); 67 | if (dto == null) 68 | { 69 | return; 70 | } 71 | 72 | // If the dto has a custom output sink, use it. Otherwise, use the default output sink 73 | var dtoType = dto.GetType(); 74 | if (_customSinks.ContainsKey(dtoType)) 75 | { 76 | _customSinks[dtoType].FormatResult(null, dto, _filterResults); 77 | } 78 | else 79 | { 80 | _defaultTextSink.FormatResult(null, dto, _filterResults); 81 | } 82 | } 83 | 84 | public void WriteVerbose(string message) => WriteOutput(new VerboseDTO(message)); 85 | 86 | public void WriteWarning(string message) => WriteOutput(new WarningDTO(message)); 87 | 88 | public void WriteError(string message) => WriteOutput(new ErrorDTO(message)); 89 | 90 | public void WriteHost(string message) => WriteOutput(new HostDTO(message)); 91 | public string GetOutput() 92 | { 93 | return ""; 94 | } 95 | public void Dispose() 96 | { 97 | _textWriter.Dispose(); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Seatbelt/Output/TextWriters/ConsoleTextWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using Seatbelt.Interop; 4 | 5 | namespace Seatbelt.Output.TextWriters 6 | { 7 | internal class ConsoleTextWriter : ITextWriter 8 | { 9 | public ConsoleTextWriter() 10 | { 11 | if(IsConsolePresent()) Console.OutputEncoding = Encoding.UTF8; 12 | } 13 | 14 | public void Write(string str) 15 | => Console.Write(str); 16 | 17 | public void WriteLine() 18 | => Console.WriteLine(); 19 | 20 | public void WriteLine(string str) 21 | => Console.WriteLine(str); 22 | 23 | public void WriteLine(string format, params object?[] args) => Console.WriteLine(format, args); 24 | 25 | public void Dispose() 26 | { 27 | } 28 | 29 | bool IsConsolePresent() 30 | { 31 | return Kernel32.GetConsoleWindow() != IntPtr.Zero; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Seatbelt/Output/TextWriters/FileTextWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace Seatbelt.Output.TextWriters 5 | { 6 | internal class FileTextWriter : ITextWriter 7 | { 8 | private readonly StreamWriter _stream; 9 | 10 | public FileTextWriter(string fileName) 11 | { 12 | if (File.Exists(fileName)) 13 | { 14 | File.Delete(fileName); 15 | } 16 | 17 | _stream = File.CreateText(fileName); 18 | _stream.AutoFlush = true; 19 | } 20 | 21 | 22 | 23 | public void Write(string str) 24 | => _stream.Write(str); 25 | 26 | public void WriteLine() 27 | => _stream.WriteLine(); 28 | 29 | public void WriteLine(string str) 30 | => _stream.WriteLine(str); 31 | 32 | public void WriteLine(string format, params object?[] args) 33 | => _stream.WriteLine(format, args); 34 | 35 | public void Dispose() 36 | { 37 | _stream.Dispose(); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Seatbelt/Output/TextWriters/ITextWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Seatbelt.Output.TextWriters 4 | { 5 | internal interface ITextWriter : IDisposable 6 | { 7 | void Write(string str); 8 | void WriteLine(); 9 | void WriteLine(string str); 10 | void WriteLine(string format, params object?[] args); 11 | } 12 | } -------------------------------------------------------------------------------- /Seatbelt/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Seatbelt 4 | { 5 | public static class Program 6 | { 7 | private static void Main(string[] args) 8 | { 9 | try 10 | { 11 | using var sb = (new Seatbelt(args)); 12 | sb.Start(); 13 | } 14 | catch (Exception e) 15 | { 16 | Console.WriteLine($"Unhandled terminating exception: {e}"); 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Seatbelt/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("Seatbelt")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("Seatbelt")] 12 | [assembly: AssemblyCopyright("Copyright © 2018")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("aec32155-d589-4150-8fe7-2900df4554c8")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /Seatbelt/SeatbeltArgumentParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Seatbelt 6 | { 7 | class SeatbeltArgumentParser 8 | { 9 | private string[] Arguments { get; set; } 10 | public SeatbeltArgumentParser(string[] args) 11 | { 12 | Arguments = args; 13 | } 14 | 15 | public SeatbeltOptions Parse() 16 | { 17 | var originalArgs = Arguments; 18 | 19 | try 20 | { 21 | var quietMode = ParseAndRemoveSwitchArgument("-q"); 22 | var filterResults = !ParseAndRemoveSwitchArgument("-Full"); 23 | var randomizeOrder = ParseAndRemoveSwitchArgument("-RandomizeOrder"); 24 | 25 | var commandGroups = ParseAndRemoveKeyValueArgument("-Group"); 26 | var outputFile = ParseAndRemoveKeyValueArgument("-OutputFile"); 27 | var computerName = ParseAndRemoveKeyValueArgument("-ComputerName"); 28 | var userName = ParseAndRemoveKeyValueArgument("-Username"); 29 | var password = ParseAndRemoveKeyValueArgument("-Password"); 30 | 31 | var delayCommands = ParseAndRemoveKeyValueArgument("-DelayCommands"); 32 | 33 | return new SeatbeltOptions( 34 | Arguments.ToList(), // Everything else that isn't parsed is interpreted as a command 35 | commandGroups == null ? new List() : commandGroups.Split(',').Select(g => g.Trim()).ToList(), 36 | outputFile, 37 | filterResults, 38 | randomizeOrder, 39 | quietMode, 40 | delayCommands, 41 | computerName, 42 | userName, 43 | password 44 | ); 45 | } 46 | finally 47 | { 48 | Arguments = originalArgs; 49 | } 50 | 51 | } 52 | 53 | private bool ParseAndRemoveSwitchArgument(string key) 54 | { 55 | if (Arguments.Contains(key, StringComparer.CurrentCultureIgnoreCase)) 56 | { 57 | Arguments = Arguments.Where(c => c.ToLower() != key.ToLower()).ToArray(); 58 | return true; 59 | } 60 | 61 | return false; 62 | } 63 | 64 | private string? ParseAndRemoveKeyValueArgument(string key) 65 | { 66 | var arg = Arguments.FirstOrDefault( 67 | c => c.ToLower().StartsWith($"{key.ToLower()}=") 68 | ); 69 | 70 | if (string.IsNullOrEmpty(arg)) 71 | return null; 72 | 73 | try 74 | { 75 | var value = arg.Substring(arg.IndexOf('=') + 1); 76 | Arguments = Arguments.Where(c => !c.ToLower().StartsWith(key.ToLower())).ToArray(); 77 | return value; 78 | } 79 | catch (Exception e) 80 | { 81 | throw new Exception($"Error parsing password argument \"{key}\": {e}"); 82 | } 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Seatbelt/SeatbeltOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Seatbelt 4 | { 5 | class SeatbeltOptions 6 | { 7 | public SeatbeltOptions(IEnumerable commands, IEnumerable commandGroup, string? outputFile, bool filterResults, bool quietMode, bool randomizeOrder, string? delayCommands, string? computerName, string? userName, string? password) 8 | { 9 | Commands = commands; 10 | CommandGroups = commandGroup; 11 | OutputFile = outputFile; 12 | FilterResults = filterResults; 13 | RandomizeOrder = randomizeOrder; 14 | QuietMode = quietMode; 15 | DelayCommands = delayCommands; 16 | ComputerName = computerName; 17 | UserName = userName; 18 | Password = password; 19 | } 20 | 21 | public IEnumerable Commands { get; set; } 22 | public IEnumerable CommandGroups { get; set; } 23 | public string? OutputFile { get; set; } 24 | public bool FilterResults { get; set; } 25 | public bool RandomizeOrder { get; set; } 26 | public bool QuietMode { get; set; } 27 | public string? DelayCommands { get; set; } 28 | public string? ComputerName { get; set; } 29 | public string? UserName { get; set; } 30 | public string? Password { get; set; } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Seatbelt/Util/ExtensionMethods.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Seatbelt.Util 4 | { 5 | internal static class ExtensionMethods 6 | { 7 | // From https://stackoverflow.com/questions/4108828/generic-extension-method-to-see-if-an-enum-contains-a-flag 8 | public static bool HasFlag(this Enum variable, Enum value) 9 | { 10 | if (variable == null) 11 | return false; 12 | 13 | if (value == null) 14 | throw new ArgumentNullException(nameof(value)); 15 | 16 | // Not as good as the .NET 4 version of this function, but should be good enough 17 | if (!Enum.IsDefined(variable.GetType(), value)) 18 | { 19 | throw new ArgumentException( 20 | $"Enumeration type mismatch. The flag is of type '{value.GetType()}', was expecting '{variable.GetType()}'."); 21 | } 22 | 23 | var num = Convert.ToUInt64(value); 24 | return ((Convert.ToUInt64(variable) & num) == num); 25 | 26 | } 27 | 28 | public static T[] SubArray(this T[] data, int index, int length) 29 | { 30 | var result = new T[length]; 31 | Array.Copy(data, index, result, 0, length); 32 | return result; 33 | } 34 | 35 | public static string TrimEnd(string input, string suffixToRemove) 36 | { 37 | if (input.EndsWith(suffixToRemove, StringComparison.OrdinalIgnoreCase)) 38 | { 39 | return input.Substring(0, input.Length - suffixToRemove.Length); 40 | } 41 | 42 | return input; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Seatbelt/Util/WMIUtil.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Management; 3 | 4 | namespace Seatbelt.Util 5 | { 6 | 7 | public class WMIUtil { 8 | 9 | public static ManagementClass WMIRegConnection() 10 | { 11 | return WMIRegConnection(""); 12 | } 13 | 14 | public static ManagementClass WMIRegConnection(string computerName) 15 | { 16 | return WMIRegConnection(computerName, "", ""); 17 | } 18 | 19 | public static ManagementClass WMIRegConnection(string computerName, string userName, string password) 20 | { 21 | ManagementScope scope; 22 | ConnectionOptions connection = new ConnectionOptions(); 23 | connection.Impersonation = ImpersonationLevel.Impersonate; 24 | 25 | if (!String.IsNullOrEmpty(userName)) 26 | { 27 | try 28 | { 29 | if (userName.Contains("\\")) 30 | { 31 | string[] parts = userName.Split('\\'); 32 | connection.Username = parts[1]; 33 | connection.Authority = $"NTLMDOMAIN:{parts[0]}"; 34 | } 35 | else 36 | { 37 | connection.Username = userName; 38 | } 39 | connection.Password = password; 40 | } 41 | catch 42 | { 43 | // ? 44 | } 45 | } 46 | 47 | scope = new ManagementScope($"\\\\{computerName}\\root\\default", connection); 48 | scope.Connect(); 49 | return new ManagementClass(scope, new ManagementPath("StdRegProv"), null); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Seatbelt/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | --------------------------------------------------------------------------------