Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 33 additions & 7 deletions app/flags/operations/flag_3.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,47 @@
import logging
from plugins.training.app.c_flag import Flag


class OperationsFlag3(Flag):
name = 'Empty operation'
name = 'Empty Op'

challenge = (
'Run and finish an operation without selecting any agent groups or adversary profiles. Add at least 5 manual '
'or potential links to the operation before finishing the operation.'
)

extra_info = (
'During an autonomous adversary emulation exercise, the operation will only run tasks in the adversary profile. '
'Manual and potential links allow an operator to "toss in" additional TTPs into a live, autonomous operation.'
'During an autonomous adversary emulation exercise, the operation will only run tasks in the adversary profile. '
'Manual and potential links allow an operator to "toss in" additional TTPs into a live, autonomous operation.'
)

async def verify(self, services):
for op in await services.get('data_svc').locate('operations'):
if op.finish and op.adversary.adversary_id == 'ad-hoc' and len(op.chain) >= 5 and not op.group:
data_svc = services.get('data_svc')
if not data_svc:
logging.error("[training.flag3] data_svc is None!")
return False

operations = await data_svc.locate('operations')
for op in operations:
logging.info(f"[training.flag3] Checking operation '{op.name}' | state={op.state}, group={op.group}, adversary_id={getattr(op.adversary, 'adversary_id', None)}")

# Gather all link lists that might exist
chain_links = getattr(op, 'chain', []) or []
potential_links = getattr(op, 'potential_links', []) or []
manual_links = getattr(op, 'links', []) or []

total_links = len(chain_links) + len(potential_links) + len(manual_links)

logging.info(f"[training.flag3] Found {len(chain_links)} chain links, {len(potential_links)} potential links, {len(manual_links)} manual links (total={total_links})")

# Verify completion conditions
if (
op.finish
and getattr(op.adversary, 'adversary_id', None) == 'ad-hoc'
and total_links >= 5
and not op.group
):
logging.info(f"[training.flag3] ✅ Operation '{op.name}' meets all criteria!")
return True
return False

logging.info("[training.flag3] ❌ No operation met the criteria.")
return False
6 changes: 4 additions & 2 deletions app/training_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,10 @@ async def retrieve_flags(self, request):
flag.completed = flag.verify(answer)
else:
flag.completed = await flag.verify(self.services)
if not hasattr(cert, 'cert_type'):
break
# Process all flags independently — don't stop after first incomplete one
# if not hasattr(cert, 'cert_type'):
# break

except Exception as e:
logging.error(e)
return web.json_response(dict(badges=[b.display for b in badges]))
Expand Down
30 changes: 29 additions & 1 deletion gui/views/training.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,48 @@ onBeforeUnmount(() => {
});

onMounted(async () => {
// ✅ Restore previous state before loading data
const savedState = localStorage.getItem("trainingState");
if (savedState) {
try {
const parsed = JSON.parse(savedState);
selectedCert.value = parsed.selectedCert || "";
selectedBadge.value = parsed.selectedBadge || "";
} catch (err) {
console.warn("Failed to parse saved training state:", err);
}
}

// ✅ Existing functionality (keep this intact)
const res = await $api.get("/plugin/training/certs");
certificates.value = res.data.certificates;

let confettiScript = document.createElement("script");
confettiScript.setAttribute(
"src",
"https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.2/dist/confetti.browser.min.js"
);
document.head.appendChild(confettiScript);

if (updateInterval) clearInterval(updateInterval);
updateInterval = setInterval(async () => {
getTraining();
}, "3000");
}, 3000); // <-- you can also remove the quotes, should be a number not a string
});

// ✅ New: persist user selections when they change
watch(
[selectedCert, selectedBadge],
() => {
const state = {
selectedCert: selectedCert.value,
selectedBadge: selectedBadge.value,
};
localStorage.setItem("trainingState", JSON.stringify(state));
},
{ deep: true }
);

watch(selectedCert, (newValue) => {
getTraining();
});
Expand Down
2 changes: 1 addition & 1 deletion solution_guides/AdvancedFlag0.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
1. Select `CONFIGURATION > configuration`.
1. Select `CONFIGURATION > settings`.
1. Change the `app.contact.http` value to a URL with an externally-facing IP address (not http://127.0.0.1:8888)
1. Press the `Update` button in the `app.contact.http` row.
1. Task completed.
6 changes: 3 additions & 3 deletions solution_guides/AdvancedFlag1.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
1. Select `CONFIGURATION > fact sources`.
1. Press the `+ Create Source` button to open the source creation menu.
1. Press the `+ New Source` button to open the source creation menu.
1. Replace `New source` in the textbox with `better basic`.
1. Under `Facts`, press the `+ new fact` button.
1. Under `Facts`, press the `+ add fact` button.
1. Enter a `Fact Trait` (ex: "host.file.path").
1. Enter a `Value` (ex: "C:\Windows\System32\calc.exe").
1. Press the `Save` button.
1. Under `Rules`, press the `+ new rule` button.
1. Under `Rules`, press the `+ add rule` button.
1. Enter a `Fact Trait` (ex: "host.file.path").
1. Next to `ALLOW` enter a `Match` (ex: "C:\Windows\System32\calc.exe").
1. Press the `Save` button.
Expand Down
3 changes: 1 addition & 2 deletions solution_guides/OperationsFlag0.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
1. First, ensure that an agent is deployed and is responsive.
1. Select `CAMPAIGNS > operations`.
1. Click the `+ Create Operation` button to open the `Start New Operation` menu.
1. Click the `+ New Operation` button to open the `Start New Operation` menu.
1. Give the operation a name.
1. Select the `Check` adversary from the `Adversary` dropdown.
1. Select `basic` from the `Fact source` menu.
1. Press `ADVANCED` to open the advanced options dialog.
1. Select `Auto close operation` from the `Auto-close`radio group.
1. Press `Start` to run the operation.
1. Wait for the operation to complete.
Expand Down
3 changes: 1 addition & 2 deletions solution_guides/OperationsFlag1.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
1. First, ensure that an agent is deployed and is responsive.
1. Select `CAMPAIGNS > operations`.
1. Click the `+ Create Operation` button to open the `Start New Operation` menu.
1. Click the `+ New Operation` button to open the `Start New Operation` menu.
1. Give the operation a name.
1. Select the `Check` adversary from the `Adversary` dropdown.
1. Select `basic` from the `Fact source` menu.
1. Press `ADVANCED` to open the advanced options dialog.
1. In the `Obfuscators` button group, choose `base64`.
1. Select `Auto close operation` from the `Auto-close`radio group.
1. In the `Jitter (sec/sec)` select `10/20`.
Expand Down
5 changes: 2 additions & 3 deletions solution_guides/OperationsFlag2.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
1. First, ensure that an agent is deployed and is responsive.
1. Select `CAMPAIGNS > operations`.
1. Click the `+ Create Operation` button to open the `Start New Operation` menu.
1. Click the `+ New Operation` button to open the `Start New Operation` menu.
1. Give the operation a name.
1. Select the `Discovery` adversary from the `Adversary` dropdown.
1. Select `basic` from the `Fact source` menu.
1. Press `ADVANCED` to open the advanced options dialog.
1. Select `Require manual approval` in the `Autonomous` radio group.
1. Press `Start` to run the operation.
1. In the list of commands a `Review Command` button will appear with each new command. Press `Review Command` button and confirm by clicking `Approve` in the dialog box that appears.
1. In the list of commands a `View Command` button will appear with each new command. Press `Review Command` button and confirm by clicking `Approve` in the dialog box that appears. Repeat for each command.
1. Press `Stop` button to finish the operation.
1. Wait for the operation to complete.
1. Task completed.
3 changes: 1 addition & 2 deletions solution_guides/OperationsFlag3.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
1. First, ensure that an agent is deployed and is responsive.
1. Select `CAMPAIGNS > operations`.
1. Click the `+ Create Operation` button to open the `Start New Operation` menu.
1. Click the `+ New Operation` button to open the `Start New Operation` menu.
1. Give the operation a name.
1. Ensure that `No adversary (manual)` is selected from the `Adversary` dropdown.
1. Select `basic` from the `Fact source` menu.
1. Press `ADVANCED` to open the advanced options dialog.
1. Select `Require manual approval` in the `Autonomous` radio group.
1. In the `Run state`, select `Pause on start` option.
1. Press `Start` to run the operation.
Expand Down