Skip to content

Commit f91e1d6

Browse files
authored
Merge pull request #36 from Fortiphyd/add-wazuh-siem
Add wazuh siem
2 parents 3f1f225 + ab857b4 commit f91e1d6

22 files changed

Lines changed: 499 additions & 24 deletions

README.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ this is for you.
3636
* **End-to-end OT / ICS security lab** — PLCs, HMIs, engineering workstations, routers, and attacker tools
3737
* **3D process visualization** — watch tank levels and valves respond in real time
3838
* **Virtual Walkthroughs** — explore the warehouse in first person, observing physical layouts and security lapses
39-
* **Built-in attack & defense tools** — Kali Linux, MITRE Caldera, and a custom firewall and Suricata IDS interface
39+
* **Built-in attack & defense tools** — Kali Linux, MITRE Caldera, a custom firewall and Suricata IDS interface, and an optional Wazuh SIEM
4040
* **Modular, containerized design** — launch everything with a single `docker compose up`
4141
* **Realistic networking** — segmented process and enterprise zones with controllable traffic flow
4242

@@ -183,6 +183,23 @@ you should see the 3D chemical plant simulation come to life.
183183
docker compose start
184184
```
185185

186+
### Optional: Wazuh SIEM
187+
188+
Wazuh is disabled by default (it adds ~3–4 GB and significant startup time). To include it:
189+
190+
```bash
191+
docker compose --profile siem up -d
192+
```
193+
194+
To stop it later, make sure to include the profile in the down command:
195+
196+
```bash
197+
docker compose --profile siem down
198+
```
199+
200+
Once running, the Wazuh dashboard is available at [http://localhost:5601](http://localhost:5601) (`admin` / `admin`).
201+
Agents installed on the router and ScadaLTS containers will automatically connect and begin forwarding logs.
202+
186203
---
187204

188205
## Core Containers & Access Points
@@ -196,6 +213,7 @@ you should see the 3D chemical plant simulation come to life.
196213
| **PLC (OpenPLC)** | [http://localhost:8080](http://localhost:8080) or `192.168.95.2:8080` | `openplc : openplc` | Programmable logic controller |
197214
| **HMI** | [http://localhost:6081](http://localhost:6081) or `192.168.90.107:8080` | `admin : admin` | Operator interface |
198215
| **Router / Firewall UI** | `192.168.90.200:5000` or `192.168.95.200:5000` | `admin : password` | View or modify firewall rules |
216+
| **Wazuh SIEM** *(optional)* | [http://localhost:5601](http://localhost:5601) | `admin : admin` | SIEM dashboard — security events, alerts |
199217

200218

201219
---

docker-compose.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,28 @@ services:
136136
c-dmz-net:
137137
ipv4_address: 192.168.90.250
138138

139+
wazuh:
140+
profiles: [siem]
141+
image: fortiphyd/grfics-wazuh
142+
container_name: wazuh
143+
hostname: wazuh
144+
build: ./wazuh
145+
restart: unless-stopped
146+
ports:
147+
- "1514:1514" # Wazuh agent enrollment
148+
- "1515:1515" # Wazuh agent communication
149+
- "55000:55000" # Wazuh REST API
150+
- "5601:5601" # Dashboard HTTP
151+
cap_add:
152+
- NET_ADMIN
153+
volumes:
154+
- wazuh_manager_data:/var/ossec
155+
- wazuh_indexer_data:/var/lib/wazuh-indexer
156+
networks:
157+
a-grfics-admin:
158+
c-dmz-net:
159+
ipv4_address: 192.168.90.20
160+
139161
networks:
140162
b-ics-net:
141163
driver: macvlan
@@ -166,3 +188,7 @@ volumes:
166188
name: plc_volume
167189
router_config:
168190
name: router_config
191+
wazuh_manager_data:
192+
name: wazuh_manager_data
193+
wazuh_indexer_data:
194+
name: wazuh_indexer_data

router/Dockerfile

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,27 @@ RUN apt-get update && apt-get install -y supervisor suricata && \
1818
# Enable IP forwarding
1919
RUN echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
2020

21+
# Fake systemctl so wazuh-agent postinstall doesn't fail
22+
RUN printf '#!/bin/bash\necho "[fake-systemctl] $@"\nexit 0\n' \
23+
> /usr/local/bin/systemctl && chmod +x /usr/local/bin/systemctl
24+
25+
# Install Wazuh agent
26+
RUN apt-get update && apt-get install -y --no-install-recommends gnupg \
27+
&& curl -s https://packages.wazuh.com/key/GPG-KEY-WAZUH \
28+
| gpg --no-default-keyring \
29+
--keyring gnupg-ring:/usr/share/keyrings/wazuh.gpg --import \
30+
&& chmod 644 /usr/share/keyrings/wazuh.gpg \
31+
&& echo "deb [signed-by=/usr/share/keyrings/wazuh.gpg] \
32+
https://packages.wazuh.com/4.x/apt/ stable main" \
33+
> /etc/apt/sources.list.d/wazuh.list \
34+
&& apt-get update \
35+
&& WAZUH_MANAGER=192.168.90.20 WAZUH_AGENT_NAME=router apt-get install -y wazuh-agent \
36+
&& rm -rf /var/lib/apt/lists/*
37+
38+
# Tell the agent to monitor Suricata alerts-only EVE log
39+
RUN sed -i 's|</ossec_config>|<localfile>\n <log_format>json</log_format>\n <location>/var/log/suricata/alerts.json</location>\n </localfile>\n</ossec_config>|' \
40+
/var/ossec/etc/ossec.conf
41+
2142
COPY entrypoint.sh /entrypoint.sh
2243
COPY app.py /opt/fwui/app.py
2344
COPY index.html /opt/fwui/templates/index.html
@@ -27,6 +48,10 @@ COPY ids.html /opt/fwui/templates/ids.html
2748
COPY base.html /opt/fwui/templates/base.html
2849
COPY router.conf /etc/supervisor/conf.d/router.conf
2950
COPY suricata.yaml /etc/suricata/suricata.yaml
51+
52+
# Add DigitalBond Quickdraw ICS/SCADA detection rules
53+
RUN curl -fsSL https://raw.githubusercontent.com/digitalbond/Quickdraw-Snort/refs/heads/master/all-quickdraw.rules \
54+
-o /etc/suricata/rules/quickdraw.rules
3055
COPY ulogd.conf /etc/ulogd.conf
3156

3257

router/entrypoint.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,11 @@ iptables -P FORWARD ACCEPT
99
ip -c addr
1010
ip route show
1111

12+
if getent hosts wazuh >/dev/null 2>&1; then
13+
/var/ossec/bin/wazuh-control start || true
14+
else
15+
echo "[router] Wazuh not in DNS, skipping agent start"
16+
fi
17+
1218
# Keep container running and provide a shell via exec
1319
exec "$@"

router/suricata.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,14 @@ outputs:
8383
append: yes
8484
#filetype: regular # 'regular', 'unix_stream' or 'unix_dgram'
8585

86+
# Alerts-only EVE log for Wazuh agent
87+
- eve-log:
88+
enabled: yes
89+
filetype: regular
90+
filename: alerts.json
91+
types:
92+
- alert
93+
8694
# Extensible Event Format (nicknamed EVE) event log in JSON format
8795
- eve-log:
8896
enabled: yes

scadalts/Dockerfile

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,14 @@ ENV SCADA_LTS_VERSION=2.7.8.1 \
99
TOMCAT_USER=tcuser \
1010
TOMCAT_PASSWORD=tcuser
1111

12+
# Fake systemctl so wazuh-agent postinstall doesn't fail
13+
RUN printf '#!/bin/bash\necho "[fake-systemctl] $@"\nexit 0\n' \
14+
> /usr/local/bin/systemctl && chmod +x /usr/local/bin/systemctl
15+
1216
# Install dependencies
1317
RUN apt-get update && \
14-
apt-get install -y wget unzip supervisor mariadb-server libjaxb-api-java libjaxb-java libactivation-java && \
18+
apt-get install -y wget unzip supervisor mariadb-server libjaxb-api-java libjaxb-java libactivation-java \
19+
gnupg curl && \
1520
rm -rf /var/lib/apt/lists/*
1621

1722

@@ -39,9 +44,10 @@ RUN wget https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-j-8.3.0
3944
mv /tmp/mysql-connector-j-8.3.0/mysql-connector-j-8.3.0.jar $CATALINA_HOME/lib/ && \
4045
rm -rf /tmp/mysql-connector*
4146

42-
# Prepare runtime dirs
43-
RUN mkdir -p /var/lib/mysql /run/mysqld /var/log/supervisor && \
44-
chown -R mysql:mysql /var/lib/mysql /run/mysqld
47+
# Prepare runtime dirs and enable MariaDB error log
48+
RUN mkdir -p /var/lib/mysql /run/mysqld /var/log/supervisor /var/log/mysql && \
49+
chown -R mysql:mysql /var/lib/mysql /run/mysqld /var/log/mysql && \
50+
printf '[mysqld]\nlog_error=/var/log/mysql/error.log\n' > /etc/mysql/conf.d/logging.cnf
4551
VOLUME /var/lib/mysql
4652

4753
# Add configs
@@ -66,6 +72,22 @@ RUN sed -i '/<\/Context>/i \
6672
COPY 1.png /usr/local/tomcat/static/uploads/1.png
6773
COPY seed_project_data.sql /seed_project_data.sql
6874

75+
# Install Wazuh agent
76+
RUN curl -s https://packages.wazuh.com/key/GPG-KEY-WAZUH \
77+
| gpg --no-default-keyring \
78+
--keyring gnupg-ring:/usr/share/keyrings/wazuh.gpg --import \
79+
&& chmod 644 /usr/share/keyrings/wazuh.gpg \
80+
&& echo "deb [signed-by=/usr/share/keyrings/wazuh.gpg] \
81+
https://packages.wazuh.com/4.x/apt/ stable main" \
82+
> /etc/apt/sources.list.d/wazuh.list \
83+
&& apt-get update \
84+
&& WAZUH_MANAGER=192.168.90.20 WAZUH_AGENT_NAME=scadalts apt-get install -y wazuh-agent \
85+
&& rm -rf /var/lib/apt/lists/*
86+
87+
# Monitor Tomcat catalina log, access logs, and MariaDB error log
88+
RUN sed -i 's|</ossec_config>|<localfile>\n <log_format>syslog</log_format>\n <location>/usr/local/tomcat/logs/catalina.out</location>\n </localfile>\n <localfile>\n <log_format>syslog</log_format>\n <location>/usr/local/tomcat/logs/localhost_access_log*.txt</location>\n </localfile>\n <localfile>\n <log_format>syslog</log_format>\n <location>/var/log/mysql/error.log</location>\n </localfile>\n</ossec_config>|' \
89+
/var/ossec/etc/ossec.conf
90+
6991
EXPOSE 8080 3306
7092

7193
CMD ["/usr/bin/supervisord", "-n"]

scadalts/init.sh

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,14 @@ PROC_EXISTS=$(mariadb -uscada -pscada scadalts -N -B -e \
3131
WHERE ROUTINE_SCHEMA='scadalts' AND ROUTINE_TYPE='PROCEDURE'
3232
AND ROUTINE_NAME='prc_alarms_notify';" 2>/dev/null || echo 0)
3333

34-
echo "[*] Ensuring admin user exists..."
34+
echo "[*] Ensuring admin user is set up right"
3535
mariadb -uscada -pscada scadalts <<-EOSQL
3636
INSERT INTO users
37-
(id, username, password, email, phone, disabled, admin, receiveAlarmEmails, receiveOwnAuditEvents)
37+
(id, username, password, email, phone, disabled, admin, receiveAlarmEmails, receiveOwnAuditEvents, homeURL)
3838
SELECT
39-
4, 'admin', '0DPiKuNIrrVmD8IUCuw1hQxNqZc=', 'admin@example.com', '', 'N', 'Y', 0, 0
39+
4, 'admin', '0DPiKuNIrrVmD8IUCuw1hQxNqZc=', 'admin@example.com', '', 'N', 'Y', 0, 0, '/views.shtm#'
4040
WHERE NOT EXISTS (SELECT 1 FROM users WHERE username='admin');
4141
EOSQL
42-
4342
# Seed project
4443
VIEW_COUNT=$(mariadb -uscada -pscada scadalts -N -B -e "SELECT COUNT(*) FROM mangoViews;" 2>/dev/null || echo 0)
4544
if [ "$VIEW_COUNT" -eq 0 ] && [ -f /seed_project_data.sql ]; then
@@ -52,4 +51,4 @@ fi
5251

5352
ip route add 192.168.95.0/24 via 192.168.90.200 || true
5453

55-
exit 0
54+
exit 0

scadalts/seed_project_data.sql

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ UNLOCK TABLES;
4040
LOCK TABLES `dataSources` WRITE;
4141
/*!40000 ALTER TABLE `dataSources` DISABLE KEYS */;
4242
INSERT INTO `dataSources` VALUES
43-
(1,'DS_939670','TenEast',3,'¬í\0sr\0=com.serotonin.mango.vo.dataSource.modbus.ModbusIpDataSourceVOÿÿÿÿÿÿÿÿ\0Z\0createSocketMonitorPointZ\0 encapsulatedI\0portL\0hostt\0Ljava/lang/String;L\0\rtransportTypet\0MLcom/serotonin/mango/vo/dataSource/modbus/ModbusIpDataSourceVO$TransportType;xr\0;com.serotonin.mango.vo.dataSource.modbus.ModbusDataSourceVOÿÿÿÿÿÿÿÿ\0\nZ\0contiguousBatchesZ\0createSlaveMonitorPointsI\0maxReadBitCountI\0maxReadRegisterCountI\0maxWriteRegisterCountZ\0quantizeI\0retriesI\0timeoutI\0updatePeriodTypeI\0\rupdatePeriodsxr\0.com.serotonin.mango.vo.dataSource.DataSourceVOÿÿÿÿÿÿÿÿ\0Z\0enabledI\0idL\0 alarmLevelst\0Ljava/util/Map;L\0nameq\0~\0L\0statet\0!Lorg/scada_lts/ds/state/IStateDs;L\0xidq\0~\0xpw\0\0\0sr\0java.util.HashMapÚÁÃ`Ñ\0F\0\nloadFactorI\0 thresholdxp?@\0\0\0\0\0 w\0\0\0\0\0\0sr\0java.lang.Integerâ ¤÷‡8\0I\0valuexr\0java.lang.Number†¬• ”à‹\0\0xp\0\0\0sq\0~\0\n\0\0\0q\0~\0\rq\0~\0\rsq\0~\0\n\0\0\0q\0~\0\rxsr\00org.scada_lts.ds.state.ImportChangeEnableStateDs/›èt£}\0\0xpxw#\0\0\0\0\0\0\0\0\0\0\0\0ô\0\0\0\0\0\0\0Ð\0\0\0}\0\0\0xxw\0\0\0~r\0Kcom.serotonin.mango.vo.dataSource.modbus.ModbusIpDataSourceVO$TransportType\0\0\0\0\0\0\0\0\0\0xr\0java.lang.Enum\0\0\0\0\0\0\0\0\0\0xpt\0TCPw\0 192.168.95.2\0\0ö\0\0x');
43+
(1,'DS_939670','TenEast',3,'¬í\0sr\0=com.serotonin.mango.vo.dataSource.modbus.ModbusIpDataSourceVOÿÿÿÿÿÿÿÿ\0Z\0createSocketMonitorPointZ\0 encapsulatedI\0portL\0hostt\0Ljava/lang/String;L\0\rtransportTypet\0MLcom/serotonin/mango/vo/dataSource/modbus/ModbusIpDataSourceVO$TransportType;xr\0;com.serotonin.mango.vo.dataSource.modbus.ModbusDataSourceVOÿÿÿÿÿÿÿÿ\0\nZ\0contiguousBatchesZ\0createSlaveMonitorPointsI\0maxReadBitCountI\0maxReadRegisterCountI\0maxWriteRegisterCountZ\0quantizeI\0retriesI\0timeoutI\0updatePeriodTypeI\0\rupdatePeriodsxr\0.com.serotonin.mango.vo.dataSource.DataSourceVOÿÿÿÿÿÿÿÿ\0Z\0enabledI\0idL\0 alarmLevelst\0Ljava/util/Map;L\0nameq\0~\0L\0statet\0!Lorg/scada_lts/ds/state/IStateDs;L\0xidq\0~\0xpw\0\0\0sr\0java.util.HashMapÚÁÃ`Ñ\0F\0\nloadFactorI\0 thresholdxp?@\0\0\0\0\0 w\0\0\0\0\0\0sr\0java.lang.Integerâ ¤÷‡8\0I\0valuexr\0java.lang.Number†¬• ”à‹\0\0xp\0\0\0sq\0~\0\n\0\0\0q\0~\0\rq\0~\0\rsq\0~\0\n\0\0\0q\0~\0\rxsr\00org.scada_lts.ds.state.ImportChangeEnableStateDs/›èt£}\0\0xpxw#\0\0\0\0\0\0\0\0\0\0\0\0ô\0\0\0\0\0\0\0Ð\0\0\0}\0\0\0xxw\0\0\0~r\0Kcom.serotonin.mango.vo.dataSource.modbus.ModbusIpDataSourceVO$TransportType\0\0\0\0\0\0\0\0\0\0xr\0java.lang.Enum\0\0\0\0\0\0\0\0\0\0xpt\0TCP_KEEP_ALIVEw\0 192.168.95.2\0\0ö\0\0x');
4444
/*!40000 ALTER TABLE `dataSources` ENABLE KEYS */;
4545
UNLOCK TABLES;
4646

@@ -76,12 +76,12 @@ UNLOCK TABLES;
7676

7777
LOCK TABLES `users` WRITE;
7878
/*!40000 ALTER TABLE `users` DISABLE KEYS */;
79-
INSERT INTO `users` VALUES
80-
(5,'admin','0DPiKuNIrrVmD8IUCuw1hQxNqZc=','admin@example.com','','Y','N',1759943951402,1,NULL,0,'0'),
79+
/*INSERT INTO `users` VALUES
80+
(5,'admin','0DPiKuNIrrVmD8IUCuw1hQxNqZc=','admin@example.com','','Y','N',1759943951402,1,'views.shtm#/',0,'0'),
8181
(6,'anonymous-user','CpL6syMBNMym6t2YmDJbmyrmeZg=','anonymous@mail.com','','N','Y',NULL,NULL,'',0,'N'),
8282
(7,'soap-services','2SkKRrabStlFmaoIfVmqeJ17zIs=','soap-services@mail.com','','N','Y',NULL,NULL,'',0,'N'),
8383
(8,'httpds-basic','hZvP2jlFXX95l2MGyfpJEBQwc3U=','null@null.com','','N','Y',NULL,NULL,'',0,'N'),
84-
(9,'anonymous-user','CpL6syMBNMym6t2YmDJbmyrmeZg=','anonymous@mail.com','','N','Y',NULL,NULL,'',0,'N');
84+
(9,'anonymous-user','CpL6syMBNMym6t2YmDJbmyrmeZg=','anonymous@mail.com','','N','Y',NULL,NULL,'',0,'N');*/
8585
/*!40000 ALTER TABLE `users` ENABLE KEYS */;
8686
UNLOCK TABLES;
8787
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

scadalts/supervisord.conf

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,11 @@ command=/bin/bash -c "sleep 10 && /usr/local/tomcat/bin/catalina.sh run"
2222
autostart=true
2323
autorestart=true
2424
priority=10
25+
26+
[program:wazuh-agent]
27+
command=/bin/bash -c "if getent hosts wazuh >/dev/null 2>&1; then /var/ossec/bin/wazuh-control start; else echo '[scadalts] Wazuh not in DNS, skipping agent start'; fi; sleep infinity"
28+
autostart=true
29+
autorestart=false
30+
priority=20
31+
stdout_logfile=/var/log/supervisor/wazuh-agent.log
32+
stderr_logfile=/var/log/supervisor/wazuh-agent.err

simulation/entrypoint.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ IF=$(ip -o -4 addr show | awk '$4 ~ /^192\.168\.95\./ {print $2}' | head -n1)
77

88
echo "[entrypoint] Adding IP aliases to $IF manually..."
99

10+
ip addr add 192.168.95.10/24 dev "$IF"
1011
ip addr add 192.168.95.11/24 dev "$IF"
1112
ip addr add 192.168.95.12/24 dev "$IF"
1213
ip addr add 192.168.95.13/24 dev "$IF"

0 commit comments

Comments
 (0)