Plugin de transport C2 serverless pour AdaptixC2 v1.2 utilisant AWS Lambda + DynamoDB comme infrastructure de relais.

Plugin de transport C2 serverless pour AdaptixC2 v1.2 utilisant AWS Lambda + DynamoDB comme infrastructure de relais. Le trafic de l'agent apparaît comme du HTTPS sortant vers des endpoints AWS, ne nécessitant aucun port entrant ni IP publique sur le serveur C2.
Kharon Agent (target)
|
| HTTPS GET/POST (outbound only, randomly alternated)
v
AWS Lambda Function URL (stateless relay)
|
| Store inbound / Poll outbound (up to 8s)
v
DynamoDB (inbound + outbound tables)
^
| Poll every 5 seconds
|
Listener Plugin (inside AdaptixC2)
|
| TsAgent API + TsExtenderData (key persistence)
v
AdaptixC2 Teamserver + UI
Flux de données :
inboundoutbound pendant jusqu'à 8 secondes (comble le décalage asynchrone pour l'enregistrement)inbound pour les enregistrements non traitésoutbound| Composant | Chemin | Objectif |
|---|---|---|
| Agent Kharon | agent/ | Implant Kharon inclus (source C++) |
| Terraform | deploy/aws/ | Infrastructure Lambda + DynamoDB + IAM + KMS |
| Relais Lambda | deploy/aws/lambda/ | Proxy HTTP-vers-DynamoDB sans état avec polling sortant |
| Plugin listener | listener/ | Plugin AdaptixC2, polling DynamoDB, pont protocole Kharon |
| Configs Kharon | kharon/ | Enregistrement des commandes AXS et config pour les extenders agent/listener |
| Patches | patches/ | Patches source AdaptixC2 pour le support BeaconServerless |
| Profils | profiles/ | Profil HTTP malleable pour l'URL Lambda |
| Scripts | scripts/ | Installation, build, déploiement, désinstallation |
aws configure)apt install clang lldapt install nasmapt install binutils-mingw-w64-x86-64Dans la console AWS :
adaptix-deployerAmazonDynamoDBFullAccessAWSLambda_FullAccessIAMFullAccessCloudWatchLogsFullAccess{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"kms:*","Resource":"*"}]}KMSFullAccessaws configure
# AWS Access Key ID: <paste access key>
# AWS Secret Access Key: <paste secret key>
# Default region: us-east-1
# Default output format: json
Vérifiez :
aws sts get-caller-identity
# Build the Lambda relay binary (cross-compiled for Amazon Linux)
./scripts/build_relay.sh
# Deploy Lambda + DynamoDB + IAM with Terraform
./scripts/deploy_infra.sh
# Note the Lambda Function URL from the output, e.g.:
# lambda_function_url = "https://xxxxx.lambda-url.us-east-1.on.aws"
./scripts/install.sh /path/to/AdaptixC2
Ce script va :
dist/ (certificats, base de données, profil)GOEXPERIMENT du binaire serveur.so) avec les flags correspondantsBeaconServerlessrelay_api_key dans votre terraform.tfvars)profiles/lambda_default.jsonBeaconServerlessdeploy/aws/terraform.tfvars)region = "us-east-1"
function_name = "adaptix-relay"
relay_api_key = "your-secret-key-here"
tags = {
Project = "adaptix-serverless"
}
| Champ | Description | Défaut |
|---|---|---|
| AWS Region | Région où l'infra est déployée | us-east-1 |
| Lambda URL | URL de fonction depuis la sortie Terraform | (requis) |
| Relay API Key | Doit correspondre au relay_api_key Terraform | (optionnel) |
| Inbound Table | Table DynamoDB pour les check-ins des agents | adaptix-inbound |
| Outbound Table | Table DynamoDB pour les réponses du serveur | adaptix-outbound |
| Poll Interval | Fréquence de vérification de DynamoDB (secondes) | 5 |
| TTL Hours | Expiration des enregistrements DynamoDB | 24 |
L'agent Kharon utilise un protocole binaire personnalisé sur HTTP :
[36-byte UUID][encrypted_checkin_data][16-byte LokyCrypt key][36-byte UUID][encrypted_payload] (pas de clé finale)TotalLen-16 chevauche la zone UUID. Pour un paquet de 44 octets, la clé commence à l'offset 28, écrasant les octets UUID 28-35 et toutes les données chiffrées.Le listener détecte ces trois formats et les gère correctement.
La nature asynchrone de Lambda + DynamoDB signifie que le listener n'a pas traité l'enregistrement entrant lorsque Lambda vérifie pour la première fois une réponse. Lambda interroge la table outbound pendant jusqu'à 8 secondes après avoir stocké un enregistrement inbound, donnant au listener le temps de traiter et de mettre en file la réponse. Ceci est critique pour l'enregistrement (la réponse Checkin doit arriver pendant la phase Checkin, pas lors d'un GetTask ultérieur).