For Empire, a small launcher (a basic proxy-aware IEX download cradle) is used to download/execute the patched ./data/stager.ps1 script. The URI resource for this request can be specified in ./setup_database.py under the STAGE0_URI paramater. The stager.ps1 is case-randomized then XOR encrypted with the AES staging key from the database config. This means the key-negotiation stager delivered to each agent will be randomized/different per server, but will be static for each server instance. The staging key is sent with the launcher in order to decrypt the stager, so is assumed to be "burned" by network defenders.
This stager generates a randomized RSA private/public key pair in memory, uses the AES staging key to post the encrypted RSA public key to the STAGE1_URI resource (also specifiable in ./setup_database.py). A random 12-character SESSIONID is also generated at this point, which is the initial name the agent uses to check in. After this post, the server returns the server’s epoch time and a randomized AES session key, encrypted in the agent’s public key.
The agent decrypts the values, gathers basic system information, and posts this information to the server encrypted with the new AES session key to STAGE2_URI. The server then returns the patched ./data/agent.ps1, which can be thought of as the standard API. From here, the agent starts its beaconing behavior.
Graph depicting key staging process