Skip to content

Commit ac84027

Browse files
committed
Initial release
1 parent c8c0fc0 commit ac84027

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+3137
-2
lines changed

NoPowerShell.cna

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# _ _ ____ ____ _ _ _
2+
# | \ | | ___ | _ \ _____ _____ _ __/ ___|| |__ ___| | |
3+
# | \| |/ _ \| |_) / _ \ \ /\ / / _ \ '__\___ \| '_ \ / _ \ | |
4+
# | |\ | (_) | __/ (_) \ V V / __/ | ___) | | | | __/ | |
5+
# |_| \_|\___/|_| \___/ \_/\_/ \___|_| |____/|_| |_|\___|_|_|
6+
#
7+
# @_bitsadmin
8+
# https://github.com/bitsadmin
9+
#
10+
11+
$binary = "scripts/NoPowerShell.exe";
12+
$help = "Execute a command via the reflective NoPowerShell commandline";
13+
beacon_command_register("nps", $help, "Use: nps [command]\n\n$help");
14+
15+
alias nps
16+
{
17+
if(!-exists $binary)
18+
{
19+
berror($1, "NoPowerShell binary cannot be found at $binary");
20+
return;
21+
}
22+
$args = replace($0, "nps ", "");
23+
bexecute_assembly($1, $binary, $args);
24+
}
81.3 KB
Loading

Pictures/SampleCommands.png

25 KB
Loading

README.md

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,89 @@
1-
# nopowershell
2-
PowerShell rebuilt in C# for Red Teaming purposes
1+
# NoPowerShell
2+
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.
3+
4+
Moreover, this project makes it easy for everyone to extend its functionality using only a few lines of C# code.
5+
6+
# Screenshots
7+
## Currently supported commands
8+
Running in Cobalt Strike.
9+
![NoPowerShell supported commands](https://raw.githubusercontent.com/bitsadmin/nopowershell/master/Pictures/CurrentlySupportedCommands.png "NoPowerShell in Cobalt Strike")
10+
## Sample commands
11+
![NoPowerShell sample commands](https://raw.githubusercontent.com/bitsadmin/nopowershell/master/Pictures/SampleCommands.png "NoPowerShell in Cobalt Strike")
12+
13+
14+
# Usage
15+
## Note
16+
When using NoPowerShell from cmd.exe or PowerShell, you need to escape the pipe character (`|`) with respectively a caret (`^`) or a backtick (`` ` ``), i.e.:
17+
18+
- cmd.exe: `ls ^| select Name`
19+
- PowerShell: ```ls `| select Name```
20+
21+
## Examples
22+
| Action | Command | Notes |
23+
| - | - | - |
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` | |
29+
| 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"` | |
35+
36+
# Known issues
37+
- Pipeline characters need to surrounded by spaces
38+
- TLS 1.1+ is not supported by .NET Framework 2, so any site enforcing it will result in a connection error
39+
40+
# Improvements
41+
- Fix above issues
42+
- Improve stability by adding exception handling
43+
- Support for parameter groups
44+
- Add support for ArrayArgument parameter
45+
- Add support for .NET code in commandline, i.e.: `[System.Security.Principal.WindowsIdentity]::GetCurrent().Name`
46+
47+
# Contributing
48+
Add your own cmdlets by submitting a pull request.
49+
## Requirement
50+
- Maintain .NET 2.0 compatibility in order to support the broadest range of operating systems
51+
52+
## Instructions
53+
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`.
54+
55+
### Example usages
56+
57+
| Action | Command |
58+
| - | - |
59+
| Simply run with default values | `gtc` |
60+
| Run with the -MyFlag parameter which executes the 'else' statement | `gtc -MyFlag` |
61+
| 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` |
62+
| 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"` |
63+
| Combination of parameters | `gtc -MyInteger 10 -MyString "Bye PowerShell"` |
64+
| Combination of parameters - Alternative | `gtc -MyInteger 10 -MyString "Bye PowerShell"` |
65+
| Combination of parameters - Using fact that MyString is the only mandatory parameter for this command | `gtc -MyInteger 10 "Bye PowerShell"` |
66+
| Command in combination with a couple of data manipulators in the pipe | `gtc "Bye PowerShell" -MyInteger 30 \| ? Attribute2 -Like Line1* \| select Attribute2 \| fl` |
67+
68+
Execute the following steps to implement your own cmdlet:
69+
1. Create a copy of the **TemplateCommand.cs** file.
70+
* 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.
71+
* In case it is a non-native command, place it in the **Additional** folder.
72+
2. Update the `TemplateCommand` classname and its constructor name.
73+
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`
74+
4. Update the static **Synopsis** variable to a small text that describes the command. This will be shown in the help.
75+
5. Update the arguments supported by the command by adding _StringArguments_, _BoolArguments_ and _IntegerArguments_ to the static **SupportedArguments** variable.
76+
6. In the Execute function:
77+
1. Fetch the values of the _StringArguments_, _BoolArguments_ and _IntegerArguments_ as shown in the examples;
78+
2. Based on the parameters provided by the user, perform your actions;
79+
3. Make sure all results are stored in the `_results` variable.
80+
7. Remove all of the template sample code and comments from the file to keep the source tidy.
81+
82+
# Contributed NoPowerShell cmdlets
83+
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!
84+
85+
| Cmdlet | Contributed by | GitHub | Twitter |
86+
| - | - | - | - |
87+
| Resolve-DnsName | | | |
88+
| Get-ADUser | | | |
89+
| Get-ADGroupMember | | | |

Source/NoPowerShell/NoPowerShell.sln

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 15
4+
VisualStudioVersion = 15.0.26228.4
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NoPowerShell", "NoPowerShell\NoPowerShell.csproj", "{555AD0AC-1FDB-4016-8257-170A74CB2F55}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Release|Any CPU = Release|Any CPU
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{555AD0AC-1FDB-4016-8257-170A74CB2F55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15+
{555AD0AC-1FDB-4016-8257-170A74CB2F55}.Debug|Any CPU.Build.0 = Debug|Any CPU
16+
{555AD0AC-1FDB-4016-8257-170A74CB2F55}.Release|Any CPU.ActiveCfg = Release|Any CPU
17+
{555AD0AC-1FDB-4016-8257-170A74CB2F55}.Release|Any CPU.Build.0 = Release|Any CPU
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
EndGlobal
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<configuration>
3+
<startup>
4+
5+
<supportedRuntime version="v2.0.50727"/></startup>
6+
</configuration>
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using System;
2+
3+
/*
4+
Author: @_bitsadmin
5+
Website: https://github.com/bitsadmin
6+
License: BSD 3-Clause
7+
*/
8+
9+
namespace NoPowerShell.Arguments
10+
{
11+
/// <summary>
12+
/// Base class for BoolArgument and StringArgument
13+
/// </summary>
14+
public class Argument : IEquatable<Argument>
15+
{
16+
/// <summary>
17+
/// Name of the argument, for example "-Path"
18+
/// </summary>
19+
protected string _name;
20+
protected bool _isOptionalArgument;
21+
protected bool _dashArgumentNameSkipUsed;
22+
23+
public Argument(string name)
24+
{
25+
this._name = name;
26+
_dashArgumentNameSkipUsed = false;
27+
}
28+
29+
public bool Equals(Argument other)
30+
{
31+
return other.Name.Equals(_name.Substring(0, other.Name.Length), StringComparison.InvariantCultureIgnoreCase);
32+
}
33+
34+
public string Name
35+
{
36+
get { return _name; }
37+
}
38+
39+
public bool IsOptionalArgument
40+
{
41+
get { return this._isOptionalArgument; }
42+
}
43+
44+
/// <summary>
45+
/// Optional StringArgument which requires a value
46+
/// </summary>
47+
public bool DashArgumentNameSkipUsed
48+
{
49+
get { return _dashArgumentNameSkipUsed; }
50+
set { _dashArgumentNameSkipUsed = value; }
51+
}
52+
}
53+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
/*
5+
Author: @_bitsadmin
6+
Website: https://github.com/bitsadmin
7+
License: BSD 3-Clause
8+
*/
9+
10+
namespace NoPowerShell.Arguments
11+
{
12+
public class ArgumentList : List<Argument>
13+
{
14+
public T Get<T>(string argumentName) where T : Argument
15+
{
16+
foreach (Argument arg in this)
17+
{
18+
// Skip irrelevant arguments
19+
if (arg.GetType() != typeof(T))
20+
continue;
21+
22+
// Check for matching argumentName
23+
T foundArg = arg as T;
24+
if (foundArg.Name.Equals(argumentName, StringComparison.InvariantCultureIgnoreCase))
25+
return foundArg;
26+
}
27+
28+
return null;
29+
}
30+
}
31+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
Author: @_bitsadmin
3+
Website: https://github.com/bitsadmin
4+
License: BSD 3-Clause
5+
*/
6+
7+
namespace NoPowerShell.Arguments
8+
{
9+
public class BoolArgument : Argument
10+
{
11+
private bool _value;
12+
13+
/// <summary>
14+
/// Create a new boolean argument including its default value. Bool arguments are always optional.
15+
/// </summary>
16+
/// <param name="argumentName">Name of the parameter</param>
17+
/// <param name="defaultValue">Default value of the argument</param>
18+
public BoolArgument(string argumentName, bool defaultValue) : base(argumentName)
19+
{
20+
this._value = defaultValue;
21+
this._isOptionalArgument = true;
22+
}
23+
24+
/// <summary>
25+
/// Create new boolean argument with false as its default value. Bool arguments are always optional.
26+
/// </summary>
27+
/// <param name="argumentName">Name of the parameter</param>
28+
public BoolArgument(string argumentName) : this(argumentName, false)
29+
{
30+
}
31+
32+
public bool Value
33+
{
34+
get { return this._value; }
35+
set { this._value = value; }
36+
}
37+
38+
public override string ToString()
39+
{
40+
return string.Format("{0}: {1}", _name, _value);
41+
}
42+
}
43+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
Author: @_bitsadmin
3+
Website: https://github.com/bitsadmin
4+
License: BSD 3-Clause
5+
*/
6+
7+
namespace NoPowerShell.Arguments
8+
{
9+
public class IntegerArgument : Argument
10+
{
11+
private int _value;
12+
private int _defaultValue;
13+
14+
/// <summary>
15+
/// Create a new integer argument including its default value.
16+
/// </summary>
17+
/// <param name="argumentName">Name of the parameter</param>
18+
/// <param name="defaultValue">Default value of the argument</param>
19+
public IntegerArgument(string argumentName, int defaultValue) : base(argumentName)
20+
{
21+
this._value = defaultValue;
22+
this._defaultValue = defaultValue;
23+
this._isOptionalArgument = false;
24+
}
25+
26+
/// <summary>
27+
/// Create a new integer argument including its default value specifying whether it is optional or not.
28+
/// </summary>
29+
/// <param name="argumentName">Name of the parameter</param>
30+
/// <param name="defaultValue">Default value of the argument</param>
31+
/// <param name="optionalArgument">True if the argument is optional; False if not</param>
32+
public IntegerArgument(string argumentName, int defaultValue, bool optionalArgument) : this(argumentName, defaultValue)
33+
{
34+
this._isOptionalArgument = optionalArgument;
35+
}
36+
37+
/// <summary>
38+
/// Create a new integer argument with a null default value.
39+
/// </summary>
40+
/// <param name="argumentName">Name of the parameter</param>
41+
public IntegerArgument(string argumentName) : this(argumentName, 0)
42+
{
43+
}
44+
45+
public int Value
46+
{
47+
get { return _value; }
48+
set { _value = value; }
49+
}
50+
51+
public bool IsDefaultValue
52+
{
53+
get { return _value == _defaultValue; }
54+
}
55+
56+
public override string ToString()
57+
{
58+
return string.Format("{0} \"{1}\"", _name, _value);
59+
}
60+
}
61+
}

0 commit comments

Comments
 (0)