Empire
Empire copied to clipboard
Multi Listener Support
Why
Currently an agent can only try to beacon back to one listener. If said listener is blocked for a long enough time the agent will die after the configured number of missed checkins.
I'm opening this issue to discuss possible changes that I propose to contribute to the empire codebase to change this situation.
What
I'm proposing the following changes:
Add the ability for an agent to beacon back to multiple listeners by priority
Say, an agent is configured with 2 http listeners (simplest case) that have the following configurations:
- http1 killdate XX/XX/XXXX (two days hence) delay 5
- http2 killdate YY/XX/XXXX (three days hence) delay 24
the agent will first try to beacon back to http1, if it can't check in with it (eg trafic blocked at the firewall) it will try to connect to http2 if the minimum delay of 24 has elapsed after his last try to connect to it. missed_checkins should be increased only after the agent tried all of it's listeners for a connection.
After http1 killdate has been reached the agent will revert back to single listener behavior and only ever try to reach http2.
How
I'm proposing to contribute the following changes to the codebase:
- Update the database schema to be able to track multiple listeners per agents (basically adding a new table with 2 primary keys: agentID and listenerID -foreign keys from the agent and listeners tables- and removing the listener column from the agent table).
- Update lib/common/agent.py functions (all the get_X that retrieve agent/listener related data) to make use of the new schema.
- Write into the agent code the send_message function and make it use functions stored in a globally accessible datastructure.
- Update the listeners generate_comms functions to write functions with unique names (eg: send_messageHTTP1 instead of send_message) and update the dictionary (using the same REPLACE_X system that already exists).
Closing Words
I would very much like some input from established contributors regarding the changes I'm proposing and how they fit in the general design of the project. Also if anyone find this endeavor worthy of their time I would be glad to work with them on the proposed changes.
Good idea, however, how do you manage staging ? One staging URL and then the agent downloads the list on the "endpoints" ? And if the stage 1 fail, it's impossible for the agent to reach another endpoint. Multiple staging URL (one per listener for example) ? But now you increase the size of the launcher and you burn the list of all your endpoint in case of forensic on the launcher...
Anyway, this is a cool idea, good luck
:sunflower:
For the first iteration I would prefer to keep it simple (less possibilities to eff it up) and keep how it's currently done (one endpoint for stager, if it fails to download the agent, so be it) but still make the agent able to callback to multiple listeners.
I'll probably tackle stagers next. I want to keep it simple and without frills (too many moving parts begets catastrophe): I would add the ability to select which endpoints should be used when running the launcher (ideally a subset of the total number of endpoints). That way of your launcher gets caught then you have lost 2 endpoints. No big deal, especially if you add "burnable endpoints" into your workflow.
Specifying them wouldn't even have to change any code:
- very low lostLimit (or maybe pre set it as burnt in the agent code? or remove entirely?)
- very early killDate
That way you can have a payload that becomes inactive and useless to IR after a set amount of time and which the agents won't try to contact.
Small update for those interested:
Where I am
- Working multi listener support serverside for the http listener
- Added an option called "SupListeners" that allow the definition of multiple supplementary listeners when configuring an http listener. When the agent code is generated, communication code for the supplementary listeners wil be generated with the other listeners options. right now the agent side rework has only been done on the python agent code, I started reworking the powershell agent communication apparatus today
- Working multilistener support agent side for python agents
- The agent will now loop through the available listeners (tested with http and https listeners, different cookies and different URIs) if the first one does not answer. The retrieval of orders as well as the posting of results works.
Next things to tackle:
- Multi listener support for all the other listeners (both powershell and python agents) with thorough testing (probably going to do it pairwise since bruteforcing agents with listeners is going to be really time consuming)
- Multi listener support for stagers.
- Moar pairwise testing with different listeners for staging, actual communications and both python and powershell agents.
Another update.
What's been done
- Powershell agents are now correctly generated and can handle multiple listeners.
- Redirector listener updated to be usasble in a multi listener setup with both python and ps agents.
- Tested basic functionality first (one listener, one agent, one redirector, another agent)
- Tested a setup where an agent has a choice between connecting directly to one listener or going through a redirector if the main listener becomes unreachable (working, with the intermediary agent both using a single listener or having backup one to report back). Both python and ps agents worked.
- Multilistener with foreign listeners doesn't seem applicable (because of the way sessionIDs not in cache are handled right now - meaning restaging - and what I would mean to change that)
What's next
- other http listeners (com, hop and mapi) as well as onedrive and dbx
- Scripting of tests using the API (not sure if any work has already been done on the integration/end to end testing side, see question)
Questions
-
Would it be a good idea to make 1 PR for multilistener support for all the infrastructure minus the stagers, then another one for the stagers or should I put everything in ONE PR?
-
The contributions rule don't seem to say anything about the commits themselves: 1 big fat commit, 1 commit per file, 1 commit per file and per logical step?
-
As any work been done to create an end to end testing toolkit using the Rest API? I was thinking something along the line of a configurable script that auto start listeners with specific configurations, then download and run stagers to check if they work correctly?
Whoah nice to see you are working hard on it!
[..] support for all the infrastructure minus the stagers [..]
Is "stagers" means "launcher" for you? (or is "stager" for you means "launcher" for me ? :stuck_out_tongue:)
Regarding your questions (full disclosure, i'm not part of official Empire team): 1 and 2: One PR by major improvement, so in your case two PR. One commit per logical step 3: I don't think there is this kind of work available, good idea, but the REST API is a little bit instable and buggy (see API issue)
:sunflower:
To clarify (and correct any misunderstanding on my part):
-
Launcher: stage0 (such as a launcher.bat or a macro), what gets actually sent to a prospective target
-
stager: stage1, the first piece of code returned by the server containing what's required to register with the server and receive the next part
-
agent: stage2 the code containing everything to operate on the target machine
I've only worked on the last part, stage0 and 1 remain unchanged for now (so they only use one listener, the one defined after doing usestager XXXX; set Listener whateverIfancy
) but once the agent code is generated then the implant gets the ability to use separate listeners that each have their own delay, lostlimit, jitter and missedcheckins.
It operates by basically chaining listeners when doing the generation, I'm still looking for a more understanble way to do it but as of now, say if you have three listeners like that (arrows showing that L2 and L3 are in L1's Suplisteners list):
L1--->L2
|
|----->L3
if you use a stager and point it to L1 then the resulting agent will get the required code to communicate with L1, L2, and L3. OTOH if you point it to L2 or L3 the resulting agent code will only be able to communicate with them.
Once I get there I think I will simply build on that. Say you want to have two listeners able to receive the first cries of your new born agent and enable it to call back to either of them AND both L3 and L2 you would set it up like so:
L1--->L2<---
| |
|----->L3<--
|
L4----------
before pointing your stager to both L1 and L4: whichever first answers will also send the communication code required to talk to both L2 and L3