Skip to content

Commit a9bdf68

Browse files
committed
update Ludus post
1 parent 657b8d3 commit a9bdf68

2 files changed

Lines changed: 97 additions & 28 deletions

File tree

-15.4 KB
Loading

blog/ludus-cyber-range.md

Lines changed: 97 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -60,46 +60,46 @@ While browsing the “Environment Guides,” I stumbled upon the **Game Of Activ
6060

6161
That meant modifying the original Ansible scripts. Thankfully, it wasn’t as dramatic as it sounds, but it did feel like giving the templates a well-deserved modern update. My current ludus range configuration looks as follows:
6262

63-
```yml
63+
```yaml
6464
ludus:
65-
- vm_name: "{{ range_id }}-NHA-DC01"
66-
hostname: "{{ range_id }}-DC01"
65+
- vm_name: "{{ '{{ range_id }}' }}-NHA-DC01"
66+
hostname: "{{ '{{ range_id }}' }}-DC01"
6767
template: win2025-server-x64-tpm-template
6868
vlan: 10
6969
ip_last_octet: 30
7070
ram_gb: 8
7171
cpus: 2
7272
windows:
7373
sysprep: true
74-
- vm_name: "{{ range_id }}-NHA-DC02"
75-
hostname: "{{ range_id }}-DC02"
74+
- vm_name: "{{ '{{ range_id }}' }}-NHA-DC02"
75+
hostname: "{{ '{{ range_id }}' }}-DC02"
7676
template: win2025-server-x64-tpm-template
7777
vlan: 10
7878
ip_last_octet: 31
7979
ram_gb: 8
8080
cpus: 2
8181
windows:
8282
sysprep: true
83-
- vm_name: "{{ range_id }}-NHA-SRV01"
84-
hostname: "{{ range_id }}-SRV01"
83+
- vm_name: "{{ '{{ range_id }}' }}-NHA-SRV01"
84+
hostname: "{{ '{{ range_id }}' }}-SRV01"
8585
template: win2025-server-x64-tpm-template
8686
vlan: 10
8787
ip_last_octet: 32
8888
ram_gb: 6
8989
cpus: 2
9090
windows:
9191
sysprep: true
92-
- vm_name: "{{ range_id }}-NHA-SRV02"
93-
hostname: "{{ range_id }}-SRV02"
92+
- vm_name: "{{ '{{ range_id }}' }}-NHA-SRV02"
93+
hostname: "{{ '{{ range_id }}' }}-SRV02"
9494
template: win2025-server-x64-tpm-template
9595
vlan: 10
9696
ip_last_octet: 33
9797
ram_gb: 6
9898
cpus: 2
9999
windows:
100100
sysprep: true
101-
- vm_name: "{{ range_id }}-NHA-SRV03"
102-
hostname: "{{ range_id }}-SRV03"
101+
- vm_name: "{{ '{{ range_id }}' }}-NHA-SRV03"
102+
hostname: "{{ '{{ range_id }}' }}-SRV03"
103103
template: win2025-server-x64-tpm-template
104104
vlan: 10
105105
ip_last_octet: 34
@@ -109,8 +109,8 @@ ludus:
109109
sysprep: true
110110

111111
router:
112-
vm_name: "{{ range_id }}-router-debian12-x64"
113-
hostname: "{{ range_id }}-router"
112+
vm_name: "{{ '{{ range_id }}' }}-router-debian12-x64"
113+
hostname: "{{ '{{ range_id }}' }}-router"
114114
template: debian-12-x64-server-template
115115
ram_gb: 2
116116
ram_min_gb: 1
@@ -126,31 +126,32 @@ defaults:
126126
ad_domain_user: domainuser
127127
ad_domain_user_password: password
128128
ad_domain_safe_mode_password: password
129-
timezone: America/New_York
129+
timezone: Europe/Brussels
130130
enable_dynamic_wallpaper: true
131131
```
132132
133133
I also made a few tweaks to the available RAM of the VMs and updated the domain/forest functional level to 2025 as well. With this file we can start building our hacker lab.
134134
135-
## Ninja Hacker Academy Setup
136-
137-
!!!info
138-
NHA is designed as an educational challenge where users normally work toward gaining domain admin on two domains (`academy.ninja.lan` and `ninja.hack`)
135+
!!!warning
136+
If the build process fails, as happened to me :(, it might be because of unsufficient system resources. Just rerun the script or reboot the VMs and try again.
139137
!!!
140138
141-
The scenario includes:
142-
- A starting point on `srv01` at `10.5.10.32`
139+
140+
## Ninja Hacker Academy Setup
141+
NHA is designed as an educational challenge where users normally work toward gaining domain admin on two domains (`academy.ninja.lan` and `ninja.hack`). The scenario includes:
142+
- A starting point on `WEB` at `10.2.10.32`
143143
- Flags hidden on each machine
144144
- Up-to-date systems with Defender enabled
145145

146146
Let's create a new user for our range and start the deployment with the Ludus CLI.
147147

148148
```console
149149
$ ludus user add --name Ninja --userid NHA --url https://127.0.0.1:8081
150+
[INFO] Adding user to Ludus, this can take up to a minute. Please wait.
150151
+--------+------------------+-------+---------------------------------------------+
151152
| USERID | PROXMOX USERNAME | ADMIN | API KEY |
152153
+--------+------------------+-------+---------------------------------------------+
153-
| NHA | Ninja | true | <YOUR_API_KEY> |
154+
| NHA | ninja | false | <YOUR_API_KEY> |
154155
+--------+------------------+-------+---------------------------------------------+
155156
156157
$ ludus range config set -f ad/NHA/providers/ludus/config.yml --user NHA
@@ -160,6 +161,10 @@ $ ludus range deploy --user NHA
160161
[INFO] range deploy started
161162
```
162163

164+
You can follow the deployment process with the `range logs -f` command:
165+
166+
![](/assets/images/homelab/ludus-range-deploy-logs.png)
167+
163168
At the end you should see something like this:
164169

165170
![](/assets/images/homelab/ludus-nha-range-status.png)
@@ -174,39 +179,87 @@ With our range deployed, we can start setting up the actual environment. With [A
174179
In the future I was thinking of publishing them on my [GitHub](https://github.com/bytebl33d), but they might already be there ;)
175180
!!!
176181

177-
We proceed with the provisioning and install the required collections:
182+
We proceed with the provisioning and install the required collections (but these should already be installed with ludus):
178183

179184
```console
180185
$ ansible-galaxy collection install ansible.windows
186+
$ ansible-galaxy collection install microsoft.ad
181187
$ ansible-galaxy collection install community.general
182188
$ ansible-galaxy collection install community.windows
183189
```
184190

191+
Before continuing, make sure that your inventory file at `workspace/ludus/inventory` matches the IP addresses from your range. In my case the range starts with `10.2.10.x` so I will update it accordingly:
192+
193+
```console
194+
$ cat NHA/workspace/ludus/inventory
195+
[default]
196+
; Note: ansible_host *MUST* be an IPv4 address or setting things like DNS
197+
; servers will break.
198+
; ------------------------------------------------
199+
; ninja.local
200+
; ------------------------------------------------
201+
dc01 ansible_host=10.2.10.30 dns_domain=dc01 dns_domain=dc02 dict_key=dc01
202+
dc02 ansible_host=10.2.10.31 dns_domain=dc02 dict_key=dc02
203+
srv01 ansible_host=10.2.10.32 dns_domain=dc02 dict_key=srv01
204+
srv02 ansible_host=10.2.10.33 dns_domain=dc02 dict_key=srv02
205+
srv03 ansible_host=10.2.10.34 dns_domain=dc02 dict_key=srv03
206+
207+
208+
[all:vars]
209+
force_dns_server=no
210+
dns_server=10.2.10.254
211+
212+
dns_server_forwarder=10.2.10.254
213+
214+
ansible_user=localuser
215+
ansible_password=password
216+
```
217+
185218
Hop into the `ansible` directory where all the playbooks are located and run them all.
186219

187220
!!!info
188221
If you get the error `Ansible could not initialize the preferred locale: unsupported locale setting`, check your locales with `locale -a` and set it with `export LC_ALL=<YOUR_LOCALE>.utf8`
189222
!!!
190223

191224
```console
192-
$ cd ansible
193-
$ ansible-playbook -i ../ad/NHA/data/inventory -i ../globalsettings.ini main.yml
225+
$ cd NHA/ansible
226+
$ ansible-playbook -i ../ad/data/inventory -i ../workspace/ludus/inventory -i ../globalsettings.ini main.yml
194227
```
195228

196-
This will take some time to finish.
229+
![](/assets/images/homelab/ansible-ludus.gif)
230+
231+
Ignore the warnings as Ansible goes brrr...
232+
233+
This will take some time for it to complete — a good opportunity to refresh your coffee while automation does its thing. In case we ever make a change to one of the playbooks or tasks we can also just run a single one:
234+
235+
```console
236+
$ ansible-playbook -i ../ad/data/inventory -i ../workspace/ludus/inventory -i ../globalsettings.ini ad-trusts.yml
237+
```
238+
239+
After it is finished provisioning our lab, we can take snapshots via the proxmox web UI or SSH run the following ludus command (make sure your disks allow snapshots)
240+
241+
```console
242+
$ ludus --user NHA snapshot create clean-setup -d "Clean NHA setup after ansible run"
243+
[INFO] Successfully created snapshot 'clean-setup' for VM 118
244+
[INFO] Successfully created snapshot 'clean-setup' for VM 119
245+
[INFO] Successfully created snapshot 'clean-setup' for VM 120
246+
[INFO] Successfully created snapshot 'clean-setup' for VM 121
247+
[INFO] Successfully created snapshot 'clean-setup' for VM 122
248+
[INFO] Successfully created snapshot 'clean-setup' for VM 123
249+
```
197250

198251
## Connecting to the Lab
199252

200253
```console
201-
$ ludus user wireguard --user NHAc531df | tee ludus-wg.conf
254+
$ ludus user wireguard --user NHA | tee ludus-wg.conf
202255
[Interface]
203256
PrivateKey = <PRIVATE_KEY>
204257
Address = 198.51.100.5/32
205258
206259
[Peer]
207260
PublicKey = <PUBLIC_KEY>
208261
Endpoint = 192.168.128.10:51820
209-
AllowedIPs = 10.5.0.0/16, 198.51.100.1/32
262+
AllowedIPs = 10.2.0.0/16, 198.51.100.1/32
210263
PersistentKeepalive = 25
211264
```
212265

@@ -215,4 +268,20 @@ Copy this file to your client and run WireGuard:
215268
```console
216269
$ wg-quick up ./ludus-wg.conf
217270
```
218-
You can optionally narrow `AllowedIPs` down to only the `srv01` host for better isolation. And just like that, you’re securely connected to your newly deployed cyber range.
271+
You can optionally narrow `AllowedIPs` down to only the `srv01` host for better isolation. And just like that, you’re securely connected to your newly deployed cyber range. Let's do a quick test with one of the local admin passwords to see if everything works fine.
272+
273+
```console
274+
$ evil-winrm-py -i SQL.academy.ninja.lan -u 'Administrator' -p '978i2pF43UqsdqsdJ-qsd'
275+
_ _ _
276+
_____ _(_| |_____ __ _(_)_ _ _ _ _ __ ___ _ __ _ _
277+
/ -_\ V | | |___\ V V | | ' \| '_| ' |___| '_ | || |
278+
\___|\_/|_|_| \_/\_/|_|_||_|_| |_|_|_| | .__/\_, |
279+
|_| |__/ v1.5.0
280+
281+
[*] Connecting to 'SQL.academy.ninja.lan:5985' as 'Administrator'
282+
evil-winrm-py PS C:\Users\Administrator.SQL\Documents>
283+
```
284+
285+
## Final Thoughts
286+
287+
Turning an old desktop into a fully automated Active Directory cyber range has been one of the most satisfying upgrades to my homelab so far. With Proxmox handling the virtualization and Ludus orchestrating everything, I now have a modern, customizable environment for testing scenarios, experimenting with configurations, and learning in a safe space.

0 commit comments

Comments
 (0)