Implant-C2 HTTP API
These are the default endpoints for the implant HTTP server. These endpoints can and should be changed by modifying the server/config/profiles/default.yaml file.
| Endpoint | Verb | Purpose | Details |
|---|---|---|---|
/c2/register | POST | Registers this implant | |
/c2/checkin | GET | Checks in with the C2 to see if there are any tasks | |
/c2/task | POST | Send the result of a task |
Crypto
All requests and responses after the initial registration are encrypted via libsodium Boxes. On the server side, each implant has a unique keypair. The server-side private key is stored in the the database, and the public key is sent to the implant during registration. All requests and responses with bodies are encrypted then Base64 encoded. Assume for all requests and response, the data has already been decoded and derypted.
This does not apply for registration
Examples
Authentication Implants can identify itself by setting the SESSID cookie to the implant’s ID. This value can be customized in the configuration file with the server.implant_id_cookie key.
/c2/register
This route allows implants to register with the server. The implant should send the following JSON object:
{
"txid": "encrypted_base64_encoded_public_key"
}
| Field | Purpose |
|---|---|
txid | The Base64 encoded LibSodium public key to use for encryption from server -> implant, encrypted with the C2 registration password |
Example responses:
-
200:
On successful registration:
{ "status": true, "k": "base64_encoded_server_public_key", "c": "base64_encoded_encrypted_maleable_config" }Field Purpose statustrueif registration was successful,falseotherwisekThe Base64 encoded LibSodium public key to use for encryption from implant -> server cThe Base64 encoded maleable profile to use. This is encrypted with the key in k. See below and profilecdecrypted would look something like:{ "status": true, "id": "74a45dc8dbec3008e74f91da3d2d05fa", "config": { "cookie": "SESSID", "kill_date": "", "sleep_time": 60, "jitter": 0.1, ... } }Field Purpose statustrueif registration was successful,falseotherwiseidThe implant ID configThe maleable profile to use. See profile -
401: This can happen for a few reasons:
- Empty request body or incorrect MIME type
- Missing or invalid
txidfield - Improperly formatted public key
- Public key already exists in the database
/c2/checkin
This endpoint is used to check in with the C2 server and pull down the next task, if there is one. The response will be encrypted with the key received during registration.
Example responses:
-
200:
If there are no tasks:
{}If there is a task:
{ "args": ["ls", "-la"], "opcode": 0, "task_id": "8af2838e2d70e2222aeb66459cec096e" }See Task for more details on the job object. Results of a job should be sent back to the appropriate endpoint to mark the task as completed.
For the meanining of
opcodes, see opcodes.
/c2/task
This endpoint is used to send the results of a task back to the C2 server. The request body should be encrypted with the key received during registration, then base64 encoded.
Example request:
{
"status": true,
"tid": "task_id_here",
"output": "b64_output_here",
}
If there is no output, set output to an empty string. If you’d like the output to be displayed in a table, output should be a JSON object (still base64 encoded).
| Field | Purpose |
|---|---|
status | true if the task was successful, false otherwise |
tid | The task ID |
output | The Base64 encoded output of the task |
Example responses:
- 200:
OK
- 401:
This can happen for a few reasons:
- Improperly formatted request body
- Missing implant identification cookie
- Implant with given ID doesn’t exist