mitre / caldera

Automated Adversary Emulation Platform
https://caldera.mitre.org
Apache License 2.0
5.66k stars 1.08k forks source link

multiple agents on the same host #991

Closed EmilioPanti closed 4 years ago

EmilioPanti commented 4 years ago

Hi, I am studying the latest stable version 2.4 and would like to better understand the management of multiple agents on the same host. To prevent backwards lateral movement you call the _exclude_existing() function in the app/utility/base_planning_svc.py file:

async def _exclude_existing(link, operation):
        all_hostnames = [agent.host for agent in await operation._active_agents()]
        for item in link.used:
            # prevent backwards lateral movement
            if 'remote.host' in item.trait:
                target_name = item.value.split('.')[0].lower()
                if target_name in all_hostnames or any(target_name in h for h in all_hostnames):
                    return False
        return True

Remarks:

  1. does the check only occur if the lateral movement uses a fact with 'remote.host' property?
  2. if the lateral movement uses ip addresses (perhaps more common) and not the host-name does the check fail?
  3. It seems to me a somewhat "superficial" control (if I understand correctly), do you think to insert more detailed controls or a different management in the future?
  4. I think it would be a good thing to let the user decide whether to allow multiple agents on the same host or not (like previous versions)
ghost commented 4 years ago

@cl-mitre can you comment?

ghost commented 4 years ago

hi @EmilioPanti nice to hear from you! I haven't seen any movement on this comment, so I'll start dropping some answers:

  1. yes- agree. I'd love to have this. Once we started allowing multiple agents-per-host, it became a little more difficult to ensure 1 host is running on a box (if the user wanted that) because each agent now gets a unique paw (identifier) that is not the hostname+username like we used in the past. If you can come up with a good solution-- that'd be awesome though.
ghost commented 4 years ago

1, 2, 3: @brianedmonds90 made some modifications to handle some of this logic recently. I think he was noticing some similar things. let's see if he can chime in on these, but I know the exlude_existing function was dropped as part of the simplifying here.

brianedmonds90 commented 4 years ago

@EmilioPanti Good questions. We are attempting to provide some flexible 'fact requirement modules' in order to allow the ability designer to describe what behavior they wish to prevent when facts are grounded. Check out the no_backwards_movement module which is best used on hostnames. You can see how this is applied to an ability here. If you want to manage IP addresses and lateral movement, and you find that one of our requirement modules doesn't suit your needs out of the box, you can always write your own. The entire operation object is passed into the requirement modules, so you should have all the information that you need to prune links that have some fact combination that isn't desirable, whether that be lateral movement to existing IP addresses, duplicate hostnames, etc.

Does that help?

brianedmonds90 commented 4 years ago

@EmilioPanti Also, I think a decent approach to allowing the user to decide whether multiple agents should be allowed on the same host would be to allow the planner modules (sequential in stockpile, for example) to pass a boolean parameter into the planning_svc's get_links() function that specifies whether links = await self.remove_links_missing_requirements(links, operation) is called in the base_planning_svc or not. I'm not sure how we would expose that on the front-end, but I like giving that option to the planner module.

ghost commented 4 years ago

circling back to this, as we've been been expanding our agents/connection options/etc lately.

we've settled into agents being quick & easy to write and the C2 server supplies "contact points" for agents to connect to via different protocols, such as HTTP, TCP, UDP, HTML, web sockets, etc.

this gives the agent author quite a bit of control over how they want to connect to caldera and how they want to design their agent. this intersects with this topic, allowing multiple agents per host. caldera accepts a beacon from anywhere and returns a server-side generated "paw" now, instead of it being generated on the agent side.

our current strategy is to let agent authors build their own controls for multi-agent handling, as it can be difficult to control server-side (as many things, such as hostname, can be spoofed - or there may be duplicate hostnames in different environments, etc.).

one neat example of this is the "manual" weather app agent. 1) go to localhost:8888/weather 2) type 'caldera' on your keyboard and a hidden page will be displayed behind the weather app 3) you'll see that you have a fully functioning agent with a paw 4) if you refresh the page, the paw remains the same (1 agent on the host) but you can clear your browser cache to get a different paw if you'd like, or open a new browser app entirely to keep both active.

The goal is to push the handling of the multi agent into the agent authors, as i think it's a better fit there.