Agent: Modify exploiters to have general and exploiter options

This commit is contained in:
Ilija Lazoroski 2022-02-18 20:05:03 +01:00
parent cecf131528
commit c83285c782
2 changed files with 29 additions and 10 deletions

View File

@ -1,6 +1,8 @@
import logging
import queue
import threading
from copy import deepcopy
from itertools import chain
from queue import Queue
from threading import Event
from typing import Callable, Dict, List, Mapping
@ -36,12 +38,10 @@ class Exploiter:
scan_completed: Event,
stop: Event,
):
# Run vulnerability exploiters before brute force exploiters to minimize the effect of
# account lockout due to invalid credentials
exploiters_to_run = exploiter_config["vulnerability"] + exploiter_config["brute_force"]
exploiters_to_run = self._process_exploiter_config(exploiter_config)
logger.debug(
"Agent is configured to run the following exploiters in order: "
f"{','.join([e['name'] for e in exploiters_to_run])}"
f"{', '.join([e['name'] for e in exploiters_to_run])}"
)
exploit_args = (exploiters_to_run, hosts_to_exploit, results_callback, scan_completed, stop)
@ -49,6 +49,22 @@ class Exploiter:
target=self._exploit_hosts_on_queue, args=exploit_args, num_workers=self._num_workers
)
@staticmethod
def _process_exploiter_config(exploiter_config: Mapping) -> List[Mapping]:
# Run vulnerability exploiters before brute force exploiters to minimize the effect of
# account lockout due to invalid credentials
ordered_exploiters = chain(
exploiter_config["vulnerability"], exploiter_config["brute_force"]
)
exploiters_to_run = list(deepcopy(ordered_exploiters))
for exploiter in exploiters_to_run:
# This order allows exploiter-specific options to
# override general options for all exploiters.
exploiter["options"] = {**exploiter_config["options"], **exploiter["options"]}
return exploiters_to_run
def _exploit_hosts_on_queue(
self,
exploiters_to_run: List[Dict],
@ -83,19 +99,21 @@ class Exploiter:
for exploiter in interruptable_iter(exploiters_to_run, stop):
exploiter_name = exploiter["name"]
exploiter_results = self._run_exploiter(exploiter_name, victim_host, stop)
exploiter_results = self._run_exploiter(
exploiter_name, exploiter["options"], victim_host, stop
)
results_callback(exploiter_name, victim_host, exploiter_results)
if exploiter_name != "ZerologonExploiter" and exploiter_results.success:
break
def _run_exploiter(
self, exploiter_name: str, victim_host: VictimHost, stop: Event
self, exploiter_name: str, options: Dict, victim_host: VictimHost, stop: Event
) -> ExploiterResultData:
logger.debug(f"Attempting to use {exploiter_name} on {victim_host}")
credentials = self._get_credentials_for_propagation()
options = {"credentials": credentials}
options = {"credentials": credentials, **options}
return self._puppet.exploit_host(exploiter_name, victim_host.ip_addr, options, stop)

View File

@ -35,12 +35,13 @@ def callback():
@pytest.fixture
def exploiter_config():
return {
"options": {"dropper_path_linux": "/tmp/monkey"},
"brute_force": [
{"name": "PowerShellExploiter"},
{"name": "SSHExploiter"},
{"name": "PowerShellExploiter", "options": {"timeout": 10}},
{"name": "SSHExploiter", "options": {}},
],
"vulnerability": [
{"name": "ZerologonExploiter"},
{"name": "ZerologonExploiter", "options": {}},
],
}