Feat/extender support - #12
Merged
Merged
Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ofiles Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Dockerfile: install git so clone_repo() doesn't FileNotFoundError
- docker-compose.yml, docker-compose.kvm.yml: add container_name:adaptixc2
so bare docker exec/restart commands resolve correctly
- test.yaml: wait for adaptixc2:4321 before running integration tests;
always print adaptixc2 logs for debugging
- runner.py: retry adaptixc2 connection for up to 60s instead of failing
immediately on ConnectionError
- cli/main.go: post-restart wait now checks adaptixc2's port (ss -tln)
rather than the always-up testing-kit health endpoint
- extender_parser.py: add _widget() factory with all known no-op methods
so axs scripts that call addWidget/setLayout/setPanel etc. don't throw;
add missing form.create_{check,label,selector_file,gridlayout,hlayout,panel}
and ax.interfaces(); add _es5_compat() to rewrite let/const→var and
for...of→.forEach before passing to Duktape (ES5 only)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- profile.yaml: add full Teamserver config (port, certs, built-in extenders, HttpServer) so adaptixc2 no longer crashes on restart
- docker-compose: mount user extenders to /app/userextenders to avoid shadowing built-in extenders at /app/extenders
- profile_manager: switch os.replace to shutil.move to handle cross-device rename (EXDEV on bind mount), update default path to /app/userextenders
- api.py: fix _extender_name_from_url to use removesuffix(".git") instead of rstrip(".git") which was stripping individual chars and truncating "Extension-Kit" to "extension-k"
- extender_parser: add bool-default-False to classify_field so ssl/checkbox fields without defaults become auto=False instead of required; add missing mock JS stubs for Kharon agent axs (add_session_agent, add_session_browser, on_filebrowser_list, etc.)
- runner.py: guard _resolve_agent_from_extender with agent_schema null check (Kharon has no GenerateUI); add string→bool/int coercion in _resolve_schema_value for CLI --override values
- test.yaml: move all --flag args before the URL (Go flag.FlagSet stops at first non-flag); add all required Kharon listener overrides (port_bind, block_user_agents, domain_rotation_strategy, proxy_*, ssl_cert, ssl_key, uploaded_file)
- install scripts: update extender paths from /app/extenders/* to /app/userextenders/*
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- install-kharon.sh: use listener_kharon_http/Makefile and agent_kharon/Makefile instead of trying go build . in the wrong directory (no Go files at listener_kharon_http root, they live in src_server/); install make if not present - test.yaml: add --no-restart for Extension-Kit add-extender because loading 11+ BOF axscripts causes adaptixc2 startup to exceed the 60s health-check timeout; the CI tasks (shell whoami etc.) don't require axscripts to be loaded Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
adaptixc2 restart health check was 60s — loading Kharon Go plugins takes longer; raised to 300s (150×2s). Both extender CI jobs now wait up to 50 minutes for Windows SSH before running tests, matching the Windows 11 QEMU boot time; timeout-minutes raised to 90 to accommodate. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Go plugin ABI requires exact package version match. The Kharon go.mod pinned axc2 v1.1.3 but the running adaptixc2 binary uses v1.2.0, causing plugin.Open to fail at startup. The install script now reads the axc2 version from the adaptixc2 binary via `go version -m` and runs `go get` to align the dependency before building. Also adds adaptixc2 log capture on failure for the Kharon test job. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The go version -m detection hit a pipefail edge case (binary is named adaptixserver not adaptixc2) that exited the install script immediately. Hardcode v1.2.0 which we confirmed from AdaptixC2's go.mod. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- install-kharon.sh: full build pipeline (GOEXPERIMENT detection, pl_agent.go patch for mask_sleep=none, go.work, src_beacon prebuild, src_core BOFs, win32.h stubs, symlinks, cstdint shim) - kharon-tasks.yaml: use real Kharon commands (token getuid, process create, fs ls) instead of generic shell commands - kharon-malleable-profile.json: malleable HTTP profile for listener - test.yaml: add --override agent.mask_sleep=none to ensure no sleep obfuscation - extender_parser.py: fix combo widget mock to track addItem/setCurrentIndex so defaults (Format=Exe, mask_sleep=none) are auto-detected from ax_config.axs; add mask_sleep to _SPECIAL registry as CI-safe override - cli/main.go: use bash TCP probe instead of ss for adaptixc2 readiness check - config/config.yaml: fix SFTP agent_path to POSIX form for OpenSSH on Windows - run-kharon-test.sh: local helper script mirroring the CI test-kharon job Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add guardrails_user, guardrails_domain, killdate_date, workingtime_start,
workingtime_end to the _SPECIAL registry with empty-string values so the
extender parser marks them as source:auto instead of source:required.
These are optional evasive features: empty string disables them in Kharon.
Also add matching --override flags in the test-kharon CI step so they are
explicitly cleared even if the schema detection changes.
Without this, add-extender exits 1 ("missing required fields") and the CI
job never reaches the Windows test run.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…aron.sh python3 is not present in the adaptixc2 base image; add it to the initial apt-get install block alongside make so the pl_agent.go and win32.h patch steps don't fail with 'command not found'. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…d 1.25 The Kharon module's go.mod requires go >= 1.25.4, but the go.work header was hardcoded to 'go 1.25', causing 'go build -buildmode=plugin' to fail with 'module requires go >= 1.25.4, but go.work lists go 1.25'. Extract the version from the adaptixserver binary (e.g. go1.25.4) and strip the 'go' prefix for the go.work directive so they always match. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…mismatch The listener .so was being built without the combined go.work, causing adaptixserver to reject it with: plugin was built with a different version of package axc2 Move AdaptixC2 clone and go.work creation before both plugin builds so that both listener_kharon_http and agent_kharon use identical package resolution. Add GOWORK to the listener make call just as it was already used for the agent. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…work - Print full go version -m /app/adaptixserver so CI logs reveal the exact axc2 version and any replace directives in the server binary - Extract axc2 version from binary (BINARY_AXC2) and use it as AXC2_VERSION instead of hardcoding v1.2.0 - Strip AdaptixC2 modules from go.work — including them caused MVS to bump axc2 to the AdaptixC2 HEAD version, which mismatches the docker image (built from an older commit); now go.work contains only the Kharon listener + agent modules so axc2 resolves to BINARY_AXC2 - Add diagnostic: print all go.mod files in the AdaptixC2 clone (including their axc2 require lines) for future debugging - Print the listener Makefile so we can verify GOEXPERIMENT is preserved - Print axc2 version from both built plugins and the server binary for direct comparison after each build Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ibility Go plugin ABI compatibility requires every shared package to have the same build ID. The build ID is: hash(source + dep_ids + go_compiler_hash). Even when go version strings match (go1.25.11), a freshly-downloaded tarball can produce a different compiler binary hash than the binary embedded in the ghcr.io/tgjls/adaptixc2 Docker image. Fix: rebuild /app/adaptixserver from the TGJLS/AdaptixC2 source clone using the same go1.25.11 we install, then build the Kharon plugins with that same binary. Since both server and plugins are compiled by the identical go binary, all package build IDs are guaranteed to match. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The previous rebuild-adaptixserver approach broke the pre-built beacon/gopher plugins (the server was rebuilt from HEAD, which uses a different axc2 than the image was built with). Root cause of original Kharon failure: axc2 ABI mismatch was caused by TRANSITIVE dependency version skew (x/sys, x/text, etc.), not the compiler binary hash. Even with identical axc2 h1: source hashes, different x/sys/x/text versions produce different axc2 build IDs because build IDs are recursive. Fix: extract every dep version embedded in the server binary via 'go version -m /app/adaptixserver' and pin them all with 'go mod edit -require' before building Kharon plugins. This guarantees identical build IDs for all shared packages without touching the pre-built server or beacon plugins. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Kharon extender config paths were pre-committed into profile.yaml, causing adaptixc2 to crash-loop at startup because those files don't exist until after install-kharon.sh runs. The testing-kit activate step adds them dynamically — the static file must not reference them. This also fixes the Extension-Kit BOFs job which shares the same profile.yaml and was crash-looping for the same reason. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The container's go env file has GOFLAGS=-ldflags="-s -w". Go combines env-var GOFLAGS and go-env-file GOFLAGS, so adding GOFLAGS='-mod=mod' produced the invalid combined value '-mod=mod -ldflags="-s -w"'. When tokenized, '-w"' appears as an unknown flag. go mod download is explicitly exempt from -mod=readonly and updates go.sum without needing -mod=mod. Use that instead to pre-populate go.sum before the plugin builds, then drop GOFLAGS entirely from the build steps. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Go plugin ABI requires every shared package (axc2, x/sys, x/text…) to have the same package build ID, computed as: hash(source_content + dep_build_ids + compiler_binary_hash) Even when go version strings match (go1.25.11), a freshly-downloaded tarball has a different compiler binary hash than the one baked into the Docker image. This causes all shared package build IDs to diverge, so plugin.Open fails with "plugin was built with a different version of package axc2". Fix (building on e6b1217): 1. Read original server dep versions from the binary BEFORE any rebuild. 2. Clone TGJLS/AdaptixC2 and pin those same dep versions in go.mod. 3. Rebuild /app/adaptixserver with our downloaded go1.25.11 (same binary that will compile Kharon plugins) → server and plugins share the same compiler hash, guaranteeing identical package build IDs. The pre-built beacon/gopher plugins will fail ABI checks against the rebuilt server (different compiler hash), but the Kharon test job only needs Kharon to load — beacon/gopher failures are non-fatal and don't block the test. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Windows QEMU VM (dockurr/windows) uses QEMU user-mode networking
where DNS for Docker container hostnames ('adaptixc2') is not available.
The Beacon agent works because its callback address is hardcoded to the
static IP 172.28.0.10:8080.
The Kharon malleable profile had 'adaptixc2:8080' as the callback host,
which gets baked into the agent binary via HTTP_MALLEABLE_BYTES. The
Windows VM cannot resolve 'adaptixc2' so the agent never beacons.
Fix: use 172.28.0.10:8080 (adaptixc2's fixed Docker network IP) directly,
matching how the Beacon agent's callback_addresses is configured in
config.yaml.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
install-kharon.sh: - Fix BINARY_GOEXP awk: only set when binary actually carries X: flags; the old awk always printed NR==1, so a server built without GOEXPERIMENT would set BINARY_GOEXP to the full version string and abort every go build - Fix pl_agent.go patch to exit 1 on failure instead of printing a warning and continuing, which would silently build the plugin with KH_SLEEP_MASK=3 - Remove 2>/dev/null from server-rebuild go mod download so errors are visible - Consolidate two separate apt-get update+install blocks into one - Drop diagnostic dump blocks (=== Original adaptixserver build info ===, === Generated go.work ===, === listener_kharon_http/Makefile ===, === axc2 version in built plugins ===, === Key dep versions ===) runner.py: - _resolve_agent_from_extender was passing port_bind=0 for all agent schema fields; network-source fields (callback_addresses) resolved to host:0 instead of the actual listener port api.py: - activate_extender for listener type now removes the previously active listener's profile.yaml entries before writing the new ones, preventing both configs from accumulating in the file across extender swaps Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.