Skip to content

Commit 1d608c6

Browse files
committed
- Added cmdlet Get-ADGroup
- Added cmdlet Get-ADGroupMember - Added cmdlet Get-ADUser - Added cmdlet Get-LocalGroup - Added cmdlet Get-LocalGroupMember - Added cmdlet Get-LocalUser - Added cmdlet Get-Help - Added cmdlet Measure-Object - Added support for providing examples - Examples added for all cmdlets - Added support for remote machines for the Get-Process cmdlet - Minor bugfixes and improvements - Updated README.md with additional examples
1 parent 136dcdf commit 1d608c6

39 files changed

+1402
-103
lines changed

README.md

Lines changed: 78 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,11 @@ NoPowerShell is a tool implemented in C# which supports executing PowerShell-lik
44
Moreover, this project makes it easy for everyone to extend its functionality using only a few lines of C# code.
55

66
# Screenshots
7-
## Currently supported commands
8-
Running in Cobalt Strike.
7+
## Running in Cobalt Strike
98
![NoPowerShell supported commands](https://raw.githubusercontent.com/bitsadmin/nopowershell/master/Pictures/CurrentlySupportedCommands.png "NoPowerShell in Cobalt Strike")
10-
## Sample commands
9+
## Sample execution of commands
1110
![NoPowerShell sample commands](https://raw.githubusercontent.com/bitsadmin/nopowershell/master/Pictures/SampleCommands.png "NoPowerShell in Cobalt Strike")
1211

13-
1412
# Usage
1513
## Note
1614
When using NoPowerShell from cmd.exe or PowerShell, you need to escape the pipe character (`|`) with respectively a caret (`^`) or a backtick (`` ` ``), i.e.:
@@ -21,17 +19,55 @@ When using NoPowerShell from cmd.exe or PowerShell, you need to escape the pipe
2119
## Examples
2220
| Action | Command | Notes |
2321
| - | - | - |
24-
| List help | `NoPowerShell.exe` | Alternative: `NoPowerShell.exe Get-Command` |
25-
| View status of a service | `NoPowerShell.exe Get-WmiObject -Class Win32_Service -Filter "Name = 'WinRM'"` | |
26-
| Search for KeePass database in C:\Users folder | `NoPowerShell.exe gci C:\Users\ -Force -Recurse -Include *.kdbx \| select Directory,Name,Length` | |
27-
| View system information | `NoPowerShell.exe systeminfo` | |
28-
| List processes on the system | `NoPowerShell.exe Get-Process` | |
22+
| List all commands supported by NoPowerShell | `Get-Command` | |
23+
| Get help for a command | `Get-Help -Name Get-Process` | Alternative: `man ps` |
2924
| Show current user | `NoPowerShell.exe whoami` | Unofficial command |
30-
| List autoruns | `NoPowerShell.exe Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Run` | |
31-
| List network shares connected to from this machine | `NoPowerShell.exe Get-NetSmbMapping` | |
32-
| Download file | `NoPowerShell.exe wget http://myserver.me/nc.exe` | When compiled using .NET 2 only supports SSL up to SSLv3 (no TLS 1.1+) |
33-
| List PowerShell processes on remote system | `NoPowerShell.exe gwmi "Select ProcessId,Name,CommandLine From Win32_Process" -ComputerName dc1.corp.local \| ? Name -Like "powershell*" \| select ProcessId,CommandLine` | Explicit credentials can be specified using the `-Username` and `-Password` parameters |
34-
| Execute program using WMI | `NoPowerShell.exe Invoke-WmiMethod -Class Win32_Process -Name Create "cmd /c calc.exe"` | |
25+
| List all user groups in domain | `Get-ADGroup -Filter *` | |
26+
| List all administrative groups in domain | `Get-ADGroup -LDAPFilter "(admincount=1)" \| select Name` | |
27+
| List all properties of the Administrator domain user | `Get-ADUser -Identity Administrator -Properties *` | |
28+
| List all Administrative users in domain | `Get-ADUser -LDAPFilter "(admincount=1)"` | |
29+
| List all users in domain | `Get-ADUser -Filter *` | |
30+
| List specific attributes of user | `Get-ADUser Administrator -Properties SamAccountName,ObjectSID` | |
31+
| Show information about the current system | `systeminfo` | Unofficial command |
32+
| List all processes containing PowerShell in the process name | `Get-Process \| ? Name -Like *PowerShell*` | |
33+
| List all active local users | `Get-LocalUser \| ? Disabled -EQ False` | |
34+
| List all local groups | `Get-LocalGroup` | |
35+
| List details of a specific group | `Get-LocalGroup Administrators` | |
36+
| List all active members of the Administrators group | `Get-LocalGroupMember -Group Administrators \| ? Disabled -eq False` | |
37+
| List all local users | `Get-LocalUser` | |
38+
| List details of a specific user | `Get-LocalUser Administrator` | |
39+
| Copy file from one location to another | `copy C:\Tmp\nc.exe C:\Windows\System32\nc.exe` | |
40+
| Copy folder | `copy C:\Tmp\MyFolder C:\Tmp\MyFolderBackup` | |
41+
| Locate KeePass files in the C:\Users\ directory | `ls -Recurse -Force C:\Users\ -Include *.kdbx` | |
42+
| List the keys under the SOFTWARE key in the registry | `ls HKLM:\SOFTWARE` | |
43+
| View contents of a file | `Get-Content C:\Windows\WindowsUpdate.log` | |
44+
| List autoruns in the registry | `Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Run \| ft` | |
45+
| List processes | `Get-Process` | |
46+
| List processes on remote host | `Get-Process -ComputerName dc01.corp.local -Username Administrator -Password P4ssw0rd!` | |
47+
| 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 |
48+
| View details about a certain service | `Get-WmiObject -Class Win32_Service -Filter "Name = 'WinRM'"` | |
49+
| Launch process using WMI | `Invoke-WmiMethod -Class Win32_Process -Name Create "cmd /c calc.exe"` | This can also be done on a remote system |
50+
| Delete a read-only file | `Remove-Item -Force C:\Tmp\MyFile.txt` | |
51+
| Recursively delete a folder | `Remove-Item -Recurse C:\Tmp\MyTools\` | |
52+
| Show all network interfaces | `Get-NetIPAddress -All` | |
53+
| Show the IP routing table | `Get-NetRoute` | |
54+
| 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` | |
55+
| Perform a traceroute with a timeout of 1 second and a maximum of 20 hops | `Test-NetConnection -TraceRoute -Timeout 1000 -Hops 20 google.com` | |
56+
| List network shares on the local machine that are exposed to the network | `Get-NetSmbMapping` | |
57+
| Format output as a list | `Get-LocalUser \| fl` | |
58+
| Format output as a list showing only specific attributes | `Get-LocalUser \| fl Name,Description` | |
59+
| Format output as a table | `Get-Process \| ft` | |
60+
| Format output as a table showing only specific attributes | `Get-Process \| ft ProcessId,Name` | |
61+
| 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+) |
62+
| Download file from the Internet specifying the destination | `wget http://myserver.me/nc.exe -OutFile C:\Tmp\netcat.exe` | |
63+
| Count number of results | `Get-Process \| measure` | |
64+
| Count number of lines in file | `gc C:\Windows\WindowsUpdate.log \| measure` | |
65+
| Show only the Name in a file listing | `ls C:\ \| select Name` | |
66+
| Show first 10 results of file listing | `ls C:\Windows\System32 -Include *.exe \| select -First 10 Name,Length` | |
67+
| List all members of the "Domain Admins" group | `Get-ADGroupMember "Domain Admins"` | |
68+
| Resolve domain name | `Resolve-DnsName microsoft.com` | Alternative: `host linux.org` |
69+
| List local shares | `Get-WmiObject -Namespace ROOT\CIMV2 -Query "Select * From Win32_Share Where Name LIKE '%$'"` | Alternative: `gwmi -Class Win32_Share -Filter "Name LIKE '%$'"` |
70+
| Show network interfaces | `Get-NetIPAddress` | Alternatives: `ipconfig`, `ifconfig` |
3571

3672
## Install in Cobalt Strike
3773
1. Copy both NoPowerShell.exe and NoPowerShell.cna to the **scripts** subfolder of Cobalt Strike
@@ -58,7 +94,6 @@ Add your own cmdlets by submitting a pull request.
5894
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`.
5995

6096
### Example usages
61-
6297
| Action | Command |
6398
| - | - |
6499
| Simply run with default values | `gtc` |
@@ -71,41 +106,54 @@ Use the TemplateCommand.cs file in the Commands folder to construct new cmdlets.
71106
| Command in combination with a couple of data manipulators in the pipe | `gtc "Bye PowerShell" -MyInteger 30 \| ? Attribute2 -Like Line1* \| select Attribute2 \| fl` |
72107

73108
Execute the following steps to implement your own cmdlet:
74-
1. Create a copy of the **TemplateCommand.cs** file.
109+
1. Download Visual Studio Community from https://visualstudio.microsoft.com/downloads/
110+
* In the installer select the **.NET desktop development** component.
111+
* From this component no optional modules are required for developing NoPowerShell modules.
112+
2. Clone this repository and create a copy of the **TemplateCommand.cs** file.
75113
* 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`. Example of a native command: `Get-Command Get-Process` -> Source: `Microsoft.PowerShell.Management` -> Place the .cs file in the **Management** subfolder.
76114
* In case it is a non-native command, place it in the **Additional** folder.
77-
2. Update the `TemplateCommand` classname and its constructor name.
78-
3. 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`
79-
4. Update the static **Synopsis** variable to a small text that describes the command. This will be shown in the help.
80-
5. Update the arguments supported by the command by adding _StringArguments_, _BoolArguments_ and _IntegerArguments_ to the static **SupportedArguments** variable.
81-
6. In the Execute function:
115+
3. Update the `TemplateCommand` classname and its constructor name.
116+
4. 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`
117+
5. Update the static **Synopsis** variable to a small text that describes the command. This will be shown in the help.
118+
6. Update the arguments supported by the command by adding _StringArguments_, _BoolArguments_ and _IntegerArguments_ to the static **SupportedArguments** variable.
119+
7. In the Execute function:
82120
1. Fetch the values of the _StringArguments_, _BoolArguments_ and _IntegerArguments_ as shown in the examples;
83121
2. Based on the parameters provided by the user, perform your actions;
84122
3. Make sure all results are stored in the `_results` variable.
85-
7. Remove all of the template sample code and comments from the file to keep the source tidy.
123+
8. Remove all of the template sample code and comments from the file to keep the source tidy.
86124

87125
# Contributed NoPowerShell cmdlets
88126
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!
89127

90-
| Cmdlet | Contributed by | GitHub | Twitter |
91-
| - | - | - | - |
92-
| Get-ADUser | | | |
93-
| Get-ADGroupMember | | | |
128+
| Cmdlet | Contributed by | GitHub | Twitter | Description |
129+
| - | - | - | - | - |
130+
| Get-ADTrusts | | | | Unofficial command showing equivalent of `nltest /domain_trusts /all_trusts /v` |
131+
| Get-QWinsta | | | | Unofficial command showing equivalent of `qwinsta` / `query session` |
132+
| Invoke-Command | | | | |
133+
| Stop-Process | | | | |
94134

95135
# Included NoPowerShell cmdlets
96136
| Cmdlet | Category | Notes |
97137
| - | - | - |
138+
| Get-ADGroup | ActiveDirectory | |
139+
| Get-ADGroupMember | ActiveDirectory | |
140+
| Get-ADUser | ActiveDirectory | |
98141
| Get-SystemInfo | Additional | Few fields still need to be added to mimick systeminfo.exe |
99142
| Get-Whoami | Additional | whoami.exe /ALL is not implemented yet |
100143
| Get-Command | Core | |
144+
| Get-Help | Core | |
101145
| Where-Object | Core | |
146+
| Resolve-DnsName | DnsClient | Very basic implementation |
147+
| Get-LocalGroup | LocalAccounts | |
148+
| Get-LocalGroupMember | LocalAccounts | |
149+
| Get-LocalUser | LocalAccounts | |
102150
| Copy-Item | Management | |
103-
| Get-Content | Management | |
104-
| Get-Process | Management | Quick & dirty implementation |
105-
| Invoke-WmiMethod | Management | Quick & dirty implementation |
106151
| Get-ChildItem | Management | |
152+
| Get-Content | Management | |
107153
| Get-ItemProperty | Management | |
154+
| Get-Process | Management | Quick & dirty implementation |
108155
| Get-WmiObject | Management | |
156+
| Invoke-WmiMethod | Management | Quick & dirty implementation |
109157
| Remove-Item | Management | |
110158
| Get-NetIPAddress | NetTCPIP | |
111159
| Get-NetRoute | NetTCPIP | |
@@ -114,7 +162,7 @@ Authors of additional NoPowerShell cmdlets are added to the table below. Moreove
114162
| Format-List | Utility | |
115163
| Format-Table | Utility | |
116164
| Invoke-WebRequest | Utility |
165+
| Measure-Object | Utility |
117166
| Select-Object | Utility |
118-
| Resolve-DnsName | DnsClient | Very basic implementation, support for specifying DNS server and query type need to be added |
119167

120168
**Authored by Arris Huijgen (@_bitsadmin - https://github.com/bitsadmin)**
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
using NoPowerShell.Arguments;
2+
using NoPowerShell.HelperClasses;
3+
using System;
4+
using System.Collections.Generic;
5+
6+
/*
7+
Author: @_bitsadmin
8+
Website: https://github.com/bitsadmin
9+
License: BSD 3-Clause
10+
*/
11+
12+
namespace NoPowerShell.Commands
13+
{
14+
public class GetADGroupCommand : PSCommand
15+
{
16+
public GetADGroupCommand(string[] userArguments) : base(userArguments, SupportedArguments)
17+
{
18+
}
19+
20+
public override CommandResult Execute(CommandResult pipeIn)
21+
{
22+
// Obtain cmdlet parameters
23+
string identity = _arguments.Get<StringArgument>("Identity").Value;
24+
string ldapFilter = _arguments.Get<StringArgument>("LDAPFilter").Value;
25+
string filter = _arguments.Get<StringArgument>("Filter").Value;
26+
string properties = _arguments.Get<StringArgument>("Properties").Value;
27+
28+
// Determine filters
29+
bool filledIdentity = !string.IsNullOrEmpty(identity);
30+
bool filledLdapFilter = !string.IsNullOrEmpty(ldapFilter);
31+
bool filledFilter = !string.IsNullOrEmpty(filter);
32+
33+
// Input checks
34+
if (filledIdentity && filledLdapFilter)
35+
throw new InvalidOperationException("Specify either Identity or LDAPFilter, not both");
36+
if (!filledIdentity && !filledLdapFilter && !filledFilter)
37+
throw new InvalidOperationException("Specify either Identity, Filter or LDAPFilter");
38+
39+
// Build filter
40+
string filterBase = "(&(objectCategory=group){0})";
41+
string queryFilter = string.Empty;
42+
43+
// -Identity Administrator
44+
if (filledIdentity)
45+
{
46+
queryFilter = string.Format(filterBase, string.Format("(sAMAccountName={0})", identity));
47+
}
48+
49+
// -LDAPFilter "(adminCount=1)"
50+
else if (filledLdapFilter)
51+
{
52+
queryFilter = string.Format(filterBase, ldapFilter);
53+
}
54+
55+
// -Filter *
56+
else if (filledFilter)
57+
{
58+
// TODO: allow more types of filters
59+
if (filter != "*")
60+
throw new InvalidOperationException("Currently only * filter is supported");
61+
62+
queryFilter = string.Format(filterBase, string.Empty);
63+
}
64+
65+
// Query
66+
_results = LDAPHelper.QueryLDAP(queryFilter, new List<string>(properties.Split(',')));
67+
68+
return _results;
69+
}
70+
71+
public static new CaseInsensitiveList Aliases
72+
{
73+
get { return new CaseInsensitiveList() { "Get-ADGroup" }; }
74+
}
75+
76+
public static new ArgumentList SupportedArguments
77+
{
78+
get
79+
{
80+
return new ArgumentList()
81+
{
82+
new StringArgument("Identity"),
83+
new StringArgument("Filter"),
84+
new StringArgument("LDAPFilter"),
85+
new StringArgument("Properties", "DistinguishedName,Name,ObjectClass,ObjectGUID,SamAccountName,ObjectSID", true)
86+
};
87+
}
88+
}
89+
90+
public static new string Synopsis
91+
{
92+
get { return "Gets one or more Active Directory groups."; }
93+
}
94+
95+
public static new ExampleEntries Examples
96+
{
97+
get
98+
{
99+
return new ExampleEntries()
100+
{
101+
new ExampleEntry("List all user groups in domain", "Get-ADGroup -Filter *"),
102+
new ExampleEntry("List all administrative groups in domain", "Get-ADGroup -LDAPFilter \"(admincount=1)\" | select Name")
103+
};
104+
}
105+
}
106+
}
107+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
using NoPowerShell.Arguments;
2+
using NoPowerShell.HelperClasses;
3+
using System.Collections.Generic;
4+
5+
/*
6+
Author: @_bitsadmin
7+
Website: https://github.com/bitsadmin
8+
License: BSD 3-Clause
9+
*/
10+
11+
namespace NoPowerShell.Commands
12+
{
13+
public class GetADGroupMemberCommand : PSCommand
14+
{
15+
public GetADGroupMemberCommand(string[] userArguments) : base(userArguments, SupportedArguments)
16+
{
17+
}
18+
19+
public override CommandResult Execute(CommandResult pipeIn)
20+
{
21+
// Obtain cmdlet parameters
22+
string identity = _arguments.Get<StringArgument>("Identity").Value;
23+
24+
// Obtain distinguishedname for group
25+
CommandResult dn = LDAPHelper.QueryLDAP(
26+
string.Format("(&(objectCategory=group)(cn={0}))", identity),
27+
new List<string>(1) { "distinguishedName" }
28+
);
29+
string distinguishedName = dn[0]["distinguishedName"];
30+
31+
_results = LDAPHelper.QueryLDAP(
32+
string.Format("(memberOf={0})", distinguishedName),
33+
new List<string>(1) { "distinguishedName", "name", "objectClass", "objectGUID", "SamAccountName", "SID" }
34+
);
35+
36+
return _results;
37+
}
38+
39+
public static new CaseInsensitiveList Aliases
40+
{
41+
get { return new CaseInsensitiveList() { "Get-ADGroupMember" }; }
42+
}
43+
44+
public static new ArgumentList SupportedArguments
45+
{
46+
get
47+
{
48+
return new ArgumentList()
49+
{
50+
new StringArgument("Identity"),
51+
};
52+
}
53+
}
54+
55+
public static new string Synopsis
56+
{
57+
get { return "Gets the members of an Active Directory group."; }
58+
}
59+
60+
public static new ExampleEntries Examples
61+
{
62+
get
63+
{
64+
return new ExampleEntries()
65+
{
66+
new ExampleEntry
67+
(
68+
"List all members of the \"Domain Admins\" group",
69+
new List<string>()
70+
{
71+
"Get-ADGroupMember -Identity \"Domain Admins\"",
72+
"Get-ADGroupMember \"Domain Admins\""
73+
}
74+
)
75+
};
76+
}
77+
}
78+
}
79+
}

0 commit comments

Comments
 (0)