diff --git a/app/controllers/break_escape/games_controller.rb b/app/controllers/break_escape/games_controller.rb index ba08907..e98f360 100644 --- a/app/controllers/break_escape/games_controller.rb +++ b/app/controllers/break_escape/games_controller.rb @@ -42,6 +42,16 @@ module BreakEscape end end + # Standalone mode with VM IPs JSON + if params[:vm_ips_json].present? + begin + vm_ips = JSON.parse(params[:vm_ips_json]) + initial_player_state['vm_ips'] = vm_ips if vm_ips.is_a?(Hash) + rescue JSON::ParserError => e + Rails.logger.warn "[BreakEscape] Invalid vm_ips_json: #{e.message}" + end + end + # Standalone mode with XML flag hints if params[:flag_hints_xml].present? flags_by_vm = Mission.parse_flag_hints_xml(params[:flag_hints_xml]) diff --git a/app/models/break_escape/game.rb b/app/models/break_escape/game.rb index a348de1..8d19429 100644 --- a/app/models/break_escape/game.rb +++ b/app/models/break_escape/game.rb @@ -555,11 +555,14 @@ module BreakEscape {} end - # Add flags_by_vm from player_state for standalone mode + # Add flags_by_vm and vm_ips from player_state for standalone mode state = player_state.is_a?(Hash) ? player_state : {} if state['flags_by_vm'].present? vm_context['flags_by_vm'] = state['flags_by_vm'] end + if state['vm_ips'].present? + vm_context['vm_ips'] = state['vm_ips'] + end # Generate with VM context (or empty context for non-VM missions) self.scenario_data = mission.generate_scenario_data(vm_context) diff --git a/app/models/break_escape/mission.rb b/app/models/break_escape/mission.rb index 08fee0e..4e3eda2 100644 --- a/app/models/break_escape/mission.rb +++ b/app/models/break_escape/mission.rb @@ -143,6 +143,8 @@ module BreakEscape attr_reader :random_password, :random_pin, :random_code, :vm_context # Get a VM from the context by title, or return a fallback VM object + # In Hacktivity mode: returns VM data from the VmSet + # In standalone mode: uses fallback but overrides IP from vm_ips if available # Usage in ERB: # "vm": <%= vm_object('kali', {"id":1,"title":"kali","ip":"192.168.1.10","enable_console":true}) %> def vm_object(title, fallback = {}) @@ -150,7 +152,13 @@ module BreakEscape vm = vm_context['vms'].find { |v| v['title'] == title } return vm.to_json if vm end - fallback.to_json + + # Standalone mode: use fallback, but override IP from vm_ips if available + result = fallback.dup + if vm_context && vm_context['vm_ips'] && vm_context['vm_ips'][title] + result['ip'] = vm_context['vm_ips'][title] + end + result.to_json end # Get flags for a specific VM from the context diff --git a/app/views/break_escape/games/new.html.erb b/app/views/break_escape/games/new.html.erb index 953f599..706cc72 100644 --- a/app/views/break_escape/games/new.html.erb +++ b/app/views/break_escape/games/new.html.erb @@ -71,14 +71,23 @@ <% else %> <%# Standalone Mode: XML Flag Hints Input %>
Paste the SecGen flag_hints.xml content below. Flags will be extracted per VM and validated at the corresponding flag stations during gameplay.
Configure your SecGen VM lab with IP addresses and flags. This information will be used by the in-game terminals.
<%= form_with url: break_escape.games_path, method: :post, local: true, class: 'flags-form' do |f| %> <%= f.hidden_field :mission_id, value: @mission.id %>JSON mapping VM names to IP addresses, e.g. {"desktop":"10.247.65.2","kali":"10.247.65.3"}
💡 How it works:
flag_hints.xmlflag_hints.xml content for flag trackingYou've discovered a computer terminal in the game. To interact with it, ` + let html = `
You've discovered a computer terminal in the game. To interact with it, `; if (this.hacktivityMode) { html += ` @@ -289,15 +312,17 @@ export class VmLauncherMinigame extends MinigameScene { } html += ` -
1. Start your VM in VirtualBox: ${this.escapeHtml(this.vm.title)}
2. Connect via SSH or VNC to: ${this.escapeHtml(this.vm.ip)}
3. Complete the challenges and capture flags
+