mirror of
https://github.com/maxDcb/C2Core
synced 2026-06-08 15:48:01 +00:00
doc
This commit is contained in:
@@ -24,3 +24,5 @@ This repository is intended to be consumed from a parent repository as a shared
|
||||
|
||||
- The parent project owns the compiler toolchain and top-level CMake configuration.
|
||||
- Module tests are enabled by the parent through `C2CORE_BUILD_TESTS`.
|
||||
- Functional, env-driven module tests are enabled through `C2CORE_BUILD_FUNCTIONAL_TESTS`.
|
||||
- Test strategy, flags, and ready-to-run commands are documented in [TESTING.md](/mnt/e/Dev/C2Implant/core/TESTING.md).
|
||||
|
||||
+361
@@ -0,0 +1,361 @@
|
||||
# C2Core Testing
|
||||
|
||||
## Scope
|
||||
|
||||
`C2Core` is shared by multiple parent projects across Windows and Linux. The test strategy separates:
|
||||
|
||||
- unit and local integration tests that must be CI-safe and autonomous
|
||||
- functional tests that exercise environment-dependent features without polluting standard CI
|
||||
|
||||
This file documents the current test logic, the relevant CMake flags, and the commands used in practice on Windows x64 and x86.
|
||||
|
||||
## CMake Flags
|
||||
|
||||
- `BUILD_TEAMSERVER`
|
||||
Enables teamserver-side parsing/help paths inside modules. This is for production builds that need CLI parsing and help text on the server side.
|
||||
|
||||
- `C2CORE_BUILD_TESTS`
|
||||
Enables the standard C2Core test targets used by CI. These tests must stay local, deterministic, and not depend on lab infrastructure.
|
||||
|
||||
- `C2CORE_BUILD_FUNCTIONAL_TESTS`
|
||||
Enables manual or env-driven functional tests. These tests are intended for operator-driven validation of modules that need credentials, network reachability, remote hosts, Kerberos tickets, or specific Windows services.
|
||||
|
||||
`enable_testing()` is active when either `C2CORE_BUILD_TESTS` or `C2CORE_BUILD_FUNCTIONAL_TESTS` is enabled.
|
||||
|
||||
## Test Categories
|
||||
|
||||
### Standard tests
|
||||
|
||||
These are the `tests<Module>` targets.
|
||||
|
||||
- compiled with `C2CORE_BUILD_TESTS=ON`
|
||||
- expected to run in CI
|
||||
- should complete quickly
|
||||
- should not require manual input
|
||||
- should not require external infrastructure
|
||||
|
||||
For modules that are hard to execute for real in CI, the unit tests should still validate:
|
||||
|
||||
- command-line parsing
|
||||
- packing and unpacking of `C2Message`
|
||||
- error mapping through `errorCodeToMsg()`
|
||||
- local guard rails before any network or remote execution is attempted
|
||||
|
||||
### Functional tests
|
||||
|
||||
These are the `tests<Module>Functional` targets.
|
||||
|
||||
- compiled with `C2CORE_BUILD_FUNCTIONAL_TESTS=ON`
|
||||
- intended for manual runs, lab validation, or env-driven automation
|
||||
- should skip cleanly when configuration is missing
|
||||
- should not run remote actions unless `--execute` is provided
|
||||
|
||||
Current functional tests are registered with `SKIP_RETURN_CODE 77`, so an unconfigured lab does not make CTest fail.
|
||||
|
||||
## Functional Test Helper Contract
|
||||
|
||||
`core/modules/tests/FunctionalTestHelpers.hpp` provides the shared behavior.
|
||||
|
||||
- `--help`
|
||||
Prints accepted options and environment variables.
|
||||
|
||||
- `--interactive`
|
||||
Prompts for missing values on stdin.
|
||||
|
||||
- `--execute`
|
||||
Actually calls the module `process()` path.
|
||||
|
||||
Without `--execute`, a functional test validates only:
|
||||
|
||||
- input collection
|
||||
- command construction
|
||||
- `init()`
|
||||
- `C2Message` packing
|
||||
|
||||
With `--execute`, the helper treats the run as failed only when `result.errorCode() > 0`.
|
||||
|
||||
This is important because many modules keep the default `errorCode == -1` on success.
|
||||
|
||||
## Current Functional Test Modules
|
||||
|
||||
Current module-level functional tests:
|
||||
|
||||
- `testsCimExecFunctional`
|
||||
- `testsDcomExecFunctional`
|
||||
- `testsEnumerateRdpSessionsFunctional`
|
||||
- `testsSpawnAsFunctional`
|
||||
- `testsSshExecFunctional`
|
||||
- `testsTaskSchedulerFunctional`
|
||||
- `testsWinRMFunctional`
|
||||
- `testsWmiExecFunctional`
|
||||
|
||||
Current transport-level functional tests:
|
||||
|
||||
- listener functional tests
|
||||
- beacon functional tests
|
||||
|
||||
Use `ctest -L functional` to discover them from a configured build tree.
|
||||
|
||||
## Windows Build Commands
|
||||
|
||||
### Configure x64 functional build
|
||||
|
||||
From PowerShell:
|
||||
|
||||
```powershell
|
||||
& 'C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe' `
|
||||
-S 'E:\Dev\C2Implant' `
|
||||
-B 'E:\Dev\C2Implant\buildx64-functional' `
|
||||
-G 'Visual Studio 17 2022' `
|
||||
-A x64 `
|
||||
-DC2CORE_BUILD_TESTS=ON `
|
||||
-DC2CORE_BUILD_FUNCTIONAL_TESTS=ON `
|
||||
-DLibssh2_DIR='E:/Dev/C2Implant/buildx64/conan/build/generators' `
|
||||
-Dnlohmann_json_DIR='E:/Dev/C2Implant/buildx64/conan/build/generators'
|
||||
```
|
||||
|
||||
### Configure x86 functional build
|
||||
|
||||
```powershell
|
||||
& 'C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe' `
|
||||
-S 'E:\Dev\C2Implant' `
|
||||
-B 'E:\Dev\C2Implant\buildx86-functional' `
|
||||
-G 'Visual Studio 17 2022' `
|
||||
-A Win32 `
|
||||
-DC2CORE_BUILD_TESTS=ON `
|
||||
-DC2CORE_BUILD_FUNCTIONAL_TESTS=ON `
|
||||
-DLibssh2_DIR='E:/Dev/C2Implant/buildx86/conan/build/generators' `
|
||||
-Dnlohmann_json_DIR='E:/Dev/C2Implant/buildx86/conan/build/generators'
|
||||
```
|
||||
|
||||
### Build selected test targets
|
||||
|
||||
```powershell
|
||||
& 'C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe' `
|
||||
--build 'E:\Dev\C2Implant\buildx64-functional' `
|
||||
--config Release `
|
||||
--target testsSpawnAs testsSshExec testsWmiExec testsSpawnAsFunctional testsSshExecFunctional testsWmiExecFunctional
|
||||
```
|
||||
|
||||
```powershell
|
||||
& 'C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe' `
|
||||
--build 'E:\Dev\C2Implant\buildx86-functional' `
|
||||
--config Release `
|
||||
--target testsSpawnAs testsSshExec testsWmiExec testsSpawnAsFunctional testsSshExecFunctional testsWmiExecFunctional
|
||||
```
|
||||
|
||||
## Standard CTest Commands
|
||||
|
||||
### Run one unit test
|
||||
|
||||
```powershell
|
||||
Set-Location 'E:\Dev\C2Implant\buildx64'
|
||||
& 'C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\ctest.exe' `
|
||||
-C Release `
|
||||
-R testsSshExec `
|
||||
--timeout 10 `
|
||||
--output-on-failure
|
||||
```
|
||||
|
||||
### Run a small group of unit tests
|
||||
|
||||
```powershell
|
||||
Set-Location 'E:\Dev\C2Implant\buildx64'
|
||||
& 'C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\ctest.exe' `
|
||||
-C Release `
|
||||
-R 'tests(SpawnAs|SshExec|WmiExec)' `
|
||||
--timeout 10 `
|
||||
--output-on-failure
|
||||
```
|
||||
|
||||
### Run all functional tests
|
||||
|
||||
```powershell
|
||||
Set-Location 'E:\Dev\C2Implant\buildx64-functional'
|
||||
& 'C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\ctest.exe' `
|
||||
-C Release `
|
||||
-L functional `
|
||||
--timeout 10 `
|
||||
--output-on-failure
|
||||
```
|
||||
|
||||
### Run only functional tests for remote execution modules
|
||||
|
||||
```powershell
|
||||
Set-Location 'E:\Dev\C2Implant\buildx64-functional'
|
||||
& 'C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\ctest.exe' `
|
||||
-C Release `
|
||||
-R 'tests(SpawnAs|SshExec|WmiExec)Functional' `
|
||||
--timeout 10 `
|
||||
--output-on-failure
|
||||
```
|
||||
|
||||
If no environment is configured, these tests should be reported as skipped rather than failed.
|
||||
|
||||
## Direct Functional Test Invocation
|
||||
|
||||
The binaries are copied under `${build}/tests`.
|
||||
|
||||
Examples on x64:
|
||||
|
||||
```powershell
|
||||
E:\Dev\C2Implant\buildx64-functional\tests\testsSshExecFunctional.exe --help
|
||||
E:\Dev\C2Implant\buildx64-functional\tests\testsWmiExecFunctional.exe --help
|
||||
E:\Dev\C2Implant\buildx64-functional\tests\testsSpawnAsFunctional.exe --help
|
||||
```
|
||||
|
||||
### Dry-run packing validation
|
||||
|
||||
This validates parsing and `init()` only:
|
||||
|
||||
```powershell
|
||||
E:\Dev\C2Implant\buildx64-functional\tests\testsSshExecFunctional.exe `
|
||||
--host 10.10.10.20 `
|
||||
--port 22 `
|
||||
--user alice `
|
||||
--password secret `
|
||||
--command "whoami"
|
||||
```
|
||||
|
||||
### Interactive mode
|
||||
|
||||
```powershell
|
||||
E:\Dev\C2Implant\buildx64-functional\tests\testsWmiExecFunctional.exe --interactive
|
||||
```
|
||||
|
||||
### Real execution
|
||||
|
||||
Only this form runs the remote or privileged action:
|
||||
|
||||
```powershell
|
||||
E:\Dev\C2Implant\buildx64-functional\tests\testsSshExecFunctional.exe `
|
||||
--execute `
|
||||
--host 10.10.10.20 `
|
||||
--user alice `
|
||||
--password secret `
|
||||
--command "whoami"
|
||||
```
|
||||
|
||||
## Environment Variables For Functional Tests
|
||||
|
||||
### SpawnAs
|
||||
|
||||
- `C2_FUNC_SPAWNAS_USER`
|
||||
- `C2_FUNC_SPAWNAS_PASSWORD`
|
||||
- `C2_FUNC_SPAWNAS_COMMAND`
|
||||
- `C2_FUNC_SPAWNAS_DOMAIN`
|
||||
- `C2_FUNC_SPAWNAS_LOGON_TYPE`
|
||||
- `C2_FUNC_SPAWNAS_PROFILE`
|
||||
- `C2_FUNC_SPAWNAS_SHOW_WINDOW`
|
||||
|
||||
Example:
|
||||
|
||||
```powershell
|
||||
$env:C2_FUNC_SPAWNAS_USER='DOMAIN\alice'
|
||||
$env:C2_FUNC_SPAWNAS_PASSWORD='secret'
|
||||
$env:C2_FUNC_SPAWNAS_COMMAND='cmd.exe /c whoami'
|
||||
E:\Dev\C2Implant\buildx64-functional\tests\testsSpawnAsFunctional.exe --execute
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- logon type `2` is the default interactive mode
|
||||
- logon type `9` maps to `--netonly`
|
||||
- `with-profile` and `no-profile` control profile loading
|
||||
- this test is Windows-only for real execution
|
||||
|
||||
### SshExec
|
||||
|
||||
- `C2_FUNC_SSH_HOST`
|
||||
- `C2_FUNC_SSH_PORT`
|
||||
- `C2_FUNC_SSH_USER`
|
||||
- `C2_FUNC_SSH_PASSWORD`
|
||||
- `C2_FUNC_SSH_COMMAND`
|
||||
|
||||
Example:
|
||||
|
||||
```powershell
|
||||
$env:C2_FUNC_SSH_HOST='10.10.10.20'
|
||||
$env:C2_FUNC_SSH_PORT='22'
|
||||
$env:C2_FUNC_SSH_USER='alice'
|
||||
$env:C2_FUNC_SSH_PASSWORD='secret'
|
||||
$env:C2_FUNC_SSH_COMMAND='whoami'
|
||||
E:\Dev\C2Implant\buildx64-functional\tests\testsSshExecFunctional.exe --execute
|
||||
```
|
||||
|
||||
### WmiExec
|
||||
|
||||
- `C2_FUNC_WMI_AUTH`
|
||||
- `C2_FUNC_WMI_TARGET`
|
||||
- `C2_FUNC_WMI_COMMAND`
|
||||
- `C2_FUNC_WMI_USER`
|
||||
- `C2_FUNC_WMI_PASSWORD`
|
||||
- `C2_FUNC_WMI_DC`
|
||||
|
||||
Example NTLM or user/password flow:
|
||||
|
||||
```powershell
|
||||
$env:C2_FUNC_WMI_AUTH='userpass'
|
||||
$env:C2_FUNC_WMI_TARGET='server01'
|
||||
$env:C2_FUNC_WMI_COMMAND='cmd.exe /c whoami'
|
||||
$env:C2_FUNC_WMI_USER='DOMAIN\alice'
|
||||
$env:C2_FUNC_WMI_PASSWORD='secret'
|
||||
E:\Dev\C2Implant\buildx64-functional\tests\testsWmiExecFunctional.exe --execute
|
||||
```
|
||||
|
||||
Example Kerberos flow:
|
||||
|
||||
```powershell
|
||||
$env:C2_FUNC_WMI_AUTH='kerberos'
|
||||
$env:C2_FUNC_WMI_TARGET='server01'
|
||||
$env:C2_FUNC_WMI_COMMAND='cmd.exe /c hostname'
|
||||
$env:C2_FUNC_WMI_DC='DOMAIN\dc01'
|
||||
E:\Dev\C2Implant\buildx64-functional\tests\testsWmiExecFunctional.exe --execute
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- `no-cred` maps to `wmiExec -n`
|
||||
- `userpass` maps to `wmiExec -u`
|
||||
- `kerberos` maps to `wmiExec -k`
|
||||
- this test is Windows-only for real execution
|
||||
|
||||
## Module-Specific Intent
|
||||
|
||||
### SpawnAs
|
||||
|
||||
The unit test should stay focused on parsing and packing. The functional test is where real credentialed process creation is exercised because it depends on:
|
||||
|
||||
- local Windows privileges
|
||||
- local or domain credentials
|
||||
- profile loading behavior
|
||||
- logon type selection
|
||||
|
||||
### SshExec
|
||||
|
||||
The unit test should validate local parameter handling and local failure paths. The functional test is the place for real SSH coverage because it depends on:
|
||||
|
||||
- reachable host
|
||||
- valid credentials
|
||||
- server-side shell behavior
|
||||
|
||||
### WmiExec
|
||||
|
||||
The unit test should validate packing and error mapping. The functional test is required for meaningful execution coverage because it depends on:
|
||||
|
||||
- COM and WMI availability
|
||||
- remote host state
|
||||
- firewall and service exposure
|
||||
- credential mode or Kerberos ticket state
|
||||
|
||||
## CI Guidance
|
||||
|
||||
Standard CI should keep using `C2CORE_BUILD_TESTS=ON` only.
|
||||
|
||||
`C2CORE_BUILD_FUNCTIONAL_TESTS=ON` is appropriate for:
|
||||
|
||||
- operator-driven validation
|
||||
- dedicated lab jobs
|
||||
- manual pre-release verification
|
||||
|
||||
Do not make the default CI pipeline depend on environment-specific functional tests.
|
||||
Reference in New Issue
Block a user