Skip to content

Commit 07acf57

Browse files
lleizerovichREDMOND\lleizerovich
and
REDMOND\lleizerovich
authored
uploaded the script that runs the simulation (#15)
Co-authored-by: REDMOND\lleizerovich <lleizerovich@microsoft.com>
1 parent 311ebc0 commit 07acf57

File tree

1 file changed

+126
-0
lines changed

1 file changed

+126
-0
lines changed

simulation.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT License.
3+
4+
import subprocess
5+
import time
6+
7+
TITLE = """
8+
+++ Defender for Cloud Attack Simulation +++
9+
10+
This simulation creates two pods - attacker and victim
11+
The attacker pod will execute the chosen scenario on the victim
12+
"""
13+
MENU = """
14+
Available scenarios:
15+
1. Reconnaissance - Gather information about the cluster environment.
16+
2. Lateral Movement - Cluster to cloud.
17+
3. Secrets Gathering - Search for sensitive information in the victim pod.
18+
4. Cryptomining - Run a cryptominer on the victim pod.
19+
5. Webshell - Exploit a webshell on the victim pod (NOTE: the webshell is used in all scenarios).
20+
6. All - Run all scenarios.
21+
22+
"""
23+
SCENARIOS = ["recon", "lateral-mov", "secrets", "crypto", "webshell", "all"]
24+
HELM_CHART = "oci://ghcr.io/microsoft/defender-for-cloud/attacksimulation/mdc-simulation"
25+
HELM_RELEASE = "mdc-simulation"
26+
NAMESPACE = "mdc-simulation"
27+
ATTACKER = "mdc-simulation-attacker"
28+
VICTIM = "mdc-simulation-victim"
29+
30+
31+
def delete_resources():
32+
subprocess.run(["helm", "uninstall", HELM_RELEASE])
33+
subprocess.run(["kubectl", "delete", "namespace", NAMESPACE])
34+
35+
36+
def run_scenario(scenario):
37+
"""Installs components using helm and shows scenario results."""
38+
# Install or update the helm chart
39+
print("Helm - creating simulation objects in namespace mdc-simulation...")
40+
try:
41+
subprocess.run(["helm", "upgrade", "--install", HELM_RELEASE, HELM_CHART,
42+
"--set", f"env.name={NAMESPACE}", "--set", f"scenario={scenario}"],
43+
check=True, capture_output=True)
44+
except subprocess.CalledProcessError as e:
45+
print("Failed to create Helm chart. Exiting")
46+
raise subprocess.CalledProcessError(returncode=e.returncode, cmd=e.cmd)
47+
except FileNotFoundError:
48+
print("Can't find Helm. Exiting")
49+
raise FileNotFoundError
50+
51+
print("Creating resources...")
52+
attacker_status = subprocess.run(["kubectl", "get", "pod", ATTACKER, "-n", NAMESPACE, "-o",
53+
r'jsonpath="{.status.phase}"'], capture_output=True, text=True)
54+
victim_status = subprocess.run(["kubectl", "get", "pod", VICTIM, "-n", NAMESPACE, "-o",
55+
r'jsonpath="{.status.phase}"'], capture_output=True, text=True)
56+
while '"Pending"' in (attacker_status.stdout, victim_status.stdout) :
57+
time.sleep(3)
58+
attacker_pending = subprocess.run(["kubectl", "get", "pod", ATTACKER, "-n", NAMESPACE, "-o",
59+
r'jsonpath="{.status.containerStatuses[0].state.waiting.reason}"'], capture_output=True, text=True)
60+
victim_pending = subprocess.run(["kubectl", "get", "pod", VICTIM, "-n", NAMESPACE, "-o",
61+
r'jsonpath="{.status.containerStatuses[0].state.waiting.reason}"'], capture_output=True, text=True)
62+
attacker_status = subprocess.run(["kubectl", "get", "pod", ATTACKER, "-n", NAMESPACE, "-o",
63+
r'jsonpath="{.status.phase}"'], capture_output=True, text=True)
64+
victim_status = subprocess.run(["kubectl", "get", "pod", VICTIM, "-n", NAMESPACE, "-o",
65+
r'jsonpath="{.status.phase}"'], capture_output=True, text=True)
66+
67+
if (attacker_status.stdout =='"Pending"' and attacker_pending.stdout != '"ContainerCreating"') or (victim_status.stdout == '"Pending"' and victim_pending.stdout != '"ContainerCreating"'):
68+
print(f"Failed to create one or more containers.\nAttacker container status: {attacker_pending.stdout},\nVictim container status: {victim_pending.stdout}.")
69+
raise Exception
70+
71+
if '"Failed"' in (attacker_status.stdout, victim_status.stdout):
72+
print(f"Failed to create one or more pods.\nAttacker pod status: {attacker_status.stdout},\nVictim pod status: {victim_status.stdout}.")
73+
raise Exception
74+
75+
# read the attack output
76+
print("Running the scenario...\n")
77+
try:
78+
subprocess.run(["kubectl", "logs", "-f", ATTACKER, "-n", NAMESPACE], timeout=90)
79+
except subprocess.TimeoutExpired:
80+
print("Scenario did not complete successfully (timeout)")
81+
return
82+
last_line = subprocess.run(["kubectl", "logs", "--tail=1", ATTACKER, "-n", NAMESPACE],
83+
text=True, capture_output=True)
84+
if last_line.stdout == "--- Simulation completed ---\n":
85+
print("\nScenario completed successfully.\n")
86+
else:
87+
print("Scenario did not complete successfully")
88+
89+
90+
def start_simulation():
91+
print(MENU)
92+
user_choise = input("Select a scenario: ")
93+
94+
while not (user_choise.isnumeric()) or not(int(user_choise) in range(1, len(SCENARIOS)+1 )):
95+
print("Invalid input")
96+
user_choise = input("Select a scenario: ")
97+
98+
choise = int(user_choise)
99+
100+
try:
101+
run_scenario(SCENARIOS[choise-1])
102+
except Exception:
103+
release_status = subprocess.run(["helm", "status", HELM_RELEASE], capture_output=True)
104+
if release_status.returncode == 0:
105+
delete_resources()
106+
return
107+
108+
again = input("Run another scenario?(Y/N): ")
109+
while again.upper() not in ["Y", "N"]:
110+
print("Invalid input")
111+
again = input("Run another scenario?(Y/N): ")
112+
if again.upper() == "Y":
113+
subprocess.run(["kubectl", "delete", "pod", ATTACKER, "-n", NAMESPACE], capture_output=True)
114+
start_simulation()
115+
else:
116+
input("Press Any Button to delete resources")
117+
delete_resources()
118+
119+
120+
def main():
121+
print(TITLE)
122+
start_simulation()
123+
124+
125+
if __name__ == '__main__':
126+
main()

0 commit comments

Comments
 (0)