-
Notifications
You must be signed in to change notification settings - Fork 256
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #119 from calebstewart/feature-reflective-dotnet
- Updated documentation for Plugin API - Updated README with notes on Windows support - Added plugin API to Windows C2 - Added GitHub Action to package Windows plugins and attach to releases automatically. - Added early support for BadPotato supported by [pwncat-badpotato](https://github.com/calebstewart/pwncat-badpotato) plugin (step toward #106)
- Loading branch information
Showing
17 changed files
with
582 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# Automatically pull down the required versions of windows plugins | ||
# and bundle them up for releases. This makes staging on non-internet | ||
# connected systems easier. | ||
name: publish | ||
on: | ||
push: | ||
tags: | ||
- 'v*.*.*' | ||
|
||
jobs: | ||
release: | ||
name: Release | ||
runs-on: ubuntu-latest | ||
if: startsWith(github.ref, 'refs/tags/') | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v2 | ||
- name: Setup Python 3.9 | ||
uses: actions/setup-python@v2 | ||
with: | ||
python-version: "3.9" | ||
- name: Install pwncat Module | ||
run: "python setup.py install" | ||
- name: Download and Archive Plugins | ||
run: | | ||
# Have pwncat download all plugins needed | ||
pwncat --download-plugins | ||
# They are stored in ~/.local/share/pwncat by default | ||
tar czvf pwncat-plugins.tar.gz --transform='s|.*pwncat/||' ~/.local/share/pwncat/* | ||
- name: Publish Plugins | ||
uses: softprops/action-gh-release@v1 | ||
with: | ||
files: "pwncat-plugins.tar.gz" | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
Windows Support | ||
=============== | ||
|
||
Starting with ``v0.4.0a1``, pwncat supports multiple platform targets. Specifically, | ||
we have implemented Windows support. Windows support is complicated, as a majority | ||
of interaction cannot be simply executed from a shell, and parsed. As a result, we | ||
implemented a very minimal C2 framework, and had pwncat automatically upload and | ||
execute this framework for you. **You only need to provide pwncat a cmd or | ||
powershell prompt**. | ||
|
||
Goals | ||
----- | ||
|
||
When building out Windows support, there were a lot of options. We had to filter out | ||
these options based on the goals for the C2. We whittled these goals down to the | ||
following: | ||
|
||
- Automatically Bypass AMSI | ||
- Automatically Bypass AppLocker | ||
- Undetected by Defender | ||
- Automatically Bypass PowerShell Constrained Language Mode | ||
- Provide the user with an interactive shell | ||
- Support structured interaction for automation | ||
- Touch disk as little as possible | ||
|
||
This was a tall order, and doing so generically was difficult. I'll talk about our | ||
solution to each of those problems. Firstly, AMSI was easy. Once everything was set | ||
in place, we could use the standard .Net reflection to bypass AMSI relatively easily. | ||
|
||
This brought up another issue: Constrained Language Mode. In PowerShell, if constrained | ||
language mode is active, we effectively have no access to .Net. This presents serious | ||
problems. The only way we could find to bypass Constrained Language Mode without | ||
depending on PowerShell v2 was to execute .Net code. From within .Net, we can reflectively | ||
modify the PowerShell implementation, and spawn an interactive session in Full Language | ||
Mode regardless of environment or Group Policy settings. | ||
|
||
With the need to execute .Net without reflective loading from PowerShell (due to CLM), | ||
we now break one of our rules. We have to upload a file to disk to execute, and with | ||
that we run into both Defender and AppLocker. For AppLocker, there is a list of safe | ||
directories where we can place a binary, and load it with the .Net ``InstallUtil`` | ||
tool. This provides a way around AppLocker. Further, we implemented a small stager | ||
which simply waits and downloads more .Net code to be reflectively loaded. This | ||
mitigates the files on disk by making the only on-disk file a simple stager with low | ||
equity. It also makes the file on disk less likely to trigger Defender. | ||
|
||
At this point, we can load stage two which implements the required structured | ||
interaction and interactive shell as needed, and have met all goals listed above | ||
with a slight compromise on files touching disk. To make things as smooth as possible, | ||
pwncat will automatically remove the stageone DLL when exiting. | ||
|
||
Communication Protocol | ||
---------------------- | ||
|
||
After initializing stage two, pwncat communicates over Base64-encoded GZip blobs. | ||
Each command sent is a JSON-encoded argument array specifying the type name, | ||
method name, and subsequent arguments for a static method within stage two. The | ||
JSON data is deserialized so you can pass any serializable type to a method natively | ||
from pwncat. | ||
|
||
Responses are formatted in the same way as requests, except are returned as a dictionary. | ||
The dictionary looks like this: | ||
|
||
.. code-block:: json | ||
{ | ||
"error": 0, | ||
"result": {}, | ||
"message": "" | ||
} | ||
If a method fails, the error property will be non-zero, and the ``message`` property | ||
will be present containing a description of the failure. If the method succeeds, the | ||
``result`` property will contain the return value of the method. This value could be | ||
any JSON serializable type (the example above shows an empty dictionary but it could | ||
just as easily be a bare integer). | ||
|
||
The Windows platform provides a helper method to call methods which seamlessly translates | ||
Python calls to method calls. The return value is the ``result`` property, and a | ||
:class:`pwncat.platform.windows.Windows.ProtocolError` will be raised if there was an error. | ||
|
||
.. code-block:: python | ||
result = session.platform.run_method("PowerShell", "run", "[PSCustomObject]@{ thing = 5; }", 1) | ||
# Prints "5" | ||
print(result[0]["thing"]) | ||
There are also other abstractions within the framework for common operations like executing | ||
PowerShell. For more information on the API of the Windows platform, please see the | ||
API Documentation. | ||
|
||
Plugin API | ||
---------- | ||
|
||
You can utilize the pwncat API to load third-party .Net assemblies from the attacker machine | ||
and easily execute their methods. The stage two C2 provides the ability to load an assembly | ||
and retrieve a unique identifier for the loaded assembly. You can then use this identifier | ||
to execute methods from the assembly in a similar way to the ``run_method`` method above. | ||
|
||
The plugins themselves must implement a specific API in order to be compatible. A basic | ||
plugin looks like this: | ||
|
||
.. code-block:: csharp | ||
using System.Reflection; | ||
class Plugin | ||
{ | ||
public static void entry(Assembly stagetwo) | ||
{ | ||
// Optional method; executing while loading the plugin | ||
} | ||
public static string test(string arg1, int arg2) | ||
{ | ||
// A method that can be called from the C2 | ||
return "Hello " + arg1 + " " + arg2.ToString(); | ||
} | ||
} | ||
If you had compiled this plugin to a dll named ``example.dll``, you could load and execute it | ||
with the following from pwncat: | ||
|
||
.. code-block:: python | ||
example = session.platform.dotnet_load("example.dll") | ||
# this prints "Hello Plugin 42" | ||
print(example.test("Plugin", 42)) | ||
The Windows platform will deduplicate plugins by name and by file hash to ensure individual | ||
assemblies are only loaded once. If a given assembly has already been loaded, the existing | ||
:class:`pwncat.platform.windows.Windows.DotNetPlugin` instance will be returned instead of | ||
reloading the existing assembly. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.