Action: Checkin
This page has the various different ways the initial checkin can happen and the encryption schemes used.
Endpoint
All messages go to the /api/v1.4/agent_message
endpoint. These messages can be:
POST request
message content in body
message content in FIRST header value
message content in FIRST cookie value
GET request
message content in FIRST header value
message content in FIRST cookie value
message content in FIRST query parameter
A note about UUIDs
You will see a bunch of UUIDs mentioned throughout this section. All UUIDs are UUIDv4 formatted UUIDs (36 characters in length) and formatted like:
In general, the UUID concatenated with the encrypted message provides a way to give context to the encrypted message without requiring a lot of extra pieces and without having to do a bunch of nested base64 encodings. 99% of the time, your messages will use your callbackUUID in the outer message. The outer UUID gives Apfell information about how to decrypt or interpret the following encrypted blob. In general:
payloadUUID as the outer UUID tells Apfell to look up that payload UUID, then look up the C2 profile associated with it, find a parameter called
AESPSK
, and use that as the key to decrypt the messagetempUUID as the outer UUID tells Apfell that this is a staging process. So, look up the UUID in the staging database to see information about the blob, such as if it's an RSA encrypted blob or is part of a Diffie-Hellman key exchange
callbackUUID as the outerUUID tells Apfell that this is a full callback with an established encryption key or in plaintext.
However, when your payload first executes, it doesn't have a callbackUUID, it's just a payloadUUID. This is why you'll see clarifiers as to which UUID we're referring to when doing specific messages. The whole goal of the checkin
process is to go from a payload (and thus payloadUUID) to a full callback (and thus callbackUUID), so at the end of staging and everything you'll end up with a new UUID that you'll use as the outer UUID.
Plaintext Checkin
The plaintext checkin is useful for testing or when creating an agent for the first time. When creating payloads, if there's an AESPSK parameter for the C2 profile, then this value will be auto-populated with the operation's 32Byte AES256 key. However, if you're doing plaintext comms, then you need to clear this value when creating your payload. Apfell looks at that outer PayloadUUID
and checks if there's an associated encryption key with it in the database. If there is, Apfell will automatically try to decrypt the rest of the message, which will fail. This checkin has the following format:
The JSON section is not encrypted in any way, it's all plaintext.
The checkin has the following response:
From here on, the agent messages use the new UUID instead of the payload UUID.
Static Encryption Checkin
This method uses a static AES256 key for all communications. This can be different for each payload that's created, or the operation specific key can be used. To use the operation specific key, make sure that the C2 profile being used has a parameter called "AESPSK" - this will be auto populated on payload creation with the operation key. This key needs to be a 32Byte, base64 encoded value.
The message sent will be of the form:
The message response will be of the form:
From here on, the agent messages use the new UUID instead of the payload UUID.
This first message from Agent -> Apfell has the Payload UUID as the outer UUID and the Payload UUID inside the checkin JSON message. Once the agent gets the reply with a callbackUUID, all future messages will have this callbackUUID as the outer UUID.
AES256 Encryption Details
Padding: PKCS7, block size of 16
Mode: CBC
IV is 16 random bytes
Final message: IV + Ciphertext + HMAC
where HMAC is SHA256 with the same AES key over (IV + Ciphertext)
Encrypted Key Exchange Checkins
There are two currently supported options for doing an encrypted key exchange in Apfell:
Client-side generated RSA keys
leveraged by the apfell-jxa and poseidon agents
Diffie-Hellman key exchange
leveraged by the viper agent
EKE by generating client-side RSA keys
The agent starts running and generates a new 4096 bit Pub/Priv RSA key pair in memory. The agent then sends the following message to Apfell:
where the AES key initially used is defined as the AESPSK value when generating the payload. Similar to the Initial Checkin with a static key, this value will be pre-populated based on the Operation's AESPSK value, but can be swapped out when creating the payload to be any AES256 key.
This message causes the following response:
The response is encrypted with the same initial AESPSK value as before. However, the session_key
value is encrypted with the public RSA key that was in the initial message and base64 encoded. The response also includes a new staging UUID for the agent to use. This is not the final UUID for the new callback, this is a temporary UUID to indicate that the next message will be encrypted with the new AES key.
The next message from the agent to Apfell is as follows:
This checkin data is the same as all the other methods of checking in, the key things here are that the tempUUID is the temp UUID specified in the other message, the inner uuid is the payload UUID, and the AES key used is the negotiated one. It's with this information that Apfell is able to track the new messages as belonging to the same staging sequence and confirm that all of the information was transmitted properly. The final response is as follows:
From here on, the agent messages use the new UUID instead of the payload UUID or temp UUID and continues to use the new negotiated AES key.
AES256 Encryption Details
Padding: PKCS7, block size of 16
Mode: CBC
IV is 16 random bytes
Final message: IV + Ciphertext + HMAC
where HMAC is SHA256 with the same AES key over (IV + Ciphertext)
RSA Encryption Details
PKCS1_OAEP
This is specifically OAEP with SHA1
4096Bits in size
EKE by using Diffie-Hellman
The agent starts running and generates a new Diffie-Hellman key-pair. The agent then sends the following message to Apfell:
where the AES key initially used is defined as the AESPSK value when generating the payload. Similar to the Initial Checkin with a static key, this value will be pre-populated based on the Operation's AESPSK value, but can be swapped out when creating the payload to be any AES256 key.
This message causes the following response:
The response is encrypted with the same AESPSK as used initially, but there's a session_key value that is encrypted with the public Diffie-Hellman negotiated public key that was in the initial message. The response also includes a new staging UUID for the agent to use. This is not the final UUID for the new callback, this is a temporary UUID to indicate that the next message will be encrypted with the new AES key.
The next message from the agent to Apfell is as follows:
This checkin data is the same as all the other methods of checking in, the key things here are that the tempUUID is the temp UUID specified in the other message, the inner uuid is the payload uuid, and the AES key used is the negotiated one. It's with this information that Apfell is able to track the new messages as belonging to the same staging sequence and confirm that all of the information was transmitted properly. The final response is as follows:
From here on, the agent messages use the new UUID instead of the payload UUID or temp UUID and continues to use the new negotiated AES key.
AES256 Encryption Details
Padding: PKCS7, block size of 16
Mode: CBC
IV is 16 random bytes
Final message: IV + Ciphertext + HMAC
where HMAC is SHA256 with the same AES key over (IV + Ciphertext)
Diffie-Hellman Encryption Details
key length: 540
Generator: 2
Group: 17
Last updated