From 089d80427ac80bf21e5a309b7b16e200c2d2b2e7 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Wed, 25 Sep 2019 09:16:30 -0400 Subject: [PATCH 001/200] Fleet - New Docker env var for path prefix --- salt/fleet/init.sls | 1 + 1 file changed, 1 insertion(+) diff --git a/salt/fleet/init.sls b/salt/fleet/init.sls index 83c019880..8284dbe91 100644 --- a/salt/fleet/init.sls +++ b/salt/fleet/init.sls @@ -83,6 +83,7 @@ so-fleet: - KOLIDE_AUTH_JWT_KEY=thisisatest - KOLIDE_OSQUERY_STATUS_LOG_FILE=/var/log/osquery/status.log - KOLIDE_OSQUERY_RESULT_LOG_FILE=/var/log/osquery/result.log + - KOLIDE_SERVER_URL_PREFIX=/fleet - binds: - /etc/pki/fleet.key:/ssl/server.key:ro - /etc/pki/fleet.crt:/ssl/server.cert:ro From ca4cd782a1413788736c456e026f8a31d7f9d8b7 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Wed, 16 Oct 2019 10:39:18 -0400 Subject: [PATCH 002/200] Docker URL Fix - Issue #68 --- salt/bro/init.sls | 8 ++++---- salt/common/init.sls | 16 ++++++++-------- salt/curator/init.sls | 4 ++-- salt/elastalert/init.sls | 4 ++-- salt/elasticsearch/init.sls | 12 ++++++------ salt/filebeat/init.sls | 4 ++-- salt/fleet/init.sls | 4 ++-- salt/fleet/so-fleet-setup.sh | 2 +- salt/hive/init.sls | 10 +++++----- salt/idstools/init.sls | 4 ++-- salt/kibana/init.sls | 4 ++-- salt/logstash/init.sls | 4 ++-- salt/master/init.sls | 4 ++-- salt/mysql/init.sls | 4 ++-- salt/pcap/init.sls | 4 ++-- salt/playbook/init.sls | 8 ++++---- salt/redis/init.sls | 4 ++-- salt/sensoroni/init.sls | 4 ++-- salt/soctopus/init.sls | 4 ++-- salt/suricata/init.sls | 4 ++-- salt/wazuh/init.sls | 4 ++-- 21 files changed, 58 insertions(+), 58 deletions(-) diff --git a/salt/bro/init.sls b/salt/bro/init.sls index f406558be..2e6f10f3c 100644 --- a/salt/bro/init.sls +++ b/salt/bro/init.sls @@ -92,13 +92,13 @@ localbrosync: so-communitybroimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-communitybro:HH1.0.3 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-communitybro:HH1.0.3 so-bro: docker_container.running: - require: - so-communitybroimage - - image: soshybridhunter/so-communitybro:HH1.0.3 + - image: docker.io/soshybridhunter/so-communitybro:HH1.0.3 - privileged: True - binds: - /nsm/bro/logs:/nsm/bro/logs:rw @@ -125,13 +125,13 @@ localbrosync: so-broimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-bro:HH1.1.1 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-bro:HH1.1.1 so-bro: docker_container.running: - require: - so-broimage - - image: soshybridhunter/so-bro:HH1.1.1 + - image: docker.io/soshybridhunter/so-bro:HH1.1.1 - privileged: True - binds: - /nsm/bro/logs:/nsm/bro/logs:rw diff --git a/salt/common/init.sls b/salt/common/init.sls index 9d34c4a20..1bba4c871 100644 --- a/salt/common/init.sls +++ b/salt/common/init.sls @@ -116,13 +116,13 @@ nginxtmp: # Start the core docker so-coreimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-core:HH1.1.2 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-core:HH1.1.2 so-core: docker_container.running: - require: - so-coreimage - - image: soshybridhunter/so-core:HH1.1.2 + - image: docker.io/soshybridhunter/so-core:HH1.1.2 - hostname: so-core - user: socore - binds: @@ -176,13 +176,13 @@ tgrafconf: so-telegrafimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-telegraf:HH1.1.0 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-telegraf:HH1.1.0 so-telegraf: docker_container.running: - require: - so-telegrafimage - - image: soshybridhunter/so-telegraf:HH1.1.0 + - image: docker.io/soshybridhunter/so-telegraf:HH1.1.0 - environment: - HOST_PROC=/host/proc - HOST_ETC=/host/etc @@ -237,13 +237,13 @@ influxdbconf: so-influximage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-influxdb:HH1.1.0 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-influxdb:HH1.1.0 so-influxdb: docker_container.running: - require: - so-influximage - - image: soshybridhunter/so-influxdb:HH1.1.0 + - image: docker.io/soshybridhunter/so-influxdb:HH1.1.0 - hostname: influxdb - environment: - INFLUXDB_HTTP_LOG_ENABLED=false @@ -402,11 +402,11 @@ dashboard-{{ SN }}: # Install the docker. This needs to be behind nginx at some point so-grafanaimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-grafana:HH1.1.0 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-grafana:HH1.1.0 so-grafana: docker_container.running: - - image: soshybridhunter/so-grafana:HH1.1.0 + - image: docker.io/soshybridhunter/so-grafana:HH1.1.0 - hostname: grafana - user: socore - binds: diff --git a/salt/curator/init.sls b/salt/curator/init.sls index 5c788b891..74dd47a99 100644 --- a/salt/curator/init.sls +++ b/salt/curator/init.sls @@ -114,13 +114,13 @@ curdel: so-curatorimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-curator:HH1.1.0 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-curator:HH1.1.0 so-curator: docker_container.running: - require: - so-curatorimage - - image: soshybridhunter/so-curator:HH1.1.0 + - image: docker.io/soshybridhunter/so-curator:HH1.1.0 - hostname: curator - name: so-curator - user: curator diff --git a/salt/elastalert/init.sls b/salt/elastalert/init.sls index 8e8b32ae6..999bbbd91 100644 --- a/salt/elastalert/init.sls +++ b/salt/elastalert/init.sls @@ -111,13 +111,13 @@ elastaconf: so-elastalertimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-elastalert:HH1.1.1 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-elastalert:HH1.1.1 so-elastalert: docker_container.running: - require: - so-elastalertimage - - image: soshybridhunter/so-elastalert:HH1.1.1 + - image: docker.io/soshybridhunter/so-elastalert:HH1.1.1 - hostname: elastalert - name: so-elastalert - user: elastalert diff --git a/salt/elasticsearch/init.sls b/salt/elasticsearch/init.sls index 1eb3a19e4..8ff9606bc 100644 --- a/salt/elasticsearch/init.sls +++ b/salt/elasticsearch/init.sls @@ -92,13 +92,13 @@ eslogdir: so-elasticsearchimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-elasticsearch:HH1.1.0 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-elasticsearch:HH1.1.0 so-elasticsearch: docker_container.running: - require: - so-elasticsearchimage - - image: soshybridhunter/so-elasticsearch:HH1.1.0 + - image: docker.io/soshybridhunter/so-elasticsearch:HH1.1.0 - hostname: elasticsearch - name: so-elasticsearch - user: elasticsearch @@ -155,13 +155,13 @@ freqlogdir: so-freqimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-freqserver:HH1.0.3 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-freqserver:HH1.0.3 so-freq: docker_container.running: - require: - so-freqimage - - image: soshybridhunter/so-freqserver:HH1.0.3 + - image: docker.io/soshybridhunter/so-freqserver:HH1.0.3 - hostname: freqserver - name: so-freqserver - user: freqserver @@ -197,13 +197,13 @@ dstatslogdir: so-domainstatsimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-domainstats:HH1.0.3 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-domainstats:HH1.0.3 so-domainstats: docker_container.running: - require: - so-domainstatsimage - - image: soshybridhunter/so-domainstats:HH1.0.3 + - image: docker.io/soshybridhunter/so-domainstats:HH1.0.3 - hostname: domainstats - name: so-domainstats - user: domainstats diff --git a/salt/filebeat/init.sls b/salt/filebeat/init.sls index b92899ef0..b1acae649 100644 --- a/salt/filebeat/init.sls +++ b/salt/filebeat/init.sls @@ -58,13 +58,13 @@ filebeatconfsync: so-filebeatimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-filebeat:HH1.1.1 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-filebeat:HH1.1.1 so-filebeat: docker_container.running: - require: - so-filebeatimage - - image: soshybridhunter/so-filebeat:HH1.1.1 + - image: docker.io/soshybridhunter/so-filebeat:HH1.1.1 - hostname: so-filebeat - user: root - extra_hosts: {{ MASTER }}:{{ MASTERIP }} diff --git a/salt/fleet/init.sls b/salt/fleet/init.sls index 83c019880..e633bef7f 100644 --- a/salt/fleet/init.sls +++ b/salt/fleet/init.sls @@ -61,13 +61,13 @@ fleetdbpriv: so-fleetimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-fleet:HH1.1.0 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-fleet:HH1.1.0 so-fleet: docker_container.running: - require: - so-fleetimage - - image: soshybridhunter/so-fleet:HH1.1.0 + - image: docker.io/soshybridhunter/so-fleet:HH1.1.0 - hostname: so-fleet - port_bindings: - 0.0.0.0:8080:8080 diff --git a/salt/fleet/so-fleet-setup.sh b/salt/fleet/so-fleet-setup.sh index 7691b1eb2..5f6dcb949 100644 --- a/salt/fleet/so-fleet-setup.sh +++ b/salt/fleet/so-fleet-setup.sh @@ -29,7 +29,7 @@ docker run \ --rm \ --mount type=bind,source=/opt/so/conf/fleet/packages,target=/output \ --mount type=bind,source=/etc/pki/launcher.crt,target=/var/launcher/launcher.crt \ - soshybridhunter/so-fleet-launcher:HH1.1.0 "$esecret" "$1":8080 + docker.io/soshybridhunter/so-fleet-launcher:HH1.1.0 "$esecret" "$1":8080 cp /opt/so/conf/fleet/packages/launcher.* /opt/so/saltstack/salt/launcher/packages/ #Update timestamp on packages webpage diff --git a/salt/hive/init.sls b/salt/hive/init.sls index 5897f6a93..ced11c6ff 100644 --- a/salt/hive/init.sls +++ b/salt/hive/init.sls @@ -33,13 +33,13 @@ hiveesdata: so-thehive-esimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-thehive-es:HH1.1.1 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-thehive-es:HH1.1.1 so-thehive-es: docker_container.running: - require: - so-thehive-esimage - - image: soshybridhunter/so-thehive-es:HH1.1.1 + - image: docker.io/soshybridhunter/so-thehive-es:HH1.1.1 - hostname: so-thehive-es - name: so-thehive-es - user: 939 @@ -68,7 +68,7 @@ so-thehive-es: #so-corteximage: # cmd.run: -# - name: docker pull --disable-content-trust=false soshybridhunter/so-cortex:HH1.0.3 +# - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-cortex:HH1.0.3 #so-cortex: # docker_container.running: @@ -80,13 +80,13 @@ so-thehive-es: so-thehiveimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-thehive:HH1.1.1 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-thehive:HH1.1.1 so-thehive: docker_container.running: - require: - so-thehiveimage - - image: soshybridhunter/so-thehive:HH1.1.1 + - image: docker.io/soshybridhunter/so-thehive:HH1.1.1 - environment: - ELASTICSEARCH_HOST={{ MASTERIP }} - hostname: so-thehive diff --git a/salt/idstools/init.sls b/salt/idstools/init.sls index cabd0ee73..9ec6f53f7 100644 --- a/salt/idstools/init.sls +++ b/salt/idstools/init.sls @@ -63,13 +63,13 @@ ruleslink: so-idstoolsimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-idstools:HH1.1.0 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-idstools:HH1.1.0 so-idstools: docker_container.running: - require: - so-idstoolsimage - - image: soshybridhunter/so-idstools:HH1.1.0 + - image: docker.io/soshybridhunter/so-idstools:HH1.1.0 - hostname: so-idstools - user: socore - binds: diff --git a/salt/kibana/init.sls b/salt/kibana/init.sls index 26910b5b0..0d6262600 100644 --- a/salt/kibana/init.sls +++ b/salt/kibana/init.sls @@ -56,14 +56,14 @@ synckibanacustom: so-kibanaimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-kibana:HH1.1.1 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-kibana:HH1.1.1 # Start the kibana docker so-kibana: docker_container.running: - require: - so-kibanaimage - - image: soshybridhunter/so-kibana:HH1.1.1 + - image: docker.io/soshybridhunter/so-kibana:HH1.1.1 - hostname: kibana - user: kibana - environment: diff --git a/salt/logstash/init.sls b/salt/logstash/init.sls index 589d22d1c..ee13db281 100644 --- a/salt/logstash/init.sls +++ b/salt/logstash/init.sls @@ -148,13 +148,13 @@ lslogdir: # Add the container so-logstashimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-logstash:HH1.1.1 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-logstash:HH1.1.1 so-logstash: docker_container.running: - require: - so-logstashimage - - image: soshybridhunter/so-logstash:HH1.1.1 + - image: docker.io/soshybridhunter/so-logstash:HH1.1.1 - hostname: so-logstash - name: so-logstash - user: logstash diff --git a/salt/master/init.sls b/salt/master/init.sls index 8b68a3cf1..1a7efe744 100644 --- a/salt/master/init.sls +++ b/salt/master/init.sls @@ -48,14 +48,14 @@ acngcopyconf: so-acngimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-acng:HH1.1.0 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-acng:HH1.1.0 # Install the apt-cacher-ng container so-aptcacherng: docker_container.running: - require: - so-acngimage - - image: soshybridhunter/so-acng:HH1.1.0 + - image: docker.io/soshybridhunter/so-acng:HH1.1.0 - hostname: so-acng - port_bindings: - 0.0.0.0:3142:3142 diff --git a/salt/mysql/init.sls b/salt/mysql/init.sls index 4ade15f33..a0136ae9b 100644 --- a/salt/mysql/init.sls +++ b/salt/mysql/init.sls @@ -50,13 +50,13 @@ mysqldatadir: so-mysqlimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-mysql:HH1.1.0 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-mysql:HH1.1.0 so-mysql: docker_container.running: - require: - so-mysqlimage - - image: soshybridhunter/so-mysql:HH1.1.0 + - image: docker.io/soshybridhunter/so-mysql:HH1.1.0 - hostname: so-mysql - user: socore - port_bindings: diff --git a/salt/pcap/init.sls b/salt/pcap/init.sls index 86408c0e3..ed23cf308 100644 --- a/salt/pcap/init.sls +++ b/salt/pcap/init.sls @@ -96,13 +96,13 @@ stenolog: so-stenoimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-steno:HH1.1.1 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-steno:HH1.1.1 so-steno: docker_container.running: - require: - so-stenoimage - - image: soshybridhunter/so-steno:HH1.1.1 + - image: docker.io/soshybridhunter/so-steno:HH1.1.1 - network_mode: host - privileged: True - port_bindings: diff --git a/salt/playbook/init.sls b/salt/playbook/init.sls index a72514fe9..ef66966f3 100644 --- a/salt/playbook/init.sls +++ b/salt/playbook/init.sls @@ -26,13 +26,13 @@ navigatorconfig: so-playbookimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-playbook:HH1.1.1 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-playbook:HH1.1.1 so-playbook: docker_container.running: - require: - so-playbookimage - - image: soshybridhunter/so-playbook:HH1.1.1 + - image: docker.io/soshybridhunter/so-playbook:HH1.1.1 - hostname: playbook - name: so-playbook - binds: @@ -42,13 +42,13 @@ so-playbook: so-navigatorimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-navigator:HH1.1.1 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-navigator:HH1.1.1 so-navigator: docker_container.running: - require: - so-navigatorimage - - image: soshybridhunter/so-navigator:HH1.1.1 + - image: docker.io/soshybridhunter/so-navigator:HH1.1.1 - hostname: navigator - name: so-navigator - binds: diff --git a/salt/redis/init.sls b/salt/redis/init.sls index 174c1725b..18178ce3b 100644 --- a/salt/redis/init.sls +++ b/salt/redis/init.sls @@ -46,13 +46,13 @@ redisconfsync: so-redisimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-redis:HH1.1.0 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-redis:HH1.1.0 so-redis: docker_container.running: - require: - so-redisimage - - image: soshybridhunter/so-redis:HH1.1.0 + - image: docker.io/soshybridhunter/so-redis:HH1.1.0 - hostname: so-redis - user: socore - port_bindings: diff --git a/salt/sensoroni/init.sls b/salt/sensoroni/init.sls index 2c06ba7a8..245c34344 100644 --- a/salt/sensoroni/init.sls +++ b/salt/sensoroni/init.sls @@ -29,13 +29,13 @@ sensoronisync: so-sensoroniimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-sensoroni:HH1.1.1 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-sensoroni:HH1.1.1 so-sensoroni: docker_container.running: - require: - so-sensoroniimage - - image: soshybridhunter/so-sensoroni:HH1.1.1 + - image: docker.io/soshybridhunter/so-sensoroni:HH1.1.1 - hostname: sensoroni - name: so-sensoroni - binds: diff --git a/salt/soctopus/init.sls b/salt/soctopus/init.sls index 98a9a4158..ebfbe3224 100644 --- a/salt/soctopus/init.sls +++ b/salt/soctopus/init.sls @@ -40,13 +40,13 @@ navigatordefaultlayer: so-soctopusimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-soctopus:HH1.1.1 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-soctopus:HH1.1.1 so-soctopus: docker_container.running: - require: - so-soctopusimage - - image: soshybridhunter/so-soctopus:HH1.1.1 + - image: docker.io/soshybridhunter/so-soctopus:HH1.1.1 - hostname: soctopus - name: so-soctopus - binds: diff --git a/salt/suricata/init.sls b/salt/suricata/init.sls index 2c3b1aba8..a30010d5e 100644 --- a/salt/suricata/init.sls +++ b/salt/suricata/init.sls @@ -72,13 +72,13 @@ suriconfigsync: so-suricataimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-suricata:HH1.1.1 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-suricata:HH1.1.1 so-suricata: docker_container.running: - require: - so-suricataimage - - image: soshybridhunter/so-suricata:HH1.1.1 + - image: docker.io/soshybridhunter/so-suricata:HH1.1.1 - privileged: True - environment: - INTERFACE={{ interface }} diff --git a/salt/wazuh/init.sls b/salt/wazuh/init.sls index b83240dfa..3169efd3f 100644 --- a/salt/wazuh/init.sls +++ b/salt/wazuh/init.sls @@ -64,13 +64,13 @@ wazuhagentregister: so-wazuhimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-wazuh:HH1.1.0 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-wazuh:HH1.1.0 so-wazuh: docker_container.running: - require: - so-wazuhimage - - image: soshybridhunter/so-wazuh:HH1.1.0 + - image: docker.io/soshybridhunter/so-wazuh:HH1.1.0 - hostname: {{HOSTNAME}}-wazuh-manager - name: so-wazuh - detach: True From 776cc8952037db69ea6f998e127fd6c3c141d6a3 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Wed, 16 Oct 2019 11:22:54 -0400 Subject: [PATCH 003/200] Filebeat Module - Issue 61 --- salt/filebeat/etc/filebeat.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/filebeat/etc/filebeat.yml b/salt/filebeat/etc/filebeat.yml index f0d3a8587..63e2dff6b 100644 --- a/salt/filebeat/etc/filebeat.yml +++ b/salt/filebeat/etc/filebeat.yml @@ -12,7 +12,7 @@ name: {{ HOSTNAME }} # Sets log level. The default log level is info. # Available log levels are: error, warning, info, debug -logging.level: debug +logging.level: error # Enable debug output for selected components. To enable all selectors use ["*"] # Other available selectors are "beat", "publish", "service" From 792cc7d4c40929a4d8b98b1273321aed1f2be4d4 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 21 Oct 2019 17:04:18 -0400 Subject: [PATCH 004/200] SSL Issue 79 - Reduce valid time --- salt/ca/files/signing_policies.conf | 10 +++++----- salt/ssl/init.sls | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/salt/ca/files/signing_policies.conf b/salt/ca/files/signing_policies.conf index a6ecdd4c3..379cc514d 100644 --- a/salt/ca/files/signing_policies.conf +++ b/salt/ca/files/signing_policies.conf @@ -10,7 +10,7 @@ x509_signing_policies: - keyUsage: "digitalSignature, nonRepudiation" - subjectKeyIdentifier: hash - authorityKeyIdentifier: keyid,issuer:always - - days_valid: 3000 + - days_valid: 820 - copypath: /etc/pki/issued_certs/ registry: - minions: '*' @@ -23,7 +23,7 @@ x509_signing_policies: - keyUsage: "critical keyEncipherment" - subjectKeyIdentifier: hash - authorityKeyIdentifier: keyid,issuer:always - - days_valid: 3000 + - days_valid: 820 - copypath: /etc/pki/issued_certs/ masterssl: - minions: '*' @@ -36,7 +36,7 @@ x509_signing_policies: - keyUsage: "critical keyEncipherment" - subjectKeyIdentifier: hash - authorityKeyIdentifier: keyid,issuer:always - - days_valid: 3000 + - days_valid: 820 - copypath: /etc/pki/issued_certs/ influxdb: - minions: '*' @@ -49,7 +49,7 @@ x509_signing_policies: - keyUsage: "critical keyEncipherment" - subjectKeyIdentifier: hash - authorityKeyIdentifier: keyid,issuer:always - - days_valid: 3000 + - days_valid: 820 - copypath: /etc/pki/issued_certs/ fleet: - minions: '*' @@ -62,5 +62,5 @@ x509_signing_policies: - keyUsage: "critical keyEncipherment" - subjectKeyIdentifier: hash - authorityKeyIdentifier: keyid,issuer:always - - days_valid: 3000 + - days_valid: 820 - copypath: /etc/pki/issued_certs/ diff --git a/salt/ssl/init.sls b/salt/ssl/init.sls index 841fc32ff..134cee9a0 100644 --- a/salt/ssl/init.sls +++ b/salt/ssl/init.sls @@ -25,7 +25,7 @@ m2cryptopkgs: - public_key: /etc/pki/influxdb.key - CN: {{ master }} - days_remaining: 0 - - days_valid: 3650 + - days_valid: 820 - backup: True - managed_private_key: name: /etc/pki/influxdb.key @@ -42,7 +42,7 @@ m2cryptopkgs: - public_key: /etc/pki/filebeat.key - CN: {{ master }} - days_remaining: 0 - - days_valid: 3650 + - days_valid: 820 - backup: True - managed_private_key: name: /etc/pki/filebeat.key @@ -75,7 +75,7 @@ fbcrtlink: - public_key: /etc/pki/registry.key - CN: {{ master }} - days_remaining: 0 - - days_valid: 3650 + - days_valid: 820 - backup: True - managed_private_key: name: /etc/pki/registry.key @@ -90,7 +90,7 @@ fbcrtlink: - public_key: /etc/pki/masterssl.key - CN: {{ master }} - days_remaining: 0 - - days_valid: 3650 + - days_valid: 820 - backup: True - managed_private_key: name: /etc/pki/masterssl.key @@ -103,7 +103,7 @@ fbcrtlink: - CN: {{ master }} - bits: 4096 - days_remaining: 0 - - days_valid: 3650 + - days_valid: 820 - backup: True /etc/pki/fleet.crt: @@ -112,7 +112,7 @@ fbcrtlink: - CN: {{ master }} - subjectAltName: DNS:{{ master }},IP:{{ masterip }} - days_remaining: 0 - - days_valid: 3650 + - days_valid: 820 - backup: True - managed_private_key: name: /etc/pki/fleet.key @@ -135,7 +135,7 @@ fbcertdir: - public_key: /opt/so/conf/filebeat/etc/pki/filebeat.key - CN: {{ master }} - days_remaining: 0 - - days_valid: 3650 + - days_valid: 820 - backup: True - managed_private_key: name: /opt/so/conf/filebeat/etc/pki/filebeat.key From 06261b0b9a63d7b57072d577e406a87420e0501b Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 21 Oct 2019 17:54:09 -0400 Subject: [PATCH 005/200] SSL Issue 79 - Add extended type to all certs --- salt/ca/files/signing_policies.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/salt/ca/files/signing_policies.conf b/salt/ca/files/signing_policies.conf index 379cc514d..b0dd33868 100644 --- a/salt/ca/files/signing_policies.conf +++ b/salt/ca/files/signing_policies.conf @@ -36,6 +36,7 @@ x509_signing_policies: - keyUsage: "critical keyEncipherment" - subjectKeyIdentifier: hash - authorityKeyIdentifier: keyid,issuer:always + - extendedKeyUsage: serverAuth - days_valid: 820 - copypath: /etc/pki/issued_certs/ influxdb: From 3ecb6a7c3ff91e6ad50891cf3083ee804a9f9562 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 21 Oct 2019 17:55:06 -0400 Subject: [PATCH 006/200] SSL Issue 79 - Add extended type to all certs --- salt/ca/files/signing_policies.conf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/salt/ca/files/signing_policies.conf b/salt/ca/files/signing_policies.conf index b0dd33868..fb79a3cc2 100644 --- a/salt/ca/files/signing_policies.conf +++ b/salt/ca/files/signing_policies.conf @@ -10,6 +10,7 @@ x509_signing_policies: - keyUsage: "digitalSignature, nonRepudiation" - subjectKeyIdentifier: hash - authorityKeyIdentifier: keyid,issuer:always + - extendedKeyUsage: serverAuth - days_valid: 820 - copypath: /etc/pki/issued_certs/ registry: @@ -23,6 +24,7 @@ x509_signing_policies: - keyUsage: "critical keyEncipherment" - subjectKeyIdentifier: hash - authorityKeyIdentifier: keyid,issuer:always + - extendedKeyUsage: serverAuth - days_valid: 820 - copypath: /etc/pki/issued_certs/ masterssl: @@ -50,6 +52,7 @@ x509_signing_policies: - keyUsage: "critical keyEncipherment" - subjectKeyIdentifier: hash - authorityKeyIdentifier: keyid,issuer:always + - extendedKeyUsage: serverAuth - days_valid: 820 - copypath: /etc/pki/issued_certs/ fleet: @@ -63,5 +66,6 @@ x509_signing_policies: - keyUsage: "critical keyEncipherment" - subjectKeyIdentifier: hash - authorityKeyIdentifier: keyid,issuer:always + - extendedKeyUsage: serverAuth - days_valid: 820 - copypath: /etc/pki/issued_certs/ From 0f5c0373c52b3ff921f66acb5cb959f089062417 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Wed, 23 Oct 2019 15:27:31 -0400 Subject: [PATCH 007/200] SSL Issue 79 - Remove extensions from filebeat cert --- salt/ca/files/signing_policies.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/salt/ca/files/signing_policies.conf b/salt/ca/files/signing_policies.conf index fb79a3cc2..e253f8911 100644 --- a/salt/ca/files/signing_policies.conf +++ b/salt/ca/files/signing_policies.conf @@ -10,7 +10,6 @@ x509_signing_policies: - keyUsage: "digitalSignature, nonRepudiation" - subjectKeyIdentifier: hash - authorityKeyIdentifier: keyid,issuer:always - - extendedKeyUsage: serverAuth - days_valid: 820 - copypath: /etc/pki/issued_certs/ registry: From 504dd6559d8f7c168036baba90c3fa5937d14e01 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Thu, 24 Oct 2019 16:44:33 -0400 Subject: [PATCH 008/200] Default ssl to false --- salt/logstash/files/dynamic/0006_input_beats.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/logstash/files/dynamic/0006_input_beats.conf b/salt/logstash/files/dynamic/0006_input_beats.conf index df590b6a1..1a6b66bbe 100644 --- a/salt/logstash/files/dynamic/0006_input_beats.conf +++ b/salt/logstash/files/dynamic/0006_input_beats.conf @@ -1,7 +1,7 @@ input { beats { port => "5044" - ssl => true + ssl => false ssl_certificate_authorities => ["/usr/share/filebeat/ca.crt"] ssl_certificate => "/usr/share/logstash/filebeat.crt" ssl_key => "/usr/share/logstash/filebeat.key" From f6a8b192df4c175b37ffb15c238f2cee60052634 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 24 Oct 2019 18:45:33 -0400 Subject: [PATCH 009/200] Elastic Search State - Fix ingest to work with storage nodes --- salt/elasticsearch/init.sls | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/salt/elasticsearch/init.sls b/salt/elasticsearch/init.sls index 8ff9606bc..a0f8b65f1 100644 --- a/salt/elasticsearch/init.sls +++ b/salt/elasticsearch/init.sls @@ -60,6 +60,20 @@ esconfdir: - group: 939 - makedirs: True +esconfdir: + file.directory: + - name: /opt/so/conf/elasticsearch/ingest + - user: 930 + - group: 939 + - makedirs: True + +esingestconf: + file.recurse: + - name: /opt/so/conf/elasticsearch/ingest + - source: salt://elasticsearch/files/ingest + - user: 930 + - group: 939 + eslog4jfile: file.managed: - name: /opt/so/conf/elasticsearch/log4j2.properties @@ -121,9 +135,17 @@ so-elasticsearch: - /nsm/elasticsearch:/usr/share/elasticsearch/data:rw - /opt/so/log/elasticsearch:/var/log/elasticsearch:rw +so-elasticsearch-pipelines-file: + file.managed: + - name: /opt/so/conf/elasticsearch/files/so-elasticsearch-pipelines + - source: salt://elasticsearch/files/so-elasticsearch-pipelines + - user: 930 + - group: 939 + - mode: 754 + so-elasticsearch-pipelines: cmd.run: - - name: /opt/so/saltstack/salt/elasticsearch/files/so-elasticsearch-pipelines {{ esclustername }} + - name: /opt/so/conf/elasticsearch/so-elasticsearch-pipelines {{ esclustername }} # Tell the main cluster I am here #curl -XPUT http://\$ELASTICSEARCH_HOST:\$ELASTICSEARCH_PORT/_cluster/settings -H'Content-Type: application/json' -d '{"persistent": {"search": {"remote": {"$HOSTNAME": {"skip_unavailable": "true", "seeds": ["$DOCKER_INTERFACE:$REVERSE_PORT"]}}}}}' From c064121f49ab5bbb4cae9285299eb57642a6ffc9 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 24 Oct 2019 18:47:21 -0400 Subject: [PATCH 010/200] Elastic Search State - Fix ingest to work with storage nodes --- salt/elasticsearch/init.sls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/elasticsearch/init.sls b/salt/elasticsearch/init.sls index a0f8b65f1..c0a20bd93 100644 --- a/salt/elasticsearch/init.sls +++ b/salt/elasticsearch/init.sls @@ -60,7 +60,7 @@ esconfdir: - group: 939 - makedirs: True -esconfdir: +esingestdir: file.directory: - name: /opt/so/conf/elasticsearch/ingest - user: 930 From 20c4f15bbbb34afe6831583dc939b173944409aa Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 24 Oct 2019 18:51:32 -0400 Subject: [PATCH 011/200] Elastic Search State - Fix ingest to work with storage nodes --- salt/elasticsearch/init.sls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/elasticsearch/init.sls b/salt/elasticsearch/init.sls index c0a20bd93..6036d5da8 100644 --- a/salt/elasticsearch/init.sls +++ b/salt/elasticsearch/init.sls @@ -137,7 +137,7 @@ so-elasticsearch: so-elasticsearch-pipelines-file: file.managed: - - name: /opt/so/conf/elasticsearch/files/so-elasticsearch-pipelines + - name: /opt/so/conf/elasticsearch/so-elasticsearch-pipelines - source: salt://elasticsearch/files/so-elasticsearch-pipelines - user: 930 - group: 939 From 783a9cd102cfde272ab9c485b2248799a4e2d1ef Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Fri, 25 Oct 2019 09:51:04 -0400 Subject: [PATCH 012/200] Elastic Search State - Fix ingest to work with storage nodes --- salt/elasticsearch/files/so-elasticsearch-pipelines | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/elasticsearch/files/so-elasticsearch-pipelines b/salt/elasticsearch/files/so-elasticsearch-pipelines index c0dd44aa9..b1b6db158 100755 --- a/salt/elasticsearch/files/so-elasticsearch-pipelines +++ b/salt/elasticsearch/files/so-elasticsearch-pipelines @@ -19,7 +19,7 @@ ELASTICSEARCH_HOST=$1 ELASTICSEARCH_PORT=9200 # Define a default directory to load pipelines from -ELASTICSEARCH_INGEST_PIPELINES="/opt/so/saltstack/salt/elasticsearch/files/ingest/" +ELASTICSEARCH_INGEST_PIPELINES="/opt/so/conf/elasticsearch/ingest/" # Wait for ElasticSearch to initialize echo -n "Waiting for ElasticSearch..." @@ -39,7 +39,7 @@ while [[ "$COUNT" -le 240 ]]; do done if [ "$ELASTICSEARCH_CONNECTED" == "no" ]; then echo - echo -e "Connection attempt timed out. Unable to connect to ElasticSearch. \nPlease try: \n -checking log(s) in /var/log/elasticsearch/\n -running 'sudo docker ps' \n -running 'sudo so-elastic-restart'" + echo -e "Connection attempt timed out. Unable to connect to ElasticSearch. \nPlease try: \n -checking log(s) in /var/log/elasticsearch/\n -running 'sudo docker ps' \n -running 'sudo so-elastic-restart'" echo fi From 4dbc5f07b2edd1d6194e0d446e16db01213ae6f3 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Fri, 25 Oct 2019 10:19:05 -0400 Subject: [PATCH 013/200] Enable 0006_input_beats.conf by default on EVAL --- salt/logstash/conf/conf.enabled.txt.so-eval | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/logstash/conf/conf.enabled.txt.so-eval b/salt/logstash/conf/conf.enabled.txt.so-eval index d125fc829..dfc3ea421 100644 --- a/salt/logstash/conf/conf.enabled.txt.so-eval +++ b/salt/logstash/conf/conf.enabled.txt.so-eval @@ -13,7 +13,7 @@ #/usr/share/logstash/pipeline.so/0002_input_windows_json.conf #/usr/share/logstash/pipeline.so/0003_input_syslog.conf #/usr/share/logstash/pipeline.so/0005_input_suricata.conf -#/usr/share/logstash/pipeline.dynamic/0006_input_beats.conf +/usr/share/logstash/pipeline.dynamic/0006_input_beats.conf /usr/share/logstash/pipeline.so/0007_input_import.conf /usr/share/logstash/pipeline.dynamic/0010_input_hhbeats.conf #/usr/share/logstash/pipeline.so/1000_preprocess_log_elapsed.conf From 0d33ce2741b101f3c71fd48e7d733f7abbfc6070 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 25 Oct 2019 11:49:17 -0400 Subject: [PATCH 014/200] QOL change, populate hostname instead of localhost in set hostname dialog box - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/92 --- so-setup-network.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index aea465f0d..fcdfdc103 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -1487,7 +1487,7 @@ whiptail_sensor_config() { whiptail_set_hostname() { HOSTNAME=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter the Hostname you would like to set." 10 60 localhost 3>&1 1>&2 2>&3) + "Enter the Hostname you would like to set." 10 60 $HOSTNAME 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus From 94e15ed5029573e8593cda68a2db8999b622af28 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Sun, 27 Oct 2019 14:36:52 -0400 Subject: [PATCH 015/200] Tweaked for sigmac backend change --- salt/soctopus/files/templates/generic.template | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/salt/soctopus/files/templates/generic.template b/salt/soctopus/files/templates/generic.template index 992db3fa9..23b693258 100644 --- a/salt/soctopus/files/templates/generic.template +++ b/salt/soctopus/files/templates/generic.template @@ -3,20 +3,6 @@ {% set hivekey = salt['pillar.get']('static:hivekey', '') %} es_host: {{es}} es_port: 9200 -name: Alert-Name -type: frequency -index: "*:logstash-*" -num_events: 1 -timeframe: - minutes: 10 -buffer_time: - minutes: 10 -allow_buffer_time_overlap: true - -filter: -- query: - query_string: - query: 'select from test' alert: modules.so.thehive.TheHiveAlerter @@ -32,7 +18,7 @@ hive_alert_config: title: '{rule[name]}' type: 'external' source: 'SecurityOnion' - description: '`Data:` {match[message]}' + description: "`Play:` https://{{es}}/playbook/issues/6000 \n\n `Data:` {match[message]}" severity: 2 tags: ['elastalert', 'SecurityOnion'] tlp: 3 From 07d2ae013d91030a34d8e0fb90c114d0e3590521 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 29 Oct 2019 11:24:17 -0400 Subject: [PATCH 016/200] changes to address - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/96 and https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/92 --- salt/common/telegraf/etc/telegraf.conf | 2 +- salt/ssl/init.sls | 22 ++-- salt/utility/bin/eval.sh | 3 +- so-setup-network.sh | 155 +++++++++++++------------ 4 files changed, 95 insertions(+), 87 deletions(-) diff --git a/salt/common/telegraf/etc/telegraf.conf b/salt/common/telegraf/etc/telegraf.conf index cf12f89bf..af9941bfa 100644 --- a/salt/common/telegraf/etc/telegraf.conf +++ b/salt/common/telegraf/etc/telegraf.conf @@ -76,7 +76,7 @@ logfile = "/var/log/telegraf/telegraf.log" ## Override default hostname, if empty use os.Hostname() - hostname = "{{ grains.host }}" + hostname = "{{ grains.id }}" ## If set to true, do no set the "host" tag in the telegraf agent. omit_hostname = false diff --git a/salt/ssl/init.sls b/salt/ssl/init.sls index 134cee9a0..a4aaba02a 100644 --- a/salt/ssl/init.sls +++ b/salt/ssl/init.sls @@ -1,15 +1,23 @@ {% set master = salt['grains.get']('master') %} {%- set masterip = salt['pillar.get']('static:masterip', '') -%} +{% if grains['role'] == 'so-master' or grains['role'] == 'so-eval' %} + {% set trusttheca_text = salt['mine.get'](grains.id, 'x509.get_pem_entries')[grains.id]['/etc/pki/ca.crt']|replace('\n', '') %} + {% set ca_server = grains.id %} +{% else %} + {% set trusttheca_text = salt['mine.get'](master, 'x509.get_pem_entries')[master]['/etc/pki/ca.crt']|replace('\n', '') %} + {% set ca_server = master %} +{% endif %} + # Trust the CA trusttheca: x509.pem_managed: - name: /etc/ssl/certs/intca.crt - - text: {{ salt['mine.get'](master, 'x509.get_pem_entries')[master]['/etc/pki/ca.crt']|replace('\n', '') }} + - text: {{ trusttheca_text }} -# Install packages needed for the sensor {% if grains['os'] != 'CentOS' %} +# Install packages needed for the sensor m2cryptopkgs: pkg.installed: - skip_suggestions: False @@ -20,7 +28,7 @@ m2cryptopkgs: # Create a cert for the talking to influxdb /etc/pki/influxdb.crt: x509.certificate_managed: - - ca_server: {{ master }} + - ca_server: {{ ca_server }} - signing_policy: influxdb - public_key: /etc/pki/influxdb.key - CN: {{ master }} @@ -37,7 +45,7 @@ m2cryptopkgs: # Request a cert and drop it where it needs to go to be distributed /etc/pki/filebeat.crt: x509.certificate_managed: - - ca_server: {{ master }} + - ca_server: {{ ca_server }} - signing_policy: filebeat - public_key: /etc/pki/filebeat.key - CN: {{ master }} @@ -70,7 +78,7 @@ fbcrtlink: # Create a cert for the docker registry /etc/pki/registry.crt: x509.certificate_managed: - - ca_server: {{ master }} + - ca_server: {{ ca_server }} - signing_policy: registry - public_key: /etc/pki/registry.key - CN: {{ master }} @@ -85,7 +93,7 @@ fbcrtlink: # Create a cert for the reverse proxy /etc/pki/masterssl.crt: x509.certificate_managed: - - ca_server: {{ master }} + - ca_server: {{ ca_server }} - signing_policy: masterssl - public_key: /etc/pki/masterssl.key - CN: {{ master }} @@ -130,7 +138,7 @@ fbcertdir: # Request a cert and drop it where it needs to go to be distributed /opt/so/conf/filebeat/etc/pki/filebeat.crt: x509.certificate_managed: - - ca_server: {{ master }} + - ca_server: {{ ca_server }} - signing_policy: filebeat - public_key: /opt/so/conf/filebeat/etc/pki/filebeat.key - CN: {{ master }} diff --git a/salt/utility/bin/eval.sh b/salt/utility/bin/eval.sh index effbdfd33..03eceef56 100644 --- a/salt/utility/bin/eval.sh +++ b/salt/utility/bin/eval.sh @@ -1,5 +1,4 @@ {%- set ES = salt['pillar.get']('master:mainip', '') -%} -{%- set MASTER = grains['master'] %} # Wait for ElasticSearch to come up, so that we can query for version infromation echo -n "Waiting for ElasticSearch..." COUNT=0 @@ -27,4 +26,4 @@ fi echo "Applying cross cluster search config..." curl -s -XPUT http://{{ ES }}:9200/_cluster/settings \ -H 'Content-Type: application/json' \ - -d "{\"persistent\": {\"search\": {\"remote\": {\"{{ MASTER }}\": {\"seeds\": [\"127.0.0.1:9300\"]}}}}}" + -d "{\"persistent\": {\"search\": {\"remote\": {\"{{ grains.id }}\": {\"seeds\": [\"127.0.0.1:9300\"]}}}}}" diff --git a/so-setup-network.sh b/so-setup-network.sh index fcdfdc103..9ab508093 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -17,6 +17,7 @@ # Global Variable Section HOSTNAME=$(cat /etc/hostname) +MINION_ID=$(echo $HOSTNAME | awk -F. {'print $1'}) TOTAL_MEM=`grep MemTotal /proc/meminfo | awk '{print $2}' | sed -r 's/.{3}$//'` NICS=$(ip link | awk -F: '$0 !~ "lo|vir|veth|br|docker|wl|^[^0-9]"{print $2 " \"" "Interface" "\"" " OFF"}') CPUCORES=$(cat /proc/cpuinfo | grep processor | wc -l) @@ -35,16 +36,16 @@ date -u >$SETUPLOG 2>&1 accept_salt_key_local() { echo "Accept the key locally on the master" >> $SETUPLOG 2>&1 # Accept the key locally on the master - salt-key -ya $HOSTNAME + salt-key -ya $MINION_ID } accept_salt_key_remote() { echo "Accept the key remotely on the master" >> $SETUPLOG 2>&1 # Delete the key just in case. - ssh -i /root/.ssh/so.key socore@$MSRV sudo salt-key -d $HOSTNAME -y + ssh -i /root/.ssh/so.key socore@$MSRV sudo salt-key -d $MINION_ID -y salt-call state.apply ca - ssh -i /root/.ssh/so.key socore@$MSRV sudo salt-key -a $HOSTNAME -y + ssh -i /root/.ssh/so.key socore@$MSRV sudo salt-key -a $MINION_ID -y } @@ -238,7 +239,7 @@ configure_minion() { echo "role: so-$TYPE" > /etc/salt/grains if [ $TYPE == 'master' ] || [ $TYPE == 'eval' ]; then echo "master: $HOSTNAME" > /etc/salt/minion - echo "id: $HOSTNAME" >> /etc/salt/minion + echo "id: $MINION_ID" >> /etc/salt/minion echo "mysql.host: '$MAINIP'" >> /etc/salt/minion echo "mysql.port: 3306" >> /etc/salt/minion echo "mysql.user: 'root'" >> /etc/salt/minion @@ -250,7 +251,7 @@ configure_minion() { fi else echo "master: $MSRV" > /etc/salt/minion - echo "id: $HOSTNAME" >> /etc/salt/minion + echo "id: $MINION_ID" >> /etc/salt/minion fi @@ -274,7 +275,7 @@ copy_minion_pillar() { # Copy over the pillar echo "Copying the pillar over" >> $SETUPLOG 2>&1 - scp -v -i /root/.ssh/so.key $TMP/$HOSTNAME.sls socore@$MSRV:/opt/so/saltstack/pillar/$TYPE/$HOSTNAME.sls + scp -v -i /root/.ssh/so.key $TMP/$MINION_ID.sls socore@$MSRV:/opt/so/saltstack/pillar/$TYPE/$MINION_ID.sls } @@ -521,42 +522,42 @@ ls_heapsize() { master_pillar() { # Create the master pillar - touch /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo "master:" > /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo " mainip: $MAINIP" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo " mainint: $MAININT" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo " esheap: $ES_HEAP_SIZE" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo " esclustername: {{ grains.host }}" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls + touch /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo "master:" > /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " mainip: $MAINIP" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " mainint: $MAININT" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " esheap: $ES_HEAP_SIZE" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " esclustername: {{ grains.host }}" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls if [ $INSTALLTYPE == 'EVALMODE' ]; then - echo " freq: 0" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo " domainstats: 0" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo " ls_pipeline_batch_size: 125" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo " ls_input_threads: 1" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo " ls_batch_count: 125" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo " mtu: 1500" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls + echo " freq: 0" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " domainstats: 0" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " ls_pipeline_batch_size: 125" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " ls_input_threads: 1" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " ls_batch_count: 125" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " mtu: 1500" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls else - echo " freq: 0" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo " domainstats: 0" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls + echo " freq: 0" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " domainstats: 0" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls fi - echo " lsheap: $LS_HEAP_SIZE" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo " lsaccessip: 127.0.0.1" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo " elastalert: 1" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo " ls_pipeline_workers: $CPUCORES" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo " nids_rules: $RULESETUP" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo " oinkcode: $OINKCODE" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - #echo " access_key: $ACCESS_KEY" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - #echo " access_secret: $ACCESS_SECRET" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo " es_port: $NODE_ES_PORT" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo " log_size_limit: $LOG_SIZE_LIMIT" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo " cur_close_days: $CURCLOSEDAYS" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - #echo " mysqlpass: $MYSQLPASS" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - #echo " fleetpass: $FLEETPASS" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo " grafana: $GRAFANA" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo " osquery: $OSQUERY" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo " wazuh: $WAZUH" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo " thehive: $THEHIVE" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls - echo " playbook: $PLAYBOOK" >> /opt/so/saltstack/pillar/masters/$HOSTNAME.sls + echo " lsheap: $LS_HEAP_SIZE" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " lsaccessip: 127.0.0.1" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " elastalert: 1" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " ls_pipeline_workers: $CPUCORES" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " nids_rules: $RULESETUP" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " oinkcode: $OINKCODE" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + #echo " access_key: $ACCESS_KEY" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + #echo " access_secret: $ACCESS_SECRET" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " es_port: $NODE_ES_PORT" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " log_size_limit: $LOG_SIZE_LIMIT" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " cur_close_days: $CURCLOSEDAYS" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + #echo " mysqlpass: $MYSQLPASS" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + #echo " fleetpass: $FLEETPASS" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " grafana: $GRAFANA" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " osquery: $OSQUERY" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " wazuh: $WAZUH" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " thehive: $THEHIVE" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " playbook: $PLAYBOOK" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls } master_static() { @@ -595,22 +596,22 @@ minio_generate_keys() { node_pillar() { # Create the node pillar - touch $TMP/$HOSTNAME.sls - echo "node:" > $TMP/$HOSTNAME.sls - echo " mainip: $MAINIP" >> $TMP/$HOSTNAME.sls - echo " mainint: $MAININT" >> $TMP/$HOSTNAME.sls - echo " esheap: $NODE_ES_HEAP_SIZE" >> $TMP/$HOSTNAME.sls - echo " esclustername: {{ grains.host }}" >> $TMP/$HOSTNAME.sls - echo " lsheap: $NODE_LS_HEAP_SIZE" >> $TMP/$HOSTNAME.sls - echo " ls_pipeline_workers: $LSPIPELINEWORKERS" >> $TMP/$HOSTNAME.sls - echo " ls_pipeline_batch_size: $LSPIPELINEBATCH" >> $TMP/$HOSTNAME.sls - echo " ls_input_threads: $LSINPUTTHREADS" >> $TMP/$HOSTNAME.sls - echo " ls_batch_count: $LSINPUTBATCHCOUNT" >> $TMP/$HOSTNAME.sls - echo " es_shard_count: $SHARDCOUNT" >> $TMP/$HOSTNAME.sls - echo " node_type: $NODETYPE" >> $TMP/$HOSTNAME.sls - echo " es_port: $NODE_ES_PORT" >> $TMP/$HOSTNAME.sls - echo " log_size_limit: $LOG_SIZE_LIMIT" >> $TMP/$HOSTNAME.sls - echo " cur_close_days: $CURCLOSEDAYS" >> $TMP/$HOSTNAME.sls + touch $TMP/$MINION_ID.sls + echo "node:" > $TMP/$MINION_ID.sls + echo " mainip: $MAINIP" >> $TMP/$MINION_ID.sls + echo " mainint: $MAININT" >> $TMP/$MINION_ID.sls + echo " esheap: $NODE_ES_HEAP_SIZE" >> $TMP/$MINION_ID.sls + echo " esclustername: {{ grains.host }}" >> $TMP/$MINION_ID.sls + echo " lsheap: $NODE_LS_HEAP_SIZE" >> $TMP/$MINION_ID.sls + echo " ls_pipeline_workers: $LSPIPELINEWORKERS" >> $TMP/$MINION_ID.sls + echo " ls_pipeline_batch_size: $LSPIPELINEBATCH" >> $TMP/$MINION_ID.sls + echo " ls_input_threads: $LSINPUTTHREADS" >> $TMP/$MINION_ID.sls + echo " ls_batch_count: $LSINPUTBATCHCOUNT" >> $TMP/$MINION_ID.sls + echo " es_shard_count: $SHARDCOUNT" >> $TMP/$MINION_ID.sls + echo " node_type: $NODETYPE" >> $TMP/$MINION_ID.sls + echo " es_port: $NODE_ES_PORT" >> $TMP/$MINION_ID.sls + echo " log_size_limit: $LOG_SIZE_LIMIT" >> $TMP/$MINION_ID.sls + echo " cur_close_days: $CURCLOSEDAYS" >> $TMP/$MINION_ID.sls } @@ -922,36 +923,36 @@ salt_master_directories() { sensor_pillar() { # Create the sensor pillar - touch $TMP/$HOSTNAME.sls - echo "sensor:" > $TMP/$HOSTNAME.sls - echo " interface: bond0" >> $TMP/$HOSTNAME.sls - echo " mainip: $MAINIP" >> $TMP/$HOSTNAME.sls - echo " mainint: $MAININT" >> $TMP/$HOSTNAME.sls + touch $TMP/$MINION_ID.sls + echo "sensor:" > $TMP/$MINION_ID.sls + echo " interface: bond0" >> $TMP/$MINION_ID.sls + echo " mainip: $MAINIP" >> $TMP/$MINION_ID.sls + echo " mainint: $MAININT" >> $TMP/$MINION_ID.sls if [ $NSMSETUP == 'ADVANCED' ]; then - echo " bro_pins:" >> $TMP/$HOSTNAME.sls + echo " bro_pins:" >> $TMP/$MINION_ID.sls for PIN in $BROPINS; do PIN=$(echo $PIN | cut -d\" -f2) - echo " - $PIN" >> $TMP/$HOSTNAME.sls + echo " - $PIN" >> $TMP/$MINION_ID.sls done - echo " suripins:" >> $TMP/$HOSTNAME.sls + echo " suripins:" >> $TMP/$MINION_ID.sls for SPIN in $SURIPINS; do SPIN=$(echo $SPIN | cut -d\" -f2) - echo " - $SPIN" >> $TMP/$HOSTNAME.sls + echo " - $SPIN" >> $TMP/$MINION_ID.sls done else - echo " bro_lbprocs: $BASICBRO" >> $TMP/$HOSTNAME.sls - echo " suriprocs: $BASICSURI" >> $TMP/$HOSTNAME.sls + echo " bro_lbprocs: $BASICBRO" >> $TMP/$MINION_ID.sls + echo " suriprocs: $BASICSURI" >> $TMP/$MINION_ID.sls fi - echo " brobpf:" >> $TMP/$HOSTNAME.sls - echo " pcapbpf:" >> $TMP/$HOSTNAME.sls - echo " nidsbpf:" >> $TMP/$HOSTNAME.sls - echo " master: $MSRV" >> $TMP/$HOSTNAME.sls - echo " mtu: $MTU" >> $TMP/$HOSTNAME.sls + echo " brobpf:" >> $TMP/$MINION_ID.sls + echo " pcapbpf:" >> $TMP/$MINION_ID.sls + echo " nidsbpf:" >> $TMP/$MINION_ID.sls + echo " master: $MSRV" >> $TMP/$MINION_ID.sls + echo " mtu: $MTU" >> $TMP/$MINION_ID.sls if [ $HNSENSOR != 'inherit' ]; then - echo " hnsensor: $HNSENSOR" >> $TMP/$HOSTNAME.sls + echo " hnsensor: $HNSENSOR" >> $TMP/$MINION_ID.sls fi - echo " access_key: $ACCESS_KEY" >> $TMP/$HOSTNAME.sls - echo " access_secret: $ACCESS_SECRET" >> $TMP/$HOSTNAME.sls + echo " access_key: $ACCESS_KEY" >> $TMP/$MINION_ID.sls + echo " access_secret: $ACCESS_SECRET" >> $TMP/$MINION_ID.sls } @@ -970,7 +971,7 @@ set_initial_firewall_policy() { if [ $INSTALLTYPE == 'MASTERONLY' ]; then printf " - $MAINIP\n" >> /opt/so/saltstack/pillar/firewall/minions.sls printf " - $MAINIP\n" >> /opt/so/saltstack/pillar/firewall/masterfw.sls - /opt/so/saltstack/pillar/data/addtotab.sh mastertab $HOSTNAME $MAINIP $CPUCORES $RANDOMUID $MAININT $FSROOT $FSNSM + /opt/so/saltstack/pillar/data/addtotab.sh mastertab $MINION_ID $MAINIP $CPUCORES $RANDOMUID $MAININT $FSROOT $FSNSM fi if [ $INSTALLTYPE == 'EVALMODE' ]; then @@ -978,19 +979,19 @@ set_initial_firewall_policy() { printf " - $MAINIP\n" >> /opt/so/saltstack/pillar/firewall/masterfw.sls printf " - $MAINIP\n" >> /opt/so/saltstack/pillar/firewall/forward_nodes.sls printf " - $MAINIP\n" >> /opt/so/saltstack/pillar/firewall/storage_nodes.sls - /opt/so/saltstack/pillar/data/addtotab.sh evaltab $HOSTNAME $MAINIP $CPUCORES $RANDOMUID $MAININT $FSROOT $FSNSM bond0 + /opt/so/saltstack/pillar/data/addtotab.sh evaltab $MINION_ID $MAINIP $CPUCORES $RANDOMUID $MAININT $FSROOT $FSNSM bond0 fi if [ $INSTALLTYPE == 'SENSORONLY' ]; then ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/firewall/addfirewall.sh minions $MAINIP ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/firewall/addfirewall.sh forward_nodes $MAINIP - ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/data/addtotab.sh sensorstab $HOSTNAME $MAINIP $CPUCORES $RANDOMUID $MAININT $FSROOT $FSNSM bond0 + ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/data/addtotab.sh sensorstab $MINION_ID $MAINIP $CPUCORES $RANDOMUID $MAININT $FSROOT $FSNSM bond0 fi if [ $INSTALLTYPE == 'STORAGENODE' ]; then ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/firewall/addfirewall.sh minions $MAINIP ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/firewall/addfirewall.sh storage_nodes $MAINIP - ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/data/addtotab.sh nodestab $HOSTNAME $MAINIP $CPUCORES $RANDOMUID $MAININT $FSROOT $FSNSM + ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/data/addtotab.sh nodestab $MINION_ID $MAINIP $CPUCORES $RANDOMUID $MAININT $FSROOT $FSNSM fi if [ $INSTALLTYPE == 'PARSINGNODE' ]; then From 974efbaf21ca0dc1a1d95d481264462480a88598 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Wed, 30 Oct 2019 12:37:44 -0400 Subject: [PATCH 017/200] fix ca signing policies for changes related to https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/96 --- salt/ca/files/signing_policies.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/salt/ca/files/signing_policies.conf b/salt/ca/files/signing_policies.conf index fb79a3cc2..e253f8911 100644 --- a/salt/ca/files/signing_policies.conf +++ b/salt/ca/files/signing_policies.conf @@ -10,7 +10,6 @@ x509_signing_policies: - keyUsage: "digitalSignature, nonRepudiation" - subjectKeyIdentifier: hash - authorityKeyIdentifier: keyid,issuer:always - - extendedKeyUsage: serverAuth - days_valid: 820 - copypath: /etc/pki/issued_certs/ registry: From c1e3615d9e13e039a4f4f20606c76bff73a663e4 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 31 Oct 2019 10:49:11 -0400 Subject: [PATCH 018/200] change the mine target to master's minion id instead of it's hostname - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/96 --- salt/ssl/init.sls | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/salt/ssl/init.sls b/salt/ssl/init.sls index a4aaba02a..b78e5f578 100644 --- a/salt/ssl/init.sls +++ b/salt/ssl/init.sls @@ -1,12 +1,13 @@ {% set master = salt['grains.get']('master') %} +{% set master_minion_id = master.split(".")[0] %} {%- set masterip = salt['pillar.get']('static:masterip', '') -%} {% if grains['role'] == 'so-master' or grains['role'] == 'so-eval' %} {% set trusttheca_text = salt['mine.get'](grains.id, 'x509.get_pem_entries')[grains.id]['/etc/pki/ca.crt']|replace('\n', '') %} {% set ca_server = grains.id %} {% else %} - {% set trusttheca_text = salt['mine.get'](master, 'x509.get_pem_entries')[master]['/etc/pki/ca.crt']|replace('\n', '') %} - {% set ca_server = master %} + {% set trusttheca_text = salt['mine.get'](master_minion_id, 'x509.get_pem_entries')[master_minion_id]['/etc/pki/ca.crt']|replace('\n', '') %} + {% set ca_server = master_minion_id %} {% endif %} # Trust the CA From 74428f33eb4ae2f632af8b976dca32085549a638 Mon Sep 17 00:00:00 2001 From: Wes Lambert Date: Thu, 31 Oct 2019 14:55:14 +0000 Subject: [PATCH 019/200] pin Wazuh agent version --- salt/wazuh/init.sls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/wazuh/init.sls b/salt/wazuh/init.sls index 3169efd3f..8ee1371ff 100644 --- a/salt/wazuh/init.sls +++ b/salt/wazuh/init.sls @@ -41,7 +41,7 @@ wazuhpkgs: pkg.installed: - skip_suggestions: False - pkgs: - - wazuh-agent + - wazuh-agent: 3.10.2-1 # Add Wazuh agent conf wazuhagentconf: From 0b0d8e21ed2db355141ab53b921f3713b7229dfa Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Thu, 31 Oct 2019 11:08:52 -0400 Subject: [PATCH 020/200] Adds NIDS SID to Hive Alert as a Tag --- salt/elastalert/files/rules/so/nids2hive.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/elastalert/files/rules/so/nids2hive.yaml b/salt/elastalert/files/rules/so/nids2hive.yaml index 7d55b4675..92de99537 100644 --- a/salt/elastalert/files/rules/so/nids2hive.yaml +++ b/salt/elastalert/files/rules/so/nids2hive.yaml @@ -40,7 +40,7 @@ hive_alert_config: source: 'SecurityOnion' description: "`NIDS Dashboard:` \n\n \n\n `IPs: `{match[source_ip]}:{match[source_port]} --> {match[destination_ip]}:{match[destination_port]} \n\n `Signature:` {match[rule_signature]}" severity: 2 - tags: ['elastalert', 'SecurityOnion', 'NIDS'] + tags: ['elastalert', 'SecurityOnion', 'NIDS','{match[sid]}'] tlp: 3 status: 'New' follow: True From b6c77ba695bbc4c381db27ef54e4028a72ffc1a2 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Fri, 1 Nov 2019 18:39:51 -0400 Subject: [PATCH 021/200] Cortex - initial commit --- salt/common/nginx/nginx.conf.so-eval | 12 ++ salt/common/nginx/nginx.conf.so-master | 12 ++ salt/firewall/init.sls | 11 ++ salt/hive/init.sls | 50 +++++-- salt/hive/thehive/etc/application.conf | 11 +- salt/hive/thehive/etc/cortex-application.conf | 130 ++++++++++++++++++ salt/hive/thehive/scripts/cortex_init.sh | 44 ++++++ so-setup-network.sh | 4 + 8 files changed, 261 insertions(+), 13 deletions(-) create mode 100644 salt/hive/thehive/etc/cortex-application.conf create mode 100644 salt/hive/thehive/scripts/cortex_init.sh diff --git a/salt/common/nginx/nginx.conf.so-eval b/salt/common/nginx/nginx.conf.so-eval index 344ca4aed..fe55dc274 100644 --- a/salt/common/nginx/nginx.conf.so-eval +++ b/salt/common/nginx/nginx.conf.so-eval @@ -177,6 +177,18 @@ http { } + location /cortex/ { + proxy_pass http://{{ masterip }}:9001/cortex/; + proxy_read_timeout 90; + proxy_connect_timeout 90; + proxy_http_version 1.1; # this is essential for chunked responses to work + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Proxy ""; + + } + location /soctopus/ { proxy_pass http://{{ masterip }}:7000/; proxy_read_timeout 90; diff --git a/salt/common/nginx/nginx.conf.so-master b/salt/common/nginx/nginx.conf.so-master index dcedcafaf..964579a96 100644 --- a/salt/common/nginx/nginx.conf.so-master +++ b/salt/common/nginx/nginx.conf.so-master @@ -176,6 +176,18 @@ http { } + location /cortex/ { + proxy_pass http://{{ masterip }}:9001/cortex/; + proxy_read_timeout 90; + proxy_connect_timeout 90; + proxy_http_version 1.1; # this is essential for chunked responses to work + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Proxy ""; + + } + location /soctopus/ { proxy_pass http://{{ masterip }}:7000/; proxy_read_timeout 90; diff --git a/salt/firewall/init.sls b/salt/firewall/init.sls index 68d1f66cd..c0c1e6d82 100644 --- a/salt/firewall/init.sls +++ b/salt/firewall/init.sls @@ -264,6 +264,17 @@ enable_master_navigator_4200_{{ip}}: - dport: 4200 - position: 1 - save: True + +enable_master_cortex_9001_{{ip}}: + iptables.insert: + - table: filter + - chain: DOCKER-USER + - jump: ACCEPT + - proto: tcp + - source: {{ ip }} + - dport: 9001 + - position: 1 + - save: True {% endfor %} diff --git a/salt/hive/init.sls b/salt/hive/init.sls index ced11c6ff..f13d81e9d 100644 --- a/salt/hive/init.sls +++ b/salt/hive/init.sls @@ -20,6 +20,28 @@ hiveconf: - user: 939 - group: 939 - template: jinja + +cortexconfdir: + file.directory: + - name: /opt/so/conf/cortex + - makedirs: True + - user: 939 + - group: 939 + +cortexlogdir: + file.directory: + - name: /opt/so/log/cortex + - makedirs: True + - user: 939 + - group: 939 + +cortexconf: + file.recurse: + - name: /opt/so/conf/cortex + - source: salt://hive/thehive/etc + - user: 939 + - group: 939 + - template: jinja # Install Elasticsearch @@ -68,15 +90,27 @@ so-thehive-es: #so-corteximage: # cmd.run: -# - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-cortex:HH1.0.3 +# - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-cortex:HH1.1.1 -#so-cortex: -# docker_container.running: -# - image: thehiveproject/cortex:latest -# - hostname: so-cortex -# - name: so-cortex -# - port_bindings: -# - 0.0.0.0:9001:9001 +so-cortex: + docker_container.running: +# - require: +# - so-corteximage +# - image: docker.io/soshybridhunter/so-cortex:HH1.1.1 + - image: so-cortex:dev + - hostname: so-cortex + - name: so-cortex + - user: 939 + - binds: + - /opt/so/conf/hive/etc/cortex-application.conf:/opt/cortex/conf/application.conf:ro + - port_bindings: + - 0.0.0.0:9001:9001 + +cortexscript: + cmd.script: + - source: salt://hive/thehive/scripts/cortex_init.sh + - cwd: /opt/so + - template: jinja so-thehiveimage: cmd.run: diff --git a/salt/hive/thehive/etc/application.conf b/salt/hive/thehive/etc/application.conf index e4dd1e2b2..6cc72813e 100644 --- a/salt/hive/thehive/etc/application.conf +++ b/salt/hive/thehive/etc/application.conf @@ -1,4 +1,5 @@ {%- set MASTERIP = salt['pillar.get']('static:masterip', '') %} +{%- set CORTEXKEY = salt['pillar.get']('static:cortexkey', '') %} # Secret Key # The secret key is used to secure cryptographic functions. @@ -130,15 +131,15 @@ play.http.parser.maxDiskBuffer = 1G # # In order to use Cortex, first you need to enable the Cortex module by uncommenting the next line -#play.modules.enabled += connectors.cortex.CortexConnector +play.modules.enabled += connectors.cortex.CortexConnector cortex { - #"CORTEX-SERVER-ID" { - # url = "" - # key = "" + "CORTEX-SERVER-ID" { + url = "http://{{ MASTERIP }}:9001/cortex/" + key = "{{ CORTEXKEY }}" # # HTTP client configuration (SSL and proxy) # ws {} - #} + } } # MISP diff --git a/salt/hive/thehive/etc/cortex-application.conf b/salt/hive/thehive/etc/cortex-application.conf new file mode 100644 index 000000000..543a2a3e9 --- /dev/null +++ b/salt/hive/thehive/etc/cortex-application.conf @@ -0,0 +1,130 @@ +{%- set MASTERIP = salt['pillar.get']('static:masterip', '') %} + +# Secret Key +# The secret key is used to secure cryptographic functions. +# WARNING: If you deploy your application on several servers, make sure to use the same key. +play.http.secret.key="letsdewdis" +play.http.context=/cortex/ +search.uri = "http://{{ MASTERIP }}:9400" + +# Elasticsearch +search { + # Name of the index + index = cortex + # Name of the Elasticsearch cluster + cluster = hive + # Address of the Elasticsearch instance + host = ["{{ MASTERIP }}:9500"] + # Scroll keepalive + keepalive = 1m + # Size of the page for scroll + pagesize = 50 + # Number of shards + nbshards = 5 + # Number of replicas + nbreplicas = 1 + # Arbitrary settings + settings { + # Maximum number of nested fields + mapping.nested_fields.limit = 100 + } + + ## Authentication configuration + #search.username = "" + #search.password = "" + + ## SSL configuration + #search.keyStore { + # path = "/path/to/keystore" + # type = "JKS" # or PKCS12 + # password = "keystore-password" + #} + #search.trustStore { + # path = "/path/to/trustStore" + # type = "JKS" # or PKCS12 + # password = "trustStore-password" + #} +} + +## Cache +# +# If an analyzer is executed against the same observable, the previous report can be returned without re-executing the +# analyzer. The cache is used only if the second job occurs within cache.job (the default is 10 minutes). +cache.job = 10 minutes + +## Authentication +auth { + # "provider" parameter contains the authentication provider(s). It can be multi-valued, which is useful + # for migration. + # The available auth types are: + # - services.LocalAuthSrv : passwords are stored in the user entity within ElasticSearch). No + # configuration are required. + # - ad : use ActiveDirectory to authenticate users. The associated configuration shall be done in + # the "ad" section below. + # - ldap : use LDAP to authenticate users. The associated configuration shall be done in the + # "ldap" section below. + provider = [local] + + ad { + # The Windows domain name in DNS format. This parameter is required if you do not use + # 'serverNames' below. + #domainFQDN = "mydomain.local" + + # Optionally you can specify the host names of the domain controllers instead of using 'domainFQDN + # above. If this parameter is not set, TheHive uses 'domainFQDN'. + #serverNames = [ad1.mydomain.local, ad2.mydomain.local] + + # The Windows domain name using short format. This parameter is required. + #domainName = "MYDOMAIN" + + # If 'true', use SSL to connect to the domain controller. + #useSSL = true + } + + ldap { + # The LDAP server name or address. The port can be specified using the 'host:port' + # syntax. This parameter is required if you don't use 'serverNames' below. + #serverName = "ldap.mydomain.local:389" + + # If you have multiple LDAP servers, use the multi-valued setting 'serverNames' instead. + #serverNames = [ldap1.mydomain.local, ldap2.mydomain.local] + + # Account to use to bind to the LDAP server. This parameter is required. + #bindDN = "cn=thehive,ou=services,dc=mydomain,dc=local" + + # Password of the binding account. This parameter is required. + #bindPW = "***secret*password***" + + # Base DN to search users. This parameter is required. + #baseDN = "ou=users,dc=mydomain,dc=local" + + # Filter to search user in the directory server. Please note that {0} is replaced + # by the actual user name. This parameter is required. + #filter = "(cn={0})" + + # If 'true', use SSL to connect to the LDAP directory server. + #useSSL = true + } +} + +## ANALYZERS +# +analyzer { + # Absolute path where you have pulled the Cortex-Analyzers repository. + path = ["/Cortex-Analyzers/analyzers"] + + # Sane defaults. Do not change unless you know what you are doing. + fork-join-executor { + + # Min number of threads available for analysis. + parallelism-min = 2 + + # Parallelism (threads) ... ceil(available processors * factor). + parallelism-factor = 2.0 + + # Max number of threads available for analysis. + parallelism-max = 4 + } +} + +# It's the end my friend. Happy hunting! diff --git a/salt/hive/thehive/scripts/cortex_init.sh b/salt/hive/thehive/scripts/cortex_init.sh new file mode 100644 index 000000000..5d4de730b --- /dev/null +++ b/salt/hive/thehive/scripts/cortex_init.sh @@ -0,0 +1,44 @@ +#!/bin/bash +{%- set MASTERIP = salt['pillar.get']('static:masterip', '') %} +{%- set CORTEXUSER = salt['pillar.get']('static:cortexuser', '') %} +{%- set CORTEXPASSWORD = salt['pillar.get']('static:cortexpassword', '') %} +{%- set CORTEXKEY = salt['pillar.get']('static:cortexkey', '') %} + +cortex_init(){ + sleep 60 + CORTEX_IP="{{MASTERIP}}" + CORTEX_USER="{{CORTEXUSER}}" + CORTEX_PASSWORD="{{CORTEXPASSWORD}}" + CORTEX_KEY="{{CORTEXKEY}}" + SOCTOPUS_CONFIG="/opt/so/saltstack/salt/soctopus/files/SOCtopus.conf" + + # Migrate DB + curl -v -k -XPOST "https://$CORTEX_IP:/cortex/api/maintenance/migrate" + + # Create intial Cortex user + curl -v -k "https://$CORTEX_IP/cortex/api/user" -H "Content-Type: application/json" -d "{\"login\" : \"$CORTEX_USER\",\"name\" : \"$CORTEX_USER\",\"roles\" : [\"read\",\"analyze\",\"orgadmin\"],\"preferences\" : \"{}\",\"password\" : \"$CORTEX_PASSWORD\", \"key\": \"$CORTEX_KEY\"}" + + # Enable URLScan.io Analyzer + curl -v -k -XPOST -H "Authorization: Bearer $CORTEX_KEY" -H "Content-Type: application/json" "https://$CORTEX_IP/cortex/api/organization/analyzer/Urlscan_io_Search_0_1_0" -d '{"name":"Urlscan_io_Search_0_1_0","configuration":{"auto_extract_artifacts":false,"check_tlp":true,"max_tlp":2}}' + + # Update SOCtopus config with apikey value + #sed -i "s/cortex_key = .*/cortex_key = $CORTEX_KEY/" $SOCTOPUS_CONFIG + + touch /opt/so/state/cortex.txt + +} + +if [ -f /opt/so/state/cortex.txt ]; then + exit 0 +else + rm -f garbage_file + while ! wget -O garbage_file {{MASTERIP}}:9500 2>/dev/null + do + echo "Waiting for Elasticsearch..." + rm -f garbage_file + sleep 1 + done + rm -f garbage_file + sleep 5 + cortex_init +fi diff --git a/so-setup-network.sh b/so-setup-network.sh index aea465f0d..bf6bc831e 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -426,6 +426,7 @@ generate_passwords(){ MYSQLPASS=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) FLEETPASS=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) HIVEKEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) + CORTEXKEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) SENSORONIKEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) } @@ -574,6 +575,9 @@ master_static() { echo " hiveuser: hiveadmin" >> /opt/so/saltstack/pillar/static.sls echo " hivepassword: hivechangeme" >> /opt/so/saltstack/pillar/static.sls echo " hivekey: $HIVEKEY" >> /opt/so/saltstack/pillar/static.sls + echo " cortexuser: cortexadmin" >> /opt/so/saltstack/pillar/static.sls + echo " cortexpassword: cortexchangeme" >> /opt/so/saltstack/pillar/static.sls + echo " cortexkey: $CORTEXKEY" >> /opt/so/saltstack/pillar/static.sls echo " fleetsetup: 0" >> /opt/so/saltstack/pillar/static.sls echo " sensoronikey: $SENSORONIKEY" >> /opt/so/saltstack/pillar/static.sls if [[ $MASTERUPDATES == 'MASTER' ]]; then From 4f66474da15c23c4fe6dcad193eb7139d0b853ed Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Sat, 2 Nov 2019 12:15:49 -0400 Subject: [PATCH 022/200] Fix docker location --- salt/hive/init.sls | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/salt/hive/init.sls b/salt/hive/init.sls index f13d81e9d..772bec3e5 100644 --- a/salt/hive/init.sls +++ b/salt/hive/init.sls @@ -88,16 +88,15 @@ so-thehive-es: # Install Cortex -#so-corteximage: -# cmd.run: -# - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-cortex:HH1.1.1 +so-corteximage: + cmd.run: + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-cortex:HH1.1.1 so-cortex: docker_container.running: -# - require: -# - so-corteximage -# - image: docker.io/soshybridhunter/so-cortex:HH1.1.1 - - image: so-cortex:dev + - require: + - so-corteximage + - image: docker.io/soshybridhunter/so-cortex:HH1.1.1 - hostname: so-cortex - name: so-cortex - user: 939 From 5a7e68206eef7f5f228266c8c7d8095eb2af42c0 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Sun, 3 Nov 2019 05:57:22 -0500 Subject: [PATCH 023/200] Update init.sls --- salt/hive/init.sls | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/hive/init.sls b/salt/hive/init.sls index 772bec3e5..a825aebf5 100644 --- a/salt/hive/init.sls +++ b/salt/hive/init.sls @@ -90,13 +90,13 @@ so-thehive-es: so-corteximage: cmd.run: - - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-cortex:HH1.1.1 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-cortex:HH1.1.3 so-cortex: docker_container.running: - require: - so-corteximage - - image: docker.io/soshybridhunter/so-cortex:HH1.1.1 + - image: docker.io/soshybridhunter/so-cortex:HH1.1.3 - hostname: so-cortex - name: so-cortex - user: 939 From f85dc497890f9f964035fade9842fac2a7d3584e Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 4 Nov 2019 09:34:04 -0500 Subject: [PATCH 024/200] update pillar/top.sls to match on id instead of host grain - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/96 --- pillar/top.sls | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pillar/top.sls b/pillar/top.sls index bc68aa644..031352a11 100644 --- a/pillar/top.sls +++ b/pillar/top.sls @@ -1,19 +1,19 @@ base: 'G@role:so-sensor': - - sensors.{{ grains.host }} + - sensors.{{ grains.id }} - static - firewall.* - brologs 'G@role:so-master': - - masters.{{ grains.host }} + - masters.{{ grains.id }} - static - firewall.* - data.* - auth 'G@role:so-eval': - - masters.{{ grains.host }} + - masters.{{ grains.id }} - static - firewall.* - data.* @@ -21,6 +21,6 @@ base: - auth 'G@role:so-node': - - nodes.{{ grains.host }} + - nodes.{{ grains.id }} - static - firewall.* From 47be406075034ca1df3563728c9955f489a707f1 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 4 Nov 2019 09:47:45 -0500 Subject: [PATCH 025/200] Setup Script - Issue 91 --- so-setup-network.sh | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index 18ab9ffee..47aa6c42f 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -578,7 +578,7 @@ master_static() { echo " hivekey: $HIVEKEY" >> /opt/so/saltstack/pillar/static.sls echo " cortexuser: cortexadmin" >> /opt/so/saltstack/pillar/static.sls echo " cortexpassword: cortexchangeme" >> /opt/so/saltstack/pillar/static.sls - echo " cortexkey: $CORTEXKEY" >> /opt/so/saltstack/pillar/static.sls + echo " cortexkey: $CORTEXKEY" >> /opt/so/saltstack/pillar/static.sls echo " fleetsetup: 0" >> /opt/so/saltstack/pillar/static.sls echo " sensoronikey: $SENSORONIKEY" >> /opt/so/saltstack/pillar/static.sls if [[ $MASTERUPDATES == 'MASTER' ]]; then @@ -966,6 +966,11 @@ set_hostname() { echo "127.0.0.1 $HOSTNAME $HOSTNAME.localdomain localhost localhost.localdomain localhost4 localhost4.localdomain" > /etc/hosts echo "::1 localhost localhost.localdomain localhost6 localhost6.localdomain6" >> /etc/hosts echo $HOSTNAME > /etc/hostname + if [ $INSTALLTYPE != 'MASTERONLY' ] || [ $INSTALLTYPE != 'EVALMODE' ]; then + if [[ $TESTHOST = *"not found"* ]]; then + add_master_hostfile + fi + fi } @@ -1311,9 +1316,9 @@ whiptail_management_server() { # See if it resolves. Otherwise prompt to add to host file TESTHOST=$(host $MSRV) - if [[ $TESTHOST = *"not found"* ]]; then - add_master_hostfile - fi + #if [[ $TESTHOST = *"not found"* ]]; then + # add_master_hostfile + #fi local exitstatus=$? From d658473485ad4b79272399b7dd14de554d954c7e Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 4 Nov 2019 11:31:27 -0500 Subject: [PATCH 026/200] Hive State - Fix cortex docker name --- salt/hive/init.sls | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/salt/hive/init.sls b/salt/hive/init.sls index a825aebf5..73b29b501 100644 --- a/salt/hive/init.sls +++ b/salt/hive/init.sls @@ -20,7 +20,7 @@ hiveconf: - user: 939 - group: 939 - template: jinja - + cortexconfdir: file.directory: - name: /opt/so/conf/cortex @@ -90,13 +90,13 @@ so-thehive-es: so-corteximage: cmd.run: - - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-cortex:HH1.1.3 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-thehive-cortex:HH1.1.3 so-cortex: docker_container.running: - require: - so-corteximage - - image: docker.io/soshybridhunter/so-cortex:HH1.1.3 + - image: docker.io/soshybridhunter/so-thehive-cortex:HH1.1.3 - hostname: so-cortex - name: so-cortex - user: 939 @@ -104,7 +104,7 @@ so-cortex: - /opt/so/conf/hive/etc/cortex-application.conf:/opt/cortex/conf/application.conf:ro - port_bindings: - 0.0.0.0:9001:9001 - + cortexscript: cmd.script: - source: salt://hive/thehive/scripts/cortex_init.sh From bdb0efa1535afa06ec45d10e68e95e1f0b6f11d2 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 4 Nov 2019 11:50:39 -0500 Subject: [PATCH 027/200] Setup Script - Issue 91 --- so-setup-network.sh | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index 47aa6c42f..cfc0912fb 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -56,9 +56,9 @@ add_master_hostfile() { "Enter your Master Server IP Address" 10 60 X.X.X.X 3>&1 1>&2 2>&3) # Add the master to the host file if it doesn't resolve - if ! grep -q $MSRVIP /etc/hosts; then - echo "$MSRVIP $MSRV" >> /etc/hosts - fi + #if ! grep -q $MSRVIP /etc/hosts; then + # echo "$MSRVIP $MSRV" >> /etc/hosts + #fi } add_socore_user_master() { @@ -968,7 +968,9 @@ set_hostname() { echo $HOSTNAME > /etc/hostname if [ $INSTALLTYPE != 'MASTERONLY' ] || [ $INSTALLTYPE != 'EVALMODE' ]; then if [[ $TESTHOST = *"not found"* ]]; then - add_master_hostfile + if ! grep -q $MSRVIP /etc/hosts; then + echo "$MSRVIP $MSRV" >> /etc/hosts + fi fi fi @@ -1316,9 +1318,9 @@ whiptail_management_server() { # See if it resolves. Otherwise prompt to add to host file TESTHOST=$(host $MSRV) - #if [[ $TESTHOST = *"not found"* ]]; then - # add_master_hostfile - #fi + if [[ $TESTHOST = *"not found"* ]]; then + add_master_hostfile + fi local exitstatus=$? From ab306dd4546228dad42b48d3e8e3be887448d71a Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 4 Nov 2019 11:56:43 -0500 Subject: [PATCH 028/200] Setup Script - Issue 91 --- so-setup-network.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index cfc0912fb..5678dbc0e 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -52,7 +52,7 @@ accept_salt_key_remote() { add_master_hostfile() { echo "Checking if I can resolve master. If not add to hosts file" >> $SETUPLOG 2>&1 # Pop up an input to get the IP address - local MSRVIP=$(whiptail --title "Security Onion Setup" --inputbox \ + MSRVIP=$(whiptail --title "Security Onion Setup" --inputbox \ "Enter your Master Server IP Address" 10 60 X.X.X.X 3>&1 1>&2 2>&3) # Add the master to the host file if it doesn't resolve From 612783d77f9e24da42be8cdde2cb19d945682b93 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 4 Nov 2019 12:03:44 -0500 Subject: [PATCH 029/200] Setup Script - Issue 91 --- so-setup-network.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index 5678dbc0e..06ad03dc9 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -1318,7 +1318,7 @@ whiptail_management_server() { # See if it resolves. Otherwise prompt to add to host file TESTHOST=$(host $MSRV) - if [[ $TESTHOST = *"not found"* ]]; then + if [[ $TESTHOST = *"not found"* ]] || [[ $TESTHOST = *"connection timed out"* ]]; then add_master_hostfile fi From ec2275f70707efe086ba980efcf4f44dae9a7a62 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 4 Nov 2019 12:12:56 -0500 Subject: [PATCH 030/200] Setup Script - Issue 91 --- so-setup-network.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index 06ad03dc9..6e54b8ce4 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -967,7 +967,7 @@ set_hostname() { echo "::1 localhost localhost.localdomain localhost6 localhost6.localdomain6" >> /etc/hosts echo $HOSTNAME > /etc/hostname if [ $INSTALLTYPE != 'MASTERONLY' ] || [ $INSTALLTYPE != 'EVALMODE' ]; then - if [[ $TESTHOST = *"not found"* ]]; then + if [[ $TESTHOST = *"not found"* ]] || [[ $TESTHOST = *"connection timed out"* ]]; then if ! grep -q $MSRVIP /etc/hosts; then echo "$MSRVIP $MSRV" >> /etc/hosts fi From f7df14b48f3f1945fe9540920080ee1fad4c6647 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 5 Nov 2019 08:58:51 -0500 Subject: [PATCH 031/200] add os patch scheduling options to the network install script - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/84 --- so-setup-network.sh | 107 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/so-setup-network.sh b/so-setup-network.sh index 6e54b8ce4..23cde3a5b 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -619,6 +619,42 @@ node_pillar() { } +patch_pillar() { + OSPATCHPILLARDIR="$TMP/patch/os" + OSPATCHPILLAR="$OSPATCHPILLARDIR/$MINION_ID.sls" + + if [ ! -d $OSPATCHPILLARDIR ] ; then + mkdir -p $OSPATCHPILLARDIR + fi + touch $OSPATCHPILLAR + echo "patch:" > $OSPATCHPILLAR + case $PATCHSCHEDULE in + Scheduled) + echo " os:" >> $OSPATCHPILLAR + echo " schedule:" >> $OSPATCHPILLAR + for psd in "${PATCHSCHEDULEDAYS[@]}" + do + psd=$(echo $psd | sed 's/"//g') + echo " - $psd:" >> $OSPATCHPILLAR + for psh in "${PATCHSCHEDULEHOURS[@]}" + do + psh=$(echo $psh | sed 's/"//g') + echo " - $psh" >> $OSPATCHPILLAR + done + done + ;; + Automatic) + echo " os:" >> $OSPATCHPILLAR + echo " schedule: auto" >> $OSPATCHPILLAR + ;; + Manual) + echo " os:" >> $OSPATCHPILLAR + echo " schedule: manual" >> $OSPATCHPILLAR + ;; + esac + +} + process_components() { CLEAN=${COMPONENTS//\"} GRAFANA=0 @@ -1469,6 +1505,69 @@ whiptail_passwords_dont_match() { } +whiptail_patch_schedule() { + + # What kind of patch schedule are we doing? + PATCHSCHEDULE=$(whiptail --title "Security Onion Setup" --radiolist \ + "Choose OS patch schedule. This will NOT update Security Onion related tools such as Zeek, Elasticsearch, Kibana, SaltStack, etc." 25 75 5 \ + "Automatic" "Package updates will be installed automatically" ON \ + "Manual" "Package updates will need to be installed manually" OFF \ + "Scheduled" "Select a schedule on the following screen" OFF 3>&1 1>&2 2>&3 ) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_patch_schedule_select_days() { + # Select the days to patch + PATCHSCHEDULEDAYS=($(whiptail --title "Security Onion Setup" --checklist \ + "Which days do you want to apply OS patches?" 20 55 9 \ + "Monday" "" OFF \ + "Tuesday" "" ON \ + "Wednesday" "" OFF \ + "Thursday" "" OFF \ + "Friday" "" OFF \ + "Saturday" "" OFF \ + "Sunday" "" OFF 3>&1 1>&2 2>&3 )) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus +} + +whiptail_patch_schedule_select_hours() { + # Select the hours to patch + PATCHSCHEDULEHOURS=($(whiptail --title "Security Onion Setup" --checklist \ + "At which time, UTC, do you want to apply OS patches on the selected days?" 35 55 26 \ + "00:00" "" OFF \ + "01:00" "" OFF \ + "02:00" "" OFF \ + "03:00" "" OFF \ + "04:00" "" OFF \ + "05:00" "" OFF \ + "06:00" "" OFF \ + "07:00" "" OFF \ + "08:00" "" OFF \ + "09:00" "" OFF \ + "10:00" "" OFF \ + "11:00" "" OFF \ + "12:00" "" OFF \ + "13:00" "" OFF \ + "14:00" "" OFF \ + "15:00" "" ON \ + "16:00" "" OFF \ + "17:00" "" OFF \ + "18:00" "" OFF \ + "19:00" "" OFF \ + "20:00" "" OFF \ + "21:00" "" OFF \ + "22:00" "" OFF \ + "23:00" "" OFF 3>&1 1>&2 2>&3 )) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus +} + whiptail_rule_setup() { # Get pulled pork info @@ -1609,6 +1708,14 @@ if (whiptail_you_sure); then # What kind of install are we doing? whiptail_install_type + # How do we want to handle OS patching? manual, auto or scheduled days and hours + whiptail_patch_schedule + if [[ $PATCHSCHEDULE == "Scheduled" ]] ; then + whiptail_patch_schedule_select_days + whiptail_patch_schedule_select_hours + fi + patch_pillar + #################### ## Master ## #################### From 5e5d0d616cdd3e8e2ef07202a6d677fccfa6d85f Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 5 Nov 2019 14:22:37 -0500 Subject: [PATCH 032/200] copy_minion_pillar replaced with copy_minion_pillar to simplify pillar copying, os patch pillar written - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/84 --- so-setup-network.sh | 108 +++++++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 46 deletions(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index 23cde3a5b..bed63a0c6 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -268,14 +268,15 @@ copy_master_config() { } -copy_minion_pillar() { +copy_minion_pillars() { - # Pass the type so it knows where to copy the pillar - local TYPE=$1 - - # Copy over the pillar - echo "Copying the pillar over" >> $SETUPLOG 2>&1 - scp -v -i /root/.ssh/so.key $TMP/$MINION_ID.sls socore@$MSRV:/opt/so/saltstack/pillar/$TYPE/$MINION_ID.sls + if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then + echo "rsyncing TMP pillar files to pillar base" >> $SETUPLOG 2>&1 + rsync -a -v $TMP/pillar/ /opt/so/saltstack/pillar/ >> $SETUPLOG 2>&1 + else + echo "scp TMP pillar files to pillar base on master" >> $SETUPLOG 2>&1 + scp -prv -i /root/.ssh/so.key $TMP/pillar socore@$MSRV:/opt/so/saltstack/pillar >> $SETUPLOG 2>&1 + fi } @@ -599,28 +600,33 @@ minio_generate_keys() { node_pillar() { + NODEPILLARPATH=$TMP/pillar/nodes + if [ ! -d $NODEPILLARPATH ]; then + mkdir -p $NODEPILLARPATH + fi + # Create the node pillar - touch $TMP/$MINION_ID.sls - echo "node:" > $TMP/$MINION_ID.sls - echo " mainip: $MAINIP" >> $TMP/$MINION_ID.sls - echo " mainint: $MAININT" >> $TMP/$MINION_ID.sls - echo " esheap: $NODE_ES_HEAP_SIZE" >> $TMP/$MINION_ID.sls - echo " esclustername: {{ grains.host }}" >> $TMP/$MINION_ID.sls - echo " lsheap: $NODE_LS_HEAP_SIZE" >> $TMP/$MINION_ID.sls - echo " ls_pipeline_workers: $LSPIPELINEWORKERS" >> $TMP/$MINION_ID.sls - echo " ls_pipeline_batch_size: $LSPIPELINEBATCH" >> $TMP/$MINION_ID.sls - echo " ls_input_threads: $LSINPUTTHREADS" >> $TMP/$MINION_ID.sls - echo " ls_batch_count: $LSINPUTBATCHCOUNT" >> $TMP/$MINION_ID.sls - echo " es_shard_count: $SHARDCOUNT" >> $TMP/$MINION_ID.sls - echo " node_type: $NODETYPE" >> $TMP/$MINION_ID.sls - echo " es_port: $NODE_ES_PORT" >> $TMP/$MINION_ID.sls - echo " log_size_limit: $LOG_SIZE_LIMIT" >> $TMP/$MINION_ID.sls - echo " cur_close_days: $CURCLOSEDAYS" >> $TMP/$MINION_ID.sls + touch $NODEPILLARPATH/$MINION_ID.sls + echo "node:" > $NODEPILLARPATH/$MINION_ID.sls + echo " mainip: $MAINIP" >> $NODEPILLARPATH/$MINION_ID.sls + echo " mainint: $MAININT" >> $NODEPILLARPATH/$MINION_ID.sls + echo " esheap: $NODE_ES_HEAP_SIZE" >> $NODEPILLARPATH/$MINION_ID.sls + echo " esclustername: {{ grains.host }}" >> $NODEPILLARPATH/$MINION_ID.sls + echo " lsheap: $NODE_LS_HEAP_SIZE" >> $NODEPILLARPATH/$MINION_ID.sls + echo " ls_pipeline_workers: $LSPIPELINEWORKERS" >> $NODEPILLARPATH/$MINION_ID.sls + echo " ls_pipeline_batch_size: $LSPIPELINEBATCH" >> $NODEPILLARPATH/$MINION_ID.sls + echo " ls_input_threads: $LSINPUTTHREADS" >> $NODEPILLARPATH/$MINION_ID.sls + echo " ls_batch_count: $LSINPUTBATCHCOUNT" >> $NODEPILLARPATH/$MINION_ID.sls + echo " es_shard_count: $SHARDCOUNT" >> $NODEPILLARPATH/$MINION_ID.sls + echo " node_type: $NODETYPE" >> $NODEPILLARPATH/$MINION_ID.sls + echo " es_port: $NODE_ES_PORT" >> $NODEPILLARPATH/$MINION_ID.sls + echo " log_size_limit: $LOG_SIZE_LIMIT" >> $NODEPILLARPATH/$MINION_ID.sls + echo " cur_close_days: $CURCLOSEDAYS" >> $NODEPILLARPATH/$MINION_ID.sls } patch_pillar() { - OSPATCHPILLARDIR="$TMP/patch/os" + OSPATCHPILLARDIR="$TMP/pillar/patch/os" OSPATCHPILLAR="$OSPATCHPILLARDIR/$MINION_ID.sls" if [ ! -d $OSPATCHPILLARDIR ] ; then @@ -962,37 +968,42 @@ salt_master_directories() { sensor_pillar() { + SENSORPILLARPATH=$TMP/pillar/sensors + if [ ! -d $SENSORPILLARPATH ]; then + mkdir -p $SENSORPILLARPATH + fi + # Create the sensor pillar - touch $TMP/$MINION_ID.sls - echo "sensor:" > $TMP/$MINION_ID.sls - echo " interface: bond0" >> $TMP/$MINION_ID.sls - echo " mainip: $MAINIP" >> $TMP/$MINION_ID.sls - echo " mainint: $MAININT" >> $TMP/$MINION_ID.sls + touch $SENSORPILLARPATH/$MINION_ID.sls + echo "sensor:" > $SENSORPILLARPATH/$MINION_ID.sls + echo " interface: bond0" >> $SENSORPILLARPATH/$MINION_ID.sls + echo " mainip: $MAINIP" >> $SENSORPILLARPATH/$MINION_ID.sls + echo " mainint: $MAININT" >> $SENSORPILLARPATH/$MINION_ID.sls if [ $NSMSETUP == 'ADVANCED' ]; then - echo " bro_pins:" >> $TMP/$MINION_ID.sls + echo " bro_pins:" >> $SENSORPILLARPATH/$MINION_ID.sls for PIN in $BROPINS; do PIN=$(echo $PIN | cut -d\" -f2) - echo " - $PIN" >> $TMP/$MINION_ID.sls + echo " - $PIN" >> $SENSORPILLARPATH/$MINION_ID.sls done - echo " suripins:" >> $TMP/$MINION_ID.sls + echo " suripins:" >> $SENSORPILLARPATH/$MINION_ID.sls for SPIN in $SURIPINS; do SPIN=$(echo $SPIN | cut -d\" -f2) - echo " - $SPIN" >> $TMP/$MINION_ID.sls + echo " - $SPIN" >> $SENSORPILLARPATH/$MINION_ID.sls done else - echo " bro_lbprocs: $BASICBRO" >> $TMP/$MINION_ID.sls - echo " suriprocs: $BASICSURI" >> $TMP/$MINION_ID.sls + echo " bro_lbprocs: $BASICBRO" >> $SENSORPILLARPATH/$MINION_ID.sls + echo " suriprocs: $BASICSURI" >> $SENSORPILLARPATH/$MINION_ID.sls fi - echo " brobpf:" >> $TMP/$MINION_ID.sls - echo " pcapbpf:" >> $TMP/$MINION_ID.sls - echo " nidsbpf:" >> $TMP/$MINION_ID.sls - echo " master: $MSRV" >> $TMP/$MINION_ID.sls - echo " mtu: $MTU" >> $TMP/$MINION_ID.sls + echo " brobpf:" >> $SENSORPILLARPATH/$MINION_ID.sls + echo " pcapbpf:" >> $SENSORPILLARPATH/$MINION_ID.sls + echo " nidsbpf:" >> $SENSORPILLARPATH/$MINION_ID.sls + echo " master: $MSRV" >> $SENSORPILLARPATH/$MINION_ID.sls + echo " mtu: $MTU" >> $SENSORPILLARPATH/$MINION_ID.sls if [ $HNSENSOR != 'inherit' ]; then - echo " hnsensor: $HNSENSOR" >> $TMP/$MINION_ID.sls + echo " hnsensor: $HNSENSOR" >> $SENSORPILLARPATH/$MINION_ID.sls fi - echo " access_key: $ACCESS_KEY" >> $TMP/$MINION_ID.sls - echo " access_secret: $ACCESS_SECRET" >> $TMP/$MINION_ID.sls + echo " access_key: $ACCESS_KEY" >> $SENSORPILLARPATH/$MINION_ID.sls + echo " access_secret: $ACCESS_SECRET" >> $SENSORPILLARPATH/$MINION_ID.sls } @@ -1811,6 +1822,8 @@ if (whiptail_you_sure); then echo "** Generating the master pillar **" >> $SETUPLOG master_pillar >> $SETUPLOG 2>&1 echo -e "XXX\n30\nAccepting Salt Keys... \nXXX" + echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" + copy_minion_pillars >> $SETUPLOG 2>&1 # Do a checkin to push the key up echo "** Pushing the key up to Master **" >> $SETUPLOG salt_firstcheckin >> $SETUPLOG 2>&1 @@ -1931,8 +1944,8 @@ if (whiptail_you_sure); then docker_install >> $SETUPLOG 2>&1 echo -e "XXX\n22\nConfiguring Salt Minion... \nXXX" configure_minion sensor >> $SETUPLOG 2>&1 - echo -e "XXX\n24\nCopying Sensor Pillar to Master... \nXXX" - copy_minion_pillar sensors >> $SETUPLOG 2>&1 + echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" + copy_minion_pillars >> $SETUPLOG 2>&1 echo -e "XXX\n25\nSending Salt Key to Master... \nXXX" salt_firstcheckin >> $SETUPLOG 2>&1 echo -e "XXX\n26\nTelling the Master to Accept Key... \nXXX" @@ -2044,6 +2057,8 @@ if (whiptail_you_sure); then node_pillar >> $SETUPLOG 2>&1 echo -e "XXX\n8\nCreating firewall policies... \nXXX" set_initial_firewall_policy >> $SETUPLOG 2>&1 + echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" + copy_minion_pillars >> $SETUPLOG 2>&1 echo -e "XXX\n10\nRegistering agent... \nXXX" salt_firstcheckin >> $SETUPLOG 2>&1 echo -e "XXX\n11\nAccepting Agent... \nXXX" @@ -2185,7 +2200,8 @@ if (whiptail_you_sure); then configure_minion node >> $SETUPLOG 2>&1 set_node_type >> $SETUPLOG 2>&1 node_pillar >> $SETUPLOG 2>&1 - copy_minion_pillar nodes >> $SETUPLOG 2>&1 + echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" + copy_minion_pillars >> $SETUPLOG 2>&1 echo -e "XXX\n35\nSending and Accepting Salt Key... \nXXX" salt_firstcheckin >> $SETUPLOG 2>&1 # Accept the Salt Key From f608cba4426fabd74675b88babc2d0b21dae7f18 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 5 Nov 2019 15:46:14 -0500 Subject: [PATCH 033/200] Sensoroni State - Fix log location --- salt/sensoroni/init.sls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/sensoroni/init.sls b/salt/sensoroni/init.sls index 245c34344..83e960716 100644 --- a/salt/sensoroni/init.sls +++ b/salt/sensoroni/init.sls @@ -41,7 +41,7 @@ so-sensoroni: - binds: - /nsm/sensoroni/jobs:/opt/sensoroni/jobs:rw - /opt/so/conf/sensoroni/sensoroni.json:/opt/sensoroni/sensoroni.json:ro - - /opt/so/log/sensoroni/:/opt/sensoroni/log/:rw + - /opt/so/log/sensoroni/:/opt/sensoroni/logs/:rw - port_bindings: - 0.0.0.0:9822:9822 - watch: From 21494ab1ffd32a801cd261be95fd5ec6c5cec0d0 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 5 Nov 2019 16:01:12 -0500 Subject: [PATCH 034/200] install package python-dateutil during setup to help with job scheduling - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/84 --- so-setup-network.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index bed63a0c6..38f5b7e44 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -833,7 +833,7 @@ EOF fi yum clean expire-cache - yum -y install salt-minion-2018.3.4 yum-utils device-mapper-persistent-data lvm2 openssl + yum -y install salt-minion-2018.3.4 yum-utils device-mapper-persistent-data lvm2 openssl python-dateutil yum -y update exclude=salt* systemctl enable salt-minion @@ -882,7 +882,7 @@ EOF # Initialize the new repos apt-get update >> $SETUPLOG 2>&1 - apt-get -y install salt-minion=2018.3.4+ds-1 salt-common=2018.3.4+ds-1 python-m2crypto >> $SETUPLOG 2>&1 + apt-get -y install salt-minion=2018.3.4+ds-1 salt-common=2018.3.4+ds-1 python-m2cryptoi python-dateutil >> $SETUPLOG 2>&1 apt-mark hold salt-minion salt-common else @@ -896,7 +896,7 @@ EOF echo "deb https://packages.wazuh.com/3.x/apt/ stable main" | tee /etc/apt/sources.list.d/wazuh.list # Initialize the new repos apt-get update >> $SETUPLOG 2>&1 - apt-get -y install salt-minion=2018.3.4+ds-1 salt-common=2018.3.4+ds-1 python-m2crypto >> $SETUPLOG 2>&1 + apt-get -y install salt-minion=2018.3.4+ds-1 salt-common=2018.3.4+ds-1 python-m2crypto python-dateutil >> $SETUPLOG 2>&1 apt-mark hold salt-minion salt-common fi From e6421f45fb3ae862a115ce419d3bdf512c3e902b Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 5 Nov 2019 17:22:27 -0500 Subject: [PATCH 035/200] add state to add os patch schedule and state to apply patches - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/84 --- pillar/top.sls | 3 +++ salt/patch/os.sls | 4 ++++ salt/patch/schedule/os.sls | 32 ++++++++++++++++++++++++++++++++ salt/top.sls | 3 +++ 4 files changed, 42 insertions(+) create mode 100644 salt/patch/os.sls create mode 100644 salt/patch/schedule/os.sls diff --git a/pillar/top.sls b/pillar/top.sls index 031352a11..13ea5e5a8 100644 --- a/pillar/top.sls +++ b/pillar/top.sls @@ -1,4 +1,7 @@ base: + '*': + - patch.os.{{ grains.id }} + 'G@role:so-sensor': - sensors.{{ grains.id }} - static diff --git a/salt/patch/os.sls b/salt/patch/os.sls new file mode 100644 index 000000000..d3ae6a1ff --- /dev/null +++ b/salt/patch/os.sls @@ -0,0 +1,4 @@ +patch_os: + pkg.uptodate: + - name: patch_os + - refresh: True diff --git a/salt/patch/schedule/os.sls b/salt/patch/schedule/os.sls new file mode 100644 index 000000000..6056f8ee3 --- /dev/null +++ b/salt/patch/schedule/os.sls @@ -0,0 +1,32 @@ +{% if salt['pillar.get']('patch:os:schedule') != 'manual' and salt['pillar.get']('patch:os:schedule') != 'auto' %} + +patch_os_schedule: + schedule.present: + - function: state.sls + - job_args: + - patch.os + - when: + {% for day in pillar['patch']['os']['schedule'] %} + {% for day, time in day.iteritems() %} + {% for each_time in time %} + - {{day}} {{each_time}} + {% endfor %} + {% endfor %} + {% endfor %} + - splay: + start: 5 + end: 10 + +{% elif salt['pillar.get']('patch:os:schedule') == 'auto' %} + +patch_os_schedule: + schedule.present: + - function: state.sls + - job_args: + - patch.os + - minutes: 20 + - splay: + start: 150 + end: 300 + +{% endif %} diff --git a/salt/top.sls b/salt/top.sls index cf5d47699..08d82285c 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -5,6 +5,9 @@ {%- set THEHIVE = salt['pillar.get']('master:thehive', '0') -%} {%- set PLAYBOOK = salt['pillar.get']('master:playbook', '0') -%} base: + '*': + - patch.schedule.os + 'G@role:so-sensor': - ca - ssl From c96678f5a0b87530e12d23407b20c7f279fb4865 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 5 Nov 2019 17:34:36 -0500 Subject: [PATCH 036/200] clean up variable name - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/84 --- salt/patch/schedule/os.sls | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/salt/patch/schedule/os.sls b/salt/patch/schedule/os.sls index 6056f8ee3..ebb84ad28 100644 --- a/salt/patch/schedule/os.sls +++ b/salt/patch/schedule/os.sls @@ -6,10 +6,10 @@ patch_os_schedule: - job_args: - patch.os - when: - {% for day in pillar['patch']['os']['schedule'] %} - {% for day, time in day.iteritems() %} - {% for each_time in time %} - - {{day}} {{each_time}} + {% for days in pillar['patch']['os']['schedule'] %} + {% for day, times in days.iteritems() %} + {% for time in times %} + - {{day}} {{time}} {% endfor %} {% endfor %} {% endfor %} From 9c83cceba15dff532566cb485f2cbd569265438d Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 5 Nov 2019 18:02:17 -0500 Subject: [PATCH 037/200] put quotes around hours to interpret properly for 24h - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/84 --- so-setup-network.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index 38f5b7e44..57280473a 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -645,7 +645,7 @@ patch_pillar() { for psh in "${PATCHSCHEDULEHOURS[@]}" do psh=$(echo $psh | sed 's/"//g') - echo " - $psh" >> $OSPATCHPILLAR + echo " - '$psh'" >> $OSPATCHPILLAR done done ;; From fa87308baca32d1a66e431209f679163543d3ce6 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Wed, 6 Nov 2019 07:47:00 -0500 Subject: [PATCH 038/200] change splay for scheduled pkg update - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/84 --- salt/patch/schedule/os.sls | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/patch/schedule/os.sls b/salt/patch/schedule/os.sls index ebb84ad28..a041afeea 100644 --- a/salt/patch/schedule/os.sls +++ b/salt/patch/schedule/os.sls @@ -14,8 +14,8 @@ patch_os_schedule: {% endfor %} {% endfor %} - splay: - start: 5 - end: 10 + start: 30 + end: 120 {% elif salt['pillar.get']('patch:os:schedule') == 'auto' %} From f3c204c7905019d75b94f9ede7f54b527329d34e Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Wed, 6 Nov 2019 13:37:42 -0500 Subject: [PATCH 039/200] Disable Beats input - Update sensoroni version --- salt/logstash/conf/conf.enabled.txt.so-eval | 2 +- salt/pcap/init.sls | 4 ++-- salt/sensoroni/init.sls | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/salt/logstash/conf/conf.enabled.txt.so-eval b/salt/logstash/conf/conf.enabled.txt.so-eval index dfc3ea421..d125fc829 100644 --- a/salt/logstash/conf/conf.enabled.txt.so-eval +++ b/salt/logstash/conf/conf.enabled.txt.so-eval @@ -13,7 +13,7 @@ #/usr/share/logstash/pipeline.so/0002_input_windows_json.conf #/usr/share/logstash/pipeline.so/0003_input_syslog.conf #/usr/share/logstash/pipeline.so/0005_input_suricata.conf -/usr/share/logstash/pipeline.dynamic/0006_input_beats.conf +#/usr/share/logstash/pipeline.dynamic/0006_input_beats.conf /usr/share/logstash/pipeline.so/0007_input_import.conf /usr/share/logstash/pipeline.dynamic/0010_input_hhbeats.conf #/usr/share/logstash/pipeline.so/1000_preprocess_log_elapsed.conf diff --git a/salt/pcap/init.sls b/salt/pcap/init.sls index ed23cf308..a49dc00e3 100644 --- a/salt/pcap/init.sls +++ b/salt/pcap/init.sls @@ -96,13 +96,13 @@ stenolog: so-stenoimage: cmd.run: - - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-steno:HH1.1.1 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-steno:HH1.1.3 so-steno: docker_container.running: - require: - so-stenoimage - - image: docker.io/soshybridhunter/so-steno:HH1.1.1 + - image: docker.io/soshybridhunter/so-steno:HH1.1.3 - network_mode: host - privileged: True - port_bindings: diff --git a/salt/sensoroni/init.sls b/salt/sensoroni/init.sls index 83e960716..19fcd8b4a 100644 --- a/salt/sensoroni/init.sls +++ b/salt/sensoroni/init.sls @@ -29,13 +29,13 @@ sensoronisync: so-sensoroniimage: cmd.run: - - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-sensoroni:HH1.1.1 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-sensoroni:HH1.1.3 so-sensoroni: docker_container.running: - require: - so-sensoroniimage - - image: docker.io/soshybridhunter/so-sensoroni:HH1.1.1 + - image: docker.io/soshybridhunter/so-sensoroni:HH1.1.3 - hostname: sensoroni - name: so-sensoroni - binds: From e323a448270b062be73de18d4c26e36c6f182877 Mon Sep 17 00:00:00 2001 From: Wes Lambert Date: Thu, 7 Nov 2019 14:37:18 +0000 Subject: [PATCH 040/200] change intial user role to superadmin --- salt/hive/thehive/scripts/cortex_init.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/hive/thehive/scripts/cortex_init.sh b/salt/hive/thehive/scripts/cortex_init.sh index 5d4de730b..3596c98dd 100644 --- a/salt/hive/thehive/scripts/cortex_init.sh +++ b/salt/hive/thehive/scripts/cortex_init.sh @@ -16,7 +16,7 @@ cortex_init(){ curl -v -k -XPOST "https://$CORTEX_IP:/cortex/api/maintenance/migrate" # Create intial Cortex user - curl -v -k "https://$CORTEX_IP/cortex/api/user" -H "Content-Type: application/json" -d "{\"login\" : \"$CORTEX_USER\",\"name\" : \"$CORTEX_USER\",\"roles\" : [\"read\",\"analyze\",\"orgadmin\"],\"preferences\" : \"{}\",\"password\" : \"$CORTEX_PASSWORD\", \"key\": \"$CORTEX_KEY\"}" + curl -v -k "https://$CORTEX_IP/cortex/api/user" -H "Content-Type: application/json" -d "{\"login\" : \"$CORTEX_USER\",\"name\" : \"$CORTEX_USER\",\"roles\" : [\"superadmin\"],\"preferences\" : \"{}\",\"password\" : \"$CORTEX_PASSWORD\", \"key\": \"$CORTEX_KEY\"}" # Enable URLScan.io Analyzer curl -v -k -XPOST -H "Authorization: Bearer $CORTEX_KEY" -H "Content-Type: application/json" "https://$CORTEX_IP/cortex/api/organization/analyzer/Urlscan_io_Search_0_1_0" -d '{"name":"Urlscan_io_Search_0_1_0","configuration":{"auto_extract_artifacts":false,"check_tlp":true,"max_tlp":2}}' From 9914e55ec3248b7f367085bab97f2fe99c6d7947 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 7 Nov 2019 09:49:36 -0500 Subject: [PATCH 041/200] rework of os patch scheduling, added the abilty to enable/disable and adjust splay - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/84 --- pillar/top.sls | 3 - salt/patch/{os.sls => os/init.sls} | 0 salt/patch/os/schedule.sls | 76 ++++++++++ salt/patch/os/schedules/example_schedule.yml | 10 ++ salt/patch/schedule/os.sls | 32 ----- salt/top.sls | 2 +- so-setup-network.sh | 139 ++++++++++++++----- 7 files changed, 188 insertions(+), 74 deletions(-) rename salt/patch/{os.sls => os/init.sls} (100%) create mode 100644 salt/patch/os/schedule.sls create mode 100644 salt/patch/os/schedules/example_schedule.yml delete mode 100644 salt/patch/schedule/os.sls diff --git a/pillar/top.sls b/pillar/top.sls index 13ea5e5a8..031352a11 100644 --- a/pillar/top.sls +++ b/pillar/top.sls @@ -1,7 +1,4 @@ base: - '*': - - patch.os.{{ grains.id }} - 'G@role:so-sensor': - sensors.{{ grains.id }} - static diff --git a/salt/patch/os.sls b/salt/patch/os/init.sls similarity index 100% rename from salt/patch/os.sls rename to salt/patch/os/init.sls diff --git a/salt/patch/os/schedule.sls b/salt/patch/os/schedule.sls new file mode 100644 index 000000000..9ea98ede7 --- /dev/null +++ b/salt/patch/os/schedule.sls @@ -0,0 +1,76 @@ +{% if salt['pillar.get']('patch:os:schedule_name') %} + {% set patch_os_pillar = salt['pillar.get']('patch:os') %} + {% set schedule_name = patch_os_pillar.schedule_name %} + {% set splay = patch_os_pillar.get('splay', 300) %} + + {% if schedule_name != 'manual' and schedule_name != 'auto' %} + {% import_yaml "patch/os/schedules/"~schedule_name~".yml" as os_schedule %} + + {% if patch_os_pillar.enabled %} + +patch_os_schedule: + schedule.present: + - function: state.sls + - job_args: + - patch.os + - when: + {% for days in os_schedule.patch.os.schedule %} + {% for day, times in days.iteritems() %} + {% for time in times %} + - {{day}} {{time}} + {% endfor %} + {% endfor %} + {% endfor %} + - splay: {{splay}} + - return_job: True + + {% else %} + +disable_patch_os_schedule: + schedule.disabled: + - name: patch_os_schedule + + {% endif %} + + + {% elif schedule_name == 'auto' %} + + {% if patch_os_pillar.enabled %} + +patch_os_schedule: + schedule.present: + - function: state.sls + - job_args: + - patch.os + - minutes: 1 + - splay: {{splay}} + - return_job: True + + {% else %} + +disable_patch_os_schedule: + schedule.disabled: + - name: patch_os_schedule + + {% endif %} + + {% elif schedule_name == 'manual' %} + +remove_patch_os_schedule: + schedule.absent: + - name: patch_os_schedule + + {% endif %} + +{% else %} + +no_os_patch_schedule_name_set: + test.fail_without_changes: + - name: "Set a pillar value for patch:os:schedule_name in this minion's .sls file. If an OS patch schedule is not listed as enabled in show_schedule output below, then OS patches will need to be applied manually until this is corrected." + +show_schedule: + module.run: + - name: schedule.is_enabled + - m_name: patch_os_schedule + +{% endif %} diff --git a/salt/patch/os/schedules/example_schedule.yml b/salt/patch/os/schedules/example_schedule.yml new file mode 100644 index 000000000..b2748ab09 --- /dev/null +++ b/salt/patch/os/schedules/example_schedule.yml @@ -0,0 +1,10 @@ +patch: + os: + schedule: + - Tuesday: + - '15:00' + - Thursday: + - '03:00' + - Saturday: + - '01:00' + - '15:00' diff --git a/salt/patch/schedule/os.sls b/salt/patch/schedule/os.sls deleted file mode 100644 index a041afeea..000000000 --- a/salt/patch/schedule/os.sls +++ /dev/null @@ -1,32 +0,0 @@ -{% if salt['pillar.get']('patch:os:schedule') != 'manual' and salt['pillar.get']('patch:os:schedule') != 'auto' %} - -patch_os_schedule: - schedule.present: - - function: state.sls - - job_args: - - patch.os - - when: - {% for days in pillar['patch']['os']['schedule'] %} - {% for day, times in days.iteritems() %} - {% for time in times %} - - {{day}} {{time}} - {% endfor %} - {% endfor %} - {% endfor %} - - splay: - start: 30 - end: 120 - -{% elif salt['pillar.get']('patch:os:schedule') == 'auto' %} - -patch_os_schedule: - schedule.present: - - function: state.sls - - job_args: - - patch.os - - minutes: 20 - - splay: - start: 150 - end: 300 - -{% endif %} diff --git a/salt/top.sls b/salt/top.sls index 08d82285c..f742a66cf 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -6,7 +6,7 @@ {%- set PLAYBOOK = salt['pillar.get']('master:playbook', '0') -%} base: '*': - - patch.schedule.os + - patch.os.schedule 'G@role:so-sensor': - ca diff --git a/so-setup-network.sh b/so-setup-network.sh index 57280473a..32217a865 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -268,14 +268,14 @@ copy_master_config() { } -copy_minion_pillars() { +copy_minion_tmp_files() { if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then - echo "rsyncing TMP pillar files to pillar base" >> $SETUPLOG 2>&1 - rsync -a -v $TMP/pillar/ /opt/so/saltstack/pillar/ >> $SETUPLOG 2>&1 + echo "rsyncing all files in $TMP to /opt/so/saltstack" >> $SETUPLOG 2>&1 + rsync -a -v $TMP/ /opt/so/saltstack/ >> $SETUPLOG 2>&1 else - echo "scp TMP pillar files to pillar base on master" >> $SETUPLOG 2>&1 - scp -prv -i /root/.ssh/so.key $TMP/pillar socore@$MSRV:/opt/so/saltstack/pillar >> $SETUPLOG 2>&1 + echo "scp all files in $TMP to master /opt/so/saltstack" >> $SETUPLOG 2>&1 + scp -prv -i /root/.ssh/so.key $TMP socore@$MSRV:/opt/so/saltstack >> $SETUPLOG 2>&1 fi } @@ -626,38 +626,51 @@ node_pillar() { } patch_pillar() { - OSPATCHPILLARDIR="$TMP/pillar/patch/os" - OSPATCHPILLAR="$OSPATCHPILLARDIR/$MINION_ID.sls" - if [ ! -d $OSPATCHPILLARDIR ] ; then - mkdir -p $OSPATCHPILLARDIR + case $INSTALLTYPE in + MASTERONLY | EVALMODE) + PATCHPILLARPATH=/opt/so/saltstack/pillar/masters + ;; + SENSORONLY) + PATCHPILLARPATH=$SENSORPILLARPATH + ;; + STORAGENODE | PARSINGNODE | HOTNODE | WARMNODE) + PATCHPILLARPATH=$NODEPILLARPATH + ;; + esac + + + echo "" >> $PATCHPILLARPATH/$MINION_ID.sls + echo "patch:" >> $PATCHPILLARPATH/$MINION_ID.sls + echo " os:" >> $PATCHPILLARPATH/$MINION_ID.sls + echo " schedule_name: $PATCHSCHEDULENAME" >> $PATCHPILLARPATH/$MINION_ID.sls + echo " enabled: True" >> $PATCHPILLARPATH/$MINION_ID.sls + echo " splay: 300" >> $PATCHPILLARPATH/$MINION_ID.sls + + +} + +patch_schedule_os_new() { + OSPATCHSCHEDULEDIR="$TMP/salt/patch/os/schedules" + OSPATCHSCHEDULE="$OSPATCHSCHEDULEDIR/$PATCHSCHEDULENAME.yml" + + if [ ! -d $OSPATCHSCHEDULEDIR ] ; then + mkdir -p $OSPATCHSCHEDULEDIR fi - touch $OSPATCHPILLAR - echo "patch:" > $OSPATCHPILLAR - case $PATCHSCHEDULE in - Scheduled) - echo " os:" >> $OSPATCHPILLAR - echo " schedule:" >> $OSPATCHPILLAR + + echo "patch:" > $OSPATCHSCHEDULE + echo " os:" >> $OSPATCHSCHEDULE + echo " schedule:" >> $OSPATCHSCHEDULE for psd in "${PATCHSCHEDULEDAYS[@]}" do psd=$(echo $psd | sed 's/"//g') - echo " - $psd:" >> $OSPATCHPILLAR + echo " - $psd:" >> $OSPATCHSCHEDULE for psh in "${PATCHSCHEDULEHOURS[@]}" do psh=$(echo $psh | sed 's/"//g') - echo " - '$psh'" >> $OSPATCHPILLAR + echo " - '$psh'" >> $OSPATCHSCHEDULE done done - ;; - Automatic) - echo " os:" >> $OSPATCHPILLAR - echo " schedule: auto" >> $OSPATCHPILLAR - ;; - Manual) - echo " os:" >> $OSPATCHPILLAR - echo " schedule: manual" >> $OSPATCHPILLAR - ;; - esac } @@ -1516,20 +1529,50 @@ whiptail_passwords_dont_match() { } +whiptail_patch_name_new_schedule() { + + unset PATCHSCHEDULENAME + while [[ -z "$PATCHSCHEDULENAME" ]]; do + PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ + "What name do you want to give this OS patch schedule? This schedule needs to be named uniquely. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 75 3>&1 1>&2 2>&3) + done + + +} + whiptail_patch_schedule() { # What kind of patch schedule are we doing? PATCHSCHEDULE=$(whiptail --title "Security Onion Setup" --radiolist \ - "Choose OS patch schedule. This will NOT update Security Onion related tools such as Zeek, Elasticsearch, Kibana, SaltStack, etc." 25 75 5 \ + "Choose OS patch schedule. This will NOT update Security Onion related tools such as Zeek, Elasticsearch, Kibana, SaltStack, etc." 25 115 5 \ "Automatic" "Package updates will be installed automatically" ON \ "Manual" "Package updates will need to be installed manually" OFF \ - "Scheduled" "Select a schedule on the following screen" OFF 3>&1 1>&2 2>&3 ) + "Import Schedule" "Enter the name of an existing schedule on the following screen and inherit it" OFF \ + "New Schedule" "Configure and name a new schedule on the following screen" OFF 3>&1 1>&2 2>&3 ) local exitstatus=$? whiptail_check_exitstatus $exitstatus } +whiptail_patch_schedule_import() { + + unset PATCHSCHEDULENAME + # Ask to inherit from master + whiptail --title "Security Onion Setup" --yesno "Do you want to inherit the OS patch schedule from the master?" 8 78 + + local exitstatus=$? + if [ $exitstatus == 0 ]; then + PATCHSCHEDULENAME=default + else + while [[ -z "$PATCHSCHEDULENAME" ]]; do + PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter the name of the OS patch schedule you want to inherit. If you leave this as default, it will use the same schedule as the master. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 60 default 3>&1 1>&2 2>&3) + done + fi + +} + whiptail_patch_schedule_select_days() { # Select the days to patch PATCHSCHEDULEDAYS=($(whiptail --title "Security Onion Setup" --checklist \ @@ -1721,11 +1764,23 @@ if (whiptail_you_sure); then # How do we want to handle OS patching? manual, auto or scheduled days and hours whiptail_patch_schedule - if [[ $PATCHSCHEDULE == "Scheduled" ]] ; then - whiptail_patch_schedule_select_days - whiptail_patch_schedule_select_hours - fi - patch_pillar + case $PATCHSCHEDULE in + 'New Schedule') + whiptail_patch_schedule_select_days + whiptail_patch_schedule_select_hours + whiptail_patch_name_new_schedule + patch_schedule_os_new + ;; + 'Import Schedule') + whiptail_patch_schedule_import + ;; + Automatic) + PATCHSCHEDULENAME=auto + ;; + Manual) + PATCHSCHEDULENAME=manual + ;; + esac #################### ## Master ## @@ -1821,9 +1876,11 @@ if (whiptail_you_sure); then master_static >> $SETUPLOG 2>&1 echo "** Generating the master pillar **" >> $SETUPLOG master_pillar >> $SETUPLOG 2>&1 + echo "** Generating the patch pillar **" >> $SETUPLOG + patch_pillar >> $SETUPLOG 2>&1 echo -e "XXX\n30\nAccepting Salt Keys... \nXXX" echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" - copy_minion_pillars >> $SETUPLOG 2>&1 + copy_minion_tmp_files >> $SETUPLOG 2>&1 # Do a checkin to push the key up echo "** Pushing the key up to Master **" >> $SETUPLOG salt_firstcheckin >> $SETUPLOG 2>&1 @@ -1938,6 +1995,8 @@ if (whiptail_you_sure); then network_setup >> $SETUPLOG 2>&1 echo -e "XXX\n4\nGenerating Sensor Pillar... \nXXX" sensor_pillar >> $SETUPLOG 2>&1 + echo "** Generating the patch pillar **" >> $SETUPLOG + patch_pillar >> $SETUPLOG 2>&1 echo -e "XXX\n5\nInstalling Salt Components... \nXXX" saltify >> $SETUPLOG 2>&1 echo -e "XXX\n20\nInstalling Docker... \nXXX" @@ -1945,7 +2004,7 @@ if (whiptail_you_sure); then echo -e "XXX\n22\nConfiguring Salt Minion... \nXXX" configure_minion sensor >> $SETUPLOG 2>&1 echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" - copy_minion_pillars >> $SETUPLOG 2>&1 + copy_minion_tmp_files >> $SETUPLOG 2>&1 echo -e "XXX\n25\nSending Salt Key to Master... \nXXX" salt_firstcheckin >> $SETUPLOG 2>&1 echo -e "XXX\n26\nTelling the Master to Accept Key... \nXXX" @@ -2049,6 +2108,8 @@ if (whiptail_you_sure); then master_static >> $SETUPLOG 2>&1 echo -e "XXX\n7\nCreating the master pillar... \nXXX" master_pillar >> $SETUPLOG 2>&1 + echo "** Generating the patch pillar **" >> $SETUPLOG + patch_pillar >> $SETUPLOG 2>&1 echo -e "XXX\n7\nConfiguring minion... \nXXX" configure_minion eval >> $SETUPLOG 2>&1 echo -e "XXX\n7\nSetting the node type to eval... \nXXX" @@ -2058,7 +2119,7 @@ if (whiptail_you_sure); then echo -e "XXX\n8\nCreating firewall policies... \nXXX" set_initial_firewall_policy >> $SETUPLOG 2>&1 echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" - copy_minion_pillars >> $SETUPLOG 2>&1 + copy_minion_tmp_files >> $SETUPLOG 2>&1 echo -e "XXX\n10\nRegistering agent... \nXXX" salt_firstcheckin >> $SETUPLOG 2>&1 echo -e "XXX\n11\nAccepting Agent... \nXXX" @@ -2200,8 +2261,10 @@ if (whiptail_you_sure); then configure_minion node >> $SETUPLOG 2>&1 set_node_type >> $SETUPLOG 2>&1 node_pillar >> $SETUPLOG 2>&1 + echo "** Generating the patch pillar **" >> $SETUPLOG + patch_pillar >> $SETUPLOG 2>&1 echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" - copy_minion_pillars >> $SETUPLOG 2>&1 + copy_minion_tmp_files >> $SETUPLOG 2>&1 echo -e "XXX\n35\nSending and Accepting Salt Key... \nXXX" salt_firstcheckin >> $SETUPLOG 2>&1 # Accept the Salt Key From 98cd96eeddd47f9bf68c9061dba4590c6339dbe0 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 7 Nov 2019 10:18:40 -0500 Subject: [PATCH 042/200] change auto schedule to every 8 hours and update wording of whiptail auto patch selection - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/84 --- salt/patch/os/schedule.sls | 2 +- so-setup-network.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/patch/os/schedule.sls b/salt/patch/os/schedule.sls index 9ea98ede7..128862fa7 100644 --- a/salt/patch/os/schedule.sls +++ b/salt/patch/os/schedule.sls @@ -42,7 +42,7 @@ patch_os_schedule: - function: state.sls - job_args: - patch.os - - minutes: 1 + - hours: 8 - splay: {{splay}} - return_job: True diff --git a/so-setup-network.sh b/so-setup-network.sh index 32217a865..40ada00cc 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -1545,7 +1545,7 @@ whiptail_patch_schedule() { # What kind of patch schedule are we doing? PATCHSCHEDULE=$(whiptail --title "Security Onion Setup" --radiolist \ "Choose OS patch schedule. This will NOT update Security Onion related tools such as Zeek, Elasticsearch, Kibana, SaltStack, etc." 25 115 5 \ - "Automatic" "Package updates will be installed automatically" ON \ + "Automatic" "Package updates will be installed automatically every 8 hours if available" ON \ "Manual" "Package updates will need to be installed manually" OFF \ "Import Schedule" "Enter the name of an existing schedule on the following screen and inherit it" OFF \ "New Schedule" "Configure and name a new schedule on the following screen" OFF 3>&1 1>&2 2>&3 ) From 43915488e27689fb444dfd18d3758d45f126ced6 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 7 Nov 2019 10:50:27 -0500 Subject: [PATCH 043/200] prevent hostname from being localhost in setup script - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/101 --- so-setup-network.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/so-setup-network.sh b/so-setup-network.sh index 40ada00cc..c82a9f6f5 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -1654,6 +1654,13 @@ whiptail_set_hostname() { HOSTNAME=$(whiptail --title "Security Onion Setup" --inputbox \ "Enter the Hostname you would like to set." 10 60 $HOSTNAME 3>&1 1>&2 2>&3) + while [[ "$HOSTNAME" == 'localhost' ]] ; do + whiptail --title "Security Onion Setup" --msgbox "Please choose a hostname that isn't localhost." 8 65 + HOSTNAME=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter the Hostname you would like to set." 10 60 $HOSTNAME 3>&1 1>&2 2>&3) + done + + local exitstatus=$? whiptail_check_exitstatus $exitstatus From d849c33b9c37ce53ee306ba26a439c6aa18f33a6 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 7 Nov 2019 10:57:35 -0500 Subject: [PATCH 044/200] ensure the os patch schedule name is set - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/84 --- so-setup-network.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index c82a9f6f5..f43bebd70 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -1530,9 +1530,12 @@ whiptail_passwords_dont_match() { } whiptail_patch_name_new_schedule() { + + PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ + "What name do you want to give this OS patch schedule? This schedule needs to be named uniquely. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 75 3>&1 1>&2 2>&3) - unset PATCHSCHEDULENAME while [[ -z "$PATCHSCHEDULENAME" ]]; do + whiptail --title "Security Onion Setup" --msgbox "Please enter a name for this OS patch schedule." 8 65 PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ "What name do you want to give this OS patch schedule? This schedule needs to be named uniquely. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 75 3>&1 1>&2 2>&3) done From c640a0bf9bb55feea412f7c2b3d0cb11f0e397b4 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 7 Nov 2019 11:22:42 -0500 Subject: [PATCH 045/200] ensure inherit patch schedule name isn't blank, allow cancel from inherit screen - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/84 --- so-setup-network.sh | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index f43bebd70..de7b6f137 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -1532,12 +1532,17 @@ whiptail_passwords_dont_match() { whiptail_patch_name_new_schedule() { PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ - "What name do you want to give this OS patch schedule? This schedule needs to be named uniquely. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 75 3>&1 1>&2 2>&3) + "What name do you want to give this OS patch schedule? This schedule needs to be named uniquely. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 105 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus while [[ -z "$PATCHSCHEDULENAME" ]]; do whiptail --title "Security Onion Setup" --msgbox "Please enter a name for this OS patch schedule." 8 65 PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ - "What name do you want to give this OS patch schedule? This schedule needs to be named uniquely. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 75 3>&1 1>&2 2>&3) + "What name do you want to give this OS patch schedule? This schedule needs to be named uniquely. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 105 3>&1 1>&2 2>&3) + local exitstatus=$? + whiptail_check_exitstatus $exitstatus done @@ -1561,18 +1566,20 @@ whiptail_patch_schedule() { whiptail_patch_schedule_import() { unset PATCHSCHEDULENAME - # Ask to inherit from master - whiptail --title "Security Onion Setup" --yesno "Do you want to inherit the OS patch schedule from the master?" 8 78 + PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter the name of the OS patch schedule you want to inherit. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 60 3>&1 1>&2 2>&3) local exitstatus=$? - if [ $exitstatus == 0 ]; then - PATCHSCHEDULENAME=default - else - while [[ -z "$PATCHSCHEDULENAME" ]]; do - PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter the name of the OS patch schedule you want to inherit. If you leave this as default, it will use the same schedule as the master. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 60 default 3>&1 1>&2 2>&3) - done - fi + whiptail_check_exitstatus $exitstatus + + while [[ -z "$PATCHSCHEDULENAME" ]]; do + whiptail --title "Security Onion Setup" --msgbox "Please enter a name for the OS patch schedule you want to inherit." 8 65 + PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter the name of the OS patch schedule you want to inherit. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 60 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + done } From 7d29787512c093e57259e5c38901487fad5f4c90 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Thu, 7 Nov 2019 11:44:08 -0500 Subject: [PATCH 046/200] Update nids2hive.yaml --- salt/elastalert/files/rules/so/nids2hive.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/salt/elastalert/files/rules/so/nids2hive.yaml b/salt/elastalert/files/rules/so/nids2hive.yaml index 92de99537..019a0844f 100644 --- a/salt/elastalert/files/rules/so/nids2hive.yaml +++ b/salt/elastalert/files/rules/so/nids2hive.yaml @@ -15,7 +15,7 @@ timeframe: buffer_time: minutes: 10 allow_buffer_time_overlap: true -query_key: alert +query_key: ["alert", "ips"] realert: days: 1 @@ -36,11 +36,11 @@ hive_proxies: hive_alert_config: title: '{match[alert]}' - type: 'external' + type: 'NIDS' source: 'SecurityOnion' description: "`NIDS Dashboard:` \n\n \n\n `IPs: `{match[source_ip]}:{match[source_port]} --> {match[destination_ip]}:{match[destination_port]} \n\n `Signature:` {match[rule_signature]}" severity: 2 - tags: ['elastalert', 'SecurityOnion', 'NIDS','{match[sid]}'] + tags: ['{match[sid]}','{match[source_ip]}','{match[destination_ip]}'] tlp: 3 status: 'New' follow: True From d99b865527850733320779c8cfd36036a5e31c97 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Thu, 7 Nov 2019 13:27:38 -0500 Subject: [PATCH 047/200] Do not disable a rule when an uncaught exception is thrown --- salt/elastalert/files/elastalert_config.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/salt/elastalert/files/elastalert_config.yaml b/salt/elastalert/files/elastalert_config.yaml index 6a918093b..735ccb190 100644 --- a/salt/elastalert/files/elastalert_config.yaml +++ b/salt/elastalert/files/elastalert_config.yaml @@ -8,6 +8,11 @@ rules_folder: /etc/elastalert/rules/ # the rules directory - true or false scan_subdirectories: true +# Do not disable a rule when an uncaught exception is thrown - +# This setting should be tweaked once the following issue has been fixed +# https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/98 +disable_rules_on_error: false + # How often ElastAlert will query Elasticsearch # The unit can be anything from weeks to seconds run_every: From cf0164a55b761d25e11d4d8630a93a46259e9d8f Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Thu, 7 Nov 2019 15:40:54 -0500 Subject: [PATCH 048/200] SOCtopus - move logging outside container --- salt/soctopus/init.sls | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/salt/soctopus/init.sls b/salt/soctopus/init.sls index ebfbe3224..a5c72e362 100644 --- a/salt/soctopus/init.sls +++ b/salt/soctopus/init.sls @@ -12,6 +12,12 @@ soctopussync: - user: 939 - group: 939 - template: jinja + +soctopuslogdir: + file.directory: + - name: /opt/so/log/soctopus + - user: 939 + - group: 939 playbookrulesdir: file.directory: @@ -51,6 +57,7 @@ so-soctopus: - name: so-soctopus - binds: - /opt/so/conf/soctopus/SOCtopus.conf:/SOCtopus/SOCtopus.conf:ro + - /opt/so/log/soctopus/:/var/log/SOCtopus/:rw - /opt/so/rules/elastalert/playbook:/etc/playbook-rules:rw - /opt/so/conf/playbook/nav_layer_playbook.json:/etc/playbook/nav_layer_playbook.json:rw - port_bindings: From c0cb281d27d883e6b7bde89235d78293096b5d56 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Thu, 7 Nov 2019 15:41:40 -0500 Subject: [PATCH 049/200] Move logging outside container --- salt/soctopus/files/SOCtopus.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/soctopus/files/SOCtopus.conf b/salt/soctopus/files/SOCtopus.conf index f1d311602..dd32507ef 100644 --- a/salt/soctopus/files/SOCtopus.conf +++ b/salt/soctopus/files/SOCtopus.conf @@ -50,4 +50,4 @@ playbook_url = http://{{ip}}:3200/playbook playbook_key = a4a34538782804adfcb8dfae96262514ad70c37c [log] -logfile = /tmp/soctopus.log +logfile = /var/log/SOCtopus/soctopus.log From 0ff5541801ccd556e419ce64920e72a0d2851913 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 7 Nov 2019 17:27:38 -0500 Subject: [PATCH 050/200] upgrade salt to 2019.2.2 - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/105 --- so-setup-network.sh | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index de7b6f137..d3ae360f1 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -500,7 +500,7 @@ install_master() { wget --inet4-only -O /opt/so/gpg/GPG-KEY-WAZUH https://packages.wazuh.com/key/GPG-KEY-WAZUH else - apt-get install -y salt-common=2018.3.4+ds-1 salt-master=2018.3.4+ds-1 salt-minion=2018.3.4+ds-1 python-m2crypto + apt-get install -y salt-common=2019.2.2+ds-1 salt-master=2019.2.2+ds-1 salt-minion=2019.2.2+ds-1 python-m2crypto apt-mark hold salt-common salt-master salt-minion apt-get install -y python-m2crypto fi @@ -697,8 +697,8 @@ saltify() { if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then yum -y install https://repo.saltstack.com/yum/redhat/salt-repo-latest-2.el7.noarch.rpm - cp /etc/yum.repos.d/salt-latest.repo /etc/yum.repos.d/salt-2018-3.repo - sed -i 's/latest/2018.3/g' /etc/yum.repos.d/salt-2018-3.repo + cp /etc/yum.repos.d/salt-latest.repo /etc/yum.repos.d/salt-2019-2.repo + sed -i 's/latest/2019.2/g' /etc/yum.repos.d/salt-2019-2.repo cat > /etc/yum.repos.d/wazuh.repo <<\EOF [wazuh_repo] gpgcheck=1 @@ -812,13 +812,13 @@ EOF echo "gpgkey=file:///etc/pki/rpm-gpg/saltstack-signing-key" >> /etc/yum.repos.d/salt-latest.repo # Proxy is hating on me.. Lets just set it manually - echo "[salt-2018.3]" > /etc/yum.repos.d/salt-2018-3.repo - echo "name=SaltStack Latest Release Channel for RHEL/Centos \$releasever" >> /etc/yum.repos.d/salt-2018-3.repo - echo "baseurl=https://repo.saltstack.com/yum/redhat/7/\$basearch/2018.3" >> /etc/yum.repos.d/salt-2018-3.repo - echo "failovermethod=priority" >> /etc/yum.repos.d/salt-2018-3.repo - echo "enabled=1" >> /etc/yum.repos.d/salt-2018-3.repo - echo "gpgcheck=1" >> /etc/yum.repos.d/salt-2018-3.repo - echo "gpgkey=file:///etc/pki/rpm-gpg/saltstack-signing-key" >> /etc/yum.repos.d/salt-2018-3.repo + echo "[salt-2019.2]" > /etc/yum.repos.d/salt-2019-2.repo + echo "name=SaltStack Latest Release Channel for RHEL/Centos \$releasever" >> /etc/yum.repos.d/salt-2019-2.repo + echo "baseurl=https://repo.saltstack.com/yum/redhat/7/\$basearch/2019.2" >> /etc/yum.repos.d/salt-2019-2.repo + echo "failovermethod=priority" >> /etc/yum.repos.d/salt-2019-2.repo + echo "enabled=1" >> /etc/yum.repos.d/salt-2019-2.repo + echo "gpgcheck=1" >> /etc/yum.repos.d/salt-2019-2.repo + echo "gpgkey=file:///etc/pki/rpm-gpg/saltstack-signing-key" >> /etc/yum.repos.d/salt-2019-2.repo cat > /etc/yum.repos.d/wazuh.repo <<\EOF [wazuh_repo] @@ -831,8 +831,8 @@ protect=1 EOF else yum -y install https://repo.saltstack.com/yum/redhat/salt-repo-latest-2.el7.noarch.rpm - cp /etc/yum.repos.d/salt-latest.repo /etc/yum.repos.d/salt-2018-3.repo - sed -i 's/latest/2018.3/g' /etc/yum.repos.d/salt-2018-3.repo + cp /etc/yum.repos.d/salt-latest.repo /etc/yum.repos.d/salt-2019-2.repo + sed -i 's/latest/2019.2/g' /etc/yum.repos.d/salt-2019-2.repo cat > /etc/yum.repos.d/wazuh.repo <<\EOF [wazuh_repo] gpgcheck=1 @@ -846,16 +846,16 @@ EOF fi yum clean expire-cache - yum -y install salt-minion-2018.3.4 yum-utils device-mapper-persistent-data lvm2 openssl python-dateutil + yum -y install salt-minion-2019.2.2 yum-utils device-mapper-persistent-data lvm2 openssl python-dateutil yum -y update exclude=salt* systemctl enable salt-minion # Nasty hack but required for now if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then - yum -y install salt-master-2018.3.4 python-m2crypto salt-minion-2018.3.4 m2crypto + yum -y install salt-master-2019.2.2 python-m2crypto salt-minion-2019.2.2 m2crypto systemctl enable salt-master else - yum -y install salt-minion-2018.3.4 python-m2m2crypto m2crypto + yum -y install salt-minion-2019.2.2 python-m2m2crypto m2crypto fi echo "exclude=salt*" >> /etc/yum.conf @@ -874,9 +874,9 @@ EOF # Install the repo for salt wget --inet4-only -O - https://repo.saltstack.com/apt/ubuntu/$UVER/amd64/latest/SALTSTACK-GPG-KEY.pub | apt-key add - - wget --inet4-only -O - https://repo.saltstack.com/apt/ubuntu/$UVER/amd64/2018.3/SALTSTACK-GPG-KEY.pub | apt-key add - + wget --inet4-only -O - https://repo.saltstack.com/apt/ubuntu/$UVER/amd64/2019.2/SALTSTACK-GPG-KEY.pub | apt-key add - echo "deb http://repo.saltstack.com/apt/ubuntu/$UVER/amd64/latest xenial main" > /etc/apt/sources.list.d/saltstack.list - echo "deb http://repo.saltstack.com/apt/ubuntu/$UVER/amd64/2018.3 xenial main" > /etc/apt/sources.list.d/saltstack2018.list + echo "deb http://repo.saltstack.com/apt/ubuntu/$UVER/amd64/2019.2 xenial main" > /etc/apt/sources.list.d/saltstack2019.list # Lets get the docker repo added curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - @@ -895,7 +895,7 @@ EOF # Initialize the new repos apt-get update >> $SETUPLOG 2>&1 - apt-get -y install salt-minion=2018.3.4+ds-1 salt-common=2018.3.4+ds-1 python-m2cryptoi python-dateutil >> $SETUPLOG 2>&1 + apt-get -y install salt-minion=2019.2.2+ds-1 salt-common=2019.2.2+ds-1 python-m2cryptoi python-dateutil >> $SETUPLOG 2>&1 apt-mark hold salt-minion salt-common else @@ -909,7 +909,7 @@ EOF echo "deb https://packages.wazuh.com/3.x/apt/ stable main" | tee /etc/apt/sources.list.d/wazuh.list # Initialize the new repos apt-get update >> $SETUPLOG 2>&1 - apt-get -y install salt-minion=2018.3.4+ds-1 salt-common=2018.3.4+ds-1 python-m2crypto python-dateutil >> $SETUPLOG 2>&1 + apt-get -y install salt-minion=2019.2.2+ds-1 salt-common=2019.2.2+ds-1 python-m2crypto python-dateutil >> $SETUPLOG 2>&1 apt-mark hold salt-minion salt-common fi From 939ab918b4778ebd3621c7a351e3760ffa0d69df Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 7 Nov 2019 17:31:06 -0500 Subject: [PATCH 051/200] update states using module.run - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/106 --- salt/ca/init.sls | 8 ++++---- salt/patch/os/schedule.sls | 8 ++++---- salt/playbook/init.sls | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/salt/ca/init.sls b/salt/ca/init.sls index 27344fc7f..407516f6e 100644 --- a/salt/ca/init.sls +++ b/salt/ca/init.sls @@ -39,10 +39,10 @@ pki_private_key: - require: - file: /etc/pki -mine.send: +send_x509_pem_entries_to_mine: module.run: - - func: x509.get_pem_entries - - kwargs: - glob_path: /etc/pki/ca.crt + - mine.send: + - func: x509.get_pem_entries + - glob_path: /etc/pki/ca.crt - onchanges: - x509: /etc/pki/ca.crt diff --git a/salt/patch/os/schedule.sls b/salt/patch/os/schedule.sls index 128862fa7..62232b0d1 100644 --- a/salt/patch/os/schedule.sls +++ b/salt/patch/os/schedule.sls @@ -64,13 +64,13 @@ remove_patch_os_schedule: {% else %} -no_os_patch_schedule_name_set: +no_patch_os_schedule_name_set: test.fail_without_changes: - name: "Set a pillar value for patch:os:schedule_name in this minion's .sls file. If an OS patch schedule is not listed as enabled in show_schedule output below, then OS patches will need to be applied manually until this is corrected." -show_schedule: +show_patch_os_schedule: module.run: - - name: schedule.is_enabled - - m_name: patch_os_schedule + - schedule.is_enabled: + - name: patch_os_schedule {% endif %} diff --git a/salt/playbook/init.sls b/salt/playbook/init.sls index ef66966f3..6a054195a 100644 --- a/salt/playbook/init.sls +++ b/salt/playbook/init.sls @@ -11,9 +11,9 @@ playbookdb: playbookwebhook: module.run: - - name: sqlite3.modify - - db: /opt/so/conf/playbook/redmine.db - - sql: "update webhooks set url = 'http://{{MASTERIP}}:7000/playbook/webhook' where project_id = 1" + - sqlite3.modify: + - db: /opt/so/conf/playbook/redmine.db + - sql: "update webhooks set url = 'http://{{MASTERIP}}:7000/playbook/webhook' where project_id = 1" navigatorconfig: file.managed: From f58031f4e3ed601a85282de6014013375cebc276 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 7 Nov 2019 17:35:19 -0500 Subject: [PATCH 052/200] enable the new module.run behavior on the minion config - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/106 --- so-setup-network.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/so-setup-network.sh b/so-setup-network.sh index d3ae360f1..f7f6c7bd9 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -255,6 +255,9 @@ configure_minion() { fi + echo "use_superseded:" >> /etc/salt/minion + echo " - module.run" >> /etc/salt/minion + service salt-minion restart } From aac9ab8e83f4f54b89a9e3050eceb7e6e576d410 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 11 Nov 2019 08:49:59 -0500 Subject: [PATCH 053/200] install the py3 version of salt 2019.2.2 - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/105 --- so-setup-network.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index f7f6c7bd9..b7c858d32 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -699,7 +699,7 @@ saltify() { ADDUSER=adduser if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then - yum -y install https://repo.saltstack.com/yum/redhat/salt-repo-latest-2.el7.noarch.rpm + yum -y install https://repo.saltstack.com/py3/redhat/salt-py3-repo-latest-2.el7.noarch.rpm cp /etc/yum.repos.d/salt-latest.repo /etc/yum.repos.d/salt-2019-2.repo sed -i 's/latest/2019.2/g' /etc/yum.repos.d/salt-2019-2.repo cat > /etc/yum.repos.d/wazuh.repo <<\EOF @@ -878,8 +878,8 @@ EOF # Install the repo for salt wget --inet4-only -O - https://repo.saltstack.com/apt/ubuntu/$UVER/amd64/latest/SALTSTACK-GPG-KEY.pub | apt-key add - wget --inet4-only -O - https://repo.saltstack.com/apt/ubuntu/$UVER/amd64/2019.2/SALTSTACK-GPG-KEY.pub | apt-key add - - echo "deb http://repo.saltstack.com/apt/ubuntu/$UVER/amd64/latest xenial main" > /etc/apt/sources.list.d/saltstack.list - echo "deb http://repo.saltstack.com/apt/ubuntu/$UVER/amd64/2019.2 xenial main" > /etc/apt/sources.list.d/saltstack2019.list + echo "deb http://repo.saltstack.com/py3/ubuntu/$UVER/amd64/latest xenial main" > /etc/apt/sources.list.d/saltstack.list + echo "deb http://repo.saltstack.com/py3/ubuntu/$UVER/amd64/2019.2 xenial main" > /etc/apt/sources.list.d/saltstack2019.list # Lets get the docker repo added curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - From bd26db1f239eea0ad7f6980e32d1a01fe86aaea7 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 11 Nov 2019 10:50:35 -0500 Subject: [PATCH 054/200] install docker python3 library and set env var PYTHONPATH - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/105 --- so-setup-network.sh | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index b7c858d32..8c9efa955 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -355,7 +355,9 @@ docker_install() { yum -y install yum-utils device-mapper-persistent-data lvm2 openssl yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo yum -y update - yum -y install docker-ce docker-python python-docker + yum -y install docker-ce + pip3 install docker + set_environment_var "PYTHONPATH=/usr/local/lib/python3.6/site-packages/" if [ $INSTALLTYPE != 'EVALMODE' ]; then docker_registry fi @@ -1023,6 +1025,15 @@ sensor_pillar() { } +set_environment_var() { + + echo "Setting environment variable: $1" + + export "$1" + echo "$1" >> /etc/environment + +} + set_hostname() { hostnamectl set-hostname --static $HOSTNAME From 67108ccc77da9e710c42eccbd812473060274610 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 11 Nov 2019 11:09:32 -0500 Subject: [PATCH 055/200] iteritems deprecated for items in py3 - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/105 --- salt/common/init.sls | 8 ++++---- salt/patch/os/schedule.sls | 2 +- salt/utility/bin/crossthestreams.sh | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/salt/common/init.sls b/salt/common/init.sls index 1bba4c871..93940669c 100644 --- a/salt/common/init.sls +++ b/salt/common/init.sls @@ -316,7 +316,7 @@ grafanaconf: - source: salt://common/grafana/etc {% if salt['pillar.get']('mastertab', False) %} -{%- for SN, SNDATA in salt['pillar.get']('mastertab', {}).iteritems() %} +{%- for SN, SNDATA in salt['pillar.get']('mastertab', {}).items() %} dashboard-master: file.managed: - name: /opt/so/conf/grafana/grafana_dashboards/master/{{ SN }}-Master.json @@ -337,7 +337,7 @@ dashboard-master: {% endif %} {% if salt['pillar.get']('sensorstab', False) %} -{%- for SN, SNDATA in salt['pillar.get']('sensorstab', {}).iteritems() %} +{%- for SN, SNDATA in salt['pillar.get']('sensorstab', {}).items() %} dashboard-{{ SN }}: file.managed: - name: /opt/so/conf/grafana/grafana_dashboards/forward_nodes/{{ SN }}-Sensor.json @@ -358,7 +358,7 @@ dashboard-{{ SN }}: {% endif %} {% if salt['pillar.get']('nodestab', False) %} -{%- for SN, SNDATA in salt['pillar.get']('nodestab', {}).iteritems() %} +{%- for SN, SNDATA in salt['pillar.get']('nodestab', {}).items() %} dashboard-{{ SN }}: file.managed: - name: /opt/so/conf/grafana/grafana_dashboards/storage_nodes/{{ SN }}-Node.json @@ -379,7 +379,7 @@ dashboard-{{ SN }}: {% endif %} {% if salt['pillar.get']('evaltab', False) %} -{%- for SN, SNDATA in salt['pillar.get']('evaltab', {}).iteritems() %} +{%- for SN, SNDATA in salt['pillar.get']('evaltab', {}).items() %} dashboard-{{ SN }}: file.managed: - name: /opt/so/conf/grafana/grafana_dashboards/eval/{{ SN }}-Node.json diff --git a/salt/patch/os/schedule.sls b/salt/patch/os/schedule.sls index 62232b0d1..a91e61dfe 100644 --- a/salt/patch/os/schedule.sls +++ b/salt/patch/os/schedule.sls @@ -15,7 +15,7 @@ patch_os_schedule: - patch.os - when: {% for days in os_schedule.patch.os.schedule %} - {% for day, times in days.iteritems() %} + {% for day, times in days.items() %} {% for time in times %} - {{day}} {{time}} {% endfor %} diff --git a/salt/utility/bin/crossthestreams.sh b/salt/utility/bin/crossthestreams.sh index b9c8f6c1d..3cd8b005c 100644 --- a/salt/utility/bin/crossthestreams.sh +++ b/salt/utility/bin/crossthestreams.sh @@ -31,6 +31,6 @@ echo "Applying cross cluster search config..." # Add all the storage nodes to cross cluster searching. -{%- for SN, SNDATA in salt['pillar.get']('nodestab', {}).iteritems() %} +{%- for SN, SNDATA in salt['pillar.get']('nodestab', {}).items() %} curl -XPUT http://{{ ES }}:9200/_cluster/settings -H'Content-Type: application/json' -d '{"persistent": {"search": {"remote": {"{{ SN }}": {"skip_unavailable": "true", "seeds": ["{{ SNDATA.ip }}:9300"]}}}}}' {%- endfor %} From f1d7dff5657f05a185afa5b075974d81944ff361 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 11 Nov 2019 12:08:37 -0500 Subject: [PATCH 056/200] set PYTHONPATH env var differently - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/105 --- so-setup-network.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index 8c9efa955..54948c538 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -357,7 +357,7 @@ docker_install() { yum -y update yum -y install docker-ce pip3 install docker - set_environment_var "PYTHONPATH=/usr/local/lib/python3.6/site-packages/" + set_environment_var "PYTHONPATH=$PYTHONPATH:/usr/local/lib/python3.6/site-packages/" if [ $INSTALLTYPE != 'EVALMODE' ]; then docker_registry fi @@ -1030,7 +1030,7 @@ set_environment_var() { echo "Setting environment variable: $1" export "$1" - echo "$1" >> /etc/environment + echo "export $1" >> /etc/profile.d/set_env_vars.sh } From 6a3eac3288b7722ea3573862b7fffb90a8dc02c8 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 12 Nov 2019 09:33:42 -0500 Subject: [PATCH 057/200] add mysql python library and dependencies for py3 salt centos7 - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/105 --- so-setup-network.sh | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index 54948c538..8b6451e59 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -357,7 +357,7 @@ docker_install() { yum -y update yum -y install docker-ce pip3 install docker - set_environment_var "PYTHONPATH=$PYTHONPATH:/usr/local/lib/python3.6/site-packages/" + set_environment_var "PYTHONPATH=$PYTHONPATH:/usr/local/lib/python3.6/site-packages/:/usr/local/lib64/python3.6/site-packages/" if [ $INSTALLTYPE != 'EVALMODE' ]; then docker_registry fi @@ -984,6 +984,13 @@ salt_master_directories() { } +salt_install_mysql_deps() { + + yum -y install gcc mariadb-devel python3-devel + pip3 install mysqlclient + +} + sensor_pillar() { SENSORPILLARPATH=$TMP/pillar/sensors @@ -1888,6 +1895,8 @@ if (whiptail_you_sure); then # Install salt and dependencies { sleep 0.5 + echo -e "XXX\n1\nInstalling mysql dependencies for saltstack... \nXXX" + salt_install_mysql_deps >> $SETUPLOG 2>&1 echo -e "XXX\n0\nInstalling and configuring Salt... \nXXX" echo " ** Installing Salt and Dependencies **" >> $SETUPLOG saltify >> $SETUPLOG 2>&1 @@ -2122,6 +2131,8 @@ if (whiptail_you_sure); then sleep 0.5 echo -e "XXX\n0\nCreating Bond Interface... \nXXX" network_setup >> $SETUPLOG 2>&1 + echo -e "XXX\n1\nInstalling mysql dependencies for saltstack... \nXXX" + salt_install_mysql_deps >> $SETUPLOG 2>&1 echo -e "XXX\n1\nInstalling saltstack... \nXXX" saltify >> $SETUPLOG 2>&1 echo -e "XXX\n3\nInstalling docker... \nXXX" From dc54860e969d372efaef605eddc27a22f2b64edf Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 12 Nov 2019 11:10:07 -0500 Subject: [PATCH 058/200] add py3 python-dateutil for salt --- so-setup-network.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index 8b6451e59..ee8f932bc 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -850,8 +850,9 @@ EOF fi fi + pip3 install python-dateutil yum clean expire-cache - yum -y install salt-minion-2019.2.2 yum-utils device-mapper-persistent-data lvm2 openssl python-dateutil + yum -y install salt-minion-2019.2.2 yum-utils device-mapper-persistent-data lvm2 openssl yum -y update exclude=salt* systemctl enable salt-minion From 3f02fed27717eb2954dcd705e40647018e9af772 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 12 Nov 2019 15:16:28 -0500 Subject: [PATCH 059/200] change PYTHONPATH assignment - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/105 --- so-setup-network.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index ee8f932bc..4121b9ecf 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -357,7 +357,7 @@ docker_install() { yum -y update yum -y install docker-ce pip3 install docker - set_environment_var "PYTHONPATH=$PYTHONPATH:/usr/local/lib/python3.6/site-packages/:/usr/local/lib64/python3.6/site-packages/" + set_environment_var "PYTHONPATH=/usr/local/lib/python3.6/site-packages:/usr/local/lib64/python3.6/site-packages" if [ $INSTALLTYPE != 'EVALMODE' ]; then docker_registry fi @@ -1038,7 +1038,7 @@ set_environment_var() { echo "Setting environment variable: $1" export "$1" - echo "export $1" >> /etc/profile.d/set_env_vars.sh + echo "$1" >> /etc/environment } From d809718d9e60dc5de4957cf017b2e66204b0efa1 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 12 Nov 2019 16:03:26 -0500 Subject: [PATCH 060/200] add --user to pip3 install --- so-setup-network.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index 4121b9ecf..ca37e4da6 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -356,7 +356,7 @@ docker_install() { yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo yum -y update yum -y install docker-ce - pip3 install docker + pip3 install --user docker set_environment_var "PYTHONPATH=/usr/local/lib/python3.6/site-packages:/usr/local/lib64/python3.6/site-packages" if [ $INSTALLTYPE != 'EVALMODE' ]; then docker_registry @@ -850,7 +850,7 @@ EOF fi fi - pip3 install python-dateutil + pip3 install --user python-dateutil yum clean expire-cache yum -y install salt-minion-2019.2.2 yum-utils device-mapper-persistent-data lvm2 openssl yum -y update exclude=salt* @@ -988,7 +988,7 @@ salt_master_directories() { salt_install_mysql_deps() { yum -y install gcc mariadb-devel python3-devel - pip3 install mysqlclient + pip3 install --user mysqlclient } From 2e82d06f27add577be5c2bce50de309173158e95 Mon Sep 17 00:00:00 2001 From: Wes Lambert Date: Tue, 12 Nov 2019 21:10:31 +0000 Subject: [PATCH 061/200] only configure Telegraf if Grafana enabled --- salt/common/init.sls | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/salt/common/init.sls b/salt/common/init.sls index 93940669c..505289bc0 100644 --- a/salt/common/init.sls +++ b/salt/common/init.sls @@ -141,6 +141,8 @@ so-core: - watch: - file: /opt/so/conf/nginx/nginx.conf +# If master or eval, install Grafana/Telegraf/Influx +{% if grains['role'] == 'so-master' or grains['role'] == 'so-eval' and GRAFANA == 1 %} # Add Telegraf to monitor all the things. tgraflogdir: file.directory: @@ -213,9 +215,6 @@ so-telegraf: - /opt/so/conf/telegraf/etc/telegraf.conf - /opt/so/conf/telegraf/scripts -# If its a master or eval lets install the back end for now -{% if grains['role'] == 'so-master' or grains['role'] == 'so-eval' and GRAFANA == 1 %} - # Influx DB influxconfdir: file.directory: From 5fc08a39b49b81c20c8f7a1601c5498090cf5115 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 12 Nov 2019 16:54:32 -0500 Subject: [PATCH 062/200] change target directory of pip3 installs --- so-setup-network.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index ca37e4da6..dfc3d1ee1 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -356,8 +356,7 @@ docker_install() { yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo yum -y update yum -y install docker-ce - pip3 install --user docker - set_environment_var "PYTHONPATH=/usr/local/lib/python3.6/site-packages:/usr/local/lib64/python3.6/site-packages" + pip3 install --user -t /usr/lib/python3.6/site-packages docker if [ $INSTALLTYPE != 'EVALMODE' ]; then docker_registry fi @@ -850,7 +849,7 @@ EOF fi fi - pip3 install --user python-dateutil + pip3 install --user -t /usr/lib/python3.6/site-packages python-dateutil yum clean expire-cache yum -y install salt-minion-2019.2.2 yum-utils device-mapper-persistent-data lvm2 openssl yum -y update exclude=salt* @@ -988,7 +987,7 @@ salt_master_directories() { salt_install_mysql_deps() { yum -y install gcc mariadb-devel python3-devel - pip3 install --user mysqlclient + pip3 install --user -t /usr/lib64/python3.6/site-packages mysqlclient } From e364638a62977aa8b3cbbd56312fa064c244dde8 Mon Sep 17 00:00:00 2001 From: Wes Lambert Date: Tue, 12 Nov 2019 22:50:00 +0000 Subject: [PATCH 063/200] add Cyberchef --- salt/common/nginx/nginx.conf.so-eval | 12 ++++++++++++ salt/common/nginx/nginx.conf.so-master | 12 ++++++++++++ salt/firewall/init.sls | 12 ++++++++++++ salt/top.sls | 2 ++ 4 files changed, 38 insertions(+) diff --git a/salt/common/nginx/nginx.conf.so-eval b/salt/common/nginx/nginx.conf.so-eval index fe55dc274..a0b3a39de 100644 --- a/salt/common/nginx/nginx.conf.so-eval +++ b/salt/common/nginx/nginx.conf.so-eval @@ -188,6 +188,18 @@ http { proxy_set_header Proxy ""; } + + location /cyberchef/ { + proxy_pass http://{{ masterip }}:9080/; + proxy_read_timeout 90; + proxy_connect_timeout 90; + proxy_http_version 1.1; # this is essential for chunked responses to work + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Proxy ""; + + } location /soctopus/ { proxy_pass http://{{ masterip }}:7000/; diff --git a/salt/common/nginx/nginx.conf.so-master b/salt/common/nginx/nginx.conf.so-master index 964579a96..265413fa2 100644 --- a/salt/common/nginx/nginx.conf.so-master +++ b/salt/common/nginx/nginx.conf.so-master @@ -187,6 +187,18 @@ http { proxy_set_header Proxy ""; } + + location /cyberchef/ { + proxy_pass http://{{ masterip }}:9080/; + proxy_read_timeout 90; + proxy_connect_timeout 90; + proxy_http_version 1.1; # this is essential for chunked responses to work + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Proxy ""; + + } location /soctopus/ { proxy_pass http://{{ masterip }}:7000/; diff --git a/salt/firewall/init.sls b/salt/firewall/init.sls index c0c1e6d82..b0ff81b00 100644 --- a/salt/firewall/init.sls +++ b/salt/firewall/init.sls @@ -276,6 +276,18 @@ enable_master_cortex_9001_{{ip}}: - position: 1 - save: True +enable_master_cyberchef_9080_{{ip}}: + iptables.insert: + - table: filter + - chain: DOCKER-USER + - jump: ACCEPT + - proto: tcp + - source: {{ ip }} + - dport: 9080 + - position: 1 + - save: True + + {% endfor %} # Make it so all the minions can talk to salt and update etc. diff --git a/salt/top.sls b/salt/top.sls index f742a66cf..1d7d6ccf8 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -43,6 +43,7 @@ base: - suricata - bro - curator + - cyberchef - elastalert {%- if OSQUERY != 0 %} - fleet @@ -69,6 +70,7 @@ base: - ca - ssl - common + - cyberchef - sensoroni - firewall - master From 1feddb79227e9204dda4463241fed553b374d10c Mon Sep 17 00:00:00 2001 From: Wes Lambert Date: Tue, 12 Nov 2019 22:50:46 +0000 Subject: [PATCH 064/200] add Cyberchef dir --- salt/cyberchef/init.sls | 53 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 salt/cyberchef/init.sls diff --git a/salt/cyberchef/init.sls b/salt/cyberchef/init.sls new file mode 100644 index 000000000..1f1d5c080 --- /dev/null +++ b/salt/cyberchef/init.sls @@ -0,0 +1,53 @@ +# Copyright 2014,2015,2016,2017,2018 Security Onion Solutions, LLC + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Create the cyberchef group +cyberchefgroup: + group.present: + - name: cyberchef + - gid: 946 + +# Add the cyberchef user +cyberchef: + user.present: + - uid: 946 + - gid: 946 + - home: /opt/so/conf/cyberchef + +cyberchefconfdir: + file.directory: + - name: /opt/so/conf/cyberchef + - user: 946 + - group: 939 + - makedirs: True + +cybercheflog: + file.directory: + - name: /opt/so/log/cyberchef + - user: 946 + - group: 946 + - makedirs: True + +so-cyberchefimage: + cmd.run: + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-cyberchef:HH1.1.3 + +so-cyberchef: + docker_container.running: + - require: + - so-cyberchef + - image: docker.io/soshybridhunter/so-cyberchef:HH1.1.3 + - port_bindings: + - 0.0.0.0:9080:8080 From b15886b26a4a43108d94032184324d78a4912f84 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 12 Nov 2019 17:51:59 -0500 Subject: [PATCH 065/200] remove --user add trailing / for pip3 target install --- so-setup-network.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index dfc3d1ee1..bfdcad7a9 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -356,7 +356,7 @@ docker_install() { yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo yum -y update yum -y install docker-ce - pip3 install --user -t /usr/lib/python3.6/site-packages docker + pip3 install -t /usr/lib/python3.6/site-packages/ docker if [ $INSTALLTYPE != 'EVALMODE' ]; then docker_registry fi @@ -849,7 +849,7 @@ EOF fi fi - pip3 install --user -t /usr/lib/python3.6/site-packages python-dateutil + pip3 install -t /usr/lib/python3.6/site-packages/ python-dateutil yum clean expire-cache yum -y install salt-minion-2019.2.2 yum-utils device-mapper-persistent-data lvm2 openssl yum -y update exclude=salt* @@ -987,7 +987,7 @@ salt_master_directories() { salt_install_mysql_deps() { yum -y install gcc mariadb-devel python3-devel - pip3 install --user -t /usr/lib64/python3.6/site-packages mysqlclient + pip3 install -t /usr/lib64/python3.6/site-packages/ mysqlclient } From 55db27c8980e2141a1434762c2805978dc99593c Mon Sep 17 00:00:00 2001 From: Wes Lambert Date: Wed, 13 Nov 2019 02:21:36 +0000 Subject: [PATCH 066/200] fix require --- salt/cyberchef/init.sls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/cyberchef/init.sls b/salt/cyberchef/init.sls index 1f1d5c080..202b15037 100644 --- a/salt/cyberchef/init.sls +++ b/salt/cyberchef/init.sls @@ -47,7 +47,7 @@ so-cyberchefimage: so-cyberchef: docker_container.running: - require: - - so-cyberchef + - so-cyberchefimage - image: docker.io/soshybridhunter/so-cyberchef:HH1.1.3 - port_bindings: - 0.0.0.0:9080:8080 From 977f39cea7e59b34cb32549e3c48cb0f3736731f Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Wed, 13 Nov 2019 09:47:04 -0500 Subject: [PATCH 067/200] Update generic.template --- salt/soctopus/files/templates/generic.template | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/salt/soctopus/files/templates/generic.template b/salt/soctopus/files/templates/generic.template index 23b693258..e278afa2c 100644 --- a/salt/soctopus/files/templates/generic.template +++ b/salt/soctopus/files/templates/generic.template @@ -1,9 +1,6 @@ {% set es = salt['pillar.get']('static:masterip', '') %} {% set hivehost = salt['pillar.get']('static:masterip', '') %} {% set hivekey = salt['pillar.get']('static:hivekey', '') %} -es_host: {{es}} -es_port: 9200 - alert: modules.so.thehive.TheHiveAlerter hive_connection: @@ -16,11 +13,11 @@ hive_proxies: hive_alert_config: title: '{rule[name]}' - type: 'external' + type: 'playbook' source: 'SecurityOnion' - description: "`Play:` https://{{es}}/playbook/issues/6000 \n\n `Data:` {match[message]}" + description: "`Play:` https://{{es}}/playbook/issues/6000 \n\n `View Event:` \n\n `Raw Data:` {match[message]}" severity: 2 - tags: ['elastalert', 'SecurityOnion'] + tags: ['playbook'] tlp: 3 status: 'New' follow: True From 3fc43fa2da243f655d68b00c23ffaaad1532edc2 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Wed, 13 Nov 2019 09:52:07 -0500 Subject: [PATCH 068/200] Update osquery.template --- .../soctopus/files/templates/osquery.template | 28 ++++--------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/salt/soctopus/files/templates/osquery.template b/salt/soctopus/files/templates/osquery.template index 1e85a3182..096921618 100644 --- a/salt/soctopus/files/templates/osquery.template +++ b/salt/soctopus/files/templates/osquery.template @@ -1,23 +1,6 @@ {% set es = salt['pillar.get']('static:masterip', '') %} {% set hivehost = salt['pillar.get']('static:masterip', '') %} {% set hivekey = salt['pillar.get']('static:hivekey', '') %} -es_host: {{es}} -es_port: 9200 -name: Alert-Name -type: frequency -index: "*:logstash-*" -num_events: 1 -timeframe: - minutes: 10 -buffer_time: - minutes: 10 -allow_buffer_time_overlap: true - -filter: -- query: - query_string: - query: 'select from test' - alert: modules.so.thehive.TheHiveAlerter hive_connection: @@ -30,17 +13,18 @@ hive_proxies: hive_alert_config: title: '{rule[name]} -- {match[osquery][hostname]} -- {match[osquery][name]}' - type: 'external' + type: 'osquery' source: 'SecurityOnion' - description: '`Hostname:` __{match[osquery][hostname]}__ `Live Query:`__[Pivot Link](https://{{es}}/fleet/queries/new?host_uuids={match[osquery][LiveQuery]})__ `Pack:` __{match[osquery][name]}__ `Data:` {match[osquery][columns]}' + description: "`Play:` https://{{es}}/playbook/issues/6000 \n\n `View Event:` \n\n `Hostname:` __{match[osquery][hostname]}__ `Live Query:`__[Pivot Link](https://{{es}}/fleet/queries/new?host_uuids={match[osquery][LiveQuery]})__ `Pack:` __{match[osquery][name]}__ `Data:` {match[osquery][columns]}" severity: 2 - tags: ['elastalert', 'SecurityOnion'] + tags: ['playbook','osquery'] tlp: 3 status: 'New' follow: True caseTemplate: '5000' - -hive_observable_data_mapping: + + + hive_observable_data_mapping: - ip: '{match[osquery][EndpointIP1]}' - ip: '{match[osquery][EndpointIP2]}' - other: '{match[osquery][hostIdentifier]}' From 7259a5346b80cd481a44d822ee769afe6ffb3ea6 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Wed, 13 Nov 2019 13:49:34 -0500 Subject: [PATCH 069/200] Update osquery.template --- salt/soctopus/files/templates/osquery.template | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/salt/soctopus/files/templates/osquery.template b/salt/soctopus/files/templates/osquery.template index 096921618..5f1c6961a 100644 --- a/salt/soctopus/files/templates/osquery.template +++ b/salt/soctopus/files/templates/osquery.template @@ -11,6 +11,12 @@ hive_proxies: http: '' https: '' +hive_observable_data_mapping: + - ip: '{match[osquery][EndpointIP1]}' + - ip: '{match[osquery][EndpointIP2]}' + - other: '{match[osquery][hostIdentifier]}' + - other: '{match[osquery][hostname]}' + hive_alert_config: title: '{rule[name]} -- {match[osquery][hostname]} -- {match[osquery][name]}' type: 'osquery' @@ -23,9 +29,4 @@ hive_alert_config: follow: True caseTemplate: '5000' - - hive_observable_data_mapping: - - ip: '{match[osquery][EndpointIP1]}' - - ip: '{match[osquery][EndpointIP2]}' - - other: '{match[osquery][hostIdentifier]}' - - other: '{match[osquery][hostname]}' + From 0007af1e124ab038e653c1c592affcdadf809e65 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Wed, 13 Nov 2019 14:27:24 -0500 Subject: [PATCH 070/200] Updated for bulk import --- salt/playbook/files/redmine.db | Bin 1454080 -> 2207744 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/salt/playbook/files/redmine.db b/salt/playbook/files/redmine.db index fdf24eae4bc011e63b0b5bcf33fb07ca0a5655e2..3477ef3c947f5107a7fd14571c53c7c36d4da742 100644 GIT binary patch literal 2207744 zcmeFa31FN@efK|mX%A_i@exOMd_9)q$SYf`y{}v-wvve0j?Y{WHjj3nl{Q}ODtp*b z0)ce`ZQRlWN(;0=fj<=5QYeMe(sHy=UhbnuD7*z;+CoVn2}emv2<88qd7fSEO1rY1 z*p8)q_1M2>cIG$NXXcsbnP=viIdou8zN)LaQh8dds$sT*SuE@Ys>;~)Nye<}8M9RB zzlY54VvO18f8)>6Fmyjt82&)YK?=S6qgFcoE&n(EU;NwrA^utZN&Zp(6#p{+Z~hqn ztL|aI1q46<1V8`;KmY_l00ck)1V8`;K!CmJ#2TV-NByNF^YuxRe|X|@lDYaWk{4Y; z;y_(=)i0hP!PvV_+(GgkC-#&4%@cmnH@EPoNV3a}lQ7~B1V8`;KmY_l00ck)1V8`; zKmY_lVA&9O)rlT4C~x846IptnaauOHLqFz=w_EZ1= zM~wdA4+KB}1V8`;KmY_l00ck)1V8`;Kw!BLP;6V>EpHFJd>6AQzs{6j_r86(WD)rQ z0T2KI5C8!X009sH0T2KI5V)`j)FW2T-0KHNtsb{KMty-ex>1l}D zKQkLl1`?rYFdUAB0_irF4cAunyQ?F256{e2r%J`)N~WBjsm3FL2|cUFGGRTC4TX{+ zJ(q|Fa#|)6OJM}j*2Ok^^dNIV1mp;U(hSg zRZiOucfL}o>FKgwkgqo?D;(r?TA!ZK%jt57v>bgswvCqK`ovVJbhP5)53wG`TrOL` z`*{9nzOu@08?6?#9CKBg6Fdgbm1jS^VdRuCSmZJniBI;s~dxAt0W8`*KKnwiqe z74iK)ZTg2l5C8!X009sH0T2KI5C8!X009sHfn`j<*#Gb6B8N|Nd0NJqMb&40L=%>>T#@~(@ML8(`kj>q0ouj9bP&qcE=@jTHC|F$($6aV-x+_WOuBi(|WtZ zMJJct;iQw(?&zUYkDWiol)2-Z|(%k9c9lqZzOmG8-5=c0!R1V8`;KmY_l00ck)1V8`;KmY{JB>_vg{=*veZ$tGT z=IIoy|L_(%1?oQ>rPE0Lhdw&_>p$$J({TOq89ME#KYjOYvG)5`h}_RwiX{RcyI;`JZU zDt#8E{{1qs`h5NSN9gpK`u8uV)2Hj--$yM~(`n&ogHadN*{_q5yK3aeHu$cevaLqDhN8kRwjlJI{BmO`D1V8`;KmY_l;M@>+ zmF{pcw`Jq2Eu%d*8_OGCUCmbudP?0@(6zF*HNvZnX zGkQ5ctrx3W!RyKD#x_s1IaI@E#`HO5_*C;nwU95??pBXanW2}SubYvO3Ld|>2Fw_s#a$zsgaS%e08ce;ivFN%6c}V6}9qg zrZl3_>dX1eFj);(b!~cNqEMO`nbs;*y==NwMh*vqk(eR}sl1PO1B~YB`@ds$Qd&by`1~7-&_(W^6|l9tlOf zoOXX}M%SPG;%hT%6gjShKn+#JpkB3@Qbwz)BU$~}NU>HZEKnufA~5kctPU26>To63qP|Gv)pD&!Ve8~0 z&^7+8BGej{Z&kg1{LtZR$M=j4s_IsiXcTp|T2gabfeL@7RLNKK$8;iTq(!ENsu?Zd z-Sl{9{I;KNu^BH>gZ?oY(S;Xp8DchY6HZQE#% zmaXKpN_N5jcE90RDiHC9BEeW95wr=vtI6-^=xD3gb}yk=DiZXEqmf7~asMq=aanJ9 zRYrQE0ywN!s(0LRhicS%t)Q2y#9){%y@}f7yz6(jtdM>fyoQSK_`3mh3mm!9#I<3={k|p%{0$qeMI=Yg| zvnG6LPFLtEDo&bKs%j{x+o?2)v~GJgH4q5|2Gr4gyQy^$R&3=15?T5))+iDTFdd3dkMAsz5~X3F_eIbWTn#z8b}4fq6z+QTZfa4IQP zXJ;r5tw>EQl~c25<#upPkV zcWcC88O$(dYGnsjTNiq*-@Ifbc`l7Y;k$mI(I{{lAkOtPzgCb z>~f21ScG+0PN<^!6Kb}UsmbYMVy2FDxA|)q%_f?piDo-{JS^xo{2Zz1G)JseeZKZ~ zhlg#pxCSYP_2bjidNxnNIL0fLn!ewhd?6IXpb^o$$F*`XT`Hz&8PH>7o2C^UwPQ_BRsHTNEqtk^bEP6JXgNsXOwXogv`IZ(&}K`u zYKj&BEa*9T9;VekX)1O_tBCpGdX`q|)XBL_)2iFt%eq+XQO{1yl6x~eS~yZ9i3d40Xtb)aEXM?UAmE z85-B3Q79Vx8c@ZiZdF?IsIBhL2-|jd-%V?K`gg3c+$%ScD(c58Y1-fHPTJm$t`hNc zy~$;K-|n$n)PZ>#1L}?Y3`>D(&gX#d#1;L{{xxeX54=dC7XHNlOWH9Dt7incC8|ct zLd}NU0&tFLtShQYjkX6Y&(5iaqS03V6jsaDfCH)+HY7V^553m*qgiHch1;nl$a`~0 zEK{l#tIam3Lm0jjD|(&%gM*g)(-L2%M%8pWEvrJM?MGib&^EVcMAir)e-BlZwzhYX z8rtHerD^SuEy2LZ360|xvZn@V)_sBBSC4s|{mG=|gtHZi45*T>mT3b-x*4?wKWE$9 z5z;)bf>x{dQ>V_1^c0GeaCi5Fn-zIp!W*`p#S-37I`f2gxOzI2me0GFz3}Wbytny# z`iJ{1FPE*%@%+(zYcnH%2h5zB?aX`~qoI+uBD*aa@YTnLo&Ej&mJ@kdFQkqXBkk~- zo?GkaX+4d!#MWqRTH96Hb+25Na|q_OCoK;&#`dENFZp0IARm!Fd3I<&+ferR&^=*? zZE+~}HEsXtY-2pnal6=na3}fnU1#sm!@3cmb zWb|}cE^37|ZN8|9t?|;qPPUHvKAW>Y8nv9bS|+ZOPA5BiTQUbasfcPtJ2Ezluvsvz zPps5{wcn0Ki)P+-HEPipyX|&#_l;V6`j3osBU7O#>}f4Mou4dgV!gpiI=H~fcDKdZ zKQdyeZ#K$nzLy0atnDxsxC;{IzL<;C@QLw%2Y;`X_Wt`e{}}%=e=mQ_v#osa4+0JZan_(_bCJUY0w4ea&na zZTOsPVGcEEtf6|5Nz3ce4 zaQD@1`<(rwJ1q4<`EFk?idh`l^mHj(E9kAGKJ#40P3q?O&pg+bL1|+oXrB9mF`=Qo zPBDaWqF25XpQkUHMvlwMVP7hHpZgB>d(Z8a+A;RJEltBe zTP*b}4OGpGHZ89@lE>z**DFj$NA`^$I5MW1HEYg&&X0+y8Jb|!ei;*?=2h#PyxrL! z-e{@!%0!q$C9QS4VYRKjlp59xYIDP3el_+UU~lZm;W@Xg_uk^{AEQC15y_x26x|$$ zZ^_~Uw>|At7PzXo=fq zdz|hxfP1f&ZPNY2GLiDra;ky_V__K6|QyGQ%9r7Y!)MpMmcf4=&vtDOCDsxW3F*Syx!GS&*k*>VpyEk{iX zU9aFdzw<9)GXz1ZdBux-HM1#Nxw>+tQEzULMbcEH)W{G27g)TYy;v5wFNm&@|JJ*+ zfw@x|&>R4Z<2k>!pX&tNKloxf&-7JWWT`Y7$Hw{6_A+Q#&%Y)b^?KgZnR%(VRq>8j zb^Fb_p)$XYS2E@Nj2M}pyRXlwQeD$?IhspHed$FWw;B@&+UD&wLTNm7b(p)?yzopN zF~P-H%A$Q9+A zp6kkk_(1>!KmY_l00ck)1V8`;KmY_l00hn!fiK@cA${pG4}Y57uIym^N%{idQT{#t zAN-sAYy6-2m-uJ-Kk$$9zu|w$|D69R|0Di3{wDr<{#yPU{6YQze>uO0*Z2%S%5z-f zFXlJ%gM2T)p6}vU@g$G%5kADXah0#<7xR_8k2|?l`GxX7%1@NXl!ul7RKBHrUHKQ~ z%gX1JPbq(={H^jK<^9Tgly@m_SKh3=LHQl!H~ydCxjmfdlmeOVl5s}Xs& z;n+{I9>(0;?QedzA;CWgfB*=b3j)^npIN9h^Fp+0IVsDmui@K$UyJz<*rta4!n6AW zZ0$l@3iBTq_4P<+Umj~0`%Ajmhq~Cmu#5df7yEm<*uSQW{rkGw6HnzA_I;h0zzzh? zB?09_mft#;;h%@Fy^k|F&b#Va#bvj-EiVz`b|GFY#EXQuO^92CxJ8JYg}6zGBSIV& z;*byrg*YI@ej#oYVxJIuh1es+4MMz7h;bpV7vef0t`%ZTh}}Z$65<*mMum8R5LXLv zl@M17afJ|<3y~5cDMUhuxDYWRqC!N32n!JsA}B;ah!G+DLJSMBQ-~cx3<=>AV!IH7 zLR==qHX$w*Vyh4XLTnL26=Jgxn}paX#0DYO3vr1M>x5VrP^Q@-~ZeA>lyzr_3gj$tm+3m zg8&GC00@8p2!H?xfB*=900@8p2%I4Sl|I{dyGLE2KrlHRpnqXCm`sIYsbIt(iw6^- zz!qx{vyeuQp%NPoMAcv@6;7t25q~lsjwO>@XmtRg;%tNxqEHg4a5xoB_~X%NGLpdl ze`i=QPzM1J009sH0T2KI5C8!X009sHfh9=5BhuWq#NZOl1d*j=jJRz$KFF0 zpPjQi&W@J5eeftr+Y2 zM~6cRH55n%qN!-qpNxhhv1oI}|F{~A({le}Q-F9V5f6uEOwYqJ3ruC@qqvcfB*=900@8p2!H?xfB*=900^980>9|-y5Gy3?(3|4NIB@f&bzwr^4>4? zPI#VhU)O$|j+OO4I*JiSK` zJDFuYRSjoFuT*IGE|Uo*0bd?J+5L%~oep$9TK+M7EpYe6tL z9HjaYPDKJ@2rn3*ZM}`by*U?h4Ey7OSU4KE^B~nj5t$iRJRXk)ayc!LOvEy|WFV*O zflxS@Nyc(oCK-=Jqp?IHmoaKwFdzmJgV9tZBnA@0p=cl;Gg1*44hO~7;o@J?A4^0- zu|z&Z8S57rqfoPza3mTFh7!48IGfBRCK8lVEt?Bw!bv?C(kBv;Xd)2M=&~?(G&lAl zk3>?@ke_xUkA#eGM{NCIgf&aV_`I#jHg%%2+rNPlOVI2xTZUk;vvW zJsG3)MuTJ%4`jme%)DHMX{&aBFqw$AjKs>l*CQ=1%17Bl=Pg&~Euy^FtQI}8TEw%F ztdhw^qfz5J=;*@u z>saA@Wo*humzJpRGFx>0B*V#2NDJg9CX(S`GNfgL6Oo)2q_#a0jnlP7hHS*hR&#_t zmI?&@(P$zXHfwt)7m=f*=P6rW{!M1(A7uQC{DX9S^gKn2Xg~l2KmY_l00ck)1V8`; zKmY_l00d4&pufk(wz(`WtNT!Xa#~Zzr)Ns#s@3vK#qMHjTyD43Ej|&j{E`A1SUfOq zpT>H6@3VTZQ+}vCsBGxHuW!=x;l=&H6$C&41V8`;KmY_l00hoI0eW!#F?8aEX zqh~eSa{Ib1ZujU)`qFm|TeH^{)@s$#v?jjv4Mp`Z4KrrLp$ttGh~{EZnkb;tw31j> z&jv!7M3R1I0{S66bK^{9bk1M<7<)Js2>62$np_gsi|qrg;bbZzz6?$Vqvlv;WBfft z(+Z;gL@XK)$BtC=aSRhju}Tpo++i_mMKGxe1*dPNGKi-21UNKLLm{3#xgWDDVzvr6JZ*r zjt3LjU`P`q)*2P(f^3DtNA0Vb*X!NvaxsyoLFQxhIXcyY+38Yk{8 zG7yfM-@CWO*>t(CT&m4bKzn64S*wg@M_V+_WGxa)EEI~FkmkiAU1TiHaHy5|aqMPzp!`2!H?xfB*=9 z00@8p2!H?xfB*=bTLNPIf2|T_{89dO{(txf_*?mJ@O$|bKf6mf6-5yUgh{L4w4!eg0`!SQG_c~t#SJS;MleDS zD^9FwT2b<%p%5kFBGW1qhzDqy%K&MumR7WeC54p?21UA7nN~rX`=6xGXF@AZtTe6Y zi;X~n@<<+6v{^+%zF)vGfN0z3}86BtPrJk*>pIs4*9OPB`GE0vnwBiD#Bm)uIG0#Uhm zR)iM*iu(Kw)faVB4f}(ML?{;V4L4M8?WP*^$D)a3IO5ycP`$aMD(xMX^oQfLS6bY+ zqoI1Fn`*)zq(PNnz&F%TJ=9G#?hnPIG(h6>HB=9DQ;qtQfk-?V@NI9X-q=Mo8287M zp?Dd-RobR55~9PmrJ*|7T{W1XvB9KIZKz(|O*Q0?(dZTx z!RChQmEBcoXfF~C_%=0EFYl%r^wZ#BC>Hl^Y^Wx?sRsNsLK#fPd>b07@h+-?q+C%i z6!)!fs7AZ1h6B+=Jnp-sp&II@N-M8Lqj9R*>l&)TZmO~p(q-UV+fW_prW*4n!!)EC z_VqVZhr6rNz-=TL_g&mj-O)`oD(XNon)Iz{sBZ73N(&QGSy4N1QA2gGyJ{p(L%UJm z>W1p2-Bd$#8Pb?<)VHdkI?zp(Rt=1W6S1UkWkXf%rW&AS1Owr4(6^$Yx~aQrC=!l^ zV?N$c-Oy1rESonffkecoG*mC?rkbEFAVqQcybaa0-BjcLWKyj5=<92!Uff-kM$nVN zu&=kFdQmsk7?oClwng-L8mgIU1_2ZmLwXXeq*Yz(>pQ8=>}e zSEcJEPR*OGp=$4@N(~Y13QK9VHdL+MRcS56WHLsN0z;?wIN;^~!u-xh8Gko_89%_c zDL+%bpuAP7DdWmU?~lCy;C+L4+B@o9)Aw-SNBVxdPwz|id3(Rz`@!A^dvEUz_BuRY z^SsAX_Z;!~+`n*t#r+QVtb4C}i|ePZ&rt9GF4vfAo%2!Wqdm^~hvNg{IK4DN3j{y_ z1VErk;84?awhZnso~@7&&V@=~XoR+AUb)gcK9b3Wl80)U4DCpss}v8j(ZF)=i3>JE3+jb)-5ZBRau8QN*;?(C`?32KqtL}Vg3 zw8PZh(N#B_(KECcvlbm1GIfW#>T0oUHWQ#k5BW@8Usv7WgfqCR4?qFA4+8aGS5l#ehLzkJlmvz+*2f}(TmW?Ndwwb!yy6R@a8a>j}UerUE zn!1;E)eTXDuUHb9U?MoQ$<*D{RX3JQ(BAYUhc=qJ z8@uXKvBk2nh^`H7Fm*R{)ujrV4QhHWF|^*)UEftV8HwkzQ9ThIy2RAIq^oW`5f9U1 z|Jm@+I#YLDSKVw zaaY}3HXF^+RPfx;8dG;oS6!OcoQ*_jdxN2iOx=sR>PB+$Tp$ukObo3ybys)Qr7KgT z_4cFLp;e~ts;;`hm>vveH7etkrtZqFy0quJ9t(>4yTa66(N#AVjAw{MCOO1SUEWnU zoR|n{k!&tAq?o!&SKaso^^9q5cVftE>Uz8CW_5bu5RYdjhWbq1zOK4~ct)ohk&O)X zn!3GRbz@mA7Yfqrlp&9)>*=bi(M=$bnb0yrZd2FYRW};WWe{;MW`dziE}IL5hODNpwX1G89*f7K^lbq>f9yETXAlp6g898) zWc(5SP5zJkQ~bmH&-mN;@A8xUK3?WIejDFMD*?p#5Z}aC@gC(Vom4}qiDj!we zue?)vqw*Wd3FVk_C#?%`P`Oq~DSl-@xmfXd|JVCt?{~dl_kPj)#l9yN9G~jza`X;7 z`@{XC(>okrT{?&T=wiod7B|#D;JG4Te>>aIEpGeAPWOeS{o(GRI2@-Niet+npX(*f5IlZkvLoS_DjxINC*c6Kw$Y0uzz9s@@G2}X*TA1tdM47G6$DtW44AO&Bk;LuQVI; zE&8O{m{8Fx&Blxgk2D)oBHYq!%z1E0voWc`Db41r1!*>>B{-znn0H{8W@BQ3O`46F z1LBJTx$r-o_|wd&s0e?Vm1b&O& z2|Pe=1@5Nz0tI?Aa0k5`I81K`uBZ0{SI`@R0KFr)l-?4orS}AVyoWP-SMcBTw%~ho z99wYQqAYTFt7q?UzM}i#dT2=s!Cnwk)yx)#;H{ zPOwdjXl>rqEtWdpUDk3{`GrDdczD=TEo+&hdO4lXraY>eD$VF+ty(Il)PXApgvBwf zP}3{IZCD+Q40pOt~~!rtdY<1zK~PY)|+V;uNkQX>twCY|`-a|$-eJ#A zJb&pq?l|Cnzhk}oCie>0=ghVK6z7+nZ+714jQ9L+&-;4vJwC^ij!#>!RBq*;wI8>~ zZNIdAz;=)A8k^nvPv;?Ph~iumsIT_-u*>UXqcertWWGp)7RH94Gv+`9y**U7lxq{S zBU4&sDrLNaJ5-wyFBns)>&fose06HPn9b*MdRZ@4N9BrC9vbSnQ_oaW>L88BG5aa-Goe-JKFaYv3kAiCB1E z;w$M~sXVP!>5cbfu%o|7jP@J7D&$~et4GWFOsSHm!ME8oWjvkDS47d%2o-^({ZTvl zkI`!3k=RJk!FKS`%4{XA&EyxQ6$?j_iKsj3A|LBVtNPv5mL!Uw`GRgllo$>NR4STi zC>4$QqfxQMt>cC4@@IG%3~z9-jq65h`E+$kpVl+^a%L_jQSD->NHi6W_{AzbiKP2M z=A@Wvm-MjFx@|NsR!k=nm1?5`rZc5NZMrDOFo)IVn_;tJQ?(Xv%*BgxaZVU#F&NM? zrfB5TsPyqvIF<^A{Iv9SEEb^oY;2H^-dQOXXBOZLL`9X4&}BkZJ`f5elYyOdjc_VI zN?uC=G)uhIMFq7 zU@yT^HSQQ%EJh1f$Ku-^>~g*^w3*sOA)o1(ne9*+kH9c+Y;7WL!ld{v)LPwT~6 zx~ff>UW^h7r9xCiLjFi19F4?7mpNFFk5;E@(-TE4U#QG0reaRiD$QbQZOfvxt#B}M#ib6mH8@(U&;Yq{CFkvOmrwf{4m`7K}7mCMd3H9h! z<07LLtTLk&%@DFw_ouZ&CvUWjb1W7e8lXtMqq5;MBJHRvHY<(~ZIQZSnA{A$lP>M< zOiM2BRH;&XN9j^2SJR~&Z8WVPU8o(Q75Hhz!oaT04t9u-QUWr1^O`GY#mSmBDdQ4t z)TExx7v~o&5uo+%qv1p(zI&5{9a%IGtyn6~PM2y6D!U9N9*)OpU+9fgZY!Jhs*wo2 z*eUh2NE@{v?w>HayY94N zT3qRJi-T1w`O(0A)qx@Xgr1v$nh<{?y!+!_}{A{7Xxq5-PdbYF;ExsEQp z^`kSIxa+5l>or@Vy~JrMN4}KR%QRM(ZNO^HLXhfdJbC$A2aC`1K2y$@$~5}BnCDnB z6iOue=|Y_6Syac$qCROc$YA(ly6RVtPHM#}C7P~#F&Tqyb+p}f$Fzzy`NPpQbhln@ zlows|cZ-LgQ+T5$I==fN%Hr@SRkk!eha9DLOjiGNR-0`!lwzz^9gNR4mu;YEk^N*i zwVEp8Ri6|3r9v zrGusC8df7d<2sgCezla&h|yrGE|jAxt-BWpCWiy<)s^-{kB6eM74i|q2x78as?DUe zN+my8q&BzOnR_rwjZ%yok2Zx;g_?uf3^nMY%`uYRIle$L9Ed4Lm_4eHU+-x9Lm2_6 zYL!N0hLSN_Br3jgR1?zysI`#SQ{!$C?wqG^geqdfPA%3-dj8SM znJIceuTYnQ9@yzNJ43gZU}vA9cpw@~*a-UO(S~ZeG$SW=g`zv7ft}5#AO1i91V8`;KmY_l00ck)1V8`;KmY`m69G59x^=H{-%PK8#4>;uS_6>& z;SU5r00ck)1V8`;KmY_l00ck)1VCUJ60q6aZZZCE>vOFAOHd&00JNY0w4ea zAOHd&00Pg3z$&|Y(9-tW!0NJ_^Z(`ezvl}~@sq$G2!H?xfB*=900@8p2rMN6uX>5q z%`EO$TfC!gt6Y>YrS2-wid}LyH?5deuc!4`X|-CfxhZ5yrSp#c z`1N{dovdTFz&Vs@Kp`jI`_=F`!lQQnY4dFgX$kkAxy#4=tNnDb;9IO*0R) zKwGvZmS>hA1T}NzN7KErbh7!=NZVj}S{<68C7;tK$w4F4rYj||qz(+IS1qPQ3;3xc zS^d~Zu|``r&Q~SeA~5ks%OVzv>To63qP|Gv)pD&U76&9Bfv)jy6`|Ise5>m9G=AIIm4S8wjS4oLG3_%Y zS{Pd_6_-*QM7*SQzQ`IIbO%=0Jn3XhbR?IFu`){#~pX5M&;8AI<4pJrNt<-`b2GV-eqL03tCb4 zmyYY@LsL4H9IezxYh$aqa%o!CigXR?nHnvgThP^sS(O%BR*%tI!jy4!I$xo+s56um zRh`zU!e)s8ZO5pWWpq@b%d=(%r8!-p%3Pc@tyI-eP`48lvCL>TH4q5|2Gr4gyXhho zR#e$F|5%Y0FV}A};`E!WQ`XHE|4^ArJ30Iiv$#S{&V2=ajBd z(Y`d`6Ci4qXcg0xN=nt)8Hz(IQcFkW)LNi4MIf9C#{H3KAd*PfjPd^`==*>E#8PVN zkya1@0T2KI5C8!X009sH0T2KI5CDNw5pdWn7OS=K{lDF_i}BC#d%b@|2K<2l2!H?x zfB*=900@A<;sjo$*?XBq4!etScMQB^;2i_+XM5oNfUTDX-o?l}hThF#`=vhgzR&6r zMVb~Rx>em>%GBgEBr)T|>k)^Rt>m;y*7$Fl=MCl4M&=QJAQVhQNIVFD00@8p2!H?xfB*=900@8p2!OyT2#E22^#4x*3CluKNTUkg8&GC00@8p2!H?xfB*=9 z00@A<(kFoN|D|7s$N>m|00@8p2!H?xfB*=900@8p2%L%l#{W-62<{*N0w4eaAOHd& z00JNY0w4eaAh7fap#Q)0%MdvL0T2KI5C8!X009sH0T2KI5CDNw5fJnLE&K`FZcXe&ppmJ^&aWn;`yoPv!1tjDxUqGVg7lKmA{ow^HF}W@_prF%C9MR zC{e}Y{TJ^adtdH7tf}6Ap(LEvv6QhdOuO~>*&7$yUH~@g z$vb+P#p1TOTtUWqY_^+A<)gVm>G`}OiPy<;Mc zV63cb*;27E>nK_y7eKC%ge62^`$@m7Uv8s*H7a0B^@=yD*Wk(FrYhgqvrx4~bLZlk zp+=a2lfI_rmQG>LluLK&nQA(pZFt#ya=Y+C*MxD=G}1A5&GeMmx0X;5oM}=w-+v1M zu(%BX_GXhX2f+C{)@z0uJQ)$nE}=|-o62(q+=+0wC4xCWa}lT~Lqelj2KI%8u>E9^ zRNOLRYPcE-bMel#TZ1P9P1TMSE72(X!ILA4YX%#d>ixHh6q-$|-DYhhU@jBxpEH-B zwEbjUsLGU5^c@g2tLv8f3ZY8MqVC!4j%L2*g56U0w(B$lY}M&&*XfWvwcaar%wo1X z7Up0}-P0C~tz&YW?K&Nk)6=fgF*%O5)%!@p-6*O~Xw-Y#G&-b2y{Ap1LpnCkN{#NI`Hayngz@@^E6LePNqem zW)17Hb!v&XpS+!PjK{amX>1|;;!~)$kbO~8^;BfHpA=bNECtaE|o$D-Ih`~ za0=CyQrO>A?UI5fui(iWo4QoLJEWjf{odE~(>c}6;J2ULdkWQNaRg7ku<PB?})2 zd?&}7eki9M8n0H?*Ee-3)g5$OSYLMv)fU#*HdVW%pa~;*a;&LKIqZ;vPONt~{d7)s zOYkpfs&)>3AwVyGoLTw9j6cl(n~sN1vxR{g2!H?xfB*=900@8p2!H?xfB*=9z=cS_ zZnwEDcK#G|FnbRfdnl3g-@|`Q{r^W9&HaCZ4$S|*5X%l}0s#;J0T2KI5C8!X009sH z0T2LzGa+ES0{A&i4>Vr@IGC0ETlv3}v{?C%q~T0Lgf0kx00@8p2!H?xfB*=900@8p z2!OzaLg1f04*D3#+S6lqyp7WIPsUIBEXeySV*P)%;zCI%(g6Y>00JNY0w4eaAOHd& z00JNY0w8cM2%!IeE~p|*5C8!X009sH0T2KI5C8!X009uVun5Sl05JZ4VHFBe0|Fob z0w4eaAOHd&00JNY0w4eaXPJQ4>R<}{npJto`)#k@_t`$D=l$->T_3l+mVM2()&7;9 zKk0p0r-POF>a(1bvm0DJevh-iw9!&8<%?PUZYk2owQ6QcFIUo~qG8r13Oa4vlGcjZ z7K`fajNVYq?m9R&dU#A7-?w}07Iol^!x>O-+@}sSLK{%G8)h@&ft{wC{4L@g@XgFR z`>&>iuk4cWT19R)(+Dzissx()3lq|C@Y!B%*>ra4pIKDUWLDs9u!S$b@KEOm-@Z1-eE_7}lafG|RzpgJt)rQgbfcd#-1nKNsPi z`!FfxtJ-6^`#xv?t}T}Ox|Y()OlieQy`ooJOKi?^s#B@WIg7@kQAF}$o^xs|J!isl zM|)b%&oB3f*!Rv)OpC-qiO4MCd^Viwo|ilOZ=|9Pb}ibnK2xIINlWEfYSib7>CRIZ zaGOu#0-f_Oin(3E=l+o8SIkTVW|Vtw$8J)H{=vju1W@HR_*Sk{Tj za;Y{`kymSlYCxs+_f2LcII?g2z>((tyj4T^Fp9p_RusPcP0r$W-DnDY_Z)ThZ=ScA`jfd5JNA~P#iE4qHk5K;nT;N;+ zVb-tBOYSFbl-#HF=?QusDwhg+rPX}6oqMa3;7(=Pq`Lp$_}z zKJvSFY#)`wTv?a_wEAmt714|O(G0W2EnlQZ&U{tRrgP=ebW?@Ou-;R*IQws)I^=6< z(pr-$?mf+zTOA5!_SzmxTNT=T8nwFBSukh@Jm9OpVA9#YaiitLAqkakmDPN4veG#F z+hI1W=YwoyT5Tap)wrll>jUaBtxPRyd3z`t^{KnZt{pwH=de0B*vj~rR;ZC?RlmF1 z)M#7^Gg(a_EENY-VXEe*^)?+}eQnO!f8~g!en7G`w>qn&%`MgFnk(k-s_6^t51M&v zZx_qH(Zw>Y zRVt-SUIOTr^;Q+pDu|w-*^+kw(CXtEVW7R!Yx-PELYXY&bF#iSxsV+_(Pj&CR~6aF zh-F=B0ug{(uuT+76VfVE)`^<<>GRN%|5pB8#=pydOviVZzzqON1OX5L0T2KI5C8!X z009sH0T2KI5a>vt$L_XR>~{V$+Wk+Od&KsCPWmtA|GW7=GyXJxlKTIT^6&Bg;NRq5 zBP;xY00@8p2!H?xfB*=900@8p2!H?xT)+hEHfC`P;S$0rM2`>-A!zSEW}&73X}>?4 zjk&%2f0&JbLyZ4FPAB|<00@8p2!H?xfB*=900@8p2!H?xEHwg7hl5!x%--X)NrTnp zv`Yi^{26nJ>|p)>rB^#7MdF(MNn00JNY0w4eaAOHd&00JNY0wAy`0rdYD#REqW009sH z0T2KI5C8!X009sH0T5Ug1knFq7R886fB*=900@8p2!H?xfB*=900@A!3m00ck)1V8`;KmY_l00cl_SrG8r_c4!UE91KI$=(M%KlM!6Le@`OueN;DvUTCX zULZ2<@>n^+Q!{qM(;c1-+7<){5Gso=wYN9jw@&?K(I%dU#Ad zJbKNZF?FDW%7D6ETBq~b0X1K&>XUj|-FM?*b>ERadv>Y=tx)f>icrDAW1tXV5|k6k-@WY1wW&{{t-Ef5yhtmdl)eLy{?l`~UXS#5+iIM^Co zR?DT3SP}p+|~TF-lpU0dt=Wfr+Zl~1HHaCI(9r~+30(t z{m;&Cg1_IADfxb6du6?f4u=L}vyX$v3`)}}B>%Nu;h2#07`E*&&=F4=O zmd`8FCZBD0U?b>Lq8t&u6(mEuSdbLv8=Hq5avS-SIRZFr=qW4V<#0RkWZ0w4eaAOHd&00JNY0w4eaAh65`VEw;k zR-niZ2!H?xfB*=900@8p2!H?xfB*<|Ab|dV2Pm)t0T2KI5C8!X009sH0T2KI5CDN? zM!;+P4pS^2uzIg?Se!RI{<8Pgo(J4-bYI3_XUkeIvwXn$l^NpORKvZMp|~#G+))eVr^5SUD;gP z((o=n#u5AXlh0LorWR&ReH)E|gA-%+6cwzL_AgQs#p7DQOi= zEn}=mZ!TWHJ?Lw$Ip4m1{ft(fG8e9IS^6?prlmkzoEmH2n~T*-=dyk*Uy;k+&tDX(H)lhpiIe~rCPbD71CL~s^trnbmMnE+c23f zJK9q;&$Y#$k*ay_B54gPu^g)7PWI{x=3>j$SJTC`#!`1nBvPb{`f<4$wN|T6mC95z zg~fgC5V~j@1cbiGb~AthU(c;<&)Ld#eRF+-v;Wo|*7{gWs`HgfO{e9w3!1oMWCjc? zS;_O+dG732J7s8|l2}%|Ef6Dr^Rz@(+qHZiC;Q*CmEC6-j_X^j`s_kDbKkTi@j5D? z!S(_&SMWWi6>7ADjM$x}ebL}HclJQ1;%QUq5QNz*7~vWbiNcu|(Et_CiS6}koc%j? zSRQc7Hob9$nwR{%pFT4&=599gTxI!pXujvQ^$lOGEq$XsZrj;}wm_ND%hlOtgStH& z=-TX)Zu+QxTDqk|HZ7ra-r%I0lkcv&&)I+VMr(a#%jI@VFN>RoEXWFNtCBBHHmum| zI+b0+RTP`)!6>eVgTUBu@ZDM8=Ip<6jkWG=iL=o#&27aZY}jviif*B9d)qV@#(=MP z#dG)=S9jI7IQ#cDZ;(dI+I%oDu9VXBbiQirWHjf(Ufn6U@MJJUQ@_FyL>^OWWVVNjW;GuNccXa;=V zPg&NUc|*ATebiaqN}F(Pv$So(HLXui=w);9c`7k;E%;XJ=}slpsvwG~v4*_dhO5<4 zluyHv_DZmPY59|W-sEtqzLPo(bh~l1Gy~MZtI{n-wuVJ*T6Fm2Z}$35^{C-0>X6Vj zuJMMgs65iv=i%>TPX2Bie}cc8{|)~p|2+RV{~#Uz+I~E5*dwDL00JNY0w4eaAOHd& z00JNY0wC~Q5)do)5A#p)Pca8`*en+3VPSJn8bkaaSr3!eJpuk5*4Id=aP9GO{&Tjn zVI|MPtBp(!hWY<(VDJM3KmY_l00ck)1V8`;KmY_l00fpL0k8ABtj}?fIS=-HxMzps zAb+Rw9`6Uek-op^-ROCTC+0Y48(<$`L(4Mr$P@^il7RaS*1##1pa23Uf%=j9_0Im; z9o7@AlZEHauAG~JY0k}0YsKth(>nh@bCTDQed7m?jH%=Mc8}en4j40K&ot~)%=a`? zB)%UpLN+IW)_d#MIs3;(7JSD-pVyT2B7J^joM}>Or8xz+;l|$HK1*$ZLW}2lvveCl zh)HYB7zTXxi|W@p`){D+BqfH0A*wS{Z>k^ zHu5p2ZgOL9HB(|vu3w-aaz1C-I(xq5L#H`33%;VF`JvYRxImW}fu6|=D#6x!=aN&X zPtvyu^aWz;w+VOE^m5+#uBBF?xzG8mX>)J;g=REb3$=|a%(NF(-V9~HSF7io{ktf- zbuIH@TLPfZMefuy)wvk&IYo?f9u`E};^e!3Rb7{#J-+f@c`2Jwnx~!ZS8YqeJ6)mk zK80zCrg^zGK7}zqIy9#3&i|sY{hP;JzEGvlP&$9k(%`osg0^pMGNnRo+L$EVC7epB zTuo=nd5S5ob&hJXT&m5aC+0rFX?~+=W~MqjLvxVlXU23CA6HJ~3wiOuPrg{yC-rjE ze}Ha7r5X7_n-MjAPMM|ll|HQs%G%JV2VydOMcjMZEZDovQfj|(w&@5@ZS}yIwlAun z(3>T9aWibrw!g2QarO^V0+Ow@!tm4^9{ zl=-$UlJ9C+%N(U^LOf!%=8VFV`8M6@XRB)^-SEeL?X)xA@N(*?I%T}!yGzFB(mCL} zxqhIhf7?3i%Ow74>8MVhoyo7&3^RLY$27Mp8YwVrM2yC_Za$3v&)wBv0s#;J0T2KI z5C8!X009sH0T2Lz1kllaRT=yUA|3A-b z1+otUAOHd&00JNY0w4eaAOHd&@H`>l;ZGRz|DUEW03N{?0MCatK1V8`;KmY_l z00ck)1V8`;mMsA>0l;aO(*SIg$sWdRHn&@R|9`u(gYhT%kNKngd;CB6H~H82Kl3l~ z&+>oZALoC=|C0YX|5N@){B8VA{Pp~`{5SZ6`~m)Qeh;tl8Ge-KxW-@1Z{`R2UVc5_ z#joN?9^oT=h;QR6U(YY*D|sJxa;x$S<$si)D32)*EB~o{OZmF;FUpsd&ncf${!aN@ zy`Qr@n-S$TuTz0)oPAI<67FM; z9jB!ZB@kEw1YF0Nlah(k;s~~iYu`1(`Wi**+RHXI%nQ#hovmGHOCdbSF70IBYUg@u z7r%eq#r`W@>>uuI@3wTYU)RMx-qoI%D8F$0pVrjF3<4mqoCtXR@(y91ln+^cd+FxR z`-o`AY5UjyXP*bV&24#!5Vs5QVj*56#BD;{D#R^9+$_XRLL3p|un>oYI4HycA@&P# zqY(Rq*ek>yA#M=jg+h!AalH`N3306uV?yi}VwVut2r(+e3xv2@h^vISQiv;rxLk;o z5J@2tLd1oL2@w?{B1Bk-kPty30z!-k;TK|9h@C?05MoFOpAg%H7!=|%A+`x|sSsO* z7!YEM5ULQHh1ev-Mj=K?e;gHo$wF}2!H?xoLvIe_n%pK?mJ|wmXoqP_X@>* zUyJz<7JHrI{y>*k5dXNSuSYuj@>sjrU(&@s)W!aVUF;{i*x%E|{xx0f-`CY%zId_k zJF{|tHV8a>0`vmlx1N0{&uIwW$C-l?U|sdBQen3-(f?O!WVm z=>Id(|7W8A&qV*9iT*zm{eLF<|4j7%ndtvB(f?O!WVm=>Id( z|7W8A&qV*9iT*zm{eLF<|4j7%ndtvB(f?O!WVm=>Id(|7W8A z&qV*9iT*!B|9`PJ152^@-}}@ld;f>eU+>?&{CfWnERWv5{k~^)A2^Gi(f>b-FcB08 zfWSE*fd0P$)r0>3IjCI-^1>#7{=Zp1qR)u_Kl=X{-u(aWqyOJotdGB#8~Xpx{!PKM z8~sQB|196C(f>coKoJ}WfWTQMfd0P$6#f6RT(J<`5+H#7zgbA=|1Zn&|DUtlyLuk#NmV@gsPR<6u0*m-XGDt{I7YxAomvh2LB4JC-5=;9{yJT zI$A;CW&AF#^IK`nfKeXhKE9Rr^OedkX?=kIQvNTk4DbnB5#UdhwOZUuD(e-l*t}1Azfa%&{}UZA?|$_C;WIltpIM5B%Xi9S%5~ljhktnx3 zB%Tuj{I{%sdrksIpdfIL2|Uxf>k1ePCd7@?7*pmF>N?c+>loWQ=ho5WdJWsq(Sa;o zA3U}9uPoyI(e7?;_abiF7I7P0#O?M)+-4VXd)*>#f3>KaShzy@jN{o&BD{t~&w+wIc)VrhPnG~Xu8w@ULZ(tNWt-z3dP zr1`KkACl&S(tJRg_e=AQ(!5Wa_e%2~X}&?4UntGv(tN!%UnkAiO7oaB@0R9W(tM3H zk4p0kr1@%TzDk;}l;$g>`EqGaNpn(~6Ve=)=9n}`r8y#HSlWc73`(1TG>=HLUz&%d zd8ah*kmeyNebQ#Tl!MadGHKo><)zYQt27Tt^A>4VrFpY7Z<6MX(!4>M*Guyy(!5TZ z*GhB0G+!*uYoz%iXWpeUDE87<{oL5JOA~_ z<^Sw*|Gysb`9JOd$Ibr#Pw5T7!}Jc|8}t_7EA$>f^wq_?fcMbbfVa~7fY;F*fd}cG zz{}{Zz+LoSK&LkYx6-?Tz4Ufql->_S=?#JC#cve-c=@K_m-MdSC-k=9zvz8|=+TRJ z2A`m}1|OpL27f|t4&FlV4qi)d4}OK-AKXiC5K8n8AwzEwZl?DLH_)4etLa@rnBFD~ z())z<^hSXzZtC^_g8KbGqMrYEsPF$Z>id6zj@j-<-y5FU(VJX~hil-J$8E0jb~rw~ zw2rga5F;cIIQImse|YZWKn%}!0_gvDt^scJ|2u<$EeJe&0_gvrIYZIYv&#OzRrdd_ zvj1D*OLd+5fl7{=ZfB z|E;qBZD*OLd+5fl7 z{=ZfB|E;qBZ&Ds`8+pN5%VyWp zB`ww1i!r!>vB9Q9XeF&zcvo5^tqTyyiV|X{mka5=-IqcVl3eN~N0Q4Wxi9^a%cYVA zq?3>a`R@C_H_~WEJK9~-Vw1lY-h2AL{(EKKn|X!J|9Lk5=h^(9XY+ra&Hs5e|L58K zpJ(%bp3VPxHvi|@{GVs@f1b_%c{cy&+5Dep^M9Vr|9Lk5=h^(9XY+ra&HwqQ(foh5 z@BjZ;^Z(OAbN%H)PuXAK?i26t*gIYHfdrm90^~vd?N4277!wlULW=d}KW%9jxIX#s za{W5M_00|pzyEV#{Qf_C9YI?p0P9@v`~NXl1NOa_&HqI<{}&Hvbpd{9k1Af051qMK=Ez+5BH*^M8@e|3x!Qu5suA2_OL^fCP{L5`B7I8wmh?{PC6Y`&AuW@5=|-YSzmESxD!{J$ z=HH190@IHKkN^@u0!RP}AOR$R1dsp{cv=%UN$?H$R&1%&rivSl80z;-#J9rA)k}Q@n%(xD{RDF+VFi{j6l-lRL#HGx35>@d769=@j=cvD7J+n3!~m z2@{{vDL#d~kn8nGJ#!uDbRA*h<(=Z?OdRSIhnP6nDGoBR*eMptFStRElyniXKzcg^ z>1ATRQ%t}2FPRZg1SBH4k0ZY$kB~o-pOgE@FK0MH0TMt0NB{{S0VIF~kN^@u0!RP} zAOR$BoD-neHWI2x^rL@_nnbF^sS;U!_}CqnLr`TzGh@+iCkc!>Op{FrjC~m zzyCjU!ek2*iUg1V5q44zkKdk?Ms$TqT>Y#?V6gRCb>avE7dddUJ3 zB?0MwrN2nOmwqMv9R6;e@i!`U`HTPCGnO#TmA$~1Ad=RT+h@&rVcRm45qGQ>RP5InYxCl z{Y-rZQ&%(fbf%uh)IO%JVrqh^r!sXVQ&%wc6s9g`>d8!9#?+-u?PcmoOkKj%#Y|nq z)P+o4z|3F1=BDwe)i7h0=4STcu}72c_$!{ZdiNN_(Ztq;1k>X@hj8WJv3!q;#6JLh6+k zNKq*e|KIpu;=hmoD*p5MkK+Fm|7QHl@&Ab58~;T7!|}W0?~K1G{_6P4;?IxY5x*sV zC_WnB6+b^N$5+N)g}xv9V(4E&Zw}doXqO_qKAQGG+-Bk3RhTj&+N?J{6N>77#i8Kvd z`7Du~Q56;9(6ych=Mc$y+K_vuZ)u8Bnyjc0meDhPvs)ymdZwS%5~+rws3}A1nZBth zGSsx3(NsOtGkv2|q-GSgXZi+*D6OYei1Dy3GL^KZ80ntrL$(NLXc-#(!Inso<+PU4 zArS|fB2`W+vXRjstf{6*Q8ZNnkC6JhTckoFYEF@2XdtS#MM_3b8IbzxnMjBH0We+B z!PR6-BxgXZ$&l1aQzS$F(m-GDnJ&9TDFZxCSR!CA%Nbp!c^q$vWKGev43y*a{-#J( z(~2f*Dy058Ceon9AaG4qfkep`0UW3R5d4@e(jj>wYTLf9x6b(StC6NCrDo)m3>oN|&b36~OHoV%JYMS% z$-1h6tE?@eb=A-ysn2YROj!j$Omt0Cq$(-M5LB|B>8ouKR5?Y_L3EW{q(Y2WwncJE zOR3;$Z%ZVn0HRLo#2$wT%0~tgSJ)y*gltmwm)jymN$V*YM7x_JMWL<3RG}PqF%fN3 zP#^RRG`{J}S|T6@nWm+^(3VcUU55QZiIIR!z1y zMbOX{Qyw=%SVgO3~B}9n!VM78!C%*Jy?=Y>ISf z3LvEY#O9`mCJX8krFubAq^giGC`m}ya7zUBi?&Gsy{RdJZbM1wv>Te<*b+hKr$b!_ zSLeG$G^rb0BIv++rq5#{-~y!~L$!lMoNI}o41ogu*E4-iQv^w9iOz0{fR=0;z`tku ztd@xOCXj1jf2J*hdJpWu)lgFeO%%dnR5LCSi!p7BQi^IYUMX7yEf&%W!JBRojnS}0 zdMl~AEz+PNv%XMsi)f*#wn$b?sJ?(uVIn9Vs1r~`v`dp+BCzP0Uf&Wy>(FGKHmgBf zq(c)`Xn#Loi2zMTfhJFrdPY+O?E-3HhSrI7O%e1ON(#DU2y3lF1U(1McCsmgx&-`G z1=6*qDWVlTqe17_Gu`hJ>9qfP1{KjJ1vLj;(%yHqEux7?(cn+FMbN>32uPgf6hWr| z8R~P14BBI^YKb7>s;*O4iKYlzF*I=K;(Mk~ZHa&?eds_QSGGjZ%|ic0L9b|vWazp~ z&7>qwX^8-!0#6v=wcIVD55tpPB9j*FGPg*9u$H<+21VHG66rdGb&^{|d$}bpkw)Px zc8e(0MJ|y_T`hEp6e?Qa7SU?b;}XGGre~TsMevw|bV)8znhr7IE>Vg;J7R7TjE1J8 zE|E!}$Pt&wpy>*`L^?$na)~rrO@b~FG}4}FHvWS8CDRhppoRBLv+^I$V8bt40yVvdjlP%!>b_>c6O9eN zpo2@v@Elj^*uV=U28=+UUx%V$nY}5r3`c#Il4Ek?2=%NxjW>sLA+EcgSf<%K(k`_7}axpj1mf%UC_plLHQ$nAe zMh_csfkcDWrs^r^;MsVKO6ceZIx(e(4Y!yCIu2cdw#G(VO$qpco{tT-KmyGS#?hLV z3XJoM6geH(PqkFwI;xq064i{r7}fN^KB{SfQL3qdBGr^Yfoigl=NDu$!U(8oAqQ$o zxE54X$bxDJ&jeK$t^rjOt_D>Vt^!pNt^`#U_VNqT8DS5oY2gY`Q^Mt-n!;{S4Ph6k zx^Nk&ny?d8Rk##XMYsf1S=hlZNM(fWpr(awpr(Yapqj$Ppc=wOpz6XFP&MH~P*q_w zsETj_sIoB3FEBI0CQ#GDMo?42`JkG@22c&*JWzGvTu?RP98gu^Y)}>9EKp_POn!lp z5r#lb3mH&TLK;+4NP%hyCaAh#fT{^PsH&iWst78mvY_w_^o$^bnikfBni2*bzvQ-ny?mBRY-!W2x~xbcsta*YH6aG7Dnvn5gb1jzKg^SiKg5%?Kgg4mU*w7D z5AekB3p~;Nex7K4o+m0y0Et4+{~wg@=V12#Tk;_J3EckoZ8!(;OXPEKBH%~KJ#Zf2 zJII^JYsf#57m*|6HgYpLM5<(*jFM}~m1Gy$PA(+ple36PWU`i=PF9koWFd(Wk#N#q zr9Vi&mhOkYn`ZnKq%ME)XFvYG;M?c-7y7^n^mk+Eg#HtM@bvv_y)gNQ(uFHLzKIJ( z=XYkta(w$wu{y+QJLwjsK=qK-M*aCp7*aCpPYyrR(YyrS-wgBKVwgBK# zwg6xUTL7?)EdaQfEdbcU765E!3jl`M0)UNd0l)^f0N`A<0N`x40N_lv03gE_0HoLg z0D~<6P}u?ig)IPB&lUg-umu3?*aCnxYym(&TL5r6TL93<762sJ0)Ull0l+D20l>*@ z0l-qW0N^CH0AMj&0I-lP0O(;003@~mAj%d1MA!m=kYfRWz!m`T*7^SwXAcM8{~sGy z^o0bF01`j~NB{{S0VIF~kN^@u0!RP}9RCC&G>JI>KmH2}Q-}nR01`j~NB{{S0VIF~ zkN^@u0!ZL-5NOT+A4d@A6$u~#B!C2v01`j~NB{{S0VIF~kN^@m&Iv@wKXZ%8`5bu& zcKv^W{2O@{c?sIL{U)4+$UvB!C2v z01`j~NB{{S0VIF~kiZj6ASn2Jz7^sMrk^67V(G$irY{qEnZ8swiRrz<5~eQ^7FxQv zi0KQ29;WvQgy}?(m@Wx%rY{vwCg0&gH0kX3N?|3_mkZ079uh)K4+=r1i-Ji0O4s$b z|1tT=!cwO50^R*Da$JPm#|=g<;mEz@EpW2`DBR|^hJ>XD;hg?=Nza$c(hfFSaViM}HjsO!TeMJEHrd7ezLQ-`4HVf9K=>Yv&qGNZ>>uAe_&g^LWx3{C|(fH~K{aNZ|M- z5W1GT>F<}i;HUn6abwIU7J-%i4L-O_A~T>U1B#YVGDEU4B%6b9?LjJItoOFo29@k(t9w}^fSDzjX{Vxol;hNTkC^q$hWDV-pyK* z;VAyhY2Mb_Aie2C)%&_xD`~hrD6`7jS{*dmjZleh)^MJ`Zpf#4TPuS)9H(!lR(e~@ zgSrkENSG@;t>w&M8gBAYQ>S#ZhJ*Xlsnl|B>+~R8hXFT%oa}AQ3KXi#GH+{hFauX- z$lB6w)^L#k+LOSRt2~Dw41e(Nh_ur@wSHcZOTv|!riQ88Ll|XguJcwLB)gyst3KTwZXKJ z*0r?gZ4D)+L0yys-K?Q5rQoIpZ)<2o^j;d>-_05>aLQy%I?rF({TYJm|GTq68zg`P zkN^@u0!RP}AOR$R1dsp{Kmtz}0(AZ_klQ(OpS1$u>5?zZ2NFO6NB{{S0VIF~kN^@u z0!RP}Ac5nKfc*tuP7kPNLP-x9%8(9AGGNt|uC%}ZH?6@=8-k@ruvkP-r`zBE+t%uk zrVq-hk~UKO3jc;MTahK318O>E#U)%cgRk%Ms1=MaktC0-$o_3n=&U5Rzk?~@#UeD#nCW_^H&0!Qb?i}8* zYdEoM!}(i>6MYVwzQmfoQlT$VD%Xqqiq*vS9lH|ScW>RAxMb&+Z5wv(O|L?KciU!GIQhy1E18zQ$XzTg@x04~g;p$N>xUp>UOlW z2GRJcP#+1q75Q7RXThnSLe)LjTSTPW4` zXGcrp#d2=KS^2q-HQ8?2zG-+*qHk``eTg00XEY60@O{bYO^q{xy;G2+8@nfoBFUA? zMM^K5D;KhD0WBy;2Dp3Xk;t}h&)__h?ex>f3ci&jR#lSIVq;yf_hQILa+ZA9rRPlY zOXibg+oyNx+SbWwe`9U1cMGIsb@!CmmC>1y>3Jl?_UM_8wr%n$>qcAU;MK5Nt;ViD z-P?83X{+Mfjo)s8?uPHK#;u;Bi(?vSt#kwQD9wk$nsmEEadi^3nnB}t_dkwMq2?7z z`-(N_9$KA~skg)GNMq$-dAyP<)a-cekX(_rORbeYZ+D)ZPphwM@+%Z;`D$shUZOoz zGl_O+EjP4>DU_(@W9W{{ko{u4mMzt4Q^gwXv6uGWaSejgM^d-r-|Koqxhdw0W%)e^_o+gp|9)6l+ z1hX+;0@GaMWEes$^SOo)Bb8jW!1|N%T&@3LjS+b?4yc+0b; zZfu6zoK#uDd5+y3aoA6>?aiqdJT>WHcIK0&<9RucXV+wcmKZ< zSs4C(_#5F5hW{yiFuW(637;H#B=p_TCql0a-4ePsv;j^B@CSbq{4AUa@SNaSa7%D) zFe?61{7>;c;tRz|@lsJ07X|(h_-5ckfmZ|$1@;Dp0?UO*h3^TU6kad9p8r+%Ki_@M zzo&}o@fA<_-s3Ahf49{5*Kw!L8hPx$X0=Akr<#EMX0&5FX)2|sjm$H#C8uvYWLcYl>m)^{}?~s>&%-H}`m3r(t`c zoJpsz=w>bJD*U_L+d4I9!gf(3v%8zM3f@g)m$xTPYn z#>kYKPG8*38g>^OntGA9wGMk1VQZtlrJHpcw&9uDh25;7B4!k2b2n?i0=qIV@V18S zg{G>T%5XPp)65vAx~ZGB3fnF|KPf3mJVwH)}vb+e|MuGN(3ZB4h)LeG{lx>+lx278}%Z|l?`YzKwdRLy(;KUixT?6Wnz_y2>ntjo}Xz4!mi8u(5b zYRY^6zf2!BnT#TP@BgRPx~gPk@BRN^EyJ+~s^Pu=Uxxj`at1bKd+-03;p-x7(eJkZ zAFNXvY+hEq_y2=6L=4{-z4!lvHSD<7)4JFGf3{sbMNf3_-2cz4VZXO(=wAE(!8#2k zrl(BJYyUs9HdNRx?z#V;S<8k7ou=3Rf3Qx$QxKY<>9zl#S?g*V_M3a{|7X^!rYff5 zwf`Ti;SmcDgN*F8|DRc#I#fl~YyUs9R#n<1d+q;c)-r4smor}b|G^p_b5PY%y4U`H z%UXsqOL^`82WvQMA_IHul`i}L;p75%1j}ZZ{r~W>SR7+v=NLnAU%Fg)n8{~u1O zfHN{uN|*ir+92$)hgR5S|Gx?y7o5Yysa$8)pG{(l8d4}fQI zy3785dgek(&FEeB|I-$#o0{5X|35sa=us2h_WwfzHWjt&{(oqpG7JWB|Nm1xWx@E6 z01`j~NB{{S0VIF~kN^@u0!RP}9DfAp_kSO`mwo>~{!)i2LIOwt2_OL^fCP{L5GUA1g6*j|7ka55cKD@d+s&{iO6zY(!ce|6%-}WLRsoJe7UK5Wwcn& zk7e^?x$?eZtyr(g#DAKvnbK@6Ke2wf|4iTH_|(2q8PZpnD3yy@8uUn|vVU-azu$LV ztx}$B1v@}7Rg1N{Gp;lG{9Amr;`LL-a=nxrx3gO+P{C-aSgoz2d1z8?+1Il5YA(OO zSk0CSwY3!53j*sD;E!DOZDPJcA{9G%GPru{U`Yq zUwv$9Vx*iajn`Vqe}=1+n-o@4B2zU;hsFGKijx*-Z8BGG%1)zhSRq?(`si;~A*|o4 zD5)A$oqD!1nmt%7?oaglFY|$AzSycw*>Na?socII4U?AQzG9(NK6Q*lTN$IYN=8!)ekSFoLx2)O0Aa`%D!B= z4q-vD)U0}X60Q3zY$%XJlNEr)>hBU7JY+KqEo(nic*ZYV$Q`aNrg`p6%_5qSRs*O_ zjWkGXt_qz7L<*fCbYIXk zCZXO6G)b)=*~%n^So8PzSNjeY$03zPmJ~kbKQ)}2oXpls_3>haJjeye4>|Hv@?6P65Bo$&8aw_!z^(!i znAz{A-~R*Te%Sv{9wNUYeg8A!34%01`j~NB{{S0VIF~kN^@u0!RP}%#(oN z5BWr@2vqS?CE)jm!g2CG&M&=}lio}A5MH`^p249rB!C2v01`j~NB{{S0VIF~kN^@u z0!{)?^r`Zf`a)bd6%KFMkfU2+&Ks}fbK`W`{2()_vXU8)jR7^CP~{<6A5zspMb|T? zV%cN{R4t*Thg5S&)&|pQO;xpBLWuL7NrMdL%DM5wwYqnx;8#f~sUbrhGL%76Hd7g` zBUF7zGX_=DGz{$uKZLr0hAPrsKCl%47UO#dY(k0?iaMlahID-}rD?jBnGvv@9@I?D zRCJ)b!%6sYn(6m{uIF(Eg5Hq;5xa(9OR6#jMWq$fB-)3Js> z_ymV}q69acoqkrZ_gNa>SXL?*iienztybVrmFxt(j)Egdn!n&Y3@V1RShBft!DR_D z4yJS3Wx( z%?!rMSEoCgDR*>z$?0HYL9lltBy^pXPubGyYv0&fhu=b)X}Dnp-HUM5zq8i`B&T9lH|ScW>RAxMb&+ zZ5wv(Oj6Z4u{F<#f@OFcSFiIefEsHWP8dU%)9HfZDYDq z=$Q@XdyXWzJklQfR$oJeI-c^~zG_BovtxJpYJoMn*FM|hJZqsVe6P+4Dod+ z+{@fm!>YVa7qrf{{aO{oX-^BuVV|7l8bYvl^J?GpDo5jT`e3bq9@17SIK|JJPfFO~ zZnTW)5X0%4wHPZ{GMc>9}b=>2UbLY&JP0#_LA$FozMnI+b?5AS##_Q_i>Y;eKe z)vJAXT*f*DXBeaCA%F;Pnfeyh2Wqa&+I*nDPs_+0B9k1l- z&d17Jjk);G4Oglp_mvrRM5&XYid z{FS>Vc8`zzmi(N2pL~;iiQG#*O5R7_L0(V(i9Da&Ms6fkQX-OwJ-2SxZ)t zrGyYs`kV9z=@-&{(tk@|k^Wu!r1U}QUDBJSS4l6H?v!qk4oDMHLApxXDQ%I?lTy;4 zv|2hvS|mjzU;NMU-^70w|6cqX@h`^zE&h@C-SM}_Ul)IQ{CV+P<2S^wkB`N(@yp}e z;+x`U#?^Q-o{0CxrFbCrXzcf~2V*~qeLME$*ym!Oh}{E!X7|5v@v;30Upo>1#5w3U4g#?)T)6qu|51nhsWFBEzOc{t zO#Ydc;TrxL%WyS+wPm=9zsfRP$zN$1_VRlz!ybN*Ww?UB!ZKXWUv3$8^Sdp>E`FC~ zxQxHdGVJ7cT82ycOD)4C{3VuQ2fxEIZ0EOIhHd;d%dnN-Y8fu(FSZO9@fTT!E&LYC za3O!8W!TJbwhR~W7g&a2e%LZ>;x}1_jr>N-a6W&&W!S)Pungz%=UIkx`ExD9Is7@6 z;cWhF%WxKdmSs4TKhrV{@k5p&!)Gi*nonDX6rZvTCU05>gEuUL&g+&z<2B2m@~UM} zc*QcvylffP^Xo0cAU|js2KWKXa0Y*dWmw0rvkYtbwU!~tCoRJoevM`5=ldx@9047IF&!uGOXlRT80(;3d?W`e~M*T&M&tN zC-Wy;hGqOR%dnJRY8iU@UdwP2f0AWb!Y{E5i}}TtVG+N`GA!g5T80Ju0?W|D_gDtP z6U!j+l4XeVamx_nW0oPxM=e8yk64B_9JIKvhvR?7PsBIHJ{WyX=&hlJ;&;R?!Y2jA|3+Vr|Be2;I4=59 z8P-0ZumI+r@W$T8nZe%W%lX@bj-@d*YvD?bd%xF$7+6p=ul3XQ!;|f0(Vc4!XIs`Z zS{jGDP#tTkJ3Yh2vGgWdNQl?MTXw&wb4*rZ2-mAa{A1<($n_l8P3d9Iz7<+ z6Ybxuy3kdRLv+<6KfT_Obht)$qR8%kEwk0k&B&-1rxo`huk<=y(7Zc5Tj_H;Xx42= zSu;K1Mux6S^|_YgJAKd~+iUooHkZvOHEplniE-E`Zw)rmY*FIvm$KICjLc~!&4`! z8BXhJ;P%4087}Cx*03m#-AmhE4ecaA)0CW!H&Re9*16X!7boC)=WMP}pcmv?yLg%% zU55?#F3-Br)qAsUxb10Kw))XzLvNVD-gWEv+g4b0!|k>+{#SQY5x47k){<7_Hg3n- z$0h_Dp|hmsT`9^HxUl>19Od5Xq+9Dy=^9*TY^_e((>^&(8b+}9QrO|5IXayDR1Hos z%ED#g<8TAAyVG#l9rh|mmx~VH%`VXyerKO^d#$0f?Jq}Hv!Zkb=lT(Lm!ivVo@MB2 zceAwg`Su75S@YUwyYOcT7kZFd2^QsM59G$Did`P*RoJI>XwnYOZnXXVbYU!96%PZ3 zea=o`3!SbbC(78!S3zB<#3*D!xfQZ zHMSFqt6exP*y4GQ0&_pJnva{A1J$-Ox+PGxc7iy^M0C8Dt-%8Sy!D`Q3~QWLMXwIZ z>AVK}Yk$^WtSP2D$O(v$P-PQJX>JL%9kT9fBv&hD3$UfHwP92>jP_ouR$TRZ zH9KC}S8}-P9D_i+%~5BgrE0D2s)nxa))iuIzAou_pq)gIsOc__;^_Ec=r#A1YIApT z^>OIiXYB@I+Q)+NoYTQGy)xCkY+y$o3>3039q{OE9ZiYO|MC34dA}Y&he!YkAOR$R z1dsp{Kmter2_OL^fCNrR0(k!a30Z8IXe59HkN^@u0!RP}AOR$R1dsp{Kmx}^0O$Y5 zgbN)b0VIF~kN^@u0!RP}AOR$R1dsp{I3WqN=Ktg`CuH(5(MSLZAOR$R1dsp{Kmter z2_OL^fCP}hJP6SJ|4X=^anc{9(fHRRx$ysnUl8sMy&}{Td`)n*c#n8);4J~wf4~14 z{sBJgyAPZm481+{x>?kycU2{F?Jd_dq^7xa13P-JWy3vZt`xZa%}hmyJ>1s24QeGM z#91p_(b0r73$i8RZl5a!cFEIQi(B3(fR;saI@s6>*Y(1&gBuz9mZL72Uh9sri|aYF z3df){y)vlQv3-pT8W#t9SFG^emSruV6?jWu(~P@$LS9Qe&qm;k&v`6RtKzzn%)w*#{rmD2Oz%E@Z!09-epZ3Zz*d#W@pqTQRjBDK3W`$RoU#C_CV zsH`4X*F&?$XFIow)$&BCw=I&>y^Srw-m4(WVMh~gM_H{@XwQ<(l?&PN(K^$s`|8aE zyl(acbn)DooTf8+LM22&HHe`vS#4YhH`qhUmUyPDO}&|z7tNlSw)@Wb9X84NJYeWO zcPiCV{jeS7)a+3@ z+;>Lmw1O^cn8NjSfm^TU^849^>sC_gv&Y(Y-WjRGCOPeIY=RCOB6W7y?Yxeb4nao^ zrwi5SnUF2Uwb`TY^wgPv8TQF%H8uu&w?HaZd)6yBP^z@AOwVSm*lDQFo(8v<&J=Xm zLW!S0TZzMCx45rTZI}4{Cl$veu8bA!FhmieA<9b#vNXsNx;aGMVu zOE}L*j-%4r4+Y0*n~o%SS=XjU=y=RN(90f-_4hlEtegFSKIjAsQ*d+{R0iubWIL4R zK+RdUb}Cv=uBMxIVc0Gl+32X3wv&!PoZW`)#u3bn24*|z2&moZ*)ANxj92peTWx>l zsc^1`yraKvKW{rC^E`*N!wul6)@MOnsFaIYb`bI$2`bj$7*r^!LUs(szHs!~=y)Yp z?<}$QQ`gRaM}k@p!fy8T>DbMVJ~F%6!6BMZigXMz$Ek4n@k$MH;X1t4nMQhm>p5^b zVv?U$Iy+A|jFR>s&GQj!St~5o?rbaWRUNIpTqqv0Ml7})`qYC2TizY5-*&(nvF(5! zVtqC|RUk<-o+`E%_9Shd{@9VCSI#d*?PEjjC%GLu8&b8-mP|Ip##zDMWU@6MbjRoZ zwZx;7as}%g@U|LD;*y3c1}xWcoG$>o%OhN z0P1YbgLXj4Nc?9fGyK>1%%WHk!eFUd^P6Be_g2ms8Y{OkN+6M@Ca4YQCr{s+um!`BB5jXuGK6R4Qf4qocWW zCT-?NGxBJ$D65*1&zPgRd?uwEhM7)}<}*8~V@)?qMNN+?S|Kx<9!bk)CRZ3$@>-^- zsKt@AZlq;72WX{-xB;)^dCF+WIXwq~Yw1*4P0Kn2njc9QMsvlCshX;xfFvd7wNzdv zhq)^~LwVdnMx&q?a(UTQQW@PGRm?(KmD6$|Eh~i_Kq_Q36)=vbocXsKHRs{g99Oqr>z6A9t~107w7{AOR$R1dsp{Kmter z2_OL^fCP?v0&)LcT#v7x^C!uj(of>cVjqlckA6P7Bl7jo;n0HMI|Hu{NWOmm=eaXE z^|;T>lb66-Z*F9Ry}iA@=Ul~>Pgg7B#Tru*?&Tp&HqRw&^Ia7(=V}jYm6-Q+xb!yL zktw)IlHQ!zxmv`vWNWfmoq(k;u&%SqrNeApOfAdq#x0G*f>(R_oa=tg{^sHn*Gf9N zfO{TZ;SOP!H+pq7TvS`HmSD}&oDp~WhTmCMAlZprIk(U2BIEW|n82x4tOKTfUfEBM zH!cnKp1s^R9d|6MYHk&wOP87})SHrnUMrSny0(^1IX0ZM*10F4D$B=Gog3#juC>

ZCp&+PgC0Cfp!9~}d%b{H5 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 Date: Wed, 13 Nov 2019 16:19:33 -0500 Subject: [PATCH 071/200] install py3 libraries for 2019.2.2 Salt on Ubuntu - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/105 --- install_scripts/disable-checksum-offload.sh | 2 +- so-setup-network.sh | 46 +++++++++++++++++---- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/install_scripts/disable-checksum-offload.sh b/install_scripts/disable-checksum-offload.sh index 9cc0b5d5b..32b8d46e6 100644 --- a/install_scripts/disable-checksum-offload.sh +++ b/install_scripts/disable-checksum-offload.sh @@ -6,4 +6,4 @@ if [ "$NM_DISPATCHER_ACTION" == "pre-up" ]; then ethtool -K $DEVICE_IFACE $i off; done fi -fi \ No newline at end of file +fi diff --git a/so-setup-network.sh b/so-setup-network.sh index bfdcad7a9..422ec8a99 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -356,10 +356,11 @@ docker_install() { yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo yum -y update yum -y install docker-ce - pip3 install -t /usr/lib/python3.6/site-packages/ docker if [ $INSTALLTYPE != 'EVALMODE' ]; then docker_registry fi + echo "Using pip3 to install docker-py for salt" + pip3 install -t /usr/lib/python3.6/site-packages/ docker echo "Restarting Docker" >> $SETUPLOG 2>&1 systemctl restart docker systemctl enable docker @@ -382,6 +383,8 @@ docker_install() { echo "Restarting Docker" >> $SETUPLOG 2>&1 systemctl restart docker >> $SETUPLOG 2>&1 fi + echo "Using pip3 to install docker-py for salt" + pip3 install docker fi } @@ -483,6 +486,15 @@ install_cleanup() { } +install_pip3() { + + if [ $OS == 'ubuntu' ]; then + echo -e "XXX\n0\nInstalling pip3... \nXXX" + apt-get -y install python3-pip gcc python3-dev + fi + +} + install_prep() { # Create a tmp space that isn't in /tmp @@ -504,9 +516,13 @@ install_master() { wget --inet4-only -O /opt/so/gpg/GPG-KEY-WAZUH https://packages.wazuh.com/key/GPG-KEY-WAZUH else - apt-get install -y salt-common=2019.2.2+ds-1 salt-master=2019.2.2+ds-1 salt-minion=2019.2.2+ds-1 python-m2crypto + apt-get install -y salt-common=2019.2.2+ds-1 salt-master=2019.2.2+ds-1 salt-minion=2019.2.2+ds-1 apt-mark hold salt-common salt-master salt-minion - apt-get install -y python-m2crypto + echo -e "XXX\n11\nInstalling libssl-dev for M2Crypto... \nXXX" + apt-get -y install libssl-dev + echo -e "XXX\n12\nUsing pip3 to install M2Crypto for Salt... \nXXX" + pip3 install M2Crypto + fi copy_master_config @@ -849,6 +865,7 @@ EOF fi fi + echo "Using pip3 to install python-dateutil for salt" pip3 install -t /usr/lib/python3.6/site-packages/ python-dateutil yum clean expire-cache yum -y install salt-minion-2019.2.2 yum-utils device-mapper-persistent-data lvm2 openssl @@ -877,6 +894,8 @@ EOF # Nasty hack but required for now if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then + echo "Using pip3 to install python-dateutil for salt" + pip3 install python-dateutil # Install the repo for salt wget --inet4-only -O - https://repo.saltstack.com/apt/ubuntu/$UVER/amd64/latest/SALTSTACK-GPG-KEY.pub | apt-key add - wget --inet4-only -O - https://repo.saltstack.com/apt/ubuntu/$UVER/amd64/2019.2/SALTSTACK-GPG-KEY.pub | apt-key add - @@ -900,7 +919,7 @@ EOF # Initialize the new repos apt-get update >> $SETUPLOG 2>&1 - apt-get -y install salt-minion=2019.2.2+ds-1 salt-common=2019.2.2+ds-1 python-m2cryptoi python-dateutil >> $SETUPLOG 2>&1 + apt-get -y install salt-minion=2019.2.2+ds-1 salt-common=2019.2.2+ds-1 >> $SETUPLOG 2>&1 apt-mark hold salt-minion salt-common else @@ -914,7 +933,7 @@ EOF echo "deb https://packages.wazuh.com/3.x/apt/ stable main" | tee /etc/apt/sources.list.d/wazuh.list # Initialize the new repos apt-get update >> $SETUPLOG 2>&1 - apt-get -y install salt-minion=2019.2.2+ds-1 salt-common=2019.2.2+ds-1 python-m2crypto python-dateutil >> $SETUPLOG 2>&1 + apt-get -y install salt-minion=2019.2.2+ds-1 salt-common=2019.2.2+ds-1 >> $SETUPLOG 2>&1 apt-mark hold salt-minion salt-common fi @@ -986,9 +1005,16 @@ salt_master_directories() { salt_install_mysql_deps() { - yum -y install gcc mariadb-devel python3-devel - pip3 install -t /usr/lib64/python3.6/site-packages/ mysqlclient - + if [ $OS == 'centos' ]; then + yum -y install gcc mariadb-devel python3-devel + echo "Using pip3 to install mysqlclient for salt" + pip3 install -t /usr/lib64/python3.6/site-packages/ mysqlclient + elif [ $OS == 'ubuntu' ]; then + apt-get -y install libmysqlclient-dev + echo "Using pip3 to install mysqlclient for salt" + pip3 install mysqlclient + fi + } sensor_pillar() { @@ -1895,9 +1921,10 @@ if (whiptail_you_sure); then # Install salt and dependencies { sleep 0.5 + install_pip3 >> $SETUPLOG 2>&1 echo -e "XXX\n1\nInstalling mysql dependencies for saltstack... \nXXX" salt_install_mysql_deps >> $SETUPLOG 2>&1 - echo -e "XXX\n0\nInstalling and configuring Salt... \nXXX" + echo -e "XXX\n2\nInstalling and configuring Salt... \nXXX" echo " ** Installing Salt and Dependencies **" >> $SETUPLOG saltify >> $SETUPLOG 2>&1 echo -e "XXX\n5\nInstalling Docker... \nXXX" @@ -2131,6 +2158,7 @@ if (whiptail_you_sure); then sleep 0.5 echo -e "XXX\n0\nCreating Bond Interface... \nXXX" network_setup >> $SETUPLOG 2>&1 + install_pip3 >> $SETUPLOG 2>&1 echo -e "XXX\n1\nInstalling mysql dependencies for saltstack... \nXXX" salt_install_mysql_deps >> $SETUPLOG 2>&1 echo -e "XXX\n1\nInstalling saltstack... \nXXX" From f8fed24aa5f7ef52cb30f04a41730788ef830218 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 14 Nov 2019 13:14:33 -0500 Subject: [PATCH 072/200] Version Updates --- salt/fleet/init.sls | 4 ++-- salt/playbook/init.sls | 4 ++-- salt/soctopus/init.sls | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/salt/fleet/init.sls b/salt/fleet/init.sls index af7951170..917ee541e 100644 --- a/salt/fleet/init.sls +++ b/salt/fleet/init.sls @@ -61,13 +61,13 @@ fleetdbpriv: so-fleetimage: cmd.run: - - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-fleet:HH1.1.0 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-fleet:HH1.1.3 so-fleet: docker_container.running: - require: - so-fleetimage - - image: docker.io/soshybridhunter/so-fleet:HH1.1.0 + - image: docker.io/soshybridhunter/so-fleet:HH1.1.3 - hostname: so-fleet - port_bindings: - 0.0.0.0:8080:8080 diff --git a/salt/playbook/init.sls b/salt/playbook/init.sls index 6a054195a..bc22b60d4 100644 --- a/salt/playbook/init.sls +++ b/salt/playbook/init.sls @@ -26,13 +26,13 @@ navigatorconfig: so-playbookimage: cmd.run: - - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-playbook:HH1.1.1 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-playbook:HH1.1.3 so-playbook: docker_container.running: - require: - so-playbookimage - - image: docker.io/soshybridhunter/so-playbook:HH1.1.1 + - image: docker.io/soshybridhunter/so-playbook:HH1.1.3 - hostname: playbook - name: so-playbook - binds: diff --git a/salt/soctopus/init.sls b/salt/soctopus/init.sls index a5c72e362..578789a76 100644 --- a/salt/soctopus/init.sls +++ b/salt/soctopus/init.sls @@ -12,7 +12,7 @@ soctopussync: - user: 939 - group: 939 - template: jinja - + soctopuslogdir: file.directory: - name: /opt/so/log/soctopus @@ -46,18 +46,18 @@ navigatordefaultlayer: so-soctopusimage: cmd.run: - - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-soctopus:HH1.1.1 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-soctopus:HH1.1.3 so-soctopus: docker_container.running: - require: - so-soctopusimage - - image: docker.io/soshybridhunter/so-soctopus:HH1.1.1 + - image: docker.io/soshybridhunter/so-soctopus:HH1.1.3 - hostname: soctopus - name: so-soctopus - binds: - /opt/so/conf/soctopus/SOCtopus.conf:/SOCtopus/SOCtopus.conf:ro - - /opt/so/log/soctopus/:/var/log/SOCtopus/:rw + - /opt/so/log/soctopus/:/var/log/SOCtopus/:rw - /opt/so/rules/elastalert/playbook:/etc/playbook-rules:rw - /opt/so/conf/playbook/nav_layer_playbook.json:/etc/playbook/nav_layer_playbook.json:rw - port_bindings: From ff4077a46f3505a3cfd04ccbfc0ce45ecee41246 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 15 Nov 2019 13:58:32 -0500 Subject: [PATCH 073/200] update all nodes motd with nodes that need restarted from patch updates - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/112 --- salt/_modules/needs_restarting.py | 25 +++++++++++++++++++ .../package_update_reboot_required.jinja | 23 +++++++++++++++++ salt/motd/init.sls | 5 ++++ salt/patch/os/init.sls | 10 ++++++++ salt/top.sls | 1 + salt/yum/packages.sls | 3 +++ 6 files changed, 67 insertions(+) create mode 100644 salt/_modules/needs_restarting.py create mode 100644 salt/motd/files/package_update_reboot_required.jinja create mode 100644 salt/motd/init.sls create mode 100644 salt/yum/packages.sls diff --git a/salt/_modules/needs_restarting.py b/salt/_modules/needs_restarting.py new file mode 100644 index 000000000..51f80670a --- /dev/null +++ b/salt/_modules/needs_restarting.py @@ -0,0 +1,25 @@ +from os import path +import subprocess + +def check(): + + os = __grains__['os'] + cmd = 'needs-restarting -r > /dev/null 2>&1' + + if os == 'Ubuntu': + if path.exists('/var/run/reboot-required'): + retval = 'True' + else: + retval = 'False' + + elif os == 'CentOS': + try: + needs_restarting = subprocess.check_call(cmd.split(), shell=True) + except subprocess.CalledProcessError: + retval = 'True' + retval = 'False' + + else: + retval = 'Unsupported OS: %s' % os + + return retval diff --git a/salt/motd/files/package_update_reboot_required.jinja b/salt/motd/files/package_update_reboot_required.jinja new file mode 100644 index 000000000..3a1fd1e9e --- /dev/null +++ b/salt/motd/files/package_update_reboot_required.jinja @@ -0,0 +1,23 @@ +{% set needs_restarting_check = salt['mine.get']('*', 'needs_restarting.check', tgt_type='glob') -%} + +{%- if needs_restarting_check %} + {%- set minions_need_restarted = [] %} + + {%- for minion, need_restarted in needs_restarting_check | dictsort() %} + {%- if need_restarted == 'True' %} + {% do minions_need_restarted.append(minion) %} + {%- endif %} + {%- endfor -%} + + {%- if minions_need_restarted | length > 0 %} +***************************************************************************************** +* The following nodes in your Security Onion grid need restarted due to package updates * +***************************************************************************************** + + {% for minion in minions_need_restarted -%} + {{ minion }} + {% endfor -%} + + {%- endif -%} + +{%- endif -%} diff --git a/salt/motd/init.sls b/salt/motd/init.sls new file mode 100644 index 000000000..a314ddb80 --- /dev/null +++ b/salt/motd/init.sls @@ -0,0 +1,5 @@ +package_update_reboot_required_motd: + file.append: + - name: /etc/motd + - source: salt://motd/files/package_update_reboot_required.jinja + - template: jinja diff --git a/salt/patch/os/init.sls b/salt/patch/os/init.sls index d3ae6a1ff..97183199b 100644 --- a/salt/patch/os/init.sls +++ b/salt/patch/os/init.sls @@ -1,4 +1,14 @@ +{% if grains.os == "CentOS" %} +include: + - yum.packages +{% endif %} + patch_os: pkg.uptodate: - name: patch_os - refresh: True + +needs_restarting: + module.run: + - mine.send: + - func: needs_restarting.check diff --git a/salt/top.sls b/salt/top.sls index f742a66cf..711cf564c 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -7,6 +7,7 @@ base: '*': - patch.os.schedule + - motd 'G@role:so-sensor': - ca diff --git a/salt/yum/packages.sls b/salt/yum/packages.sls new file mode 100644 index 000000000..4c773d0e9 --- /dev/null +++ b/salt/yum/packages.sls @@ -0,0 +1,3 @@ +install_yum_utils: + pkg.installed: + - name: yum-utils From 8261b6fc6341893eef81e956efb236f0772d2ce4 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 15 Nov 2019 14:02:06 -0500 Subject: [PATCH 074/200] move cmd assignment - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/112 --- salt/_modules/needs_restarting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/_modules/needs_restarting.py b/salt/_modules/needs_restarting.py index 51f80670a..49f82bbf2 100644 --- a/salt/_modules/needs_restarting.py +++ b/salt/_modules/needs_restarting.py @@ -4,7 +4,6 @@ import subprocess def check(): os = __grains__['os'] - cmd = 'needs-restarting -r > /dev/null 2>&1' if os == 'Ubuntu': if path.exists('/var/run/reboot-required'): @@ -13,6 +12,7 @@ def check(): retval = 'False' elif os == 'CentOS': + cmd = 'needs-restarting -r > /dev/null 2>&1' try: needs_restarting = subprocess.check_call(cmd.split(), shell=True) except subprocess.CalledProcessError: From f9b1fc8b1fc22adaf2071684a9b8ae5285ae9a88 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 15 Nov 2019 15:48:21 -0500 Subject: [PATCH 075/200] bug fix for remote distribution so setup - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/114 --- so-setup-network.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index 422ec8a99..db0a313b3 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -278,7 +278,7 @@ copy_minion_tmp_files() { rsync -a -v $TMP/ /opt/so/saltstack/ >> $SETUPLOG 2>&1 else echo "scp all files in $TMP to master /opt/so/saltstack" >> $SETUPLOG 2>&1 - scp -prv -i /root/.ssh/so.key $TMP socore@$MSRV:/opt/so/saltstack >> $SETUPLOG 2>&1 + scp -prv -i /root/.ssh/so.key "${TMP}/*" socore@$MSRV:/opt/so/saltstack >> $SETUPLOG 2>&1 fi } From f40f00255f1756663a5cbb5544129ed00baddabe Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 15 Nov 2019 16:02:21 -0500 Subject: [PATCH 076/200] adding install_pip3 for sensor and node types --- so-setup-network.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/so-setup-network.sh b/so-setup-network.sh index db0a313b3..e1adb38c8 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -2056,6 +2056,7 @@ if (whiptail_you_sure); then copy_ssh_key { sleep 0.5 + install_pip3 >> $SETUPLOG 2>&1 echo -e "XXX\n0\nSetting Initial Firewall Policy... \nXXX" set_initial_firewall_policy >> $SETUPLOG 2>&1 echo -e "XXX\n3\nCreating Bond Interface... \nXXX" @@ -2321,6 +2322,7 @@ if (whiptail_you_sure); then copy_ssh_key { sleep 0.5 + install_pip3 >> $SETUPLOG 2>&1 echo -e "XXX\n0\nSetting Initial Firewall Policy... \nXXX" set_initial_firewall_policy >> $SETUPLOG 2>&1 echo -e "XXX\n5\nInstalling Salt Packages... \nXXX" From 95a3919df44ff528f01c8c80a7253121e695fae1 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 15 Nov 2019 16:08:50 -0500 Subject: [PATCH 077/200] make socore own /opt/so/saltstack recursively - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/113 --- salt/master/init.sls | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/salt/master/init.sls b/salt/master/init.sls index 1a7efe744..c6e11279d 100644 --- a/salt/master/init.sls +++ b/salt/master/init.sls @@ -17,6 +17,15 @@ {% if masterproxy == 1 %} +socore_own_saltstack: + file.directory: + - name: /opt/so/saltstack + - user: socore + - group: socore + - recurse: + - user + - group + # Create the directories for apt-cacher-ng aptcacherconfdir: file.directory: From 6bcadded1452a4d02bdf709718b17e4e17341fea Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 15 Nov 2019 18:16:27 -0500 Subject: [PATCH 078/200] change scp of pillar files, install pip3 for centos --- so-setup-network.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index e1adb38c8..a2871a9f5 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -278,7 +278,7 @@ copy_minion_tmp_files() { rsync -a -v $TMP/ /opt/so/saltstack/ >> $SETUPLOG 2>&1 else echo "scp all files in $TMP to master /opt/so/saltstack" >> $SETUPLOG 2>&1 - scp -prv -i /root/.ssh/so.key "${TMP}/*" socore@$MSRV:/opt/so/saltstack >> $SETUPLOG 2>&1 + scp -prv -i /root/.ssh/so.key $TMP/* socore@$MSRV:/opt/so/saltstack >> $SETUPLOG 2>&1 fi } @@ -488,9 +488,12 @@ install_cleanup() { install_pip3() { + echo "Installing pip3" + if [ $OS == 'ubuntu' ]; then - echo -e "XXX\n0\nInstalling pip3... \nXXX" apt-get -y install python3-pip gcc python3-dev + elif [ $OS == 'centos' ]; then + yum -y install python3-pip gcc python3-devel fi } @@ -716,7 +719,7 @@ saltify() { ADDUSER=adduser if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then - yum -y install https://repo.saltstack.com/py3/redhat/salt-py3-repo-latest-2.el7.noarch.rpm + yum -y install https://repo.saltstack.com/py3/redhat/salt-py3-repo-2019.2-2.el7.noarch.rpm cp /etc/yum.repos.d/salt-latest.repo /etc/yum.repos.d/salt-2019-2.repo sed -i 's/latest/2019.2/g' /etc/yum.repos.d/salt-2019-2.repo cat > /etc/yum.repos.d/wazuh.repo <<\EOF @@ -1006,7 +1009,7 @@ salt_master_directories() { salt_install_mysql_deps() { if [ $OS == 'centos' ]; then - yum -y install gcc mariadb-devel python3-devel + yum -y install mariadb-devel echo "Using pip3 to install mysqlclient for salt" pip3 install -t /usr/lib64/python3.6/site-packages/ mysqlclient elif [ $OS == 'ubuntu' ]; then From 8da092e49752f7262ecf2fc0a3ea2753a7c1e77c Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 18 Nov 2019 09:40:08 -0500 Subject: [PATCH 079/200] fix repo for distributed salt install - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/116 --- so-setup-network.sh | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index a2871a9f5..45ede5393 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -525,7 +525,7 @@ install_master() { apt-get -y install libssl-dev echo -e "XXX\n12\nUsing pip3 to install M2Crypto for Salt... \nXXX" pip3 install M2Crypto - + fi copy_master_config @@ -661,7 +661,7 @@ patch_pillar() { PATCHPILLARPATH=$NODEPILLARPATH ;; esac - + echo "" >> $PATCHPILLARPATH/$MINION_ID.sls echo "patch:" >> $PATCHPILLARPATH/$MINION_ID.sls @@ -719,7 +719,7 @@ saltify() { ADDUSER=adduser if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then - yum -y install https://repo.saltstack.com/py3/redhat/salt-py3-repo-2019.2-2.el7.noarch.rpm + yum -y install https://repo.saltstack.com/py3/redhat/salt-py3-repo-latest-2.el7.noarch.rpm cp /etc/yum.repos.d/salt-latest.repo /etc/yum.repos.d/salt-2019-2.repo sed -i 's/latest/2019.2/g' /etc/yum.repos.d/salt-2019-2.repo cat > /etc/yum.repos.d/wazuh.repo <<\EOF @@ -828,7 +828,7 @@ EOF # Proxy is hating on me.. Lets just set it manually echo "[salt-latest]" > /etc/yum.repos.d/salt-latest.repo echo "name=SaltStack Latest Release Channel for RHEL/Centos \$releasever" >> /etc/yum.repos.d/salt-latest.repo - echo "baseurl=https://repo.saltstack.com/yum/redhat/7/\$basearch/latest" >> /etc/yum.repos.d/salt-latest.repo + echo "baseurl=https://repo.saltstack.com/py3/redhat/7/\$basearch/latest" >> /etc/yum.repos.d/salt-latest.repo echo "failovermethod=priority" >> /etc/yum.repos.d/salt-latest.repo echo "enabled=1" >> /etc/yum.repos.d/salt-latest.repo echo "gpgcheck=1" >> /etc/yum.repos.d/salt-latest.repo @@ -837,7 +837,7 @@ EOF # Proxy is hating on me.. Lets just set it manually echo "[salt-2019.2]" > /etc/yum.repos.d/salt-2019-2.repo echo "name=SaltStack Latest Release Channel for RHEL/Centos \$releasever" >> /etc/yum.repos.d/salt-2019-2.repo - echo "baseurl=https://repo.saltstack.com/yum/redhat/7/\$basearch/2019.2" >> /etc/yum.repos.d/salt-2019-2.repo + echo "baseurl=https://repo.saltstack.com/py3/redhat/7/\$basearch/2019.2" >> /etc/yum.repos.d/salt-2019-2.repo echo "failovermethod=priority" >> /etc/yum.repos.d/salt-2019-2.repo echo "enabled=1" >> /etc/yum.repos.d/salt-2019-2.repo echo "gpgcheck=1" >> /etc/yum.repos.d/salt-2019-2.repo @@ -853,7 +853,7 @@ baseurl=https://packages.wazuh.com/3.x/yum/ protect=1 EOF else - yum -y install https://repo.saltstack.com/yum/redhat/salt-repo-latest-2.el7.noarch.rpm + yum -y install https://repo.saltstack.com/py3/redhat/salt-py3-repo-latest-2.el7.noarch.rpm cp /etc/yum.repos.d/salt-latest.repo /etc/yum.repos.d/salt-2019-2.repo sed -i 's/latest/2019.2/g' /etc/yum.repos.d/salt-2019-2.repo cat > /etc/yum.repos.d/wazuh.repo <<\EOF @@ -1017,7 +1017,7 @@ salt_install_mysql_deps() { echo "Using pip3 to install mysqlclient for salt" pip3 install mysqlclient fi - + } sensor_pillar() { @@ -1586,7 +1586,7 @@ whiptail_patch_name_new_schedule() { local exitstatus=$? whiptail_check_exitstatus $exitstatus - + while [[ -z "$PATCHSCHEDULENAME" ]]; do whiptail --title "Security Onion Setup" --msgbox "Please enter a name for this OS patch schedule." 8 65 PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ @@ -1617,16 +1617,16 @@ whiptail_patch_schedule_import() { unset PATCHSCHEDULENAME PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter the name of the OS patch schedule you want to inherit. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 60 3>&1 1>&2 2>&3) + "Enter the name of the OS patch schedule you want to inherit. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 60 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus - + while [[ -z "$PATCHSCHEDULENAME" ]]; do whiptail --title "Security Onion Setup" --msgbox "Please enter a name for the OS patch schedule you want to inherit." 8 65 PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ "Enter the name of the OS patch schedule you want to inherit. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 60 3>&1 1>&2 2>&3) - + local exitstatus=$? whiptail_check_exitstatus $exitstatus done From 81e825b9545115ea30e3bee8f9816e14f23b8903 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 18 Nov 2019 11:12:05 -0500 Subject: [PATCH 080/200] move pip3 install after firewall setup --- so-setup-network.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index 45ede5393..59e4437fc 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -2059,9 +2059,10 @@ if (whiptail_you_sure); then copy_ssh_key { sleep 0.5 - install_pip3 >> $SETUPLOG 2>&1 echo -e "XXX\n0\nSetting Initial Firewall Policy... \nXXX" set_initial_firewall_policy >> $SETUPLOG 2>&1 + echo -e "XXX\n1\nInstalling pip3... \nXXX" + install_pip3 >> $SETUPLOG 2>&1 echo -e "XXX\n3\nCreating Bond Interface... \nXXX" network_setup >> $SETUPLOG 2>&1 echo -e "XXX\n4\nGenerating Sensor Pillar... \nXXX" @@ -2325,9 +2326,10 @@ if (whiptail_you_sure); then copy_ssh_key { sleep 0.5 - install_pip3 >> $SETUPLOG 2>&1 echo -e "XXX\n0\nSetting Initial Firewall Policy... \nXXX" set_initial_firewall_policy >> $SETUPLOG 2>&1 + echo -e "XXX\n1\nInstalling pip3... \nXXX" + install_pip3 >> $SETUPLOG 2>&1 echo -e "XXX\n5\nInstalling Salt Packages... \nXXX" saltify >> $SETUPLOG 2>&1 echo -e "XXX\n20\nInstalling Docker... \nXXX" From f05fcc271f44d6072533ca3266fb89802cb6ebdb Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 18 Nov 2019 12:45:12 -0500 Subject: [PATCH 081/200] Trying using packages vs pip for centos --- so-setup-network.sh | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index 59e4437fc..8618553eb 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -359,8 +359,8 @@ docker_install() { if [ $INSTALLTYPE != 'EVALMODE' ]; then docker_registry fi - echo "Using pip3 to install docker-py for salt" - pip3 install -t /usr/lib/python3.6/site-packages/ docker + #echo "Using pip3 to install docker-py for salt" + #pip3 install -t /usr/lib/python3.6/site-packages/ docker echo "Restarting Docker" >> $SETUPLOG 2>&1 systemctl restart docker systemctl enable docker @@ -493,7 +493,8 @@ install_pip3() { if [ $OS == 'ubuntu' ]; then apt-get -y install python3-pip gcc python3-dev elif [ $OS == 'centos' ]; then - yum -y install python3-pip gcc python3-devel + #yum -y install python3-pip gcc python3-devel + yum -y install epel-release python3 python36-dateutil python36-m2crypto python36-mysql python36-docker fi } @@ -868,8 +869,8 @@ EOF fi fi - echo "Using pip3 to install python-dateutil for salt" - pip3 install -t /usr/lib/python3.6/site-packages/ python-dateutil + #echo "Using pip3 to install python-dateutil for salt" + #pip3 install -t /usr/lib/python3.6/site-packages/ python-dateutil yum clean expire-cache yum -y install salt-minion-2019.2.2 yum-utils device-mapper-persistent-data lvm2 openssl yum -y update exclude=salt* @@ -1010,8 +1011,8 @@ salt_install_mysql_deps() { if [ $OS == 'centos' ]; then yum -y install mariadb-devel - echo "Using pip3 to install mysqlclient for salt" - pip3 install -t /usr/lib64/python3.6/site-packages/ mysqlclient + #echo "Using pip3 to install mysqlclient for salt" + #pip3 install -t /usr/lib64/python3.6/site-packages/ mysqlclient elif [ $OS == 'ubuntu' ]; then apt-get -y install libmysqlclient-dev echo "Using pip3 to install mysqlclient for salt" From 05ef3d54e5ea23e435ae1ffdfe883914f1d16c8d Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 18 Nov 2019 13:39:06 -0500 Subject: [PATCH 082/200] Change install time for python36-docker --- so-setup-network.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index 8618553eb..8b5e060ef 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -355,7 +355,7 @@ docker_install() { yum -y install yum-utils device-mapper-persistent-data lvm2 openssl yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo yum -y update - yum -y install docker-ce + yum -y install docker-ce python36-docker if [ $INSTALLTYPE != 'EVALMODE' ]; then docker_registry fi @@ -494,7 +494,7 @@ install_pip3() { apt-get -y install python3-pip gcc python3-dev elif [ $OS == 'centos' ]; then #yum -y install python3-pip gcc python3-devel - yum -y install epel-release python3 python36-dateutil python36-m2crypto python36-mysql python36-docker + yum -y install epel-release python3 python36-dateutil python36-m2crypto python36-mysql fi } From 525b0e2a90f9891205759e3e10ca57c177d40f79 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 18 Nov 2019 14:16:13 -0500 Subject: [PATCH 083/200] Change install time for python36-docker --- so-setup-network.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index 8b5e060ef..12029a4d3 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -494,7 +494,7 @@ install_pip3() { apt-get -y install python3-pip gcc python3-dev elif [ $OS == 'centos' ]; then #yum -y install python3-pip gcc python3-devel - yum -y install epel-release python3 python36-dateutil python36-m2crypto python36-mysql + yum -y install epel-release python3 fi } @@ -511,7 +511,7 @@ install_master() { # Install the salt master package if [ $OS == 'centos' ]; then - yum -y install wget salt-common salt-master >> $SETUPLOG 2>&1 + yum -y install wget salt-common salt-master python36-mysql python36-dateutil python36-m2crypto >> $SETUPLOG 2>&1 # Create a place for the keys for Ubuntu minions mkdir -p /opt/so/gpg From cc5565d5bc1fe95993076fe0a5736fba5e5e9359 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 18 Nov 2019 15:33:21 -0500 Subject: [PATCH 084/200] fix needs_restarting module --- salt/_modules/needs_restarting.py | 7 +++---- salt/motd/init.sls | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/salt/_modules/needs_restarting.py b/salt/_modules/needs_restarting.py index 49f82bbf2..5afb6f02a 100644 --- a/salt/_modules/needs_restarting.py +++ b/salt/_modules/needs_restarting.py @@ -4,20 +4,19 @@ import subprocess def check(): os = __grains__['os'] + retval = 'False' if os == 'Ubuntu': if path.exists('/var/run/reboot-required'): retval = 'True' - else: - retval = 'False' elif os == 'CentOS': cmd = 'needs-restarting -r > /dev/null 2>&1' + try: - needs_restarting = subprocess.check_call(cmd.split(), shell=True) + needs_restarting = subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError: retval = 'True' - retval = 'False' else: retval = 'Unsupported OS: %s' % os diff --git a/salt/motd/init.sls b/salt/motd/init.sls index a314ddb80..4dae979bf 100644 --- a/salt/motd/init.sls +++ b/salt/motd/init.sls @@ -1,5 +1,5 @@ package_update_reboot_required_motd: - file.append: + file.managed: - name: /etc/motd - source: salt://motd/files/package_update_reboot_required.jinja - template: jinja From 726251cd940b46d932f0e4e3b1939d70a375f82e Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 18 Nov 2019 16:02:48 -0500 Subject: [PATCH 085/200] changes to patch motd so nodes can be removed after they restarted - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/112 --- salt/patch/needs_restarting.sls | 4 ++++ salt/patch/os/init.sls | 9 +++------ 2 files changed, 7 insertions(+), 6 deletions(-) create mode 100644 salt/patch/needs_restarting.sls diff --git a/salt/patch/needs_restarting.sls b/salt/patch/needs_restarting.sls new file mode 100644 index 000000000..f7ba2626d --- /dev/null +++ b/salt/patch/needs_restarting.sls @@ -0,0 +1,4 @@ +needs_restarting: + module.run: + - mine.send: + - func: needs_restarting.check diff --git a/salt/patch/os/init.sls b/salt/patch/os/init.sls index 97183199b..a29bf8d12 100644 --- a/salt/patch/os/init.sls +++ b/salt/patch/os/init.sls @@ -1,5 +1,6 @@ -{% if grains.os == "CentOS" %} include: + - patch.needs_restarting +{% if grains.os == "CentOS" %} - yum.packages {% endif %} @@ -7,8 +8,4 @@ patch_os: pkg.uptodate: - name: patch_os - refresh: True - -needs_restarting: - module.run: - - mine.send: - - func: needs_restarting.check + - onchanges_in: needs_restarting From bec95f3aef89160d8c18b09d84966c4478bc8aa5 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 18 Nov 2019 16:25:06 -0500 Subject: [PATCH 086/200] apply patch.needs_restarting state to all nodes --- salt/top.sls | 1 + 1 file changed, 1 insertion(+) diff --git a/salt/top.sls b/salt/top.sls index 46745a38b..7f3d7fef4 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -6,6 +6,7 @@ {%- set PLAYBOOK = salt['pillar.get']('master:playbook', '0') -%} base: '*': + = patch.needs_restarting - patch.os.schedule - motd From 767115c218cb9c147a4d732d7168dc4979ac143e Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 18 Nov 2019 16:27:14 -0500 Subject: [PATCH 087/200] fix typo in salt top file --- salt/top.sls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/top.sls b/salt/top.sls index 7f3d7fef4..b1c64def4 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -6,7 +6,7 @@ {%- set PLAYBOOK = salt['pillar.get']('master:playbook', '0') -%} base: '*': - = patch.needs_restarting + - patch.needs_restarting - patch.os.schedule - motd From 09bf22c97a6e738672de2f7a2bbb277af700939c Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 19 Nov 2019 10:06:52 -0500 Subject: [PATCH 088/200] fix issues with updating motd if nodes needs restarted due to OS patch updates --- salt/patch/needs_restarting.sls | 1 + salt/patch/os/init.sls | 1 - salt/top.sls | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/patch/needs_restarting.sls b/salt/patch/needs_restarting.sls index f7ba2626d..f60909d22 100644 --- a/salt/patch/needs_restarting.sls +++ b/salt/patch/needs_restarting.sls @@ -2,3 +2,4 @@ needs_restarting: module.run: - mine.send: - func: needs_restarting.check + - order: last diff --git a/salt/patch/os/init.sls b/salt/patch/os/init.sls index a29bf8d12..7f2adc65b 100644 --- a/salt/patch/os/init.sls +++ b/salt/patch/os/init.sls @@ -8,4 +8,3 @@ patch_os: pkg.uptodate: - name: patch_os - refresh: True - - onchanges_in: needs_restarting diff --git a/salt/top.sls b/salt/top.sls index b1c64def4..a2662a89b 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -6,8 +6,8 @@ {%- set PLAYBOOK = salt['pillar.get']('master:playbook', '0') -%} base: '*': - - patch.needs_restarting - patch.os.schedule + - patch.needs_restarting - motd 'G@role:so-sensor': From 34460a6b07c0814ae623564a3ef7907b234c78ac Mon Sep 17 00:00:00 2001 From: Wes Lambert Date: Tue, 19 Nov 2019 16:25:10 +0000 Subject: [PATCH 089/200] add Cortex org user to setup --- so-setup-network.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/so-setup-network.sh b/so-setup-network.sh index 12029a4d3..5bf574429 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -436,6 +436,7 @@ generate_passwords(){ FLEETPASS=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) HIVEKEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) CORTEXKEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) + CORTEXORGUSERKEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) SENSORONIKEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) } @@ -604,6 +605,9 @@ master_static() { echo " cortexuser: cortexadmin" >> /opt/so/saltstack/pillar/static.sls echo " cortexpassword: cortexchangeme" >> /opt/so/saltstack/pillar/static.sls echo " cortexkey: $CORTEXKEY" >> /opt/so/saltstack/pillar/static.sls + echo " cortexorgname: SecurityOnion" >> /opt/so/saltstack/pillar/static.sls + echo " cortexorguser: soadmin" >> /opt/so/saltstack/pillar/static.sls + echo " cortexorguserkey: $CORTEXORGUSERKEY" >> /opt/so/saltstack/pillar/static.sls echo " fleetsetup: 0" >> /opt/so/saltstack/pillar/static.sls echo " sensoronikey: $SENSORONIKEY" >> /opt/so/saltstack/pillar/static.sls if [[ $MASTERUPDATES == 'MASTER' ]]; then From b7ad65a837bfaac5d31160f54c42b4bec9a33e87 Mon Sep 17 00:00:00 2001 From: Wes Lambert Date: Tue, 19 Nov 2019 16:28:05 +0000 Subject: [PATCH 090/200] add Cortex org user --- salt/hive/thehive/scripts/cortex_init.sh | 26 +++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/salt/hive/thehive/scripts/cortex_init.sh b/salt/hive/thehive/scripts/cortex_init.sh index 3596c98dd..506b14be5 100644 --- a/salt/hive/thehive/scripts/cortex_init.sh +++ b/salt/hive/thehive/scripts/cortex_init.sh @@ -3,6 +3,9 @@ {%- set CORTEXUSER = salt['pillar.get']('static:cortexuser', '') %} {%- set CORTEXPASSWORD = salt['pillar.get']('static:cortexpassword', '') %} {%- set CORTEXKEY = salt['pillar.get']('static:cortexkey', '') %} +{%- set CORTEXORGNAME = salt['pillar.get']('static:cortexorgname', '') %} +{%- set CORTEXORGUSER = salt['pillar.get']('static:cortexorguser', '') %} +{%- set CORTEXORGUSERKEY = salt['pillar.get']('static:cortexorguserkey', '') %} cortex_init(){ sleep 60 @@ -10,17 +13,34 @@ cortex_init(){ CORTEX_USER="{{CORTEXUSER}}" CORTEX_PASSWORD="{{CORTEXPASSWORD}}" CORTEX_KEY="{{CORTEXKEY}}" + CORTEX_ORG_NAME="{{CORTEXORGNAME}}" + CORTEX_ORG_DESC="{{CORTEXORGNAME}} organization created by Security Onion setup" + CORTEX_ORG_USER="{{CORTEXORGUSER}}" + CORTEX_ORG_USER_KEY="{{CORTEXORGUSERKEY}}" SOCTOPUS_CONFIG="/opt/so/saltstack/salt/soctopus/files/SOCtopus.conf" + # Migrate DB curl -v -k -XPOST "https://$CORTEX_IP:/cortex/api/maintenance/migrate" - # Create intial Cortex user + # Create intial Cortex superadmin curl -v -k "https://$CORTEX_IP/cortex/api/user" -H "Content-Type: application/json" -d "{\"login\" : \"$CORTEX_USER\",\"name\" : \"$CORTEX_USER\",\"roles\" : [\"superadmin\"],\"preferences\" : \"{}\",\"password\" : \"$CORTEX_PASSWORD\", \"key\": \"$CORTEX_KEY\"}" - # Enable URLScan.io Analyzer - curl -v -k -XPOST -H "Authorization: Bearer $CORTEX_KEY" -H "Content-Type: application/json" "https://$CORTEX_IP/cortex/api/organization/analyzer/Urlscan_io_Search_0_1_0" -d '{"name":"Urlscan_io_Search_0_1_0","configuration":{"auto_extract_artifacts":false,"check_tlp":true,"max_tlp":2}}' + # Create user-supplied org + curl -k -XPOST -H "Authorization: Bearer $CORTEX_KEY" -H "Content-Type: application/json" "https://$CORTEX_IP/cortex/api/organization" -d "{ \"name\": \"$CORTEX_ORG_NAME\",\"description\": \"$CORTEX_ORG_DESC\",\"status\": \"Active\"}" + # Create user-supplied org user + curl -k -XPOST -H "Authorization: Bearer $CORTEX_KEY" -H "Content-Type: application/json" "https://$CORTEX_IP/cortex/api/user" -d "{\"name\": \"$CORTEX_ORG_USER\",\"roles\": [\"read\",\"analyze\",\"orgadmin\"],\"organization\": \"$CORTEX_ORG_NAME\",\"login\": \"$CORTEX_ORG_USER\",\"key\": \"$CORTEX_ORG_USER_KEY\" }" + + # Enable URLScan.io Analyzer + curl -v -k -XPOST -H "Authorization: Bearer $CORTEX_ORG_USER_KEY" -H "Content-Type: application/json" "https://$CORTEX_IP/cortex/api/organization/analyzer/Urlscan_io_Search_0_1_0" -d '{"name":"Urlscan_io_Search_0_1_0","configuration":{"auto_extract_artifacts":false,"check_tlp":true,"max_tlp":2}}' + + # Enable Cert PassiveDNS Analyzer + curl -v -k -XPOST -H "Authorization: Bearer $CORTEX_ORG_USER_KEY" -H "Content-Type: application/json" "https://$CORTEX_IP/cortex/api/organization/analyzer/CERTatPassiveDNS_2_0" -d '{"name":"CERTatPassiveDNS_2_0","configuration":{"auto_extract_artifacts":false,"check_tlp":true,"max_tlp":2, "limit": 100}}' + + # Revoke $CORTEX_USER key + curl -k -XDELETE -H "Authorization: Bearer $CORTEX_KEY" "https:///$CORTEX_IP/api/user/$CORTEX_USER/key" + # Update SOCtopus config with apikey value #sed -i "s/cortex_key = .*/cortex_key = $CORTEX_KEY/" $SOCTOPUS_CONFIG From 76cdc02305abb43c8709af760723a5a29cda1c95 Mon Sep 17 00:00:00 2001 From: Wes Lambert Date: Tue, 19 Nov 2019 16:28:42 +0000 Subject: [PATCH 091/200] user Cortex org user instead --- salt/hive/thehive/etc/application.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/hive/thehive/etc/application.conf b/salt/hive/thehive/etc/application.conf index 6cc72813e..3b6c89637 100644 --- a/salt/hive/thehive/etc/application.conf +++ b/salt/hive/thehive/etc/application.conf @@ -1,5 +1,5 @@ {%- set MASTERIP = salt['pillar.get']('static:masterip', '') %} -{%- set CORTEXKEY = salt['pillar.get']('static:cortexkey', '') %} +{%- set CORTEXKEY = salt['pillar.get']('static:cortexorguserkey', '') %} # Secret Key # The secret key is used to secure cryptographic functions. From e895d8509b58bd3df3164e19f36e0ed3a732d409 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Tue, 19 Nov 2019 14:06:12 -0500 Subject: [PATCH 092/200] append /fleet to osquery client config --- salt/fleet/so-fleet-setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/fleet/so-fleet-setup.sh b/salt/fleet/so-fleet-setup.sh index 5f6dcb949..c20e5a0fc 100644 --- a/salt/fleet/so-fleet-setup.sh +++ b/salt/fleet/so-fleet-setup.sh @@ -29,7 +29,7 @@ docker run \ --rm \ --mount type=bind,source=/opt/so/conf/fleet/packages,target=/output \ --mount type=bind,source=/etc/pki/launcher.crt,target=/var/launcher/launcher.crt \ - docker.io/soshybridhunter/so-fleet-launcher:HH1.1.0 "$esecret" "$1":8080 + docker.io/soshybridhunter/so-fleet-launcher:HH1.1.0 "$esecret" "$1":8080/fleet cp /opt/so/conf/fleet/packages/launcher.* /opt/so/saltstack/salt/launcher/packages/ #Update timestamp on packages webpage From 118f4e34f20230bd0cdb24db4a1a2282941b5d01 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Tue, 19 Nov 2019 14:33:51 -0500 Subject: [PATCH 093/200] Update nginx.conf.so-eval --- salt/common/nginx/nginx.conf.so-eval | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/salt/common/nginx/nginx.conf.so-eval b/salt/common/nginx/nginx.conf.so-eval index fe55dc274..41f455216 100644 --- a/salt/common/nginx/nginx.conf.so-eval +++ b/salt/common/nginx/nginx.conf.so-eval @@ -152,10 +152,7 @@ http { } location /fleet/ { - auth_basic "Security Onion"; - auth_basic_user_file /opt/so/conf/nginx/.htpasswd; - rewrite /fleet/(.*) /$1 break; - proxy_pass https://{{ masterip }}:8080/; + proxy_pass https://{{ masterip }}:8080/fleet/; proxy_read_timeout 90; proxy_connect_timeout 90; proxy_set_header Host $host; From cc98e45f736d574161aa6fc3383641955f48209e Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 19 Nov 2019 14:52:29 -0500 Subject: [PATCH 094/200] Move and simplify dependencies for Centos --- so-setup-network.sh | 85 +++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 54 deletions(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index 12029a4d3..c68a39fca 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -55,10 +55,6 @@ add_master_hostfile() { MSRVIP=$(whiptail --title "Security Onion Setup" --inputbox \ "Enter your Master Server IP Address" 10 60 X.X.X.X 3>&1 1>&2 2>&3) - # Add the master to the host file if it doesn't resolve - #if ! grep -q $MSRVIP /etc/hosts; then - # echo "$MSRVIP $MSRV" >> /etc/hosts - #fi } add_socore_user_master() { @@ -77,21 +73,6 @@ add_socore_user_master() { } -#add_socore_user_master() { -# echo "Add socore on the master" >> $SETUPLOG 2>&1 -# if [ $OS == 'centos' ]; then -# local ADDUSER=adduser -# else -# local ADDUSER=useradd -# fi -# # Add user "socore" to the master. This will be for things like accepting keys. -# groupadd --gid 939 socore -# $ADDUSER --uid 939 --gid 939 --home-dir /opt/so socore -# # Prompt the user to set a password for the user -# passwd socore - -#} - add_socore_user_notmaster() { echo "Add socore user on non master" >> $SETUPLOG 2>&1 # Add socore user to the non master system. Probably not a bad idea to make system user @@ -359,8 +340,6 @@ docker_install() { if [ $INSTALLTYPE != 'EVALMODE' ]; then docker_registry fi - #echo "Using pip3 to install docker-py for salt" - #pip3 install -t /usr/lib/python3.6/site-packages/ docker echo "Restarting Docker" >> $SETUPLOG 2>&1 systemctl restart docker systemctl enable docker @@ -486,14 +465,13 @@ install_cleanup() { } -install_pip3() { +install_python3() { - echo "Installing pip3" + echo "Installing Python3" if [ $OS == 'ubuntu' ]; then apt-get -y install python3-pip gcc python3-dev elif [ $OS == 'centos' ]; then - #yum -y install python3-pip gcc python3-devel yum -y install epel-release python3 fi @@ -511,13 +489,13 @@ install_master() { # Install the salt master package if [ $OS == 'centos' ]; then - yum -y install wget salt-common salt-master python36-mysql python36-dateutil python36-m2crypto >> $SETUPLOG 2>&1 - + #yum -y install wget salt-common salt-master python36-mysql python36-dateutil python36-m2crypto >> $SETUPLOG 2>&1 + echo "" # Create a place for the keys for Ubuntu minions - mkdir -p /opt/so/gpg - wget --inet4-only -O /opt/so/gpg/SALTSTACK-GPG-KEY.pub https://repo.saltstack.com/apt/ubuntu/16.04/amd64/latest/SALTSTACK-GPG-KEY.pub - wget --inet4-only -O /opt/so/gpg/docker.pub https://download.docker.com/linux/ubuntu/gpg - wget --inet4-only -O /opt/so/gpg/GPG-KEY-WAZUH https://packages.wazuh.com/key/GPG-KEY-WAZUH + #mkdir -p /opt/so/gpg + #wget --inet4-only -O /opt/so/gpg/SALTSTACK-GPG-KEY.pub https://repo.saltstack.com/apt/ubuntu/16.04/amd64/latest/SALTSTACK-GPG-KEY.pub + #wget --inet4-only -O /opt/so/gpg/docker.pub https://download.docker.com/linux/ubuntu/gpg + #wget --inet4-only -O /opt/so/gpg/GPG-KEY-WAZUH https://packages.wazuh.com/key/GPG-KEY-WAZUH else apt-get install -y salt-common=2019.2.2+ds-1 salt-master=2019.2.2+ds-1 salt-minion=2019.2.2+ds-1 @@ -720,9 +698,14 @@ saltify() { ADDUSER=adduser if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then - yum -y install https://repo.saltstack.com/py3/redhat/salt-py3-repo-latest-2.el7.noarch.rpm + yum -y install wget https://repo.saltstack.com/py3/redhat/salt-py3-repo-latest-2.el7.noarch.rpm cp /etc/yum.repos.d/salt-latest.repo /etc/yum.repos.d/salt-2019-2.repo sed -i 's/latest/2019.2/g' /etc/yum.repos.d/salt-2019-2.repo + # Download Ubuntu Keys in case master updates = 1 + mkdir -p /opt/so/gpg + wget --inet4-only -O /opt/so/gpg/SALTSTACK-GPG-KEY.pub https://repo.saltstack.com/apt/ubuntu/16.04/amd64/latest/SALTSTACK-GPG-KEY.pub + wget --inet4-only -O /opt/so/gpg/docker.pub https://download.docker.com/linux/ubuntu/gpg + wget --inet4-only -O /opt/so/gpg/GPG-KEY-WAZUH https://packages.wazuh.com/key/GPG-KEY-WAZUH cat > /etc/yum.repos.d/wazuh.repo <<\EOF [wazuh_repo] gpgcheck=1 @@ -869,19 +852,16 @@ EOF fi fi - #echo "Using pip3 to install python-dateutil for salt" - #pip3 install -t /usr/lib/python3.6/site-packages/ python-dateutil yum clean expire-cache - yum -y install salt-minion-2019.2.2 yum-utils device-mapper-persistent-data lvm2 openssl + yum -y install epel-release salt-minion-2019.2.2 yum-utils device-mapper-persistent-data lvm2 openssl yum -y update exclude=salt* systemctl enable salt-minion - # Nasty hack but required for now if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then - yum -y install salt-master-2019.2.2 python-m2crypto salt-minion-2019.2.2 m2crypto + yum -y install salt-master-2019.2.2 python3 python36-m2crypto salt-minion-2019.2.2 python36-dateutil python36-mysql python36-docker systemctl enable salt-master else - yum -y install salt-minion-2019.2.2 python-m2m2crypto m2crypto + yum -y install salt-minion-2019.2.2 python3 python36-m2crypto python36-dateutil python36-docker fi echo "exclude=salt*" >> /etc/yum.conf @@ -898,8 +878,8 @@ EOF # Nasty hack but required for now if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then - echo "Using pip3 to install python-dateutil for salt" - pip3 install python-dateutil + #echo "Using pip3 to install python-dateutil for salt" + #pip3 install python-dateutil # Install the repo for salt wget --inet4-only -O - https://repo.saltstack.com/apt/ubuntu/$UVER/amd64/latest/SALTSTACK-GPG-KEY.pub | apt-key add - wget --inet4-only -O - https://repo.saltstack.com/apt/ubuntu/$UVER/amd64/2019.2/SALTSTACK-GPG-KEY.pub | apt-key add - @@ -923,7 +903,8 @@ EOF # Initialize the new repos apt-get update >> $SETUPLOG 2>&1 - apt-get -y install salt-minion=2019.2.2+ds-1 salt-common=2019.2.2+ds-1 >> $SETUPLOG 2>&1 + # Need to add python packages here + apt-get -y install salt-minion=2019.2.2+ds-1 salt-common=2019.2.2+ds-1 python3-dateutil >> $SETUPLOG 2>&1 apt-mark hold salt-minion salt-common else @@ -937,6 +918,7 @@ EOF echo "deb https://packages.wazuh.com/3.x/apt/ stable main" | tee /etc/apt/sources.list.d/wazuh.list # Initialize the new repos apt-get update >> $SETUPLOG 2>&1 + # Need to add python dateutil here apt-get -y install salt-minion=2019.2.2+ds-1 salt-common=2019.2.2+ds-1 >> $SETUPLOG 2>&1 apt-mark hold salt-minion salt-common @@ -1011,12 +993,8 @@ salt_install_mysql_deps() { if [ $OS == 'centos' ]; then yum -y install mariadb-devel - #echo "Using pip3 to install mysqlclient for salt" - #pip3 install -t /usr/lib64/python3.6/site-packages/ mysqlclient elif [ $OS == 'ubuntu' ]; then - apt-get -y install libmysqlclient-dev - echo "Using pip3 to install mysqlclient for salt" - pip3 install mysqlclient + apt-get -y install libmysqlclient-dev python3-mysqldb fi } @@ -1925,11 +1903,10 @@ if (whiptail_you_sure); then # Install salt and dependencies { sleep 0.5 - install_pip3 >> $SETUPLOG 2>&1 - echo -e "XXX\n1\nInstalling mysql dependencies for saltstack... \nXXX" - salt_install_mysql_deps >> $SETUPLOG 2>&1 - echo -e "XXX\n2\nInstalling and configuring Salt... \nXXX" + #install_pip3 >> $SETUPLOG 2>&1 + echo -e "XXX\n1\nInstalling and configuring Salt... \nXXX" echo " ** Installing Salt and Dependencies **" >> $SETUPLOG + salt_install_mysql_deps >> $SETUPLOG 2>&1 saltify >> $SETUPLOG 2>&1 echo -e "XXX\n5\nInstalling Docker... \nXXX" docker_install >> $SETUPLOG 2>&1 @@ -2062,8 +2039,8 @@ if (whiptail_you_sure); then sleep 0.5 echo -e "XXX\n0\nSetting Initial Firewall Policy... \nXXX" set_initial_firewall_policy >> $SETUPLOG 2>&1 - echo -e "XXX\n1\nInstalling pip3... \nXXX" - install_pip3 >> $SETUPLOG 2>&1 + #echo -e "XXX\n1\nInstalling pip3... \nXXX" + #install_pip3 >> $SETUPLOG 2>&1 echo -e "XXX\n3\nCreating Bond Interface... \nXXX" network_setup >> $SETUPLOG 2>&1 echo -e "XXX\n4\nGenerating Sensor Pillar... \nXXX" @@ -2164,7 +2141,7 @@ if (whiptail_you_sure); then sleep 0.5 echo -e "XXX\n0\nCreating Bond Interface... \nXXX" network_setup >> $SETUPLOG 2>&1 - install_pip3 >> $SETUPLOG 2>&1 + #install_pip3 >> $SETUPLOG 2>&1 echo -e "XXX\n1\nInstalling mysql dependencies for saltstack... \nXXX" salt_install_mysql_deps >> $SETUPLOG 2>&1 echo -e "XXX\n1\nInstalling saltstack... \nXXX" @@ -2329,8 +2306,8 @@ if (whiptail_you_sure); then sleep 0.5 echo -e "XXX\n0\nSetting Initial Firewall Policy... \nXXX" set_initial_firewall_policy >> $SETUPLOG 2>&1 - echo -e "XXX\n1\nInstalling pip3... \nXXX" - install_pip3 >> $SETUPLOG 2>&1 + #echo -e "XXX\n1\nInstalling pip3... \nXXX" + #install_pip3 >> $SETUPLOG 2>&1 echo -e "XXX\n5\nInstalling Salt Packages... \nXXX" saltify >> $SETUPLOG 2>&1 echo -e "XXX\n20\nInstalling Docker... \nXXX" From 7373473b3f2719ba5c7acfc051dbf32f4f06ab5b Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Tue, 19 Nov 2019 15:02:35 -0500 Subject: [PATCH 095/200] Fix dup events --- .../files/dynamic/0006_input_beats.conf | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/salt/logstash/files/dynamic/0006_input_beats.conf b/salt/logstash/files/dynamic/0006_input_beats.conf index 1a6b66bbe..a7140f859 100644 --- a/salt/logstash/files/dynamic/0006_input_beats.conf +++ b/salt/logstash/files/dynamic/0006_input_beats.conf @@ -9,23 +9,6 @@ input { } } filter { - if [type] == "ids" or [type] =~ "bro" { - mutate { - rename => { "host" => "beat_host" } - remove_tag => ["beat"] - add_field => { "sensor_name" => "%{[beat][name]}" } - add_field => { "syslog-host_from" => "%{[beat][name]}" } - remove_field => [ "beat", "prospector", "input", "offset" ] - } - } - if [type] =~ "ossec" { - mutate { - rename => { "host" => "beat_host" } - remove_tag => ["beat"] - add_field => { "syslog-host_from" => "%{[beat][name]}" } - remove_field => [ "beat", "prospector", "input", "offset" ] - } - } if [type] == "osquery" { mutate { rename => { "host" => "beat_host" } From 6153c25c37127611b28ebfa4c4988d18313b345f Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 19 Nov 2019 15:34:27 -0500 Subject: [PATCH 096/200] update mine via mine_interval now vs applying a state --- pillar/patch/needs_restarting.sls | 2 ++ pillar/top.sls | 3 +++ salt/patch/os/init.sls | 2 +- salt/top.sls | 1 - 4 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 pillar/patch/needs_restarting.sls diff --git a/pillar/patch/needs_restarting.sls b/pillar/patch/needs_restarting.sls new file mode 100644 index 000000000..f77dd2269 --- /dev/null +++ b/pillar/patch/needs_restarting.sls @@ -0,0 +1,2 @@ +mine_functions: + needs_restarting.check: [] diff --git a/pillar/top.sls b/pillar/top.sls index 031352a11..ffa99de59 100644 --- a/pillar/top.sls +++ b/pillar/top.sls @@ -1,4 +1,7 @@ base: + '*': + - patch.needs_restarting + 'G@role:so-sensor': - sensors.{{ grains.id }} - static diff --git a/salt/patch/os/init.sls b/salt/patch/os/init.sls index 7f2adc65b..ade35294a 100644 --- a/salt/patch/os/init.sls +++ b/salt/patch/os/init.sls @@ -1,8 +1,8 @@ include: - - patch.needs_restarting {% if grains.os == "CentOS" %} - yum.packages {% endif %} + - patch.needs_restarting patch_os: pkg.uptodate: diff --git a/salt/top.sls b/salt/top.sls index a2662a89b..46745a38b 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -7,7 +7,6 @@ base: '*': - patch.os.schedule - - patch.needs_restarting - motd 'G@role:so-sensor': From 21a29d7274294d67a8c6e5a092a2771fdc49aec5 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Wed, 20 Nov 2019 10:36:32 -0500 Subject: [PATCH 097/200] Initial Setup overhaul testing --- .../registry/scripts/so-docker-download.sh | 48 + setup/functions.sh | 1125 +++++++++++++++++ setup/so-setup.sh | 627 +++++++++ setup/whiplash.sh | 611 +++++++++ 4 files changed, 2411 insertions(+) create mode 100644 salt/master/files/registry/scripts/so-docker-download.sh create mode 100644 setup/functions.sh create mode 100644 setup/so-setup.sh create mode 100644 setup/whiplash.sh diff --git a/salt/master/files/registry/scripts/so-docker-download.sh b/salt/master/files/registry/scripts/so-docker-download.sh new file mode 100644 index 000000000..33b5065ae --- /dev/null +++ b/salt/master/files/registry/scripts/so-docker-download.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +MASTER={{ MASTER }} +VERSION="HH1.1.3" +TRUSTED_CONTAINERS=( \ +"so-core:$VERSION" \ +"so-cyberchef:$VERSION" \ +"so-acng:$VERSION" \ +"so-sensoroni:$VERSION" \ +"so-fleet:$VERSION" \ +"so-soctopus:$VERSION" \ +"so-steno:$VERSION" \ +"so-playbook:$VERSION" \ +"so-thehive-cortex:$VERSION" \ +"so-thehive:$VERSION" \ +"so-thehive-es:$VERSION" \ +"so-wazuh:$VERSION" \ +"so-kibana:$VERSION" \ +"so-auth-ui:$VERSION" \ +"so-auth-api:$VERSION" \ +"so-elastalert:$VERSION" \ +"so-navigator:$VERSION" \ +"so-filebeat:$VERSION" \ +"so-suricata:$VERSION" \ +"so-logstash:$VERSION" \ +"so-bro:$VERSION" \ +"so-idstools:$VERSION" \ +"so-fleet-launcher:$VERSION" \ +"so-freqserver:$VERSION" \ +"so-influxdb:$VERSION" \ +"so-grafana:$VERSION" \ +"so-telegraf:$VERSION" \ +"so-redis:$VERSION" \ +"so-mysql:$VERSION" \ +"so-curtor:$VERSION" \ +"so-elasticsearch:$VERSION" \ +"so-domainstats:$VERSION" \ +"so-tcpreplay:$VERSION" \ +) + +for i in "${TRUSTED_CONTAINERS[@]}" +do + # Pull down the trusted docker image + docker pull --disable-content-trust=false docker.io/soshybridhunter/$i + # Tag it with the new registry destination + docker tag soshybridhunter/$i $MASTER:5000/soshybridhunter/$i + docker push $MASTER:5000/soshybridhunter/$i +done diff --git a/setup/functions.sh b/setup/functions.sh new file mode 100644 index 000000000..184750d61 --- /dev/null +++ b/setup/functions.sh @@ -0,0 +1,1125 @@ +# Functions + +accept_salt_key_local() { + echo "Accept the key locally on the master" >> $SETUPLOG 2>&1 + # Accept the key locally on the master + salt-key -ya $MINION_ID + +} + +accept_salt_key_remote() { + echo "Accept the key remotely on the master" >> $SETUPLOG 2>&1 + # Delete the key just in case. + ssh -i /root/.ssh/so.key socore@$MSRV sudo salt-key -d $MINION_ID -y + salt-call state.apply ca + ssh -i /root/.ssh/so.key socore@$MSRV sudo salt-key -a $MINION_ID -y + +} + +add_master_hostfile() { + echo "Checking if I can resolve master. If not add to hosts file" >> $SETUPLOG 2>&1 + # Pop up an input to get the IP address + MSRVIP=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter your Master Server IP Address" 10 60 X.X.X.X 3>&1 1>&2 2>&3) + +} + +add_socore_user_master() { + + echo "Add socore on the master" >>~/sosetup.log 2>&1 + # Add user "socore" to the master. This will be for things like accepting keys. + if [ $OS == 'centos' ]; then + local ADDUSER=adduser + else + local ADDUSER=useradd + fi + groupadd --gid 939 socore + $ADDUSER --uid 939 --gid 939 --home-dir /opt/so socore + # Set the password for socore that we got during setup + echo socore:$COREPASS1 | chpasswd --crypt-method=SHA512 + +} + +add_socore_user_notmaster() { + echo "Add socore user on non master" >> $SETUPLOG 2>&1 + # Add socore user to the non master system. Probably not a bad idea to make system user + groupadd --gid 939 socore + $ADDUSER --uid 939 --gid 939 --home-dir /opt/so --no-create-home socore + +} + +# Create an auth pillar so that passwords survive re-install +auth_pillar(){ + + if [ ! -f /opt/so/saltstack/pillar/auth.sls ]; then + echo "Creating Auth Pillar" >> $SETUPLOG 2>&1 + mkdir -p /opt/so/saltstack/pillar + echo "auth:" >> /opt/so/saltstack/pillar/auth.sls + echo " mysql: $MYSQLPASS" >> /opt/so/saltstack/pillar/auth.sls + echo " fleet: $FLEETPASS" >> /opt/so/saltstack/pillar/auth.sls + fi + +} + +# Enable Bro Logs +bro_logs_enabled() { + echo "Enabling Bro Logs" >> $SETUPLOG 2>&1 + + echo "brologs:" > pillar/brologs.sls + echo " enabled:" >> pillar/brologs.sls + + if [ $MASTERADV == 'ADVANCED' ]; then + for BLOG in ${BLOGS[@]}; do + echo " - $BLOG" | tr -d '"' >> pillar/brologs.sls + done + else + echo " - conn" >> pillar/brologs.sls + echo " - dce_rpc" >> pillar/brologs.sls + echo " - dhcp" >> pillar/brologs.sls + echo " - dhcpv6" >> pillar/brologs.sls + echo " - dnp3" >> pillar/brologs.sls + echo " - dns" >> pillar/brologs.sls + echo " - dpd" >> pillar/brologs.sls + echo " - files" >> pillar/brologs.sls + echo " - ftp" >> pillar/brologs.sls + echo " - http" >> pillar/brologs.sls + echo " - intel" >> pillar/brologs.sls + echo " - irc" >> pillar/brologs.sls + echo " - kerberos" >> pillar/brologs.sls + echo " - modbus" >> pillar/brologs.sls + echo " - mqtt" >> pillar/brologs.sls + echo " - notice" >> pillar/brologs.sls + echo " - ntlm" >> pillar/brologs.sls + echo " - openvpn" >> pillar/brologs.sls + echo " - pe" >> pillar/brologs.sls + echo " - radius" >> pillar/brologs.sls + echo " - rfb" >> pillar/brologs.sls + echo " - rdp" >> pillar/brologs.sls + echo " - signatures" >> pillar/brologs.sls + echo " - sip" >> pillar/brologs.sls + echo " - smb_files" >> pillar/brologs.sls + echo " - smb_mapping" >> pillar/brologs.sls + echo " - smtp" >> pillar/brologs.sls + echo " - snmp" >> pillar/brologs.sls + echo " - software" >> pillar/brologs.sls + echo " - ssh" >> pillar/brologs.sls + echo " - ssl" >> pillar/brologs.sls + echo " - syslog" >> pillar/brologs.sls + echo " - telnet" >> pillar/brologs.sls + echo " - tunnel" >> pillar/brologs.sls + echo " - weird" >> pillar/brologs.sls + echo " - mysql" >> pillar/brologs.sls + echo " - socks" >> pillar/brologs.sls + echo " - x509" >> pillar/brologs.sls + fi +} + +calculate_useable_cores() { + + # Calculate reasonable core usage + local CORES4BRO=$(( $CPUCORES/2 - 1 )) + LBPROCSROUND=$(printf "%.0f\n" $CORES4BRO) + # We don't want it to be 0 + if [ "$LBPROCSROUND" -lt 1 ]; then + LBPROCS=1 + else + LBPROCS=$LBPROCSROUND + fi + +} + +checkin_at_boot() { + echo "Enabling checkin at boot" >> $SETUPLOG 2>&1 + echo "startup_states: highstate" >> /etc/salt/minion +} + +check_hive_init_then_reboot() { + WAIT_STEP=0 + MAX_WAIT=100 + until [ -f /opt/so/state/thehive.txt ] ; do + WAIT_STEP=$(( ${WAIT_STEP} + 1 )) + echo "Waiting on the_hive to init...Attempt #$WAIT_STEP" + if [ ${WAIT_STEP} -gt ${MAX_WAIT} ]; then + echo "ERROR: We waited ${MAX_WAIT} seconds but the_hive is not working." + exit 5 + fi + sleep 1s; + done + docker stop so-thehive + docker rm so-thehive + shutdown -r now +} + +check_socore_pass() { + + if [ $COREPASS1 == $COREPASS2 ]; then + SCMATCH=yes + else + whiptail_passwords_dont_match + fi + +} + +chown_salt_master() { + + echo "Chown the salt dirs on the master for socore" >> $SETUPLOG 2>&1 + chown -R socore:socore /opt/so + +} + +clear_master() { + # Clear out the old master public key in case this is a re-install. + # This only happens if you re-install the master. + if [ -f /etc/salt/pki/minion/minion_master.pub ]; then + echo "Clearing old master key" >> $SETUPLOG 2>&1 + rm /etc/salt/pki/minion/minion_master.pub + service salt-minion restart + fi + +} + +configure_minion() { + + # You have to pass the TYPE to this function so it knows if its a master or not + local TYPE=$1 + echo "Configuring minion type as $TYPE" >> $SETUPLOG 2>&1 + touch /etc/salt/grains + echo "role: so-$TYPE" > /etc/salt/grains + if [ $TYPE == 'master' ] || [ $TYPE == 'eval' ]; then + echo "master: $HOSTNAME" > /etc/salt/minion + echo "id: $MINION_ID" >> /etc/salt/minion + echo "mysql.host: '$MAINIP'" >> /etc/salt/minion + echo "mysql.port: 3306" >> /etc/salt/minion + echo "mysql.user: 'root'" >> /etc/salt/minion + if [ ! -f /opt/so/saltstack/pillar/auth.sls ]; then + echo "mysql.pass: '$MYSQLPASS'" >> /etc/salt/minion + else + OLDPASS=$(cat /opt/so/saltstack/pillar/auth.sls | grep mysql | awk {'print $2'}) + echo "mysql.pass: '$OLDPASS'" >> /etc/salt/minion + fi + else + echo "master: $MSRV" > /etc/salt/minion + echo "id: $MINION_ID" >> /etc/salt/minion + + fi + + echo "use_superseded:" >> /etc/salt/minion + echo " - module.run" >> /etc/salt/minion + + service salt-minion restart + +} + +copy_master_config() { + + # Copy the master config template to the proper directory + cp files/master /etc/salt/master + # Restart the service so it picks up the changes -TODO Enable service on CentOS + service salt-master restart + +} + +copy_minion_tmp_files() { + + if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then + echo "rsyncing all files in $TMP to /opt/so/saltstack" >> $SETUPLOG 2>&1 + rsync -a -v $TMP/ /opt/so/saltstack/ >> $SETUPLOG 2>&1 + else + echo "scp all files in $TMP to master /opt/so/saltstack" >> $SETUPLOG 2>&1 + scp -prv -i /root/.ssh/so.key $TMP/* socore@$MSRV:/opt/so/saltstack >> $SETUPLOG 2>&1 + fi + + } + +copy_ssh_key() { + + # Generate SSH key + mkdir -p /root/.ssh + cat /dev/zero | ssh-keygen -f /root/.ssh/so.key -t rsa -q -N "" + chown -R $SUDO_USER:$SUDO_USER /root/.ssh + #Copy the key over to the master + ssh-copy-id -f -i /root/.ssh/so.key socore@$MSRV + +} + +network_setup() { + echo "Setting up Bond" >> $SETUPLOG 2>&1 + + # Set the MTU + if [ "$NSMSETUP" != 'ADVANCED' ]; then + MTU=1500 + fi + + # Create the bond interface + nmcli con add ifname bond0 con-name "bond0" type bond mode 0 -- \ + ipv4.method disabled \ + ipv6.method link-local \ + ethernet.mtu $MTU \ + connection.autoconnect "yes" >> $SETUPLOG 2>&1 + + for BNIC in ${BNICS[@]}; do + # Strip the quotes from the NIC names + BONDNIC="$(echo -e "${BNIC}" | tr -d '"')" + # Turn off various offloading settings for the interface + for i in rx tx sg tso ufo gso gro lro; do + ethtool -K $BONDNIC $i off >> $SETUPLOG 2>&1 + done + # Create the slave interface and assign it to the bond + nmcli con add type ethernet ifname $BONDNIC con-name "bond0-slave-$BONDNIC" master bond0 -- \ + ethernet.mtu $MTU \ + connection.autoconnect "yes" >> $SETUPLOG 2>&1 + # Bring the slave interface up + nmcli con up bond0-slave-$BONDNIC >> $SETUPLOG 2>&1 + done + # Replace the variable string in the network script + sed -i "s/\$MAININT/${MAININT}/g" ./install_scripts/disable-checksum-offload.sh >> $SETUPLOG 2>&1 + # Copy the checksum offload script to prevent issues with packet capture + cp ./install_scripts/disable-checksum-offload.sh /etc/NetworkManager/dispatcher.d/disable-checksum-offload.sh >> $SETUPLOG 2>&1 +} + +detect_os() { + + # Detect Base OS + echo "Detecting Base OS" >> $SETUPLOG 2>&1 + if [ -f /etc/redhat-release ]; then + OS=centos + yum -y install bind-utils + elif [ -f /etc/os-release ]; then + OS=ubuntu + apt install -y network-manager + /bin/systemctl enable network-manager + /bin/systemctl start network-manager + else + echo "We were unable to determine if you are using a supported OS." >> $SETUPLOG 2>&1 + exit + fi + +} + +docker_install() { + + if [ $OS == 'centos' ]; then + yum clean expire-cache + yum -y install yum-utils device-mapper-persistent-data lvm2 openssl + yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo + yum -y update + yum -y install docker-ce python36-docker + if [ $INSTALLTYPE != 'EVALMODE' ]; then + docker_registry + fi + echo "Restarting Docker" >> $SETUPLOG 2>&1 + systemctl restart docker + systemctl enable docker + + else + if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then + apt-get update >> $SETUPLOG 2>&1 + apt-get -y install docker-ce >> $SETUPLOG 2>&1 + if [ $INSTALLTYPE != 'EVALMODE' ]; then + docker_registry >> $SETUPLOG 2>&1 + fi + echo "Restarting Docker" >> $SETUPLOG 2>&1 + systemctl restart docker >> $SETUPLOG 2>&1 + else + apt-key add $TMP/gpg/docker.pub >> $SETUPLOG 2>&1 + add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" >> $SETUPLOG 2>&1 + apt-get update >> $SETUPLOG 2>&1 + apt-get -y install docker-ce >> $SETUPLOG 2>&1 + docker_registry >> $SETUPLOG 2>&1 + echo "Restarting Docker" >> $SETUPLOG 2>&1 + systemctl restart docker >> $SETUPLOG 2>&1 + fi + echo "Using pip3 to install docker-py for salt" + pip3 install docker + fi + +} + +docker_registry() { + + echo "Setting up Docker Registry" >> $SETUPLOG 2>&1 + mkdir -p /etc/docker >> $SETUPLOG 2>&1 + # Make the host use the master docker registry + echo "{" > /etc/docker/daemon.json + echo " \"registry-mirrors\": [\"https://$MSRV:5000\"]" >> /etc/docker/daemon.json + echo "}" >> /etc/docker/daemon.json + echo "Docker Registry Setup - Complete" >> $SETUPLOG 2>&1 + +} + +es_heapsize() { + + # Determine ES Heap Size + if [ $TOTAL_MEM -lt 8000 ] ; then + ES_HEAP_SIZE="600m" + elif [ $TOTAL_MEM -ge 100000 ]; then + # Set a max of 25GB for heap size + # https://www.elastic.co/guide/en/elasticsearch/guide/current/heap-sizing.html + ES_HEAP_SIZE="25000m" + else + # Set heap size to 25% of available memory + ES_HEAP_SIZE=$(($TOTAL_MEM / 4))"m" + fi + +} + +eval_mode_hostsfile() { + + echo "127.0.0.1 $HOSTNAME" >> /etc/hosts + +} + +filter_nics() { + + # Filter the NICs that we don't want to see in setup + FNICS=$(ip link | grep -vw $MNIC | awk -F: '$0 !~ "lo|vir|veth|br|docker|wl|^[^0-9]"{print $2 " \"" "Interface" "\"" " OFF"}') + +} + +generate_passwords(){ + # Generate Random Passwords for Things + MYSQLPASS=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) + FLEETPASS=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) + HIVEKEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) + CORTEXKEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) + SENSORONIKEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) +} + +get_filesystem_nsm(){ + FSNSM=$(df /nsm | awk '$3 ~ /[0-9]+/ { print $2 * 1000 }') +} + +get_log_size_limit() { + + DISK_DIR="/" + if [ -d /nsm ]; then + DISK_DIR="/nsm" + fi + DISK_SIZE_K=`df $DISK_DIR |grep -v "^Filesystem" | awk '{print $2}'` + PERCENTAGE=85 + DISK_SIZE=DISK_SIZE_K*1000 + PERCENTAGE_DISK_SPACE=`echo $(($DISK_SIZE*$PERCENTAGE/100))` + LOG_SIZE_LIMIT=$(($PERCENTAGE_DISK_SPACE/1000000000)) + +} + +get_filesystem_root(){ + FSROOT=$(df / | awk '$3 ~ /[0-9]+/ { print $2 * 1000 }') +} + +get_main_ip() { + + # Get the main IP address the box is using + MAINIP=$(ip route get 1 | awk '{print $NF;exit}') + MAININT=$(ip route get 1 | awk '{print $5;exit}') + +} + +got_root() { + + # Make sure you are root + if [ "$(id -u)" -ne 0 ]; then + echo "This script must be run using sudo!" + exit 1 + fi + +} + +install_cleanup() { + + # Clean up after ourselves + rm -rf /root/installtmp + +} + +install_python3() { + + echo "Installing Python3" + + if [ $OS == 'ubuntu' ]; then + apt-get -y install python3-pip gcc python3-dev + elif [ $OS == 'centos' ]; then + yum -y install epel-release python3 + fi + +} + +install_prep() { + + # Create a tmp space that isn't in /tmp + mkdir /root/installtmp + TMP=/root/installtmp + +} + +install_master() { + + # Install the salt master package + if [ $OS == 'centos' ]; then + #yum -y install wget salt-common salt-master python36-mysql python36-dateutil python36-m2crypto >> $SETUPLOG 2>&1 + echo "" + # Create a place for the keys for Ubuntu minions + #mkdir -p /opt/so/gpg + #wget --inet4-only -O /opt/so/gpg/SALTSTACK-GPG-KEY.pub https://repo.saltstack.com/apt/ubuntu/16.04/amd64/latest/SALTSTACK-GPG-KEY.pub + #wget --inet4-only -O /opt/so/gpg/docker.pub https://download.docker.com/linux/ubuntu/gpg + #wget --inet4-only -O /opt/so/gpg/GPG-KEY-WAZUH https://packages.wazuh.com/key/GPG-KEY-WAZUH + + else + apt-get install -y salt-common=2019.2.2+ds-1 salt-master=2019.2.2+ds-1 salt-minion=2019.2.2+ds-1 + apt-mark hold salt-common salt-master salt-minion + echo -e "XXX\n11\nInstalling libssl-dev for M2Crypto... \nXXX" + apt-get -y install libssl-dev + echo -e "XXX\n12\nUsing pip3 to install M2Crypto for Salt... \nXXX" + pip3 install M2Crypto + + fi + + copy_master_config + +} + +ls_heapsize() { + + # Determine LS Heap Size + if [ $TOTAL_MEM -ge 32000 ] ; then + LS_HEAP_SIZE="1000m" + else + # If minimal RAM, then set minimal heap + LS_HEAP_SIZE="500m" + fi + +} + +master_pillar() { + + # Create the master pillar + touch /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo "master:" > /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " mainip: $MAINIP" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " mainint: $MAININT" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " esheap: $ES_HEAP_SIZE" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " esclustername: {{ grains.host }}" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + if [ $INSTALLTYPE == 'EVALMODE' ]; then + echo " freq: 0" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " domainstats: 0" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " ls_pipeline_batch_size: 125" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " ls_input_threads: 1" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " ls_batch_count: 125" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " mtu: 1500" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + + else + echo " freq: 0" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " domainstats: 0" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + fi + echo " lsheap: $LS_HEAP_SIZE" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " lsaccessip: 127.0.0.1" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " elastalert: 1" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " ls_pipeline_workers: $CPUCORES" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " nids_rules: $RULESETUP" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " oinkcode: $OINKCODE" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + #echo " access_key: $ACCESS_KEY" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + #echo " access_secret: $ACCESS_SECRET" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " es_port: $NODE_ES_PORT" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " log_size_limit: $LOG_SIZE_LIMIT" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " cur_close_days: $CURCLOSEDAYS" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + #echo " mysqlpass: $MYSQLPASS" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + #echo " fleetpass: $FLEETPASS" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " grafana: $GRAFANA" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " osquery: $OSQUERY" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " wazuh: $WAZUH" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " thehive: $THEHIVE" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + echo " playbook: $PLAYBOOK" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + } + +master_static() { + + # Create a static file for global values + touch /opt/so/saltstack/pillar/static.sls + + echo "static:" > /opt/so/saltstack/pillar/static.sls + echo " hnmaster: $HNMASTER" >> /opt/so/saltstack/pillar/static.sls + echo " ntpserver: $NTPSERVER" >> /opt/so/saltstack/pillar/static.sls + echo " proxy: $PROXY" >> /opt/so/saltstack/pillar/static.sls + echo " broversion: $BROVERSION" >> /opt/so/saltstack/pillar/static.sls + echo " ids: $NIDS" >> /opt/so/saltstack/pillar/static.sls + echo " masterip: $MAINIP" >> /opt/so/saltstack/pillar/static.sls + echo " hiveuser: hiveadmin" >> /opt/so/saltstack/pillar/static.sls + echo " hivepassword: hivechangeme" >> /opt/so/saltstack/pillar/static.sls + echo " hivekey: $HIVEKEY" >> /opt/so/saltstack/pillar/static.sls + echo " cortexuser: cortexadmin" >> /opt/so/saltstack/pillar/static.sls + echo " cortexpassword: cortexchangeme" >> /opt/so/saltstack/pillar/static.sls + echo " cortexkey: $CORTEXKEY" >> /opt/so/saltstack/pillar/static.sls + echo " fleetsetup: 0" >> /opt/so/saltstack/pillar/static.sls + echo " sensoronikey: $SENSORONIKEY" >> /opt/so/saltstack/pillar/static.sls + if [[ $MASTERUPDATES == 'MASTER' ]]; then + echo " masterupdate: 1" >> /opt/so/saltstack/pillar/static.sls + else + echo " masterupdate: 0" >> /opt/so/saltstack/pillar/static.sls + fi +} + +minio_generate_keys() { + + local charSet="[:graph:]" + + ACCESS_KEY=$(cat /dev/urandom | tr -cd "$charSet" | tr -d \' | tr -d \" | head -c 20) + ACCESS_SECRET=$(cat /dev/urandom | tr -cd "$charSet" | tr -d \' | tr -d \" | head -c 40) + +} + +node_pillar() { + + NODEPILLARPATH=$TMP/pillar/nodes + if [ ! -d $NODEPILLARPATH ]; then + mkdir -p $NODEPILLARPATH + fi + + # Create the node pillar + touch $NODEPILLARPATH/$MINION_ID.sls + echo "node:" > $NODEPILLARPATH/$MINION_ID.sls + echo " mainip: $MAINIP" >> $NODEPILLARPATH/$MINION_ID.sls + echo " mainint: $MAININT" >> $NODEPILLARPATH/$MINION_ID.sls + echo " esheap: $NODE_ES_HEAP_SIZE" >> $NODEPILLARPATH/$MINION_ID.sls + echo " esclustername: {{ grains.host }}" >> $NODEPILLARPATH/$MINION_ID.sls + echo " lsheap: $NODE_LS_HEAP_SIZE" >> $NODEPILLARPATH/$MINION_ID.sls + echo " ls_pipeline_workers: $LSPIPELINEWORKERS" >> $NODEPILLARPATH/$MINION_ID.sls + echo " ls_pipeline_batch_size: $LSPIPELINEBATCH" >> $NODEPILLARPATH/$MINION_ID.sls + echo " ls_input_threads: $LSINPUTTHREADS" >> $NODEPILLARPATH/$MINION_ID.sls + echo " ls_batch_count: $LSINPUTBATCHCOUNT" >> $NODEPILLARPATH/$MINION_ID.sls + echo " es_shard_count: $SHARDCOUNT" >> $NODEPILLARPATH/$MINION_ID.sls + echo " node_type: $NODETYPE" >> $NODEPILLARPATH/$MINION_ID.sls + echo " es_port: $NODE_ES_PORT" >> $NODEPILLARPATH/$MINION_ID.sls + echo " log_size_limit: $LOG_SIZE_LIMIT" >> $NODEPILLARPATH/$MINION_ID.sls + echo " cur_close_days: $CURCLOSEDAYS" >> $NODEPILLARPATH/$MINION_ID.sls + +} + +patch_pillar() { + + case $INSTALLTYPE in + MASTERONLY | EVALMODE) + PATCHPILLARPATH=/opt/so/saltstack/pillar/masters + ;; + SENSORONLY) + PATCHPILLARPATH=$SENSORPILLARPATH + ;; + STORAGENODE | PARSINGNODE | HOTNODE | WARMNODE) + PATCHPILLARPATH=$NODEPILLARPATH + ;; + esac + + + echo "" >> $PATCHPILLARPATH/$MINION_ID.sls + echo "patch:" >> $PATCHPILLARPATH/$MINION_ID.sls + echo " os:" >> $PATCHPILLARPATH/$MINION_ID.sls + echo " schedule_name: $PATCHSCHEDULENAME" >> $PATCHPILLARPATH/$MINION_ID.sls + echo " enabled: True" >> $PATCHPILLARPATH/$MINION_ID.sls + echo " splay: 300" >> $PATCHPILLARPATH/$MINION_ID.sls + + +} + +patch_schedule_os_new() { + OSPATCHSCHEDULEDIR="$TMP/salt/patch/os/schedules" + OSPATCHSCHEDULE="$OSPATCHSCHEDULEDIR/$PATCHSCHEDULENAME.yml" + + if [ ! -d $OSPATCHSCHEDULEDIR ] ; then + mkdir -p $OSPATCHSCHEDULEDIR + fi + + echo "patch:" > $OSPATCHSCHEDULE + echo " os:" >> $OSPATCHSCHEDULE + echo " schedule:" >> $OSPATCHSCHEDULE + for psd in "${PATCHSCHEDULEDAYS[@]}" + do + psd=$(echo $psd | sed 's/"//g') + echo " - $psd:" >> $OSPATCHSCHEDULE + for psh in "${PATCHSCHEDULEHOURS[@]}" + do + psh=$(echo $psh | sed 's/"//g') + echo " - '$psh'" >> $OSPATCHSCHEDULE + done + done + +} + +process_components() { + CLEAN=${COMPONENTS//\"} + GRAFANA=0 + OSQUERY=0 + WAZUH=0 + THEHIVE=0 + PLAYBOOK=0 + + IFS=$' ' + for item in $(echo "$CLEAN"); do + let $item=1 + done + unset IFS +} + +saltify() { + + # Install updates and Salt + if [ $OS == 'centos' ]; then + ADDUSER=adduser + + if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then + yum -y install wget https://repo.saltstack.com/py3/redhat/salt-py3-repo-latest-2.el7.noarch.rpm + cp /etc/yum.repos.d/salt-latest.repo /etc/yum.repos.d/salt-2019-2.repo + sed -i 's/latest/2019.2/g' /etc/yum.repos.d/salt-2019-2.repo + # Download Ubuntu Keys in case master updates = 1 + mkdir -p /opt/so/gpg + wget --inet4-only -O /opt/so/gpg/SALTSTACK-GPG-KEY.pub https://repo.saltstack.com/apt/ubuntu/16.04/amd64/latest/SALTSTACK-GPG-KEY.pub + wget --inet4-only -O /opt/so/gpg/docker.pub https://download.docker.com/linux/ubuntu/gpg + wget --inet4-only -O /opt/so/gpg/GPG-KEY-WAZUH https://packages.wazuh.com/key/GPG-KEY-WAZUH + cat > /etc/yum.repos.d/wazuh.repo <<\EOF +[wazuh_repo] +gpgcheck=1 +gpgkey=https://packages.wazuh.com/key/GPG-KEY-WAZUH +enabled=1 +name=Wazuh repository +baseurl=https://packages.wazuh.com/3.x/yum/ +protect=1 +EOF + + else + + if [ $MASTERUPDATES == 'MASTER' ]; then + + # Create the GPG Public Key for the Salt Repo + echo "-----BEGIN PGP PUBLIC KEY BLOCK-----" > /etc/pki/rpm-gpg/saltstack-signing-key + echo "Version: GnuPG v2.0.22 (GNU/Linux)" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "mQENBFOpvpgBCADkP656H41i8fpplEEB8IeLhugyC2rTEwwSclb8tQNYtUiGdna9" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "m38kb0OS2DDrEdtdQb2hWCnswxaAkUunb2qq18vd3dBvlnI+C4/xu5ksZZkRj+fW" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "tArNR18V+2jkwcG26m8AxIrT+m4M6/bgnSfHTBtT5adNfVcTHqiT1JtCbQcXmwVw" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "WbqS6v/LhcsBE//SHne4uBCK/GHxZHhQ5jz5h+3vWeV4gvxS3Xu6v1IlIpLDwUts" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "kT1DumfynYnnZmWTGc6SYyIFXTPJLtnoWDb9OBdWgZxXfHEcBsKGha+bXO+m2tHA" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "gNneN9i5f8oNxo5njrL8jkCckOpNpng18BKXABEBAAG0MlNhbHRTdGFjayBQYWNr" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "YWdpbmcgVGVhbSA8cGFja2FnaW5nQHNhbHRzdGFjay5jb20+iQE4BBMBAgAiBQJT" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "qb6YAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRAOCKFJ3le/vhkqB/0Q" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "WzELZf4d87WApzolLG+zpsJKtt/ueXL1W1KA7JILhXB1uyvVORt8uA9FjmE083o1" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "yE66wCya7V8hjNn2lkLXboOUd1UTErlRg1GYbIt++VPscTxHxwpjDGxDB1/fiX2o" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "nK5SEpuj4IeIPJVE/uLNAwZyfX8DArLVJ5h8lknwiHlQLGlnOu9ulEAejwAKt9CU" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "4oYTszYM4xrbtjB/fR+mPnYh2fBoQO4d/NQiejIEyd9IEEMd/03AJQBuMux62tjA" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "/NwvQ9eqNgLw9NisFNHRWtP4jhAOsshv1WW+zPzu3ozoO+lLHixUIz7fqRk38q8Q" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "9oNR31KvrkSNrFbA3D89uQENBFOpvpgBCADJ79iH10AfAfpTBEQwa6vzUI3Eltqb" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "9aZ0xbZV8V/8pnuU7rqM7Z+nJgldibFk4gFG2bHCG1C5aEH/FmcOMvTKDhJSFQUx" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "uhgxttMArXm2c22OSy1hpsnVG68G32Nag/QFEJ++3hNnbyGZpHnPiYgej3FrerQJ" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "zv456wIsxRDMvJ1NZQB3twoCqwapC6FJE2hukSdWB5yCYpWlZJXBKzlYz/gwD/Fr" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "GL578WrLhKw3UvnJmlpqQaDKwmV2s7MsoZogC6wkHE92kGPG2GmoRD3ALjmCvN1E" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "PsIsQGnwpcXsRpYVCoW7e2nW4wUf7IkFZ94yOCmUq6WreWI4NggRcFC5ABEBAAGJ" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "AR8EGAECAAkFAlOpvpgCGwwACgkQDgihSd5Xv74/NggA08kEdBkiWWwJZUZEy7cK" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "WWcgjnRuOHd4rPeT+vQbOWGu6x4bxuVf9aTiYkf7ZjVF2lPn97EXOEGFWPZeZbH4" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "vdRFH9jMtP+rrLt6+3c9j0M8SIJYwBL1+CNpEC/BuHj/Ra/cmnG5ZNhYebm76h5f" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "T9iPW9fFww36FzFka4VPlvA4oB7ebBtquFg3sdQNU/MmTVV4jPFWXxh4oRDDR+8N" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "1bcPnbB11b5ary99F/mqr7RgQ+YFF0uKRE3SKa7a+6cIuHEZ7Za+zhPaQlzAOZlx" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "fuBmScum8uQTrEF5+Um5zkwC7EXTdH1co/+/V/fpOtxIg4XO4kcugZefVm5ERfVS" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "MA==" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "=dtMN" >> /etc/pki/rpm-gpg/saltstack-signing-key + echo "-----END PGP PUBLIC KEY BLOCK-----" >> /etc/pki/rpm-gpg/saltstack-signing-key + + # Add the Wazuh Key + cat > /etc/pki/rpm-gpg/GPG-KEY-WAZUH <<\EOF +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mQINBFeeyYwBEACyf4VwV8c2++J5BmCl6ofLCtSIW3UoVrF4F+P19k/0ngnSfjWb +8pSWB11HjZ3Mr4YQeiD7yY06UZkrCXk+KXDlUjMK3VOY7oNPkqzNaP6+8bDwj4UA +hADMkaXBvWooGizhCoBtDb1bSbHKcAnQ3PTdiuaqF5bcyKk8hv939CHulL2xH+BP +mmTBi+PM83pwvR+VRTOT7QSzf29lW1jD79v4rtXHJs4KCz/amT/nUm/tBpv3q0sT +9M9rH7MTQPdqvzMl122JcZST75GzFJFl0XdSHd5PAh2mV8qYak5NYNnwA41UQVIa ++xqhSu44liSeZWUfRdhrQ/Nb01KV8lLAs11Sz787xkdF4ad25V/Rtg/s4UXt35K3 +klGOBwDnzPgHK/OK2PescI5Ve1z4x1C2bkGze+gk/3IcfGJwKZDfKzTtqkZ0MgpN +7RGghjkH4wpFmuswFFZRyV+s7jXYpxAesElDSmPJ0O07O4lQXQMROE+a2OCcm0eF +3+Cr6qxGtOp1oYMOVH0vOLYTpwOkAM12/qm7/fYuVPBQtVpTojjV5GDl2uGq7p0o +h9hyWnLeNRbAha0px6rXcF9wLwU5n7mH75mq5clps3sP1q1/VtP/Fr84Lm7OGke4 +9eD+tPNCdRx78RNWzhkdQxHk/b22LCn1v6p1Q0qBco9vw6eawEkz1qwAjQARAQAB +tDFXYXp1aC5jb20gKFdhenVoIFNpZ25pbmcgS2V5KSA8c3VwcG9ydEB3YXp1aC5j +b20+iQI9BBMBCAAnBQJXnsmMAhsDBQkFo5qABQsJCAcDBRUKCQgLBRYCAwEAAh4B +AheAAAoJEJaz7l8pERFFHEsQAIaslejcW2NgjgOZuvn1Bht4JFMbCIPOekg4Z5yF +binRz0wmA7JNaawDHTBYa6L+A2Xneu/LmuRjFRMesqopUukVeGQgHBXbGMzY46eI +rqq/xgvgWzHSbWweiOX0nn+exbEAM5IyW+efkWNz0e8xM1LcxdYZxkVOqFqkp3Wv +J9QUKw6z9ifUOx++G8UO307O3hT2f+x4MUoGZeOF4q1fNy/VyBS2lMg2HF7GWy2y +kjbSe0p2VOFGEZLuu2f5tpPNth9UJiTliZKmgSk/zbKYmSjiVY2eDqNJ4qjuqes0 +vhpUaBjA+DgkEWUrUVXG5yfQDzTiYIF84LknjSJBYSLZ4ABsMjNO+GApiFPcih+B +Xc9Kx7E9RNsNTDqvx40y+xmxDOzVIssXeKqwO8r5IdG3K7dkt2Vkc/7oHOpcKwE5 +8uASMPiqqMo+t1RVa6Spckp3Zz8REILbotnnVwDIwo2HmgASirMGUcttEJzubaIa +Mv43GKs8RUH9s5NenC02lfZG7D8WQCz5ZH7yEWrt5bCaQRNDXjhsYE17SZ/ToHi3 +OpWu050ECWOHdxlXNG3dOWIdFDdBJM7UfUNSSOe2Y5RLsWfwvMFGbfpdlgJcMSDV +X+ienkrtXhBteTu0dwPu6HZTFOjSftvtAo0VIqGQrKMvKelkkdNGdDFLQw2mUDcw +EQj6uQINBFeeyYwBEADD1Y3zW5OrnYZ6ghTd5PXDAMB8Z1ienmnb2IUzLM+i0yE2 +TpKSP/XYCTBhFa390rYgFO2lbLDVsiz7Txd94nHrdWXGEQfwrbxsvdlLLWk7iN8l +Fb4B60OfRi3yoR96a/kIPNa0x26+n79LtDuWZ/DTq5JSHztdd9F1sr3h8i5zYmtv +luj99ZorpwYejbBVUm0+gP0ioaXM37uO56UFVQk3po9GaS+GtLnlgoE5volgNYyO +rkeIua4uZVsifREkHCKoLJip6P7S3kTyfrpiSLhouEZ7kV1lbMbFgvHXyjm+/AIx +HIBy+H+e+HNt5gZzTKUJsuBjx44+4jYsOR67EjOdtPOpgiuJXhedzShEO6rbu/O4 +wM1rX45ZXDYa2FGblHCQ/VaS0ttFtztk91xwlWvjTR8vGvp5tIfCi+1GixPRQpbN +Y/oq8Kv4A7vB3JlJscJCljvRgaX0gTBzlaF6Gq0FdcWEl5F1zvsWCSc/Fv5WrUPY +5mG0m69YUTeVO6cZS1aiu9Qh3QAT/7NbUuGXIaAxKnu+kkjLSz+nTTlOyvbG7BVF +a6sDmv48Wqicebkc/rCtO4g8lO7KoA2xC/K/6PAxDrLkVyw8WPsAendmezNfHU+V +32pvWoQoQqu8ysoaEYc/j9fN4H3mEBCN3QUJYCugmHP0pu7VtpWwwMUqcGeUVwAR +AQABiQIlBBgBCAAPBQJXnsmMAhsMBQkFo5qAAAoJEJaz7l8pERFFz8IP/jfBxJSB +iOw+uML+C4aeYxuHSdxmSsrJclYjkw7Asha/fm4Kkve00YAW8TGxwH2kgS72ooNJ +1Q7hUxNbVyrJjQDSMkRKwghmrPnUM3UyHmE0dq+G2NhaPdFo8rKifLOPgwaWAfSV +wgMTK86o0kqRbGpXgVIG5eRwv2FcxM3xGfy7sub07J2VEz7Ba6rYQ3NTbPK42AtV ++wRJDXcgS7y6ios4XQtSbIB5f6GI56zVlwfRd3hovV9ZAIJQ6DKM31wD6Kt/pRun +DjwMZu0/82JMoqmxX/00sNdDT1S13guCfl1WhBu7y1ja9MUX5OpUzyEKg5sxme+L +iY2Rhs6CjmbTm8ER4Uj8ydKyVTy8zbumbB6T8IwCAbEMtPxm6pKh/tgLpoJ+Bj0y +AsGjmhV7R6PKZSDXg7/qQI98iC6DtWc9ibC/QuHLcvm3hz40mBgXAemPJygpxGst +mVtU7O3oHw9cIUpkbMuVqSxgPFmSSq5vEYkka1CYeg8bOz6aCTuO5J0GDlLrpjtx +6lyImbZAF/8zKnW19aq5lshT2qJlTQlZRwwDZX5rONhA6T8IEUnUyD4rAIQFwfJ+ +gsXa4ojD/tA9NLdiNeyEcNfyX3FZwXWCtVLXflzdRN293FKamcdnMjVRjkCnp7iu +7eO7nMgcRoWddeU+2aJFqCoQtKCp/5EKhFey +=UIVm +-----END PGP PUBLIC KEY BLOCK----- +EOF + + # Proxy is hating on me.. Lets just set it manually + echo "[salt-latest]" > /etc/yum.repos.d/salt-latest.repo + echo "name=SaltStack Latest Release Channel for RHEL/Centos \$releasever" >> /etc/yum.repos.d/salt-latest.repo + echo "baseurl=https://repo.saltstack.com/py3/redhat/7/\$basearch/latest" >> /etc/yum.repos.d/salt-latest.repo + echo "failovermethod=priority" >> /etc/yum.repos.d/salt-latest.repo + echo "enabled=1" >> /etc/yum.repos.d/salt-latest.repo + echo "gpgcheck=1" >> /etc/yum.repos.d/salt-latest.repo + echo "gpgkey=file:///etc/pki/rpm-gpg/saltstack-signing-key" >> /etc/yum.repos.d/salt-latest.repo + + # Proxy is hating on me.. Lets just set it manually + echo "[salt-2019.2]" > /etc/yum.repos.d/salt-2019-2.repo + echo "name=SaltStack Latest Release Channel for RHEL/Centos \$releasever" >> /etc/yum.repos.d/salt-2019-2.repo + echo "baseurl=https://repo.saltstack.com/py3/redhat/7/\$basearch/2019.2" >> /etc/yum.repos.d/salt-2019-2.repo + echo "failovermethod=priority" >> /etc/yum.repos.d/salt-2019-2.repo + echo "enabled=1" >> /etc/yum.repos.d/salt-2019-2.repo + echo "gpgcheck=1" >> /etc/yum.repos.d/salt-2019-2.repo + echo "gpgkey=file:///etc/pki/rpm-gpg/saltstack-signing-key" >> /etc/yum.repos.d/salt-2019-2.repo + + cat > /etc/yum.repos.d/wazuh.repo <<\EOF +[wazuh_repo] +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/GPG-KEY-WAZUH +enabled=1 +name=Wazuh repository +baseurl=https://packages.wazuh.com/3.x/yum/ +protect=1 +EOF + else + yum -y install https://repo.saltstack.com/py3/redhat/salt-py3-repo-latest-2.el7.noarch.rpm + cp /etc/yum.repos.d/salt-latest.repo /etc/yum.repos.d/salt-2019-2.repo + sed -i 's/latest/2019.2/g' /etc/yum.repos.d/salt-2019-2.repo +cat > /etc/yum.repos.d/wazuh.repo <<\EOF +[wazuh_repo] +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/GPG-KEY-WAZUH +enabled=1 +name=Wazuh repository +baseurl=https://packages.wazuh.com/3.x/yum/ +protect=1 +EOF + fi + fi + + yum clean expire-cache + yum -y install epel-release salt-minion-2019.2.2 yum-utils device-mapper-persistent-data lvm2 openssl + yum -y update exclude=salt* + systemctl enable salt-minion + + if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then + yum -y install salt-master-2019.2.2 python3 python36-m2crypto salt-minion-2019.2.2 python36-dateutil python36-mysql python36-docker + systemctl enable salt-master + else + yum -y install salt-minion-2019.2.2 python3 python36-m2crypto python36-dateutil python36-docker + fi + echo "exclude=salt*" >> /etc/yum.conf + + else + ADDUSER=useradd + DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade + + # Add the pre-requisites for installing docker-ce + apt-get -y install ca-certificates curl software-properties-common apt-transport-https openssl >> $SETUPLOG 2>&1 + + # Grab the version from the os-release file + UVER=$(grep VERSION_ID /etc/os-release | awk -F '[ "]' '{print $2}') + + # Nasty hack but required for now + if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then + + #echo "Using pip3 to install python-dateutil for salt" + #pip3 install python-dateutil + # Install the repo for salt + wget --inet4-only -O - https://repo.saltstack.com/apt/ubuntu/$UVER/amd64/latest/SALTSTACK-GPG-KEY.pub | apt-key add - + wget --inet4-only -O - https://repo.saltstack.com/apt/ubuntu/$UVER/amd64/2019.2/SALTSTACK-GPG-KEY.pub | apt-key add - + echo "deb http://repo.saltstack.com/py3/ubuntu/$UVER/amd64/latest xenial main" > /etc/apt/sources.list.d/saltstack.list + echo "deb http://repo.saltstack.com/py3/ubuntu/$UVER/amd64/2019.2 xenial main" > /etc/apt/sources.list.d/saltstack2019.list + + # Lets get the docker repo added + curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - + add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" + + # Create a place for the keys + mkdir -p /opt/so/gpg + wget --inet4-only -O /opt/so/gpg/SALTSTACK-GPG-KEY.pub https://repo.saltstack.com/apt/ubuntu/$UVER/amd64/latest/SALTSTACK-GPG-KEY.pub + wget --inet4-only -O /opt/so/gpg/docker.pub https://download.docker.com/linux/ubuntu/gpg + wget --inet4-only -O /opt/so/gpg/GPG-KEY-WAZUH https://packages.wazuh.com/key/GPG-KEY-WAZUH + + # Get key and install wazuh + curl -s https://packages.wazuh.com/key/GPG-KEY-WAZUH | apt-key add - + # Add repo + echo "deb https://packages.wazuh.com/3.x/apt/ stable main" | tee /etc/apt/sources.list.d/wazuh.list + + # Initialize the new repos + apt-get update >> $SETUPLOG 2>&1 + # Need to add python packages here + apt-get -y install salt-minion=2019.2.2+ds-1 salt-common=2019.2.2+ds-1 python3-dateutil >> $SETUPLOG 2>&1 + apt-mark hold salt-minion salt-common + + else + + # Copy down the gpg keys and install them from the master + mkdir $TMP/gpg + scp socore@$MSRV:/opt/so/gpg/* $TMP/gpg + apt-key add $TMP/gpg/SALTSTACK-GPG-KEY.pub + apt-key add $TMP/gpg/GPG-KEY-WAZUH + echo "deb http://repo.saltstack.com/apt/ubuntu/$UVER/amd64/latest xenial main" > /etc/apt/sources.list.d/saltstack.list + echo "deb https://packages.wazuh.com/3.x/apt/ stable main" | tee /etc/apt/sources.list.d/wazuh.list + # Initialize the new repos + apt-get update >> $SETUPLOG 2>&1 + # Need to add python dateutil here + apt-get -y install salt-minion=2019.2.2+ds-1 salt-common=2019.2.2+ds-1 >> $SETUPLOG 2>&1 + apt-mark hold salt-minion salt-common + + fi + + fi + +} + +salt_checkin() { + # Master State to Fix Mine Usage + if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then + echo "Building Certificate Authority" + salt-call state.apply ca >> $SETUPLOG 2>&1 + echo " *** Restarting Salt to fix any SSL errors. ***" + service salt-master restart >> $SETUPLOG 2>&1 + sleep 5 + service salt-minion restart >> $SETUPLOG 2>&1 + sleep 15 + echo " Applyng a mine hack " + sudo salt '*' mine.send x509.get_pem_entries glob_path=/etc/pki/ca.crt >> $SETUPLOG 2>&1 + echo " Applying SSL state " + salt-call state.apply ssl >> $SETUPLOG 2>&1 + echo "Still Working... Hang in there" + #salt-call state.highstate + + else + + # Run Checkin + salt-call state.apply ca >> $SETUPLOG 2>&1 + salt-call state.apply ssl >> $SETUPLOG 2>&1 + #salt-call state.highstate >> $SETUPLOG 2>&1 + + fi + +} + +salt_checkin_message() { + + # Warn the user that this might take a while + echo "####################################################" + echo "## ##" + echo "## Applying and Installing everything ##" + echo "## (This will take a while) ##" + echo "## ##" + echo "####################################################" + +} + +salt_firstcheckin() { + + #First Checkin + salt-call state.highstate >> $SETUPLOG 2>&1 + +} + +salt_master_directories() { + + # Create salt paster directories + mkdir -p /opt/so/saltstack/salt + mkdir -p /opt/so/saltstack/pillar + + # Copy over the salt code and templates + cp -R pillar/* /opt/so/saltstack/pillar/ + chmod +x /opt/so/saltstack/pillar/firewall/addfirewall.sh + chmod +x /opt/so/saltstack/pillar/data/addtotab.sh + cp -R salt/* /opt/so/saltstack/salt/ + +} + +salt_install_mysql_deps() { + + if [ $OS == 'centos' ]; then + yum -y install mariadb-devel + elif [ $OS == 'ubuntu' ]; then + apt-get -y install libmysqlclient-dev python3-mysqldb + fi + +} + +sensor_pillar() { + + SENSORPILLARPATH=$TMP/pillar/sensors + if [ ! -d $SENSORPILLARPATH ]; then + mkdir -p $SENSORPILLARPATH + fi + + # Create the sensor pillar + touch $SENSORPILLARPATH/$MINION_ID.sls + echo "sensor:" > $SENSORPILLARPATH/$MINION_ID.sls + echo " interface: bond0" >> $SENSORPILLARPATH/$MINION_ID.sls + echo " mainip: $MAINIP" >> $SENSORPILLARPATH/$MINION_ID.sls + echo " mainint: $MAININT" >> $SENSORPILLARPATH/$MINION_ID.sls + if [ $NSMSETUP == 'ADVANCED' ]; then + echo " bro_pins:" >> $SENSORPILLARPATH/$MINION_ID.sls + for PIN in $BROPINS; do + PIN=$(echo $PIN | cut -d\" -f2) + echo " - $PIN" >> $SENSORPILLARPATH/$MINION_ID.sls + done + echo " suripins:" >> $SENSORPILLARPATH/$MINION_ID.sls + for SPIN in $SURIPINS; do + SPIN=$(echo $SPIN | cut -d\" -f2) + echo " - $SPIN" >> $SENSORPILLARPATH/$MINION_ID.sls + done + else + echo " bro_lbprocs: $BASICBRO" >> $SENSORPILLARPATH/$MINION_ID.sls + echo " suriprocs: $BASICSURI" >> $SENSORPILLARPATH/$MINION_ID.sls + fi + echo " brobpf:" >> $SENSORPILLARPATH/$MINION_ID.sls + echo " pcapbpf:" >> $SENSORPILLARPATH/$MINION_ID.sls + echo " nidsbpf:" >> $SENSORPILLARPATH/$MINION_ID.sls + echo " master: $MSRV" >> $SENSORPILLARPATH/$MINION_ID.sls + echo " mtu: $MTU" >> $SENSORPILLARPATH/$MINION_ID.sls + if [ $HNSENSOR != 'inherit' ]; then + echo " hnsensor: $HNSENSOR" >> $SENSORPILLARPATH/$MINION_ID.sls + fi + echo " access_key: $ACCESS_KEY" >> $SENSORPILLARPATH/$MINION_ID.sls + echo " access_secret: $ACCESS_SECRET" >> $SENSORPILLARPATH/$MINION_ID.sls + +} + +set_environment_var() { + + echo "Setting environment variable: $1" + + export "$1" + echo "$1" >> /etc/environment + +} + +set_hostname() { + + hostnamectl set-hostname --static $HOSTNAME + echo "127.0.0.1 $HOSTNAME $HOSTNAME.localdomain localhost localhost.localdomain localhost4 localhost4.localdomain" > /etc/hosts + echo "::1 localhost localhost.localdomain localhost6 localhost6.localdomain6" >> /etc/hosts + echo $HOSTNAME > /etc/hostname + if [ $INSTALLTYPE != 'MASTERONLY' ] || [ $INSTALLTYPE != 'EVALMODE' ]; then + if [[ $TESTHOST = *"not found"* ]] || [[ $TESTHOST = *"connection timed out"* ]]; then + if ! grep -q $MSRVIP /etc/hosts; then + echo "$MSRVIP $MSRV" >> /etc/hosts + fi + fi + fi + +} + +set_initial_firewall_policy() { + + get_main_ip + if [ $INSTALLTYPE == 'MASTERONLY' ]; then + printf " - $MAINIP\n" >> /opt/so/saltstack/pillar/firewall/minions.sls + printf " - $MAINIP\n" >> /opt/so/saltstack/pillar/firewall/masterfw.sls + /opt/so/saltstack/pillar/data/addtotab.sh mastertab $MINION_ID $MAINIP $CPUCORES $RANDOMUID $MAININT $FSROOT $FSNSM + fi + + if [ $INSTALLTYPE == 'EVALMODE' ]; then + printf " - $MAINIP\n" >> /opt/so/saltstack/pillar/firewall/minions.sls + printf " - $MAINIP\n" >> /opt/so/saltstack/pillar/firewall/masterfw.sls + printf " - $MAINIP\n" >> /opt/so/saltstack/pillar/firewall/forward_nodes.sls + printf " - $MAINIP\n" >> /opt/so/saltstack/pillar/firewall/storage_nodes.sls + /opt/so/saltstack/pillar/data/addtotab.sh evaltab $MINION_ID $MAINIP $CPUCORES $RANDOMUID $MAININT $FSROOT $FSNSM bond0 + fi + + if [ $INSTALLTYPE == 'SENSORONLY' ]; then + ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/firewall/addfirewall.sh minions $MAINIP + ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/firewall/addfirewall.sh forward_nodes $MAINIP + ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/data/addtotab.sh sensorstab $MINION_ID $MAINIP $CPUCORES $RANDOMUID $MAININT $FSROOT $FSNSM bond0 + fi + + if [ $INSTALLTYPE == 'STORAGENODE' ]; then + ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/firewall/addfirewall.sh minions $MAINIP + ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/firewall/addfirewall.sh storage_nodes $MAINIP + ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/data/addtotab.sh nodestab $MINION_ID $MAINIP $CPUCORES $RANDOMUID $MAININT $FSROOT $FSNSM + fi + + if [ $INSTALLTYPE == 'PARSINGNODE' ]; then + echo "blah" + fi + + if [ $INSTALLTYPE == 'HOTNODE' ]; then + echo "blah" + fi + + if [ $INSTALLTYPE == 'WARMNODE' ]; then + echo "blah" + fi + +} + +set_node_type() { + + # Determine the node type based on whiplash choice + if [ $INSTALLTYPE == 'STORAGENODE' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then + NODETYPE='storage' + fi + if [ $INSTALLTYPE == 'PARSINGNODE' ]; then + NODETYPE='parser' + fi + if [ $INSTALLTYPE == 'HOTNODE' ]; then + NODETYPE='hot' + fi + if [ $INSTALLTYPE == 'WARMNODE' ]; then + NODETYPE='warm' + fi + +} + +set_updates() { + echo "MASTERUPDATES is $MASTERUPDATES" + if [ $MASTERUPDATES == 'MASTER' ]; then + if [ $OS == 'centos' ]; then + if ! grep -q $MSRV /etc/yum.conf; then + echo "proxy=http://$MSRV:3142" >> /etc/yum.conf + fi + + else + + # Set it up so the updates roll through the master + echo "Acquire::http::Proxy \"http://$MSRV:3142\";" > /etc/apt/apt.conf.d/00Proxy + echo "Acquire::https::Proxy \"http://$MSRV:3142\";" >> /etc/apt/apt.conf.d/00Proxy + + fi + fi +} + +update_sudoers() { + + if ! grep -qE '^socore\ ALL=\(ALL\)\ NOPASSWD:(\/usr\/bin\/salt\-key|\/opt\/so\/saltstack)' /etc/sudoers; then + # Update Sudoers so that socore can accept keys without a password + echo "socore ALL=(ALL) NOPASSWD:/usr/bin/salt-key" | sudo tee -a /etc/sudoers + echo "socore ALL=(ALL) NOPASSWD:/opt/so/saltstack/pillar/firewall/addfirewall.sh" | sudo tee -a /etc/sudoers + echo "socore ALL=(ALL) NOPASSWD:/opt/so/saltstack/pillar/data/addtotab.sh" | sudo tee -a /etc/sudoers + else + echo "User socore already granted sudo privileges" + fi + +} diff --git a/setup/so-setup.sh b/setup/so-setup.sh new file mode 100644 index 000000000..837cf6d6e --- /dev/null +++ b/setup/so-setup.sh @@ -0,0 +1,627 @@ +#!/bin/bash + +# Copyright 2014,2015,2016,2017,2018,2019 Security Onion Solutions, LLC + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Source the other pieces of the setup +source functions.sh +source whiplash.sh + +# Global Variables +HOSTNAME=$(cat /etc/hostname) +MINION_ID=$(echo $HOSTNAME | awk -F. {'print $1'}) +TOTAL_MEM=`grep MemTotal /proc/meminfo | awk '{print $2}' | sed -r 's/.{3}$//'` +NICS=$(ip link | awk -F: '$0 !~ "lo|vir|veth|br|docker|wl|^[^0-9]"{print $2 " \"" "Interface" "\"" " OFF"}') +CPUCORES=$(cat /proc/cpuinfo | grep processor | wc -l) +LISTCORES=$(cat /proc/cpuinfo | grep processor | awk '{print $3 " \"" "core" "\""}') +RANDOMUID=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1) +NODE_ES_PORT="9200" +SETUPLOG="/root/sosetup.log" +# End Global Variables + +# Reset the Install Log +date -u >$SETUPLOG 2>&1 + +# Check for prerequisites +got_root +detect_os + +if [ $OS == ubuntu ]; then + # Override the Ubuntu whiptail color pallete + update-alternatives --set newt-palette /etc/newt/palette.original +fi + +# Question Time +if (whiptail_you_sure); then + + # Create a temp dir to get started + install_prep + + # Determine if this is a network install or ISO install + + # Let folks know they need their management interface already set up. + whiptail_network_notice + + # Set the hostname to reduce errors + whiptail_set_hostname + + # Go ahead and gen the keys so we can use them for any sensor type - Disabled for now + #minio_generate_keys + + # What kind of install are we doing? + whiptail_install_type + + # How do we want to handle OS patching? manual, auto or scheduled days and hours + whiptail_patch_schedule + case $PATCHSCHEDULE in + 'New Schedule') + whiptail_patch_schedule_select_days + whiptail_patch_schedule_select_hours + whiptail_patch_name_new_schedule + patch_schedule_os_new + ;; + 'Import Schedule') + whiptail_patch_schedule_import + ;; + Automatic) + PATCHSCHEDULENAME=auto + ;; + Manual) + PATCHSCHEDULENAME=manual + ;; + esac + + #################### + ## Master ## + #################### + + if [ $INSTALLTYPE == 'MASTERONLY' ]; then + + # Would you like to do an advanced install? + whiptail_master_adv + + # Pick the Management NIC + whiptail_management_nic + + # Choose Zeek or Community NSM + whiptail_bro_version + + # Select Snort or Suricata + whiptail_nids + + # Snag the HOME_NET + whiptail_homenet_master + + # Pick your Ruleset + whiptail_rule_setup + + # Get the code if it isn't ET Open + if [ $RULESETUP != 'ETOPEN' ]; then + # Get the code + whiptail_oinkcode + fi + + # Find out how to handle updates + whiptail_master_updates + whiptail_enable_components + process_components + + # Do Advacned Setup if they chose it + if [ $MASTERADV == 'ADVANCED' ]; then + # Ask which bro logs to enable - Need to add Suricata check + if [ $BROVERSION != 'SURICATA' ]; then + whiptail_master_adv_service_brologs + fi + fi + + whiptail_create_socore_user + SCMATCH=no + while [ $SCMATCH != yes ]; do + whiptail_create_socore_user_password1 + whiptail_create_socore_user_password2 + check_socore_pass + done + + # Last Chance to back out + whiptail_make_changes + set_hostname + generate_passwords + auth_pillar + clear_master + mkdir -p /nsm + get_filesystem_root + get_filesystem_nsm + # Enable Bro Logs + bro_logs_enabled + + # Figure out the main IP address + get_main_ip + + # Add the user so we can sit back and relax + #echo "" + #echo "**** Please set a password for socore. You will use this password when setting up other Nodes/Sensors" + #echo "" + add_socore_user_master + + # Install salt and dependencies + { + sleep 0.5 + #install_pip3 >> $SETUPLOG 2>&1 + echo -e "XXX\n1\nInstalling and configuring Salt... \nXXX" + echo " ** Installing Salt and Dependencies **" >> $SETUPLOG + salt_install_mysql_deps >> $SETUPLOG 2>&1 + saltify >> $SETUPLOG 2>&1 + echo -e "XXX\n5\nInstalling Docker... \nXXX" + docker_install >> $SETUPLOG 2>&1 + echo -e "XXX\n10\nConfiguring Salt Master... \nXXX" + echo " ** Configuring Minion **" >> $SETUPLOG + configure_minion master >> $SETUPLOG 2>&1 + echo " ** Installing Salt Master **" >> $SETUPLOG + install_master >> $SETUPLOG 2>&1 + salt_master_directories >> $SETUPLOG 2>&1 + update_sudoers >> $SETUPLOG 2>&1 + chown_salt_master >> $SETUPLOG 2>&1 + es_heapsize >> $SETUPLOG 2>&1 + ls_heapsize >> $SETUPLOG 2>&1 + echo -e "XXX\n25\nConfiguring Default Pillars... \nXXX" + master_static >> $SETUPLOG 2>&1 + echo "** Generating the master pillar **" >> $SETUPLOG + master_pillar >> $SETUPLOG 2>&1 + echo "** Generating the patch pillar **" >> $SETUPLOG + patch_pillar >> $SETUPLOG 2>&1 + echo -e "XXX\n30\nAccepting Salt Keys... \nXXX" + echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" + copy_minion_tmp_files >> $SETUPLOG 2>&1 + # Do a checkin to push the key up + echo "** Pushing the key up to Master **" >> $SETUPLOG + salt_firstcheckin >> $SETUPLOG 2>&1 + # Accept the Master Key + echo "** Accepting the key on the master **" >> $SETUPLOG + accept_salt_key_local >> $SETUPLOG 2>&1 + echo -e "XXX\n35\nConfiguring Firewall... \nXXX" + # Open the firewall + echo "** Setting the initial firewall policy **" >> $SETUPLOG + set_initial_firewall_policy >> $SETUPLOG 2>&1 + # Do the big checkin but first let them know it will take a bit. + echo -e "XXX\n40\nGenerating CA... \nXXX" + salt_checkin >> $SETUPLOG 2>&1 + salt-call state.apply ca >> $SETUPLOG 2>&1 + salt-call state.apply ssl >> $SETUPLOG 2>&1 + echo -e "XXX\n43\nInstalling Common Components... \nXXX" + salt-call state.apply common >> $SETUPLOG 2>&1 + echo -e "XXX\n45\nApplying firewall rules... \nXXX" + salt-call state.apply firewall >> $SETUPLOG 2>&1 + salt-call state.apply master >> $SETUPLOG 2>&1 + salt-call state.apply idstools >> $SETUPLOG 2>&1 + echo -e "XXX\n40\nInstalling Redis... \nXXX" + salt-call state.apply redis >> $SETUPLOG 2>&1 + if [[ $OSQUERY == '1' ]]; then + echo -e "XXX\n41\nInstalling MySQL... \nXXX" + salt-call state.apply mysql >> $SETUPLOG 2>&1 + fi + echo -e "XXX\n45\nInstalling Elastic Components... \nXXX" + salt-call state.apply elasticsearch >> $SETUPLOG 2>&1 + salt-call state.apply logstash >> $SETUPLOG 2>&1 + salt-call state.apply kibana >> $SETUPLOG 2>&1 + salt-call state.apply elastalert >> $SETUPLOG 2>&1 + if [[ $WAZUH == '1' ]]; then + echo -e "XXX\n68\nInstalling Wazuh... \nXXX" + salt-call state.apply wazuh >> $SETUPLOG 2>&1 + fi + echo -e "XXX\n75\nInstalling Filebeat... \nXXX" + salt-call state.apply filebeat >> $SETUPLOG 2>&1 + salt-call state.apply utility >> $SETUPLOG 2>&1 + salt-call state.apply schedule >> $SETUPLOG 2>&1 + if [[ $OSQUERY == '1' ]]; then + echo -e "XXX\n79\nInstalling Fleet... \nXXX" + salt-call state.apply fleet >> $SETUPLOG 2>&1 + salt-call state.apply launcher >> $SETUPLOG 2>&1 + fi + echo -e "XXX\n85\nConfiguring SOctopus... \nXXX" + salt-call state.apply soctopus >> $SETUPLOG 2>&1 + if [[ $THEHIVE == '1' ]]; then + echo -e "XXX\n87\nInstalling TheHive... \nXXX" + salt-call state.apply hive >> $SETUPLOG 2>&1 + fi + if [[ $PLAYBOOK == '1' ]]; then + echo -e "XXX\n89\nInstalling Playbook... \nXXX" + salt-call state.apply playbook >> $SETUPLOG 2>&1 + fi + echo -e "XXX\n75\nEnabling Checking at Boot... \nXXX" + checkin_at_boot >> $SETUPLOG 2>&1 + echo -e "XXX\n95\nVerifying Install... \nXXX" + salt-call state.highstate >> $SETUPLOG 2>&1 + + } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 + GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') + if [[ $GOODSETUP == '0' ]]; then + whiptail_setup_complete + if [[ $THEHIVE == '1' ]]; then + check_hive_init_then_reboot + else + shutdown -r now + fi + else + whiptail_setup_failed + shutdown -r now + fi + + fi + + #################### + ## Sensor ## + #################### + + if [ $INSTALLTYPE == 'SENSORONLY' ]; then + whiptail_management_nic + filter_nics + whiptail_bond_nics + whiptail_management_server + whiptail_master_updates + set_updates + whiptail_homenet_sensor + whiptail_sensor_config + # Calculate lbprocs so we can call it in the prompts + calculate_useable_cores + if [ $NSMSETUP == 'ADVANCED' ]; then + whiptail_bro_pins + whiptail_suricata_pins + whiptail_bond_nics_mtu + else + whiptail_basic_bro + whiptail_basic_suri + fi + whiptail_make_changes + set_hostname + clear_master + mkdir -p /nsm + get_filesystem_root + get_filesystem_nsm + copy_ssh_key + { + sleep 0.5 + echo -e "XXX\n0\nSetting Initial Firewall Policy... \nXXX" + set_initial_firewall_policy >> $SETUPLOG 2>&1 + #echo -e "XXX\n1\nInstalling pip3... \nXXX" + #install_pip3 >> $SETUPLOG 2>&1 + echo -e "XXX\n3\nCreating Bond Interface... \nXXX" + network_setup >> $SETUPLOG 2>&1 + echo -e "XXX\n4\nGenerating Sensor Pillar... \nXXX" + sensor_pillar >> $SETUPLOG 2>&1 + echo "** Generating the patch pillar **" >> $SETUPLOG + patch_pillar >> $SETUPLOG 2>&1 + echo -e "XXX\n5\nInstalling Salt Components... \nXXX" + saltify >> $SETUPLOG 2>&1 + echo -e "XXX\n20\nInstalling Docker... \nXXX" + docker_install >> $SETUPLOG 2>&1 + echo -e "XXX\n22\nConfiguring Salt Minion... \nXXX" + configure_minion sensor >> $SETUPLOG 2>&1 + echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" + copy_minion_tmp_files >> $SETUPLOG 2>&1 + echo -e "XXX\n25\nSending Salt Key to Master... \nXXX" + salt_firstcheckin >> $SETUPLOG 2>&1 + echo -e "XXX\n26\nTelling the Master to Accept Key... \nXXX" + # Accept the Salt Key + accept_salt_key_remote >> $SETUPLOG 2>&1 + echo -e "XXX\n27\nApplying SSL Certificates... \nXXX" + salt-call state.apply ca >> $SETUPLOG 2>&1 + salt-call state.apply ssl >> $SETUPLOG 2>&1 + echo -e "XXX\n35\nInstalling Core Components... \nXXX" + salt-call state.apply common >> $SETUPLOG 2>&1 + salt-call state.apply firewall >> $SETUPLOG 2>&1 + echo -e "XXX\n50\nInstalling PCAP... \nXXX" + salt-call state.apply pcap >> $SETUPLOG 2>&1 + echo -e "XXX\n60\nInstalling IDS components... \nXXX" + salt-call state.apply suricata >> $SETUPLOG 2>&1 + echo -e "XXX\n80\nVerifying Install... \nXXX" + salt-call state.highstate >> $SETUPLOG 2>&1 + checkin_at_boot >> $SETUPLOG 2>&1 + } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 + GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') + if [[ $GOODSETUP == '0' ]]; then + whiptail_setup_complete + shutdown -r now + else + whiptail_setup_failed + shutdown -r now + fi + fi + + ####################### + ## Eval Mode ## + ####################### + + if [ $INSTALLTYPE == 'EVALMODE' ]; then + # Select the management NIC + whiptail_management_nic + + # Filter out the management NIC + filter_nics + + # Select which NICs are in the bond + whiptail_bond_nics + + # Snag the HOME_NET + whiptail_homenet_master + whiptail_eval_adv_warning + whiptail_enable_components + + # Set a bunch of stuff since this is eval + es_heapsize + ls_heapsize + NODE_ES_HEAP_SIZE="600m" + NODE_LS_HEAP_SIZE="500m" + LSPIPELINEWORKERS=1 + LSPIPELINEBATCH=125 + LSINPUTTHREADS=1 + LSINPUTBATCHCOUNT=125 + RULESETUP=ETOPEN + NSMSETUP=BASIC + NIDS=Suricata + BROVERSION=ZEEK + CURCLOSEDAYS=30 + process_components + whiptail_create_socore_user + SCMATCH=no + while [ $SCMATCH != yes ]; do + whiptail_create_socore_user_password1 + whiptail_create_socore_user_password2 + check_socore_pass + done + whiptail_make_changes + set_hostname + generate_passwords + auth_pillar + clear_master + mkdir -p /nsm + get_filesystem_root + get_filesystem_nsm + get_log_size_limit + get_main_ip + # Add the user so we can sit back and relax + add_socore_user_master + { + sleep 0.5 + echo -e "XXX\n0\nCreating Bond Interface... \nXXX" + network_setup >> $SETUPLOG 2>&1 + #install_pip3 >> $SETUPLOG 2>&1 + echo -e "XXX\n1\nInstalling mysql dependencies for saltstack... \nXXX" + salt_install_mysql_deps >> $SETUPLOG 2>&1 + echo -e "XXX\n1\nInstalling saltstack... \nXXX" + saltify >> $SETUPLOG 2>&1 + echo -e "XXX\n3\nInstalling docker... \nXXX" + docker_install >> $SETUPLOG 2>&1 + echo -e "XXX\n5\nInstalling master code... \nXXX" + install_master >> $SETUPLOG 2>&1 + echo -e "XXX\n6\nCopying salt code... \nXXX" + salt_master_directories >> $SETUPLOG 2>&1 + echo -e "XXX\n6\nupdating suduers... \nXXX" + update_sudoers >> $SETUPLOG 2>&1 + echo -e "XXX\n7\nFixing some permissions... \nXXX" + chown_salt_master >> $SETUPLOG 2>&1 + echo -e "XXX\n7\nCreating the static pillar... \nXXX" + # Set the static values + master_static >> $SETUPLOG 2>&1 + echo -e "XXX\n7\nCreating the master pillar... \nXXX" + master_pillar >> $SETUPLOG 2>&1 + echo "** Generating the patch pillar **" >> $SETUPLOG + patch_pillar >> $SETUPLOG 2>&1 + echo -e "XXX\n7\nConfiguring minion... \nXXX" + configure_minion eval >> $SETUPLOG 2>&1 + echo -e "XXX\n7\nSetting the node type to eval... \nXXX" + set_node_type >> $SETUPLOG 2>&1 + echo -e "XXX\n7\nStorage node pillar... \nXXX" + node_pillar >> $SETUPLOG 2>&1 + echo -e "XXX\n8\nCreating firewall policies... \nXXX" + set_initial_firewall_policy >> $SETUPLOG 2>&1 + echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" + copy_minion_tmp_files >> $SETUPLOG 2>&1 + echo -e "XXX\n10\nRegistering agent... \nXXX" + salt_firstcheckin >> $SETUPLOG 2>&1 + echo -e "XXX\n11\nAccepting Agent... \nXXX" + accept_salt_key_local >> $SETUPLOG 2>&1 + echo -e "XXX\n12\nRunning the SSL states... \nXXX" + salt_checkin >> $SETUPLOG 2>&1 + salt-call state.apply ca >> $SETUPLOG 2>&1 + salt-call state.apply ssl >> $SETUPLOG 2>&1 + echo -e "XXX\n15\nInstalling core components... \nXXX" + salt-call state.apply common >> $SETUPLOG 2>&1 + echo -e "XXX\n18\nInitializing firewall rules... \nXXX" + salt-call state.apply firewall >> $SETUPLOG 2>&1 + echo -e "XXX\n25\nInstalling master components... \nXXX" + salt-call state.apply master >> $SETUPLOG 2>&1 + salt-call state.apply idstools >> $SETUPLOG 2>&1 + if [[ $OSQUERY == '1' ]]; then + salt-call state.apply mysql >> $SETUPLOG 2>&1 + fi + echo -e "XXX\n35\nInstalling ElasticSearch... \nXXX" + salt-call state.apply elasticsearch >> $SETUPLOG 2>&1 + echo -e "XXX\n40\nInstalling Logstash... \nXXX" + salt-call state.apply logstash >> $SETUPLOG 2>&1 + echo -e "XXX\n45\nInstalling Kibana... \nXXX" + salt-call state.apply kibana >> $SETUPLOG 2>&1 + echo -e "XXX\n50\nInstalling pcap... \nXXX" + salt-call state.apply pcap >> $SETUPLOG 2>&1 + echo -e "XXX\n52\nInstalling Suricata... \nXXX" + salt-call state.apply suricata >> $SETUPLOG 2>&1 + echo -e "XXX\n54\nInstalling Zeek... \nXXX" + salt-call state.apply bro >> $SETUPLOG 2>&1 + echo -e "XXX\n56\nInstalling curator... \nXXX" + salt-call state.apply curator >> $SETUPLOG 2>&1 + echo -e "XXX\n58\nInstalling elastalert... \nXXX" + salt-call state.apply elastalert >> $SETUPLOG 2>&1 + if [[ $OSQUERY == '1' ]]; then + echo -e "XXX\n60\nInstalling fleet... \nXXX" + salt-call state.apply fleet >> $SETUPLOG 2>&1 + salt-call state.apply redis >> $SETUPLOG 2>&1 + fi + if [[ $WAZUH == '1' ]]; then + echo -e "XXX\n65\nInstalling Wazuh components... \nXXX" + salt-call state.apply wazuh >> $SETUPLOG 2>&1 + fi + echo -e "XXX\n85\nInstalling filebeat... \nXXX" + salt-call state.apply filebeat >> $SETUPLOG 2>&1 + salt-call state.apply utility >> $SETUPLOG 2>&1 + echo -e "XXX\n95\nInstalling misc components... \nXXX" + salt-call state.apply schedule >> $SETUPLOG 2>&1 + salt-call state.apply soctopus >> $SETUPLOG 2>&1 + if [[ $THEHIVE == '1' ]]; then + echo -e "XXX\n96\nInstalling The Hive... \nXXX" + salt-call state.apply hive >> $SETUPLOG 2>&1 + fi + if [[ $PLAYBOOK == '1' ]]; then + echo -e "XXX\n97\nInstalling Playbook... \nXXX" + salt-call state.apply playbook >> $SETUPLOG 2>&1 + fi + echo -e "XXX\n98\nSetting checkin to run on boot... \nXXX" + checkin_at_boot >> $SETUPLOG 2>&1 + echo -e "XXX\n99\nVerifying Setup... \nXXX" + salt-call state.highstate >> $SETUPLOG 2>&1 + + } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 + GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') + if [ $OS == 'centos' ]; then + if [[ $GOODSETUP == '1' ]]; then + whiptail_setup_complete + if [[ $THEHIVE == '1' ]]; then + check_hive_init_then_reboot + else + shutdown -r now + fi + else + whiptail_setup_failed + shutdown -r now + fi + else + if [[ $GOODSETUP == '0' ]]; then + whiptail_setup_complete + if [[ $THEHIVE == '1' ]]; then + check_hive_init_then_reboot + else + shutdown -r now + fi + else + whiptail_setup_failed + shutdown -r now + fi + fi + fi + + ################### + ## Nodes ## + ################### + + if [ $INSTALLTYPE == 'STORAGENODE' ] || [ $INSTALLTYPE == 'PARSINGNODE' ] || [ $INSTALLTYPE == 'HOTNODE' ] || [ $INSTALLTYPE == 'WARMNODE' ]; then + whiptail_management_nic + whiptail_management_server + whiptail_master_updates + set_updates + get_log_size_limit + CURCLOSEDAYS=30 + es_heapsize + ls_heapsize + whiptail_node_advanced + if [ $NODESETUP == 'NODEADVANCED' ]; then + whiptail_node_es_heap + whiptail_node_ls_heap + whiptail_node_ls_pipeline_worker + whiptail_node_ls_pipline_batchsize + whiptail_node_ls_input_threads + whiptail_node_ls_input_batch_count + whiptail_cur_close_days + whiptail_log_size_limit + else + NODE_ES_HEAP_SIZE=$ES_HEAP_SIZE + NODE_LS_HEAP_SIZE=$LS_HEAP_SIZE + LSPIPELINEWORKERS=$CPUCORES + LSPIPELINEBATCH=125 + LSINPUTTHREADS=1 + LSINPUTBATCHCOUNT=125 + fi + whiptail_make_changes + set_hostname + clear_master + mkdir -p /nsm + get_filesystem_root + get_filesystem_nsm + copy_ssh_key + { + sleep 0.5 + echo -e "XXX\n0\nSetting Initial Firewall Policy... \nXXX" + set_initial_firewall_policy >> $SETUPLOG 2>&1 + #echo -e "XXX\n1\nInstalling pip3... \nXXX" + #install_pip3 >> $SETUPLOG 2>&1 + echo -e "XXX\n5\nInstalling Salt Packages... \nXXX" + saltify >> $SETUPLOG 2>&1 + echo -e "XXX\n20\nInstalling Docker... \nXXX" + docker_install >> $SETUPLOG 2>&1 + echo -e "XXX\n30\nInitializing Minion... \nXXX" + configure_minion node >> $SETUPLOG 2>&1 + set_node_type >> $SETUPLOG 2>&1 + node_pillar >> $SETUPLOG 2>&1 + echo "** Generating the patch pillar **" >> $SETUPLOG + patch_pillar >> $SETUPLOG 2>&1 + echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" + copy_minion_tmp_files >> $SETUPLOG 2>&1 + echo -e "XXX\n35\nSending and Accepting Salt Key... \nXXX" + salt_firstcheckin >> $SETUPLOG 2>&1 + # Accept the Salt Key + accept_salt_key_remote >> $SETUPLOG 2>&1 + echo -e "XXX\n40\nApplying SSL Certificates... \nXXX" + salt-call state.apply ca >> $SETUPLOG 2>&1 + salt-call state.apply ssl >> $SETUPLOG 2>&1 + echo -e "XXX\n50\nConfiguring Firewall... \nXXX" + salt-call state.apply common >> $SETUPLOG 2>&1 + salt-call state.apply firewall >> $SETUPLOG 2>&1 + echo -e "XXX\n70\nInstalling Elastic Components... \nXXX" + salt-call state.apply logstash >> $SETUPLOG 2>&1 + salt-call state.apply elasticsearch >> $SETUPLOG 2>&1 + salt-call state.apply curator >> $SETUPLOG 2>&1 + salt-call state.apply filebeat >> $SETUPLOG 2>&1 + echo -e "XXX\n90\nVerifying Install... \nXXX" + salt-call state.highstate >> $SETUPLOG 2>&1 + checkin_at_boot >> $SETUPLOG 2>&1 + + } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 + GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') + if [[ $GOODSETUP == '0' ]]; then + whiptail_setup_complete + shutdown -r now + else + whiptail_setup_failed + shutdown -r now + fi + + #set_initial_firewall_policy + #saltify + #docker_install + #configure_minion node + #set_node_type + #node_pillar + #copy_minion_pillar nodes + #salt_checkin + # Accept the Salt Key + #accept_salt_key_remote + # Do the big checkin but first let them know it will take a bit. + #salt_checkin_message + #salt_checkin + #checkin_at_boot + + #whiptail_setup_complete + fi + +else + exit +fi diff --git a/setup/whiplash.sh b/setup/whiplash.sh new file mode 100644 index 000000000..1806588ae --- /dev/null +++ b/setup/whiplash.sh @@ -0,0 +1,611 @@ +########################################### +## ## +## Whiptail Menu Section ## +## ## +########################################### + +whiptail_basic_bro() { + + BASICBRO=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter the number of bro processes:" 10 60 $LBPROCS 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_basic_suri() { + + BASICSURI=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter the number of Suricata Processes:" 10 60 $LBPROCS 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_bro_pins() { + + BROPINS=$(whiptail --noitem --title "Pin Bro CPUS" --checklist "Please Select $LBPROCS cores to pin Bro to:" 20 78 12 ${LISTCORES[@]} 3>&1 1>&2 2>&3 ) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + + +} + +whiptail_bro_version() { + + BROVERSION=$(whiptail --title "Security Onion Setup" --radiolist "What tool would you like to use to generate meta data?" 20 78 4 "ZEEK" "Install Zeek (aka Bro)" ON \ + "COMMUNITY" "Install Community NSM" OFF "SURICATA" "SUPER EXPERIMENTAL" OFF 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_bond_nics() { + + BNICS=$(whiptail --title "NIC Setup" --checklist "Please add NICs to the Monitor Interface" 20 78 12 ${FNICS[@]} 3>&1 1>&2 2>&3 ) + + while [ -z "$BNICS" ] + do + BNICS=$(whiptail --title "NIC Setup" --checklist "Please add NICs to the Monitor Interface" 20 78 12 ${FNICS[@]} 3>&1 1>&2 2>&3 ) + done + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_bond_nics_mtu() { + + # Set the MTU on the monitor interface + MTU=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter the MTU for the monitor NICs" 10 60 1500 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_cancel() { + + whiptail --title "Security Onion Setup" --msgbox "Cancelling Setup. No changes have been made." 8 78 + install_cleanup + exit + +} + +whiptail_check_exitstatus() { + + if [ $1 == '1' ]; then + echo "They hit cancel" + whiptail_cancel + fi + +} + +whiptail_create_socore_user() { + + whiptail --title "Security Onion Setup" --msgbox "Set a password for the socore user. This account is used for adding sensors remotely." 8 78 + +} + +whiptail_create_socore_user_password1() { + + COREPASS1=$(whiptail --title "Security Onion Install" --passwordbox \ + "Enter a password for user socore" 10 60 3>&1 1>&2 2>&3) + +} + +whiptail_create_socore_user_password2() { + + COREPASS2=$(whiptail --title "Security Onion Install" --passwordbox \ + "Re-enter a password for user socore" 10 60 3>&1 1>&2 2>&3) + +} + +whiptail_cur_close_days() { + + CURCLOSEDAYS=$(whiptail --title "Security Onion Setup" --inputbox \ + "Please specify the threshold (in days) at which Elasticsearch indices will be closed" 10 60 $CURCLOSEDAYS 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} +whiptail_enable_components() { + COMPONENTS=$(whiptail --title "Security Onion Setup" --checklist \ + "Select Components to install" 20 78 8 \ + "GRAFANA" "Enable Grafana for system monitoring" ON \ + "OSQUERY" "Enable Fleet with osquery" ON \ + "WAZUH" "Enable Wazuh" ON \ + "THEHIVE" "Enable TheHive" ON \ + "PLAYBOOK" "Enable Playbook" ON 3>&1 1>&2 2>&3 ) +} + +whiptail_eval_adv() { + EVALADVANCED=$(whiptail --title "Security Onion Setup" --radiolist \ + "Choose your eval install:" 20 78 4 \ + "BASIC" "Install basic components for evaluation" ON \ + "ADVANCED" "Choose additional components to be installed" OFF 3>&1 1>&2 2>&3 ) +} + +whiptail_eval_adv_warning() { + whiptail --title "Security Onion Setup" --msgbox "Please keep in mind the more services that you enable the more RAM that is required." 8 78 +} + +whiptail_homenet_master() { + + # Ask for the HOME_NET on the master + HNMASTER=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter your HOME_NET separated by ," 10 60 10.0.0.0/8,192.168.0.0/16,172.16.0.0/12 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_homenet_sensor() { + + # Ask to inherit from master + whiptail --title "Security Onion Setup" --yesno "Do you want to inherit the HOME_NET from the Master?" 8 78 + + local exitstatus=$? + if [ $exitstatus == 0 ]; then + HNSENSOR=inherit + else + HNSENSOR=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter your HOME_NET separated by ," 10 60 10.0.0.0/8,192.168.0.0/16,172.16.0.0/12 3>&1 1>&2 2>&3) + fi + +} + +whiptail_install_type() { + + # What kind of install are we doing? + INSTALLTYPE=$(whiptail --title "Security Onion Setup" --radiolist \ + "Choose Install Type:" 20 78 14 \ + "SENSORONLY" "Create a forward only sensor" ON \ + "STORAGENODE" "Add a Storage Hot Node with parsing" OFF \ + "MASTERONLY" "Start a new grid" OFF \ + "PARSINGNODE" "TODO Add a dedicated Parsing Node" OFF \ + "HOTNODE" "TODO Add a Hot Node (Storage Node without Parsing)" OFF \ + "WARMNODE" "TODO Add a Warm Node to an existing Hot or Storage node" OFF \ + "EVALMODE" "Evaluate all the things" OFF \ + "WAZUH" "TODO Stand Alone Wazuh Node" OFF \ + "STRELKA" "TODO Stand Alone Strelka Node" OFF \ + "FLEET" "TODO Stand Alone Fleet OSQuery Node" OFF 3>&1 1>&2 2>&3 ) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_log_size_limit() { + + LOG_SIZE_LIMIT=$(whiptail --title "Security Onion Setup" --inputbox \ + "Please specify the amount of disk space (in GB) you would like to allocate for Elasticsearch data storage. \ + By default, this is set to 85% of the disk space allotted for /nsm." 10 60 $LOG_SIZE_LIMIT 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + + +whiptail_management_nic() { + + MNIC=$(whiptail --title "NIC Setup" --radiolist "Please select your management NIC" 20 78 12 ${NICS[@]} 3>&1 1>&2 2>&3 ) + + while [ -z "$MNIC" ] + do + MNIC=$(whiptail --title "NIC Setup" --radiolist "Please select your management NIC" 20 78 12 ${NICS[@]} 3>&1 1>&2 2>&3 ) + done + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_nids() { + + NIDS=$(whiptail --title "Security Onion Setup" --radiolist \ + "Choose which IDS to run:" 20 78 4 \ + "Suricata" "Suricata 4.X" ON \ + "Snort" "Snort 3.0 Beta" OFF 3>&1 1>&2 2>&3 ) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_oinkcode() { + + OINKCODE=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter your oinkcode" 10 60 XXXXXXX 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_make_changes() { + + whiptail --title "Security Onion Setup" --yesno "We are going to set this machine up as a $INSTALLTYPE. Please hit YES to make changes or NO to cancel." 8 78 + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_management_server() { + + MSRV=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter your Master Server HOSTNAME. It is CASE SENSITIVE!" 10 60 XXXX 3>&1 1>&2 2>&3) + + # See if it resolves. Otherwise prompt to add to host file + TESTHOST=$(host $MSRV) + + if [[ $TESTHOST = *"not found"* ]] || [[ $TESTHOST = *"connection timed out"* ]]; then + add_master_hostfile + fi + + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +# Ask if you want to do advanced setup of the Master +whiptail_master_adv() { + MASTERADV=$(whiptail --title "Security Onion Setup" --radiolist \ + "Choose what type of master install:" 20 78 4 \ + "BASIC" "Install master with recommended settings" ON \ + "ADVANCED" "Do additional configuration to the master" OFF 3>&1 1>&2 2>&3 ) +} + +# Ask which additional components to install +whiptail_master_adv_service_brologs() { + + BLOGS=$(whiptail --title "Security Onion Setup" --checklist "Please Select Logs to Send:" 24 78 12 \ + "conn" "Connection Logging" ON \ + "dce_rpc" "RPC Logs" ON \ + "dhcp" "DHCP Logs" ON \ + "dhcpv6" "DHCP IPv6 Logs" ON \ + "dnp3" "DNP3 Logs" ON \ + "dns" "DNS Logs" ON \ + "dpd" "DPD Logs" ON \ + "files" "Files Logs" ON \ + "ftp" "FTP Logs" ON \ + "http" "HTTP Logs" ON \ + "intel" "Intel Hits Logs" ON \ + "irc" "IRC Chat Logs" ON \ + "kerberos" "Kerberos Logs" ON \ + "modbus" "MODBUS Logs" ON \ + "mqtt" "MQTT Logs" ON \ + "notice" "Zeek Notice Logs" ON \ + "ntlm" "NTLM Logs" ON \ + "openvpn" "OPENVPN Logs" ON \ + "pe" "PE Logs" ON \ + "radius" "Radius Logs" ON \ + "rfb" "RFB Logs" ON \ + "rdp" "RDP Logs" ON \ + "signatures" "Signatures Logs" ON \ + "sip" "SIP Logs" ON \ + "smb_files" "SMB Files Logs" ON \ + "smb_mapping" "SMB Mapping Logs" ON \ + "smtp" "SMTP Logs" ON \ + "snmp" "SNMP Logs" ON \ + "software" "Software Logs" ON \ + "ssh" "SSH Logs" ON \ + "ssl" "SSL Logs" ON \ + "syslog" "Syslog Logs" ON \ + "telnet" "Telnet Logs" ON \ + "tunnel" "Tunnel Logs" ON \ + "weird" "Zeek Weird Logs" ON \ + "mysql" "MySQL Logs" ON \ + "socks" "SOCKS Logs" ON \ + "x509" "x.509 Logs" ON 3>&1 1>&2 2>&3 ) +} + +whiptail_network_notice() { + + whiptail --title "Security Onion Setup" --yesno "Since this is a network install we assume the management interface, DNS, Hostname, etc are already set up. Hit YES to continue." 8 78 + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_node_advanced() { + + NODESETUP=$(whiptail --title "Security Onion Setup" --radiolist \ + "What type of config would you like to use?:" 20 78 4 \ + "NODEBASIC" "Install Storage Node with recommended settings" ON \ + "NODEADVANCED" "Advanced Node Setup" OFF 3>&1 1>&2 2>&3 ) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_node_es_heap() { + + es_heapsize + NODE_ES_HEAP_SIZE=$(whiptail --title "Security Onion Setup" --inputbox \ + "\nEnter ES Heap Size: \n \n(Recommended value is pre-populated)" 10 60 $ES_HEAP_SIZE 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_node_ls_heap() { + + ls_heapsize + NODE_LS_HEAP_SIZE=$(whiptail --title "Security Onion Setup" --inputbox \ + "\nEnter LogStash Heap Size: \n \n(Recommended value is pre-populated)" 10 60 $LS_HEAP_SIZE 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_node_ls_pipeline_worker() { + + LSPIPELINEWORKERS=$(whiptail --title "Security Onion Setup" --inputbox \ + "\nEnter LogStash Pipeline Workers: \n \n(Recommended value is pre-populated)" 10 60 $CPUCORES 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_node_ls_pipline_batchsize() { + + LSPIPELINEBATCH=$(whiptail --title "Security Onion Setup" --inputbox \ + "\nEnter LogStash Pipeline Batch Size: \n \n(Default value is pre-populated)" 10 60 125 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_node_ls_input_threads() { + + LSINPUTTHREADS=$(whiptail --title "Security Onion Setup" --inputbox \ + "\nEnter LogStash Input Threads: \n \n(Default value is pre-populated)" 10 60 1 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_node_ls_input_batch_count() { + + LSINPUTBATCHCOUNT=$(whiptail --title "Security Onion Setup" --inputbox \ + "\nEnter LogStash Input Batch Count: \n \n(Default value is pre-populated)" 10 60 125 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_passwords_dont_match() { + + whiptail --title "Security Onion Setup" --msgbox "Passwords don't match. Please re-enter." 8 78 + +} + +whiptail_patch_name_new_schedule() { + + PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ + "What name do you want to give this OS patch schedule? This schedule needs to be named uniquely. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 105 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + + while [[ -z "$PATCHSCHEDULENAME" ]]; do + whiptail --title "Security Onion Setup" --msgbox "Please enter a name for this OS patch schedule." 8 65 + PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ + "What name do you want to give this OS patch schedule? This schedule needs to be named uniquely. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 105 3>&1 1>&2 2>&3) + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + done + + +} + +whiptail_patch_schedule() { + + # What kind of patch schedule are we doing? + PATCHSCHEDULE=$(whiptail --title "Security Onion Setup" --radiolist \ + "Choose OS patch schedule. This will NOT update Security Onion related tools such as Zeek, Elasticsearch, Kibana, SaltStack, etc." 25 115 5 \ + "Automatic" "Package updates will be installed automatically every 8 hours if available" ON \ + "Manual" "Package updates will need to be installed manually" OFF \ + "Import Schedule" "Enter the name of an existing schedule on the following screen and inherit it" OFF \ + "New Schedule" "Configure and name a new schedule on the following screen" OFF 3>&1 1>&2 2>&3 ) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_patch_schedule_import() { + + unset PATCHSCHEDULENAME + PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter the name of the OS patch schedule you want to inherit. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 60 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + + while [[ -z "$PATCHSCHEDULENAME" ]]; do + whiptail --title "Security Onion Setup" --msgbox "Please enter a name for the OS patch schedule you want to inherit." 8 65 + PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter the name of the OS patch schedule you want to inherit. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 60 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + done + +} + +whiptail_patch_schedule_select_days() { + # Select the days to patch + PATCHSCHEDULEDAYS=($(whiptail --title "Security Onion Setup" --checklist \ + "Which days do you want to apply OS patches?" 20 55 9 \ + "Monday" "" OFF \ + "Tuesday" "" ON \ + "Wednesday" "" OFF \ + "Thursday" "" OFF \ + "Friday" "" OFF \ + "Saturday" "" OFF \ + "Sunday" "" OFF 3>&1 1>&2 2>&3 )) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus +} + +whiptail_patch_schedule_select_hours() { + # Select the hours to patch + PATCHSCHEDULEHOURS=($(whiptail --title "Security Onion Setup" --checklist \ + "At which time, UTC, do you want to apply OS patches on the selected days?" 35 55 26 \ + "00:00" "" OFF \ + "01:00" "" OFF \ + "02:00" "" OFF \ + "03:00" "" OFF \ + "04:00" "" OFF \ + "05:00" "" OFF \ + "06:00" "" OFF \ + "07:00" "" OFF \ + "08:00" "" OFF \ + "09:00" "" OFF \ + "10:00" "" OFF \ + "11:00" "" OFF \ + "12:00" "" OFF \ + "13:00" "" OFF \ + "14:00" "" OFF \ + "15:00" "" ON \ + "16:00" "" OFF \ + "17:00" "" OFF \ + "18:00" "" OFF \ + "19:00" "" OFF \ + "20:00" "" OFF \ + "21:00" "" OFF \ + "22:00" "" OFF \ + "23:00" "" OFF 3>&1 1>&2 2>&3 )) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus +} + +whiptail_rule_setup() { + + # Get pulled pork info + RULESETUP=$(whiptail --title "Security Onion Setup" --radiolist \ + "What IDS rules to use?:" 20 140 4 \ + "ETOPEN" "Emerging Threats Open - no oinkcode required" ON \ + "ETPRO" "Emerging Threats PRO - requires ETPRO oinkcode" OFF \ + "TALOSET" "Snort Subscriber (Talos) ruleset and Emerging Threats NoGPL ruleset - requires Snort Subscriber oinkcode" OFF \ + "TALOS" "Snort Subscriber (Talos) ruleset only and set a Snort Subscriber policy - requires Snort Subscriber oinkcode" OFF 3>&1 1>&2 2>&3 ) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_sensor_config() { + + NSMSETUP=$(whiptail --title "Security Onion Setup" --radiolist \ + "What type of configuration would you like to use?:" 20 78 4 \ + "BASIC" "Install NSM components with recommended settings" ON \ + "ADVANCED" "Configure each component individually" OFF 3>&1 1>&2 2>&3 ) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_set_hostname() { + + HOSTNAME=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter the Hostname you would like to set." 10 60 $HOSTNAME 3>&1 1>&2 2>&3) + + while [[ "$HOSTNAME" == 'localhost' ]] ; do + whiptail --title "Security Onion Setup" --msgbox "Please choose a hostname that isn't localhost." 8 65 + HOSTNAME=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter the Hostname you would like to set." 10 60 $HOSTNAME 3>&1 1>&2 2>&3) + done + + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_setup_complete() { + + whiptail --title "Security Onion Setup" --msgbox "Finished installing this as an $INSTALLTYPE. Press Enter to reboot." 8 78 + install_cleanup + +} + +whiptail_setup_failed() { + + whiptail --title "Security Onion Setup" --msgbox "Install had a problem. Please see $SETUPLOG for details. Press Enter to reboot." 8 78 + install_cleanup + +} + +whiptail_shard_count() { + + SHARDCOUNT=$(whiptail --title "Security Onion Setup" --inputbox \ + "\nEnter ES Shard Count: \n \n(Default value is pre-populated)" 10 60 125 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_suricata_pins() { + + FILTEREDCORES=$(echo ${LISTCORES[@]} ${BROPINS[@]} | tr -d '"' | tr ' ' '\n' | sort | uniq -u | awk '{print $1 " \"" "core" "\""}') + SURIPINS=$(whiptail --noitem --title "Pin Suricata CPUS" --checklist "Please Select $LBPROCS cores to pin Suricata to:" 20 78 12 ${FILTEREDCORES[@]} 3>&1 1>&2 2>&3 ) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_master_updates() { + + MASTERUPDATES=$(whiptail --title "Security Onion Setup" --radiolist \ + "How would you like to download updates for your grid?:" 20 78 4 \ + "MASTER" "Have the master node act as a proxy for OS/Docker updates." ON \ + "OPEN" "Have each node connect to the Internet for updates" OFF 3>&1 1>&2 2>&3 ) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_node_updates() { + + NODEUPDATES=$(whiptail --title "Security Onion Setup" --radiolist \ + "How would you like to download updates for this node?:" 20 78 4 \ + "MASTER" "Download OS/Docker updates from the Master." ON \ + "OPEN" "Download updates directly from the Internet" OFF 3>&1 1>&2 2>&3 ) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + +whiptail_you_sure() { + + whiptail --title "Security Onion Setup" --yesno "Are you sure you want to install Security Onion over the internet?" 8 78 + +} From d16f5c53984d143e57e5bb68ee12c33e3cc9802a Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Thu, 21 Nov 2019 16:10:22 -0500 Subject: [PATCH 098/200] redmine db updated for new custom field - Case Analyzers --- salt/playbook/files/redmine.db | Bin 2207744 -> 2207744 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/salt/playbook/files/redmine.db b/salt/playbook/files/redmine.db index 3477ef3c947f5107a7fd14571c53c7c36d4da742..7d84b5856cd5da11e7431b3bebcefaa6443b4fa1 100644 GIT binary patch delta 66951 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 Date: Thu, 21 Nov 2019 19:11:52 -0500 Subject: [PATCH 099/200] Network setup fixes --- so-setup-network.sh | 97 +++++++++++++++++++++++++++++++++------------ 1 file changed, 72 insertions(+), 25 deletions(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index c32635574..e0e03ed28 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -275,11 +275,11 @@ copy_ssh_key() { } -network_setup() { - echo "Setting up Bond" >> $SETUPLOG 2>&1 +create_sensor_bond() { + echo "Setting up sensor bond" >> $SETUPLOG 2>&1 # Set the MTU - if [ "$NSMSETUP" != 'ADVANCED' ]; then + if [[ $NSMSETUP != 'ADVANCED' ]]; then MTU=1500 fi @@ -304,10 +304,6 @@ network_setup() { # Bring the slave interface up nmcli con up bond0-slave-$BONDNIC >> $SETUPLOG 2>&1 done - # Replace the variable string in the network script - sed -i "s/\$MAININT/${MAININT}/g" ./install_scripts/disable-checksum-offload.sh >> $SETUPLOG 2>&1 - # Copy the checksum offload script to prevent issues with packet capture - cp ./install_scripts/disable-checksum-offload.sh /etc/NetworkManager/dispatcher.d/disable-checksum-offload.sh >> $SETUPLOG 2>&1 } detect_os() { @@ -329,6 +325,19 @@ detect_os() { } +disable_unused_nics() { + for UNUSED_NIC in ${FNICS[@]}; do + # Disable DHCPv4/v6 and autoconnect + nmcli con mod $UNUSED_NIC \ + ipv4.method disabled \ + ipv6.method link-local \ + connection.autoconnect "no" >> $SETUPLOG 2>&1 + + # Flush any existing IPs + ip addr flush $UNUSED_NIC >> $SETUPLOG 2>&1 + done +} + docker_install() { if [ $OS == 'centos' ]; then @@ -402,11 +411,19 @@ eval_mode_hostsfile() { } -filter_nics() { +filter_unused_nics() { + # Set the main NIC as the default grep search string + grep_string=$MNIC - # Filter the NICs that we don't want to see in setup - FNICS=$(ip link | grep -vw $MNIC | awk -F: '$0 !~ "lo|vir|veth|br|docker|wl|^[^0-9]"{print $2 " \"" "Interface" "\"" " OFF"}') + # If we call this function and NICs have already been assigned to the bond interface then add them to the grep search string + if [[ $BNICS ]]; then + for BONDNIC in ${BNICS[@]}; do + grep_string="$grep_string\|$BONDNIC" + done + fi + # Finally, set FNICS to any NICs we aren't using (and ignore interfaces that aren't of use) + FNICS=$(ip link | grep -vwe $grep_string | awk -F: '$0 !~ "lo|vir|veth|br|docker|wl|^[^0-9]"{print $2}') } generate_passwords(){ @@ -604,6 +621,22 @@ minio_generate_keys() { } +network_setup() { + echo "Finishing up network setup" >> $SETUPLOG 2>&1 + + echo "... Disabling unused NICs" >> $SETUPLOG 2>&1 + disable_unused_nics >> $SETUPLOG 2>&1 + + echo "... Setting ONBOOT for management interface" >> $SETUPLOG 2>&1 + nmcli con mod $MAININT connection.autoconnect "yes" >> $SETUPLOG 2>&1 + + echo "... Copying disable-checksum-offload.sh" >> $SETUPLOG 2>&1 + cp ./install_scripts/disable-checksum-offload.sh /etc/NetworkManager/dispatcher.d/disable-checksum-offload.sh >> $SETUPLOG 2>&1 + + echo "... Modifying disable-checksum-offload.sh" >> $SETUPLOG 2>&1 + sed -i "s/\$MAININT/${MAININT}/g" /etc/NetworkManager/dispatcher.d/disable-checksum-offload.sh >> $SETUPLOG 2>&1 +} + node_pillar() { NODEPILLARPATH=$TMP/pillar/nodes @@ -664,7 +697,7 @@ patch_schedule_os_new() { mkdir -p $OSPATCHSCHEDULEDIR fi - echo "patch:" > $OSPATCHSCHEDULE + echo "patch:" > $OSPATCHSCHEDULE echo " os:" >> $OSPATCHSCHEDULE echo " schedule:" >> $OSPATCHSCHEDULE for psd in "${PATCHSCHEDULEDAYS[@]}" @@ -1209,11 +1242,16 @@ whiptail_bro_version() { whiptail_bond_nics() { - BNICS=$(whiptail --title "NIC Setup" --checklist "Please add NICs to the Monitor Interface" 20 78 12 ${FNICS[@]} 3>&1 1>&2 2>&3 ) + local nic_list=() + for FNIC in ${FNICS[@]}; do + nic_list+=($FNIC "Interface" "OFF") + done + + BNICS=$(whiptail --title "NIC Setup" --checklist "Please add NICs to the Monitor Interface" 20 78 12 ${nic_list[@]} 3>&1 1>&2 2>&3 ) while [ -z "$BNICS" ] do - BNICS=$(whiptail --title "NIC Setup" --checklist "Please add NICs to the Monitor Interface" 20 78 12 ${FNICS[@]} 3>&1 1>&2 2>&3 ) + BNICS=$(whiptail --title "NIC Setup" --checklist "Please add NICs to the Monitor Interface" 20 78 12 ${nic_list[@]} 3>&1 1>&2 2>&3 ) done local exitstatus=$? @@ -1992,7 +2030,9 @@ if (whiptail_you_sure); then checkin_at_boot >> $SETUPLOG 2>&1 echo -e "XXX\n95\nVerifying Install... \nXXX" salt-call state.highstate >> $SETUPLOG 2>&1 - + echo -e "XX\n99\nFinishing touches... \nXXX" + filter_unused_nics >> $SETUPLOG 2>&1 + network_setup >> $SETUPLOG 2>&1 } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') if [[ $GOODSETUP == '0' ]]; then @@ -2015,7 +2055,7 @@ if (whiptail_you_sure); then if [ $INSTALLTYPE == 'SENSORONLY' ]; then whiptail_management_nic - filter_nics + filter_unused_nics whiptail_bond_nics whiptail_management_server whiptail_master_updates @@ -2046,7 +2086,7 @@ if (whiptail_you_sure); then #echo -e "XXX\n1\nInstalling pip3... \nXXX" #install_pip3 >> $SETUPLOG 2>&1 echo -e "XXX\n3\nCreating Bond Interface... \nXXX" - network_setup >> $SETUPLOG 2>&1 + create_sensor_bond >> $SETUPLOG 2>&1 echo -e "XXX\n4\nGenerating Sensor Pillar... \nXXX" sensor_pillar >> $SETUPLOG 2>&1 echo "** Generating the patch pillar **" >> $SETUPLOG @@ -2077,6 +2117,9 @@ if (whiptail_you_sure); then echo -e "XXX\n80\nVerifying Install... \nXXX" salt-call state.highstate >> $SETUPLOG 2>&1 checkin_at_boot >> $SETUPLOG 2>&1 + echo -e "XX\n99\nFinishing touches... \nXXX" + filter_unused_nics >> $SETUPLOG 2>&1 + network_setup >> $SETUPLOG 2>&1 } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') if [[ $GOODSETUP == '0' ]]; then @@ -2097,7 +2140,7 @@ if (whiptail_you_sure); then whiptail_management_nic # Filter out the management NIC - filter_nics + filter_unused_nics # Select which NICs are in the bond whiptail_bond_nics @@ -2144,7 +2187,7 @@ if (whiptail_you_sure); then { sleep 0.5 echo -e "XXX\n0\nCreating Bond Interface... \nXXX" - network_setup >> $SETUPLOG 2>&1 + create_sensor_bond >> $SETUPLOG 2>&1 #install_pip3 >> $SETUPLOG 2>&1 echo -e "XXX\n1\nInstalling mysql dependencies for saltstack... \nXXX" salt_install_mysql_deps >> $SETUPLOG 2>&1 @@ -2223,22 +2266,24 @@ if (whiptail_you_sure); then echo -e "XXX\n85\nInstalling filebeat... \nXXX" salt-call state.apply filebeat >> $SETUPLOG 2>&1 salt-call state.apply utility >> $SETUPLOG 2>&1 - echo -e "XXX\n95\nInstalling misc components... \nXXX" + echo -e "XXX\n90\nInstalling misc components... \nXXX" salt-call state.apply schedule >> $SETUPLOG 2>&1 salt-call state.apply soctopus >> $SETUPLOG 2>&1 if [[ $THEHIVE == '1' ]]; then - echo -e "XXX\n96\nInstalling The Hive... \nXXX" + echo -e "XXX\n91\nInstalling The Hive... \nXXX" salt-call state.apply hive >> $SETUPLOG 2>&1 fi if [[ $PLAYBOOK == '1' ]]; then - echo -e "XXX\n97\nInstalling Playbook... \nXXX" + echo -e "XXX\n93\nInstalling Playbook... \nXXX" salt-call state.apply playbook >> $SETUPLOG 2>&1 fi - echo -e "XXX\n98\nSetting checkin to run on boot... \nXXX" + echo -e "XXX\n95\nSetting checkin to run on boot... \nXXX" checkin_at_boot >> $SETUPLOG 2>&1 - echo -e "XXX\n99\nVerifying Setup... \nXXX" + echo -e "XXX\n98\nVerifying Setup... \nXXX" salt-call state.highstate >> $SETUPLOG 2>&1 - + echo -e "XX\n99\nFinishing touches... \nXXX" + filter_unused_nics >> $SETUPLOG 2>&1 + network_setup >> $SETUPLOG 2>&1 } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') if [ $OS == 'centos' ]; then @@ -2342,7 +2387,9 @@ if (whiptail_you_sure); then echo -e "XXX\n90\nVerifying Install... \nXXX" salt-call state.highstate >> $SETUPLOG 2>&1 checkin_at_boot >> $SETUPLOG 2>&1 - + echo -e "XX\n99\nFinishing touches... \nXXX" + filter_unused_nics >> $SETUPLOG 2>&1 + network_setup >> $SETUPLOG 2>&1 } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') if [[ $GOODSETUP == '0' ]]; then From ed9c52925a92bebe75c5f1102fd294c5209a0f70 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Sat, 23 Nov 2019 14:09:41 -0500 Subject: [PATCH 100/200] Playbook - thehive alert tweak --- salt/soctopus/files/templates/generic.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/soctopus/files/templates/generic.template b/salt/soctopus/files/templates/generic.template index e278afa2c..80dd1a762 100644 --- a/salt/soctopus/files/templates/generic.template +++ b/salt/soctopus/files/templates/generic.template @@ -12,7 +12,7 @@ hive_proxies: https: '' hive_alert_config: - title: '{rule[name]}' + title: '{rule[name]} - ' type: 'playbook' source: 'SecurityOnion' description: "`Play:` https://{{es}}/playbook/issues/6000 \n\n `View Event:` \n\n `Raw Data:` {match[message]}" From 185dd7983c525d85dec833c26434b72849d01187 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Tue, 26 Nov 2019 08:28:06 -0500 Subject: [PATCH 101/200] Update so-fleet-setup.sh --- salt/fleet/so-fleet-setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/fleet/so-fleet-setup.sh b/salt/fleet/so-fleet-setup.sh index c20e5a0fc..7054d859d 100644 --- a/salt/fleet/so-fleet-setup.sh +++ b/salt/fleet/so-fleet-setup.sh @@ -7,7 +7,7 @@ fi initpw=$(date +%s | sha256sum | base64 | head -c 16 ; echo) -docker exec so-fleet fleetctl config set --address https://$1:443 --tls-skip-verify +docker exec so-fleet fleetctl config set --address https://$1:443 --tls-skip-verify --url-prefix /fleet docker exec so-fleet fleetctl setup --email $2 --password $initpw docker exec so-fleet fleetctl apply -f /packs/palantir/Fleet/Endpoints/options.yaml From c0d342c46ee31d295ba42cb6f466ca3ad367417a Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 26 Nov 2019 09:54:27 -0500 Subject: [PATCH 102/200] changes for py3 salt on ubuntu --- so-setup-network.sh | 52 +++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index c32635574..474721bef 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -255,10 +255,10 @@ copy_master_config() { copy_minion_tmp_files() { if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then - echo "rsyncing all files in $TMP to /opt/so/saltstack" >> $SETUPLOG 2>&1 + echo "rsyncing all files in $TMP to /opt/so/saltstack" rsync -a -v $TMP/ /opt/so/saltstack/ >> $SETUPLOG 2>&1 else - echo "scp all files in $TMP to master /opt/so/saltstack" >> $SETUPLOG 2>&1 + echo "scp all files in $TMP to master /opt/so/saltstack" scp -prv -i /root/.ssh/so.key $TMP/* socore@$MSRV:/opt/so/saltstack >> $SETUPLOG 2>&1 fi @@ -266,10 +266,12 @@ copy_minion_tmp_files() { copy_ssh_key() { + echo "Generating SSH key" # Generate SSH key mkdir -p /root/.ssh cat /dev/zero | ssh-keygen -f /root/.ssh/so.key -t rsa -q -N "" chown -R $SUDO_USER:$SUDO_USER /root/.ssh + echo "Copying the SSH key to the master" #Copy the key over to the master ssh-copy-id -f -i /root/.ssh/so.key socore@$MSRV @@ -326,6 +328,16 @@ detect_os() { echo "We were unable to determine if you are using a supported OS." >> $SETUPLOG 2>&1 exit fi + echo "Detected OS as: $OS" >> $SETUPLOG 2>&1 + +} + +disable_dnsmasq() { + + if [ -f /etc/NetworkManager/NetworkManager.conf ]; then + echo "Disabling dnsmasq in /etc/NetworkManager/NetworkManager.conf" + sed -e 's/^dns=dnsmasq/#dns=dnsmasq/g' -i /etc/NetworkManager/NetworkManager.conf + fi } @@ -347,7 +359,7 @@ docker_install() { else if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then apt-get update >> $SETUPLOG 2>&1 - apt-get -y install docker-ce >> $SETUPLOG 2>&1 + apt-get -y install docker-ce python3-docker >> $SETUPLOG 2>&1 if [ $INSTALLTYPE != 'EVALMODE' ]; then docker_registry >> $SETUPLOG 2>&1 fi @@ -357,13 +369,11 @@ docker_install() { apt-key add $TMP/gpg/docker.pub >> $SETUPLOG 2>&1 add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" >> $SETUPLOG 2>&1 apt-get update >> $SETUPLOG 2>&1 - apt-get -y install docker-ce >> $SETUPLOG 2>&1 + apt-get -y install docker-ce python3-docker >> $SETUPLOG 2>&1 docker_registry >> $SETUPLOG 2>&1 echo "Restarting Docker" >> $SETUPLOG 2>&1 systemctl restart docker >> $SETUPLOG 2>&1 fi - echo "Using pip3 to install docker-py for salt" - pip3 install docker fi } @@ -471,9 +481,9 @@ install_python3() { echo "Installing Python3" if [ $OS == 'ubuntu' ]; then - apt-get -y install python3-pip gcc python3-dev - elif [ $OS == 'centos' ]; then - yum -y install epel-release python3 + apt-get -y install python3-pip python3-dev +# elif [ $OS == 'centos' ]; then +# yum -y install epel-release python3 fi } @@ -915,7 +925,10 @@ EOF # Copy down the gpg keys and install them from the master mkdir $TMP/gpg + echo "scp the gpg keys and install them from the master" + ls -l $TMP scp socore@$MSRV:/opt/so/gpg/* $TMP/gpg + echo "Using apt-key add to add SALTSTACK-GPG-KEY.pub and GPG-KEY-WAZUH" apt-key add $TMP/gpg/SALTSTACK-GPG-KEY.pub apt-key add $TMP/gpg/GPG-KEY-WAZUH echo "deb http://repo.saltstack.com/apt/ubuntu/$UVER/amd64/latest xenial main" > /etc/apt/sources.list.d/saltstack.list @@ -998,7 +1011,9 @@ salt_install_mysql_deps() { if [ $OS == 'centos' ]; then yum -y install mariadb-devel elif [ $OS == 'ubuntu' ]; then - apt-get -y install libmysqlclient-dev python3-mysqldb + apt-get -y install libmysqlclient-dev gcc + echo "Using pip3 to install mysqlclient for salt" + pip3 install mysqlclient fi } @@ -1893,7 +1908,8 @@ if (whiptail_you_sure); then get_filesystem_root get_filesystem_nsm # Enable Bro Logs - bro_logs_enabled + # comment this out since we already copy this file to the destination that this function writes to + #bro_logs_enabled # Figure out the main IP address get_main_ip @@ -1907,10 +1923,9 @@ if (whiptail_you_sure); then # Install salt and dependencies { sleep 0.5 - #install_pip3 >> $SETUPLOG 2>&1 + install_python3 >> $SETUPLOG 2>&1 echo -e "XXX\n1\nInstalling and configuring Salt... \nXXX" echo " ** Installing Salt and Dependencies **" >> $SETUPLOG - salt_install_mysql_deps >> $SETUPLOG 2>&1 saltify >> $SETUPLOG 2>&1 echo -e "XXX\n5\nInstalling Docker... \nXXX" docker_install >> $SETUPLOG 2>&1 @@ -1919,6 +1934,7 @@ if (whiptail_you_sure); then configure_minion master >> $SETUPLOG 2>&1 echo " ** Installing Salt Master **" >> $SETUPLOG install_master >> $SETUPLOG 2>&1 + salt_install_mysql_deps >> $SETUPLOG 2>&1 salt_master_directories >> $SETUPLOG 2>&1 update_sudoers >> $SETUPLOG 2>&1 chown_salt_master >> $SETUPLOG 2>&1 @@ -2038,7 +2054,7 @@ if (whiptail_you_sure); then mkdir -p /nsm get_filesystem_root get_filesystem_nsm - copy_ssh_key + copy_ssh_key >> $SETUPLOG 2>&1 { sleep 0.5 echo -e "XXX\n0\nSetting Initial Firewall Policy... \nXXX" @@ -2145,15 +2161,15 @@ if (whiptail_you_sure); then sleep 0.5 echo -e "XXX\n0\nCreating Bond Interface... \nXXX" network_setup >> $SETUPLOG 2>&1 - #install_pip3 >> $SETUPLOG 2>&1 - echo -e "XXX\n1\nInstalling mysql dependencies for saltstack... \nXXX" - salt_install_mysql_deps >> $SETUPLOG 2>&1 + install_python3 >> $SETUPLOG 2>&1 echo -e "XXX\n1\nInstalling saltstack... \nXXX" saltify >> $SETUPLOG 2>&1 echo -e "XXX\n3\nInstalling docker... \nXXX" docker_install >> $SETUPLOG 2>&1 echo -e "XXX\n5\nInstalling master code... \nXXX" install_master >> $SETUPLOG 2>&1 + echo -e "XXX\n1\nInstalling mysql dependencies for saltstack... \nXXX" + salt_install_mysql_deps >> $SETUPLOG 2>&1 echo -e "XXX\n6\nCopying salt code... \nXXX" salt_master_directories >> $SETUPLOG 2>&1 echo -e "XXX\n6\nupdating suduers... \nXXX" @@ -2305,7 +2321,7 @@ if (whiptail_you_sure); then mkdir -p /nsm get_filesystem_root get_filesystem_nsm - copy_ssh_key + copy_ssh_key >> $SETUPLOG 2>&1 { sleep 0.5 echo -e "XXX\n0\nSetting Initial Firewall Policy... \nXXX" From f36d7b692670a4087bb2b0561357587e755c1a97 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Tue, 26 Nov 2019 10:28:48 -0500 Subject: [PATCH 103/200] Update so-fleet-setup.sh --- salt/fleet/so-fleet-setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/fleet/so-fleet-setup.sh b/salt/fleet/so-fleet-setup.sh index 7054d859d..32bbddbe7 100644 --- a/salt/fleet/so-fleet-setup.sh +++ b/salt/fleet/so-fleet-setup.sh @@ -29,7 +29,7 @@ docker run \ --rm \ --mount type=bind,source=/opt/so/conf/fleet/packages,target=/output \ --mount type=bind,source=/etc/pki/launcher.crt,target=/var/launcher/launcher.crt \ - docker.io/soshybridhunter/so-fleet-launcher:HH1.1.0 "$esecret" "$1":8080/fleet + docker.io/soshybridhunter/so-fleet-launcher:HH1.1.0 "$esecret" "$1":8080 cp /opt/so/conf/fleet/packages/launcher.* /opt/so/saltstack/salt/launcher/packages/ #Update timestamp on packages webpage From 130eceab14201360425a004c6c48a6fdf3897e66 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 2 Dec 2019 11:16:24 -0500 Subject: [PATCH 104/200] Setup Changes --- setup/functions.sh | 189 +++++++++++++++++++---------- setup/so-setup.sh | 13 +- setup/{whiplash.sh => whiptail.sh} | 8 +- 3 files changed, 143 insertions(+), 67 deletions(-) rename setup/{whiplash.sh => whiptail.sh} (98%) diff --git a/setup/functions.sh b/setup/functions.sh index 184750d61..ccc1a76d3 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # Functions accept_salt_key_local() { @@ -16,6 +18,14 @@ accept_salt_key_remote() { } +add_admin_user() { + + # Add an admin user with full sudo rights if this is an ISO install. + useradd $ADMINUSER && echo $ADMINUSER:$ADMINPASS1 | chpasswd --crypt-method=SHA512 + usermod -aG wheel $ADMINUSER + +} + add_master_hostfile() { echo "Checking if I can resolve master. If not add to hosts file" >> $SETUPLOG 2>&1 # Pop up an input to get the IP address @@ -49,7 +59,7 @@ add_socore_user_notmaster() { } # Create an auth pillar so that passwords survive re-install -auth_pillar(){ +auth_pillar() { if [ ! -f /opt/so/saltstack/pillar/auth.sls ]; then echo "Creating Auth Pillar" >> $SETUPLOG 2>&1 @@ -128,9 +138,14 @@ calculate_useable_cores() { } -checkin_at_boot() { - echo "Enabling checkin at boot" >> $SETUPLOG 2>&1 - echo "startup_states: highstate" >> /etc/salt/minion +check_admin_pass() { + + if [ $ADMINPASS1 == $ADMINPASS2 ]; then + APMATCH=yes + else + whiptail_passwords_dont_match + fi + } check_hive_init_then_reboot() { @@ -160,6 +175,13 @@ check_socore_pass() { } +checkin_at_boot() { + + echo "Enabling checkin at boot" >> $SETUPLOG 2>&1 + echo "startup_states: highstate" >> /etc/salt/minion + +} + chown_salt_master() { echo "Chown the salt dirs on the master for socore" >> $SETUPLOG 2>&1 @@ -168,6 +190,7 @@ chown_salt_master() { } clear_master() { + # Clear out the old master public key in case this is a re-install. # This only happens if you re-install the master. if [ -f /etc/salt/pki/minion/minion_master.pub ]; then @@ -213,7 +236,12 @@ configure_minion() { copy_master_config() { # Copy the master config template to the proper directory - cp files/master /etc/salt/master + if [ $ISOINSTALL == '1' ]; then + cp /root/SecurityOnion/files/master /etc/salt/master + else + cp ../files/master /etc/salt/master + fi + # Restart the service so it picks up the changes -TODO Enable service on CentOS service salt-master restart @@ -229,7 +257,7 @@ copy_minion_tmp_files() { scp -prv -i /root/.ssh/so.key $TMP/* socore@$MSRV:/opt/so/saltstack >> $SETUPLOG 2>&1 fi - } +} copy_ssh_key() { @@ -242,50 +270,40 @@ copy_ssh_key() { } -network_setup() { - echo "Setting up Bond" >> $SETUPLOG 2>&1 - - # Set the MTU - if [ "$NSMSETUP" != 'ADVANCED' ]; then - MTU=1500 - fi - - # Create the bond interface - nmcli con add ifname bond0 con-name "bond0" type bond mode 0 -- \ - ipv4.method disabled \ - ipv6.method link-local \ - ethernet.mtu $MTU \ - connection.autoconnect "yes" >> $SETUPLOG 2>&1 - - for BNIC in ${BNICS[@]}; do - # Strip the quotes from the NIC names - BONDNIC="$(echo -e "${BNIC}" | tr -d '"')" - # Turn off various offloading settings for the interface - for i in rx tx sg tso ufo gso gro lro; do - ethtool -K $BONDNIC $i off >> $SETUPLOG 2>&1 - done - # Create the slave interface and assign it to the bond - nmcli con add type ethernet ifname $BONDNIC con-name "bond0-slave-$BONDNIC" master bond0 -- \ - ethernet.mtu $MTU \ - connection.autoconnect "yes" >> $SETUPLOG 2>&1 - # Bring the slave interface up - nmcli con up bond0-slave-$BONDNIC >> $SETUPLOG 2>&1 - done - # Replace the variable string in the network script - sed -i "s/\$MAININT/${MAININT}/g" ./install_scripts/disable-checksum-offload.sh >> $SETUPLOG 2>&1 - # Copy the checksum offload script to prevent issues with packet capture - cp ./install_scripts/disable-checksum-offload.sh /etc/NetworkManager/dispatcher.d/disable-checksum-offload.sh >> $SETUPLOG 2>&1 -} - detect_os() { # Detect Base OS echo "Detecting Base OS" >> $SETUPLOG 2>&1 if [ -f /etc/redhat-release ]; then OS=centos + if grep -q "CentOS Linux release 7" /etc/redhat-release; then + OSVER=7 + elif grep -q "CentOS Linux release 8" /etc/redhat-release; then + OSVER=8 + echo "We currently do not support CentOS $OSVER but we are working on it!" + exit + else + echo "We do not support the version of CentOS you are trying to use" + exit + fi + + # Install bind-utils so the host command exists yum -y install bind-utils + + elif [ -f /etc/os-release ]; then OS=ubuntu + if grep -q "UBUNTU_CODENAME=bionic" /etc/os-release; then + OSVER=bionic + echo "We currently don't support Ubuntu $OSVER but we are working on it!" + exit + elif grep -q "UBUNTU_CODENAME=xenial" /etc/os-release; then + OSVER=xenial + else + echo "We do not support your current version of Ubuntu" + exit + fi + # Install netowrk manager so we can do interface stuff apt install -y network-manager /bin/systemctl enable network-manager /bin/systemctl start network-manager @@ -296,6 +314,15 @@ detect_os() { } + +disable_onion_user() { + + # Disable the default account cause security. + usermod -L onion + +} + + docker_install() { if [ $OS == 'centos' ]; then @@ -363,12 +390,6 @@ es_heapsize() { } -eval_mode_hostsfile() { - - echo "127.0.0.1 $HOSTNAME" >> /etc/hosts - -} - filter_nics() { # Filter the NICs that we don't want to see in setup @@ -567,6 +588,41 @@ minio_generate_keys() { } +network_setup() { + echo "Setting up Bond" >> $SETUPLOG 2>&1 + + # Set the MTU + if [ "$NSMSETUP" != 'ADVANCED' ]; then + MTU=1500 + fi + + # Create the bond interface + nmcli con add ifname bond0 con-name "bond0" type bond mode 0 -- \ + ipv4.method disabled \ + ipv6.method link-local \ + ethernet.mtu $MTU \ + connection.autoconnect "yes" >> $SETUPLOG 2>&1 + + for BNIC in ${BNICS[@]}; do + # Strip the quotes from the NIC names + BONDNIC="$(echo -e "${BNIC}" | tr -d '"')" + # Turn off various offloading settings for the interface + for i in rx tx sg tso ufo gso gro lro; do + ethtool -K $BONDNIC $i off >> $SETUPLOG 2>&1 + done + # Create the slave interface and assign it to the bond + nmcli con add type ethernet ifname $BONDNIC con-name "bond0-slave-$BONDNIC" master bond0 -- \ + ethernet.mtu $MTU \ + connection.autoconnect "yes" >> $SETUPLOG 2>&1 + # Bring the slave interface up + nmcli con up bond0-slave-$BONDNIC >> $SETUPLOG 2>&1 + done + # Replace the variable string in the network script + sed -i "s/\$MAININT/${MAININT}/g" ./install_scripts/disable-checksum-offload.sh >> $SETUPLOG 2>&1 + # Copy the checksum offload script to prevent issues with packet capture + cp ../install_scripts/disable-checksum-offload.sh /etc/NetworkManager/dispatcher.d/disable-checksum-offload.sh >> $SETUPLOG 2>&1 +} + node_pillar() { NODEPILLARPATH=$TMP/pillar/nodes @@ -923,18 +979,6 @@ salt_checkin() { } -salt_checkin_message() { - - # Warn the user that this might take a while - echo "####################################################" - echo "## ##" - echo "## Applying and Installing everything ##" - echo "## (This will take a while) ##" - echo "## ##" - echo "####################################################" - -} - salt_firstcheckin() { #First Checkin @@ -949,10 +993,17 @@ salt_master_directories() { mkdir -p /opt/so/saltstack/pillar # Copy over the salt code and templates - cp -R pillar/* /opt/so/saltstack/pillar/ + if [ $ISOINSTALL == '1' ]; then + cp /root/SecurityOnion/pillar/* /opt/so/saltstack/pillar/ + cp /root/SecurityOnion/salt/* /opt/so/saltstack/salt/ + else + # if ISO /root/SecurityOnion/blah + cp -R ../pillar/* /opt/so/saltstack/pillar/ + cp -R ../salt/* /opt/so/saltstack/salt/ + fi + chmod +x /opt/so/saltstack/pillar/firewall/addfirewall.sh chmod +x /opt/so/saltstack/pillar/data/addtotab.sh - cp -R salt/* /opt/so/saltstack/salt/ } @@ -1075,6 +1126,22 @@ set_initial_firewall_policy() { } +# Set up the management interface on the ISO +set_management_interface() { + + if [ $ADDRESSTYPE == 'DHCP' ]; then + /usr/bin/nmcli con up $MNIC + /usr/bin/nmcli con mod $MNIC connection.autoconnect yes + else + # Set Static IP + /usr/bin/nmcli con mod $MNIC ipv4.addresses $MIP/$MMASK ipv4.gateway $MGATEWAY \ + ipv4.dns $MDNS ipv4.dns-search $MSEARCH ipv4.method manual + /usr/bin/nmcli con up $MNIC + /usr/bin/nmcli con mod $MNIC connection.autoconnect yes + fi + +} + set_node_type() { # Determine the node type based on whiplash choice diff --git a/setup/so-setup.sh b/setup/so-setup.sh index 837cf6d6e..a70361976 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -17,7 +17,16 @@ # Source the other pieces of the setup source functions.sh -source whiplash.sh +source whiptail.sh + +# See if this is an ISO install +OPTIONS=$1 + +if [[ $OPTIONS = 'iso' ]]; then + ISOINSTALL=1 +else + ISOINSTALL=0 +fi # Global Variables HOSTNAME=$(cat /etc/hostname) @@ -49,8 +58,6 @@ if (whiptail_you_sure); then # Create a temp dir to get started install_prep - # Determine if this is a network install or ISO install - # Let folks know they need their management interface already set up. whiptail_network_notice diff --git a/setup/whiplash.sh b/setup/whiptail.sh similarity index 98% rename from setup/whiplash.sh rename to setup/whiptail.sh index 1806588ae..637ac8cdd 100644 --- a/setup/whiplash.sh +++ b/setup/whiptail.sh @@ -36,8 +36,10 @@ whiptail_bro_pins() { whiptail_bro_version() { - BROVERSION=$(whiptail --title "Security Onion Setup" --radiolist "What tool would you like to use to generate meta data?" 20 78 4 "ZEEK" "Install Zeek (aka Bro)" ON \ - "COMMUNITY" "Install Community NSM" OFF "SURICATA" "SUPER EXPERIMENTAL" OFF 3>&1 1>&2 2>&3) + BROVERSION=$(whiptail --title "Security Onion Setup" \ + --radiolist "What tool would you like to use to generate meta data?" 20 78 4 \ + "ZEEK" "Install Zeek (aka Bro)" ON \ + "SURICATA" "SUPER EXPERIMENTAL" OFF 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -170,10 +172,10 @@ whiptail_install_type() { "SENSORONLY" "Create a forward only sensor" ON \ "STORAGENODE" "Add a Storage Hot Node with parsing" OFF \ "MASTERONLY" "Start a new grid" OFF \ + "EVALMODE" "Evaluate all the things" OFF \ "PARSINGNODE" "TODO Add a dedicated Parsing Node" OFF \ "HOTNODE" "TODO Add a Hot Node (Storage Node without Parsing)" OFF \ "WARMNODE" "TODO Add a Warm Node to an existing Hot or Storage node" OFF \ - "EVALMODE" "Evaluate all the things" OFF \ "WAZUH" "TODO Stand Alone Wazuh Node" OFF \ "STRELKA" "TODO Stand Alone Strelka Node" OFF \ "FLEET" "TODO Stand Alone Fleet OSQuery Node" OFF 3>&1 1>&2 2>&3 ) From e57715a5ec0e62f06ba308b65441458ba1831ada Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 3 Dec 2019 10:39:48 -0500 Subject: [PATCH 105/200] unbutu py3 salt install changes --- so-setup-network.sh | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index 474721bef..b31d55a24 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -255,11 +255,13 @@ copy_master_config() { copy_minion_tmp_files() { if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then - echo "rsyncing all files in $TMP to /opt/so/saltstack" - rsync -a -v $TMP/ /opt/so/saltstack/ >> $SETUPLOG 2>&1 + echo "rsyncing pillar and salt files in $TMP to /opt/so/saltstack" + rsync -a -v $TMP/pillar/ /opt/so/saltstack/pillar/ >> $SETUPLOG 2>&1 + rsync -a -v $TMP/salt/ /opt/so/saltstack/salt/ >> $SETUPLOG 2>&1 else - echo "scp all files in $TMP to master /opt/so/saltstack" - scp -prv -i /root/.ssh/so.key $TMP/* socore@$MSRV:/opt/so/saltstack >> $SETUPLOG 2>&1 + echo "scp pillar and salt files in $TMP to master /opt/so/saltstack" + scp -prv -i /root/.ssh/so.key $TMP/pillar/* socore@$MSRV:/opt/so/saltstack/pillar >> $SETUPLOG 2>&1 + scp -prv -i /root/.ssh/so.key $TMP/salt/* socore@$MSRV:/opt/so/saltstack/salt >> $SETUPLOG 2>&1 fi } @@ -713,8 +715,8 @@ saltify() { if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then yum -y install wget https://repo.saltstack.com/py3/redhat/salt-py3-repo-latest-2.el7.noarch.rpm - cp /etc/yum.repos.d/salt-latest.repo /etc/yum.repos.d/salt-2019-2.repo - sed -i 's/latest/2019.2/g' /etc/yum.repos.d/salt-2019-2.repo + cp /etc/yum.repos.d/salt-py3-latest.repo /etc/yum.repos.d/salt-py3-2019-2.repo + sed -i 's/latest/2019.2/g' /etc/yum.repos.d/salt-py3-2019-2.repo # Download Ubuntu Keys in case master updates = 1 mkdir -p /opt/so/gpg wget --inet4-only -O /opt/so/gpg/SALTSTACK-GPG-KEY.pub https://repo.saltstack.com/apt/ubuntu/16.04/amd64/latest/SALTSTACK-GPG-KEY.pub @@ -926,15 +928,18 @@ EOF # Copy down the gpg keys and install them from the master mkdir $TMP/gpg echo "scp the gpg keys and install them from the master" - ls -l $TMP - scp socore@$MSRV:/opt/so/gpg/* $TMP/gpg + scp -v -i /root/.ssh/so.key socore@$MSRV:/opt/so/gpg/* $TMP/gpg echo "Using apt-key add to add SALTSTACK-GPG-KEY.pub and GPG-KEY-WAZUH" apt-key add $TMP/gpg/SALTSTACK-GPG-KEY.pub apt-key add $TMP/gpg/GPG-KEY-WAZUH - echo "deb http://repo.saltstack.com/apt/ubuntu/$UVER/amd64/latest xenial main" > /etc/apt/sources.list.d/saltstack.list + echo "deb http://repo.saltstack.com/py3/ubuntu/$UVER/amd64/latest xenial main" > /etc/apt/sources.list.d/saltstack.list echo "deb https://packages.wazuh.com/3.x/apt/ stable main" | tee /etc/apt/sources.list.d/wazuh.list # Initialize the new repos apt-get update >> $SETUPLOG 2>&1 + echo "Installing libssl-dev for M2Crypto" + apt-get -y install libssl-dev + echo "Using pip3 to install M2Crypto for Salt" + pip3 install M2Crypto # Need to add python dateutil here apt-get -y install salt-minion=2019.2.2+ds-1 salt-common=2019.2.2+ds-1 >> $SETUPLOG 2>&1 apt-mark hold salt-minion salt-common @@ -2059,8 +2064,8 @@ if (whiptail_you_sure); then sleep 0.5 echo -e "XXX\n0\nSetting Initial Firewall Policy... \nXXX" set_initial_firewall_policy >> $SETUPLOG 2>&1 - #echo -e "XXX\n1\nInstalling pip3... \nXXX" - #install_pip3 >> $SETUPLOG 2>&1 + echo -e "XXX\n1\nInstalling pip3... \nXXX" + install_python3 >> $SETUPLOG 2>&1 echo -e "XXX\n3\nCreating Bond Interface... \nXXX" network_setup >> $SETUPLOG 2>&1 echo -e "XXX\n4\nGenerating Sensor Pillar... \nXXX" @@ -2326,8 +2331,8 @@ if (whiptail_you_sure); then sleep 0.5 echo -e "XXX\n0\nSetting Initial Firewall Policy... \nXXX" set_initial_firewall_policy >> $SETUPLOG 2>&1 - #echo -e "XXX\n1\nInstalling pip3... \nXXX" - #install_pip3 >> $SETUPLOG 2>&1 + echo -e "XXX\n1\nInstalling pip3... \nXXX" + install_python3 >> $SETUPLOG 2>&1 echo -e "XXX\n5\nInstalling Salt Packages... \nXXX" saltify >> $SETUPLOG 2>&1 echo -e "XXX\n20\nInstalling Docker... \nXXX" From 67e7fa19c2a545a5daf5f1abfc65d4fcc01686b4 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 3 Dec 2019 16:05:35 -0500 Subject: [PATCH 106/200] New Setup Script Layout --- setup/functions.sh | 176 +++- setup/so-setup.sh | 63 +- setup/whiptail.sh | 38 +- so-setup-network.sh | 2431 +------------------------------------------ 4 files changed, 185 insertions(+), 2523 deletions(-) diff --git a/setup/functions.sh b/setup/functions.sh index ccc1a76d3..3c9c65896 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -1,6 +1,19 @@ #!/bin/bash -# Functions +# Copyright 2014,2015,2016,2017,2018,2019 Security Onion Solutions, LLC + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . accept_salt_key_local() { echo "Accept the key locally on the master" >> $SETUPLOG 2>&1 @@ -59,7 +72,7 @@ add_socore_user_notmaster() { } # Create an auth pillar so that passwords survive re-install -auth_pillar() { +auth_pillar(){ if [ ! -f /opt/so/saltstack/pillar/auth.sls ]; then echo "Creating Auth Pillar" >> $SETUPLOG 2>&1 @@ -176,10 +189,8 @@ check_socore_pass() { } checkin_at_boot() { - echo "Enabling checkin at boot" >> $SETUPLOG 2>&1 echo "startup_states: highstate" >> /etc/salt/minion - } chown_salt_master() { @@ -190,7 +201,6 @@ chown_salt_master() { } clear_master() { - # Clear out the old master public key in case this is a re-install. # This only happens if you re-install the master. if [ -f /etc/salt/pki/minion/minion_master.pub ]; then @@ -250,26 +260,61 @@ copy_master_config() { copy_minion_tmp_files() { if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then - echo "rsyncing all files in $TMP to /opt/so/saltstack" >> $SETUPLOG 2>&1 - rsync -a -v $TMP/ /opt/so/saltstack/ >> $SETUPLOG 2>&1 + echo "rsyncing pillar and salt files in $TMP to /opt/so/saltstack" + rsync -a -v $TMP/pillar/ /opt/so/saltstack/pillar/ >> $SETUPLOG 2>&1 + rsync -a -v $TMP/salt/ /opt/so/saltstack/salt/ >> $SETUPLOG 2>&1 else - echo "scp all files in $TMP to master /opt/so/saltstack" >> $SETUPLOG 2>&1 - scp -prv -i /root/.ssh/so.key $TMP/* socore@$MSRV:/opt/so/saltstack >> $SETUPLOG 2>&1 + echo "scp pillar and salt files in $TMP to master /opt/so/saltstack" + scp -prv -i /root/.ssh/so.key $TMP/pillar/* socore@$MSRV:/opt/so/saltstack/pillar >> $SETUPLOG 2>&1 + scp -prv -i /root/.ssh/so.key $TMP/salt/* socore@$MSRV:/opt/so/saltstack/salt >> $SETUPLOG 2>&1 fi -} + } copy_ssh_key() { + echo "Generating SSH key" # Generate SSH key mkdir -p /root/.ssh cat /dev/zero | ssh-keygen -f /root/.ssh/so.key -t rsa -q -N "" chown -R $SUDO_USER:$SUDO_USER /root/.ssh + echo "Copying the SSH key to the master" #Copy the key over to the master ssh-copy-id -f -i /root/.ssh/so.key socore@$MSRV } +create_sensor_bond() { + echo "Setting up sensor bond" >> $SETUPLOG 2>&1 + + # Set the MTU + if [[ $NSMSETUP != 'ADVANCED' ]]; then + MTU=1500 + fi + + # Create the bond interface + nmcli con add ifname bond0 con-name "bond0" type bond mode 0 -- \ + ipv4.method disabled \ + ipv6.method link-local \ + ethernet.mtu $MTU \ + connection.autoconnect "yes" >> $SETUPLOG 2>&1 + + for BNIC in ${BNICS[@]}; do + # Strip the quotes from the NIC names + BONDNIC="$(echo -e "${BNIC}" | tr -d '"')" + # Turn off various offloading settings for the interface + for i in rx tx sg tso ufo gso gro lro; do + ethtool -K $BONDNIC $i off >> $SETUPLOG 2>&1 + done + # Create the slave interface and assign it to the bond + nmcli con add type ethernet ifname $BONDNIC con-name "bond0-slave-$BONDNIC" master bond0 -- \ + ethernet.mtu $MTU \ + connection.autoconnect "yes" >> $SETUPLOG 2>&1 + # Bring the slave interface up + nmcli con up bond0-slave-$BONDNIC >> $SETUPLOG 2>&1 + done +} + detect_os() { # Detect Base OS @@ -303,7 +348,7 @@ detect_os() { echo "We do not support your current version of Ubuntu" exit fi - # Install netowrk manager so we can do interface stuff + # Install network manager so we can do interface stuff apt install -y network-manager /bin/systemctl enable network-manager /bin/systemctl start network-manager @@ -314,6 +359,14 @@ detect_os() { } +#disable_dnsmasq() { + +# if [ -f /etc/NetworkManager/NetworkManager.conf ]; then +# echo "Disabling dnsmasq in /etc/NetworkManager/NetworkManager.conf" +# sed -e 's/^dns=dnsmasq/#dns=dnsmasq/g' -i /etc/NetworkManager/NetworkManager.conf +# fi + +#} disable_onion_user() { @@ -322,6 +375,18 @@ disable_onion_user() { } +disable_unused_nics() { + for UNUSED_NIC in ${FNICS[@]}; do + # Disable DHCPv4/v6 and autoconnect + nmcli con mod $UNUSED_NIC \ + ipv4.method disabled \ + ipv6.method link-local \ + connection.autoconnect "no" >> $SETUPLOG 2>&1 + + # Flush any existing IPs + ip addr flush $UNUSED_NIC >> $SETUPLOG 2>&1 + done +} docker_install() { @@ -341,7 +406,7 @@ docker_install() { else if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then apt-get update >> $SETUPLOG 2>&1 - apt-get -y install docker-ce >> $SETUPLOG 2>&1 + apt-get -y install docker-ce python3-docker >> $SETUPLOG 2>&1 if [ $INSTALLTYPE != 'EVALMODE' ]; then docker_registry >> $SETUPLOG 2>&1 fi @@ -351,13 +416,11 @@ docker_install() { apt-key add $TMP/gpg/docker.pub >> $SETUPLOG 2>&1 add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" >> $SETUPLOG 2>&1 apt-get update >> $SETUPLOG 2>&1 - apt-get -y install docker-ce >> $SETUPLOG 2>&1 + apt-get -y install docker-ce python3-docker >> $SETUPLOG 2>&1 docker_registry >> $SETUPLOG 2>&1 echo "Restarting Docker" >> $SETUPLOG 2>&1 systemctl restart docker >> $SETUPLOG 2>&1 fi - echo "Using pip3 to install docker-py for salt" - pip3 install docker fi } @@ -390,11 +453,19 @@ es_heapsize() { } -filter_nics() { +filter_unused_nics() { + # Set the main NIC as the default grep search string + grep_string=$MNIC - # Filter the NICs that we don't want to see in setup - FNICS=$(ip link | grep -vw $MNIC | awk -F: '$0 !~ "lo|vir|veth|br|docker|wl|^[^0-9]"{print $2 " \"" "Interface" "\"" " OFF"}') + # If we call this function and NICs have already been assigned to the bond interface then add them to the grep search string + if [[ $BNICS ]]; then + for BONDNIC in ${BNICS[@]}; do + grep_string="$grep_string\|$BONDNIC" + done + fi + # Finally, set FNICS to any NICs we aren't using (and ignore interfaces that aren't of use) + FNICS=$(ip link | grep -vwe $grep_string | awk -F: '$0 !~ "lo|vir|veth|br|docker|wl|^[^0-9]"{print $2}') } generate_passwords(){ @@ -403,6 +474,7 @@ generate_passwords(){ FLEETPASS=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) HIVEKEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) CORTEXKEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) + CORTEXORGUSERKEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) SENSORONIKEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) } @@ -458,9 +530,9 @@ install_python3() { echo "Installing Python3" if [ $OS == 'ubuntu' ]; then - apt-get -y install python3-pip gcc python3-dev - elif [ $OS == 'centos' ]; then - yum -y install epel-release python3 + apt-get -y install python3-pip python3-dev +# elif [ $OS == 'centos' ]; then +# yum -y install epel-release python3 fi } @@ -570,6 +642,9 @@ master_static() { echo " cortexuser: cortexadmin" >> /opt/so/saltstack/pillar/static.sls echo " cortexpassword: cortexchangeme" >> /opt/so/saltstack/pillar/static.sls echo " cortexkey: $CORTEXKEY" >> /opt/so/saltstack/pillar/static.sls + echo " cortexorgname: SecurityOnion" >> /opt/so/saltstack/pillar/static.sls + echo " cortexorguser: soadmin" >> /opt/so/saltstack/pillar/static.sls + echo " cortexorguserkey: $CORTEXORGUSERKEY" >> /opt/so/saltstack/pillar/static.sls echo " fleetsetup: 0" >> /opt/so/saltstack/pillar/static.sls echo " sensoronikey: $SENSORONIKEY" >> /opt/so/saltstack/pillar/static.sls if [[ $MASTERUPDATES == 'MASTER' ]]; then @@ -589,38 +664,19 @@ minio_generate_keys() { } network_setup() { - echo "Setting up Bond" >> $SETUPLOG 2>&1 + echo "Finishing up network setup" >> $SETUPLOG 2>&1 - # Set the MTU - if [ "$NSMSETUP" != 'ADVANCED' ]; then - MTU=1500 - fi + echo "... Disabling unused NICs" >> $SETUPLOG 2>&1 + disable_unused_nics >> $SETUPLOG 2>&1 - # Create the bond interface - nmcli con add ifname bond0 con-name "bond0" type bond mode 0 -- \ - ipv4.method disabled \ - ipv6.method link-local \ - ethernet.mtu $MTU \ - connection.autoconnect "yes" >> $SETUPLOG 2>&1 + echo "... Setting ONBOOT for management interface" >> $SETUPLOG 2>&1 + nmcli con mod $MAININT connection.autoconnect "yes" >> $SETUPLOG 2>&1 - for BNIC in ${BNICS[@]}; do - # Strip the quotes from the NIC names - BONDNIC="$(echo -e "${BNIC}" | tr -d '"')" - # Turn off various offloading settings for the interface - for i in rx tx sg tso ufo gso gro lro; do - ethtool -K $BONDNIC $i off >> $SETUPLOG 2>&1 - done - # Create the slave interface and assign it to the bond - nmcli con add type ethernet ifname $BONDNIC con-name "bond0-slave-$BONDNIC" master bond0 -- \ - ethernet.mtu $MTU \ - connection.autoconnect "yes" >> $SETUPLOG 2>&1 - # Bring the slave interface up - nmcli con up bond0-slave-$BONDNIC >> $SETUPLOG 2>&1 - done - # Replace the variable string in the network script - sed -i "s/\$MAININT/${MAININT}/g" ./install_scripts/disable-checksum-offload.sh >> $SETUPLOG 2>&1 - # Copy the checksum offload script to prevent issues with packet capture - cp ../install_scripts/disable-checksum-offload.sh /etc/NetworkManager/dispatcher.d/disable-checksum-offload.sh >> $SETUPLOG 2>&1 + echo "... Copying disable-checksum-offload.sh" >> $SETUPLOG 2>&1 + cp ./install_scripts/disable-checksum-offload.sh /etc/NetworkManager/dispatcher.d/disable-checksum-offload.sh >> $SETUPLOG 2>&1 + + echo "... Modifying disable-checksum-offload.sh" >> $SETUPLOG 2>&1 + sed -i "s/\$MAININT/${MAININT}/g" /etc/NetworkManager/dispatcher.d/disable-checksum-offload.sh >> $SETUPLOG 2>&1 } node_pillar() { @@ -683,7 +739,7 @@ patch_schedule_os_new() { mkdir -p $OSPATCHSCHEDULEDIR fi - echo "patch:" > $OSPATCHSCHEDULE + echo "patch:" > $OSPATCHSCHEDULE echo " os:" >> $OSPATCHSCHEDULE echo " schedule:" >> $OSPATCHSCHEDULE for psd in "${PATCHSCHEDULEDAYS[@]}" @@ -722,8 +778,8 @@ saltify() { if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then yum -y install wget https://repo.saltstack.com/py3/redhat/salt-py3-repo-latest-2.el7.noarch.rpm - cp /etc/yum.repos.d/salt-latest.repo /etc/yum.repos.d/salt-2019-2.repo - sed -i 's/latest/2019.2/g' /etc/yum.repos.d/salt-2019-2.repo + cp /etc/yum.repos.d/salt-py3-latest.repo /etc/yum.repos.d/salt-py3-2019-2.repo + sed -i 's/latest/2019.2/g' /etc/yum.repos.d/salt-py3-2019-2.repo # Download Ubuntu Keys in case master updates = 1 mkdir -p /opt/so/gpg wget --inet4-only -O /opt/so/gpg/SALTSTACK-GPG-KEY.pub https://repo.saltstack.com/apt/ubuntu/16.04/amd64/latest/SALTSTACK-GPG-KEY.pub @@ -934,13 +990,19 @@ EOF # Copy down the gpg keys and install them from the master mkdir $TMP/gpg - scp socore@$MSRV:/opt/so/gpg/* $TMP/gpg + echo "scp the gpg keys and install them from the master" + scp -v -i /root/.ssh/so.key socore@$MSRV:/opt/so/gpg/* $TMP/gpg + echo "Using apt-key add to add SALTSTACK-GPG-KEY.pub and GPG-KEY-WAZUH" apt-key add $TMP/gpg/SALTSTACK-GPG-KEY.pub apt-key add $TMP/gpg/GPG-KEY-WAZUH - echo "deb http://repo.saltstack.com/apt/ubuntu/$UVER/amd64/latest xenial main" > /etc/apt/sources.list.d/saltstack.list + echo "deb http://repo.saltstack.com/py3/ubuntu/$UVER/amd64/latest xenial main" > /etc/apt/sources.list.d/saltstack.list echo "deb https://packages.wazuh.com/3.x/apt/ stable main" | tee /etc/apt/sources.list.d/wazuh.list # Initialize the new repos apt-get update >> $SETUPLOG 2>&1 + echo "Installing libssl-dev for M2Crypto" + apt-get -y install libssl-dev + echo "Using pip3 to install M2Crypto for Salt" + pip3 install M2Crypto # Need to add python dateutil here apt-get -y install salt-minion=2019.2.2+ds-1 salt-common=2019.2.2+ds-1 >> $SETUPLOG 2>&1 apt-mark hold salt-minion salt-common @@ -1012,7 +1074,9 @@ salt_install_mysql_deps() { if [ $OS == 'centos' ]; then yum -y install mariadb-devel elif [ $OS == 'ubuntu' ]; then - apt-get -y install libmysqlclient-dev python3-mysqldb + apt-get -y install libmysqlclient-dev gcc + echo "Using pip3 to install mysqlclient for salt" + pip3 install mysqlclient fi } diff --git a/setup/so-setup.sh b/setup/so-setup.sh index a70361976..6975cc33a 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -48,7 +48,7 @@ got_root detect_os if [ $OS == ubuntu ]; then - # Override the Ubuntu whiptail color pallete + # Override the horrible Ubuntu whiptail color pallete update-alternatives --set newt-palette /etc/newt/palette.original fi @@ -151,7 +151,8 @@ if (whiptail_you_sure); then get_filesystem_root get_filesystem_nsm # Enable Bro Logs - bro_logs_enabled + # comment this out since we already copy this file to the destination that this function writes to + #bro_logs_enabled # Figure out the main IP address get_main_ip @@ -165,10 +166,9 @@ if (whiptail_you_sure); then # Install salt and dependencies { sleep 0.5 - #install_pip3 >> $SETUPLOG 2>&1 + install_python3 >> $SETUPLOG 2>&1 echo -e "XXX\n1\nInstalling and configuring Salt... \nXXX" echo " ** Installing Salt and Dependencies **" >> $SETUPLOG - salt_install_mysql_deps >> $SETUPLOG 2>&1 saltify >> $SETUPLOG 2>&1 echo -e "XXX\n5\nInstalling Docker... \nXXX" docker_install >> $SETUPLOG 2>&1 @@ -177,6 +177,7 @@ if (whiptail_you_sure); then configure_minion master >> $SETUPLOG 2>&1 echo " ** Installing Salt Master **" >> $SETUPLOG install_master >> $SETUPLOG 2>&1 + salt_install_mysql_deps >> $SETUPLOG 2>&1 salt_master_directories >> $SETUPLOG 2>&1 update_sudoers >> $SETUPLOG 2>&1 chown_salt_master >> $SETUPLOG 2>&1 @@ -250,7 +251,9 @@ if (whiptail_you_sure); then checkin_at_boot >> $SETUPLOG 2>&1 echo -e "XXX\n95\nVerifying Install... \nXXX" salt-call state.highstate >> $SETUPLOG 2>&1 - + echo -e "XX\n99\nFinishing touches... \nXXX" + filter_unused_nics >> $SETUPLOG 2>&1 + network_setup >> $SETUPLOG 2>&1 } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') if [[ $GOODSETUP == '0' ]]; then @@ -273,7 +276,7 @@ if (whiptail_you_sure); then if [ $INSTALLTYPE == 'SENSORONLY' ]; then whiptail_management_nic - filter_nics + filter_unused_nics whiptail_bond_nics whiptail_management_server whiptail_master_updates @@ -296,15 +299,15 @@ if (whiptail_you_sure); then mkdir -p /nsm get_filesystem_root get_filesystem_nsm - copy_ssh_key + copy_ssh_key >> $SETUPLOG 2>&1 { sleep 0.5 echo -e "XXX\n0\nSetting Initial Firewall Policy... \nXXX" set_initial_firewall_policy >> $SETUPLOG 2>&1 - #echo -e "XXX\n1\nInstalling pip3... \nXXX" - #install_pip3 >> $SETUPLOG 2>&1 + echo -e "XXX\n1\nInstalling pip3... \nXXX" + install_python3 >> $SETUPLOG 2>&1 echo -e "XXX\n3\nCreating Bond Interface... \nXXX" - network_setup >> $SETUPLOG 2>&1 + create_sensor_bond >> $SETUPLOG 2>&1 echo -e "XXX\n4\nGenerating Sensor Pillar... \nXXX" sensor_pillar >> $SETUPLOG 2>&1 echo "** Generating the patch pillar **" >> $SETUPLOG @@ -335,6 +338,9 @@ if (whiptail_you_sure); then echo -e "XXX\n80\nVerifying Install... \nXXX" salt-call state.highstate >> $SETUPLOG 2>&1 checkin_at_boot >> $SETUPLOG 2>&1 + echo -e "XX\n99\nFinishing touches... \nXXX" + filter_unused_nics >> $SETUPLOG 2>&1 + network_setup >> $SETUPLOG 2>&1 } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') if [[ $GOODSETUP == '0' ]]; then @@ -355,7 +361,7 @@ if (whiptail_you_sure); then whiptail_management_nic # Filter out the management NIC - filter_nics + filter_unused_nics # Select which NICs are in the bond whiptail_bond_nics @@ -402,16 +408,17 @@ if (whiptail_you_sure); then { sleep 0.5 echo -e "XXX\n0\nCreating Bond Interface... \nXXX" - network_setup >> $SETUPLOG 2>&1 - #install_pip3 >> $SETUPLOG 2>&1 - echo -e "XXX\n1\nInstalling mysql dependencies for saltstack... \nXXX" - salt_install_mysql_deps >> $SETUPLOG 2>&1 - echo -e "XXX\n1\nInstalling saltstack... \nXXX" + create_sensor_bond >> $SETUPLOG 2>&1 + echo -e "XXX\n1\nInstalling Python 3... \nXXX" + install_python3 >> $SETUPLOG 2>&1 + echo -e "XXX\n2\nInstalling saltstack... \nXXX" saltify >> $SETUPLOG 2>&1 echo -e "XXX\n3\nInstalling docker... \nXXX" docker_install >> $SETUPLOG 2>&1 echo -e "XXX\n5\nInstalling master code... \nXXX" install_master >> $SETUPLOG 2>&1 + echo -e "XXX\n5\nInstalling mysql dependencies for saltstack... \nXXX" + salt_install_mysql_deps >> $SETUPLOG 2>&1 echo -e "XXX\n6\nCopying salt code... \nXXX" salt_master_directories >> $SETUPLOG 2>&1 echo -e "XXX\n6\nupdating suduers... \nXXX" @@ -481,22 +488,24 @@ if (whiptail_you_sure); then echo -e "XXX\n85\nInstalling filebeat... \nXXX" salt-call state.apply filebeat >> $SETUPLOG 2>&1 salt-call state.apply utility >> $SETUPLOG 2>&1 - echo -e "XXX\n95\nInstalling misc components... \nXXX" + echo -e "XXX\n90\nInstalling misc components... \nXXX" salt-call state.apply schedule >> $SETUPLOG 2>&1 salt-call state.apply soctopus >> $SETUPLOG 2>&1 if [[ $THEHIVE == '1' ]]; then - echo -e "XXX\n96\nInstalling The Hive... \nXXX" + echo -e "XXX\n91\nInstalling The Hive... \nXXX" salt-call state.apply hive >> $SETUPLOG 2>&1 fi if [[ $PLAYBOOK == '1' ]]; then - echo -e "XXX\n97\nInstalling Playbook... \nXXX" + echo -e "XXX\n93\nInstalling Playbook... \nXXX" salt-call state.apply playbook >> $SETUPLOG 2>&1 fi - echo -e "XXX\n98\nSetting checkin to run on boot... \nXXX" + echo -e "XXX\n95\nSetting checkin to run on boot... \nXXX" checkin_at_boot >> $SETUPLOG 2>&1 - echo -e "XXX\n99\nVerifying Setup... \nXXX" + echo -e "XXX\n98\nVerifying Setup... \nXXX" salt-call state.highstate >> $SETUPLOG 2>&1 - + echo -e "XX\n99\nFinishing touches... \nXXX" + filter_unused_nics >> $SETUPLOG 2>&1 + network_setup >> $SETUPLOG 2>&1 } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') if [ $OS == 'centos' ]; then @@ -563,13 +572,13 @@ if (whiptail_you_sure); then mkdir -p /nsm get_filesystem_root get_filesystem_nsm - copy_ssh_key + copy_ssh_key >> $SETUPLOG 2>&1 { sleep 0.5 echo -e "XXX\n0\nSetting Initial Firewall Policy... \nXXX" set_initial_firewall_policy >> $SETUPLOG 2>&1 - #echo -e "XXX\n1\nInstalling pip3... \nXXX" - #install_pip3 >> $SETUPLOG 2>&1 + echo -e "XXX\n1\nInstalling pip3... \nXXX" + install_python3 >> $SETUPLOG 2>&1 echo -e "XXX\n5\nInstalling Salt Packages... \nXXX" saltify >> $SETUPLOG 2>&1 echo -e "XXX\n20\nInstalling Docker... \nXXX" @@ -600,7 +609,9 @@ if (whiptail_you_sure); then echo -e "XXX\n90\nVerifying Install... \nXXX" salt-call state.highstate >> $SETUPLOG 2>&1 checkin_at_boot >> $SETUPLOG 2>&1 - + echo -e "XX\n99\nFinishing touches... \nXXX" + filter_unused_nics >> $SETUPLOG 2>&1 + network_setup >> $SETUPLOG 2>&1 } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') if [[ $GOODSETUP == '0' ]]; then diff --git a/setup/whiptail.sh b/setup/whiptail.sh index 637ac8cdd..146275bb8 100644 --- a/setup/whiptail.sh +++ b/setup/whiptail.sh @@ -1,8 +1,19 @@ -########################################### -## ## -## Whiptail Menu Section ## -## ## -########################################### +#!/bin/bash + +# Copyright 2014,2015,2016,2017,2018,2019 Security Onion Solutions, LLC + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . whiptail_basic_bro() { @@ -36,10 +47,8 @@ whiptail_bro_pins() { whiptail_bro_version() { - BROVERSION=$(whiptail --title "Security Onion Setup" \ - --radiolist "What tool would you like to use to generate meta data?" 20 78 4 \ - "ZEEK" "Install Zeek (aka Bro)" ON \ - "SURICATA" "SUPER EXPERIMENTAL" OFF 3>&1 1>&2 2>&3) + BROVERSION=$(whiptail --title "Security Onion Setup" --radiolist "What tool would you like to use to generate meta data?" 20 78 4 "ZEEK" "Install Zeek (aka Bro)" ON \ + "COMMUNITY" "Install Community NSM" OFF "SURICATA" "SUPER EXPERIMENTAL" OFF 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -48,11 +57,16 @@ whiptail_bro_version() { whiptail_bond_nics() { - BNICS=$(whiptail --title "NIC Setup" --checklist "Please add NICs to the Monitor Interface" 20 78 12 ${FNICS[@]} 3>&1 1>&2 2>&3 ) + local nic_list=() + for FNIC in ${FNICS[@]}; do + nic_list+=($FNIC "Interface" "OFF") + done + + BNICS=$(whiptail --title "NIC Setup" --checklist "Please add NICs to the Monitor Interface" 20 78 12 ${nic_list[@]} 3>&1 1>&2 2>&3 ) while [ -z "$BNICS" ] do - BNICS=$(whiptail --title "NIC Setup" --checklist "Please add NICs to the Monitor Interface" 20 78 12 ${FNICS[@]} 3>&1 1>&2 2>&3 ) + BNICS=$(whiptail --title "NIC Setup" --checklist "Please add NICs to the Monitor Interface" 20 78 12 ${nic_list[@]} 3>&1 1>&2 2>&3 ) done local exitstatus=$? @@ -172,10 +186,10 @@ whiptail_install_type() { "SENSORONLY" "Create a forward only sensor" ON \ "STORAGENODE" "Add a Storage Hot Node with parsing" OFF \ "MASTERONLY" "Start a new grid" OFF \ - "EVALMODE" "Evaluate all the things" OFF \ "PARSINGNODE" "TODO Add a dedicated Parsing Node" OFF \ "HOTNODE" "TODO Add a Hot Node (Storage Node without Parsing)" OFF \ "WARMNODE" "TODO Add a Warm Node to an existing Hot or Storage node" OFF \ + "EVALMODE" "Evaluate all the things" OFF \ "WAZUH" "TODO Stand Alone Wazuh Node" OFF \ "STRELKA" "TODO Stand Alone Strelka Node" OFF \ "FLEET" "TODO Stand Alone Fleet OSQuery Node" OFF 3>&1 1>&2 2>&3 ) diff --git a/so-setup-network.sh b/so-setup-network.sh index b6002e9ac..329c18b1b 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2014,2015,2016,2017,2018, 2019 Security Onion Solutions, LLC +# Copyright 2014,2015,2016,2017,2018,2019 Security Onion Solutions, LLC # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -15,2431 +15,4 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# Global Variable Section -HOSTNAME=$(cat /etc/hostname) -MINION_ID=$(echo $HOSTNAME | awk -F. {'print $1'}) -TOTAL_MEM=`grep MemTotal /proc/meminfo | awk '{print $2}' | sed -r 's/.{3}$//'` -NICS=$(ip link | awk -F: '$0 !~ "lo|vir|veth|br|docker|wl|^[^0-9]"{print $2 " \"" "Interface" "\"" " OFF"}') -CPUCORES=$(cat /proc/cpuinfo | grep processor | wc -l) -LISTCORES=$(cat /proc/cpuinfo | grep processor | awk '{print $3 " \"" "core" "\""}') -RANDOMUID=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1) -NODE_ES_PORT="9200" -SETUPLOG="/root/sosetup.log" - -# Reset the Install Log -date -u >$SETUPLOG 2>&1 - -# End Global Variable Section - -# Functions - -accept_salt_key_local() { - echo "Accept the key locally on the master" >> $SETUPLOG 2>&1 - # Accept the key locally on the master - salt-key -ya $MINION_ID - -} - -accept_salt_key_remote() { - echo "Accept the key remotely on the master" >> $SETUPLOG 2>&1 - # Delete the key just in case. - ssh -i /root/.ssh/so.key socore@$MSRV sudo salt-key -d $MINION_ID -y - salt-call state.apply ca - ssh -i /root/.ssh/so.key socore@$MSRV sudo salt-key -a $MINION_ID -y - -} - -add_master_hostfile() { - echo "Checking if I can resolve master. If not add to hosts file" >> $SETUPLOG 2>&1 - # Pop up an input to get the IP address - MSRVIP=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter your Master Server IP Address" 10 60 X.X.X.X 3>&1 1>&2 2>&3) - -} - -add_socore_user_master() { - - echo "Add socore on the master" >>~/sosetup.log 2>&1 - # Add user "socore" to the master. This will be for things like accepting keys. - if [ $OS == 'centos' ]; then - local ADDUSER=adduser - else - local ADDUSER=useradd - fi - groupadd --gid 939 socore - $ADDUSER --uid 939 --gid 939 --home-dir /opt/so socore - # Set the password for socore that we got during setup - echo socore:$COREPASS1 | chpasswd --crypt-method=SHA512 - -} - -add_socore_user_notmaster() { - echo "Add socore user on non master" >> $SETUPLOG 2>&1 - # Add socore user to the non master system. Probably not a bad idea to make system user - groupadd --gid 939 socore - $ADDUSER --uid 939 --gid 939 --home-dir /opt/so --no-create-home socore - -} - -# Create an auth pillar so that passwords survive re-install -auth_pillar(){ - - if [ ! -f /opt/so/saltstack/pillar/auth.sls ]; then - echo "Creating Auth Pillar" >> $SETUPLOG 2>&1 - mkdir -p /opt/so/saltstack/pillar - echo "auth:" >> /opt/so/saltstack/pillar/auth.sls - echo " mysql: $MYSQLPASS" >> /opt/so/saltstack/pillar/auth.sls - echo " fleet: $FLEETPASS" >> /opt/so/saltstack/pillar/auth.sls - fi - -} - -# Enable Bro Logs -bro_logs_enabled() { - echo "Enabling Bro Logs" >> $SETUPLOG 2>&1 - - echo "brologs:" > pillar/brologs.sls - echo " enabled:" >> pillar/brologs.sls - - if [ $MASTERADV == 'ADVANCED' ]; then - for BLOG in ${BLOGS[@]}; do - echo " - $BLOG" | tr -d '"' >> pillar/brologs.sls - done - else - echo " - conn" >> pillar/brologs.sls - echo " - dce_rpc" >> pillar/brologs.sls - echo " - dhcp" >> pillar/brologs.sls - echo " - dhcpv6" >> pillar/brologs.sls - echo " - dnp3" >> pillar/brologs.sls - echo " - dns" >> pillar/brologs.sls - echo " - dpd" >> pillar/brologs.sls - echo " - files" >> pillar/brologs.sls - echo " - ftp" >> pillar/brologs.sls - echo " - http" >> pillar/brologs.sls - echo " - intel" >> pillar/brologs.sls - echo " - irc" >> pillar/brologs.sls - echo " - kerberos" >> pillar/brologs.sls - echo " - modbus" >> pillar/brologs.sls - echo " - mqtt" >> pillar/brologs.sls - echo " - notice" >> pillar/brologs.sls - echo " - ntlm" >> pillar/brologs.sls - echo " - openvpn" >> pillar/brologs.sls - echo " - pe" >> pillar/brologs.sls - echo " - radius" >> pillar/brologs.sls - echo " - rfb" >> pillar/brologs.sls - echo " - rdp" >> pillar/brologs.sls - echo " - signatures" >> pillar/brologs.sls - echo " - sip" >> pillar/brologs.sls - echo " - smb_files" >> pillar/brologs.sls - echo " - smb_mapping" >> pillar/brologs.sls - echo " - smtp" >> pillar/brologs.sls - echo " - snmp" >> pillar/brologs.sls - echo " - software" >> pillar/brologs.sls - echo " - ssh" >> pillar/brologs.sls - echo " - ssl" >> pillar/brologs.sls - echo " - syslog" >> pillar/brologs.sls - echo " - telnet" >> pillar/brologs.sls - echo " - tunnel" >> pillar/brologs.sls - echo " - weird" >> pillar/brologs.sls - echo " - mysql" >> pillar/brologs.sls - echo " - socks" >> pillar/brologs.sls - echo " - x509" >> pillar/brologs.sls - fi -} - -calculate_useable_cores() { - - # Calculate reasonable core usage - local CORES4BRO=$(( $CPUCORES/2 - 1 )) - LBPROCSROUND=$(printf "%.0f\n" $CORES4BRO) - # We don't want it to be 0 - if [ "$LBPROCSROUND" -lt 1 ]; then - LBPROCS=1 - else - LBPROCS=$LBPROCSROUND - fi - -} - -checkin_at_boot() { - echo "Enabling checkin at boot" >> $SETUPLOG 2>&1 - echo "startup_states: highstate" >> /etc/salt/minion -} - -check_hive_init_then_reboot() { - WAIT_STEP=0 - MAX_WAIT=100 - until [ -f /opt/so/state/thehive.txt ] ; do - WAIT_STEP=$(( ${WAIT_STEP} + 1 )) - echo "Waiting on the_hive to init...Attempt #$WAIT_STEP" - if [ ${WAIT_STEP} -gt ${MAX_WAIT} ]; then - echo "ERROR: We waited ${MAX_WAIT} seconds but the_hive is not working." - exit 5 - fi - sleep 1s; - done - docker stop so-thehive - docker rm so-thehive - shutdown -r now -} - -check_socore_pass() { - - if [ $COREPASS1 == $COREPASS2 ]; then - SCMATCH=yes - else - whiptail_passwords_dont_match - fi - -} - -chown_salt_master() { - - echo "Chown the salt dirs on the master for socore" >> $SETUPLOG 2>&1 - chown -R socore:socore /opt/so - -} - -clear_master() { - # Clear out the old master public key in case this is a re-install. - # This only happens if you re-install the master. - if [ -f /etc/salt/pki/minion/minion_master.pub ]; then - echo "Clearing old master key" >> $SETUPLOG 2>&1 - rm /etc/salt/pki/minion/minion_master.pub - service salt-minion restart - fi - -} - -configure_minion() { - - # You have to pass the TYPE to this function so it knows if its a master or not - local TYPE=$1 - echo "Configuring minion type as $TYPE" >> $SETUPLOG 2>&1 - touch /etc/salt/grains - echo "role: so-$TYPE" > /etc/salt/grains - if [ $TYPE == 'master' ] || [ $TYPE == 'eval' ]; then - echo "master: $HOSTNAME" > /etc/salt/minion - echo "id: $MINION_ID" >> /etc/salt/minion - echo "mysql.host: '$MAINIP'" >> /etc/salt/minion - echo "mysql.port: 3306" >> /etc/salt/minion - echo "mysql.user: 'root'" >> /etc/salt/minion - if [ ! -f /opt/so/saltstack/pillar/auth.sls ]; then - echo "mysql.pass: '$MYSQLPASS'" >> /etc/salt/minion - else - OLDPASS=$(cat /opt/so/saltstack/pillar/auth.sls | grep mysql | awk {'print $2'}) - echo "mysql.pass: '$OLDPASS'" >> /etc/salt/minion - fi - else - echo "master: $MSRV" > /etc/salt/minion - echo "id: $MINION_ID" >> /etc/salt/minion - - fi - - echo "use_superseded:" >> /etc/salt/minion - echo " - module.run" >> /etc/salt/minion - - service salt-minion restart - -} - -copy_master_config() { - - # Copy the master config template to the proper directory - cp files/master /etc/salt/master - # Restart the service so it picks up the changes -TODO Enable service on CentOS - service salt-master restart - -} - -copy_minion_tmp_files() { - - if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then - echo "rsyncing pillar and salt files in $TMP to /opt/so/saltstack" - rsync -a -v $TMP/pillar/ /opt/so/saltstack/pillar/ >> $SETUPLOG 2>&1 - rsync -a -v $TMP/salt/ /opt/so/saltstack/salt/ >> $SETUPLOG 2>&1 - else - echo "scp pillar and salt files in $TMP to master /opt/so/saltstack" - scp -prv -i /root/.ssh/so.key $TMP/pillar/* socore@$MSRV:/opt/so/saltstack/pillar >> $SETUPLOG 2>&1 - scp -prv -i /root/.ssh/so.key $TMP/salt/* socore@$MSRV:/opt/so/saltstack/salt >> $SETUPLOG 2>&1 - fi - - } - -copy_ssh_key() { - - echo "Generating SSH key" - # Generate SSH key - mkdir -p /root/.ssh - cat /dev/zero | ssh-keygen -f /root/.ssh/so.key -t rsa -q -N "" - chown -R $SUDO_USER:$SUDO_USER /root/.ssh - echo "Copying the SSH key to the master" - #Copy the key over to the master - ssh-copy-id -f -i /root/.ssh/so.key socore@$MSRV - -} - -create_sensor_bond() { - echo "Setting up sensor bond" >> $SETUPLOG 2>&1 - - # Set the MTU - if [[ $NSMSETUP != 'ADVANCED' ]]; then - MTU=1500 - fi - - # Create the bond interface - nmcli con add ifname bond0 con-name "bond0" type bond mode 0 -- \ - ipv4.method disabled \ - ipv6.method link-local \ - ethernet.mtu $MTU \ - connection.autoconnect "yes" >> $SETUPLOG 2>&1 - - for BNIC in ${BNICS[@]}; do - # Strip the quotes from the NIC names - BONDNIC="$(echo -e "${BNIC}" | tr -d '"')" - # Turn off various offloading settings for the interface - for i in rx tx sg tso ufo gso gro lro; do - ethtool -K $BONDNIC $i off >> $SETUPLOG 2>&1 - done - # Create the slave interface and assign it to the bond - nmcli con add type ethernet ifname $BONDNIC con-name "bond0-slave-$BONDNIC" master bond0 -- \ - ethernet.mtu $MTU \ - connection.autoconnect "yes" >> $SETUPLOG 2>&1 - # Bring the slave interface up - nmcli con up bond0-slave-$BONDNIC >> $SETUPLOG 2>&1 - done -} - -detect_os() { - - # Detect Base OS - echo "Detecting Base OS" >> $SETUPLOG 2>&1 - if [ -f /etc/redhat-release ]; then - OS=centos - yum -y install bind-utils - elif [ -f /etc/os-release ]; then - OS=ubuntu - apt install -y network-manager - /bin/systemctl enable network-manager - /bin/systemctl start network-manager - else - echo "We were unable to determine if you are using a supported OS." >> $SETUPLOG 2>&1 - exit - fi - echo "Detected OS as: $OS" >> $SETUPLOG 2>&1 - -} - -disable_dnsmasq() { - - if [ -f /etc/NetworkManager/NetworkManager.conf ]; then - echo "Disabling dnsmasq in /etc/NetworkManager/NetworkManager.conf" - sed -e 's/^dns=dnsmasq/#dns=dnsmasq/g' -i /etc/NetworkManager/NetworkManager.conf - fi - -} - -disable_unused_nics() { - for UNUSED_NIC in ${FNICS[@]}; do - # Disable DHCPv4/v6 and autoconnect - nmcli con mod $UNUSED_NIC \ - ipv4.method disabled \ - ipv6.method link-local \ - connection.autoconnect "no" >> $SETUPLOG 2>&1 - - # Flush any existing IPs - ip addr flush $UNUSED_NIC >> $SETUPLOG 2>&1 - done -} - -docker_install() { - - if [ $OS == 'centos' ]; then - yum clean expire-cache - yum -y install yum-utils device-mapper-persistent-data lvm2 openssl - yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo - yum -y update - yum -y install docker-ce python36-docker - if [ $INSTALLTYPE != 'EVALMODE' ]; then - docker_registry - fi - echo "Restarting Docker" >> $SETUPLOG 2>&1 - systemctl restart docker - systemctl enable docker - - else - if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then - apt-get update >> $SETUPLOG 2>&1 - apt-get -y install docker-ce python3-docker >> $SETUPLOG 2>&1 - if [ $INSTALLTYPE != 'EVALMODE' ]; then - docker_registry >> $SETUPLOG 2>&1 - fi - echo "Restarting Docker" >> $SETUPLOG 2>&1 - systemctl restart docker >> $SETUPLOG 2>&1 - else - apt-key add $TMP/gpg/docker.pub >> $SETUPLOG 2>&1 - add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" >> $SETUPLOG 2>&1 - apt-get update >> $SETUPLOG 2>&1 - apt-get -y install docker-ce python3-docker >> $SETUPLOG 2>&1 - docker_registry >> $SETUPLOG 2>&1 - echo "Restarting Docker" >> $SETUPLOG 2>&1 - systemctl restart docker >> $SETUPLOG 2>&1 - fi - fi - -} - -docker_registry() { - - echo "Setting up Docker Registry" >> $SETUPLOG 2>&1 - mkdir -p /etc/docker >> $SETUPLOG 2>&1 - # Make the host use the master docker registry - echo "{" > /etc/docker/daemon.json - echo " \"registry-mirrors\": [\"https://$MSRV:5000\"]" >> /etc/docker/daemon.json - echo "}" >> /etc/docker/daemon.json - echo "Docker Registry Setup - Complete" >> $SETUPLOG 2>&1 - -} - -es_heapsize() { - - # Determine ES Heap Size - if [ $TOTAL_MEM -lt 8000 ] ; then - ES_HEAP_SIZE="600m" - elif [ $TOTAL_MEM -ge 100000 ]; then - # Set a max of 25GB for heap size - # https://www.elastic.co/guide/en/elasticsearch/guide/current/heap-sizing.html - ES_HEAP_SIZE="25000m" - else - # Set heap size to 25% of available memory - ES_HEAP_SIZE=$(($TOTAL_MEM / 4))"m" - fi - -} - -eval_mode_hostsfile() { - - echo "127.0.0.1 $HOSTNAME" >> /etc/hosts - -} - -filter_unused_nics() { - # Set the main NIC as the default grep search string - grep_string=$MNIC - - # If we call this function and NICs have already been assigned to the bond interface then add them to the grep search string - if [[ $BNICS ]]; then - for BONDNIC in ${BNICS[@]}; do - grep_string="$grep_string\|$BONDNIC" - done - fi - - # Finally, set FNICS to any NICs we aren't using (and ignore interfaces that aren't of use) - FNICS=$(ip link | grep -vwe $grep_string | awk -F: '$0 !~ "lo|vir|veth|br|docker|wl|^[^0-9]"{print $2}') -} - -generate_passwords(){ - # Generate Random Passwords for Things - MYSQLPASS=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) - FLEETPASS=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) - HIVEKEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) - CORTEXKEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) - CORTEXORGUSERKEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) - SENSORONIKEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) -} - -get_filesystem_nsm(){ - FSNSM=$(df /nsm | awk '$3 ~ /[0-9]+/ { print $2 * 1000 }') -} - -get_log_size_limit() { - - DISK_DIR="/" - if [ -d /nsm ]; then - DISK_DIR="/nsm" - fi - DISK_SIZE_K=`df $DISK_DIR |grep -v "^Filesystem" | awk '{print $2}'` - PERCENTAGE=85 - DISK_SIZE=DISK_SIZE_K*1000 - PERCENTAGE_DISK_SPACE=`echo $(($DISK_SIZE*$PERCENTAGE/100))` - LOG_SIZE_LIMIT=$(($PERCENTAGE_DISK_SPACE/1000000000)) - -} - -get_filesystem_root(){ - FSROOT=$(df / | awk '$3 ~ /[0-9]+/ { print $2 * 1000 }') -} - -get_main_ip() { - - # Get the main IP address the box is using - MAINIP=$(ip route get 1 | awk '{print $NF;exit}') - MAININT=$(ip route get 1 | awk '{print $5;exit}') - -} - -got_root() { - - # Make sure you are root - if [ "$(id -u)" -ne 0 ]; then - echo "This script must be run using sudo!" - exit 1 - fi - -} - -install_cleanup() { - - # Clean up after ourselves - rm -rf /root/installtmp - -} - -install_python3() { - - echo "Installing Python3" - - if [ $OS == 'ubuntu' ]; then - apt-get -y install python3-pip python3-dev -# elif [ $OS == 'centos' ]; then -# yum -y install epel-release python3 - fi - -} - -install_prep() { - - # Create a tmp space that isn't in /tmp - mkdir /root/installtmp - TMP=/root/installtmp - -} - -install_master() { - - # Install the salt master package - if [ $OS == 'centos' ]; then - #yum -y install wget salt-common salt-master python36-mysql python36-dateutil python36-m2crypto >> $SETUPLOG 2>&1 - echo "" - # Create a place for the keys for Ubuntu minions - #mkdir -p /opt/so/gpg - #wget --inet4-only -O /opt/so/gpg/SALTSTACK-GPG-KEY.pub https://repo.saltstack.com/apt/ubuntu/16.04/amd64/latest/SALTSTACK-GPG-KEY.pub - #wget --inet4-only -O /opt/so/gpg/docker.pub https://download.docker.com/linux/ubuntu/gpg - #wget --inet4-only -O /opt/so/gpg/GPG-KEY-WAZUH https://packages.wazuh.com/key/GPG-KEY-WAZUH - - else - apt-get install -y salt-common=2019.2.2+ds-1 salt-master=2019.2.2+ds-1 salt-minion=2019.2.2+ds-1 - apt-mark hold salt-common salt-master salt-minion - echo -e "XXX\n11\nInstalling libssl-dev for M2Crypto... \nXXX" - apt-get -y install libssl-dev - echo -e "XXX\n12\nUsing pip3 to install M2Crypto for Salt... \nXXX" - pip3 install M2Crypto - - fi - - copy_master_config - -} - -ls_heapsize() { - - # Determine LS Heap Size - if [ $TOTAL_MEM -ge 32000 ] ; then - LS_HEAP_SIZE="1000m" - else - # If minimal RAM, then set minimal heap - LS_HEAP_SIZE="500m" - fi - -} - -master_pillar() { - - # Create the master pillar - touch /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo "master:" > /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo " mainip: $MAINIP" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo " mainint: $MAININT" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo " esheap: $ES_HEAP_SIZE" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo " esclustername: {{ grains.host }}" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - if [ $INSTALLTYPE == 'EVALMODE' ]; then - echo " freq: 0" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo " domainstats: 0" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo " ls_pipeline_batch_size: 125" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo " ls_input_threads: 1" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo " ls_batch_count: 125" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo " mtu: 1500" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - - else - echo " freq: 0" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo " domainstats: 0" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - fi - echo " lsheap: $LS_HEAP_SIZE" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo " lsaccessip: 127.0.0.1" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo " elastalert: 1" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo " ls_pipeline_workers: $CPUCORES" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo " nids_rules: $RULESETUP" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo " oinkcode: $OINKCODE" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - #echo " access_key: $ACCESS_KEY" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - #echo " access_secret: $ACCESS_SECRET" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo " es_port: $NODE_ES_PORT" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo " log_size_limit: $LOG_SIZE_LIMIT" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo " cur_close_days: $CURCLOSEDAYS" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - #echo " mysqlpass: $MYSQLPASS" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - #echo " fleetpass: $FLEETPASS" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo " grafana: $GRAFANA" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo " osquery: $OSQUERY" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo " wazuh: $WAZUH" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo " thehive: $THEHIVE" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - echo " playbook: $PLAYBOOK" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - } - -master_static() { - - # Create a static file for global values - touch /opt/so/saltstack/pillar/static.sls - - echo "static:" > /opt/so/saltstack/pillar/static.sls - echo " hnmaster: $HNMASTER" >> /opt/so/saltstack/pillar/static.sls - echo " ntpserver: $NTPSERVER" >> /opt/so/saltstack/pillar/static.sls - echo " proxy: $PROXY" >> /opt/so/saltstack/pillar/static.sls - echo " broversion: $BROVERSION" >> /opt/so/saltstack/pillar/static.sls - echo " ids: $NIDS" >> /opt/so/saltstack/pillar/static.sls - echo " masterip: $MAINIP" >> /opt/so/saltstack/pillar/static.sls - echo " hiveuser: hiveadmin" >> /opt/so/saltstack/pillar/static.sls - echo " hivepassword: hivechangeme" >> /opt/so/saltstack/pillar/static.sls - echo " hivekey: $HIVEKEY" >> /opt/so/saltstack/pillar/static.sls - echo " cortexuser: cortexadmin" >> /opt/so/saltstack/pillar/static.sls - echo " cortexpassword: cortexchangeme" >> /opt/so/saltstack/pillar/static.sls - echo " cortexkey: $CORTEXKEY" >> /opt/so/saltstack/pillar/static.sls - echo " cortexorgname: SecurityOnion" >> /opt/so/saltstack/pillar/static.sls - echo " cortexorguser: soadmin" >> /opt/so/saltstack/pillar/static.sls - echo " cortexorguserkey: $CORTEXORGUSERKEY" >> /opt/so/saltstack/pillar/static.sls - echo " fleetsetup: 0" >> /opt/so/saltstack/pillar/static.sls - echo " sensoronikey: $SENSORONIKEY" >> /opt/so/saltstack/pillar/static.sls - if [[ $MASTERUPDATES == 'MASTER' ]]; then - echo " masterupdate: 1" >> /opt/so/saltstack/pillar/static.sls - else - echo " masterupdate: 0" >> /opt/so/saltstack/pillar/static.sls - fi -} - -minio_generate_keys() { - - local charSet="[:graph:]" - - ACCESS_KEY=$(cat /dev/urandom | tr -cd "$charSet" | tr -d \' | tr -d \" | head -c 20) - ACCESS_SECRET=$(cat /dev/urandom | tr -cd "$charSet" | tr -d \' | tr -d \" | head -c 40) - -} - -network_setup() { - echo "Finishing up network setup" >> $SETUPLOG 2>&1 - - echo "... Disabling unused NICs" >> $SETUPLOG 2>&1 - disable_unused_nics >> $SETUPLOG 2>&1 - - echo "... Setting ONBOOT for management interface" >> $SETUPLOG 2>&1 - nmcli con mod $MAININT connection.autoconnect "yes" >> $SETUPLOG 2>&1 - - echo "... Copying disable-checksum-offload.sh" >> $SETUPLOG 2>&1 - cp ./install_scripts/disable-checksum-offload.sh /etc/NetworkManager/dispatcher.d/disable-checksum-offload.sh >> $SETUPLOG 2>&1 - - echo "... Modifying disable-checksum-offload.sh" >> $SETUPLOG 2>&1 - sed -i "s/\$MAININT/${MAININT}/g" /etc/NetworkManager/dispatcher.d/disable-checksum-offload.sh >> $SETUPLOG 2>&1 -} - -node_pillar() { - - NODEPILLARPATH=$TMP/pillar/nodes - if [ ! -d $NODEPILLARPATH ]; then - mkdir -p $NODEPILLARPATH - fi - - # Create the node pillar - touch $NODEPILLARPATH/$MINION_ID.sls - echo "node:" > $NODEPILLARPATH/$MINION_ID.sls - echo " mainip: $MAINIP" >> $NODEPILLARPATH/$MINION_ID.sls - echo " mainint: $MAININT" >> $NODEPILLARPATH/$MINION_ID.sls - echo " esheap: $NODE_ES_HEAP_SIZE" >> $NODEPILLARPATH/$MINION_ID.sls - echo " esclustername: {{ grains.host }}" >> $NODEPILLARPATH/$MINION_ID.sls - echo " lsheap: $NODE_LS_HEAP_SIZE" >> $NODEPILLARPATH/$MINION_ID.sls - echo " ls_pipeline_workers: $LSPIPELINEWORKERS" >> $NODEPILLARPATH/$MINION_ID.sls - echo " ls_pipeline_batch_size: $LSPIPELINEBATCH" >> $NODEPILLARPATH/$MINION_ID.sls - echo " ls_input_threads: $LSINPUTTHREADS" >> $NODEPILLARPATH/$MINION_ID.sls - echo " ls_batch_count: $LSINPUTBATCHCOUNT" >> $NODEPILLARPATH/$MINION_ID.sls - echo " es_shard_count: $SHARDCOUNT" >> $NODEPILLARPATH/$MINION_ID.sls - echo " node_type: $NODETYPE" >> $NODEPILLARPATH/$MINION_ID.sls - echo " es_port: $NODE_ES_PORT" >> $NODEPILLARPATH/$MINION_ID.sls - echo " log_size_limit: $LOG_SIZE_LIMIT" >> $NODEPILLARPATH/$MINION_ID.sls - echo " cur_close_days: $CURCLOSEDAYS" >> $NODEPILLARPATH/$MINION_ID.sls - -} - -patch_pillar() { - - case $INSTALLTYPE in - MASTERONLY | EVALMODE) - PATCHPILLARPATH=/opt/so/saltstack/pillar/masters - ;; - SENSORONLY) - PATCHPILLARPATH=$SENSORPILLARPATH - ;; - STORAGENODE | PARSINGNODE | HOTNODE | WARMNODE) - PATCHPILLARPATH=$NODEPILLARPATH - ;; - esac - - - echo "" >> $PATCHPILLARPATH/$MINION_ID.sls - echo "patch:" >> $PATCHPILLARPATH/$MINION_ID.sls - echo " os:" >> $PATCHPILLARPATH/$MINION_ID.sls - echo " schedule_name: $PATCHSCHEDULENAME" >> $PATCHPILLARPATH/$MINION_ID.sls - echo " enabled: True" >> $PATCHPILLARPATH/$MINION_ID.sls - echo " splay: 300" >> $PATCHPILLARPATH/$MINION_ID.sls - - -} - -patch_schedule_os_new() { - OSPATCHSCHEDULEDIR="$TMP/salt/patch/os/schedules" - OSPATCHSCHEDULE="$OSPATCHSCHEDULEDIR/$PATCHSCHEDULENAME.yml" - - if [ ! -d $OSPATCHSCHEDULEDIR ] ; then - mkdir -p $OSPATCHSCHEDULEDIR - fi - - echo "patch:" > $OSPATCHSCHEDULE - echo " os:" >> $OSPATCHSCHEDULE - echo " schedule:" >> $OSPATCHSCHEDULE - for psd in "${PATCHSCHEDULEDAYS[@]}" - do - psd=$(echo $psd | sed 's/"//g') - echo " - $psd:" >> $OSPATCHSCHEDULE - for psh in "${PATCHSCHEDULEHOURS[@]}" - do - psh=$(echo $psh | sed 's/"//g') - echo " - '$psh'" >> $OSPATCHSCHEDULE - done - done - -} - -process_components() { - CLEAN=${COMPONENTS//\"} - GRAFANA=0 - OSQUERY=0 - WAZUH=0 - THEHIVE=0 - PLAYBOOK=0 - - IFS=$' ' - for item in $(echo "$CLEAN"); do - let $item=1 - done - unset IFS -} - -saltify() { - - # Install updates and Salt - if [ $OS == 'centos' ]; then - ADDUSER=adduser - - if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then - yum -y install wget https://repo.saltstack.com/py3/redhat/salt-py3-repo-latest-2.el7.noarch.rpm - cp /etc/yum.repos.d/salt-py3-latest.repo /etc/yum.repos.d/salt-py3-2019-2.repo - sed -i 's/latest/2019.2/g' /etc/yum.repos.d/salt-py3-2019-2.repo - # Download Ubuntu Keys in case master updates = 1 - mkdir -p /opt/so/gpg - wget --inet4-only -O /opt/so/gpg/SALTSTACK-GPG-KEY.pub https://repo.saltstack.com/apt/ubuntu/16.04/amd64/latest/SALTSTACK-GPG-KEY.pub - wget --inet4-only -O /opt/so/gpg/docker.pub https://download.docker.com/linux/ubuntu/gpg - wget --inet4-only -O /opt/so/gpg/GPG-KEY-WAZUH https://packages.wazuh.com/key/GPG-KEY-WAZUH - cat > /etc/yum.repos.d/wazuh.repo <<\EOF -[wazuh_repo] -gpgcheck=1 -gpgkey=https://packages.wazuh.com/key/GPG-KEY-WAZUH -enabled=1 -name=Wazuh repository -baseurl=https://packages.wazuh.com/3.x/yum/ -protect=1 -EOF - - else - - if [ $MASTERUPDATES == 'MASTER' ]; then - - # Create the GPG Public Key for the Salt Repo - echo "-----BEGIN PGP PUBLIC KEY BLOCK-----" > /etc/pki/rpm-gpg/saltstack-signing-key - echo "Version: GnuPG v2.0.22 (GNU/Linux)" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "mQENBFOpvpgBCADkP656H41i8fpplEEB8IeLhugyC2rTEwwSclb8tQNYtUiGdna9" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "m38kb0OS2DDrEdtdQb2hWCnswxaAkUunb2qq18vd3dBvlnI+C4/xu5ksZZkRj+fW" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "tArNR18V+2jkwcG26m8AxIrT+m4M6/bgnSfHTBtT5adNfVcTHqiT1JtCbQcXmwVw" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "WbqS6v/LhcsBE//SHne4uBCK/GHxZHhQ5jz5h+3vWeV4gvxS3Xu6v1IlIpLDwUts" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "kT1DumfynYnnZmWTGc6SYyIFXTPJLtnoWDb9OBdWgZxXfHEcBsKGha+bXO+m2tHA" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "gNneN9i5f8oNxo5njrL8jkCckOpNpng18BKXABEBAAG0MlNhbHRTdGFjayBQYWNr" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "YWdpbmcgVGVhbSA8cGFja2FnaW5nQHNhbHRzdGFjay5jb20+iQE4BBMBAgAiBQJT" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "qb6YAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRAOCKFJ3le/vhkqB/0Q" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "WzELZf4d87WApzolLG+zpsJKtt/ueXL1W1KA7JILhXB1uyvVORt8uA9FjmE083o1" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "yE66wCya7V8hjNn2lkLXboOUd1UTErlRg1GYbIt++VPscTxHxwpjDGxDB1/fiX2o" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "nK5SEpuj4IeIPJVE/uLNAwZyfX8DArLVJ5h8lknwiHlQLGlnOu9ulEAejwAKt9CU" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "4oYTszYM4xrbtjB/fR+mPnYh2fBoQO4d/NQiejIEyd9IEEMd/03AJQBuMux62tjA" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "/NwvQ9eqNgLw9NisFNHRWtP4jhAOsshv1WW+zPzu3ozoO+lLHixUIz7fqRk38q8Q" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "9oNR31KvrkSNrFbA3D89uQENBFOpvpgBCADJ79iH10AfAfpTBEQwa6vzUI3Eltqb" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "9aZ0xbZV8V/8pnuU7rqM7Z+nJgldibFk4gFG2bHCG1C5aEH/FmcOMvTKDhJSFQUx" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "uhgxttMArXm2c22OSy1hpsnVG68G32Nag/QFEJ++3hNnbyGZpHnPiYgej3FrerQJ" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "zv456wIsxRDMvJ1NZQB3twoCqwapC6FJE2hukSdWB5yCYpWlZJXBKzlYz/gwD/Fr" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "GL578WrLhKw3UvnJmlpqQaDKwmV2s7MsoZogC6wkHE92kGPG2GmoRD3ALjmCvN1E" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "PsIsQGnwpcXsRpYVCoW7e2nW4wUf7IkFZ94yOCmUq6WreWI4NggRcFC5ABEBAAGJ" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "AR8EGAECAAkFAlOpvpgCGwwACgkQDgihSd5Xv74/NggA08kEdBkiWWwJZUZEy7cK" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "WWcgjnRuOHd4rPeT+vQbOWGu6x4bxuVf9aTiYkf7ZjVF2lPn97EXOEGFWPZeZbH4" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "vdRFH9jMtP+rrLt6+3c9j0M8SIJYwBL1+CNpEC/BuHj/Ra/cmnG5ZNhYebm76h5f" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "T9iPW9fFww36FzFka4VPlvA4oB7ebBtquFg3sdQNU/MmTVV4jPFWXxh4oRDDR+8N" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "1bcPnbB11b5ary99F/mqr7RgQ+YFF0uKRE3SKa7a+6cIuHEZ7Za+zhPaQlzAOZlx" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "fuBmScum8uQTrEF5+Um5zkwC7EXTdH1co/+/V/fpOtxIg4XO4kcugZefVm5ERfVS" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "MA==" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "=dtMN" >> /etc/pki/rpm-gpg/saltstack-signing-key - echo "-----END PGP PUBLIC KEY BLOCK-----" >> /etc/pki/rpm-gpg/saltstack-signing-key - - # Add the Wazuh Key - cat > /etc/pki/rpm-gpg/GPG-KEY-WAZUH <<\EOF ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v1 - -mQINBFeeyYwBEACyf4VwV8c2++J5BmCl6ofLCtSIW3UoVrF4F+P19k/0ngnSfjWb -8pSWB11HjZ3Mr4YQeiD7yY06UZkrCXk+KXDlUjMK3VOY7oNPkqzNaP6+8bDwj4UA -hADMkaXBvWooGizhCoBtDb1bSbHKcAnQ3PTdiuaqF5bcyKk8hv939CHulL2xH+BP -mmTBi+PM83pwvR+VRTOT7QSzf29lW1jD79v4rtXHJs4KCz/amT/nUm/tBpv3q0sT -9M9rH7MTQPdqvzMl122JcZST75GzFJFl0XdSHd5PAh2mV8qYak5NYNnwA41UQVIa -+xqhSu44liSeZWUfRdhrQ/Nb01KV8lLAs11Sz787xkdF4ad25V/Rtg/s4UXt35K3 -klGOBwDnzPgHK/OK2PescI5Ve1z4x1C2bkGze+gk/3IcfGJwKZDfKzTtqkZ0MgpN -7RGghjkH4wpFmuswFFZRyV+s7jXYpxAesElDSmPJ0O07O4lQXQMROE+a2OCcm0eF -3+Cr6qxGtOp1oYMOVH0vOLYTpwOkAM12/qm7/fYuVPBQtVpTojjV5GDl2uGq7p0o -h9hyWnLeNRbAha0px6rXcF9wLwU5n7mH75mq5clps3sP1q1/VtP/Fr84Lm7OGke4 -9eD+tPNCdRx78RNWzhkdQxHk/b22LCn1v6p1Q0qBco9vw6eawEkz1qwAjQARAQAB -tDFXYXp1aC5jb20gKFdhenVoIFNpZ25pbmcgS2V5KSA8c3VwcG9ydEB3YXp1aC5j -b20+iQI9BBMBCAAnBQJXnsmMAhsDBQkFo5qABQsJCAcDBRUKCQgLBRYCAwEAAh4B -AheAAAoJEJaz7l8pERFFHEsQAIaslejcW2NgjgOZuvn1Bht4JFMbCIPOekg4Z5yF -binRz0wmA7JNaawDHTBYa6L+A2Xneu/LmuRjFRMesqopUukVeGQgHBXbGMzY46eI -rqq/xgvgWzHSbWweiOX0nn+exbEAM5IyW+efkWNz0e8xM1LcxdYZxkVOqFqkp3Wv -J9QUKw6z9ifUOx++G8UO307O3hT2f+x4MUoGZeOF4q1fNy/VyBS2lMg2HF7GWy2y -kjbSe0p2VOFGEZLuu2f5tpPNth9UJiTliZKmgSk/zbKYmSjiVY2eDqNJ4qjuqes0 -vhpUaBjA+DgkEWUrUVXG5yfQDzTiYIF84LknjSJBYSLZ4ABsMjNO+GApiFPcih+B -Xc9Kx7E9RNsNTDqvx40y+xmxDOzVIssXeKqwO8r5IdG3K7dkt2Vkc/7oHOpcKwE5 -8uASMPiqqMo+t1RVa6Spckp3Zz8REILbotnnVwDIwo2HmgASirMGUcttEJzubaIa -Mv43GKs8RUH9s5NenC02lfZG7D8WQCz5ZH7yEWrt5bCaQRNDXjhsYE17SZ/ToHi3 -OpWu050ECWOHdxlXNG3dOWIdFDdBJM7UfUNSSOe2Y5RLsWfwvMFGbfpdlgJcMSDV -X+ienkrtXhBteTu0dwPu6HZTFOjSftvtAo0VIqGQrKMvKelkkdNGdDFLQw2mUDcw -EQj6uQINBFeeyYwBEADD1Y3zW5OrnYZ6ghTd5PXDAMB8Z1ienmnb2IUzLM+i0yE2 -TpKSP/XYCTBhFa390rYgFO2lbLDVsiz7Txd94nHrdWXGEQfwrbxsvdlLLWk7iN8l -Fb4B60OfRi3yoR96a/kIPNa0x26+n79LtDuWZ/DTq5JSHztdd9F1sr3h8i5zYmtv -luj99ZorpwYejbBVUm0+gP0ioaXM37uO56UFVQk3po9GaS+GtLnlgoE5volgNYyO -rkeIua4uZVsifREkHCKoLJip6P7S3kTyfrpiSLhouEZ7kV1lbMbFgvHXyjm+/AIx -HIBy+H+e+HNt5gZzTKUJsuBjx44+4jYsOR67EjOdtPOpgiuJXhedzShEO6rbu/O4 -wM1rX45ZXDYa2FGblHCQ/VaS0ttFtztk91xwlWvjTR8vGvp5tIfCi+1GixPRQpbN -Y/oq8Kv4A7vB3JlJscJCljvRgaX0gTBzlaF6Gq0FdcWEl5F1zvsWCSc/Fv5WrUPY -5mG0m69YUTeVO6cZS1aiu9Qh3QAT/7NbUuGXIaAxKnu+kkjLSz+nTTlOyvbG7BVF -a6sDmv48Wqicebkc/rCtO4g8lO7KoA2xC/K/6PAxDrLkVyw8WPsAendmezNfHU+V -32pvWoQoQqu8ysoaEYc/j9fN4H3mEBCN3QUJYCugmHP0pu7VtpWwwMUqcGeUVwAR -AQABiQIlBBgBCAAPBQJXnsmMAhsMBQkFo5qAAAoJEJaz7l8pERFFz8IP/jfBxJSB -iOw+uML+C4aeYxuHSdxmSsrJclYjkw7Asha/fm4Kkve00YAW8TGxwH2kgS72ooNJ -1Q7hUxNbVyrJjQDSMkRKwghmrPnUM3UyHmE0dq+G2NhaPdFo8rKifLOPgwaWAfSV -wgMTK86o0kqRbGpXgVIG5eRwv2FcxM3xGfy7sub07J2VEz7Ba6rYQ3NTbPK42AtV -+wRJDXcgS7y6ios4XQtSbIB5f6GI56zVlwfRd3hovV9ZAIJQ6DKM31wD6Kt/pRun -DjwMZu0/82JMoqmxX/00sNdDT1S13guCfl1WhBu7y1ja9MUX5OpUzyEKg5sxme+L -iY2Rhs6CjmbTm8ER4Uj8ydKyVTy8zbumbB6T8IwCAbEMtPxm6pKh/tgLpoJ+Bj0y -AsGjmhV7R6PKZSDXg7/qQI98iC6DtWc9ibC/QuHLcvm3hz40mBgXAemPJygpxGst -mVtU7O3oHw9cIUpkbMuVqSxgPFmSSq5vEYkka1CYeg8bOz6aCTuO5J0GDlLrpjtx -6lyImbZAF/8zKnW19aq5lshT2qJlTQlZRwwDZX5rONhA6T8IEUnUyD4rAIQFwfJ+ -gsXa4ojD/tA9NLdiNeyEcNfyX3FZwXWCtVLXflzdRN293FKamcdnMjVRjkCnp7iu -7eO7nMgcRoWddeU+2aJFqCoQtKCp/5EKhFey -=UIVm ------END PGP PUBLIC KEY BLOCK----- -EOF - - # Proxy is hating on me.. Lets just set it manually - echo "[salt-latest]" > /etc/yum.repos.d/salt-latest.repo - echo "name=SaltStack Latest Release Channel for RHEL/Centos \$releasever" >> /etc/yum.repos.d/salt-latest.repo - echo "baseurl=https://repo.saltstack.com/py3/redhat/7/\$basearch/latest" >> /etc/yum.repos.d/salt-latest.repo - echo "failovermethod=priority" >> /etc/yum.repos.d/salt-latest.repo - echo "enabled=1" >> /etc/yum.repos.d/salt-latest.repo - echo "gpgcheck=1" >> /etc/yum.repos.d/salt-latest.repo - echo "gpgkey=file:///etc/pki/rpm-gpg/saltstack-signing-key" >> /etc/yum.repos.d/salt-latest.repo - - # Proxy is hating on me.. Lets just set it manually - echo "[salt-2019.2]" > /etc/yum.repos.d/salt-2019-2.repo - echo "name=SaltStack Latest Release Channel for RHEL/Centos \$releasever" >> /etc/yum.repos.d/salt-2019-2.repo - echo "baseurl=https://repo.saltstack.com/py3/redhat/7/\$basearch/2019.2" >> /etc/yum.repos.d/salt-2019-2.repo - echo "failovermethod=priority" >> /etc/yum.repos.d/salt-2019-2.repo - echo "enabled=1" >> /etc/yum.repos.d/salt-2019-2.repo - echo "gpgcheck=1" >> /etc/yum.repos.d/salt-2019-2.repo - echo "gpgkey=file:///etc/pki/rpm-gpg/saltstack-signing-key" >> /etc/yum.repos.d/salt-2019-2.repo - - cat > /etc/yum.repos.d/wazuh.repo <<\EOF -[wazuh_repo] -gpgcheck=1 -gpgkey=file:///etc/pki/rpm-gpg/GPG-KEY-WAZUH -enabled=1 -name=Wazuh repository -baseurl=https://packages.wazuh.com/3.x/yum/ -protect=1 -EOF - else - yum -y install https://repo.saltstack.com/py3/redhat/salt-py3-repo-latest-2.el7.noarch.rpm - cp /etc/yum.repos.d/salt-latest.repo /etc/yum.repos.d/salt-2019-2.repo - sed -i 's/latest/2019.2/g' /etc/yum.repos.d/salt-2019-2.repo -cat > /etc/yum.repos.d/wazuh.repo <<\EOF -[wazuh_repo] -gpgcheck=1 -gpgkey=file:///etc/pki/rpm-gpg/GPG-KEY-WAZUH -enabled=1 -name=Wazuh repository -baseurl=https://packages.wazuh.com/3.x/yum/ -protect=1 -EOF - fi - fi - - yum clean expire-cache - yum -y install epel-release salt-minion-2019.2.2 yum-utils device-mapper-persistent-data lvm2 openssl - yum -y update exclude=salt* - systemctl enable salt-minion - - if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then - yum -y install salt-master-2019.2.2 python3 python36-m2crypto salt-minion-2019.2.2 python36-dateutil python36-mysql python36-docker - systemctl enable salt-master - else - yum -y install salt-minion-2019.2.2 python3 python36-m2crypto python36-dateutil python36-docker - fi - echo "exclude=salt*" >> /etc/yum.conf - - else - ADDUSER=useradd - DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade - - # Add the pre-requisites for installing docker-ce - apt-get -y install ca-certificates curl software-properties-common apt-transport-https openssl >> $SETUPLOG 2>&1 - - # Grab the version from the os-release file - UVER=$(grep VERSION_ID /etc/os-release | awk -F '[ "]' '{print $2}') - - # Nasty hack but required for now - if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then - - #echo "Using pip3 to install python-dateutil for salt" - #pip3 install python-dateutil - # Install the repo for salt - wget --inet4-only -O - https://repo.saltstack.com/apt/ubuntu/$UVER/amd64/latest/SALTSTACK-GPG-KEY.pub | apt-key add - - wget --inet4-only -O - https://repo.saltstack.com/apt/ubuntu/$UVER/amd64/2019.2/SALTSTACK-GPG-KEY.pub | apt-key add - - echo "deb http://repo.saltstack.com/py3/ubuntu/$UVER/amd64/latest xenial main" > /etc/apt/sources.list.d/saltstack.list - echo "deb http://repo.saltstack.com/py3/ubuntu/$UVER/amd64/2019.2 xenial main" > /etc/apt/sources.list.d/saltstack2019.list - - # Lets get the docker repo added - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - - add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" - - # Create a place for the keys - mkdir -p /opt/so/gpg - wget --inet4-only -O /opt/so/gpg/SALTSTACK-GPG-KEY.pub https://repo.saltstack.com/apt/ubuntu/$UVER/amd64/latest/SALTSTACK-GPG-KEY.pub - wget --inet4-only -O /opt/so/gpg/docker.pub https://download.docker.com/linux/ubuntu/gpg - wget --inet4-only -O /opt/so/gpg/GPG-KEY-WAZUH https://packages.wazuh.com/key/GPG-KEY-WAZUH - - # Get key and install wazuh - curl -s https://packages.wazuh.com/key/GPG-KEY-WAZUH | apt-key add - - # Add repo - echo "deb https://packages.wazuh.com/3.x/apt/ stable main" | tee /etc/apt/sources.list.d/wazuh.list - - # Initialize the new repos - apt-get update >> $SETUPLOG 2>&1 - # Need to add python packages here - apt-get -y install salt-minion=2019.2.2+ds-1 salt-common=2019.2.2+ds-1 python3-dateutil >> $SETUPLOG 2>&1 - apt-mark hold salt-minion salt-common - - else - - # Copy down the gpg keys and install them from the master - mkdir $TMP/gpg - echo "scp the gpg keys and install them from the master" - scp -v -i /root/.ssh/so.key socore@$MSRV:/opt/so/gpg/* $TMP/gpg - echo "Using apt-key add to add SALTSTACK-GPG-KEY.pub and GPG-KEY-WAZUH" - apt-key add $TMP/gpg/SALTSTACK-GPG-KEY.pub - apt-key add $TMP/gpg/GPG-KEY-WAZUH - echo "deb http://repo.saltstack.com/py3/ubuntu/$UVER/amd64/latest xenial main" > /etc/apt/sources.list.d/saltstack.list - echo "deb https://packages.wazuh.com/3.x/apt/ stable main" | tee /etc/apt/sources.list.d/wazuh.list - # Initialize the new repos - apt-get update >> $SETUPLOG 2>&1 - echo "Installing libssl-dev for M2Crypto" - apt-get -y install libssl-dev - echo "Using pip3 to install M2Crypto for Salt" - pip3 install M2Crypto - # Need to add python dateutil here - apt-get -y install salt-minion=2019.2.2+ds-1 salt-common=2019.2.2+ds-1 >> $SETUPLOG 2>&1 - apt-mark hold salt-minion salt-common - - fi - - fi - -} - -salt_checkin() { - # Master State to Fix Mine Usage - if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then - echo "Building Certificate Authority" - salt-call state.apply ca >> $SETUPLOG 2>&1 - echo " *** Restarting Salt to fix any SSL errors. ***" - service salt-master restart >> $SETUPLOG 2>&1 - sleep 5 - service salt-minion restart >> $SETUPLOG 2>&1 - sleep 15 - echo " Applyng a mine hack " - sudo salt '*' mine.send x509.get_pem_entries glob_path=/etc/pki/ca.crt >> $SETUPLOG 2>&1 - echo " Applying SSL state " - salt-call state.apply ssl >> $SETUPLOG 2>&1 - echo "Still Working... Hang in there" - #salt-call state.highstate - - else - - # Run Checkin - salt-call state.apply ca >> $SETUPLOG 2>&1 - salt-call state.apply ssl >> $SETUPLOG 2>&1 - #salt-call state.highstate >> $SETUPLOG 2>&1 - - fi - -} - -salt_checkin_message() { - - # Warn the user that this might take a while - echo "####################################################" - echo "## ##" - echo "## Applying and Installing everything ##" - echo "## (This will take a while) ##" - echo "## ##" - echo "####################################################" - -} - -salt_firstcheckin() { - - #First Checkin - salt-call state.highstate >> $SETUPLOG 2>&1 - -} - -salt_master_directories() { - - # Create salt paster directories - mkdir -p /opt/so/saltstack/salt - mkdir -p /opt/so/saltstack/pillar - - # Copy over the salt code and templates - cp -R pillar/* /opt/so/saltstack/pillar/ - chmod +x /opt/so/saltstack/pillar/firewall/addfirewall.sh - chmod +x /opt/so/saltstack/pillar/data/addtotab.sh - cp -R salt/* /opt/so/saltstack/salt/ - -} - -salt_install_mysql_deps() { - - if [ $OS == 'centos' ]; then - yum -y install mariadb-devel - elif [ $OS == 'ubuntu' ]; then - apt-get -y install libmysqlclient-dev gcc - echo "Using pip3 to install mysqlclient for salt" - pip3 install mysqlclient - fi - -} - -sensor_pillar() { - - SENSORPILLARPATH=$TMP/pillar/sensors - if [ ! -d $SENSORPILLARPATH ]; then - mkdir -p $SENSORPILLARPATH - fi - - # Create the sensor pillar - touch $SENSORPILLARPATH/$MINION_ID.sls - echo "sensor:" > $SENSORPILLARPATH/$MINION_ID.sls - echo " interface: bond0" >> $SENSORPILLARPATH/$MINION_ID.sls - echo " mainip: $MAINIP" >> $SENSORPILLARPATH/$MINION_ID.sls - echo " mainint: $MAININT" >> $SENSORPILLARPATH/$MINION_ID.sls - if [ $NSMSETUP == 'ADVANCED' ]; then - echo " bro_pins:" >> $SENSORPILLARPATH/$MINION_ID.sls - for PIN in $BROPINS; do - PIN=$(echo $PIN | cut -d\" -f2) - echo " - $PIN" >> $SENSORPILLARPATH/$MINION_ID.sls - done - echo " suripins:" >> $SENSORPILLARPATH/$MINION_ID.sls - for SPIN in $SURIPINS; do - SPIN=$(echo $SPIN | cut -d\" -f2) - echo " - $SPIN" >> $SENSORPILLARPATH/$MINION_ID.sls - done - else - echo " bro_lbprocs: $BASICBRO" >> $SENSORPILLARPATH/$MINION_ID.sls - echo " suriprocs: $BASICSURI" >> $SENSORPILLARPATH/$MINION_ID.sls - fi - echo " brobpf:" >> $SENSORPILLARPATH/$MINION_ID.sls - echo " pcapbpf:" >> $SENSORPILLARPATH/$MINION_ID.sls - echo " nidsbpf:" >> $SENSORPILLARPATH/$MINION_ID.sls - echo " master: $MSRV" >> $SENSORPILLARPATH/$MINION_ID.sls - echo " mtu: $MTU" >> $SENSORPILLARPATH/$MINION_ID.sls - if [ $HNSENSOR != 'inherit' ]; then - echo " hnsensor: $HNSENSOR" >> $SENSORPILLARPATH/$MINION_ID.sls - fi - echo " access_key: $ACCESS_KEY" >> $SENSORPILLARPATH/$MINION_ID.sls - echo " access_secret: $ACCESS_SECRET" >> $SENSORPILLARPATH/$MINION_ID.sls - -} - -set_environment_var() { - - echo "Setting environment variable: $1" - - export "$1" - echo "$1" >> /etc/environment - -} - -set_hostname() { - - hostnamectl set-hostname --static $HOSTNAME - echo "127.0.0.1 $HOSTNAME $HOSTNAME.localdomain localhost localhost.localdomain localhost4 localhost4.localdomain" > /etc/hosts - echo "::1 localhost localhost.localdomain localhost6 localhost6.localdomain6" >> /etc/hosts - echo $HOSTNAME > /etc/hostname - if [ $INSTALLTYPE != 'MASTERONLY' ] || [ $INSTALLTYPE != 'EVALMODE' ]; then - if [[ $TESTHOST = *"not found"* ]] || [[ $TESTHOST = *"connection timed out"* ]]; then - if ! grep -q $MSRVIP /etc/hosts; then - echo "$MSRVIP $MSRV" >> /etc/hosts - fi - fi - fi - -} - -set_initial_firewall_policy() { - - get_main_ip - if [ $INSTALLTYPE == 'MASTERONLY' ]; then - printf " - $MAINIP\n" >> /opt/so/saltstack/pillar/firewall/minions.sls - printf " - $MAINIP\n" >> /opt/so/saltstack/pillar/firewall/masterfw.sls - /opt/so/saltstack/pillar/data/addtotab.sh mastertab $MINION_ID $MAINIP $CPUCORES $RANDOMUID $MAININT $FSROOT $FSNSM - fi - - if [ $INSTALLTYPE == 'EVALMODE' ]; then - printf " - $MAINIP\n" >> /opt/so/saltstack/pillar/firewall/minions.sls - printf " - $MAINIP\n" >> /opt/so/saltstack/pillar/firewall/masterfw.sls - printf " - $MAINIP\n" >> /opt/so/saltstack/pillar/firewall/forward_nodes.sls - printf " - $MAINIP\n" >> /opt/so/saltstack/pillar/firewall/storage_nodes.sls - /opt/so/saltstack/pillar/data/addtotab.sh evaltab $MINION_ID $MAINIP $CPUCORES $RANDOMUID $MAININT $FSROOT $FSNSM bond0 - fi - - if [ $INSTALLTYPE == 'SENSORONLY' ]; then - ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/firewall/addfirewall.sh minions $MAINIP - ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/firewall/addfirewall.sh forward_nodes $MAINIP - ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/data/addtotab.sh sensorstab $MINION_ID $MAINIP $CPUCORES $RANDOMUID $MAININT $FSROOT $FSNSM bond0 - fi - - if [ $INSTALLTYPE == 'STORAGENODE' ]; then - ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/firewall/addfirewall.sh minions $MAINIP - ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/firewall/addfirewall.sh storage_nodes $MAINIP - ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/data/addtotab.sh nodestab $MINION_ID $MAINIP $CPUCORES $RANDOMUID $MAININT $FSROOT $FSNSM - fi - - if [ $INSTALLTYPE == 'PARSINGNODE' ]; then - echo "blah" - fi - - if [ $INSTALLTYPE == 'HOTNODE' ]; then - echo "blah" - fi - - if [ $INSTALLTYPE == 'WARMNODE' ]; then - echo "blah" - fi - -} - -set_node_type() { - - # Determine the node type based on whiplash choice - if [ $INSTALLTYPE == 'STORAGENODE' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then - NODETYPE='storage' - fi - if [ $INSTALLTYPE == 'PARSINGNODE' ]; then - NODETYPE='parser' - fi - if [ $INSTALLTYPE == 'HOTNODE' ]; then - NODETYPE='hot' - fi - if [ $INSTALLTYPE == 'WARMNODE' ]; then - NODETYPE='warm' - fi - -} - -set_updates() { - echo "MASTERUPDATES is $MASTERUPDATES" - if [ $MASTERUPDATES == 'MASTER' ]; then - if [ $OS == 'centos' ]; then - if ! grep -q $MSRV /etc/yum.conf; then - echo "proxy=http://$MSRV:3142" >> /etc/yum.conf - fi - - else - - # Set it up so the updates roll through the master - echo "Acquire::http::Proxy \"http://$MSRV:3142\";" > /etc/apt/apt.conf.d/00Proxy - echo "Acquire::https::Proxy \"http://$MSRV:3142\";" >> /etc/apt/apt.conf.d/00Proxy - - fi - fi -} - -update_sudoers() { - - if ! grep -qE '^socore\ ALL=\(ALL\)\ NOPASSWD:(\/usr\/bin\/salt\-key|\/opt\/so\/saltstack)' /etc/sudoers; then - # Update Sudoers so that socore can accept keys without a password - echo "socore ALL=(ALL) NOPASSWD:/usr/bin/salt-key" | sudo tee -a /etc/sudoers - echo "socore ALL=(ALL) NOPASSWD:/opt/so/saltstack/pillar/firewall/addfirewall.sh" | sudo tee -a /etc/sudoers - echo "socore ALL=(ALL) NOPASSWD:/opt/so/saltstack/pillar/data/addtotab.sh" | sudo tee -a /etc/sudoers - else - echo "User socore already granted sudo privileges" - fi - -} - -########################################### -## ## -## Whiptail Menu Section ## -## ## -########################################### - -whiptail_basic_bro() { - - BASICBRO=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter the number of bro processes:" 10 60 $LBPROCS 3>&1 1>&2 2>&3) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_basic_suri() { - - BASICSURI=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter the number of Suricata Processes:" 10 60 $LBPROCS 3>&1 1>&2 2>&3) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_bro_pins() { - - BROPINS=$(whiptail --noitem --title "Pin Bro CPUS" --checklist "Please Select $LBPROCS cores to pin Bro to:" 20 78 12 ${LISTCORES[@]} 3>&1 1>&2 2>&3 ) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - - -} - -whiptail_bro_version() { - - BROVERSION=$(whiptail --title "Security Onion Setup" --radiolist "What tool would you like to use to generate meta data?" 20 78 4 "ZEEK" "Install Zeek (aka Bro)" ON \ - "COMMUNITY" "Install Community NSM" OFF "SURICATA" "SUPER EXPERIMENTAL" OFF 3>&1 1>&2 2>&3) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_bond_nics() { - - local nic_list=() - for FNIC in ${FNICS[@]}; do - nic_list+=($FNIC "Interface" "OFF") - done - - BNICS=$(whiptail --title "NIC Setup" --checklist "Please add NICs to the Monitor Interface" 20 78 12 ${nic_list[@]} 3>&1 1>&2 2>&3 ) - - while [ -z "$BNICS" ] - do - BNICS=$(whiptail --title "NIC Setup" --checklist "Please add NICs to the Monitor Interface" 20 78 12 ${nic_list[@]} 3>&1 1>&2 2>&3 ) - done - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_bond_nics_mtu() { - - # Set the MTU on the monitor interface - MTU=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter the MTU for the monitor NICs" 10 60 1500 3>&1 1>&2 2>&3) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_cancel() { - - whiptail --title "Security Onion Setup" --msgbox "Cancelling Setup. No changes have been made." 8 78 - install_cleanup - exit - -} - -whiptail_check_exitstatus() { - - if [ $1 == '1' ]; then - echo "They hit cancel" - whiptail_cancel - fi - -} - -whiptail_create_socore_user() { - - whiptail --title "Security Onion Setup" --msgbox "Set a password for the socore user. This account is used for adding sensors remotely." 8 78 - -} - -whiptail_create_socore_user_password1() { - - COREPASS1=$(whiptail --title "Security Onion Install" --passwordbox \ - "Enter a password for user socore" 10 60 3>&1 1>&2 2>&3) - -} - -whiptail_create_socore_user_password2() { - - COREPASS2=$(whiptail --title "Security Onion Install" --passwordbox \ - "Re-enter a password for user socore" 10 60 3>&1 1>&2 2>&3) - -} - -whiptail_cur_close_days() { - - CURCLOSEDAYS=$(whiptail --title "Security Onion Setup" --inputbox \ - "Please specify the threshold (in days) at which Elasticsearch indices will be closed" 10 60 $CURCLOSEDAYS 3>&1 1>&2 2>&3) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} -whiptail_enable_components() { - COMPONENTS=$(whiptail --title "Security Onion Setup" --checklist \ - "Select Components to install" 20 78 8 \ - "GRAFANA" "Enable Grafana for system monitoring" ON \ - "OSQUERY" "Enable Fleet with osquery" ON \ - "WAZUH" "Enable Wazuh" ON \ - "THEHIVE" "Enable TheHive" ON \ - "PLAYBOOK" "Enable Playbook" ON 3>&1 1>&2 2>&3 ) -} - -whiptail_eval_adv() { - EVALADVANCED=$(whiptail --title "Security Onion Setup" --radiolist \ - "Choose your eval install:" 20 78 4 \ - "BASIC" "Install basic components for evaluation" ON \ - "ADVANCED" "Choose additional components to be installed" OFF 3>&1 1>&2 2>&3 ) -} - -whiptail_eval_adv_warning() { - whiptail --title "Security Onion Setup" --msgbox "Please keep in mind the more services that you enable the more RAM that is required." 8 78 -} - -whiptail_homenet_master() { - - # Ask for the HOME_NET on the master - HNMASTER=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter your HOME_NET separated by ," 10 60 10.0.0.0/8,192.168.0.0/16,172.16.0.0/12 3>&1 1>&2 2>&3) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_homenet_sensor() { - - # Ask to inherit from master - whiptail --title "Security Onion Setup" --yesno "Do you want to inherit the HOME_NET from the Master?" 8 78 - - local exitstatus=$? - if [ $exitstatus == 0 ]; then - HNSENSOR=inherit - else - HNSENSOR=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter your HOME_NET separated by ," 10 60 10.0.0.0/8,192.168.0.0/16,172.16.0.0/12 3>&1 1>&2 2>&3) - fi - -} - -whiptail_install_type() { - - # What kind of install are we doing? - INSTALLTYPE=$(whiptail --title "Security Onion Setup" --radiolist \ - "Choose Install Type:" 20 78 14 \ - "SENSORONLY" "Create a forward only sensor" ON \ - "STORAGENODE" "Add a Storage Hot Node with parsing" OFF \ - "MASTERONLY" "Start a new grid" OFF \ - "PARSINGNODE" "TODO Add a dedicated Parsing Node" OFF \ - "HOTNODE" "TODO Add a Hot Node (Storage Node without Parsing)" OFF \ - "WARMNODE" "TODO Add a Warm Node to an existing Hot or Storage node" OFF \ - "EVALMODE" "Evaluate all the things" OFF \ - "WAZUH" "TODO Stand Alone Wazuh Node" OFF \ - "STRELKA" "TODO Stand Alone Strelka Node" OFF \ - "FLEET" "TODO Stand Alone Fleet OSQuery Node" OFF 3>&1 1>&2 2>&3 ) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_log_size_limit() { - - LOG_SIZE_LIMIT=$(whiptail --title "Security Onion Setup" --inputbox \ - "Please specify the amount of disk space (in GB) you would like to allocate for Elasticsearch data storage. \ - By default, this is set to 85% of the disk space allotted for /nsm." 10 60 $LOG_SIZE_LIMIT 3>&1 1>&2 2>&3) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - - -whiptail_management_nic() { - - MNIC=$(whiptail --title "NIC Setup" --radiolist "Please select your management NIC" 20 78 12 ${NICS[@]} 3>&1 1>&2 2>&3 ) - - while [ -z "$MNIC" ] - do - MNIC=$(whiptail --title "NIC Setup" --radiolist "Please select your management NIC" 20 78 12 ${NICS[@]} 3>&1 1>&2 2>&3 ) - done - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_nids() { - - NIDS=$(whiptail --title "Security Onion Setup" --radiolist \ - "Choose which IDS to run:" 20 78 4 \ - "Suricata" "Suricata 4.X" ON \ - "Snort" "Snort 3.0 Beta" OFF 3>&1 1>&2 2>&3 ) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_oinkcode() { - - OINKCODE=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter your oinkcode" 10 60 XXXXXXX 3>&1 1>&2 2>&3) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_make_changes() { - - whiptail --title "Security Onion Setup" --yesno "We are going to set this machine up as a $INSTALLTYPE. Please hit YES to make changes or NO to cancel." 8 78 - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_management_server() { - - MSRV=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter your Master Server HOSTNAME. It is CASE SENSITIVE!" 10 60 XXXX 3>&1 1>&2 2>&3) - - # See if it resolves. Otherwise prompt to add to host file - TESTHOST=$(host $MSRV) - - if [[ $TESTHOST = *"not found"* ]] || [[ $TESTHOST = *"connection timed out"* ]]; then - add_master_hostfile - fi - - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -# Ask if you want to do advanced setup of the Master -whiptail_master_adv() { - MASTERADV=$(whiptail --title "Security Onion Setup" --radiolist \ - "Choose what type of master install:" 20 78 4 \ - "BASIC" "Install master with recommended settings" ON \ - "ADVANCED" "Do additional configuration to the master" OFF 3>&1 1>&2 2>&3 ) -} - -# Ask which additional components to install -whiptail_master_adv_service_brologs() { - - BLOGS=$(whiptail --title "Security Onion Setup" --checklist "Please Select Logs to Send:" 24 78 12 \ - "conn" "Connection Logging" ON \ - "dce_rpc" "RPC Logs" ON \ - "dhcp" "DHCP Logs" ON \ - "dhcpv6" "DHCP IPv6 Logs" ON \ - "dnp3" "DNP3 Logs" ON \ - "dns" "DNS Logs" ON \ - "dpd" "DPD Logs" ON \ - "files" "Files Logs" ON \ - "ftp" "FTP Logs" ON \ - "http" "HTTP Logs" ON \ - "intel" "Intel Hits Logs" ON \ - "irc" "IRC Chat Logs" ON \ - "kerberos" "Kerberos Logs" ON \ - "modbus" "MODBUS Logs" ON \ - "mqtt" "MQTT Logs" ON \ - "notice" "Zeek Notice Logs" ON \ - "ntlm" "NTLM Logs" ON \ - "openvpn" "OPENVPN Logs" ON \ - "pe" "PE Logs" ON \ - "radius" "Radius Logs" ON \ - "rfb" "RFB Logs" ON \ - "rdp" "RDP Logs" ON \ - "signatures" "Signatures Logs" ON \ - "sip" "SIP Logs" ON \ - "smb_files" "SMB Files Logs" ON \ - "smb_mapping" "SMB Mapping Logs" ON \ - "smtp" "SMTP Logs" ON \ - "snmp" "SNMP Logs" ON \ - "software" "Software Logs" ON \ - "ssh" "SSH Logs" ON \ - "ssl" "SSL Logs" ON \ - "syslog" "Syslog Logs" ON \ - "telnet" "Telnet Logs" ON \ - "tunnel" "Tunnel Logs" ON \ - "weird" "Zeek Weird Logs" ON \ - "mysql" "MySQL Logs" ON \ - "socks" "SOCKS Logs" ON \ - "x509" "x.509 Logs" ON 3>&1 1>&2 2>&3 ) -} - -whiptail_network_notice() { - - whiptail --title "Security Onion Setup" --yesno "Since this is a network install we assume the management interface, DNS, Hostname, etc are already set up. Hit YES to continue." 8 78 - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_node_advanced() { - - NODESETUP=$(whiptail --title "Security Onion Setup" --radiolist \ - "What type of config would you like to use?:" 20 78 4 \ - "NODEBASIC" "Install Storage Node with recommended settings" ON \ - "NODEADVANCED" "Advanced Node Setup" OFF 3>&1 1>&2 2>&3 ) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_node_es_heap() { - - es_heapsize - NODE_ES_HEAP_SIZE=$(whiptail --title "Security Onion Setup" --inputbox \ - "\nEnter ES Heap Size: \n \n(Recommended value is pre-populated)" 10 60 $ES_HEAP_SIZE 3>&1 1>&2 2>&3) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_node_ls_heap() { - - ls_heapsize - NODE_LS_HEAP_SIZE=$(whiptail --title "Security Onion Setup" --inputbox \ - "\nEnter LogStash Heap Size: \n \n(Recommended value is pre-populated)" 10 60 $LS_HEAP_SIZE 3>&1 1>&2 2>&3) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_node_ls_pipeline_worker() { - - LSPIPELINEWORKERS=$(whiptail --title "Security Onion Setup" --inputbox \ - "\nEnter LogStash Pipeline Workers: \n \n(Recommended value is pre-populated)" 10 60 $CPUCORES 3>&1 1>&2 2>&3) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_node_ls_pipline_batchsize() { - - LSPIPELINEBATCH=$(whiptail --title "Security Onion Setup" --inputbox \ - "\nEnter LogStash Pipeline Batch Size: \n \n(Default value is pre-populated)" 10 60 125 3>&1 1>&2 2>&3) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_node_ls_input_threads() { - - LSINPUTTHREADS=$(whiptail --title "Security Onion Setup" --inputbox \ - "\nEnter LogStash Input Threads: \n \n(Default value is pre-populated)" 10 60 1 3>&1 1>&2 2>&3) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_node_ls_input_batch_count() { - - LSINPUTBATCHCOUNT=$(whiptail --title "Security Onion Setup" --inputbox \ - "\nEnter LogStash Input Batch Count: \n \n(Default value is pre-populated)" 10 60 125 3>&1 1>&2 2>&3) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_passwords_dont_match() { - - whiptail --title "Security Onion Setup" --msgbox "Passwords don't match. Please re-enter." 8 78 - -} - -whiptail_patch_name_new_schedule() { - - PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ - "What name do you want to give this OS patch schedule? This schedule needs to be named uniquely. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 105 3>&1 1>&2 2>&3) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - - while [[ -z "$PATCHSCHEDULENAME" ]]; do - whiptail --title "Security Onion Setup" --msgbox "Please enter a name for this OS patch schedule." 8 65 - PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ - "What name do you want to give this OS patch schedule? This schedule needs to be named uniquely. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 105 3>&1 1>&2 2>&3) - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - done - - -} - -whiptail_patch_schedule() { - - # What kind of patch schedule are we doing? - PATCHSCHEDULE=$(whiptail --title "Security Onion Setup" --radiolist \ - "Choose OS patch schedule. This will NOT update Security Onion related tools such as Zeek, Elasticsearch, Kibana, SaltStack, etc." 25 115 5 \ - "Automatic" "Package updates will be installed automatically every 8 hours if available" ON \ - "Manual" "Package updates will need to be installed manually" OFF \ - "Import Schedule" "Enter the name of an existing schedule on the following screen and inherit it" OFF \ - "New Schedule" "Configure and name a new schedule on the following screen" OFF 3>&1 1>&2 2>&3 ) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_patch_schedule_import() { - - unset PATCHSCHEDULENAME - PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter the name of the OS patch schedule you want to inherit. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 60 3>&1 1>&2 2>&3) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - - while [[ -z "$PATCHSCHEDULENAME" ]]; do - whiptail --title "Security Onion Setup" --msgbox "Please enter a name for the OS patch schedule you want to inherit." 8 65 - PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter the name of the OS patch schedule you want to inherit. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 60 3>&1 1>&2 2>&3) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - done - -} - -whiptail_patch_schedule_select_days() { - # Select the days to patch - PATCHSCHEDULEDAYS=($(whiptail --title "Security Onion Setup" --checklist \ - "Which days do you want to apply OS patches?" 20 55 9 \ - "Monday" "" OFF \ - "Tuesday" "" ON \ - "Wednesday" "" OFF \ - "Thursday" "" OFF \ - "Friday" "" OFF \ - "Saturday" "" OFF \ - "Sunday" "" OFF 3>&1 1>&2 2>&3 )) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus -} - -whiptail_patch_schedule_select_hours() { - # Select the hours to patch - PATCHSCHEDULEHOURS=($(whiptail --title "Security Onion Setup" --checklist \ - "At which time, UTC, do you want to apply OS patches on the selected days?" 35 55 26 \ - "00:00" "" OFF \ - "01:00" "" OFF \ - "02:00" "" OFF \ - "03:00" "" OFF \ - "04:00" "" OFF \ - "05:00" "" OFF \ - "06:00" "" OFF \ - "07:00" "" OFF \ - "08:00" "" OFF \ - "09:00" "" OFF \ - "10:00" "" OFF \ - "11:00" "" OFF \ - "12:00" "" OFF \ - "13:00" "" OFF \ - "14:00" "" OFF \ - "15:00" "" ON \ - "16:00" "" OFF \ - "17:00" "" OFF \ - "18:00" "" OFF \ - "19:00" "" OFF \ - "20:00" "" OFF \ - "21:00" "" OFF \ - "22:00" "" OFF \ - "23:00" "" OFF 3>&1 1>&2 2>&3 )) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus -} - -whiptail_rule_setup() { - - # Get pulled pork info - RULESETUP=$(whiptail --title "Security Onion Setup" --radiolist \ - "What IDS rules to use?:" 20 140 4 \ - "ETOPEN" "Emerging Threats Open - no oinkcode required" ON \ - "ETPRO" "Emerging Threats PRO - requires ETPRO oinkcode" OFF \ - "TALOSET" "Snort Subscriber (Talos) ruleset and Emerging Threats NoGPL ruleset - requires Snort Subscriber oinkcode" OFF \ - "TALOS" "Snort Subscriber (Talos) ruleset only and set a Snort Subscriber policy - requires Snort Subscriber oinkcode" OFF 3>&1 1>&2 2>&3 ) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_sensor_config() { - - NSMSETUP=$(whiptail --title "Security Onion Setup" --radiolist \ - "What type of configuration would you like to use?:" 20 78 4 \ - "BASIC" "Install NSM components with recommended settings" ON \ - "ADVANCED" "Configure each component individually" OFF 3>&1 1>&2 2>&3 ) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_set_hostname() { - - HOSTNAME=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter the Hostname you would like to set." 10 60 $HOSTNAME 3>&1 1>&2 2>&3) - - while [[ "$HOSTNAME" == 'localhost' ]] ; do - whiptail --title "Security Onion Setup" --msgbox "Please choose a hostname that isn't localhost." 8 65 - HOSTNAME=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter the Hostname you would like to set." 10 60 $HOSTNAME 3>&1 1>&2 2>&3) - done - - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_setup_complete() { - - whiptail --title "Security Onion Setup" --msgbox "Finished installing this as an $INSTALLTYPE. Press Enter to reboot." 8 78 - install_cleanup - -} - -whiptail_setup_failed() { - - whiptail --title "Security Onion Setup" --msgbox "Install had a problem. Please see $SETUPLOG for details. Press Enter to reboot." 8 78 - install_cleanup - -} - -whiptail_shard_count() { - - SHARDCOUNT=$(whiptail --title "Security Onion Setup" --inputbox \ - "\nEnter ES Shard Count: \n \n(Default value is pre-populated)" 10 60 125 3>&1 1>&2 2>&3) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_suricata_pins() { - - FILTEREDCORES=$(echo ${LISTCORES[@]} ${BROPINS[@]} | tr -d '"' | tr ' ' '\n' | sort | uniq -u | awk '{print $1 " \"" "core" "\""}') - SURIPINS=$(whiptail --noitem --title "Pin Suricata CPUS" --checklist "Please Select $LBPROCS cores to pin Suricata to:" 20 78 12 ${FILTEREDCORES[@]} 3>&1 1>&2 2>&3 ) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_master_updates() { - - MASTERUPDATES=$(whiptail --title "Security Onion Setup" --radiolist \ - "How would you like to download updates for your grid?:" 20 78 4 \ - "MASTER" "Have the master node act as a proxy for OS/Docker updates." ON \ - "OPEN" "Have each node connect to the Internet for updates" OFF 3>&1 1>&2 2>&3 ) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_node_updates() { - - NODEUPDATES=$(whiptail --title "Security Onion Setup" --radiolist \ - "How would you like to download updates for this node?:" 20 78 4 \ - "MASTER" "Download OS/Docker updates from the Master." ON \ - "OPEN" "Download updates directly from the Internet" OFF 3>&1 1>&2 2>&3 ) - - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - -} - -whiptail_you_sure() { - - whiptail --title "Security Onion Setup" --yesno "Are you sure you want to install Security Onion over the internet?" 8 78 - -} - -######################## -## ## -## End Functions ## -## ## -######################## - -##################### -## ## -## Let's Go! ## -## ## -##################### - -# Check for prerequisites -got_root -detect_os - -if [ $OS == ubuntu ]; then - # Override the horrible Ubuntu whiptail color pallete - update-alternatives --set newt-palette /etc/newt/palette.original -fi - -# Question Time -if (whiptail_you_sure); then - - # Create a temp dir to get started - install_prep - - # Let folks know they need their management interface already set up. - whiptail_network_notice - - # Set the hostname to reduce errors - whiptail_set_hostname - - # Go ahead and gen the keys so we can use them for any sensor type - Disabled for now - #minio_generate_keys - - # What kind of install are we doing? - whiptail_install_type - - # How do we want to handle OS patching? manual, auto or scheduled days and hours - whiptail_patch_schedule - case $PATCHSCHEDULE in - 'New Schedule') - whiptail_patch_schedule_select_days - whiptail_patch_schedule_select_hours - whiptail_patch_name_new_schedule - patch_schedule_os_new - ;; - 'Import Schedule') - whiptail_patch_schedule_import - ;; - Automatic) - PATCHSCHEDULENAME=auto - ;; - Manual) - PATCHSCHEDULENAME=manual - ;; - esac - - #################### - ## Master ## - #################### - - if [ $INSTALLTYPE == 'MASTERONLY' ]; then - - # Would you like to do an advanced install? - whiptail_master_adv - - # Pick the Management NIC - whiptail_management_nic - - # Choose Zeek or Community NSM - whiptail_bro_version - - # Select Snort or Suricata - whiptail_nids - - # Snag the HOME_NET - whiptail_homenet_master - - # Pick your Ruleset - whiptail_rule_setup - - # Get the code if it isn't ET Open - if [ $RULESETUP != 'ETOPEN' ]; then - # Get the code - whiptail_oinkcode - fi - - # Find out how to handle updates - whiptail_master_updates - whiptail_enable_components - process_components - - # Do Advacned Setup if they chose it - if [ $MASTERADV == 'ADVANCED' ]; then - # Ask which bro logs to enable - Need to add Suricata check - if [ $BROVERSION != 'SURICATA' ]; then - whiptail_master_adv_service_brologs - fi - fi - - whiptail_create_socore_user - SCMATCH=no - while [ $SCMATCH != yes ]; do - whiptail_create_socore_user_password1 - whiptail_create_socore_user_password2 - check_socore_pass - done - - # Last Chance to back out - whiptail_make_changes - set_hostname - generate_passwords - auth_pillar - clear_master - mkdir -p /nsm - get_filesystem_root - get_filesystem_nsm - # Enable Bro Logs - # comment this out since we already copy this file to the destination that this function writes to - #bro_logs_enabled - - # Figure out the main IP address - get_main_ip - - # Add the user so we can sit back and relax - #echo "" - #echo "**** Please set a password for socore. You will use this password when setting up other Nodes/Sensors" - #echo "" - add_socore_user_master - - # Install salt and dependencies - { - sleep 0.5 - install_python3 >> $SETUPLOG 2>&1 - echo -e "XXX\n1\nInstalling and configuring Salt... \nXXX" - echo " ** Installing Salt and Dependencies **" >> $SETUPLOG - saltify >> $SETUPLOG 2>&1 - echo -e "XXX\n5\nInstalling Docker... \nXXX" - docker_install >> $SETUPLOG 2>&1 - echo -e "XXX\n10\nConfiguring Salt Master... \nXXX" - echo " ** Configuring Minion **" >> $SETUPLOG - configure_minion master >> $SETUPLOG 2>&1 - echo " ** Installing Salt Master **" >> $SETUPLOG - install_master >> $SETUPLOG 2>&1 - salt_install_mysql_deps >> $SETUPLOG 2>&1 - salt_master_directories >> $SETUPLOG 2>&1 - update_sudoers >> $SETUPLOG 2>&1 - chown_salt_master >> $SETUPLOG 2>&1 - es_heapsize >> $SETUPLOG 2>&1 - ls_heapsize >> $SETUPLOG 2>&1 - echo -e "XXX\n25\nConfiguring Default Pillars... \nXXX" - master_static >> $SETUPLOG 2>&1 - echo "** Generating the master pillar **" >> $SETUPLOG - master_pillar >> $SETUPLOG 2>&1 - echo "** Generating the patch pillar **" >> $SETUPLOG - patch_pillar >> $SETUPLOG 2>&1 - echo -e "XXX\n30\nAccepting Salt Keys... \nXXX" - echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" - copy_minion_tmp_files >> $SETUPLOG 2>&1 - # Do a checkin to push the key up - echo "** Pushing the key up to Master **" >> $SETUPLOG - salt_firstcheckin >> $SETUPLOG 2>&1 - # Accept the Master Key - echo "** Accepting the key on the master **" >> $SETUPLOG - accept_salt_key_local >> $SETUPLOG 2>&1 - echo -e "XXX\n35\nConfiguring Firewall... \nXXX" - # Open the firewall - echo "** Setting the initial firewall policy **" >> $SETUPLOG - set_initial_firewall_policy >> $SETUPLOG 2>&1 - # Do the big checkin but first let them know it will take a bit. - echo -e "XXX\n40\nGenerating CA... \nXXX" - salt_checkin >> $SETUPLOG 2>&1 - salt-call state.apply ca >> $SETUPLOG 2>&1 - salt-call state.apply ssl >> $SETUPLOG 2>&1 - echo -e "XXX\n43\nInstalling Common Components... \nXXX" - salt-call state.apply common >> $SETUPLOG 2>&1 - echo -e "XXX\n45\nApplying firewall rules... \nXXX" - salt-call state.apply firewall >> $SETUPLOG 2>&1 - salt-call state.apply master >> $SETUPLOG 2>&1 - salt-call state.apply idstools >> $SETUPLOG 2>&1 - echo -e "XXX\n40\nInstalling Redis... \nXXX" - salt-call state.apply redis >> $SETUPLOG 2>&1 - if [[ $OSQUERY == '1' ]]; then - echo -e "XXX\n41\nInstalling MySQL... \nXXX" - salt-call state.apply mysql >> $SETUPLOG 2>&1 - fi - echo -e "XXX\n45\nInstalling Elastic Components... \nXXX" - salt-call state.apply elasticsearch >> $SETUPLOG 2>&1 - salt-call state.apply logstash >> $SETUPLOG 2>&1 - salt-call state.apply kibana >> $SETUPLOG 2>&1 - salt-call state.apply elastalert >> $SETUPLOG 2>&1 - if [[ $WAZUH == '1' ]]; then - echo -e "XXX\n68\nInstalling Wazuh... \nXXX" - salt-call state.apply wazuh >> $SETUPLOG 2>&1 - fi - echo -e "XXX\n75\nInstalling Filebeat... \nXXX" - salt-call state.apply filebeat >> $SETUPLOG 2>&1 - salt-call state.apply utility >> $SETUPLOG 2>&1 - salt-call state.apply schedule >> $SETUPLOG 2>&1 - if [[ $OSQUERY == '1' ]]; then - echo -e "XXX\n79\nInstalling Fleet... \nXXX" - salt-call state.apply fleet >> $SETUPLOG 2>&1 - salt-call state.apply launcher >> $SETUPLOG 2>&1 - fi - echo -e "XXX\n85\nConfiguring SOctopus... \nXXX" - salt-call state.apply soctopus >> $SETUPLOG 2>&1 - if [[ $THEHIVE == '1' ]]; then - echo -e "XXX\n87\nInstalling TheHive... \nXXX" - salt-call state.apply hive >> $SETUPLOG 2>&1 - fi - if [[ $PLAYBOOK == '1' ]]; then - echo -e "XXX\n89\nInstalling Playbook... \nXXX" - salt-call state.apply playbook >> $SETUPLOG 2>&1 - fi - echo -e "XXX\n75\nEnabling Checking at Boot... \nXXX" - checkin_at_boot >> $SETUPLOG 2>&1 - echo -e "XXX\n95\nVerifying Install... \nXXX" - salt-call state.highstate >> $SETUPLOG 2>&1 - echo -e "XX\n99\nFinishing touches... \nXXX" - filter_unused_nics >> $SETUPLOG 2>&1 - network_setup >> $SETUPLOG 2>&1 - } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 - GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') - if [[ $GOODSETUP == '0' ]]; then - whiptail_setup_complete - if [[ $THEHIVE == '1' ]]; then - check_hive_init_then_reboot - else - shutdown -r now - fi - else - whiptail_setup_failed - shutdown -r now - fi - - fi - - #################### - ## Sensor ## - #################### - - if [ $INSTALLTYPE == 'SENSORONLY' ]; then - whiptail_management_nic - filter_unused_nics - whiptail_bond_nics - whiptail_management_server - whiptail_master_updates - set_updates - whiptail_homenet_sensor - whiptail_sensor_config - # Calculate lbprocs so we can call it in the prompts - calculate_useable_cores - if [ $NSMSETUP == 'ADVANCED' ]; then - whiptail_bro_pins - whiptail_suricata_pins - whiptail_bond_nics_mtu - else - whiptail_basic_bro - whiptail_basic_suri - fi - whiptail_make_changes - set_hostname - clear_master - mkdir -p /nsm - get_filesystem_root - get_filesystem_nsm - copy_ssh_key >> $SETUPLOG 2>&1 - { - sleep 0.5 - echo -e "XXX\n0\nSetting Initial Firewall Policy... \nXXX" - set_initial_firewall_policy >> $SETUPLOG 2>&1 - echo -e "XXX\n1\nInstalling pip3... \nXXX" - install_python3 >> $SETUPLOG 2>&1 - echo -e "XXX\n3\nCreating Bond Interface... \nXXX" - create_sensor_bond >> $SETUPLOG 2>&1 - echo -e "XXX\n4\nGenerating Sensor Pillar... \nXXX" - sensor_pillar >> $SETUPLOG 2>&1 - echo "** Generating the patch pillar **" >> $SETUPLOG - patch_pillar >> $SETUPLOG 2>&1 - echo -e "XXX\n5\nInstalling Salt Components... \nXXX" - saltify >> $SETUPLOG 2>&1 - echo -e "XXX\n20\nInstalling Docker... \nXXX" - docker_install >> $SETUPLOG 2>&1 - echo -e "XXX\n22\nConfiguring Salt Minion... \nXXX" - configure_minion sensor >> $SETUPLOG 2>&1 - echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" - copy_minion_tmp_files >> $SETUPLOG 2>&1 - echo -e "XXX\n25\nSending Salt Key to Master... \nXXX" - salt_firstcheckin >> $SETUPLOG 2>&1 - echo -e "XXX\n26\nTelling the Master to Accept Key... \nXXX" - # Accept the Salt Key - accept_salt_key_remote >> $SETUPLOG 2>&1 - echo -e "XXX\n27\nApplying SSL Certificates... \nXXX" - salt-call state.apply ca >> $SETUPLOG 2>&1 - salt-call state.apply ssl >> $SETUPLOG 2>&1 - echo -e "XXX\n35\nInstalling Core Components... \nXXX" - salt-call state.apply common >> $SETUPLOG 2>&1 - salt-call state.apply firewall >> $SETUPLOG 2>&1 - echo -e "XXX\n50\nInstalling PCAP... \nXXX" - salt-call state.apply pcap >> $SETUPLOG 2>&1 - echo -e "XXX\n60\nInstalling IDS components... \nXXX" - salt-call state.apply suricata >> $SETUPLOG 2>&1 - echo -e "XXX\n80\nVerifying Install... \nXXX" - salt-call state.highstate >> $SETUPLOG 2>&1 - checkin_at_boot >> $SETUPLOG 2>&1 - echo -e "XX\n99\nFinishing touches... \nXXX" - filter_unused_nics >> $SETUPLOG 2>&1 - network_setup >> $SETUPLOG 2>&1 - } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 - GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') - if [[ $GOODSETUP == '0' ]]; then - whiptail_setup_complete - shutdown -r now - else - whiptail_setup_failed - shutdown -r now - fi - fi - - ####################### - ## Eval Mode ## - ####################### - - if [ $INSTALLTYPE == 'EVALMODE' ]; then - # Select the management NIC - whiptail_management_nic - - # Filter out the management NIC - filter_unused_nics - - # Select which NICs are in the bond - whiptail_bond_nics - - # Snag the HOME_NET - whiptail_homenet_master - whiptail_eval_adv_warning - whiptail_enable_components - - # Set a bunch of stuff since this is eval - es_heapsize - ls_heapsize - NODE_ES_HEAP_SIZE="600m" - NODE_LS_HEAP_SIZE="500m" - LSPIPELINEWORKERS=1 - LSPIPELINEBATCH=125 - LSINPUTTHREADS=1 - LSINPUTBATCHCOUNT=125 - RULESETUP=ETOPEN - NSMSETUP=BASIC - NIDS=Suricata - BROVERSION=ZEEK - CURCLOSEDAYS=30 - process_components - whiptail_create_socore_user - SCMATCH=no - while [ $SCMATCH != yes ]; do - whiptail_create_socore_user_password1 - whiptail_create_socore_user_password2 - check_socore_pass - done - whiptail_make_changes - set_hostname - generate_passwords - auth_pillar - clear_master - mkdir -p /nsm - get_filesystem_root - get_filesystem_nsm - get_log_size_limit - get_main_ip - # Add the user so we can sit back and relax - add_socore_user_master - { - sleep 0.5 - echo -e "XXX\n0\nCreating Bond Interface... \nXXX" - create_sensor_bond >> $SETUPLOG 2>&1 - echo -e "XXX\n1\nInstalling Python 3... \nXXX" - install_python3 >> $SETUPLOG 2>&1 - echo -e "XXX\n2\nInstalling saltstack... \nXXX" - saltify >> $SETUPLOG 2>&1 - echo -e "XXX\n3\nInstalling docker... \nXXX" - docker_install >> $SETUPLOG 2>&1 - echo -e "XXX\n5\nInstalling master code... \nXXX" - install_master >> $SETUPLOG 2>&1 - echo -e "XXX\n5\nInstalling mysql dependencies for saltstack... \nXXX" - salt_install_mysql_deps >> $SETUPLOG 2>&1 - echo -e "XXX\n6\nCopying salt code... \nXXX" - salt_master_directories >> $SETUPLOG 2>&1 - echo -e "XXX\n6\nupdating suduers... \nXXX" - update_sudoers >> $SETUPLOG 2>&1 - echo -e "XXX\n7\nFixing some permissions... \nXXX" - chown_salt_master >> $SETUPLOG 2>&1 - echo -e "XXX\n7\nCreating the static pillar... \nXXX" - # Set the static values - master_static >> $SETUPLOG 2>&1 - echo -e "XXX\n7\nCreating the master pillar... \nXXX" - master_pillar >> $SETUPLOG 2>&1 - echo "** Generating the patch pillar **" >> $SETUPLOG - patch_pillar >> $SETUPLOG 2>&1 - echo -e "XXX\n7\nConfiguring minion... \nXXX" - configure_minion eval >> $SETUPLOG 2>&1 - echo -e "XXX\n7\nSetting the node type to eval... \nXXX" - set_node_type >> $SETUPLOG 2>&1 - echo -e "XXX\n7\nStorage node pillar... \nXXX" - node_pillar >> $SETUPLOG 2>&1 - echo -e "XXX\n8\nCreating firewall policies... \nXXX" - set_initial_firewall_policy >> $SETUPLOG 2>&1 - echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" - copy_minion_tmp_files >> $SETUPLOG 2>&1 - echo -e "XXX\n10\nRegistering agent... \nXXX" - salt_firstcheckin >> $SETUPLOG 2>&1 - echo -e "XXX\n11\nAccepting Agent... \nXXX" - accept_salt_key_local >> $SETUPLOG 2>&1 - echo -e "XXX\n12\nRunning the SSL states... \nXXX" - salt_checkin >> $SETUPLOG 2>&1 - salt-call state.apply ca >> $SETUPLOG 2>&1 - salt-call state.apply ssl >> $SETUPLOG 2>&1 - echo -e "XXX\n15\nInstalling core components... \nXXX" - salt-call state.apply common >> $SETUPLOG 2>&1 - echo -e "XXX\n18\nInitializing firewall rules... \nXXX" - salt-call state.apply firewall >> $SETUPLOG 2>&1 - echo -e "XXX\n25\nInstalling master components... \nXXX" - salt-call state.apply master >> $SETUPLOG 2>&1 - salt-call state.apply idstools >> $SETUPLOG 2>&1 - if [[ $OSQUERY == '1' ]]; then - salt-call state.apply mysql >> $SETUPLOG 2>&1 - fi - echo -e "XXX\n35\nInstalling ElasticSearch... \nXXX" - salt-call state.apply elasticsearch >> $SETUPLOG 2>&1 - echo -e "XXX\n40\nInstalling Logstash... \nXXX" - salt-call state.apply logstash >> $SETUPLOG 2>&1 - echo -e "XXX\n45\nInstalling Kibana... \nXXX" - salt-call state.apply kibana >> $SETUPLOG 2>&1 - echo -e "XXX\n50\nInstalling pcap... \nXXX" - salt-call state.apply pcap >> $SETUPLOG 2>&1 - echo -e "XXX\n52\nInstalling Suricata... \nXXX" - salt-call state.apply suricata >> $SETUPLOG 2>&1 - echo -e "XXX\n54\nInstalling Zeek... \nXXX" - salt-call state.apply bro >> $SETUPLOG 2>&1 - echo -e "XXX\n56\nInstalling curator... \nXXX" - salt-call state.apply curator >> $SETUPLOG 2>&1 - echo -e "XXX\n58\nInstalling elastalert... \nXXX" - salt-call state.apply elastalert >> $SETUPLOG 2>&1 - if [[ $OSQUERY == '1' ]]; then - echo -e "XXX\n60\nInstalling fleet... \nXXX" - salt-call state.apply fleet >> $SETUPLOG 2>&1 - salt-call state.apply redis >> $SETUPLOG 2>&1 - fi - if [[ $WAZUH == '1' ]]; then - echo -e "XXX\n65\nInstalling Wazuh components... \nXXX" - salt-call state.apply wazuh >> $SETUPLOG 2>&1 - fi - echo -e "XXX\n85\nInstalling filebeat... \nXXX" - salt-call state.apply filebeat >> $SETUPLOG 2>&1 - salt-call state.apply utility >> $SETUPLOG 2>&1 - echo -e "XXX\n90\nInstalling misc components... \nXXX" - salt-call state.apply schedule >> $SETUPLOG 2>&1 - salt-call state.apply soctopus >> $SETUPLOG 2>&1 - if [[ $THEHIVE == '1' ]]; then - echo -e "XXX\n91\nInstalling The Hive... \nXXX" - salt-call state.apply hive >> $SETUPLOG 2>&1 - fi - if [[ $PLAYBOOK == '1' ]]; then - echo -e "XXX\n93\nInstalling Playbook... \nXXX" - salt-call state.apply playbook >> $SETUPLOG 2>&1 - fi - echo -e "XXX\n95\nSetting checkin to run on boot... \nXXX" - checkin_at_boot >> $SETUPLOG 2>&1 - echo -e "XXX\n98\nVerifying Setup... \nXXX" - salt-call state.highstate >> $SETUPLOG 2>&1 - echo -e "XX\n99\nFinishing touches... \nXXX" - filter_unused_nics >> $SETUPLOG 2>&1 - network_setup >> $SETUPLOG 2>&1 - } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 - GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') - if [ $OS == 'centos' ]; then - if [[ $GOODSETUP == '1' ]]; then - whiptail_setup_complete - if [[ $THEHIVE == '1' ]]; then - check_hive_init_then_reboot - else - shutdown -r now - fi - else - whiptail_setup_failed - shutdown -r now - fi - else - if [[ $GOODSETUP == '0' ]]; then - whiptail_setup_complete - if [[ $THEHIVE == '1' ]]; then - check_hive_init_then_reboot - else - shutdown -r now - fi - else - whiptail_setup_failed - shutdown -r now - fi - fi - fi - - ################### - ## Nodes ## - ################### - - if [ $INSTALLTYPE == 'STORAGENODE' ] || [ $INSTALLTYPE == 'PARSINGNODE' ] || [ $INSTALLTYPE == 'HOTNODE' ] || [ $INSTALLTYPE == 'WARMNODE' ]; then - whiptail_management_nic - whiptail_management_server - whiptail_master_updates - set_updates - get_log_size_limit - CURCLOSEDAYS=30 - es_heapsize - ls_heapsize - whiptail_node_advanced - if [ $NODESETUP == 'NODEADVANCED' ]; then - whiptail_node_es_heap - whiptail_node_ls_heap - whiptail_node_ls_pipeline_worker - whiptail_node_ls_pipline_batchsize - whiptail_node_ls_input_threads - whiptail_node_ls_input_batch_count - whiptail_cur_close_days - whiptail_log_size_limit - else - NODE_ES_HEAP_SIZE=$ES_HEAP_SIZE - NODE_LS_HEAP_SIZE=$LS_HEAP_SIZE - LSPIPELINEWORKERS=$CPUCORES - LSPIPELINEBATCH=125 - LSINPUTTHREADS=1 - LSINPUTBATCHCOUNT=125 - fi - whiptail_make_changes - set_hostname - clear_master - mkdir -p /nsm - get_filesystem_root - get_filesystem_nsm - copy_ssh_key >> $SETUPLOG 2>&1 - { - sleep 0.5 - echo -e "XXX\n0\nSetting Initial Firewall Policy... \nXXX" - set_initial_firewall_policy >> $SETUPLOG 2>&1 - echo -e "XXX\n1\nInstalling pip3... \nXXX" - install_python3 >> $SETUPLOG 2>&1 - echo -e "XXX\n5\nInstalling Salt Packages... \nXXX" - saltify >> $SETUPLOG 2>&1 - echo -e "XXX\n20\nInstalling Docker... \nXXX" - docker_install >> $SETUPLOG 2>&1 - echo -e "XXX\n30\nInitializing Minion... \nXXX" - configure_minion node >> $SETUPLOG 2>&1 - set_node_type >> $SETUPLOG 2>&1 - node_pillar >> $SETUPLOG 2>&1 - echo "** Generating the patch pillar **" >> $SETUPLOG - patch_pillar >> $SETUPLOG 2>&1 - echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" - copy_minion_tmp_files >> $SETUPLOG 2>&1 - echo -e "XXX\n35\nSending and Accepting Salt Key... \nXXX" - salt_firstcheckin >> $SETUPLOG 2>&1 - # Accept the Salt Key - accept_salt_key_remote >> $SETUPLOG 2>&1 - echo -e "XXX\n40\nApplying SSL Certificates... \nXXX" - salt-call state.apply ca >> $SETUPLOG 2>&1 - salt-call state.apply ssl >> $SETUPLOG 2>&1 - echo -e "XXX\n50\nConfiguring Firewall... \nXXX" - salt-call state.apply common >> $SETUPLOG 2>&1 - salt-call state.apply firewall >> $SETUPLOG 2>&1 - echo -e "XXX\n70\nInstalling Elastic Components... \nXXX" - salt-call state.apply logstash >> $SETUPLOG 2>&1 - salt-call state.apply elasticsearch >> $SETUPLOG 2>&1 - salt-call state.apply curator >> $SETUPLOG 2>&1 - salt-call state.apply filebeat >> $SETUPLOG 2>&1 - echo -e "XXX\n90\nVerifying Install... \nXXX" - salt-call state.highstate >> $SETUPLOG 2>&1 - checkin_at_boot >> $SETUPLOG 2>&1 - echo -e "XX\n99\nFinishing touches... \nXXX" - filter_unused_nics >> $SETUPLOG 2>&1 - network_setup >> $SETUPLOG 2>&1 - } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 - GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') - if [[ $GOODSETUP == '0' ]]; then - whiptail_setup_complete - shutdown -r now - else - whiptail_setup_failed - shutdown -r now - fi - - #set_initial_firewall_policy - #saltify - #docker_install - #configure_minion node - #set_node_type - #node_pillar - #copy_minion_pillar nodes - #salt_checkin - # Accept the Salt Key - #accept_salt_key_remote - # Do the big checkin but first let them know it will take a bit. - #salt_checkin_message - #salt_checkin - #checkin_at_boot - - #whiptail_setup_complete - fi - -else - exit -fi +bash setup/so-setup.sh network From 1cc2365cf129500cc38e1fcc6b473b79af99d513 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 3 Dec 2019 16:17:47 -0500 Subject: [PATCH 107/200] New Setup Script - Fix Path --- so-setup-network.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/so-setup-network.sh b/so-setup-network.sh index 329c18b1b..d12ad6181 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -15,4 +15,4 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -bash setup/so-setup.sh network +cd setup && bash so-setup.sh network From 3cf547c50c5322ad9c32edb517b252b27ad5a638 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 3 Dec 2019 17:07:38 -0500 Subject: [PATCH 108/200] New Setup Script - Fix path for copy of offload script --- setup/functions.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/functions.sh b/setup/functions.sh index 3c9c65896..601b66c89 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -673,7 +673,7 @@ network_setup() { nmcli con mod $MAININT connection.autoconnect "yes" >> $SETUPLOG 2>&1 echo "... Copying disable-checksum-offload.sh" >> $SETUPLOG 2>&1 - cp ./install_scripts/disable-checksum-offload.sh /etc/NetworkManager/dispatcher.d/disable-checksum-offload.sh >> $SETUPLOG 2>&1 + cp ../install_scripts/disable-checksum-offload.sh /etc/NetworkManager/dispatcher.d/disable-checksum-offload.sh >> $SETUPLOG 2>&1 echo "... Modifying disable-checksum-offload.sh" >> $SETUPLOG 2>&1 sed -i "s/\$MAININT/${MAININT}/g" /etc/NetworkManager/dispatcher.d/disable-checksum-offload.sh >> $SETUPLOG 2>&1 From 649c7069267e309f4c2821770ad96d0846598a6f Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 3 Dec 2019 17:16:34 -0500 Subject: [PATCH 109/200] New Setup Script - Fix order so setup check works --- setup/so-setup.sh | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/setup/so-setup.sh b/setup/so-setup.sh index 6975cc33a..ced442145 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -249,11 +249,11 @@ if (whiptail_you_sure); then fi echo -e "XXX\n75\nEnabling Checking at Boot... \nXXX" checkin_at_boot >> $SETUPLOG 2>&1 - echo -e "XXX\n95\nVerifying Install... \nXXX" - salt-call state.highstate >> $SETUPLOG 2>&1 - echo -e "XX\n99\nFinishing touches... \nXXX" + echo -e "XX\n97\nFinishing touches... \nXXX" filter_unused_nics >> $SETUPLOG 2>&1 network_setup >> $SETUPLOG 2>&1 + echo -e "XXX\n98\nVerifying Setup... \nXXX" + salt-call state.highstate >> $SETUPLOG 2>&1 } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') if [[ $GOODSETUP == '0' ]]; then @@ -335,12 +335,12 @@ if (whiptail_you_sure); then salt-call state.apply pcap >> $SETUPLOG 2>&1 echo -e "XXX\n60\nInstalling IDS components... \nXXX" salt-call state.apply suricata >> $SETUPLOG 2>&1 - echo -e "XXX\n80\nVerifying Install... \nXXX" - salt-call state.highstate >> $SETUPLOG 2>&1 checkin_at_boot >> $SETUPLOG 2>&1 - echo -e "XX\n99\nFinishing touches... \nXXX" + echo -e "XX\n97\nFinishing touches... \nXXX" filter_unused_nics >> $SETUPLOG 2>&1 network_setup >> $SETUPLOG 2>&1 + echo -e "XXX\n98\nVerifying Setup... \nXXX" + salt-call state.highstate >> $SETUPLOG 2>&1 } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') if [[ $GOODSETUP == '0' ]]; then @@ -501,11 +501,11 @@ if (whiptail_you_sure); then fi echo -e "XXX\n95\nSetting checkin to run on boot... \nXXX" checkin_at_boot >> $SETUPLOG 2>&1 - echo -e "XXX\n98\nVerifying Setup... \nXXX" - salt-call state.highstate >> $SETUPLOG 2>&1 - echo -e "XX\n99\nFinishing touches... \nXXX" + echo -e "XX\n97\nFinishing touches... \nXXX" filter_unused_nics >> $SETUPLOG 2>&1 network_setup >> $SETUPLOG 2>&1 + echo -e "XXX\n98\nVerifying Setup... \nXXX" + salt-call state.highstate >> $SETUPLOG 2>&1 } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') if [ $OS == 'centos' ]; then @@ -606,12 +606,11 @@ if (whiptail_you_sure); then salt-call state.apply elasticsearch >> $SETUPLOG 2>&1 salt-call state.apply curator >> $SETUPLOG 2>&1 salt-call state.apply filebeat >> $SETUPLOG 2>&1 - echo -e "XXX\n90\nVerifying Install... \nXXX" - salt-call state.highstate >> $SETUPLOG 2>&1 checkin_at_boot >> $SETUPLOG 2>&1 - echo -e "XX\n99\nFinishing touches... \nXXX" + echo -e "XX\n97\nFinishing touches... \nXXX" filter_unused_nics >> $SETUPLOG 2>&1 network_setup >> $SETUPLOG 2>&1 + echo -e "XXX\n98\nVerifying Setup... \nXXX" } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') if [[ $GOODSETUP == '0' ]]; then From 5eb0a4f19c01d41fcb585d26beb4ddae6113646e Mon Sep 17 00:00:00 2001 From: Wes Lambert Date: Wed, 4 Dec 2019 03:12:02 +0000 Subject: [PATCH 110/200] update SOCtopus conf --- salt/soctopus/files/SOCtopus.conf | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/salt/soctopus/files/SOCtopus.conf b/salt/soctopus/files/SOCtopus.conf index dd32507ef..d7314bbac 100644 --- a/salt/soctopus/files/SOCtopus.conf +++ b/salt/soctopus/files/SOCtopus.conf @@ -1,9 +1,15 @@ {%- set ip = salt['pillar.get']('static:masterip', '') %} {%- set HIVEKEY = salt['pillar.get']('static:hivekey', '') %} +{%- set CORTEXKEY = salt['pillar.get']('static:cortexorguserkey', '') %} [es] es_url = http://{{ip}}:9200 +[cortex] +supported_analyzers = Urlscan_io_Search,CERTatPassiveDNS +cortex_url = https://{{ip}}/cortex/ +cortex_key = {{ CORTEXKEY }} + [fir] fir_url = YOURFIRURL fir_token = YOURFIRTOKEN From 79e1ac533604b58623ae209d09e26fe34d576670 Mon Sep 17 00:00:00 2001 From: Wes Lambert Date: Wed, 4 Dec 2019 18:39:58 +0000 Subject: [PATCH 111/200] add webhook --- salt/hive/thehive/etc/application.conf | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/salt/hive/thehive/etc/application.conf b/salt/hive/thehive/etc/application.conf index 3b6c89637..14a635e54 100644 --- a/salt/hive/thehive/etc/application.conf +++ b/salt/hive/thehive/etc/application.conf @@ -208,3 +208,8 @@ misp { # purpose = ImportAndExport #} ## <-- Uncomment to complete the configuration } +webhooks { + SOCtopusWebHook { + url = "http://{{ MASTERIP }}:7000/enrich" + } +} From b58b3afa35347f2dc8d7de0dc5571776b76e7442 Mon Sep 17 00:00:00 2001 From: Wes Lambert Date: Thu, 5 Dec 2019 03:22:10 +0000 Subject: [PATCH 112/200] add auto_analyze_alerts option --- salt/soctopus/files/SOCtopus.conf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/salt/soctopus/files/SOCtopus.conf b/salt/soctopus/files/SOCtopus.conf index d7314bbac..37ec0172d 100644 --- a/salt/soctopus/files/SOCtopus.conf +++ b/salt/soctopus/files/SOCtopus.conf @@ -6,9 +6,10 @@ es_url = http://{{ip}}:9200 [cortex] -supported_analyzers = Urlscan_io_Search,CERTatPassiveDNS +auto_analyze_alerts = no cortex_url = https://{{ip}}/cortex/ cortex_key = {{ CORTEXKEY }} +supported_analyzers = Urlscan_io_Search,CERTatPassiveDNS [fir] fir_url = YOURFIRURL From fb0fc1120b51f1046f7b23db732c91e9a1037bad Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 5 Dec 2019 10:41:21 -0500 Subject: [PATCH 113/200] revert Ubuntu to Salt py2.7 --- salt/filebeat/init.sls | 6 +++--- setup/functions.sh | 34 +++++++--------------------------- setup/so-setup.sh | 4 ---- 3 files changed, 10 insertions(+), 34 deletions(-) diff --git a/salt/filebeat/init.sls b/salt/filebeat/init.sls index b1acae649..31c996f51 100644 --- a/salt/filebeat/init.sls +++ b/salt/filebeat/init.sls @@ -39,9 +39,9 @@ filebeatpkidir: # This needs to be owned by root filebeatconfsync: - file.recurse: - - name: /opt/so/conf/filebeat/etc - - source: salt://filebeat/etc + file.managed: + - name: /opt/so/conf/filebeat/etc/filebeat.yml + - source: salt://filebeat/etc/filebeat.yml - user: 0 - group: 0 - template: jinja diff --git a/setup/functions.sh b/setup/functions.sh index 601b66c89..d251ecbac 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -525,18 +525,6 @@ install_cleanup() { } -install_python3() { - - echo "Installing Python3" - - if [ $OS == 'ubuntu' ]; then - apt-get -y install python3-pip python3-dev -# elif [ $OS == 'centos' ]; then -# yum -y install epel-release python3 - fi - -} - install_prep() { # Create a tmp space that isn't in /tmp @@ -944,6 +932,7 @@ EOF fi echo "exclude=salt*" >> /etc/yum.conf + # Our OS is not CentOS else ADDUSER=useradd DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade @@ -957,13 +946,11 @@ EOF # Nasty hack but required for now if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then - #echo "Using pip3 to install python-dateutil for salt" - #pip3 install python-dateutil # Install the repo for salt wget --inet4-only -O - https://repo.saltstack.com/apt/ubuntu/$UVER/amd64/latest/SALTSTACK-GPG-KEY.pub | apt-key add - wget --inet4-only -O - https://repo.saltstack.com/apt/ubuntu/$UVER/amd64/2019.2/SALTSTACK-GPG-KEY.pub | apt-key add - - echo "deb http://repo.saltstack.com/py3/ubuntu/$UVER/amd64/latest xenial main" > /etc/apt/sources.list.d/saltstack.list - echo "deb http://repo.saltstack.com/py3/ubuntu/$UVER/amd64/2019.2 xenial main" > /etc/apt/sources.list.d/saltstack2019.list + echo "deb http://repo.saltstack.com/apt/ubuntu/$UVER/amd64/latest xenial main" > /etc/apt/sources.list.d/saltstack.list + echo "deb http://repo.saltstack.com/apt/ubuntu/$UVER/amd64/2019.2 xenial main" > /etc/apt/sources.list.d/saltstack2019.list # Lets get the docker repo added curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - @@ -983,7 +970,7 @@ EOF # Initialize the new repos apt-get update >> $SETUPLOG 2>&1 # Need to add python packages here - apt-get -y install salt-minion=2019.2.2+ds-1 salt-common=2019.2.2+ds-1 python3-dateutil >> $SETUPLOG 2>&1 + apt-get -y install salt-minion=2019.2.2+ds-1 salt-common=2019.2.2+ds-1 python-dateutil python-m2crypto >> $SETUPLOG 2>&1 apt-mark hold salt-minion salt-common else @@ -995,16 +982,11 @@ EOF echo "Using apt-key add to add SALTSTACK-GPG-KEY.pub and GPG-KEY-WAZUH" apt-key add $TMP/gpg/SALTSTACK-GPG-KEY.pub apt-key add $TMP/gpg/GPG-KEY-WAZUH - echo "deb http://repo.saltstack.com/py3/ubuntu/$UVER/amd64/latest xenial main" > /etc/apt/sources.list.d/saltstack.list + echo "deb http://repo.saltstack.com/apt/ubuntu/$UVER/amd64/latest xenial main" > /etc/apt/sources.list.d/saltstack.list echo "deb https://packages.wazuh.com/3.x/apt/ stable main" | tee /etc/apt/sources.list.d/wazuh.list # Initialize the new repos apt-get update >> $SETUPLOG 2>&1 - echo "Installing libssl-dev for M2Crypto" - apt-get -y install libssl-dev - echo "Using pip3 to install M2Crypto for Salt" - pip3 install M2Crypto - # Need to add python dateutil here - apt-get -y install salt-minion=2019.2.2+ds-1 salt-common=2019.2.2+ds-1 >> $SETUPLOG 2>&1 + apt-get -y install salt-minion=2019.2.2+ds-1 salt-common=2019.2.2+ds-1 python-dateutil python-m2crypto >> $SETUPLOG 2>&1 apt-mark hold salt-minion salt-common fi @@ -1074,9 +1056,7 @@ salt_install_mysql_deps() { if [ $OS == 'centos' ]; then yum -y install mariadb-devel elif [ $OS == 'ubuntu' ]; then - apt-get -y install libmysqlclient-dev gcc - echo "Using pip3 to install mysqlclient for salt" - pip3 install mysqlclient + apt-get -y install python-mysqldb fi } diff --git a/setup/so-setup.sh b/setup/so-setup.sh index ced442145..627e3bc2b 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -166,7 +166,6 @@ if (whiptail_you_sure); then # Install salt and dependencies { sleep 0.5 - install_python3 >> $SETUPLOG 2>&1 echo -e "XXX\n1\nInstalling and configuring Salt... \nXXX" echo " ** Installing Salt and Dependencies **" >> $SETUPLOG saltify >> $SETUPLOG 2>&1 @@ -305,7 +304,6 @@ if (whiptail_you_sure); then echo -e "XXX\n0\nSetting Initial Firewall Policy... \nXXX" set_initial_firewall_policy >> $SETUPLOG 2>&1 echo -e "XXX\n1\nInstalling pip3... \nXXX" - install_python3 >> $SETUPLOG 2>&1 echo -e "XXX\n3\nCreating Bond Interface... \nXXX" create_sensor_bond >> $SETUPLOG 2>&1 echo -e "XXX\n4\nGenerating Sensor Pillar... \nXXX" @@ -410,7 +408,6 @@ if (whiptail_you_sure); then echo -e "XXX\n0\nCreating Bond Interface... \nXXX" create_sensor_bond >> $SETUPLOG 2>&1 echo -e "XXX\n1\nInstalling Python 3... \nXXX" - install_python3 >> $SETUPLOG 2>&1 echo -e "XXX\n2\nInstalling saltstack... \nXXX" saltify >> $SETUPLOG 2>&1 echo -e "XXX\n3\nInstalling docker... \nXXX" @@ -578,7 +575,6 @@ if (whiptail_you_sure); then echo -e "XXX\n0\nSetting Initial Firewall Policy... \nXXX" set_initial_firewall_policy >> $SETUPLOG 2>&1 echo -e "XXX\n1\nInstalling pip3... \nXXX" - install_python3 >> $SETUPLOG 2>&1 echo -e "XXX\n5\nInstalling Salt Packages... \nXXX" saltify >> $SETUPLOG 2>&1 echo -e "XXX\n20\nInstalling Docker... \nXXX" From 9413ec97dc178bb03af6fbf20828b308c98ada29 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 5 Dec 2019 12:04:22 -0500 Subject: [PATCH 114/200] New Setup Script - Add ISO support --- setup/so-setup.sh | 106 +++++++++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 44 deletions(-) diff --git a/setup/so-setup.sh b/setup/so-setup.sh index 627e3bc2b..d848d46e8 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -23,9 +23,9 @@ source whiptail.sh OPTIONS=$1 if [[ $OPTIONS = 'iso' ]]; then - ISOINSTALL=1 + INSTALLMETHOD="iso" else - ISOINSTALL=0 + INSTALLMETHOD="network" fi # Global Variables @@ -58,11 +58,67 @@ if (whiptail_you_sure); then # Create a temp dir to get started install_prep - # Let folks know they need their management interface already set up. - whiptail_network_notice + if [ $INSTALLMETHOD == network ]; then + # Let folks know they need their management interface already set up. + whiptail_network_notice - # Set the hostname to reduce errors - whiptail_set_hostname + # Set the hostname to reduce errors + whiptail_set_hostname + + # Set management nic + whiptail_management_nic + + whiptail_create_socore_user + SCMATCH=no + while [ $SCMATCH != yes ]; do + whiptail_create_socore_user_password1 + whiptail_create_socore_user_password2 + check_socore_pass + done + + else + + # Set the hostname + whiptail_set_hostname + whiptail_management_nic + + # Ask if you want dhcp or static + whiptail_dhcp_or_static + + # Do this if it static is selected + if [ $ADDRESSTYPE != 'DHCP' ]; then + whiptail_management_interface_ip + whiptail_management_interface_mask + whiptail_management_interface_gateway + whiptail_management_interface_dns + whiptail_management_interface_dns_search + fi + + # Go ahead and bring up networking so other parts of the install work + set_hostname + set_management_interface + + # Add an admin user + whiptail_create_admin_user + + # Get a password for the admin user + APMATCH=no + while [ $APMATCH != yes ]; do + whiptail_create_admin_user_password1 + whiptail_create_admin_user_password2 + check_admin_pass + done + + # Get a password for the socore user + whiptail_create_socore_user + SCMATCH=no + while [ $SCMATCH != yes ]; do + whiptail_create_socore_user_password1 + whiptail_create_socore_user_password2 + check_socore_pass + done + + fi # Go ahead and gen the keys so we can use them for any sensor type - Disabled for now #minio_generate_keys @@ -99,9 +155,6 @@ if (whiptail_you_sure); then # Would you like to do an advanced install? whiptail_master_adv - # Pick the Management NIC - whiptail_management_nic - # Choose Zeek or Community NSM whiptail_bro_version @@ -133,14 +186,6 @@ if (whiptail_you_sure); then fi fi - whiptail_create_socore_user - SCMATCH=no - while [ $SCMATCH != yes ]; do - whiptail_create_socore_user_password1 - whiptail_create_socore_user_password2 - check_socore_pass - done - # Last Chance to back out whiptail_make_changes set_hostname @@ -274,7 +319,6 @@ if (whiptail_you_sure); then #################### if [ $INSTALLTYPE == 'SENSORONLY' ]; then - whiptail_management_nic filter_unused_nics whiptail_bond_nics whiptail_management_server @@ -355,8 +399,6 @@ if (whiptail_you_sure); then ####################### if [ $INSTALLTYPE == 'EVALMODE' ]; then - # Select the management NIC - whiptail_management_nic # Filter out the management NIC filter_unused_nics @@ -384,13 +426,6 @@ if (whiptail_you_sure); then BROVERSION=ZEEK CURCLOSEDAYS=30 process_components - whiptail_create_socore_user - SCMATCH=no - while [ $SCMATCH != yes ]; do - whiptail_create_socore_user_password1 - whiptail_create_socore_user_password2 - check_socore_pass - done whiptail_make_changes set_hostname generate_passwords @@ -537,7 +572,6 @@ if (whiptail_you_sure); then ################### if [ $INSTALLTYPE == 'STORAGENODE' ] || [ $INSTALLTYPE == 'PARSINGNODE' ] || [ $INSTALLTYPE == 'HOTNODE' ] || [ $INSTALLTYPE == 'WARMNODE' ]; then - whiptail_management_nic whiptail_management_server whiptail_master_updates set_updates @@ -617,22 +651,6 @@ if (whiptail_you_sure); then shutdown -r now fi - #set_initial_firewall_policy - #saltify - #docker_install - #configure_minion node - #set_node_type - #node_pillar - #copy_minion_pillar nodes - #salt_checkin - # Accept the Salt Key - #accept_salt_key_remote - # Do the big checkin but first let them know it will take a bit. - #salt_checkin_message - #salt_checkin - #checkin_at_boot - - #whiptail_setup_complete fi else From 6040633a8c0eccd463a84a5d879604634064a436 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 5 Dec 2019 12:38:46 -0500 Subject: [PATCH 115/200] update OS patch restart needed MOTD --- salt/motd/files/package_update_reboot_required.jinja | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/salt/motd/files/package_update_reboot_required.jinja b/salt/motd/files/package_update_reboot_required.jinja index 3a1fd1e9e..6d94fc613 100644 --- a/salt/motd/files/package_update_reboot_required.jinja +++ b/salt/motd/files/package_update_reboot_required.jinja @@ -10,9 +10,12 @@ {%- endfor -%} {%- if minions_need_restarted | length > 0 %} -***************************************************************************************** -* The following nodes in your Security Onion grid need restarted due to package updates * -***************************************************************************************** +**************************************************************************************************** +* The following nodes in your Security Onion grid may need to be restarted due to package updates. * +* If the node has already been patched, restarted and been up for less than 15 minutes, then it * +* may not have updated it's restart_needed status yet. This will cause it to be listed below, even * +* if it has already been restarted. This feature will be improved in the future. * +**************************************************************************************************** {% for minion in minions_need_restarted -%} {{ minion }} From 65a5a2e64a82d715cf59fd208b36dae34fc90d2a Mon Sep 17 00:00:00 2001 From: Wes Lambert Date: Thu, 5 Dec 2019 17:41:19 +0000 Subject: [PATCH 116/200] pre-load custom reputation field --- salt/hive/thehive/scripts/hive_init.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/salt/hive/thehive/scripts/hive_init.sh b/salt/hive/thehive/scripts/hive_init.sh index 4e121e078..2215d4e44 100755 --- a/salt/hive/thehive/scripts/hive_init.sh +++ b/salt/hive/thehive/scripts/hive_init.sh @@ -19,7 +19,13 @@ hive_init(){ # Create intial TheHive user curl -v -k "https://$HIVE_IP/thehive/api/user" -H "Content-Type: application/json" -d "{\"login\" : \"$HIVE_USER\",\"name\" : \"$HIVE_USER\",\"roles\" : [\"read\",\"alert\",\"write\",\"admin\"],\"preferences\" : \"{}\",\"password\" : \"$HIVE_PASSWORD\", \"key\": \"$HIVE_KEY\"}" + + # Pre-load custom fields + # + # reputation + curl -v -k "https://$HIVE_IP/thehive/api/list/custom_fields" -H "Authorization: Bearer $HIVE_KEY" -H "Content-Type: application/json" -d "{\"value\":{\"name\": \"reputation\", \"reference\": \"reputation\", \"description\": \"This field provides an overall reputation status for an address/domain.\", \"type\": \"string\", \"options\": []}}" + # Update SOCtopus config with apikey value #sed -i "s/hive_key = .*/hive_key = $HIVE_KEY/" $SOCTOPUS_CONFIG From 91f67cb62fc8a18e38e7533fda245fd6001a3d0a Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 5 Dec 2019 15:09:45 -0500 Subject: [PATCH 117/200] Misc Script - Redis Count --- salt/common/tools/sbin/so-redis-count | 1 + 1 file changed, 1 insertion(+) create mode 100644 salt/common/tools/sbin/so-redis-count diff --git a/salt/common/tools/sbin/so-redis-count b/salt/common/tools/sbin/so-redis-count new file mode 100644 index 000000000..5b299e494 --- /dev/null +++ b/salt/common/tools/sbin/so-redis-count @@ -0,0 +1 @@ +sudo docker exec -it so-redis redis-cli llen logstash:unparsed From 84485b7f79bc03cdc1a3f5b915a9baacf2342f72 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Thu, 5 Dec 2019 16:34:30 -0500 Subject: [PATCH 118/200] Create so-playbook-sync --- salt/common/tools/sbin/so-playbook-sync | 1 + 1 file changed, 1 insertion(+) create mode 100644 salt/common/tools/sbin/so-playbook-sync diff --git a/salt/common/tools/sbin/so-playbook-sync b/salt/common/tools/sbin/so-playbook-sync new file mode 100644 index 000000000..3fc13c199 --- /dev/null +++ b/salt/common/tools/sbin/so-playbook-sync @@ -0,0 +1 @@ +sudo docker exec so-soctopus python3 playbook_play-sync.py From 7721e913ec326902158e4198e6def2b9932008a5 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Thu, 5 Dec 2019 16:36:29 -0500 Subject: [PATCH 119/200] Create so-playbook-ruleupdate --- salt/common/tools/sbin/so-playbook-ruleupdate | 1 + 1 file changed, 1 insertion(+) create mode 100644 salt/common/tools/sbin/so-playbook-ruleupdate diff --git a/salt/common/tools/sbin/so-playbook-ruleupdate b/salt/common/tools/sbin/so-playbook-ruleupdate new file mode 100644 index 000000000..6e2d16f5d --- /dev/null +++ b/salt/common/tools/sbin/so-playbook-ruleupdate @@ -0,0 +1 @@ +sudo docker exec so-soctopus python3 playbook_bulk-update.py From 65ddac4535245c8bac021a6968454e08440e3515 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Thu, 5 Dec 2019 16:50:58 -0500 Subject: [PATCH 120/200] Playbook - add cron job for so-playbook-sync --- salt/playbook/init.sls | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/salt/playbook/init.sls b/salt/playbook/init.sls index bc22b60d4..6a5ab542e 100644 --- a/salt/playbook/init.sls +++ b/salt/playbook/init.sls @@ -56,3 +56,8 @@ so-navigator: - /opt/so/conf/playbook/nav_layer_playbook.json:/nav-app/src/assets/playbook.json:ro - port_bindings: - 0.0.0.0:4200:4200 + +/usr/sbin/so-playbook-sync: + cron.present: + - user: root + - minute: '*/5' From d27de7c8be3b840d1d59530a2ddfc080bd5b7e03 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Thu, 5 Dec 2019 16:54:33 -0500 Subject: [PATCH 121/200] Update init.sls --- salt/playbook/init.sls | 1 + 1 file changed, 1 insertion(+) diff --git a/salt/playbook/init.sls b/salt/playbook/init.sls index 6a5ab542e..770316ab9 100644 --- a/salt/playbook/init.sls +++ b/salt/playbook/init.sls @@ -59,5 +59,6 @@ so-navigator: /usr/sbin/so-playbook-sync: cron.present: + - identifier: so-playbook-sync - user: root - minute: '*/5' From 2d7ff4e0fd3987b8b025219f4da5ba556aca4ab2 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 6 Dec 2019 15:29:07 -0500 Subject: [PATCH 122/200] whiptail size adjustments. fix menus that couldn't be cancelled out of. add path for source so setup can be called from anywhere --- setup/functions.sh | 10 +++ setup/so-setup.sh | 12 ++- setup/whiptail.sh | 219 +++++++++++++++++++++++++++------------------ 3 files changed, 148 insertions(+), 93 deletions(-) diff --git a/setup/functions.sh b/setup/functions.sh index d251ecbac..ff546ea31 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -15,6 +15,9 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +SCRIPTDIR=$(dirname "$0") +source $SCRIPTDIR/whiptail.sh + accept_salt_key_local() { echo "Accept the key locally on the master" >> $SETUPLOG 2>&1 # Accept the key locally on the master @@ -45,6 +48,9 @@ add_master_hostfile() { MSRVIP=$(whiptail --title "Security Onion Setup" --inputbox \ "Enter your Master Server IP Address" 10 60 X.X.X.X 3>&1 1>&2 2>&3) + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + } add_socore_user_master() { @@ -357,6 +363,8 @@ detect_os() { exit fi + echo "Found OS: $OS $OSVER" >> $SETUPLOG 2>&1 + } #disable_dnsmasq() { @@ -520,6 +528,8 @@ got_root() { install_cleanup() { + echo "install_cleanup called" >> $SETUPLOG 2>&1 + # Clean up after ourselves rm -rf /root/installtmp diff --git a/setup/so-setup.sh b/setup/so-setup.sh index 627e3bc2b..c3a6abab1 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -16,8 +16,9 @@ # along with this program. If not, see . # Source the other pieces of the setup -source functions.sh -source whiptail.sh +SCRIPTDIR=$(dirname "$0") +source $SCRIPTDIR/functions.sh +source $SCRIPTDIR/whiptail.sh # See if this is an ISO install OPTIONS=$1 @@ -42,6 +43,7 @@ SETUPLOG="/root/sosetup.log" # Reset the Install Log date -u >$SETUPLOG 2>&1 +echo "stty size is: $(stty size)" >> $SETUPLOG 2>&1 # Check for prerequisites got_root @@ -53,7 +55,8 @@ if [ $OS == ubuntu ]; then fi # Question Time -if (whiptail_you_sure); then +echo "Asking user if they are sure they want to proceed" >> $SETUPLOG 2>&1 +if (whiptail_you_sure) ; then # Create a temp dir to get started install_prep @@ -636,5 +639,6 @@ if (whiptail_you_sure); then fi else - exit + echo "User not sure. Cancelling setup.">> $SETUPLOG 2>&1 + whiptail_cancel fi diff --git a/setup/whiptail.sh b/setup/whiptail.sh index 146275bb8..bd40f5e83 100644 --- a/setup/whiptail.sh +++ b/setup/whiptail.sh @@ -18,7 +18,7 @@ whiptail_basic_bro() { BASICBRO=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter the number of bro processes:" 10 60 $LBPROCS 3>&1 1>&2 2>&3) + "Enter the number of bro processes:" 10 75 $LBPROCS 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -28,7 +28,7 @@ whiptail_basic_bro() { whiptail_basic_suri() { BASICSURI=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter the number of Suricata Processes:" 10 60 $LBPROCS 3>&1 1>&2 2>&3) + "Enter the number of Suricata Processes:" 10 75 $LBPROCS 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -37,17 +37,16 @@ whiptail_basic_suri() { whiptail_bro_pins() { - BROPINS=$(whiptail --noitem --title "Pin Bro CPUS" --checklist "Please Select $LBPROCS cores to pin Bro to:" 20 78 12 ${LISTCORES[@]} 3>&1 1>&2 2>&3 ) + BROPINS=$(whiptail --noitem --title "Pin Bro CPUS" --checklist "Please Select $LBPROCS cores to pin Bro to:" 20 75 12 ${LISTCORES[@]} 3>&1 1>&2 2>&3 ) local exitstatus=$? whiptail_check_exitstatus $exitstatus - } whiptail_bro_version() { - BROVERSION=$(whiptail --title "Security Onion Setup" --radiolist "What tool would you like to use to generate meta data?" 20 78 4 "ZEEK" "Install Zeek (aka Bro)" ON \ + BROVERSION=$(whiptail --title "Security Onion Setup" --radiolist "What tool would you like to use to generate meta data?" 20 75 4 "ZEEK" "Install Zeek (aka Bro)" ON \ "COMMUNITY" "Install Community NSM" OFF "SURICATA" "SUPER EXPERIMENTAL" OFF 3>&1 1>&2 2>&3) local exitstatus=$? @@ -62,23 +61,24 @@ whiptail_bond_nics() { nic_list+=($FNIC "Interface" "OFF") done - BNICS=$(whiptail --title "NIC Setup" --checklist "Please add NICs to the Monitor Interface" 20 78 12 ${nic_list[@]} 3>&1 1>&2 2>&3 ) + BNICS=$(whiptail --title "NIC Setup" --checklist "Please add NICs to the Monitor Interface" 20 75 12 ${nic_list[@]} 3>&1 1>&2 2>&3 ) + local exitstatus=$? + whiptail_check_exitstatus $exitstatus while [ -z "$BNICS" ] do - BNICS=$(whiptail --title "NIC Setup" --checklist "Please add NICs to the Monitor Interface" 20 78 12 ${nic_list[@]} 3>&1 1>&2 2>&3 ) + BNICS=$(whiptail --title "NIC Setup" --checklist "Please add NICs to the Monitor Interface" 20 75 12 ${nic_list[@]} 3>&1 1>&2 2>&3 ) + local exitstatus=$? + whiptail_check_exitstatus $exitstatus done - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - } whiptail_bond_nics_mtu() { # Set the MTU on the monitor interface MTU=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter the MTU for the monitor NICs" 10 60 1500 3>&1 1>&2 2>&3) + "Enter the MTU for the monitor NICs" 10 75 1500 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -87,8 +87,12 @@ whiptail_bond_nics_mtu() { whiptail_cancel() { - whiptail --title "Security Onion Setup" --msgbox "Cancelling Setup. No changes have been made." 8 78 - install_cleanup + whiptail --title "Security Onion Setup" --msgbox "Cancelling Setup. No changes have been made." 8 75 + if [ -d "/root/installtmp" ]; then + echo "/root/installtmp exists" >> $SETUPLOG 2>&1 + install_cleanup + echo "/root/installtmp removed" >> $SETUPLOG 2>&1 + fi exit } @@ -104,28 +108,34 @@ whiptail_check_exitstatus() { whiptail_create_socore_user() { - whiptail --title "Security Onion Setup" --msgbox "Set a password for the socore user. This account is used for adding sensors remotely." 8 78 + whiptail --title "Security Onion Setup" --msgbox "Set a password for the socore user. This account is used for adding sensors remotely." 8 75 } whiptail_create_socore_user_password1() { COREPASS1=$(whiptail --title "Security Onion Install" --passwordbox \ - "Enter a password for user socore" 10 60 3>&1 1>&2 2>&3) + "Enter a password for user socore" 10 75 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus } whiptail_create_socore_user_password2() { COREPASS2=$(whiptail --title "Security Onion Install" --passwordbox \ - "Re-enter a password for user socore" 10 60 3>&1 1>&2 2>&3) + "Re-enter a password for user socore" 10 75 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus } whiptail_cur_close_days() { CURCLOSEDAYS=$(whiptail --title "Security Onion Setup" --inputbox \ - "Please specify the threshold (in days) at which Elasticsearch indices will be closed" 10 60 $CURCLOSEDAYS 3>&1 1>&2 2>&3) + "Please specify the threshold (in days) at which Elasticsearch indices will be closed" 10 75 $CURCLOSEDAYS 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -133,30 +143,37 @@ whiptail_cur_close_days() { } whiptail_enable_components() { COMPONENTS=$(whiptail --title "Security Onion Setup" --checklist \ - "Select Components to install" 20 78 8 \ + "Select Components to install" 20 75 8 \ "GRAFANA" "Enable Grafana for system monitoring" ON \ "OSQUERY" "Enable Fleet with osquery" ON \ "WAZUH" "Enable Wazuh" ON \ "THEHIVE" "Enable TheHive" ON \ "PLAYBOOK" "Enable Playbook" ON 3>&1 1>&2 2>&3 ) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + } whiptail_eval_adv() { EVALADVANCED=$(whiptail --title "Security Onion Setup" --radiolist \ - "Choose your eval install:" 20 78 4 \ + "Choose your eval install:" 20 75 4 \ "BASIC" "Install basic components for evaluation" ON \ "ADVANCED" "Choose additional components to be installed" OFF 3>&1 1>&2 2>&3 ) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus } whiptail_eval_adv_warning() { - whiptail --title "Security Onion Setup" --msgbox "Please keep in mind the more services that you enable the more RAM that is required." 8 78 + whiptail --title "Security Onion Setup" --msgbox "Please keep in mind the more services that you enable the more RAM that is required." 8 75 } whiptail_homenet_master() { # Ask for the HOME_NET on the master HNMASTER=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter your HOME_NET separated by ," 10 60 10.0.0.0/8,192.168.0.0/16,172.16.0.0/12 3>&1 1>&2 2>&3) + "Enter your HOME_NET separated by ," 10 75 10.0.0.0/8,192.168.0.0/16,172.16.0.0/12 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -166,14 +183,16 @@ whiptail_homenet_master() { whiptail_homenet_sensor() { # Ask to inherit from master - whiptail --title "Security Onion Setup" --yesno "Do you want to inherit the HOME_NET from the Master?" 8 78 + whiptail --title "Security Onion Setup" --yesno "Do you want to inherit the HOME_NET from the Master?" 8 75 local exitstatus=$? if [ $exitstatus == 0 ]; then HNSENSOR=inherit else HNSENSOR=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter your HOME_NET separated by ," 10 60 10.0.0.0/8,192.168.0.0/16,172.16.0.0/12 3>&1 1>&2 2>&3) + "Enter your HOME_NET separated by ," 10 75 10.0.0.0/8,192.168.0.0/16,172.16.0.0/12 3>&1 1>&2 2>&3) + local exitstatus=$? + whiptail_check_exitstatus $exitstatus fi } @@ -182,14 +201,14 @@ whiptail_install_type() { # What kind of install are we doing? INSTALLTYPE=$(whiptail --title "Security Onion Setup" --radiolist \ - "Choose Install Type:" 20 78 14 \ + "Choose Install Type:" 20 75 13 \ "SENSORONLY" "Create a forward only sensor" ON \ "STORAGENODE" "Add a Storage Hot Node with parsing" OFF \ "MASTERONLY" "Start a new grid" OFF \ - "PARSINGNODE" "TODO Add a dedicated Parsing Node" OFF \ - "HOTNODE" "TODO Add a Hot Node (Storage Node without Parsing)" OFF \ - "WARMNODE" "TODO Add a Warm Node to an existing Hot or Storage node" OFF \ "EVALMODE" "Evaluate all the things" OFF \ + "PARSINGNODE" "TODO Add a dedicated Parsing Node" OFF \ + "HOTNODE" "TODO Add Hot Node (Storage Node without Parsing)" OFF \ + "WARMNODE" "TODO Add Warm Node to existing Hot or Storage node" OFF \ "WAZUH" "TODO Stand Alone Wazuh Node" OFF \ "STRELKA" "TODO Stand Alone Strelka Node" OFF \ "FLEET" "TODO Stand Alone Fleet OSQuery Node" OFF 3>&1 1>&2 2>&3 ) @@ -203,7 +222,7 @@ whiptail_log_size_limit() { LOG_SIZE_LIMIT=$(whiptail --title "Security Onion Setup" --inputbox \ "Please specify the amount of disk space (in GB) you would like to allocate for Elasticsearch data storage. \ - By default, this is set to 85% of the disk space allotted for /nsm." 10 60 $LOG_SIZE_LIMIT 3>&1 1>&2 2>&3) + By default, this is set to 85% of the disk space allotted for /nsm." 10 75 $LOG_SIZE_LIMIT 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -213,22 +232,23 @@ whiptail_log_size_limit() { whiptail_management_nic() { - MNIC=$(whiptail --title "NIC Setup" --radiolist "Please select your management NIC" 20 78 12 ${NICS[@]} 3>&1 1>&2 2>&3 ) + MNIC=$(whiptail --title "NIC Setup" --radiolist "Please select your management NIC" 20 75 12 ${NICS[@]} 3>&1 1>&2 2>&3 ) + local exitstatus=$? + whiptail_check_exitstatus $exitstatus while [ -z "$MNIC" ] do - MNIC=$(whiptail --title "NIC Setup" --radiolist "Please select your management NIC" 20 78 12 ${NICS[@]} 3>&1 1>&2 2>&3 ) + MNIC=$(whiptail --title "NIC Setup" --radiolist "Please select your management NIC" 20 75 12 ${NICS[@]} 3>&1 1>&2 2>&3 ) + local exitstatus=$? + whiptail_check_exitstatus $exitstatus done - local exitstatus=$? - whiptail_check_exitstatus $exitstatus - } whiptail_nids() { NIDS=$(whiptail --title "Security Onion Setup" --radiolist \ - "Choose which IDS to run:" 20 78 4 \ + "Choose which IDS to run:" 20 75 4 \ "Suricata" "Suricata 4.X" ON \ "Snort" "Snort 3.0 Beta" OFF 3>&1 1>&2 2>&3 ) @@ -240,7 +260,7 @@ whiptail_nids() { whiptail_oinkcode() { OINKCODE=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter your oinkcode" 10 60 XXXXXXX 3>&1 1>&2 2>&3) + "Enter your oinkcode" 10 75 XXXXXXX 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -249,7 +269,7 @@ whiptail_oinkcode() { whiptail_make_changes() { - whiptail --title "Security Onion Setup" --yesno "We are going to set this machine up as a $INSTALLTYPE. Please hit YES to make changes or NO to cancel." 8 78 + whiptail --title "Security Onion Setup" --yesno "We are going to set this machine up as a $INSTALLTYPE. Please hit YES to make changes or NO to cancel." 8 75 local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -259,7 +279,10 @@ whiptail_make_changes() { whiptail_management_server() { MSRV=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter your Master Server HOSTNAME. It is CASE SENSITIVE!" 10 60 XXXX 3>&1 1>&2 2>&3) + "Enter your Master Server HOSTNAME. It is CASE SENSITIVE!" 10 75 XXXX 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus # See if it resolves. Otherwise prompt to add to host file TESTHOST=$(host $MSRV) @@ -268,24 +291,25 @@ whiptail_management_server() { add_master_hostfile fi +} + +# Ask if you want to do advanced setup of the Master +whiptail_master_adv() { + + MASTERADV=$(whiptail --title "Security Onion Setup" --radiolist \ + "Choose what type of master install:" 20 75 4 \ + "BASIC" "Install master with recommended settings" ON \ + "ADVANCED" "Do additional configuration to the master" OFF 3>&1 1>&2 2>&3 ) local exitstatus=$? whiptail_check_exitstatus $exitstatus } -# Ask if you want to do advanced setup of the Master -whiptail_master_adv() { - MASTERADV=$(whiptail --title "Security Onion Setup" --radiolist \ - "Choose what type of master install:" 20 78 4 \ - "BASIC" "Install master with recommended settings" ON \ - "ADVANCED" "Do additional configuration to the master" OFF 3>&1 1>&2 2>&3 ) -} - # Ask which additional components to install whiptail_master_adv_service_brologs() { - BLOGS=$(whiptail --title "Security Onion Setup" --checklist "Please Select Logs to Send:" 24 78 12 \ + BLOGS=$(whiptail --title "Security Onion Setup" --checklist "Please Select Logs to Send:" 24 75 12 \ "conn" "Connection Logging" ON \ "dce_rpc" "RPC Logs" ON \ "dhcp" "DHCP Logs" ON \ @@ -324,11 +348,15 @@ whiptail_master_adv_service_brologs() { "mysql" "MySQL Logs" ON \ "socks" "SOCKS Logs" ON \ "x509" "x.509 Logs" ON 3>&1 1>&2 2>&3 ) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + } whiptail_network_notice() { - whiptail --title "Security Onion Setup" --yesno "Since this is a network install we assume the management interface, DNS, Hostname, etc are already set up. Hit YES to continue." 8 78 + whiptail --title "Security Onion Setup" --yesno "Since this is a network install we assume the management interface, DNS, Hostname, etc are already set up. Hit YES to continue." 8 75 local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -338,7 +366,7 @@ whiptail_network_notice() { whiptail_node_advanced() { NODESETUP=$(whiptail --title "Security Onion Setup" --radiolist \ - "What type of config would you like to use?:" 20 78 4 \ + "What type of config would you like to use?:" 20 75 4 \ "NODEBASIC" "Install Storage Node with recommended settings" ON \ "NODEADVANCED" "Advanced Node Setup" OFF 3>&1 1>&2 2>&3 ) @@ -351,7 +379,7 @@ whiptail_node_es_heap() { es_heapsize NODE_ES_HEAP_SIZE=$(whiptail --title "Security Onion Setup" --inputbox \ - "\nEnter ES Heap Size: \n \n(Recommended value is pre-populated)" 10 60 $ES_HEAP_SIZE 3>&1 1>&2 2>&3) + "\nEnter ES Heap Size: \n \n(Recommended value is pre-populated)" 10 75 $ES_HEAP_SIZE 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -362,7 +390,7 @@ whiptail_node_ls_heap() { ls_heapsize NODE_LS_HEAP_SIZE=$(whiptail --title "Security Onion Setup" --inputbox \ - "\nEnter LogStash Heap Size: \n \n(Recommended value is pre-populated)" 10 60 $LS_HEAP_SIZE 3>&1 1>&2 2>&3) + "\nEnter LogStash Heap Size: \n \n(Recommended value is pre-populated)" 10 75 $LS_HEAP_SIZE 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -372,7 +400,7 @@ whiptail_node_ls_heap() { whiptail_node_ls_pipeline_worker() { LSPIPELINEWORKERS=$(whiptail --title "Security Onion Setup" --inputbox \ - "\nEnter LogStash Pipeline Workers: \n \n(Recommended value is pre-populated)" 10 60 $CPUCORES 3>&1 1>&2 2>&3) + "\nEnter LogStash Pipeline Workers: \n \n(Recommended value is pre-populated)" 10 75 $CPUCORES 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -382,7 +410,7 @@ whiptail_node_ls_pipeline_worker() { whiptail_node_ls_pipline_batchsize() { LSPIPELINEBATCH=$(whiptail --title "Security Onion Setup" --inputbox \ - "\nEnter LogStash Pipeline Batch Size: \n \n(Default value is pre-populated)" 10 60 125 3>&1 1>&2 2>&3) + "\nEnter LogStash Pipeline Batch Size: \n \n(Default value is pre-populated)" 10 75 125 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -392,7 +420,7 @@ whiptail_node_ls_pipline_batchsize() { whiptail_node_ls_input_threads() { LSINPUTTHREADS=$(whiptail --title "Security Onion Setup" --inputbox \ - "\nEnter LogStash Input Threads: \n \n(Default value is pre-populated)" 10 60 1 3>&1 1>&2 2>&3) + "\nEnter LogStash Input Threads: \n \n(Default value is pre-populated)" 10 75 1 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -402,7 +430,7 @@ whiptail_node_ls_input_threads() { whiptail_node_ls_input_batch_count() { LSINPUTBATCHCOUNT=$(whiptail --title "Security Onion Setup" --inputbox \ - "\nEnter LogStash Input Batch Count: \n \n(Default value is pre-populated)" 10 60 125 3>&1 1>&2 2>&3) + "\nEnter LogStash Input Batch Count: \n \n(Default value is pre-populated)" 10 75 125 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -411,22 +439,22 @@ whiptail_node_ls_input_batch_count() { whiptail_passwords_dont_match() { - whiptail --title "Security Onion Setup" --msgbox "Passwords don't match. Please re-enter." 8 78 + whiptail --title "Security Onion Setup" --msgbox "Passwords don't match. Please re-enter." 8 75 } whiptail_patch_name_new_schedule() { PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ - "What name do you want to give this OS patch schedule? This schedule needs to be named uniquely. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 105 3>&1 1>&2 2>&3) + "What name do you want to give this OS patch schedule? This schedule needs to be named uniquely. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 75 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus while [[ -z "$PATCHSCHEDULENAME" ]]; do - whiptail --title "Security Onion Setup" --msgbox "Please enter a name for this OS patch schedule." 8 65 + whiptail --title "Security Onion Setup" --msgbox "Please enter a name for this OS patch schedule." 8 75 PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ - "What name do you want to give this OS patch schedule? This schedule needs to be named uniquely. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 105 3>&1 1>&2 2>&3) + "What name do you want to give this OS patch schedule? This schedule needs to be named uniquely. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 75 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus done @@ -438,11 +466,11 @@ whiptail_patch_schedule() { # What kind of patch schedule are we doing? PATCHSCHEDULE=$(whiptail --title "Security Onion Setup" --radiolist \ - "Choose OS patch schedule. This will NOT update Security Onion related tools such as Zeek, Elasticsearch, Kibana, SaltStack, etc." 25 115 5 \ - "Automatic" "Package updates will be installed automatically every 8 hours if available" ON \ - "Manual" "Package updates will need to be installed manually" OFF \ - "Import Schedule" "Enter the name of an existing schedule on the following screen and inherit it" OFF \ - "New Schedule" "Configure and name a new schedule on the following screen" OFF 3>&1 1>&2 2>&3 ) + "Choose OS patch schedule. This will NOT update Security Onion related tools such as Zeek, Elasticsearch, Kibana, SaltStack, etc." 15 75 5 \ + "Automatic" "Updates installed every 8 hours if available" ON \ + "Manual" "Updates will be installed manually" OFF \ + "Import Schedule" "Import named schedule on following screen" OFF \ + "New Schedule" "Configure and name new schedule on next screen" OFF 3>&1 1>&2 2>&3 ) local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -453,15 +481,15 @@ whiptail_patch_schedule_import() { unset PATCHSCHEDULENAME PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter the name of the OS patch schedule you want to inherit. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 60 3>&1 1>&2 2>&3) + "Enter the name of the OS patch schedule you want to inherit. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 75 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus while [[ -z "$PATCHSCHEDULENAME" ]]; do - whiptail --title "Security Onion Setup" --msgbox "Please enter a name for the OS patch schedule you want to inherit." 8 65 + whiptail --title "Security Onion Setup" --msgbox "Please enter a name for the OS patch schedule you want to inherit." 8 75 PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter the name of the OS patch schedule you want to inherit. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 60 3>&1 1>&2 2>&3) + "Enter the name of the OS patch schedule you want to inherit. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 75 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -472,7 +500,7 @@ whiptail_patch_schedule_import() { whiptail_patch_schedule_select_days() { # Select the days to patch PATCHSCHEDULEDAYS=($(whiptail --title "Security Onion Setup" --checklist \ - "Which days do you want to apply OS patches?" 20 55 9 \ + "Which days do you want to apply OS patches?" 15 75 8 \ "Monday" "" OFF \ "Tuesday" "" ON \ "Wednesday" "" OFF \ @@ -486,9 +514,9 @@ whiptail_patch_schedule_select_days() { } whiptail_patch_schedule_select_hours() { - # Select the hours to patch + # Select the hours to patch PATCHSCHEDULEHOURS=($(whiptail --title "Security Onion Setup" --checklist \ - "At which time, UTC, do you want to apply OS patches on the selected days?" 35 55 26 \ + "At which time, UTC, do you want to apply OS patches on the selected days? Hours 12 through 23 can be selected on the next screen." 22 75 13 \ "00:00" "" OFF \ "01:00" "" OFF \ "02:00" "" OFF \ @@ -500,7 +528,14 @@ whiptail_patch_schedule_select_hours() { "08:00" "" OFF \ "09:00" "" OFF \ "10:00" "" OFF \ - "11:00" "" OFF \ + "11:00" "" OFF 3>&1 1>&2 2>&3 )) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + + # Select the hours to patch + PATCHSCHEDULEHOURS+=($(whiptail --title "Security Onion Setup" --checklist \ + "At which time, UTC, do you want to apply OS patches on the selected days?" 22 75 13 \ "12:00" "" OFF \ "13:00" "" OFF \ "14:00" "" OFF \ @@ -522,7 +557,7 @@ whiptail_rule_setup() { # Get pulled pork info RULESETUP=$(whiptail --title "Security Onion Setup" --radiolist \ - "What IDS rules to use?:" 20 140 4 \ + "What IDS rules to use?:" 20 75 4 \ "ETOPEN" "Emerging Threats Open - no oinkcode required" ON \ "ETPRO" "Emerging Threats PRO - requires ETPRO oinkcode" OFF \ "TALOSET" "Snort Subscriber (Talos) ruleset and Emerging Threats NoGPL ruleset - requires Snort Subscriber oinkcode" OFF \ @@ -536,7 +571,7 @@ whiptail_rule_setup() { whiptail_sensor_config() { NSMSETUP=$(whiptail --title "Security Onion Setup" --radiolist \ - "What type of configuration would you like to use?:" 20 78 4 \ + "What type of configuration would you like to use?:" 20 75 4 \ "BASIC" "Install NSM components with recommended settings" ON \ "ADVANCED" "Configure each component individually" OFF 3>&1 1>&2 2>&3 ) @@ -548,30 +583,31 @@ whiptail_sensor_config() { whiptail_set_hostname() { HOSTNAME=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter the Hostname you would like to set." 10 60 $HOSTNAME 3>&1 1>&2 2>&3) - - while [[ "$HOSTNAME" == 'localhost' ]] ; do - whiptail --title "Security Onion Setup" --msgbox "Please choose a hostname that isn't localhost." 8 65 - HOSTNAME=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter the Hostname you would like to set." 10 60 $HOSTNAME 3>&1 1>&2 2>&3) - done - + "Enter the Hostname you would like to set." 10 75 $HOSTNAME 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus + while [[ "$HOSTNAME" == 'localhost' ]] ; do + whiptail --title "Security Onion Setup" --msgbox "Please choose a hostname that isn't localhost." 8 75 + HOSTNAME=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter the Hostname you would like to set." 10 75 $HOSTNAME 3>&1 1>&2 2>&3) + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + done + } whiptail_setup_complete() { - whiptail --title "Security Onion Setup" --msgbox "Finished installing this as an $INSTALLTYPE. Press Enter to reboot." 8 78 + whiptail --title "Security Onion Setup" --msgbox "Finished installing this as an $INSTALLTYPE. Press Enter to reboot." 8 75 install_cleanup } whiptail_setup_failed() { - whiptail --title "Security Onion Setup" --msgbox "Install had a problem. Please see $SETUPLOG for details. Press Enter to reboot." 8 78 + whiptail --title "Security Onion Setup" --msgbox "Install had a problem. Please see $SETUPLOG for details. Press Enter to reboot." 8 75 install_cleanup } @@ -579,7 +615,7 @@ whiptail_setup_failed() { whiptail_shard_count() { SHARDCOUNT=$(whiptail --title "Security Onion Setup" --inputbox \ - "\nEnter ES Shard Count: \n \n(Default value is pre-populated)" 10 60 125 3>&1 1>&2 2>&3) + "\nEnter ES Shard Count: \n \n(Default value is pre-populated)" 10 75 125 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -589,7 +625,7 @@ whiptail_shard_count() { whiptail_suricata_pins() { FILTEREDCORES=$(echo ${LISTCORES[@]} ${BROPINS[@]} | tr -d '"' | tr ' ' '\n' | sort | uniq -u | awk '{print $1 " \"" "core" "\""}') - SURIPINS=$(whiptail --noitem --title "Pin Suricata CPUS" --checklist "Please Select $LBPROCS cores to pin Suricata to:" 20 78 12 ${FILTEREDCORES[@]} 3>&1 1>&2 2>&3 ) + SURIPINS=$(whiptail --noitem --title "Pin Suricata CPUS" --checklist "Please Select $LBPROCS cores to pin Suricata to:" 20 75 12 ${FILTEREDCORES[@]} 3>&1 1>&2 2>&3 ) local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -599,9 +635,9 @@ whiptail_suricata_pins() { whiptail_master_updates() { MASTERUPDATES=$(whiptail --title "Security Onion Setup" --radiolist \ - "How would you like to download updates for your grid?:" 20 78 4 \ - "MASTER" "Have the master node act as a proxy for OS/Docker updates." ON \ - "OPEN" "Have each node connect to the Internet for updates" OFF 3>&1 1>&2 2>&3 ) + "How would you like to download updates for your grid?:" 20 75 4 \ + "MASTER" "Master node is proxy for OS/Docker updates." ON \ + "OPEN" "Each node connect to the Internet for updates" OFF 3>&1 1>&2 2>&3 ) local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -611,7 +647,7 @@ whiptail_master_updates() { whiptail_node_updates() { NODEUPDATES=$(whiptail --title "Security Onion Setup" --radiolist \ - "How would you like to download updates for this node?:" 20 78 4 \ + "How would you like to download updates for this node?:" 20 75 4 \ "MASTER" "Download OS/Docker updates from the Master." ON \ "OPEN" "Download updates directly from the Internet" OFF 3>&1 1>&2 2>&3 ) @@ -622,6 +658,11 @@ whiptail_node_updates() { whiptail_you_sure() { - whiptail --title "Security Onion Setup" --yesno "Are you sure you want to install Security Onion over the internet?" 8 78 + echo "whiptail_you_sure called" >> $SETUPLOG 2>&1 + whiptail --title "Security Onion Setup" --yesno "Are you sure you want to install Security Onion over the internet?" 8 75 + + local exitstatus=$? + echo "whiptail_you_sure returning $exitstatus" >> $SETUPLOG 2>&1 + return $exitstatus } From 22389d99effbd7ed0788f94c55e506604e348ea0 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Sun, 8 Dec 2019 19:17:33 -0500 Subject: [PATCH 123/200] Add Helix Install Option to Setup --- setup/so-setup.sh | 88 +++++++++++++++++++++++++++++++++++++++++++++++ setup/whiptail.sh | 3 +- 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/setup/so-setup.sh b/setup/so-setup.sh index 7f8a03d9b..42a1e70c8 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -152,6 +152,94 @@ if (whiptail_you_sure) ; then #################### ## Master ## #################### + if [ $INSTALLTYPE == 'HELIXSESOR']; then + whiptail_homenet_master + whiptail_rule_setup + # Get the code if it isn't ET Open + if [ $RULESETUP != 'ETOPEN' ]; then + # Get the code + whiptail_oinkcode + fi + whiptail_make_changes + set_hostname + clear_master + mkdir -p /nsm + get_filesystem_root + get_filesystem_nsm + get_main_ip + add_socore_user_master + # Install salt and dependencies + { + sleep 0.5 + echo -e "XXX\n1\nInstalling and configuring Salt... \nXXX" + echo " ** Installing Salt and Dependencies **" >> $SETUPLOG + saltify >> $SETUPLOG 2>&1 + echo -e "XXX\n5\nInstalling Docker... \nXXX" + docker_install >> $SETUPLOG 2>&1 + echo -e "XXX\n10\nConfiguring Salt Master... \nXXX" + echo " ** Configuring Minion **" >> $SETUPLOG + configure_minion master >> $SETUPLOG 2>&1 + echo " ** Installing Salt Master **" >> $SETUPLOG + install_master >> $SETUPLOG 2>&1 + salt_master_directories >> $SETUPLOG 2>&1 + update_sudoers >> $SETUPLOG 2>&1 + chown_salt_master >> $SETUPLOG 2>&1 + es_heapsize >> $SETUPLOG 2>&1 + ls_heapsize >> $SETUPLOG 2>&1 + echo -e "XXX\n25\nConfiguring Default Pillars... \nXXX" + master_static >> $SETUPLOG 2>&1 + echo "** Generating the master pillar **" >> $SETUPLOG + master_pillar >> $SETUPLOG 2>&1 + echo "** Generating the patch pillar **" >> $SETUPLOG + patch_pillar >> $SETUPLOG 2>&1 + echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" + copy_minion_tmp_files >> $SETUPLOG 2>&1 + # Do a checkin to push the key up + echo "** Pushing the key up to Master **" >> $SETUPLOG + salt_firstcheckin >> $SETUPLOG 2>&1 + # Accept the Master Key + echo "** Accepting the key on the master **" >> $SETUPLOG + accept_salt_key_local >> $SETUPLOG 2>&1 + echo -e "XXX\n35\nConfiguring Firewall... \nXXX" + # Open the firewall + echo "** Setting the initial firewall policy **" >> $SETUPLOG + set_initial_firewall_policy >> $SETUPLOG 2>&1 + echo -e "XXX\n40\nGenerating CA... \nXXX" + salt_checkin >> $SETUPLOG 2>&1 + salt-call state.apply ca >> $SETUPLOG 2>&1 + salt-call state.apply ssl >> $SETUPLOG 2>&1 + echo -e "XXX\n43\nInstalling Common Components... \nXXX" + salt-call state.apply common >> $SETUPLOG 2>&1 + echo -e "XXX\n45\nApplying firewall rules... \nXXX" + salt-call state.apply firewall >> $SETUPLOG 2>&1 + salt-call state.apply master >> $SETUPLOG 2>&1 + salt-call state.apply idstools >> $SETUPLOG 2>&1 + echo -e "XXX\n40\nInstalling Redis... \nXXX" + salt-call state.apply redis >> $SETUPLOG 2>&1 + echo -e "XXX\n60\nInstalling Redis... \nXXX" + salt-call state.apply logstash >> $SETUPLOG 2>&1 + echo -e "XXX\n75\nInstalling Filebeat... \nXXX" + salt-call state.apply filebeat >> $SETUPLOG 2>&1 + salt-call state.apply utility >> $SETUPLOG 2>&1 + salt-call state.apply schedule >> $SETUPLOG 2>&1 + echo -e "XXX\n85\nEnabling Checking at Boot... \nXXX" + checkin_at_boot >> $SETUPLOG 2>&1 + echo -e "XX\n97\nFinishing touches... \nXXX" + filter_unused_nics >> $SETUPLOG 2>&1 + network_setup >> $SETUPLOG 2>&1 + echo -e "XXX\n98\nVerifying Setup... \nXXX" + salt-call state.highstate >> $SETUPLOG 2>&1 + } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 + GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') + if [[ $GOODSETUP == '0' ]]; then + whiptail_setup_complete + shutdown -r now + else + whiptail_setup_failed + shutdown -r now + fi + + fi if [ $INSTALLTYPE == 'MASTERONLY' ]; then diff --git a/setup/whiptail.sh b/setup/whiptail.sh index bd40f5e83..547fb4a9a 100644 --- a/setup/whiptail.sh +++ b/setup/whiptail.sh @@ -206,6 +206,7 @@ whiptail_install_type() { "STORAGENODE" "Add a Storage Hot Node with parsing" OFF \ "MASTERONLY" "Start a new grid" OFF \ "EVALMODE" "Evaluate all the things" OFF \ + "HELIXSENSOR" "Connect this sensor to FireEye Helix" "PARSINGNODE" "TODO Add a dedicated Parsing Node" OFF \ "HOTNODE" "TODO Add Hot Node (Storage Node without Parsing)" OFF \ "WARMNODE" "TODO Add Warm Node to existing Hot or Storage node" OFF \ @@ -529,7 +530,7 @@ whiptail_patch_schedule_select_hours() { "09:00" "" OFF \ "10:00" "" OFF \ "11:00" "" OFF 3>&1 1>&2 2>&3 )) - + local exitstatus=$? whiptail_check_exitstatus $exitstatus From 897e009231f454fdaa346c0d84043a14bbc20c99 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Sun, 8 Dec 2019 19:21:16 -0500 Subject: [PATCH 124/200] Salt Top file for helix sensor --- salt/top.sls | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/salt/top.sls b/salt/top.sls index 46745a38b..bf3725f9f 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -9,6 +9,19 @@ base: - patch.os.schedule - motd + 'G@role:so-helix': + - ca + - ssl + - common + - firewall + - pcap + - suricata + - bro + - redis + - logstash + - filebeat + - schedule + 'G@role:so-sensor': - ca - ssl @@ -101,7 +114,7 @@ base: {%- if PLAYBOOK != 0 %} - playbook {%- endif %} - + # Storage node logic From 362cd0487fa06ff1ea9d7a41f8ae39cf76a0abaa Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 9 Dec 2019 09:52:52 -0500 Subject: [PATCH 125/200] Additional Helix Support --- salt/logstash/conf/conf.enabled.txt.so-helix | 18 +++ .../files/dynamic/9997_output_helix.conf | 112 ++++++++++++++++++ setup/so-setup.sh | 1 + setup/whiptail.sh | 9 ++ 4 files changed, 140 insertions(+) create mode 100644 salt/logstash/conf/conf.enabled.txt.so-helix create mode 100644 salt/logstash/files/dynamic/9997_output_helix.conf diff --git a/salt/logstash/conf/conf.enabled.txt.so-helix b/salt/logstash/conf/conf.enabled.txt.so-helix new file mode 100644 index 000000000..6464496fa --- /dev/null +++ b/salt/logstash/conf/conf.enabled.txt.so-helix @@ -0,0 +1,18 @@ +# This is where can specify which LogStash configs get loaded. +# +# The custom folder on the master gets automatically synced to each logstash +# node. +# +# To enable a custom configuration see the following example and uncomment: +# /usr/share/logstash/pipeline.custom/1234_input_custom.conf +## +# All of the defaults are loaded. +/usr/share/logstash/pipeline.so/0000_input_syslogng.conf +/usr/share/logstash/pipeline.so/0001_input_json.conf +/usr/share/logstash/pipeline.so/0002_input_windows_json.conf +/usr/share/logstash/pipeline.so/0003_input_syslog.conf +/usr/share/logstash/pipeline.so/0005_input_suricata.conf +#/usr/share/logstash/pipeline.dynamic/0006_input_beats.conf +/usr/share/logstash/pipeline.dynamic/0010_input_hhbeats.conf +/usr/share/logstash/pipeline.so/0007_input_import.conf +/usr/share/logstash/pipeline.dynamic/9999_output_redis.conf diff --git a/salt/logstash/files/dynamic/9997_output_helix.conf b/salt/logstash/files/dynamic/9997_output_helix.conf new file mode 100644 index 000000000..c71b7d241 --- /dev/null +++ b/salt/logstash/files/dynamic/9997_output_helix.conf @@ -0,0 +1,112 @@ +{%- if salt['grains.get']('role') == 'so-master' %} +{% set master = salt['pillar.get']('static:masterip', '') %} +{%- set nodetype = 'master' %} +{%- else %} +{%- set nodetype = salt['pillar.get']('node:node_type', 'storage') %} +{% set master = salt['pillar.get']('static:masterip', '') %} +{%- endif %} +filter { + if "fe_clone" in [type] { + grok { + match => [ + "source_ip", "^%{IPV4:srcipv4}$", + "source_ip", "(?^([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{1,4}$|((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4})$)" + ] + } + grok { + match => [ + "destination_ip", "(?^([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{1,4}$|((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4})$)", + "destination_ip", "^%{IPV4:dstipv4}$" + ] + } + geoip { + source => "[source_ip]" + target => "source_geo" + } + geoip { + source => "[destination_ip]" + target => "destination_geo" + + } + mutate { + #rename => { "%{[source_geo][country_code]}" => "srccountrycode" } + #rename => { "%{[destination_geo][country_code]}" => "dstcountrycode" } + rename => { "syslog-host_from" => "sensor" } + rename => { "message" => "rawmsg" } + rename => { "event_type" => "program" } + copy => { "program" => "class" } + rename => { "source_port" => "srcport" } + rename => { "destination_port" => "dstport" } + + remove_field => ["source_ip", "destination_ip"] + remove_field => ["sensorname", "sensor_name", "service", "source", "tags", "syslog-host"] + remove_field => ["sensor_name", "source_ips", "ips", "destination_ips", "syslog-priority", "syslog-file_name", "syslog-facility"] + } + } + if "bro_conn" in [program] { + mutate { + #add_field => { "metaclass" => "connection" } + rename => { "original_bytes" => "sentbytes" } + rename => { "respond_bytes" => "rcvdbytes" } + rename => { "connection_state" => "connstate" } + rename => { "uid" => "connectionid" } + rename => { "respond_packets" => "rcvdpackets" } + rename => { "original_packets" => "sentpackets" } + rename => { "respond_ip_bytes" => "rcvdipbytes" } + rename => { "original_ip_bytes" => "sentipbytes" } + rename => { "local_respond" => "local_resp" } + rename => { "local_orig" => "localorig" } + rename => { "missed_bytes" => "missingbytes" } + } + } + if "bro_dns" in [program] { + mutate{ + #add_field = { "metaclass" => "dns"} + rename => { "query" => "domain" } + rename => { "query_class" => "queryclass" } + rename => { "query_class_name" => "queryclassname" } + rename => { "query_type" => "querytype" } + rename => { "query_type_name" => "querytypename" } + rename => { "ra" => "recursionavailable" } + rename => { "rd" => "recursiondesired" } + + } + } + if "bro_dhcp" in [program] { + mutate{ + #add_field = { "metaclass" => "dhcp"} + rename => { "ips" => "ip" } + } + } + if "bro_files" in [program] { + mutate{ + #add_field = { "metaclass" => "dns"} + rename => { "missing_bytes" => "missingbytes" } + rename => { "fuid" => "fileid" } + rename => { "uid" => "connectionid" } + } + } + if "bro_http" in [program] { + mutate{ + #add_field = { "metaclass" => "dns"} + rename => { "status_code" => "statuscode" } + rename => { "status_message" => "statusmsg" } + rename => { "resp_mime_types" => "rcvdmimetype" } + rename => { "resp_fuids" => "rcvdfileid" } + rename => { "response_body_len" => "rcvdbodybytes" } + rename => { "request_body_len" => "sentbodybytes" } + + } + } +} +output { + if "fe_clone" in [type] { + http { + url => "https://helix-integrations.cloud.aws.apps.fireeye.com/api/upload?source=test&format=json" + http_method => post + http_compression => true + headers => ["Authorization", "{{ HELIXAPIKEY }}"] + format => json_batch + } + } +} diff --git a/setup/so-setup.sh b/setup/so-setup.sh index 42a1e70c8..ea7e869af 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -153,6 +153,7 @@ if (whiptail_you_sure) ; then ## Master ## #################### if [ $INSTALLTYPE == 'HELIXSESOR']; then + whiptail_helix_apikey whiptail_homenet_master whiptail_rule_setup # Get the code if it isn't ET Open diff --git a/setup/whiptail.sh b/setup/whiptail.sh index 547fb4a9a..7ad53333e 100644 --- a/setup/whiptail.sh +++ b/setup/whiptail.sh @@ -169,6 +169,15 @@ whiptail_eval_adv_warning() { whiptail --title "Security Onion Setup" --msgbox "Please keep in mind the more services that you enable the more RAM that is required." 8 75 } +whiptail_helix_apikey() { + HELIXAPIKEY=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter your Helix API Key" 10 75 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus + +} + whiptail_homenet_master() { # Ask for the HOME_NET on the master From 599341483e969a9e71868bbb2c67bf5b52cae6ac Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 9 Dec 2019 09:59:28 -0500 Subject: [PATCH 126/200] adding api key for Helix --- salt/logstash/files/dynamic/9997_output_helix.conf | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/salt/logstash/files/dynamic/9997_output_helix.conf b/salt/logstash/files/dynamic/9997_output_helix.conf index c71b7d241..a6aefbf53 100644 --- a/salt/logstash/files/dynamic/9997_output_helix.conf +++ b/salt/logstash/files/dynamic/9997_output_helix.conf @@ -1,10 +1,5 @@ -{%- if salt['grains.get']('role') == 'so-master' %} -{% set master = salt['pillar.get']('static:masterip', '') %} -{%- set nodetype = 'master' %} -{%- else %} -{%- set nodetype = salt['pillar.get']('node:node_type', 'storage') %} -{% set master = salt['pillar.get']('static:masterip', '') %} -{%- endif %} +{% set helix_api_key = salt['pillar.get']('fireeye:helix:api_key', '') %} + filter { if "fe_clone" in [type] { grok { @@ -105,7 +100,7 @@ output { url => "https://helix-integrations.cloud.aws.apps.fireeye.com/api/upload?source=test&format=json" http_method => post http_compression => true - headers => ["Authorization", "{{ HELIXAPIKEY }}"] + headers => ["Authorization", "{{ helix_api_key }}"] format => json_batch } } From 3904c193338279e6e54fb4c1ebd5b6b45db0069e Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 9 Dec 2019 10:04:14 -0500 Subject: [PATCH 127/200] Change Variables to UperCase --- salt/logstash/files/dynamic/9997_output_helix.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/logstash/files/dynamic/9997_output_helix.conf b/salt/logstash/files/dynamic/9997_output_helix.conf index a6aefbf53..495c4ea9e 100644 --- a/salt/logstash/files/dynamic/9997_output_helix.conf +++ b/salt/logstash/files/dynamic/9997_output_helix.conf @@ -1,4 +1,4 @@ -{% set helix_api_key = salt['pillar.get']('fireeye:helix:api_key', '') %} +{% set HELIX_API_KEY = salt['pillar.get']('fireeye:helix:api_key', '') %} filter { if "fe_clone" in [type] { @@ -100,7 +100,7 @@ output { url => "https://helix-integrations.cloud.aws.apps.fireeye.com/api/upload?source=test&format=json" http_method => post http_compression => true - headers => ["Authorization", "{{ helix_api_key }}"] + headers => ["Authorization", "{{ HELIX_API_KEY }}"] format => json_batch } } From a4b59ee8bf708dc72d424b734438e2119a5fd964 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 9 Dec 2019 10:22:35 -0500 Subject: [PATCH 128/200] logstash helix --- pillar/top.sls | 4 ++++ salt/logstash/files/dynamic/9997_output_helix.conf | 2 +- setup/functions.sh | 11 +++++++++++ setup/so-setup.sh | 2 ++ 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/pillar/top.sls b/pillar/top.sls index ffa99de59..77e0c1672 100644 --- a/pillar/top.sls +++ b/pillar/top.sls @@ -27,3 +27,7 @@ base: - nodes.{{ grains.id }} - static - firewall.* + + 'G@role:so-helix': + - fireeye + - static diff --git a/salt/logstash/files/dynamic/9997_output_helix.conf b/salt/logstash/files/dynamic/9997_output_helix.conf index a6aefbf53..fcb9d9367 100644 --- a/salt/logstash/files/dynamic/9997_output_helix.conf +++ b/salt/logstash/files/dynamic/9997_output_helix.conf @@ -1,4 +1,4 @@ -{% set helix_api_key = salt['pillar.get']('fireeye:helix:api_key', '') %} +{% set HELIXAPIKEY = salt['pillar.get']('fireeye:helix:api_key', '') %} filter { if "fe_clone" in [type] { diff --git a/setup/functions.sh b/setup/functions.sh index ff546ea31..8ae3a28c1 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -476,6 +476,17 @@ filter_unused_nics() { FNICS=$(ip link | grep -vwe $grep_string | awk -F: '$0 !~ "lo|vir|veth|br|docker|wl|^[^0-9]"{print $2}') } +fireeye_pillar() { + + FIREEYEPILLARPATH=$TMP/pillar/fireeye + + echo "" >> $FIREEYEPILLARPATH/init.sls + echo "fireeye:" >> $FIREEYEPILLARPATH/init.sls + echo " helix:" >> $FIREEYEPILLARPATH/init.sls + echo " api_key: $HELIXAPIKEY" >> $FIREEYEPILLARPATH/init.sls + +} + generate_passwords(){ # Generate Random Passwords for Things MYSQLPASS=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) diff --git a/setup/so-setup.sh b/setup/so-setup.sh index ea7e869af..0f206fc26 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -193,6 +193,8 @@ if (whiptail_you_sure) ; then master_pillar >> $SETUPLOG 2>&1 echo "** Generating the patch pillar **" >> $SETUPLOG patch_pillar >> $SETUPLOG 2>&1 + echo "** Generating the FireEye pillar **" >> $SETUPLOG + fireeye_pillar >> $SETUPLOG 2>&1 echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" copy_minion_tmp_files >> $SETUPLOG 2>&1 # Do a checkin to push the key up From 0bb5922372e98990cff32970a1757b32dccbb357 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 9 Dec 2019 10:26:25 -0500 Subject: [PATCH 129/200] Fix Setup Syntax --- setup/so-setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/so-setup.sh b/setup/so-setup.sh index ea7e869af..eb2d54117 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -152,7 +152,7 @@ if (whiptail_you_sure) ; then #################### ## Master ## #################### - if [ $INSTALLTYPE == 'HELIXSESOR']; then + if [ $INSTALLTYPE == 'HELIXSESOR' ]; then whiptail_helix_apikey whiptail_homenet_master whiptail_rule_setup From bb6e736e7950acc779cf3b3960318c0167388cc3 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 9 Dec 2019 10:31:11 -0500 Subject: [PATCH 130/200] Fix Setup Syntax --- setup/so-setup.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/setup/so-setup.sh b/setup/so-setup.sh index 142bab9e0..8d5c63a3b 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -278,8 +278,7 @@ if (whiptail_you_sure) ; then if [ $BROVERSION != 'SURICATA' ]; then whiptail_master_adv_service_brologs fi - fi - + # Last Chance to back out whiptail_make_changes set_hostname From fe8a70f661305504fede4bd0631444f5953e172c Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 9 Dec 2019 10:32:45 -0500 Subject: [PATCH 131/200] Fix Setup Syntax --- setup/so-setup.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup/so-setup.sh b/setup/so-setup.sh index 8d5c63a3b..142bab9e0 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -278,7 +278,8 @@ if (whiptail_you_sure) ; then if [ $BROVERSION != 'SURICATA' ]; then whiptail_master_adv_service_brologs fi - + fi + # Last Chance to back out whiptail_make_changes set_hostname From 21843089c4a422b9512984437827f93ebee4d1a8 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 9 Dec 2019 10:37:53 -0500 Subject: [PATCH 132/200] Fix Setup Syntax --- setup/whiptail.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/whiptail.sh b/setup/whiptail.sh index 7ad53333e..dd6b9d776 100644 --- a/setup/whiptail.sh +++ b/setup/whiptail.sh @@ -215,7 +215,7 @@ whiptail_install_type() { "STORAGENODE" "Add a Storage Hot Node with parsing" OFF \ "MASTERONLY" "Start a new grid" OFF \ "EVALMODE" "Evaluate all the things" OFF \ - "HELIXSENSOR" "Connect this sensor to FireEye Helix" + "HELIXSENSOR" "Connect this sensor to FireEye Helix" OFF \ "PARSINGNODE" "TODO Add a dedicated Parsing Node" OFF \ "HOTNODE" "TODO Add Hot Node (Storage Node without Parsing)" OFF \ "WARMNODE" "TODO Add Warm Node to existing Hot or Storage node" OFF \ From 1c8553d4cd0349f83aeabbffb29f8278c1656d0a Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 9 Dec 2019 10:40:57 -0500 Subject: [PATCH 133/200] Fix Spelling --- setup/so-setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/so-setup.sh b/setup/so-setup.sh index 142bab9e0..aa7a19d28 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -152,7 +152,7 @@ if (whiptail_you_sure) ; then #################### ## Master ## #################### - if [ $INSTALLTYPE == 'HELIXSESOR' ]; then + if [ $INSTALLTYPE == 'HELIXSENSOR' ]; then whiptail_helix_apikey whiptail_homenet_master whiptail_rule_setup From 88ef3d05c1a1156d40a111fe595f761a9b4ed541 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 9 Dec 2019 10:50:29 -0500 Subject: [PATCH 134/200] add fireeye pillar dir during setup --- setup/functions.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/setup/functions.sh b/setup/functions.sh index 8ae3a28c1..e543658d3 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -479,6 +479,7 @@ filter_unused_nics() { fireeye_pillar() { FIREEYEPILLARPATH=$TMP/pillar/fireeye + mkdir $FIREEYEPILLARPATH echo "" >> $FIREEYEPILLARPATH/init.sls echo "fireeye:" >> $FIREEYEPILLARPATH/init.sls From e5ef8de1a85cd2128c496eb59b9598d1e092d3d2 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 9 Dec 2019 10:54:20 -0500 Subject: [PATCH 135/200] Fix variable nbame for iso install --- setup/functions.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup/functions.sh b/setup/functions.sh index e543658d3..4880e2fa4 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -252,7 +252,7 @@ configure_minion() { copy_master_config() { # Copy the master config template to the proper directory - if [ $ISOINSTALL == '1' ]; then + if [ $INSTALLMETHOD =='iso' ]; then cp /root/SecurityOnion/files/master /etc/salt/master else cp ../files/master /etc/salt/master @@ -1059,11 +1059,11 @@ salt_master_directories() { mkdir -p /opt/so/saltstack/pillar # Copy over the salt code and templates - if [ $ISOINSTALL == '1' ]; then + if [ $INSTALLMETHOD =='iso' ]; then cp /root/SecurityOnion/pillar/* /opt/so/saltstack/pillar/ cp /root/SecurityOnion/salt/* /opt/so/saltstack/salt/ else - # if ISO /root/SecurityOnion/blah + cp -R ../pillar/* /opt/so/saltstack/pillar/ cp -R ../salt/* /opt/so/saltstack/salt/ fi From 087b6eabab8a7b800658ed6503dba3beda2c62c3 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 9 Dec 2019 11:00:22 -0500 Subject: [PATCH 136/200] Fix py3 issue for the yum repo --- setup/functions.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/functions.sh b/setup/functions.sh index 4880e2fa4..fa8628082 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -927,7 +927,7 @@ protect=1 EOF else yum -y install https://repo.saltstack.com/py3/redhat/salt-py3-repo-latest-2.el7.noarch.rpm - cp /etc/yum.repos.d/salt-latest.repo /etc/yum.repos.d/salt-2019-2.repo + cp /etc/yum.repos.d/salt-py3-latest.repo /etc/yum.repos.d/salt-2019-2.repo sed -i 's/latest/2019.2/g' /etc/yum.repos.d/salt-2019-2.repo cat > /etc/yum.repos.d/wazuh.repo <<\EOF [wazuh_repo] From 5a52623e7105fbd88286dee751c366506a322429 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 9 Dec 2019 11:04:20 -0500 Subject: [PATCH 137/200] Add Master Updates Variable to HELIXSENSOR role --- setup/so-setup.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/setup/so-setup.sh b/setup/so-setup.sh index aa7a19d28..e9c2a4076 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -153,6 +153,7 @@ if (whiptail_you_sure) ; then ## Master ## #################### if [ $INSTALLTYPE == 'HELIXSENSOR' ]; then + MASTERUPDATES=OPEN whiptail_helix_apikey whiptail_homenet_master whiptail_rule_setup From cdb38770775ec6e51a66df52c47e3fdb10457f87 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 9 Dec 2019 11:15:54 -0500 Subject: [PATCH 138/200] Install Master is HelixSensor --- setup/functions.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/functions.sh b/setup/functions.sh index fa8628082..f70fef17d 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -786,7 +786,7 @@ saltify() { if [ $OS == 'centos' ]; then ADDUSER=adduser - if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then + if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ] || [ $INSTALLTYPE == 'HELIXSENSOR' ]; then yum -y install wget https://repo.saltstack.com/py3/redhat/salt-py3-repo-latest-2.el7.noarch.rpm cp /etc/yum.repos.d/salt-py3-latest.repo /etc/yum.repos.d/salt-py3-2019-2.repo sed -i 's/latest/2019.2/g' /etc/yum.repos.d/salt-py3-2019-2.repo From 5c9dddf90ab3f7079e1c77fd86556e787f906f4e Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 9 Dec 2019 11:47:56 -0500 Subject: [PATCH 139/200] Helix Role Additions --- setup/functions.sh | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/setup/functions.sh b/setup/functions.sh index f70fef17d..9dbed1309 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -265,10 +265,12 @@ copy_master_config() { copy_minion_tmp_files() { - if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then + if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ] || [ $INSTALLTYPE == 'HELIXSENSOR' ]; then echo "rsyncing pillar and salt files in $TMP to /opt/so/saltstack" rsync -a -v $TMP/pillar/ /opt/so/saltstack/pillar/ >> $SETUPLOG 2>&1 - rsync -a -v $TMP/salt/ /opt/so/saltstack/salt/ >> $SETUPLOG 2>&1 + if [ -d $TMP/salt ] ; then + rsync -a -v $TMP/salt/ /opt/so/saltstack/salt/ >> $SETUPLOG 2>&1 + fi else echo "scp pillar and salt files in $TMP to master /opt/so/saltstack" scp -prv -i /root/.ssh/so.key $TMP/pillar/* socore@$MSRV:/opt/so/saltstack/pillar >> $SETUPLOG 2>&1 @@ -404,7 +406,7 @@ docker_install() { yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo yum -y update yum -y install docker-ce python36-docker - if [ $INSTALLTYPE != 'EVALMODE' ]; then + if [ $INSTALLTYPE != 'EVALMODE' ] || [ $INSTALLTYPE == 'HELIXSENSOR' ]; then docker_registry fi echo "Restarting Docker" >> $SETUPLOG 2>&1 @@ -602,7 +604,7 @@ master_pillar() { echo " mainint: $MAININT" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls echo " esheap: $ES_HEAP_SIZE" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls echo " esclustername: {{ grains.host }}" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls - if [ $INSTALLTYPE == 'EVALMODE' ]; then + if [ $INSTALLTYPE == 'EVALMODE' ] || [ $INSTALLTYPE == 'HELIXSENSOR' ]; then echo " freq: 0" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls echo " domainstats: 0" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls echo " ls_pipeline_batch_size: 125" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls @@ -719,7 +721,7 @@ node_pillar() { patch_pillar() { case $INSTALLTYPE in - MASTERONLY | EVALMODE) + MASTERONLY | EVALMODE | HELIXSENSOR) PATCHPILLARPATH=/opt/so/saltstack/pillar/masters ;; SENSORONLY) @@ -946,7 +948,7 @@ EOF yum -y update exclude=salt* systemctl enable salt-minion - if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then + if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ] || [ $INSTALLTYPE == 'HELIXSENSOR' ]; then yum -y install salt-master-2019.2.2 python3 python36-m2crypto salt-minion-2019.2.2 python36-dateutil python36-mysql python36-docker systemctl enable salt-master else @@ -1019,7 +1021,7 @@ EOF salt_checkin() { # Master State to Fix Mine Usage - if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then + if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ] || [ $INSTALLTYPE == 'HELIXSENSOR' ]; then echo "Building Certificate Authority" salt-call state.apply ca >> $SETUPLOG 2>&1 echo " *** Restarting Salt to fix any SSL errors. ***" @@ -1059,7 +1061,7 @@ salt_master_directories() { mkdir -p /opt/so/saltstack/pillar # Copy over the salt code and templates - if [ $INSTALLMETHOD =='iso' ]; then + if [ $INSTALLMETHOD == 'iso' ]; then cp /root/SecurityOnion/pillar/* /opt/so/saltstack/pillar/ cp /root/SecurityOnion/salt/* /opt/so/saltstack/salt/ else @@ -1139,7 +1141,7 @@ set_hostname() { echo "127.0.0.1 $HOSTNAME $HOSTNAME.localdomain localhost localhost.localdomain localhost4 localhost4.localdomain" > /etc/hosts echo "::1 localhost localhost.localdomain localhost6 localhost6.localdomain6" >> /etc/hosts echo $HOSTNAME > /etc/hostname - if [ $INSTALLTYPE != 'MASTERONLY' ] || [ $INSTALLTYPE != 'EVALMODE' ]; then + if [ $INSTALLTYPE != 'MASTERONLY' ] || [ $INSTALLTYPE != 'EVALMODE' ] || [ $INSTALLTYPE == 'HELIXSENSOR' ]; then if [[ $TESTHOST = *"not found"* ]] || [[ $TESTHOST = *"connection timed out"* ]]; then if ! grep -q $MSRVIP /etc/hosts; then echo "$MSRVIP $MSRV" >> /etc/hosts @@ -1166,6 +1168,12 @@ set_initial_firewall_policy() { /opt/so/saltstack/pillar/data/addtotab.sh evaltab $MINION_ID $MAINIP $CPUCORES $RANDOMUID $MAININT $FSROOT $FSNSM bond0 fi + if [ $INSTALLTYPE == 'HELIXSENSOR' ]; then + printf " - $MAINIP\n" >> /opt/so/saltstack/pillar/firewall/minions.sls + printf " - $MAINIP\n" >> /opt/so/saltstack/pillar/firewall/masterfw.sls + printf " - $MAINIP\n" >> /opt/so/saltstack/pillar/firewall/forward_nodes.sls + fi + if [ $INSTALLTYPE == 'SENSORONLY' ]; then ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/firewall/addfirewall.sh minions $MAINIP ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/firewall/addfirewall.sh forward_nodes $MAINIP From f1abab560c4a5c62c4617b1136d1e1c4d60bae08 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 9 Dec 2019 11:55:53 -0500 Subject: [PATCH 140/200] Fix pillar dir --- setup/functions.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup/functions.sh b/setup/functions.sh index 9dbed1309..0a62249ed 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -252,7 +252,7 @@ configure_minion() { copy_master_config() { # Copy the master config template to the proper directory - if [ $INSTALLMETHOD =='iso' ]; then + if [ $INSTALLMETHOD == 'iso' ]; then cp /root/SecurityOnion/files/master /etc/salt/master else cp ../files/master /etc/salt/master @@ -481,7 +481,7 @@ filter_unused_nics() { fireeye_pillar() { FIREEYEPILLARPATH=$TMP/pillar/fireeye - mkdir $FIREEYEPILLARPATH + mkdir -p $FIREEYEPILLARPATH echo "" >> $FIREEYEPILLARPATH/init.sls echo "fireeye:" >> $FIREEYEPILLARPATH/init.sls From c58c1a494a8b33d68f55d260aad560eab516f42a Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 9 Dec 2019 12:21:17 -0500 Subject: [PATCH 141/200] top.sls troubleshooting --- setup/functions.sh | 1 - setup/so-setup.sh | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/functions.sh b/setup/functions.sh index 0a62249ed..a00cb7b25 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -1065,7 +1065,6 @@ salt_master_directories() { cp /root/SecurityOnion/pillar/* /opt/so/saltstack/pillar/ cp /root/SecurityOnion/salt/* /opt/so/saltstack/salt/ else - cp -R ../pillar/* /opt/so/saltstack/pillar/ cp -R ../salt/* /opt/so/saltstack/salt/ fi diff --git a/setup/so-setup.sh b/setup/so-setup.sh index e9c2a4076..23ee52cbe 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -188,6 +188,7 @@ if (whiptail_you_sure) ; then chown_salt_master >> $SETUPLOG 2>&1 es_heapsize >> $SETUPLOG 2>&1 ls_heapsize >> $SETUPLOG 2>&1 + exit echo -e "XXX\n25\nConfiguring Default Pillars... \nXXX" master_static >> $SETUPLOG 2>&1 echo "** Generating the master pillar **" >> $SETUPLOG From a3d88fd4a43d53b7309deef711ce04e00f3c1bde Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 9 Dec 2019 12:26:21 -0500 Subject: [PATCH 142/200] top.sls troubleshooting --- setup/so-setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/so-setup.sh b/setup/so-setup.sh index 23ee52cbe..23b9347b5 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -188,7 +188,6 @@ if (whiptail_you_sure) ; then chown_salt_master >> $SETUPLOG 2>&1 es_heapsize >> $SETUPLOG 2>&1 ls_heapsize >> $SETUPLOG 2>&1 - exit echo -e "XXX\n25\nConfiguring Default Pillars... \nXXX" master_static >> $SETUPLOG 2>&1 echo "** Generating the master pillar **" >> $SETUPLOG @@ -197,6 +196,7 @@ if (whiptail_you_sure) ; then patch_pillar >> $SETUPLOG 2>&1 echo "** Generating the FireEye pillar **" >> $SETUPLOG fireeye_pillar >> $SETUPLOG 2>&1 + exit echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" copy_minion_tmp_files >> $SETUPLOG 2>&1 # Do a checkin to push the key up From 768784ccaaf17c9fbd1e88035d5372a4ab0909b6 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 9 Dec 2019 12:33:13 -0500 Subject: [PATCH 143/200] top.sls troubleshooting --- setup/so-setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/so-setup.sh b/setup/so-setup.sh index 23b9347b5..61e24a48b 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -196,9 +196,9 @@ if (whiptail_you_sure) ; then patch_pillar >> $SETUPLOG 2>&1 echo "** Generating the FireEye pillar **" >> $SETUPLOG fireeye_pillar >> $SETUPLOG 2>&1 - exit echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" copy_minion_tmp_files >> $SETUPLOG 2>&1 + exit # Do a checkin to push the key up echo "** Pushing the key up to Master **" >> $SETUPLOG salt_firstcheckin >> $SETUPLOG 2>&1 From f61cb3b8909428cbaad821f2c2bac56e38fc24b5 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 9 Dec 2019 12:37:27 -0500 Subject: [PATCH 144/200] top.sls troubleshooting --- setup/so-setup.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/setup/so-setup.sh b/setup/so-setup.sh index 61e24a48b..e9c2a4076 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -198,7 +198,6 @@ if (whiptail_you_sure) ; then fireeye_pillar >> $SETUPLOG 2>&1 echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" copy_minion_tmp_files >> $SETUPLOG 2>&1 - exit # Do a checkin to push the key up echo "** Pushing the key up to Master **" >> $SETUPLOG salt_firstcheckin >> $SETUPLOG 2>&1 From 8342dc1447472c8435b599e8aee564f6b4b03b57 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 9 Dec 2019 12:49:46 -0500 Subject: [PATCH 145/200] Helix node type --- pillar/top.sls | 3 +++ setup/functions.sh | 2 +- setup/so-setup.sh | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/pillar/top.sls b/pillar/top.sls index 77e0c1672..992549ffa 100644 --- a/pillar/top.sls +++ b/pillar/top.sls @@ -29,5 +29,8 @@ base: - firewall.* 'G@role:so-helix': + - masters.{{ grains.id }} + - static + - firewall.* - fireeye - static diff --git a/setup/functions.sh b/setup/functions.sh index a00cb7b25..951a37a87 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -406,7 +406,7 @@ docker_install() { yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo yum -y update yum -y install docker-ce python36-docker - if [ $INSTALLTYPE != 'EVALMODE' ] || [ $INSTALLTYPE == 'HELIXSENSOR' ]; then + if [ $INSTALLTYPE != 'EVALMODE' ]; then docker_registry fi echo "Restarting Docker" >> $SETUPLOG 2>&1 diff --git a/setup/so-setup.sh b/setup/so-setup.sh index e9c2a4076..a2889a0da 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -180,7 +180,7 @@ if (whiptail_you_sure) ; then docker_install >> $SETUPLOG 2>&1 echo -e "XXX\n10\nConfiguring Salt Master... \nXXX" echo " ** Configuring Minion **" >> $SETUPLOG - configure_minion master >> $SETUPLOG 2>&1 + configure_minion helix >> $SETUPLOG 2>&1 echo " ** Installing Salt Master **" >> $SETUPLOG install_master >> $SETUPLOG 2>&1 salt_master_directories >> $SETUPLOG 2>&1 From 4c4cdb7189bb49f6f0ffd5cd706f1f23e1d2ca2a Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 9 Dec 2019 16:27:03 -0500 Subject: [PATCH 146/200] Helix changes and Wazuh --- salt/logstash/conf/conf.enabled.txt.so-helix | 9 +-------- salt/top.sls | 1 + salt/wazuh/init.sls | 6 +++--- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/salt/logstash/conf/conf.enabled.txt.so-helix b/salt/logstash/conf/conf.enabled.txt.so-helix index 6464496fa..5d10847cd 100644 --- a/salt/logstash/conf/conf.enabled.txt.so-helix +++ b/salt/logstash/conf/conf.enabled.txt.so-helix @@ -7,12 +7,5 @@ # /usr/share/logstash/pipeline.custom/1234_input_custom.conf ## # All of the defaults are loaded. -/usr/share/logstash/pipeline.so/0000_input_syslogng.conf -/usr/share/logstash/pipeline.so/0001_input_json.conf -/usr/share/logstash/pipeline.so/0002_input_windows_json.conf -/usr/share/logstash/pipeline.so/0003_input_syslog.conf -/usr/share/logstash/pipeline.so/0005_input_suricata.conf -#/usr/share/logstash/pipeline.dynamic/0006_input_beats.conf /usr/share/logstash/pipeline.dynamic/0010_input_hhbeats.conf -/usr/share/logstash/pipeline.so/0007_input_import.conf -/usr/share/logstash/pipeline.dynamic/9999_output_redis.conf +/usr/share/logstash/pipeline.dynamic/9997_output_helix.conf diff --git a/salt/top.sls b/salt/top.sls index bf3725f9f..7a6d5b99b 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -14,6 +14,7 @@ base: - ssl - common - firewall + - idstools - pcap - suricata - bro diff --git a/salt/wazuh/init.sls b/salt/wazuh/init.sls index 8ee1371ff..a59a1d215 100644 --- a/salt/wazuh/init.sls +++ b/salt/wazuh/init.sls @@ -5,7 +5,7 @@ ossecgroup: group.present: - name: ossec - gid: 945 - + # Add ossecm user ossecm: user.present: @@ -64,13 +64,13 @@ wazuhagentregister: so-wazuhimage: cmd.run: - - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-wazuh:HH1.1.0 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-wazuh:HH1.1.3 so-wazuh: docker_container.running: - require: - so-wazuhimage - - image: docker.io/soshybridhunter/so-wazuh:HH1.1.0 + - image: docker.io/soshybridhunter/so-wazuh:HH1.1.3 - hostname: {{HOSTNAME}}-wazuh-manager - name: so-wazuh - detach: True From 4874e540dac6426133457e7b9febabe3098b74f8 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 9 Dec 2019 17:18:12 -0500 Subject: [PATCH 147/200] changes for FireEye Helix integration --- salt/firewall/init.sls | 2 +- setup/functions.sh | 9 ++++++--- setup/so-setup.sh | 9 +++++++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/salt/firewall/init.sls b/salt/firewall/init.sls index b0ff81b00..f238fbf59 100644 --- a/salt/firewall/init.sls +++ b/salt/firewall/init.sls @@ -1,5 +1,5 @@ # Firewall Magic for the grid -{%- if grains['role'] == 'so-master' or grains['role'] == 'so-eval' %} +{%- if grains['role'] in ['so-eval','so-master','so-helix'] %} {%- set ip = salt['pillar.get']('static:masterip', '') %} {%- elif grains['role'] == 'so-node' %} {%- set ip = salt['pillar.get']('node:mainip', '') %} diff --git a/setup/functions.sh b/setup/functions.sh index 951a37a87..78a460054 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -236,6 +236,9 @@ configure_minion() { OLDPASS=$(cat /opt/so/saltstack/pillar/auth.sls | grep mysql | awk {'print $2'}) echo "mysql.pass: '$OLDPASS'" >> /etc/salt/minion fi + elif [ $TYPE == 'helix' ]; then + echo "master: $HOSTNAME" > /etc/salt/minion + echo "id: $MINION_ID" >> /etc/salt/minion else echo "master: $MSRV" > /etc/salt/minion echo "id: $MINION_ID" >> /etc/salt/minion @@ -255,7 +258,7 @@ copy_master_config() { if [ $INSTALLMETHOD == 'iso' ]; then cp /root/SecurityOnion/files/master /etc/salt/master else - cp ../files/master /etc/salt/master + cp $SCRIPTDIR/../files/master /etc/salt/master fi # Restart the service so it picks up the changes -TODO Enable service on CentOS @@ -1065,8 +1068,8 @@ salt_master_directories() { cp /root/SecurityOnion/pillar/* /opt/so/saltstack/pillar/ cp /root/SecurityOnion/salt/* /opt/so/saltstack/salt/ else - cp -R ../pillar/* /opt/so/saltstack/pillar/ - cp -R ../salt/* /opt/so/saltstack/salt/ + cp -R $SCRIPTDIR/../pillar/* /opt/so/saltstack/pillar/ + cp -R $SCRIPTDIR/../salt/* /opt/so/saltstack/salt/ fi chmod +x /opt/so/saltstack/pillar/firewall/addfirewall.sh diff --git a/setup/so-setup.sh b/setup/so-setup.sh index a2889a0da..f3b60792a 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -35,7 +35,7 @@ MINION_ID=$(echo $HOSTNAME | awk -F. {'print $1'}) TOTAL_MEM=`grep MemTotal /proc/meminfo | awk '{print $2}' | sed -r 's/.{3}$//'` NICS=$(ip link | awk -F: '$0 !~ "lo|vir|veth|br|docker|wl|^[^0-9]"{print $2 " \"" "Interface" "\"" " OFF"}') CPUCORES=$(cat /proc/cpuinfo | grep processor | wc -l) -LISTCORES=$(cat /proc/cpuinfo | grep processor | awk '{print $3 " \"" "core" "\""}') +LSTCORES=$(cat /proc/cpuinfo | grep processor | awk '{print $3 " \"" "core" "\""}') RANDOMUID=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1) NODE_ES_PORT="9200" SETUPLOG="/root/sosetup.log" @@ -150,10 +150,12 @@ if (whiptail_you_sure) ; then esac #################### - ## Master ## + ## Helix ## #################### if [ $INSTALLTYPE == 'HELIXSENSOR' ]; then MASTERUPDATES=OPEN + filter_unused_nics + whiptail_bond_nics whiptail_helix_apikey whiptail_homenet_master whiptail_rule_setup @@ -245,6 +247,9 @@ if (whiptail_you_sure) ; then fi + #################### + ## Master ## + #################### if [ $INSTALLTYPE == 'MASTERONLY' ]; then # Would you like to do an advanced install? From 69172b05b5cf19cdad280c14263ed25eb92b5cc8 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 9 Dec 2019 17:21:03 -0500 Subject: [PATCH 148/200] fix vi typo from last commit --- setup/so-setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/so-setup.sh b/setup/so-setup.sh index f3b60792a..56b4885be 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -35,7 +35,7 @@ MINION_ID=$(echo $HOSTNAME | awk -F. {'print $1'}) TOTAL_MEM=`grep MemTotal /proc/meminfo | awk '{print $2}' | sed -r 's/.{3}$//'` NICS=$(ip link | awk -F: '$0 !~ "lo|vir|veth|br|docker|wl|^[^0-9]"{print $2 " \"" "Interface" "\"" " OFF"}') CPUCORES=$(cat /proc/cpuinfo | grep processor | wc -l) -LSTCORES=$(cat /proc/cpuinfo | grep processor | awk '{print $3 " \"" "core" "\""}') +LISTCORES=$(cat /proc/cpuinfo | grep processor | awk '{print $3 " \"" "core" "\""}') RANDOMUID=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1) NODE_ES_PORT="9200" SETUPLOG="/root/sosetup.log" From ae3c428941ac1758753c02d057068b9cbc16fc66 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 10 Dec 2019 10:02:41 -0500 Subject: [PATCH 149/200] Helix Logstash Changes --- salt/common/nginx/nginx.conf.so-helix | 89 +++++++++++++++++++++++++++ salt/logstash/init.sls | 7 +++ 2 files changed, 96 insertions(+) create mode 100644 salt/common/nginx/nginx.conf.so-helix diff --git a/salt/common/nginx/nginx.conf.so-helix b/salt/common/nginx/nginx.conf.so-helix new file mode 100644 index 000000000..39688f3df --- /dev/null +++ b/salt/common/nginx/nginx.conf.so-helix @@ -0,0 +1,89 @@ +# For more information on configuration, see: +# * Official English Documentation: http://nginx.org/en/docs/ +# * Official Russian Documentation: http://nginx.org/ru/docs/ + +user nginx; +worker_processes auto; +error_log /var/log/nginx/error.log; +pid /run/nginx.pid; + +# Load dynamic modules. See /usr/share/nginx/README.dynamic. +include /usr/share/nginx/modules/*.conf; + +events { + worker_connections 1024; +} + +http { + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + # Load modular configuration files from the /etc/nginx/conf.d directory. + # See http://nginx.org/en/docs/ngx_core_module.html#include + # for more information. + include /etc/nginx/conf.d/*.conf; + + server { + listen 80 default_server; + listen [::]:80 default_server; + server_name _; + root /usr/share/nginx/html; + + # Load configuration files for the default server block. + include /etc/nginx/default.d/*.conf; + + location / { + } + + error_page 404 /404.html; + location = /40x.html { + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + } + } + +# Settings for a TLS enabled server. +# +# server { +# listen 443 ssl http2 default_server; +# listen [::]:443 ssl http2 default_server; +# server_name _; +# root /usr/share/nginx/html; +# +# ssl_certificate "/etc/pki/nginx/server.crt"; +# ssl_certificate_key "/etc/pki/nginx/private/server.key"; +# ssl_session_cache shared:SSL:1m; +# ssl_session_timeout 10m; +# ssl_ciphers HIGH:!aNULL:!MD5; +# ssl_prefer_server_ciphers on; +# +# # Load configuration files for the default server block. +# include /etc/nginx/default.d/*.conf; +# +# location / { +# } +# +# error_page 404 /404.html; +# location = /40x.html { +# } +# +# error_page 500 502 503 504 /50x.html; +# location = /50x.html { +# } +# } + +} diff --git a/salt/logstash/init.sls b/salt/logstash/init.sls index ee13db281..c2b80346f 100644 --- a/salt/logstash/init.sls +++ b/salt/logstash/init.sls @@ -30,6 +30,13 @@ {% set dstats = salt['pillar.get']('master:domainstats', '0') %} {% set nodetype = salt['grains.get']('role', '') %} +{% elif grains['role'] == 'so-helix' %} + +{% set lsheap = salt['pillar.get']('master:lsheap', '') %} +{% set freq = salt['pillar.get']('master:freq', '0') %} +{% set dstats = salt['pillar.get']('master:domainstats', '0') %} +{% set nodetype = salt['grains.get']('role', '') %} + {% elif grains['role'] == 'so-eval' %} {% set lsheap = salt['pillar.get']('master:lsheap', '') %} From 115a0ec2294c0a009e164bed1843f45ddbc7bd28 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 10 Dec 2019 10:18:16 -0500 Subject: [PATCH 150/200] Helix Mode - Add bond --- setup/so-setup.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup/so-setup.sh b/setup/so-setup.sh index 56b4885be..c9dc12da8 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -175,6 +175,8 @@ if (whiptail_you_sure) ; then # Install salt and dependencies { sleep 0.5 + echo -e "XXX\n0\nCreating Bond Interface... \nXXX" + create_sensor_bond >> $SETUPLOG 2>&1 echo -e "XXX\n1\nInstalling and configuring Salt... \nXXX" echo " ** Installing Salt and Dependencies **" >> $SETUPLOG saltify >> $SETUPLOG 2>&1 From ce517dfebca3e4bc35e03342dbc25420a3841d63 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 10 Dec 2019 10:40:28 -0500 Subject: [PATCH 151/200] Helix Mode - Fix SSL so Filebeat works properly --- salt/ssl/init.sls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/ssl/init.sls b/salt/ssl/init.sls index b78e5f578..a6be4e6e7 100644 --- a/salt/ssl/init.sls +++ b/salt/ssl/init.sls @@ -129,7 +129,7 @@ fbcrtlink: backup: True {% endif %} -{% if grains['role'] == 'so-sensor' or grains['role'] == 'so-node' or grains['role'] == 'so-eval' %} +{% if grains['role'] == 'so-sensor' or grains['role'] == 'so-node' or grains['role'] == 'so-eval' or grains['role'] == 'so-helix' %} fbcertdir: file.directory: From fe042ed2bb18eac43f8a9fc04291a558d235dd94 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 10 Dec 2019 10:59:35 -0500 Subject: [PATCH 152/200] Filebeat State - Fix watch statement to only change on yml --- salt/filebeat/init.sls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/filebeat/init.sls b/salt/filebeat/init.sls index 31c996f51..fce1c6b38 100644 --- a/salt/filebeat/init.sls +++ b/salt/filebeat/init.sls @@ -85,4 +85,4 @@ so-filebeat: {%- endif %} - /etc/ssl/certs/intca.crt:/usr/share/filebeat/intraca.crt:ro - watch: - - file: /opt/so/conf/filebeat/etc + - file: /opt/so/conf/filebeat/etc/filebeat.yml From e350ee71bb7df4f9917d8ed664990e388455dadf Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 10 Dec 2019 11:03:46 -0500 Subject: [PATCH 153/200] Helix - Add sensor pillar --- setup/so-setup.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/setup/so-setup.sh b/setup/so-setup.sh index c9dc12da8..f11a2d438 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -177,7 +177,9 @@ if (whiptail_you_sure) ; then sleep 0.5 echo -e "XXX\n0\nCreating Bond Interface... \nXXX" create_sensor_bond >> $SETUPLOG 2>&1 - echo -e "XXX\n1\nInstalling and configuring Salt... \nXXX" + echo -e "XXX\n1\nGenerating Sensor Pillar... \nXXX" + sensor_pillar >> $SETUPLOG 2>&1 + echo -e "XXX\n2\nInstalling and configuring Salt... \nXXX" echo " ** Installing Salt and Dependencies **" >> $SETUPLOG saltify >> $SETUPLOG 2>&1 echo -e "XXX\n5\nInstalling Docker... \nXXX" From c46c539277f890cf005b6e11524b01274f67f609 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 10 Dec 2019 11:24:56 -0500 Subject: [PATCH 154/200] Helix - fix suricata.yml --- salt/suricata/files/suricata.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/salt/suricata/files/suricata.yaml b/salt/suricata/files/suricata.yaml index 1acce5b96..093612335 100644 --- a/salt/suricata/files/suricata.yaml +++ b/salt/suricata/files/suricata.yaml @@ -3,6 +3,8 @@ {%- set interface = salt['pillar.get']('sensor:interface', 'bond0') %} {%- if grains['role'] == 'so-eval' %} {%- set MTU = 1500 %} +{%- elif grains['role'] == 'so-helix' %} +{%- set MTU = 9000 %} {%- else %} {%- set MTU = salt['pillar.get']('sensor:mtu', '1500') %} {%- endif %} From e134071295a1d990b6c8550c67756c759fb1737c Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 10 Dec 2019 13:50:27 -0500 Subject: [PATCH 155/200] Helix - Change Parsers for Helix --- salt/logstash/conf/conf.enabled.txt.so-helix | 35 +++++ .../files/dynamic/9997_output_helix.conf | 148 ++++++++++-------- 2 files changed, 122 insertions(+), 61 deletions(-) diff --git a/salt/logstash/conf/conf.enabled.txt.so-helix b/salt/logstash/conf/conf.enabled.txt.so-helix index 5d10847cd..72bbc2ece 100644 --- a/salt/logstash/conf/conf.enabled.txt.so-helix +++ b/salt/logstash/conf/conf.enabled.txt.so-helix @@ -8,4 +8,39 @@ ## # All of the defaults are loaded. /usr/share/logstash/pipeline.dynamic/0010_input_hhbeats.conf +/usr/share/logstash/pipeline.so/1033_preprocess_snort.conf +/usr/share/logstash/pipeline.so/1100_preprocess_bro_conn.conf +/usr/share/logstash/pipeline.so/1101_preprocess_bro_dhcp.conf +/usr/share/logstash/pipeline.so/1102_preprocess_bro_dns.conf +/usr/share/logstash/pipeline.so/1103_preprocess_bro_dpd.conf +/usr/share/logstash/pipeline.so/1104_preprocess_bro_files.conf +/usr/share/logstash/pipeline.so/1105_preprocess_bro_ftp.conf +/usr/share/logstash/pipeline.so/1106_preprocess_bro_http.conf +/usr/share/logstash/pipeline.so/1107_preprocess_bro_irc.conf +/usr/share/logstash/pipeline.so/1108_preprocess_bro_kerberos.conf +/usr/share/logstash/pipeline.so/1109_preprocess_bro_notice.conf +/usr/share/logstash/pipeline.so/1110_preprocess_bro_rdp.conf +/usr/share/logstash/pipeline.so/1111_preprocess_bro_signatures.conf +/usr/share/logstash/pipeline.so/1112_preprocess_bro_smtp.conf +/usr/share/logstash/pipeline.so/1113_preprocess_bro_snmp.conf +/usr/share/logstash/pipeline.so/1114_preprocess_bro_software.conf +/usr/share/logstash/pipeline.so/1115_preprocess_bro_ssh.conf +/usr/share/logstash/pipeline.so/1116_preprocess_bro_ssl.conf +/usr/share/logstash/pipeline.so/1117_preprocess_bro_syslog.conf +/usr/share/logstash/pipeline.so/1118_preprocess_bro_tunnel.conf +/usr/share/logstash/pipeline.so/1119_preprocess_bro_weird.conf +/usr/share/logstash/pipeline.so/1121_preprocess_bro_mysql.conf +/usr/share/logstash/pipeline.so/1122_preprocess_bro_socks.conf +/usr/share/logstash/pipeline.so/1123_preprocess_bro_x509.conf +/usr/share/logstash/pipeline.so/1124_preprocess_bro_intel.conf +/usr/share/logstash/pipeline.so/1125_preprocess_bro_modbus.conf +/usr/share/logstash/pipeline.so/1126_preprocess_bro_sip.conf +/usr/share/logstash/pipeline.so/1127_preprocess_bro_radius.conf +/usr/share/logstash/pipeline.so/1128_preprocess_bro_pe.conf +/usr/share/logstash/pipeline.so/1129_preprocess_bro_rfb.conf +/usr/share/logstash/pipeline.so/1130_preprocess_bro_dnp3.conf +/usr/share/logstash/pipeline.so/1131_preprocess_bro_smb_files.conf +/usr/share/logstash/pipeline.so/1132_preprocess_bro_smb_mapping.conf +/usr/share/logstash/pipeline.so/1133_preprocess_bro_ntlm.conf +/usr/share/logstash/pipeline.so/1134_preprocess_bro_dce_rpc.conf /usr/share/logstash/pipeline.dynamic/9997_output_helix.conf diff --git a/salt/logstash/files/dynamic/9997_output_helix.conf b/salt/logstash/files/dynamic/9997_output_helix.conf index 495c4ea9e..6168bfb07 100644 --- a/salt/logstash/files/dynamic/9997_output_helix.conf +++ b/salt/logstash/files/dynamic/9997_output_helix.conf @@ -1,7 +1,7 @@ {% set HELIX_API_KEY = salt['pillar.get']('fireeye:helix:api_key', '') %} filter { - if "fe_clone" in [type] { + if [type] =~ /^bro_conn|bro_dns|bro_http|bro_files|bro_ssl$/ { grok { match => [ "source_ip", "^%{IPV4:srcipv4}$", @@ -14,6 +14,11 @@ filter { "destination_ip", "^%{IPV4:dstipv4}$" ] } + + grok { + match => [ "syslog-tags", "^.source.s_%{DATA:class}$" ] + } + geoip { source => "[source_ip]" target => "source_geo" @@ -21,87 +26,108 @@ filter { geoip { source => "[destination_ip]" target => "destination_geo" - } mutate { #rename => { "%{[source_geo][country_code]}" => "srccountrycode" } #rename => { "%{[destination_geo][country_code]}" => "dstcountrycode" } rename => { "syslog-host_from" => "sensor" } rename => { "message" => "rawmsg" } - rename => { "event_type" => "program" } - copy => { "program" => "class" } + #rename => { "event_type" => "program" } + #copy => { "program" => "class" } rename => { "source_port" => "srcport" } rename => { "destination_port" => "dstport" } - remove_field => ["source_ip", "destination_ip"] remove_field => ["sensorname", "sensor_name", "service", "source", "tags", "syslog-host"] remove_field => ["sensor_name", "source_ips", "ips", "destination_ips", "syslog-priority", "syslog-file_name", "syslog-facility"] + } + if "bro_conn" in [class] { + mutate { + #add_field => { "metaclass" => "connection" } + rename => { "original_bytes" => "sentbytes" } + rename => { "respond_bytes" => "rcvdbytes" } + rename => { "connection_state" => "connstate" } + rename => { "uid" => "connectionid" } + rename => { "respond_packets" => "rcvdpackets" } + rename => { "original_packets" => "sentpackets" } + rename => { "respond_ip_bytes" => "rcvdipbytes" } + rename => { "original_ip_bytes" => "sentipbytes" } + rename => { "local_respond" => "local_resp" } + rename => { "local_orig" => "localorig" } + rename => { "missed_bytes" => "missingbytes" } } } - if "bro_conn" in [program] { - mutate { - #add_field => { "metaclass" => "connection" } - rename => { "original_bytes" => "sentbytes" } - rename => { "respond_bytes" => "rcvdbytes" } - rename => { "connection_state" => "connstate" } - rename => { "uid" => "connectionid" } - rename => { "respond_packets" => "rcvdpackets" } - rename => { "original_packets" => "sentpackets" } - rename => { "respond_ip_bytes" => "rcvdipbytes" } - rename => { "original_ip_bytes" => "sentipbytes" } - rename => { "local_respond" => "local_resp" } - rename => { "local_orig" => "localorig" } - rename => { "missed_bytes" => "missingbytes" } + if "bro_dns" in [class] { + mutate{ + #add_field = { "metaclass" => "dns"} + rename => { "answers" => "answer" } + rename => { "query" => "domain" } + rename => { "query_class" => "queryclass" } + rename => { "query_class_name" => "queryclassname" } + rename => { "query_type" => "querytype" } + rename => { "query_type_name" => "querytypename" } + rename => { "ra" => "recursionavailable" } + rename => { "rd" => "recursiondesired" } + } } - } - if "bro_dns" in [program] { - mutate{ - #add_field = { "metaclass" => "dns"} - rename => { "query" => "domain" } - rename => { "query_class" => "queryclass" } - rename => { "query_class_name" => "queryclassname" } - rename => { "query_type" => "querytype" } - rename => { "query_type_name" => "querytypename" } - rename => { "ra" => "recursionavailable" } - rename => { "rd" => "recursiondesired" } - + if "bro_dhcp" in [class] { + mutate{ + #add_field = { "metaclass" => "dhcp"} + rename => { "ips" => "ip" } + } } - } - if "bro_dhcp" in [program] { - mutate{ - #add_field = { "metaclass" => "dhcp"} - rename => { "ips" => "ip" } + if "bro_files" in [class] { + mutate{ + #add_field = { "metaclass" => "dns"} + rename => { "missing_bytes" => "missingbytes" } + rename => { "fuid" => "fileid" } + rename => { "uid" => "connectionid" } + } } - } - if "bro_files" in [program] { - mutate{ - #add_field = { "metaclass" => "dns"} - rename => { "missing_bytes" => "missingbytes" } - rename => { "fuid" => "fileid" } - rename => { "uid" => "connectionid" } + if "bro_http" in [class] { + mutate{ + #add_field = { "metaclass" => "dns"} + rename => { "virtual_host" => "hostname" } + rename => { "status_code" => "statuscode" } + rename => { "status_message" => "statusmsg" } + rename => { "resp_mime_types" => "rcvdmimetype" } + rename => { "resp_fuids" => "rcvdfileid" } + rename => { "response_body_len" => "rcvdbodybytes" } + rename => { "request_body_len" => "sentbodybytes" } + rename => { "uid" => "connectionid" } + rename => { "ts"=> "eventtime" } + rename => { "@timestamp"=> "eventtime" } + } } - } - if "bro_http" in [program] { - mutate{ - #add_field = { "metaclass" => "dns"} - rename => { "status_code" => "statuscode" } - rename => { "status_message" => "statusmsg" } - rename => { "resp_mime_types" => "rcvdmimetype" } - rename => { "resp_fuids" => "rcvdfileid" } - rename => { "response_body_len" => "rcvdbodybytes" } - rename => { "request_body_len" => "sentbodybytes" } - + if "bro_ssl" in [class] { + mutate{ + #add_field = { "metaclass" => "dns"} + rename => { "status_code" => "statuscode" } + rename => { "status_message" => "statusmsg" } + rename => { "resp_mime_types" => "rcvdmimetype" } + rename => { "resp_fuids" => "rcvdfileid" } + rename => { "response_body_len" => "rcvdbodybytes" } + rename => { "request_body_len" => "sentbodybytes" } + } } } } + +#output { +# if [event_type] =~ /^bro_conn|bro_dns|bro_http|bro_files|bro_ssl$/ { +# http { +# url => "https://helix-integrations.cloud.aws.apps.fireeye.com/api/upload" +# http_method => post +# http_compression => true +# socket_timeout => 60 +# headers => ["Authorization","{{ HELIX_API_KEY }}"] +# format => json_batch +# } +# } +#} output { - if "fe_clone" in [type] { - http { - url => "https://helix-integrations.cloud.aws.apps.fireeye.com/api/upload?source=test&format=json" - http_method => post - http_compression => true - headers => ["Authorization", "{{ HELIX_API_KEY }}"] - format => json_batch + if [event_type] =~ /^bro_conn|bro_dns|bro_http|bro_files|bro_ssl$/ { + file { + path => "/var/log/logstash/output.json" } } } From 7386d800ae872463153c760880a94c3ad0475edd Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 10 Dec 2019 14:06:20 -0500 Subject: [PATCH 156/200] Helix - add filebeat config for helix --- salt/filebeat/etc/filebeat.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/filebeat/etc/filebeat.yml b/salt/filebeat/etc/filebeat.yml index 63e2dff6b..0da9b68bc 100644 --- a/salt/filebeat/etc/filebeat.yml +++ b/salt/filebeat/etc/filebeat.yml @@ -66,7 +66,7 @@ filebeat.modules: # List of prospectors to fetch data. filebeat.prospectors: #------------------------------ Log prospector -------------------------------- -{%- if grains['role'] == 'so-sensor' or grains['role'] == "so-eval" %} +{%- if grains['role'] == 'so-sensor' or grains['role'] == "so-eval" or grains['role'] == "so-helix" %} {%- if BROVER != 'SURICATA' %} {%- for LOGNAME in salt['pillar.get']('brologs:enabled', '') %} - type: log From ae6fa3f4a4f11aab599032e29d248dc6292c38e0 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 10 Dec 2019 14:24:25 -0500 Subject: [PATCH 157/200] Helix - add brologs pillar --- pillar/top.sls | 1 + 1 file changed, 1 insertion(+) diff --git a/pillar/top.sls b/pillar/top.sls index 992549ffa..afdd155c6 100644 --- a/pillar/top.sls +++ b/pillar/top.sls @@ -34,3 +34,4 @@ base: - firewall.* - fireeye - static + - brologs From c83decc0a01c74ab64c46110cc40107317f52809 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 10 Dec 2019 14:44:10 -0500 Subject: [PATCH 158/200] Helix - add firewall for mode helix --- salt/firewall/init.sls | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/salt/firewall/init.sls b/salt/firewall/init.sls index f238fbf59..8a6d41f0f 100644 --- a/salt/firewall/init.sls +++ b/salt/firewall/init.sls @@ -20,7 +20,7 @@ iptables_fix_fwd: - jump: ACCEPT - position: 1 - target: DOCKER-USER - + # Keep localhost in the game iptables_allow_localhost: iptables.append: @@ -131,7 +131,7 @@ enable_wazuh_manager_1514_udp_{{ip}}: - save: True # Rules if you are a Master -{% if grains['role'] == 'so-master' or grains['role'] == 'so-eval' %} +{% if grains['role'] == 'so-master' or grains['role'] == 'so-eval' or grains['role'] == 'so-helix'%} #This should be more granular iptables_allow_master_docker: iptables.insert: @@ -264,7 +264,7 @@ enable_master_navigator_4200_{{ip}}: - dport: 4200 - position: 1 - save: True - + enable_master_cortex_9001_{{ip}}: iptables.insert: - table: filter @@ -274,7 +274,7 @@ enable_master_cortex_9001_{{ip}}: - source: {{ ip }} - dport: 9001 - position: 1 - - save: True + - save: True enable_master_cyberchef_9080_{{ip}}: iptables.insert: From 0c637b2fff1c473f6ca72dc02454b909a76d5c95 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 10 Dec 2019 16:27:29 -0500 Subject: [PATCH 159/200] Helix - Fix Group Error --- setup/functions.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/setup/functions.sh b/setup/functions.sh index 78a460054..017932834 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -785,6 +785,23 @@ process_components() { unset IFS } +reserve_group_ids() { + + # This is a hack to fix CentOS from taking group IDs that we need + groupadd -g 930 elasticsearch + groupadd -g 931 logstash + groupadd -g 932 kibana + groupadd -g 933 elastalert + groupadd -g 934 curator + groupadd -g 937 bro + groupadd -g 939 socore + groupadd -g 940 suricata + groupadd -g 941 stenographer + groupadd -g 945 ossec + groupadd -g 946 cyberchef + +} + saltify() { # Install updates and Salt @@ -792,6 +809,7 @@ saltify() { ADDUSER=adduser if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ] || [ $INSTALLTYPE == 'HELIXSENSOR' ]; then + reserve_group_ids yum -y install wget https://repo.saltstack.com/py3/redhat/salt-py3-repo-latest-2.el7.noarch.rpm cp /etc/yum.repos.d/salt-py3-latest.repo /etc/yum.repos.d/salt-py3-2019-2.repo sed -i 's/latest/2019.2/g' /etc/yum.repos.d/salt-py3-2019-2.repo From 72b481855f28cd05ced9f8f5e4734f8ef08de244 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 10 Dec 2019 16:50:23 -0500 Subject: [PATCH 160/200] Setup - add jq and fix eval calculation of failure --- salt/common/init.sls | 1 + setup/so-setup.sh | 26 ++++++-------------------- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/salt/common/init.sls b/salt/common/init.sls index 505289bc0..0004bbc7e 100644 --- a/salt/common/init.sls +++ b/salt/common/init.sls @@ -38,6 +38,7 @@ sensorpkgs: - pkgs: - docker-ce - wget + - jq {% if grains['os'] != 'CentOS' %} - python-docker - python-m2crypto diff --git a/setup/so-setup.sh b/setup/so-setup.sh index f11a2d438..f2e48314c 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -644,30 +644,16 @@ if (whiptail_you_sure) ; then salt-call state.highstate >> $SETUPLOG 2>&1 } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') - if [ $OS == 'centos' ]; then - if [[ $GOODSETUP == '1' ]]; then - whiptail_setup_complete - if [[ $THEHIVE == '1' ]]; then - check_hive_init_then_reboot - else - shutdown -r now - fi + if [[ $GOODSETUP == '0' ]]; then + whiptail_setup_complete + if [[ $THEHIVE == '1' ]]; then + check_hive_init_then_reboot else - whiptail_setup_failed shutdown -r now fi else - if [[ $GOODSETUP == '0' ]]; then - whiptail_setup_complete - if [[ $THEHIVE == '1' ]]; then - check_hive_init_then_reboot - else - shutdown -r now - fi - else - whiptail_setup_failed - shutdown -r now - fi + whiptail_setup_failed + shutdown -r now fi fi From 96bf8f66ff515cc1f3c211e34dc69cd353fb1cb8 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 10 Dec 2019 17:04:18 -0500 Subject: [PATCH 161/200] SSL - Fix helix mode ssl certs --- salt/ssl/init.sls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/ssl/init.sls b/salt/ssl/init.sls index a6be4e6e7..0dff9b855 100644 --- a/salt/ssl/init.sls +++ b/salt/ssl/init.sls @@ -41,7 +41,7 @@ m2cryptopkgs: bits: 4096 backup: True -{% if grains['role'] == 'so-master' or grains['role'] == 'so-eval' %} +{% if grains['role'] == 'so-master' or grains['role'] == 'so-eval' or grains['role'] == 'so-helix' %} # Request a cert and drop it where it needs to go to be distributed /etc/pki/filebeat.crt: From f0b2d4526814841ac1460325a1154d6039c8e51e Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 10 Dec 2019 17:27:29 -0500 Subject: [PATCH 162/200] whiptail changes for rule setup --- setup/whiptail.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/setup/whiptail.sh b/setup/whiptail.sh index dd6b9d776..434662081 100644 --- a/setup/whiptail.sh +++ b/setup/whiptail.sh @@ -567,11 +567,11 @@ whiptail_rule_setup() { # Get pulled pork info RULESETUP=$(whiptail --title "Security Onion Setup" --radiolist \ - "What IDS rules to use?:" 20 75 4 \ - "ETOPEN" "Emerging Threats Open - no oinkcode required" ON \ - "ETPRO" "Emerging Threats PRO - requires ETPRO oinkcode" OFF \ - "TALOSET" "Snort Subscriber (Talos) ruleset and Emerging Threats NoGPL ruleset - requires Snort Subscriber oinkcode" OFF \ - "TALOS" "Snort Subscriber (Talos) ruleset only and set a Snort Subscriber policy - requires Snort Subscriber oinkcode" OFF 3>&1 1>&2 2>&3 ) + "Which IDS ruleset would you like to use?\n\nThis master server is responsible for downloading the IDS ruleset from the Internet.\n\nSensors then pull a copy of this ruleset from the master server.\n\nIf you select a commercial ruleset, it is your responsibility to purchase enough licenses for all of your sensors in compliance with your vendor's policies." 20 75 4 \ + "ETOPEN" "Emerging Threats Open" "no oinkcode required" ON \ + "ETPRO" "Emerging Threats PRO" "requires ETPRO oinkcode" OFF \ + "TALOSET" "Snort Subscriber (Talos) ruleset and Emerging Threats NoGPL ruleset" "requires Snort Subscriber oinkcode" OFF \ + "TALOS" "Snort Subscriber (Talos) ruleset only and set a Snort Subscriber policy" "requires Snort Subscriber oinkcode" OFF 3>&1 1>&2 2>&3 ) local exitstatus=$? whiptail_check_exitstatus $exitstatus From 5cf527fd6e8e65bd1f8988f09a0f8b5c5e430a4c Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 10 Dec 2019 17:41:32 -0500 Subject: [PATCH 163/200] Helix - Remove rules --- setup/so-setup.sh | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/setup/so-setup.sh b/setup/so-setup.sh index f2e48314c..d4286f913 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -158,12 +158,7 @@ if (whiptail_you_sure) ; then whiptail_bond_nics whiptail_helix_apikey whiptail_homenet_master - whiptail_rule_setup - # Get the code if it isn't ET Open - if [ $RULESETUP != 'ETOPEN' ]; then - # Get the code - whiptail_oinkcode - fi + RULESETUP=ETOPEN whiptail_make_changes set_hostname clear_master From 858bb486d8467063584f209536e63ac10b97c83b Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 10 Dec 2019 20:51:44 -0500 Subject: [PATCH 164/200] change whiptail rules text --- setup/whiptail.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup/whiptail.sh b/setup/whiptail.sh index 434662081..21870bd64 100644 --- a/setup/whiptail.sh +++ b/setup/whiptail.sh @@ -568,10 +568,10 @@ whiptail_rule_setup() { # Get pulled pork info RULESETUP=$(whiptail --title "Security Onion Setup" --radiolist \ "Which IDS ruleset would you like to use?\n\nThis master server is responsible for downloading the IDS ruleset from the Internet.\n\nSensors then pull a copy of this ruleset from the master server.\n\nIf you select a commercial ruleset, it is your responsibility to purchase enough licenses for all of your sensors in compliance with your vendor's policies." 20 75 4 \ - "ETOPEN" "Emerging Threats Open" "no oinkcode required" ON \ - "ETPRO" "Emerging Threats PRO" "requires ETPRO oinkcode" OFF \ - "TALOSET" "Snort Subscriber (Talos) ruleset and Emerging Threats NoGPL ruleset" "requires Snort Subscriber oinkcode" OFF \ - "TALOS" "Snort Subscriber (Talos) ruleset only and set a Snort Subscriber policy" "requires Snort Subscriber oinkcode" OFF 3>&1 1>&2 2>&3 ) + "ETOPEN" "Emerging Threats Open" ON \ + "ETPRO" "Emerging Threats PRO" OFF \ + "TALOSET" "Snort Subscriber (Talos) and ET NoGPL rulesets" OFF \ + "TALOS" "Snort Subscriber (Talos) ruleset and set a policy" OFF \ local exitstatus=$? whiptail_check_exitstatus $exitstatus From e52f46991567c7e6600e95887355fb7762d92f84 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 10 Dec 2019 20:55:03 -0500 Subject: [PATCH 165/200] Setup - Fix rules lingo --- setup/whiptail.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/setup/whiptail.sh b/setup/whiptail.sh index 21870bd64..123970bd5 100644 --- a/setup/whiptail.sh +++ b/setup/whiptail.sh @@ -572,6 +572,7 @@ whiptail_rule_setup() { "ETPRO" "Emerging Threats PRO" OFF \ "TALOSET" "Snort Subscriber (Talos) and ET NoGPL rulesets" OFF \ "TALOS" "Snort Subscriber (Talos) ruleset and set a policy" OFF \ + 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus From 989641eb5a2bbf5d9feba0fc23961eeacb3ffac9 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Wed, 11 Dec 2019 13:44:40 -0500 Subject: [PATCH 166/200] Setup - Fix prompts and disable onion user if iso --- salt/common/init.sls | 4 +- .../files/dynamic/9997_output_helix.conf | 53 +++++++++++-------- setup/so-setup.sh | 49 ++++++++++++++--- 3 files changed, 75 insertions(+), 31 deletions(-) diff --git a/salt/common/init.sls b/salt/common/init.sls index 0004bbc7e..3cd4dce19 100644 --- a/salt/common/init.sls +++ b/salt/common/init.sls @@ -117,13 +117,13 @@ nginxtmp: # Start the core docker so-coreimage: cmd.run: - - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-core:HH1.1.2 + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-core:HH1.1.3 so-core: docker_container.running: - require: - so-coreimage - - image: docker.io/soshybridhunter/so-core:HH1.1.2 + - image: docker.io/soshybridhunter/so-core:HH1.1.3 - hostname: so-core - user: socore - binds: diff --git a/salt/logstash/files/dynamic/9997_output_helix.conf b/salt/logstash/files/dynamic/9997_output_helix.conf index 6168bfb07..320648de5 100644 --- a/salt/logstash/files/dynamic/9997_output_helix.conf +++ b/salt/logstash/files/dynamic/9997_output_helix.conf @@ -1,7 +1,7 @@ {% set HELIX_API_KEY = salt['pillar.get']('fireeye:helix:api_key', '') %} filter { - if [type] =~ /^bro_conn|bro_dns|bro_http|bro_files|bro_ssl$/ { + if [type] =~ /^bro_conn|bro_dns|bro_http|bro_files|bro_ssl|bro_dhcp|bro_x509$/ { grok { match => [ "source_ip", "^%{IPV4:srcipv4}$", @@ -72,7 +72,8 @@ filter { if "bro_dhcp" in [class] { mutate{ #add_field = { "metaclass" => "dhcp"} - rename => { "ips" => "ip" } + rename => { "message_types" => "direction" } + rename => { "lease_time" => "duration" } } } if "bro_files" in [class] { @@ -109,25 +110,35 @@ filter { rename => { "request_body_len" => "sentbodybytes" } } } - } -} - -#output { -# if [event_type] =~ /^bro_conn|bro_dns|bro_http|bro_files|bro_ssl$/ { -# http { -# url => "https://helix-integrations.cloud.aws.apps.fireeye.com/api/upload" -# http_method => post -# http_compression => true -# socket_timeout => 60 -# headers => ["Authorization","{{ HELIX_API_KEY }}"] -# format => json_batch -# } -# } -#} -output { - if [event_type] =~ /^bro_conn|bro_dns|bro_http|bro_files|bro_ssl$/ { - file { - path => "/var/log/logstash/output.json" + if "bro_weird" in [class] { + mutate{ + #add_field = { "metaclass" => "dns"} + rename => { "name" => "eventname" } + } + } + if "bro_x509" in [class] { + mutate{ + #add_field = { "metaclass" => "dns"} + rename => { "certificate_common_name" => "certname" } + rename => { "certificate_subject" => "certsubject" } + rename => { "issuer_common_name" => "issuer" } + reanme => { "certificate_issuer" => "issuersubject" } + rename => { "certificate_not_valid_before" => "issuetime" } + rename => { "certificate_key_type" => "cert_type" } + } + } + } +} + +output { + if [event_type] =~ /^bro_conn|bro_dns|bro_http|bro_files|bro_ssl|bro_dhcp|bro_x509$/ { + http { + url => "https://helix-integrations.cloud.aws.apps.fireeye.com/api/upload" + http_method => post + http_compression => true + socket_timeout => 60 + headers => ["Authorization","{{ HELIX_API_KEY }}"] + format => json_batch } } } diff --git a/setup/so-setup.sh b/setup/so-setup.sh index d4286f913..b5a06dfe4 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -71,13 +71,13 @@ if (whiptail_you_sure) ; then # Set management nic whiptail_management_nic - whiptail_create_socore_user - SCMATCH=no - while [ $SCMATCH != yes ]; do - whiptail_create_socore_user_password1 - whiptail_create_socore_user_password2 - check_socore_pass - done +# whiptail_create_socore_user +# SCMATCH=no +# while [ $SCMATCH != yes ]; do +# whiptail_create_socore_user_password1 +# whiptail_create_socore_user_password2 +# check_socore_pass +# done else @@ -166,7 +166,10 @@ if (whiptail_you_sure) ; then get_filesystem_root get_filesystem_nsm get_main_ip - add_socore_user_master + if [ $INSTALLMETHOD == iso ]; then + disable_onion_user + fi + #add_socore_user_master # Install salt and dependencies { sleep 0.5 @@ -285,6 +288,15 @@ if (whiptail_you_sure) ; then fi fi + # Get a password for the socore user + whiptail_create_socore_user + SCMATCH=no + while [ $SCMATCH != yes ]; do + whiptail_create_socore_user_password1 + whiptail_create_socore_user_password2 + check_socore_pass + done + # Last Chance to back out whiptail_make_changes set_hostname @@ -300,6 +312,9 @@ if (whiptail_you_sure) ; then # Figure out the main IP address get_main_ip + if [ $INSTALLMETHOD == iso ]; then + disable_onion_user + fi # Add the user so we can sit back and relax #echo "" @@ -441,6 +456,9 @@ if (whiptail_you_sure) ; then mkdir -p /nsm get_filesystem_root get_filesystem_nsm + if [ $INSTALLMETHOD == iso ]; then + disable_onion_user + fi copy_ssh_key >> $SETUPLOG 2>&1 { sleep 0.5 @@ -525,6 +543,15 @@ if (whiptail_you_sure) ; then BROVERSION=ZEEK CURCLOSEDAYS=30 process_components + # Get a password for the socore user + whiptail_create_socore_user + SCMATCH=no + while [ $SCMATCH != yes ]; do + whiptail_create_socore_user_password1 + whiptail_create_socore_user_password2 + check_socore_pass + done + whiptail_make_changes set_hostname generate_passwords @@ -535,6 +562,9 @@ if (whiptail_you_sure) ; then get_filesystem_nsm get_log_size_limit get_main_ip + if [ $INSTALLMETHOD == iso ]; then + disable_onion_user + fi # Add the user so we can sit back and relax add_socore_user_master { @@ -688,6 +718,9 @@ if (whiptail_you_sure) ; then mkdir -p /nsm get_filesystem_root get_filesystem_nsm + if [ $INSTALLMETHOD == iso ]; then + disable_onion_user + fi copy_ssh_key >> $SETUPLOG 2>&1 { sleep 0.5 From dd74c224dff7c56c9d1f980b7d1f397c68ccbeed Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Wed, 11 Dec 2019 13:49:31 -0500 Subject: [PATCH 167/200] Setup - get rid of setting pw in eval --- setup/so-setup.sh | 9 --------- 1 file changed, 9 deletions(-) diff --git a/setup/so-setup.sh b/setup/so-setup.sh index b5a06dfe4..3570fc940 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -543,15 +543,6 @@ if (whiptail_you_sure) ; then BROVERSION=ZEEK CURCLOSEDAYS=30 process_components - # Get a password for the socore user - whiptail_create_socore_user - SCMATCH=no - while [ $SCMATCH != yes ]; do - whiptail_create_socore_user_password1 - whiptail_create_socore_user_password2 - check_socore_pass - done - whiptail_make_changes set_hostname generate_passwords From c47d163a3262e135eba3d78f6fbda0127a1b1ace Mon Sep 17 00:00:00 2001 From: Wes Lambert Date: Wed, 11 Dec 2019 19:39:03 +0000 Subject: [PATCH 168/200] add initial tcpreplay state --- salt/tcpreplay/init.sls | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 salt/tcpreplay/init.sls diff --git a/salt/tcpreplay/init.sls b/salt/tcpreplay/init.sls new file mode 100644 index 000000000..a6cc62c32 --- /dev/null +++ b/salt/tcpreplay/init.sls @@ -0,0 +1,18 @@ +{% if grains['role'] == 'so-sensor' or grains['role'] == 'so-eval' %} + +so-tcpreplayimage: + cmd.run: + - name: docker pull --disable-content-trust=false docker.io/soshybridhunter/so-tcpreplay:HH1.1.4 + +so-tcpreplay: + docker_container.running: + - require: + - so-tcpreplay + - network_mode: "host" + - image: docker.io/soshybridhunter/so-tcpreplay:HH1.1.4 + - name: so-tcpreplay + - user: root + - interactive: True + - tty: True + +{% endif %} From 549358c0eaf89a497794937686d39bd0b044eee4 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Wed, 11 Dec 2019 17:08:23 -0500 Subject: [PATCH 169/200] Setup - add dhcp or static for iso install --- setup/whiptail.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/setup/whiptail.sh b/setup/whiptail.sh index 123970bd5..4992e20d4 100644 --- a/setup/whiptail.sh +++ b/setup/whiptail.sh @@ -141,6 +141,18 @@ whiptail_cur_close_days() { whiptail_check_exitstatus $exitstatus } + +whiptail_dhcp_or_static() { + + ADDRESSTYPE=$(whiptail --title "Security Onion Setup" --radiolist \ + "Choose how to set up your management interface:" 20 78 4 \ + "STATIC" "Set a static IPv4 address" ON \ + "DHCP" "Use DHCP to configure the Management Interface" OFF 3>&1 1>&2 2>&3 ) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus +} + whiptail_enable_components() { COMPONENTS=$(whiptail --title "Security Onion Setup" --checklist \ "Select Components to install" 20 75 8 \ From e4c8786e36605b83d7813bc3eeeb3778743e3d27 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 12 Dec 2019 09:07:32 -0500 Subject: [PATCH 170/200] Setup - fix missing whiptail for iso --- setup/whiptail.sh | 60 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/setup/whiptail.sh b/setup/whiptail.sh index 4992e20d4..6b095859d 100644 --- a/setup/whiptail.sh +++ b/setup/whiptail.sh @@ -106,6 +106,32 @@ whiptail_check_exitstatus() { } +whiptail_create_admin_user() { + + ADMINUSER=$(whiptail --title "Security Onion Install" --inputbox \ + "Please enter a username for your new admin user" 10 60 3>&1 1>&2 2>&3) + +} + +whiptail_create_admin_user_password1() { + + ADMINPASS1=$(whiptail --title "Security Onion Install" --passwordbox \ + "Enter a password for $ADMINUSER" 10 60 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus +} + +whiptail_create_admin_user_password2() { + + ADMINPASS2=$(whiptail --title "Security Onion Install" --passwordbox \ + "Re-enter a password for $ADMINUSER" 10 60 3>&1 1>&2 2>&3) + + local exitstatus=$? + whiptail_check_exitstatus $exitstatus + +} + whiptail_create_socore_user() { whiptail --title "Security Onion Setup" --msgbox "Set a password for the socore user. This account is used for adding sensors remotely." 8 75 @@ -251,6 +277,40 @@ whiptail_log_size_limit() { } +whiptail_management_interface_dns() { + + MDNS=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter your DNS server using space between multiple" 10 60 8.8.8.8 8.8.4.4 3>&1 1>&2 2>&3) + +} + +whiptail_management_interface_dns_search() { + + MSEARCH=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter your DNS search domain" 10 60 searchdomain.local 3>&1 1>&2 2>&3) + +} + +whiptail_management_interface_gateway() { + + MGATEWAY=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter your gateway" 10 60 X.X.X.X 3>&1 1>&2 2>&3) + +} + +whiptail_management_interface_ip() { + + MIP=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter your IP address" 10 60 X.X.X.X 3>&1 1>&2 2>&3) + +} + +whiptail_management_interface_mask() { + + MMASK=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter the bit mask for your subnet" 10 60 24 3>&1 1>&2 2>&3) + +} whiptail_management_nic() { From 6eab27f1de6fcec285c83546a1399343e0cf94c7 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 12 Dec 2019 09:19:05 -0500 Subject: [PATCH 171/200] Setup - fix iso hostname --- setup/functions.sh | 9 +++++++++ setup/so-setup.sh | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/setup/functions.sh b/setup/functions.sh index 017932834..ef8409df1 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -1171,6 +1171,15 @@ set_hostname() { } +set_hostname_iso() { + + hostnamectl set-hostname --static $HOSTNAME + echo "127.0.0.1 $HOSTNAME $HOSTNAME.localdomain localhost localhost.localdomain localhost4 localhost4.localdomain" > /etc/hosts + echo "::1 localhost localhost.localdomain localhost6 localhost6.localdomain6" >> /etc/hosts + echo $HOSTNAME > /etc/hostname + +} + set_initial_firewall_policy() { get_main_ip diff --git a/setup/so-setup.sh b/setup/so-setup.sh index 3570fc940..57f75c015 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -98,7 +98,7 @@ if (whiptail_you_sure) ; then fi # Go ahead and bring up networking so other parts of the install work - set_hostname + set_hostname_iso set_management_interface # Add an admin user From 1deb520a56a513750d408cad996285e5820fb066 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 12 Dec 2019 11:02:18 -0500 Subject: [PATCH 172/200] remove pip3 installing m2crypto --- setup/functions.sh | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/setup/functions.sh b/setup/functions.sh index 017932834..de3044a27 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -573,13 +573,8 @@ install_master() { #wget --inet4-only -O /opt/so/gpg/GPG-KEY-WAZUH https://packages.wazuh.com/key/GPG-KEY-WAZUH else - apt-get install -y salt-common=2019.2.2+ds-1 salt-master=2019.2.2+ds-1 salt-minion=2019.2.2+ds-1 + apt-get install -y salt-common=2019.2.2+ds-1 salt-master=2019.2.2+ds-1 salt-minion=2019.2.2+ds-1 libssl-dev python-m2crypto apt-mark hold salt-common salt-master salt-minion - echo -e "XXX\n11\nInstalling libssl-dev for M2Crypto... \nXXX" - apt-get -y install libssl-dev - echo -e "XXX\n12\nUsing pip3 to install M2Crypto for Salt... \nXXX" - pip3 install M2Crypto - fi copy_master_config From b8ea1f041ac70222f768e331250d5d14a38146c8 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 12 Dec 2019 13:08:07 -0500 Subject: [PATCH 173/200] Setup - add admin user iso --- setup/so-setup.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/setup/so-setup.sh b/setup/so-setup.sh index 57f75c015..1d364d948 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -167,6 +167,7 @@ if (whiptail_you_sure) ; then get_filesystem_nsm get_main_ip if [ $INSTALLMETHOD == iso ]; then + add_admin_user disable_onion_user fi #add_socore_user_master @@ -313,6 +314,7 @@ if (whiptail_you_sure) ; then # Figure out the main IP address get_main_ip if [ $INSTALLMETHOD == iso ]; then + add_admin_user disable_onion_user fi @@ -457,6 +459,7 @@ if (whiptail_you_sure) ; then get_filesystem_root get_filesystem_nsm if [ $INSTALLMETHOD == iso ]; then + add_admin_user disable_onion_user fi copy_ssh_key >> $SETUPLOG 2>&1 @@ -554,6 +557,7 @@ if (whiptail_you_sure) ; then get_log_size_limit get_main_ip if [ $INSTALLMETHOD == iso ]; then + add_admin_user disable_onion_user fi # Add the user so we can sit back and relax @@ -710,6 +714,7 @@ if (whiptail_you_sure) ; then get_filesystem_root get_filesystem_nsm if [ $INSTALLMETHOD == iso ]; then + add_admin_user disable_onion_user fi copy_ssh_key >> $SETUPLOG 2>&1 From bd9b1957bacea8814d79127da53cada03d8dfaf1 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 12 Dec 2019 14:12:51 -0500 Subject: [PATCH 174/200] Logstash - Fix helix output --- salt/logstash/files/dynamic/9997_output_helix.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/logstash/files/dynamic/9997_output_helix.conf b/salt/logstash/files/dynamic/9997_output_helix.conf index 320648de5..9a30abf19 100644 --- a/salt/logstash/files/dynamic/9997_output_helix.conf +++ b/salt/logstash/files/dynamic/9997_output_helix.conf @@ -131,7 +131,7 @@ filter { } output { - if [event_type] =~ /^bro_conn|bro_dns|bro_http|bro_files|bro_ssl|bro_dhcp|bro_x509$/ { + if [type] =~ /^bro_conn|bro_dns|bro_http|bro_files|bro_ssl|bro_dhcp|bro_x509$/ { http { url => "https://helix-integrations.cloud.aws.apps.fireeye.com/api/upload" http_method => post From 79d48f9e77adec9409432cb05fc59c846d7bb53d Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 12 Dec 2019 15:17:19 -0500 Subject: [PATCH 175/200] Logstash - Fix helix output typeo --- salt/logstash/files/dynamic/9997_output_helix.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/logstash/files/dynamic/9997_output_helix.conf b/salt/logstash/files/dynamic/9997_output_helix.conf index 9a30abf19..8c01eab65 100644 --- a/salt/logstash/files/dynamic/9997_output_helix.conf +++ b/salt/logstash/files/dynamic/9997_output_helix.conf @@ -122,7 +122,7 @@ filter { rename => { "certificate_common_name" => "certname" } rename => { "certificate_subject" => "certsubject" } rename => { "issuer_common_name" => "issuer" } - reanme => { "certificate_issuer" => "issuersubject" } + rename => { "certificate_issuer" => "issuersubject" } rename => { "certificate_not_valid_before" => "issuetime" } rename => { "certificate_key_type" => "cert_type" } } From cab0fb369fbc5b4f16c47c500976ff6f953c44b2 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 12 Dec 2019 15:44:13 -0500 Subject: [PATCH 176/200] Copying Helps with -R --- setup/functions.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup/functions.sh b/setup/functions.sh index f88b6eef9..c90a15b23 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -1078,8 +1078,8 @@ salt_master_directories() { # Copy over the salt code and templates if [ $INSTALLMETHOD == 'iso' ]; then - cp /root/SecurityOnion/pillar/* /opt/so/saltstack/pillar/ - cp /root/SecurityOnion/salt/* /opt/so/saltstack/salt/ + cp -R /root/SecurityOnion/pillar/* /opt/so/saltstack/pillar/ + cp -R /root/SecurityOnion/salt/* /opt/so/saltstack/salt/ else cp -R $SCRIPTDIR/../pillar/* /opt/so/saltstack/pillar/ cp -R $SCRIPTDIR/../salt/* /opt/so/saltstack/salt/ From 1d5a4a564b12733b4b3b60724fb2197d0aa4ddc6 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 12 Dec 2019 16:15:49 -0500 Subject: [PATCH 177/200] Setup - Remove extra socore add --- setup/so-setup.sh | 9 --------- 1 file changed, 9 deletions(-) diff --git a/setup/so-setup.sh b/setup/so-setup.sh index 1d364d948..42e539c98 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -112,15 +112,6 @@ if (whiptail_you_sure) ; then check_admin_pass done - # Get a password for the socore user - whiptail_create_socore_user - SCMATCH=no - while [ $SCMATCH != yes ]; do - whiptail_create_socore_user_password1 - whiptail_create_socore_user_password2 - check_socore_pass - done - fi # Go ahead and gen the keys so we can use them for any sensor type - Disabled for now From 481d52a5a838fa4204c9fe397954d7ddcf25a45c Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 12 Dec 2019 16:21:57 -0500 Subject: [PATCH 178/200] reverting for https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/111 --- salt/common/init.sls | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/salt/common/init.sls b/salt/common/init.sls index 3cd4dce19..3a8d569b9 100644 --- a/salt/common/init.sls +++ b/salt/common/init.sls @@ -1,4 +1,3 @@ -{%- set GRAFANA = salt['pillar.get']('master:grafana', '0') %} # Add socore Group socoregroup: group.present: @@ -143,7 +142,7 @@ so-core: - file: /opt/so/conf/nginx/nginx.conf # If master or eval, install Grafana/Telegraf/Influx -{% if grains['role'] == 'so-master' or grains['role'] == 'so-eval' and GRAFANA == 1 %} +{% if grains['role'] == 'so-master' or grains['role'] == 'so-eval' %} # Add Telegraf to monitor all the things. tgraflogdir: file.directory: From 3ec642963169a473d13b9eac7f20365014a8a5e3 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 12 Dec 2019 16:29:41 -0500 Subject: [PATCH 179/200] Setup - setterm so iso doesn't blank out --- setup/so-setup.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/setup/so-setup.sh b/setup/so-setup.sh index 42e539c98..219ec589d 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -60,6 +60,7 @@ if (whiptail_you_sure) ; then # Create a temp dir to get started install_prep + setterm -blank 0 if [ $INSTALLMETHOD == network ]; then # Let folks know they need their management interface already set up. From cc7de9aee27c0862c912940003549be642f9a9ff Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 12 Dec 2019 16:36:22 -0500 Subject: [PATCH 180/200] reverting for https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/111 --- salt/common/init.sls | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/salt/common/init.sls b/salt/common/init.sls index 3a8d569b9..83ae31a9d 100644 --- a/salt/common/init.sls +++ b/salt/common/init.sls @@ -1,3 +1,4 @@ +{%- set GRAFANA = salt['pillar.get']('master:grafana', '0') %} # Add socore Group socoregroup: group.present: @@ -215,6 +216,9 @@ so-telegraf: - /opt/so/conf/telegraf/etc/telegraf.conf - /opt/so/conf/telegraf/scripts +# If its a master or eval lets install the back end for now +{% if grains['role'] == 'so-master' or grains['role'] == 'so-eval' and GRAFANA == 1 %} + # Influx DB influxconfdir: file.directory: From 349d8f4bd761310a4393aea777e4867f49656ffb Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 12 Dec 2019 16:40:24 -0500 Subject: [PATCH 181/200] reverting for https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/111 --- salt/common/init.sls | 2 -- 1 file changed, 2 deletions(-) diff --git a/salt/common/init.sls b/salt/common/init.sls index 83ae31a9d..e34431a46 100644 --- a/salt/common/init.sls +++ b/salt/common/init.sls @@ -142,8 +142,6 @@ so-core: - watch: - file: /opt/so/conf/nginx/nginx.conf -# If master or eval, install Grafana/Telegraf/Influx -{% if grains['role'] == 'so-master' or grains['role'] == 'so-eval' %} # Add Telegraf to monitor all the things. tgraflogdir: file.directory: From ed6ca5a3a99c6b54344ba367238412fe29855be7 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 12 Dec 2019 16:45:19 -0500 Subject: [PATCH 182/200] Setup - copy from the onion home dir vs root --- setup/functions.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup/functions.sh b/setup/functions.sh index c90a15b23..e2d993aed 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -1078,8 +1078,8 @@ salt_master_directories() { # Copy over the salt code and templates if [ $INSTALLMETHOD == 'iso' ]; then - cp -R /root/SecurityOnion/pillar/* /opt/so/saltstack/pillar/ - cp -R /root/SecurityOnion/salt/* /opt/so/saltstack/salt/ + cp -R /home/onion/SecurityOnion/pillar/* /opt/so/saltstack/pillar/ + cp -R /home/onion/SecurityOnion/salt/* /opt/so/saltstack/salt/ else cp -R $SCRIPTDIR/../pillar/* /opt/so/saltstack/pillar/ cp -R $SCRIPTDIR/../salt/* /opt/so/saltstack/salt/ From 897cf5704209aa38c328637c2cc4a61b7b41895d Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 12 Dec 2019 20:00:35 -0500 Subject: [PATCH 183/200] Setup - Fix Hostname Race Condition --- setup/so-setup.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup/so-setup.sh b/setup/so-setup.sh index 219ec589d..f4a87aec1 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -153,6 +153,8 @@ if (whiptail_you_sure) ; then RULESETUP=ETOPEN whiptail_make_changes set_hostname + HOSTNAME=$(cat /etc/hostname) + MINION_ID=$(echo $HOSTNAME | awk -F. {'print $1'}) clear_master mkdir -p /nsm get_filesystem_root From d8d94b7dc51f31eec21cb67ee8f3156dad14a39a Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 12 Dec 2019 20:46:30 -0500 Subject: [PATCH 184/200] Helix - Add API Key Option --- salt/common/tools/sbin/so-helix-apikey | 23 +++++++++++++++++++++++ setup/whiptail.sh | 4 ++-- 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 salt/common/tools/sbin/so-helix-apikey diff --git a/salt/common/tools/sbin/so-helix-apikey b/salt/common/tools/sbin/so-helix-apikey new file mode 100644 index 000000000..58894f3ab --- /dev/null +++ b/salt/common/tools/sbin/so-helix-apikey @@ -0,0 +1,23 @@ +#!/bin/bash +got_root() { + + # Make sure you are root + if [ "$(id -u)" -ne 0 ]; then + echo "This script must be run using sudo!" + exit 1 + fi + +} + +got_root +if [ ! -f /opt/so/saltstack/pillar/fireeye/init.sls ]; then + echo "This is nto configured for Helix Mode. Please re-install." + exit +else + echo "Enter your Helix API Key: " + read APIKEY + sed -i 's/^ apikey.*/ apikey: $APIKEY/' /opt/so/saltstack/pillar/fireeye/init.sls + docker stop so-logstash + docker rm so-logstash + salt-call state.apply logstash queue=True +fi diff --git a/setup/whiptail.sh b/setup/whiptail.sh index 6b095859d..8497635c5 100644 --- a/setup/whiptail.sh +++ b/setup/whiptail.sh @@ -47,7 +47,7 @@ whiptail_bro_pins() { whiptail_bro_version() { BROVERSION=$(whiptail --title "Security Onion Setup" --radiolist "What tool would you like to use to generate meta data?" 20 75 4 "ZEEK" "Install Zeek (aka Bro)" ON \ - "COMMUNITY" "Install Community NSM" OFF "SURICATA" "SUPER EXPERIMENTAL" OFF 3>&1 1>&2 2>&3) + "SURICATA" "SUPER EXPERIMENTAL" OFF 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -209,7 +209,7 @@ whiptail_eval_adv_warning() { whiptail_helix_apikey() { HELIXAPIKEY=$(whiptail --title "Security Onion Setup" --inputbox \ - "Enter your Helix API Key" 10 75 3>&1 1>&2 2>&3) + "Enter your Helix API Key: \n \nThis can be set later using so-helix-apikey" 10 75 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus From 3b4e371505fd2278803638f40b678a5a8abc1997 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 12 Dec 2019 21:10:41 -0500 Subject: [PATCH 185/200] Setup - Remove rsync --- setup/functions.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup/functions.sh b/setup/functions.sh index e2d993aed..6f68b0428 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -269,10 +269,10 @@ copy_master_config() { copy_minion_tmp_files() { if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ] || [ $INSTALLTYPE == 'HELIXSENSOR' ]; then - echo "rsyncing pillar and salt files in $TMP to /opt/so/saltstack" - rsync -a -v $TMP/pillar/ /opt/so/saltstack/pillar/ >> $SETUPLOG 2>&1 + echo "Copying pillar and salt files in $TMP to /opt/so/saltstack" + cp -Rv $TMP/pillar/ /opt/so/saltstack/pillar/ >> $SETUPLOG 2>&1 if [ -d $TMP/salt ] ; then - rsync -a -v $TMP/salt/ /opt/so/saltstack/salt/ >> $SETUPLOG 2>&1 + cp -Rv $TMP/salt/ /opt/so/saltstack/salt/ >> $SETUPLOG 2>&1 fi else echo "scp pillar and salt files in $TMP to master /opt/so/saltstack" From 9b1f5abc22e61c84521ba3fe76113ab161568128 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 12 Dec 2019 21:12:20 -0500 Subject: [PATCH 186/200] Setup - Fix HOSTNAME race condition --- setup/functions.sh | 2 ++ setup/so-setup.sh | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setup/functions.sh b/setup/functions.sh index 6f68b0428..5303c5fbc 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -1156,6 +1156,8 @@ set_hostname() { echo "127.0.0.1 $HOSTNAME $HOSTNAME.localdomain localhost localhost.localdomain localhost4 localhost4.localdomain" > /etc/hosts echo "::1 localhost localhost.localdomain localhost6 localhost6.localdomain6" >> /etc/hosts echo $HOSTNAME > /etc/hostname + HOSTNAME=$(cat /etc/hostname) + MINION_ID=$(echo $HOSTNAME | awk -F. {'print $1'}) if [ $INSTALLTYPE != 'MASTERONLY' ] || [ $INSTALLTYPE != 'EVALMODE' ] || [ $INSTALLTYPE == 'HELIXSENSOR' ]; then if [[ $TESTHOST = *"not found"* ]] || [[ $TESTHOST = *"connection timed out"* ]]; then if ! grep -q $MSRVIP /etc/hosts; then diff --git a/setup/so-setup.sh b/setup/so-setup.sh index f4a87aec1..219ec589d 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -153,8 +153,6 @@ if (whiptail_you_sure) ; then RULESETUP=ETOPEN whiptail_make_changes set_hostname - HOSTNAME=$(cat /etc/hostname) - MINION_ID=$(echo $HOSTNAME | awk -F. {'print $1'}) clear_master mkdir -p /nsm get_filesystem_root From 6095f0ed9d338267e666296e09b21e45a76f7820 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 12 Dec 2019 22:11:08 -0500 Subject: [PATCH 187/200] Setup - Fix paths so checksum will disable --- setup/functions.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup/functions.sh b/setup/functions.sh index 5303c5fbc..ac678cb9f 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -483,7 +483,7 @@ filter_unused_nics() { fireeye_pillar() { - FIREEYEPILLARPATH=$TMP/pillar/fireeye + FIREEYEPILLARPATH=/opt/so/saltstack/pillar/fireeye mkdir -p $FIREEYEPILLARPATH echo "" >> $FIREEYEPILLARPATH/init.sls @@ -683,7 +683,7 @@ network_setup() { nmcli con mod $MAININT connection.autoconnect "yes" >> $SETUPLOG 2>&1 echo "... Copying disable-checksum-offload.sh" >> $SETUPLOG 2>&1 - cp ../install_scripts/disable-checksum-offload.sh /etc/NetworkManager/dispatcher.d/disable-checksum-offload.sh >> $SETUPLOG 2>&1 + cp $SCRIPTDIR/install_scripts/disable-checksum-offload.sh /etc/NetworkManager/dispatcher.d/disable-checksum-offload.sh >> $SETUPLOG 2>&1 echo "... Modifying disable-checksum-offload.sh" >> $SETUPLOG 2>&1 sed -i "s/\$MAININT/${MAININT}/g" /etc/NetworkManager/dispatcher.d/disable-checksum-offload.sh >> $SETUPLOG 2>&1 From 222ea74bbbfe21ef67431565ec39f0d9bd068879 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 12 Dec 2019 22:51:09 -0500 Subject: [PATCH 188/200] Setup - Fix paths so checksum will disable for real --- .../install_scripts}/disable-checksum-offload.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {install_scripts => setup/install_scripts}/disable-checksum-offload.sh (100%) diff --git a/install_scripts/disable-checksum-offload.sh b/setup/install_scripts/disable-checksum-offload.sh similarity index 100% rename from install_scripts/disable-checksum-offload.sh rename to setup/install_scripts/disable-checksum-offload.sh From 4c89cb50bbc45911f9a57adfb3f9e180e4a0c251 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 12 Dec 2019 23:12:08 -0500 Subject: [PATCH 189/200] Setup - update Helix Script --- salt/common/tools/sbin/so-helix-apikey | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/salt/common/tools/sbin/so-helix-apikey b/salt/common/tools/sbin/so-helix-apikey index 58894f3ab..529ab93e4 100644 --- a/salt/common/tools/sbin/so-helix-apikey +++ b/salt/common/tools/sbin/so-helix-apikey @@ -16,8 +16,9 @@ if [ ! -f /opt/so/saltstack/pillar/fireeye/init.sls ]; then else echo "Enter your Helix API Key: " read APIKEY - sed -i 's/^ apikey.*/ apikey: $APIKEY/' /opt/so/saltstack/pillar/fireeye/init.sls + sed -i "s/^ api_key.*/ api_key: $APIKEY/g" /opt/so/saltstack/pillar/fireeye/init.sls docker stop so-logstash docker rm so-logstash + echo "Restarting Logstash for updated key" salt-call state.apply logstash queue=True fi From 30023ae725a8bbdc5fc159e48302cf964786b41e Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Fri, 13 Dec 2019 10:06:49 -0500 Subject: [PATCH 190/200] Setup - Add sensor pillar to Helix --- pillar/top.sls | 1 + setup/functions.sh | 3 +++ setup/so-setup.sh | 2 ++ 3 files changed, 6 insertions(+) diff --git a/pillar/top.sls b/pillar/top.sls index afdd155c6..17bf33e02 100644 --- a/pillar/top.sls +++ b/pillar/top.sls @@ -30,6 +30,7 @@ base: 'G@role:so-helix': - masters.{{ grains.id }} + - sensors.{{ grains.id }} - static - firewall.* - fireeye diff --git a/setup/functions.sh b/setup/functions.sh index ac678cb9f..910be0437 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -1124,6 +1124,9 @@ sensor_pillar() { SPIN=$(echo $SPIN | cut -d\" -f2) echo " - $SPIN" >> $SENSORPILLARPATH/$MINION_ID.sls done + elif [ $INSTALLTYPE == 'HELIXSENSOR' ]; then + echo " bro_lbprocs: $LBPROCS" >> $SENSORPILLARPATH/$MINION_ID.sls + echo " suriprocs: $LBPROCS" >> $SENSORPILLARPATH/$MINION_ID.sls else echo " bro_lbprocs: $BASICBRO" >> $SENSORPILLARPATH/$MINION_ID.sls echo " suriprocs: $BASICSURI" >> $SENSORPILLARPATH/$MINION_ID.sls diff --git a/setup/so-setup.sh b/setup/so-setup.sh index 219ec589d..a53e24aaf 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -151,6 +151,7 @@ if (whiptail_you_sure) ; then whiptail_helix_apikey whiptail_homenet_master RULESETUP=ETOPEN + calculate_useable_cores whiptail_make_changes set_hostname clear_master @@ -193,6 +194,7 @@ if (whiptail_you_sure) ; then patch_pillar >> $SETUPLOG 2>&1 echo "** Generating the FireEye pillar **" >> $SETUPLOG fireeye_pillar >> $SETUPLOG 2>&1 + sensor_pillar >> $SETUPLOG 2>&1 echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" copy_minion_tmp_files >> $SETUPLOG 2>&1 # Do a checkin to push the key up From b61d0222541e05e4d256cd11b6d7282cbfcd5631 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Fri, 13 Dec 2019 10:56:55 -0500 Subject: [PATCH 191/200] Setup - Add sensor pillar to Helix --- setup/so-setup.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup/so-setup.sh b/setup/so-setup.sh index a53e24aaf..c35e9e7aa 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -151,6 +151,8 @@ if (whiptail_you_sure) ; then whiptail_helix_apikey whiptail_homenet_master RULESETUP=ETOPEN + NSMSETUP=BASIC + HNSENSOR=inherit calculate_useable_cores whiptail_make_changes set_hostname From e263d72813bab7183763630d6c26a3e6213962e7 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Fri, 13 Dec 2019 11:46:30 -0500 Subject: [PATCH 192/200] Setup - Add sensor pillar to Helix --- salt/logstash/files/dynamic/9997_output_helix.conf | 8 ++------ setup/functions.sh | 7 +++++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/salt/logstash/files/dynamic/9997_output_helix.conf b/salt/logstash/files/dynamic/9997_output_helix.conf index 8c01eab65..14cca8352 100644 --- a/salt/logstash/files/dynamic/9997_output_helix.conf +++ b/salt/logstash/files/dynamic/9997_output_helix.conf @@ -15,10 +15,6 @@ filter { ] } - grok { - match => [ "syslog-tags", "^.source.s_%{DATA:class}$" ] - } - geoip { source => "[source_ip]" target => "source_geo" @@ -30,10 +26,10 @@ filter { mutate { #rename => { "%{[source_geo][country_code]}" => "srccountrycode" } #rename => { "%{[destination_geo][country_code]}" => "dstcountrycode" } - rename => { "syslog-host_from" => "sensor" } + rename => { "[beat_host][name]" => "sensor" } rename => { "message" => "rawmsg" } #rename => { "event_type" => "program" } - #copy => { "program" => "class" } + copy => { "type" => "class" } rename => { "source_port" => "srcport" } rename => { "destination_port" => "dstport" } remove_field => ["source_ip", "destination_ip"] diff --git a/setup/functions.sh b/setup/functions.sh index 910be0437..87d8bdce4 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -1101,8 +1101,11 @@ salt_install_mysql_deps() { } sensor_pillar() { - - SENSORPILLARPATH=$TMP/pillar/sensors + if [ $INSTALLTYPE == 'HELIXSENSOR' ]; then + SENSORPILLARPATH=/opt/so/saltstack + else + SENSORPILLARPATH=$TMP/pillar/sensors + fi if [ ! -d $SENSORPILLARPATH ]; then mkdir -p $SENSORPILLARPATH fi From fdbb223155b26a645db9deed0bd6b50375d28000 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Fri, 13 Dec 2019 11:52:43 -0500 Subject: [PATCH 193/200] Helix - Add geo --- salt/logstash/conf/conf.enabled.txt.so-helix | 1 + 1 file changed, 1 insertion(+) diff --git a/salt/logstash/conf/conf.enabled.txt.so-helix b/salt/logstash/conf/conf.enabled.txt.so-helix index 72bbc2ece..ec07b5a90 100644 --- a/salt/logstash/conf/conf.enabled.txt.so-helix +++ b/salt/logstash/conf/conf.enabled.txt.so-helix @@ -43,4 +43,5 @@ /usr/share/logstash/pipeline.so/1132_preprocess_bro_smb_mapping.conf /usr/share/logstash/pipeline.so/1133_preprocess_bro_ntlm.conf /usr/share/logstash/pipeline.so/1134_preprocess_bro_dce_rpc.conf +/usr/share/logstash/pipeline.so/8001_postprocess_common_ip_augmentation.conf /usr/share/logstash/pipeline.dynamic/9997_output_helix.conf From 13e9bf91f9637712ad37acf26098ddb95c15fa92 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Fri, 13 Dec 2019 11:58:18 -0500 Subject: [PATCH 194/200] Helix - Fix Helix Setup --- setup/functions.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup/functions.sh b/setup/functions.sh index 87d8bdce4..ad92298de 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -1102,7 +1102,8 @@ salt_install_mysql_deps() { sensor_pillar() { if [ $INSTALLTYPE == 'HELIXSENSOR' ]; then - SENSORPILLARPATH=/opt/so/saltstack + SENSORPILLARPATH=/opt/so/saltstack/pillar/sensor + mkdir -p $TMP else SENSORPILLARPATH=$TMP/pillar/sensors fi From 80acab7bec5a244d69d23024e99f31a72a703066 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Fri, 13 Dec 2019 12:00:51 -0500 Subject: [PATCH 195/200] Helix - Fix Helix Setup --- setup/functions.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/setup/functions.sh b/setup/functions.sh index ad92298de..1196be2e1 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -1104,6 +1104,7 @@ sensor_pillar() { if [ $INSTALLTYPE == 'HELIXSENSOR' ]; then SENSORPILLARPATH=/opt/so/saltstack/pillar/sensor mkdir -p $TMP + mkdir -p $SENSORPILLARPATH else SENSORPILLARPATH=$TMP/pillar/sensors fi From 684ab737bf5516eae7b9684a9f95cd49ec8d084b Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Fri, 13 Dec 2019 12:11:41 -0500 Subject: [PATCH 196/200] Helix - Fix Helix Setup --- setup/functions.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/functions.sh b/setup/functions.sh index 1196be2e1..a86ceff47 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -1102,7 +1102,7 @@ salt_install_mysql_deps() { sensor_pillar() { if [ $INSTALLTYPE == 'HELIXSENSOR' ]; then - SENSORPILLARPATH=/opt/so/saltstack/pillar/sensor + SENSORPILLARPATH=/opt/so/saltstack/pillar/sensors mkdir -p $TMP mkdir -p $SENSORPILLARPATH else From e49de63460b58cd3a5a1862bd7ce2f57f3e40512 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Fri, 13 Dec 2019 13:59:29 -0500 Subject: [PATCH 197/200] Helix - Final Parser Fixes --- salt/logstash/files/dynamic/9997_output_helix.conf | 2 ++ setup/so-setup.sh | 1 + 2 files changed, 3 insertions(+) diff --git a/salt/logstash/files/dynamic/9997_output_helix.conf b/salt/logstash/files/dynamic/9997_output_helix.conf index 14cca8352..5dd0036fe 100644 --- a/salt/logstash/files/dynamic/9997_output_helix.conf +++ b/salt/logstash/files/dynamic/9997_output_helix.conf @@ -27,9 +27,11 @@ filter { #rename => { "%{[source_geo][country_code]}" => "srccountrycode" } #rename => { "%{[destination_geo][country_code]}" => "dstcountrycode" } rename => { "[beat_host][name]" => "sensor" } + copy => { "sensor" => "rawmsghostname" } rename => { "message" => "rawmsg" } #rename => { "event_type" => "program" } copy => { "type" => "class" } + copy => { "class" => "program"} rename => { "source_port" => "srcport" } rename => { "destination_port" => "dstport" } remove_field => ["source_ip", "destination_ip"] diff --git a/setup/so-setup.sh b/setup/so-setup.sh index c35e9e7aa..81cde370b 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -153,6 +153,7 @@ if (whiptail_you_sure) ; then RULESETUP=ETOPEN NSMSETUP=BASIC HNSENSOR=inherit + LS_HEAP_SIZE="1000m" calculate_useable_cores whiptail_make_changes set_hostname From dc09f14379d62561ff8f2e95bc9a94003523fb87 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Fri, 13 Dec 2019 14:29:54 -0500 Subject: [PATCH 198/200] Helix - Fix heap size --- setup/functions.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/setup/functions.sh b/setup/functions.sh index a86ceff47..e0145c7a1 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -614,7 +614,11 @@ master_pillar() { echo " freq: 0" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls echo " domainstats: 0" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls fi - echo " lsheap: $LS_HEAP_SIZE" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + if [ $INSTALLTYPE == 'HELIXSENSOR' ]; then + echo " lsheap: 1000m" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + else + echo " lsheap: $LS_HEAP_SIZE" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls + fi echo " lsaccessip: 127.0.0.1" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls echo " elastalert: 1" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls echo " ls_pipeline_workers: $CPUCORES" >> /opt/so/saltstack/pillar/masters/$MINION_ID.sls From b53c3362f29245a263e98f5a1c1383ca0de3dc8e Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 16 Dec 2019 09:31:52 -0500 Subject: [PATCH 199/200] Update README.md --- README.md | 43 +++++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index c13c1741c..948c4713c 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,23 @@ -## Hybrid Hunter Alpha 1.1.2 - -- Quick firewall fix to address latest docker version. -- Added the option to install playbook from the initial install. -- Fixed an issue with multiple monitor interfaces not working properly. - -ISO Download: [HH 1.1.2-2](https://github.com/Security-Onion-Solutions/securityonion-hh-iso/releases/download/HH1.1.2/HH-1.1.2-2.iso) -MD5 (HH-1.1.2-2.iso) = abbbae7b40a50623546ed3d7f8cda0ec - - -## Hybrid Hunter Alpha 1.1.1 +## Hybrid Hunter Alpha 1.1.3 ### Changes: -- Alpha 2 is here! -- Suricata 4.1.5. -- Bro/Zeek 2.6.4. -- TheHive 3.4.0 (Includes ES 6.8.3 for TheHive only). -- Fixed Bro/Zeek packet loss calculation for Grafana. -- Updated to latest Sensoroni which includes websockets support for job status updates without having to refresh the page. -- NIDS and HIDS dashboard updates. -- Playbook and ATT&CK Navigator features are now included. -- Filebeat now logs to a file, instead of stdout. -- Elastalert has been updated to use Python 3 and allow for use of custom alerters. -- Moved Bro/Zeek log parsing from Logstash to Elasticsearch Ingest for higher performance and lower memory usage! -- Several changes to the setup script have been made to improve stability of the setup process: - - Setup now modifies your hosts file so that the install works better in environments without DNS. - - You are now prompted for setting a password for the socore user. - - The install now forces a reboot at the end of the install. This fixes an issue with some of the Docker containers being in the wrong state from a manual reboot. Manual reboots are fine after the initial reboot. +- Overhaul of the setup script to support both ISO and network based setups. +- ISO will now boot properly from a USB stick. +- Python 3 is now default. +- Fix Filebeat from restarting every check in due to x509 refresh issue. +- Cortex installed and integrated with TheHive. +- Switched to using vanilla Kolide Fleet and upgraded to latest version (2.4) . +- Playbook changes: + - Now preloaded with Plays generated from Sysmon Sigma signatures in the [Sigma community repo](https://github.com/Neo23x0/sigma/tree/master/rules/windows/sysmon). + - New update script that updates / pulls in new Sigma signatures from the community repo . + - Bulk enable / disable plays from the webui . + - Updated sigmac mapping template & configuration (backend is now `elastalert`) . + - Updated TheHive alerts formatting . +- OS patch scheduling: + - During setup, choose between auto, manual, or scheduled OS patch interval + - For scheduled, create a new or import an existing named schedule + ### Warnings and Disclaimers From 8a615b12628d3c386c286173e6e8c526f4984c73 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 16 Dec 2019 09:48:39 -0500 Subject: [PATCH 200/200] Update README.md --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 948c4713c..3b6188b5c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,17 @@ ## Hybrid Hunter Alpha 1.1.3 +### ISO Download: + +[HH1.1.3-20.iso](https://github.com/Security-Onion-Solutions/securityonion-hh-iso/releases/download/HH1.1.3/HH-1.1.3-20.iso) +MD5: 5A97980365A2A63EBFABB8C1DEB32BB6 +SHA1: 2A780B41903D907CED91D944569FD24FC131281F +SHA256: 56FA65EB5957903B967C16E792B17386848101CD058E0289878373110446C4B2 + +``` +Default Username: onion +Default Password: V@daL1aZ +``` + ### Changes: - Overhaul of the setup script to support both ISO and network based setups.