diff --git a/.github/DISCUSSION_TEMPLATE/2-4.yml b/.github/DISCUSSION_TEMPLATE/2-4.yml new file mode 100644 index 0000000000..8e25920717 --- /dev/null +++ b/.github/DISCUSSION_TEMPLATE/2-4.yml @@ -0,0 +1,190 @@ +body: + - type: markdown + attributes: + value: | + ⚠️ This category is solely for conversations related to Security Onion 2.4 ⚠️ + + If your organization needs more immediate, enterprise grade professional support, with one-on-one virtual meetings and screensharing, contact us via our website: https://securityonion.com/support + - type: dropdown + attributes: + label: Version + description: Which version of Security Onion 2.4.x are you asking about? + options: + - + - 2.4 Pre-release (Beta, Release Candidate) + - 2.4.10 + - 2.4.20 + - 2.4.30 + - 2.4.40 + - 2.4.50 + - 2.4.60 + - 2.4.70 + - 2.4.80 + - 2.4.90 + - 2.4.100 + - Other (please provide detail below) + validations: + required: true + - type: dropdown + attributes: + label: Installation Method + description: How did you install Security Onion? + options: + - + - Security Onion ISO image + - Network installation on Red Hat derivative like Oracle, Rocky, Alma, etc. + - Network installation on Ubuntu + - Network installation on Debian + - Other (please provide detail below) + validations: + required: true + - type: dropdown + attributes: + label: Description + description: > + Is this discussion about installation, configuration, upgrading, or other? + options: + - + - installation + - configuration + - upgrading + - other (please provide detail below) + validations: + required: true + - type: dropdown + attributes: + label: Installation Type + description: > + When you installed, did you choose Import, Eval, Standalone, Distributed, or something else? + options: + - + - Import + - Eval + - Standalone + - Distributed + - other (please provide detail below) + validations: + required: true + - type: dropdown + attributes: + label: Location + description: > + Is this deployment in the cloud, on-prem with Internet access, or airgap? + options: + - + - cloud + - on-prem with Internet access + - airgap + - other (please provide detail below) + validations: + required: true + - type: dropdown + attributes: + label: Hardware Specs + description: > + Does your hardware meet or exceed the minimum requirements for your installation type as shown at https://docs.securityonion.net/en/2.4/hardware.html? + options: + - + - Meets minimum requirements + - Exceeds minimum requirements + - Does not meet minimum requirements + - other (please provide detail below) + validations: + required: true + - type: input + attributes: + label: CPU + description: How many CPU cores do you have? + validations: + required: true + - type: input + attributes: + label: RAM + description: How much RAM do you have? + validations: + required: true + - type: input + attributes: + label: Storage for / + description: How much storage do you have for the / partition? + validations: + required: true + - type: input + attributes: + label: Storage for /nsm + description: How much storage do you have for the /nsm partition? + validations: + required: true + - type: dropdown + attributes: + label: Network Traffic Collection + description: > + Are you collecting network traffic from a tap or span port? + options: + - + - tap + - span port + - other (please provide detail below) + validations: + required: true + - type: dropdown + attributes: + label: Network Traffic Speeds + description: > + How much network traffic are you monitoring? + options: + - + - Less than 1Gbps + - 1Gbps to 10Gbps + - more than 10Gbps + validations: + required: true + - type: dropdown + attributes: + label: Status + description: > + Does SOC Grid show all services on all nodes as running OK? + options: + - + - Yes, all services on all nodes are running OK + - No, one or more services are failed (please provide detail below) + validations: + required: true + - type: dropdown + attributes: + label: Salt Status + description: > + Do you get any failures when you run "sudo salt-call state.highstate"? + options: + - + - Yes, there are salt failures (please provide detail below) + - No, there are no failures + validations: + required: true + - type: dropdown + attributes: + label: Logs + description: > + Are there any additional clues in /opt/so/log/? + options: + - + - Yes, there are additional clues in /opt/so/log/ (please provide detail below) + - No, there are no additional clues + validations: + required: true + - type: textarea + attributes: + label: Detail + description: Please read our discussion guidelines at https://github.com/Security-Onion-Solutions/securityonion/discussions/1720 and then provide detailed information to help us help you. + placeholder: |- + STOP! Before typing, please read our discussion guidelines at https://github.com/Security-Onion-Solutions/securityonion/discussions/1720 in their entirety! + + If your organization needs more immediate, enterprise grade professional support, with one-on-one virtual meetings and screensharing, contact us via our website: https://securityonion.com/support + validations: + required: true + - type: checkboxes + attributes: + label: Guidelines + options: + - label: I have read the discussion guidelines at https://github.com/Security-Onion-Solutions/securityonion/discussions/1720 and assert that I have followed the guidelines. + required: true diff --git a/.github/workflows/lock-threads.yml b/.github/workflows/lock-threads.yml new file mode 100644 index 0000000000..25e5d8c170 --- /dev/null +++ b/.github/workflows/lock-threads.yml @@ -0,0 +1,42 @@ +name: 'Lock Threads' + +on: + schedule: + - cron: '50 1 * * *' + workflow_dispatch: + +permissions: + issues: write + pull-requests: write + discussions: write + +concurrency: + group: lock-threads + +jobs: + close-threads: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/stale@v5 + with: + days-before-issue-stale: -1 + days-before-issue-close: 60 + stale-issue-message: "This issue is stale because it has been inactive for an extended period. Stale issues convey that the issue, while important to someone, is not critical enough for the author, or other community members to work on, sponsor, or otherwise shepherd the issue through to a resolution." + close-issue-message: "This issue was closed because it has been stale for an extended period. It will be automatically locked in 30 days, after which no further commenting will be available." + days-before-pr-stale: 45 + days-before-pr-close: 60 + stale-pr-message: "This PR is stale because it has been inactive for an extended period. The longer a PR remains stale the more out of date with the main branch it becomes." + close-pr-message: "This PR was closed because it has been stale for an extended period. It will be automatically locked in 30 days. If there is still a commitment to finishing this PR re-open it before it is locked." + + lock-threads: + runs-on: ubuntu-latest + steps: + - uses: jertel/lock-threads@main + with: + include-discussion-currently-open: true + discussion-inactive-days: 90 + issue-inactive-days: 30 + pr-inactive-days: 30 diff --git a/DOWNLOAD_AND_VERIFY_ISO.md b/DOWNLOAD_AND_VERIFY_ISO.md index a23d88d4dc..4493f210db 100644 --- a/DOWNLOAD_AND_VERIFY_ISO.md +++ b/DOWNLOAD_AND_VERIFY_ISO.md @@ -1,17 +1,17 @@ -### 2.4.50-20240220 ISO image released on 2024/02/20 +### 2.4.60-20240320 ISO image released on 2024/03/20 ### Download and Verify -2.4.50-20240220 ISO image: -https://download.securityonion.net/file/securityonion/securityonion-2.4.50-20240220.iso +2.4.60-20240320 ISO image: +https://download.securityonion.net/file/securityonion/securityonion-2.4.60-20240320.iso -MD5: BCA6476EF1BF79773D8EFB11700FDE8E -SHA1: 9FF0A304AA368BCD2EF2BE89AD47E65650241927 -SHA256: 49D7695EFFF6F3C4840079BF564F3191B585639816ADE98672A38017F25E9570 +MD5: 178DD42D06B2F32F3870E0C27219821E +SHA1: 73EDCD50817A7F6003FE405CF1808A30D034F89D +SHA256: DD334B8D7088A7B78160C253B680D645E25984BA5CCAB5CC5C327CA72137FC06 Signature for ISO image: -https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.50-20240220.iso.sig +https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.60-20240320.iso.sig Signing key: https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/2.4/main/KEYS @@ -25,22 +25,22 @@ wget https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/2. Download the signature file for the ISO: ``` -wget https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.50-20240220.iso.sig +wget https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.60-20240320.iso.sig ``` Download the ISO image: ``` -wget https://download.securityonion.net/file/securityonion/securityonion-2.4.50-20240220.iso +wget https://download.securityonion.net/file/securityonion/securityonion-2.4.60-20240320.iso ``` Verify the downloaded ISO image using the signature file: ``` -gpg --verify securityonion-2.4.50-20240220.iso.sig securityonion-2.4.50-20240220.iso +gpg --verify securityonion-2.4.60-20240320.iso.sig securityonion-2.4.60-20240320.iso ``` The output should show "Good signature" and the Primary key fingerprint should match what's shown below: ``` -gpg: Signature made Fri 16 Feb 2024 11:36:25 AM EST using RSA key ID FE507013 +gpg: Signature made Tue 19 Mar 2024 03:17:58 PM EDT using RSA key ID FE507013 gpg: Good signature from "Security Onion Solutions, LLC " gpg: WARNING: This key is not certified with a trusted signature! gpg: There is no indication that the signature belongs to the owner. diff --git a/VERSION b/VERSION index 9cf89c6c7a..5a99ed019d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.4.50 +2.4.60 diff --git a/salt/bpf/pcap.map.jinja b/salt/bpf/pcap.map.jinja index c1d7562ccd..4d8fef4609 100644 --- a/salt/bpf/pcap.map.jinja +++ b/salt/bpf/pcap.map.jinja @@ -1,7 +1,10 @@ -{% import_yaml 'bpf/defaults.yaml' as BPFDEFAULTS %} -{% set BPFMERGED = salt['pillar.get']('bpf', BPFDEFAULTS.bpf, merge=True) %} -{% import 'bpf/macros.jinja' as MACROS %} - -{{ MACROS.remove_comments(BPFMERGED, 'pcap') }} - -{% set PCAPBPF = BPFMERGED.pcap %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% if GLOBALS.pcap_engine == "TRANSITION" %} +{% set PCAPBPF = ["ip and host 255.255.255.1 and port 1"] %} +{% else %} +{% import_yaml 'bpf/defaults.yaml' as BPFDEFAULTS %} +{% set BPFMERGED = salt['pillar.get']('bpf', BPFDEFAULTS.bpf, merge=True) %} +{% import 'bpf/macros.jinja' as MACROS %} +{{ MACROS.remove_comments(BPFMERGED, 'pcap') }} +{% set PCAPBPF = BPFMERGED.pcap %} +{% endif %} diff --git a/salt/common/tools/sbin/so-common-status-check b/salt/common/tools/sbin/so-common-status-check index d713ba6c60..4aa9811239 100644 --- a/salt/common/tools/sbin/so-common-status-check +++ b/salt/common/tools/sbin/so-common-status-check @@ -47,12 +47,16 @@ def check_for_fps(): fps = 1 except FileNotFoundError: fn = '/proc/sys/crypto/' + feat_full + '_enabled' - with open(fn, 'r') as f: - contents = f.read() - if '1' in contents: - fps = 1 + try: + with open(fn, 'r') as f: + contents = f.read() + if '1' in contents: + fps = 1 + except: + # Unknown, so assume 0 + fps = 0 - with open('/opt/so/log/sostatus/lks_enabled', 'w') as f: + with open('/opt/so/log/sostatus/fps_enabled', 'w') as f: f.write(str(fps)) def check_for_lks(): @@ -76,7 +80,7 @@ def check_for_lks(): lks = 1 if lks: break - with open('/opt/so/log/sostatus/fps_enabled', 'w') as f: + with open('/opt/so/log/sostatus/lks_enabled', 'w') as f: f.write(str(lks)) def fail(msg): diff --git a/salt/elasticfleet/defaults.yaml b/salt/elasticfleet/defaults.yaml index e4f54ceb0e..7b2d9d6a3c 100644 --- a/salt/elasticfleet/defaults.yaml +++ b/salt/elasticfleet/defaults.yaml @@ -65,6 +65,7 @@ elasticfleet: - http_endpoint - httpjson - iis + - journald - juniper - juniper_srx - kafka_log diff --git a/salt/elasticfleet/tools/sbin_jinja/so-elastic-agent-gen-installers b/salt/elasticfleet/tools/sbin_jinja/so-elastic-agent-gen-installers index 275bc6a116..ff46a3e072 100755 --- a/salt/elasticfleet/tools/sbin_jinja/so-elastic-agent-gen-installers +++ b/salt/elasticfleet/tools/sbin_jinja/so-elastic-agent-gen-installers @@ -46,7 +46,7 @@ do done printf "\n### Stripping out unused components" -find /nsm/elastic-agent-workspace/elastic-agent-*/data/elastic-agent-*/components -maxdepth 1 -regex '.*fleet.*\|.*packet.*\|.*apm.*\|.*audit.*\|.*heart.*\|.*cloud.*' -delete +find /nsm/elastic-agent-workspace/elastic-agent-*/data/elastic-agent-*/components -maxdepth 1 -regex '.*fleet.*\|.*packet.*\|.*apm.*\|.*heart.*\|.*cloud.*' -delete printf "\n### Tarring everything up again" for OS in "${OSARCH[@]}" diff --git a/salt/elasticsearch/defaults.yaml b/salt/elasticsearch/defaults.yaml index 03cd6d5190..2274018b16 100644 --- a/salt/elasticsearch/defaults.yaml +++ b/salt/elasticsearch/defaults.yaml @@ -198,6 +198,35 @@ elasticsearch: sort: field: '@timestamp' order: desc + so-detection: + index_sorting: false + index_template: + composed_of: + - detection-mappings + - detection-settings + index_patterns: + - so-detection* + priority: 500 + template: + mappings: + date_detection: false + dynamic_templates: + - strings_as_keyword: + mapping: + ignore_above: 1024 + type: keyword + match_mapping_type: string + settings: + index: + mapping: + total_fields: + limit: 1500 + number_of_replicas: 0 + number_of_shards: 1 + refresh_interval: 30s + sort: + field: '@timestamp' + order: desc so-common: close: 30 delete: 365 @@ -1078,6 +1107,50 @@ elasticsearch: set_priority: priority: 50 min_age: 30d + so-logs-aws_x_cloudfront_logs: + index_sorting: False + index_template: + index_patterns: + - "logs-aws.cloudfront_logs-*" + template: + settings: + index: + lifecycle: + name: so-logs-aws.cloudfront_logs-logs + number_of_replicas: 0 + composed_of: + - "logs-aws.cloudfront_logs@package" + - "logs-aws.cloudfront_logs@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + policy: + phases: + cold: + actions: + set_priority: + priority: 0 + min_age: 30d + delete: + actions: + delete: {} + min_age: 365d + hot: + actions: + rollover: + max_age: 30d + max_primary_shard_size: 50gb + set_priority: + priority: 100 + min_age: 0ms + warm: + actions: + set_priority: + priority: 50 + min_age: 30d so-logs-aws_x_cloudtrail: index_sorting: false index_template: @@ -1298,6 +1371,94 @@ elasticsearch: set_priority: priority: 50 min_age: 30d + so-logs-aws_x_guardduty: + index_sorting: False + index_template: + index_patterns: + - "logs-aws.guardduty-*" + template: + settings: + index: + lifecycle: + name: so-logs-aws.guardduty-logs + number_of_replicas: 0 + composed_of: + - "logs-aws.guardduty@package" + - "logs-aws.guardduty@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + policy: + phases: + cold: + actions: + set_priority: + priority: 0 + min_age: 30d + delete: + actions: + delete: {} + min_age: 365d + hot: + actions: + rollover: + max_age: 30d + max_primary_shard_size: 50gb + set_priority: + priority: 100 + min_age: 0ms + warm: + actions: + set_priority: + priority: 50 + min_age: 30d + so-logs-aws_x_inspector: + index_sorting: False + index_template: + index_patterns: + - "logs-aws.inspector-*" + template: + settings: + index: + lifecycle: + name: so-logs-aws.inspector-logs + number_of_replicas: 0 + composed_of: + - "logs-aws.inspector@package" + - "logs-aws.inspector@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + policy: + phases: + cold: + actions: + set_priority: + priority: 0 + min_age: 30d + delete: + actions: + delete: {} + min_age: 365d + hot: + actions: + rollover: + max_age: 30d + max_primary_shard_size: 50gb + set_priority: + priority: 100 + min_age: 0ms + warm: + actions: + set_priority: + priority: 50 + min_age: 30d so-logs-aws_x_route53_public_logs: index_sorting: false index_template: @@ -1430,6 +1591,94 @@ elasticsearch: set_priority: priority: 50 min_age: 30d + so-logs-aws_x_securityhub_findings: + index_sorting: False + index_template: + index_patterns: + - "logs-aws.securityhub_findings-*" + template: + settings: + index: + lifecycle: + name: so-logs-aws.securityhub_findings-logs + number_of_replicas: 0 + composed_of: + - "logs-aws.securityhub_findings@package" + - "logs-aws.securityhub_findings@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + policy: + phases: + cold: + actions: + set_priority: + priority: 0 + min_age: 30d + delete: + actions: + delete: {} + min_age: 365d + hot: + actions: + rollover: + max_age: 30d + max_primary_shard_size: 50gb + set_priority: + priority: 100 + min_age: 0ms + warm: + actions: + set_priority: + priority: 50 + min_age: 30d + so-logs-aws_x_securityhub_insights: + index_sorting: False + index_template: + index_patterns: + - "logs-aws.securityhub_insights-*" + template: + settings: + index: + lifecycle: + name: so-logs-aws.securityhub_insights-logs + number_of_replicas: 0 + composed_of: + - "logs-aws.securityhub_insights@package" + - "logs-aws.securityhub_insights@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + policy: + phases: + cold: + actions: + set_priority: + priority: 0 + min_age: 30d + delete: + actions: + delete: {} + min_age: 365d + hot: + actions: + rollover: + max_age: 30d + max_primary_shard_size: 50gb + set_priority: + priority: 100 + min_age: 0ms + warm: + actions: + set_priority: + priority: 50 + min_age: 30d so-logs-aws_x_vpcflow: index_sorting: false index_template: @@ -3897,7 +4146,7 @@ elasticsearch: allow_custom_routing: false hidden: false index_patterns: - - logs-endpoint.diagnostic.collection-* + - .logs-endpoint.diagnostic.collection-* priority: 501 template: settings: @@ -8990,7 +9239,7 @@ elasticsearch: actions: set_priority: priority: 50 - min_age: 30d + min_age: 30d so-logs-ti_otx_x_threat: index_sorting: false index_template: @@ -10568,7 +10817,7 @@ elasticsearch: hot: actions: rollover: - max_age: 30d + max_age: 1d max_primary_shard_size: 50gb set_priority: priority: 100 diff --git a/salt/elasticsearch/soc_elasticsearch.yaml b/salt/elasticsearch/soc_elasticsearch.yaml index 9a64190b35..e68d0441b5 100644 --- a/salt/elasticsearch/soc_elasticsearch.yaml +++ b/salt/elasticsearch/soc_elasticsearch.yaml @@ -95,6 +95,7 @@ elasticsearch: description: The order to sort by. Must set index_sorting to True. global: True helpLink: elasticsearch.html + policy: phases: hot: max_age: diff --git a/salt/elasticsearch/templates/component/elastic-agent/logs-system.syslog@custom.json b/salt/elasticsearch/templates/component/elastic-agent/logs-system.syslog@custom.json new file mode 100644 index 0000000000..0123fb9561 --- /dev/null +++ b/salt/elasticsearch/templates/component/elastic-agent/logs-system.syslog@custom.json @@ -0,0 +1,22 @@ +{ + "template": { + "mappings": { + "properties": { + "error": { + "properties": { + "message": { + "type": "match_only_text" + } + } + } + } + } + }, + "_meta": { + "package": { + "name": "system" + }, + "managed_by": "fleet", + "managed": true + } +} diff --git a/salt/elasticsearch/templates/component/so/detection-mappings.json b/salt/elasticsearch/templates/component/so/detection-mappings.json new file mode 100644 index 0000000000..9b68421e71 --- /dev/null +++ b/salt/elasticsearch/templates/component/so/detection-mappings.json @@ -0,0 +1,138 @@ +{ + "template": { + "mappings": { + "properties": { + "so_audit_doc_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "@timestamp": { + "type": "date" + }, + "so_kind": { + "ignore_above": 1024, + "type": "keyword" + }, + "so_operation": { + "ignore_above": 1024, + "type": "keyword" + }, + "so_detection": { + "properties": { + "publicId": { + "type": "text" + }, + "title": { + "type": "text" + }, + "severity": { + "ignore_above": 1024, + "type": "keyword" + }, + "author": { + "type": "text" + }, + "description": { + "type": "text" + }, + "content": { + "type": "text" + }, + "isEnabled": { + "type": "boolean" + }, + "isReporting": { + "type": "boolean" + }, + "isCommunity": { + "type": "boolean" + }, + "tags": { + "type": "text" + }, + "ruleset": { + "ignore_above": 1024, + "type": "keyword" + }, + "engine": { + "ignore_above": 1024, + "type": "keyword" + }, + "language": { + "ignore_above": 1024, + "type": "keyword" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "overrides": { + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "isEnabled": { + "type": "boolean" + }, + "createdAt": { + "type": "date" + }, + "updatedAt": { + "type": "date" + }, + "regex": { + "type": "text" + }, + "value": { + "type": "text" + }, + "thresholdType": { + "ignore_above": 1024, + "type": "keyword" + }, + "track": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "text" + }, + "count": { + "type": "long" + }, + "seconds": { + "type": "long" + }, + "customFilter": { + "type": "text" + } + } + } + } + }, + "so_detectioncomment": { + "properties": { + "createTime": { + "type": "date" + }, + "detectionId": { + "ignore_above": 1024, + "type": "keyword" + }, + "value": { + "type": "text" + }, + "userId": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + }, + "_meta": { + "ecs_version": "1.12.2" + } +} \ No newline at end of file diff --git a/salt/elasticsearch/templates/component/so/detection-settings.json b/salt/elasticsearch/templates/component/so/detection-settings.json new file mode 100644 index 0000000000..7b0947a4cf --- /dev/null +++ b/salt/elasticsearch/templates/component/so/detection-settings.json @@ -0,0 +1,7 @@ +{ + "template": {}, + "version": 1, + "_meta": { + "description": "default settings for common Security Onion Detections indices" + } +} \ No newline at end of file diff --git a/salt/firewall/defaults.yaml b/salt/firewall/defaults.yaml index 75df49b253..75a70828e4 100644 --- a/salt/firewall/defaults.yaml +++ b/salt/firewall/defaults.yaml @@ -1295,6 +1295,10 @@ firewall: portgroups: - redis - beats_5644 + managersearch: + portgroups: + - redis + - beats_5644 self: portgroups: - redis diff --git a/salt/global/defaults.yaml b/salt/global/defaults.yaml new file mode 100644 index 0000000000..bd7244a587 --- /dev/null +++ b/salt/global/defaults.yaml @@ -0,0 +1,2 @@ +global: + pcapengine: STENO \ No newline at end of file diff --git a/salt/global/map.jinja b/salt/global/map.jinja new file mode 100644 index 0000000000..54abb8c799 --- /dev/null +++ b/salt/global/map.jinja @@ -0,0 +1,2 @@ +{% import_yaml 'global/defaults.yaml' as GLOBALDEFAULTS %} +{% set GLOBALMERGED = salt['pillar.get']('global', GLOBALDEFAULTS.global, merge=True) %} diff --git a/salt/global/soc_global.yaml b/salt/global/soc_global.yaml index 14d637d50e..a48476214f 100644 --- a/salt/global/soc_global.yaml +++ b/salt/global/soc_global.yaml @@ -10,10 +10,15 @@ global: regex: ^(([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?)?$ regexFailureMessage: You must enter a valid IP address or CIDR. mdengine: - description: What engine to use for meta data generation. Options are ZEEK and SURICATA. + description: Which engine to use for meta data generation. Options are ZEEK and SURICATA. regex: ^(ZEEK|SURICATA)$ regexFailureMessage: You must enter either ZEEK or SURICATA. global: True + pcapengine: + description: Which engine to use for generating pcap. Options are STENO, SURICATA or TRANSITION. + regex: ^(STENO|SURICATA|TRANSITION)$ + regexFailureMessage: You must enter either STENO, SURICATA or TRANSITION. + global: True ids: description: Which IDS engine to use. Currently only Suricata is supported. global: True diff --git a/salt/idstools/soc_idstools.yaml b/salt/idstools/soc_idstools.yaml index 634f68803f..3e3a68117d 100644 --- a/salt/idstools/soc_idstools.yaml +++ b/salt/idstools/soc_idstools.yaml @@ -6,9 +6,10 @@ idstools: description: Enter your registration code or oinkcode for paid NIDS rulesets. title: Registration Code global: True + forcedType: string helpLink: rules.html ruleset: - description: Defines the ruleset you want to run. Options are ETOPEN or ETPRO. + description: 'Defines the ruleset you want to run. Options are ETOPEN or ETPRO. WARNING! Changing the ruleset will remove all existing Suricata rules of the previous ruleset and their associated overrides. This removal cannot be undone.' global: True regex: ETPRO\b|ETOPEN\b helpLink: rules.html diff --git a/salt/manager/files/mirror.txt b/salt/manager/files/mirror.txt new file mode 100644 index 0000000000..732c116b41 --- /dev/null +++ b/salt/manager/files/mirror.txt @@ -0,0 +1,2 @@ +https://repo.securityonion.net/file/so-repo/prod/2.4/oracle/9 +https://repo-alt.securityonion.net/prod/2.4/oracle/9 \ No newline at end of file diff --git a/salt/manager/files/repodownload.conf b/salt/manager/files/repodownload.conf new file mode 100644 index 0000000000..3c156a9db6 --- /dev/null +++ b/salt/manager/files/repodownload.conf @@ -0,0 +1,13 @@ +[main] +gpgcheck=1 +installonly_limit=3 +clean_requirements_on_remove=True +best=True +skip_if_unavailable=False +cachedir=/opt/so/conf/reposync/cache +keepcache=0 +[securityonionsync] +name=Security Onion Repo repo +mirrorlist=file:///opt/so/conf/reposync/mirror.txt +enabled=1 +gpgcheck=1 \ No newline at end of file diff --git a/salt/manager/init.sls b/salt/manager/init.sls index 23ef189b53..c62a419998 100644 --- a/salt/manager/init.sls +++ b/salt/manager/init.sls @@ -1,5 +1,5 @@ # Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. @@ -61,7 +61,7 @@ manager_sbin: - user: 939 - group: 939 - file_mode: 755 - - exclude_pat: + - exclude_pat: - "*_test.py" yara_update_scripts: @@ -75,6 +75,20 @@ yara_update_scripts: - defaults: EXCLUDEDRULES: {{ STRELKAMERGED.rules.excluded }} +so-repo-file: + file.managed: + - name: /opt/so/conf/reposync/repodownload.conf + - source: salt://manager/files/repodownload.conf + - user: socore + - group: socore + +so-repo-mirrorlist: + file.managed: + - name: /opt/so/conf/reposync/mirror.txt + - source: salt://manager/files/mirror.txt + - user: socore + - group: socore + so-repo-sync: {% if MANAGERMERGED.reposync.enabled %} cron.present: @@ -103,55 +117,51 @@ rules_dir: - group: socore - makedirs: True -{% if STRELKAMERGED.rules.enabled %} - +{% if STRELKAMERGED.rules.enabled %} strelkarepos: file.managed: - name: /opt/so/conf/strelka/repos.txt - source: salt://strelka/rules/repos.txt.jinja - template: jinja - defaults: - STRELKAREPOS: {{ STRELKAMERGED.rules.repos }} + STRELKAREPOS: {{ STRELKAMERGED.rules.repos }} - makedirs: True - strelka-yara-update: - {% if MANAGERMERGED.reposync.enabled and not GLOBALS.airgap %} + {% if MANAGERMERGED.reposync.enabled and not GLOBALS.airgap %} cron.present: - {% else %} + {% else %} cron.absent: - {% endif %} + {% endif %} - user: socore - name: '/usr/sbin/so-yara-update >> /opt/so/log/yarasync/yara-update.log 2>&1' - identifier: strelka-yara-update - hour: '7' - minute: '1' - strelka-yara-download: - {% if MANAGERMERGED.reposync.enabled and not GLOBALS.airgap %} + {% if MANAGERMERGED.reposync.enabled and not GLOBALS.airgap %} cron.present: - {% else %} + {% else %} cron.absent: - {% endif %} + {% endif %} - user: socore - name: '/usr/sbin/so-yara-download >> /opt/so/log/yarasync/yara-download.log 2>&1' - identifier: strelka-yara-download - hour: '7' - minute: '1' - -{% if not GLOBALS.airgap %} +{% if not GLOBALS.airgap %} update_yara_rules: cmd.run: - name: /usr/sbin/so-yara-update - onchanges: - file: yara_update_scripts - download_yara_rules: cmd.run: - name: /usr/sbin/so-yara-download - onchanges: - file: yara_update_scripts -{% endif %} -{% endif %} +{% endif %} +{% endif %} + {% else %} {{sls}}_state_not_allowed: diff --git a/salt/manager/tools/sbin/so-minion b/salt/manager/tools/sbin/so-minion index d5225cc827..cb4e40adee 100755 --- a/salt/manager/tools/sbin/so-minion +++ b/salt/manager/tools/sbin/so-minion @@ -79,6 +79,32 @@ function getinstallinfo() { source <(echo $INSTALLVARS) } +function pcapspace() { + if [[ "$OPERATION" == "setup" ]]; then + # Use 25% for PCAP + PCAP_PERCENTAGE=1 + DFREEPERCENT=21 + local SPACESIZE=$(df -k /nsm | tail -1 | awk '{print $2}' | tr -d \n) + else + + local NSMSIZE=$(salt "$MINION_ID" disk.usage --out=json | jq -r '.[]."/nsm"."1K-blocks" ') + local ROOTSIZE=$(salt "$MINION_ID" disk.usage --out=json | jq -r '.[]."/"."1K-blocks" ') + + if [[ "$NSMSIZE" == "null" ]]; then + # Looks like there is no dedicated nsm partition. Using root + local SPACESIZE=$ROOTSIZE + else + local SPACESIZE=$NSMSIZE + fi + fi + + local s=$(( $SPACESIZE / 1000000 )) + local s1=$(( $s / 4 * $PCAP_PERCENTAGE )) + + MAX_PCAP_SPACE=$s1 + +} + function testMinion() { # Always run on the host, since this is going to be the manager of a distributed grid, or an eval/standalone. # Distributed managers must run this in order for the sensor nodes to have access to the so-tcpreplay image. @@ -244,6 +270,10 @@ function add_sensor_to_minion() { echo " lb_procs: '$CORECOUNT'" >> $PILLARFILE echo "suricata:" >> $PILLARFILE echo " enabled: True " >> $PILLARFILE + if [[ $is_pcaplimit ]]; then + echo " pcap:" >> $PILLARFILE + echo " maxsize: $MAX_PCAP_SPACE" >> $PILLARFILE + fi echo " config:" >> $PILLARFILE echo " af-packet:" >> $PILLARFILE echo " threads: '$CORECOUNT'" >> $PILLARFILE @@ -251,7 +281,7 @@ function add_sensor_to_minion() { echo " enabled: True" >> $PILLARFILE if [[ $is_pcaplimit ]]; then echo " config:" >> $PILLARFILE - echo " diskfreepercentage: 60" >> $PILLARFILE + echo " diskfreepercentage: $DFREEPERCENT" >> $PILLARFILE fi echo " " >> $PILLARFILE } @@ -422,6 +452,7 @@ function updateMine() { function createEVAL() { is_pcaplimit=true + pcapspace add_elasticsearch_to_minion add_sensor_to_minion add_strelka_to_minion @@ -442,6 +473,7 @@ function createEVAL() { function createSTANDALONE() { is_pcaplimit=true + pcapspace add_elasticsearch_to_minion add_logstash_to_minion add_sensor_to_minion @@ -531,6 +563,9 @@ function createIDH() { function createHEAVYNODE() { is_pcaplimit=true + PCAP_PERCENTAGE=1 + DFREEPERCENT=21 + pcapspace add_elasticsearch_to_minion add_elastic_agent_to_minion add_logstash_to_minion @@ -541,6 +576,10 @@ function createHEAVYNODE() { } function createSENSOR() { + is_pcaplimit=true + DFREEPERCENT=10 + PCAP_PERCENTAGE=3 + pcapspace add_sensor_to_minion add_strelka_to_minion add_telegraf_to_minion diff --git a/salt/manager/tools/sbin/so-saltstack-update b/salt/manager/tools/sbin/so-saltstack-update index b15fce0089..4be8f095cf 100755 --- a/salt/manager/tools/sbin/so-saltstack-update +++ b/salt/manager/tools/sbin/so-saltstack-update @@ -47,7 +47,7 @@ got_root(){ got_root if [ $# -ne 1 ] ; then - BRANCH=master + BRANCH=2.4/main else BRANCH=$1 fi diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index 8b9d4a6b33..a585f877c7 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -247,67 +247,6 @@ check_sudoers() { fi } -check_log_size_limit() { - local num_minion_pillars - num_minion_pillars=$(find /opt/so/saltstack/local/pillar/minions/ -type f | wc -l) - - if [[ $num_minion_pillars -gt 1 ]]; then - if find /opt/so/saltstack/local/pillar/minions/ -type f | grep -q "_heavynode"; then - lsl_msg='distributed' - fi - else - local minion_id - minion_id=$(lookup_salt_value "id" "" "grains" "" "local") - - local minion_arr - IFS='_' read -ra minion_arr <<< "$minion_id" - - local node_type="${minion_arr[0]}" - - local current_limit - # since it is possible for the salt-master service to be stopped when this is run, we need to check the pillar values locally - # we need to combine default local and default pillars before doing this so we can define --pillar-root in salt-call - local epoch_date=$(date +%s%N) - mkdir -vp /opt/so/saltstack/soup_tmp_${epoch_date}/ - cp -r /opt/so/saltstack/default/pillar/ /opt/so/saltstack/soup_tmp_${epoch_date}/ - # use \cp here to overwrite any pillar files from default with those in local for the tmp directory - \cp -r /opt/so/saltstack/local/pillar/ /opt/so/saltstack/soup_tmp_${epoch_date}/ - current_limit=$(salt-call pillar.get elasticsearch:log_size_limit --local --pillar-root=/opt/so/saltstack/soup_tmp_${epoch_date}/pillar --out=newline_values_only) - rm -rf /opt/so/saltstack/soup_tmp_${epoch_date}/ - - local percent - case $node_type in - 'standalone' | 'eval') - percent=50 - ;; - *) - percent=80 - ;; - esac - - local disk_dir="/" - if [ -d /nsm ]; then - disk_dir="/nsm" - fi - - local disk_size_1k - disk_size_1k=$(df $disk_dir | grep -v "^Filesystem" | awk '{print $2}') - - local ratio="1048576" - - local disk_size_gb - disk_size_gb=$( echo "$disk_size_1k" "$ratio" | awk '{print($1/$2)}' ) - - local new_limit - new_limit=$( echo "$disk_size_gb" "$percent" | awk '{printf("%.0f", $1 * ($2/100))}') - - if [[ $current_limit != "$new_limit" ]]; then - lsl_msg='single-node' - lsl_details=( "$current_limit" "$new_limit" "$minion_id" ) - fi - fi -} - check_os_updates() { # Check to see if there are OS updates echo "Checking for OS updates." @@ -417,6 +356,7 @@ preupgrade_changes() { [[ "$INSTALLEDVERSION" == 2.4.20 ]] && up_to_2.4.30 [[ "$INSTALLEDVERSION" == 2.4.30 ]] && up_to_2.4.40 [[ "$INSTALLEDVERSION" == 2.4.40 ]] && up_to_2.4.50 + [[ "$INSTALLEDVERSION" == 2.4.50 ]] && up_to_2.4.60 true } @@ -432,6 +372,7 @@ postupgrade_changes() { [[ "$POSTVERSION" == 2.4.20 ]] && post_to_2.4.30 [[ "$POSTVERSION" == 2.4.30 ]] && post_to_2.4.40 [[ "$POSTVERSION" == 2.4.40 ]] && post_to_2.4.50 + [[ "$POSTVERSION" == 2.4.50 ]] && post_to_2.4.60 true } @@ -488,6 +429,12 @@ post_to_2.4.50() { POSTVERSION=2.4.50 } +post_to_2.4.60() { + echo "Regenerating Elastic Agent Installers..." + so-elastic-agent-gen-installers + POSTVERSION=2.4.60 +} + repo_sync() { echo "Sync the local repo." su socore -c '/usr/sbin/so-repo-sync' || fail "Unable to complete so-repo-sync." @@ -591,6 +538,8 @@ up_to_2.4.40() { up_to_2.4.50() { echo "Creating additional pillars.." mkdir -p /opt/so/saltstack/local/pillar/stig/ + mkdir -p /opt/so/saltstack/local/salt/stig/ + chown socore:socore /opt/so/saltstack/local/salt/stig/ touch /opt/so/saltstack/local/pillar/stig/adv_stig.sls touch /opt/so/saltstack/local/pillar/stig/soc_stig.sls @@ -617,6 +566,14 @@ up_to_2.4.50() { INSTALLEDVERSION=2.4.50 } +up_to_2.4.60() { + echo "Creating directory to store Suricata classification.config" + mkdir -vp /opt/so/saltstack/local/salt/suricata/classification + chown socore:socore /opt/so/saltstack/local/salt/suricata/classification + + INSTALLEDVERSION=2.4.60 +} + determine_elastic_agent_upgrade() { if [[ $is_airgap -eq 0 ]]; then update_elastic_agent_airgap @@ -664,6 +621,10 @@ update_airgap_rules() { if [ -d /nsm/repo/rules/sigma ]; then rsync -av $UPDATE_DIR/agrules/sigma/* /nsm/repo/rules/sigma/ fi + + # SOC Detections Airgap + rsync -av $UPDATE_DIR/agrules/detect-sigma/* /nsm/rules/detect-sigma/ + rsync -av $UPDATE_DIR/agrules/detect-yara/* /nsm/rules/detect-yara/ } update_airgap_repo() { diff --git a/salt/manager/tools/sbin_jinja/so-yara-update b/salt/manager/tools/sbin_jinja/so-yara-update old mode 100755 new mode 100644 diff --git a/salt/pcap/config.map.jinja b/salt/pcap/config.map.jinja index 7ed500f25f..e6d9f8bdac 100644 --- a/salt/pcap/config.map.jinja +++ b/salt/pcap/config.map.jinja @@ -2,6 +2,12 @@ or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at https://securityonion.net/license; you may not use this file except in compliance with the Elastic License 2.0. #} - + +{% from 'vars/globals.map.jinja' import GLOBALS %} {% import_yaml 'pcap/defaults.yaml' as PCAPDEFAULTS %} {% set PCAPMERGED = salt['pillar.get']('pcap', PCAPDEFAULTS.pcap, merge=True) %} + +{# disable stenographer if the pcap engine is set to SURICATA #} +{% if GLOBALS.pcap_engine == "SURICATA" %} +{% do PCAPMERGED.update({'enabled': False}) %} +{% endif %} diff --git a/salt/pcap/config.sls b/salt/pcap/config.sls index 9ea5cee658..eb37765c5c 100644 --- a/salt/pcap/config.sls +++ b/salt/pcap/config.sls @@ -72,13 +72,6 @@ stenoca: - user: 941 - group: 939 -pcapdir: - file.directory: - - name: /nsm/pcap - - user: 941 - - group: 941 - - makedirs: True - pcaptmpdir: file.directory: - name: /nsm/pcaptmp diff --git a/salt/pcap/init.sls b/salt/pcap/init.sls index 9de272ad7a..7a172e8fd8 100644 --- a/salt/pcap/init.sls +++ b/salt/pcap/init.sls @@ -15,3 +15,12 @@ include: {% else %} - pcap.disabled {% endif %} + +# This directory needs to exist regardless of whether STENO is enabled or not, in order for +# Sensoroni to be able to look at old steno PCAP data +pcapdir: + file.directory: + - name: /nsm/pcap + - user: 941 + - group: 941 + - makedirs: True \ No newline at end of file diff --git a/salt/pcap/soc_pcap.yaml b/salt/pcap/soc_pcap.yaml index 32204a23a4..65fb99d869 100644 --- a/salt/pcap/soc_pcap.yaml +++ b/salt/pcap/soc_pcap.yaml @@ -4,32 +4,32 @@ pcap: helpLink: stenographer.html config: maxdirectoryfiles: - description: The maximum number of packet/index files to create before deleting old files. + description: By default, Stenographer limits the number of files in the pcap directory to 30000 to avoid limitations with the ext3 filesystem. However, if you're using the ext4 or xfs filesystems, then it is safe to increase this value. So if you have a large amount of storage and find that you only have 3 weeks worth of PCAP on disk while still having plenty of free space, then you may want to increase this default setting. helpLink: stenographer.html diskfreepercentage: - description: The disk space percent to always keep free for PCAP + description: Stenographer will purge old PCAP on a regular basis to keep the disk free percentage at this level. If you have a distributed deployment with dedicated forward nodes, then the default value of 10 should be reasonable since Stenographer should be the main consumer of disk space in the /nsm partition. However, if you have systems that run both Stenographer and Elasticsearch at the same time (like eval and standalone installations), then you’ll want to make sure that this value is no lower than 21 so that you avoid Elasticsearch hitting its watermark setting at 80% disk usage. If you have an older standalone installation, then you may need to manually change this value to 21. helpLink: stenographer.html blocks: - description: The number of 1MB packet blocks used by AF_PACKET to store packets in memory, per thread. You shouldn't need to change this. + description: The number of 1MB packet blocks used by Stenographer and AF_PACKET to store packets in memory, per thread. You shouldn't need to change this. advanced: True helpLink: stenographer.html preallocate_file_mb: - description: File size to pre-allocate for individual PCAP files. You shouldn't need to change this. + description: File size to pre-allocate for individual Stenographer PCAP files. You shouldn't need to change this. advanced: True helpLink: stenographer.html aiops: - description: The max number of async writes to allow at once. + description: The max number of async writes to allow for Stenographer at once. advanced: True helpLink: stenographer.html pin_to_cpu: - description: Enable CPU pinning for PCAP. + description: Enable CPU pinning for Stenographer PCAP. advanced: True helpLink: stenographer.html cpus_to_pin_to: - description: CPU to pin PCAP to. Currently only a single CPU is supported. + description: CPU to pin Stenographer PCAP to. Currently only a single CPU is supported. advanced: True helpLink: stenographer.html disks: - description: List of disks to use for PCAP. This is currently not used. + description: List of disks to use for Stenographer PCAP. This is currently not used. advanced: True helpLink: stenographer.html diff --git a/salt/salt/init.sls b/salt/salt/init.sls index a190a84eb2..b2ea31a65a 100644 --- a/salt/salt/init.sls +++ b/salt/salt/init.sls @@ -10,3 +10,4 @@ salt_bootstrap: - name: /usr/sbin/bootstrap-salt.sh - source: salt://salt/scripts/bootstrap-salt.sh - mode: 755 + - show_changes: False diff --git a/salt/sensoroni/defaults.yaml b/salt/sensoroni/defaults.yaml index 4ebd666a94..7777985dd2 100644 --- a/salt/sensoroni/defaults.yaml +++ b/salt/sensoroni/defaults.yaml @@ -1,58 +1,60 @@ -sensoroni: - enabled: False - config: - analyze: - enabled: False - timeout_ms: 900000 - parallel_limit: 5 - node_checkin_interval_ms: 10000 - sensoronikey: - soc_host: - analyzers: - echotrail: - base_url: https://api.echotrail.io/insights/ - api_key: - elasticsearch: - base_url: - auth_user: - auth_pwd: - num_results: 10 - api_key: - index: _all - time_delta_minutes: 14400 - timestamp_field_name: '@timestamp' - map: {} - cert_path: - emailrep: - base_url: https://emailrep.io/ - api_key: - greynoise: - base_url: https://api.greynoise.io/ - api_key: - api_version: community - localfile: - file_path: [] - otx: - base_url: https://otx.alienvault.com/api/v1/ - api_key: - pulsedive: - base_url: https://pulsedive.com/api/ - api_key: - spamhaus: - lookup_host: zen.spamhaus.org - nameservers: [] - sublime_platform: - base_url: https://api.platform.sublimesecurity.com - api_key: - live_flow: False - mailbox_email_address: - message_source_id: - urlscan: - base_url: https://urlscan.io/api/v1/ - api_key: - enabled: False - visibility: public - timeout: 180 - virustotal: - base_url: https://www.virustotal.com/api/v3/search?query= - api_key: +sensoroni: + enabled: False + config: + analyze: + enabled: False + timeout_ms: 900000 + parallel_limit: 5 + node_checkin_interval_ms: 10000 + sensoronikey: + soc_host: + suripcap: + pcapMaxCount: 999999 + analyzers: + echotrail: + base_url: https://api.echotrail.io/insights/ + api_key: + elasticsearch: + base_url: + auth_user: + auth_pwd: + num_results: 10 + api_key: + index: _all + time_delta_minutes: 14400 + timestamp_field_name: '@timestamp' + map: {} + cert_path: + emailrep: + base_url: https://emailrep.io/ + api_key: + greynoise: + base_url: https://api.greynoise.io/ + api_key: + api_version: community + localfile: + file_path: [] + otx: + base_url: https://otx.alienvault.com/api/v1/ + api_key: + pulsedive: + base_url: https://pulsedive.com/api/ + api_key: + spamhaus: + lookup_host: zen.spamhaus.org + nameservers: [] + sublime_platform: + base_url: https://api.platform.sublimesecurity.com + api_key: + live_flow: False + mailbox_email_address: + message_source_id: + urlscan: + base_url: https://urlscan.io/api/v1/ + api_key: + enabled: False + visibility: public + timeout: 180 + virustotal: + base_url: https://www.virustotal.com/api/v3/search?query= + api_key: diff --git a/salt/sensoroni/enabled.sls b/salt/sensoroni/enabled.sls index 2111e8f1bb..3f05568a03 100644 --- a/salt/sensoroni/enabled.sls +++ b/salt/sensoroni/enabled.sls @@ -23,6 +23,7 @@ so-sensoroni: - /opt/so/conf/sensoroni/sensoroni.json:/opt/sensoroni/sensoroni.json:ro - /opt/so/conf/sensoroni/analyzers:/opt/sensoroni/analyzers:rw - /opt/so/log/sensoroni:/opt/sensoroni/logs:rw + - /nsm/suripcap/:/nsm/suripcap:rw {% if DOCKER.containers['so-sensoroni'].custom_bind_mounts %} {% for BIND in DOCKER.containers['so-sensoroni'].custom_bind_mounts %} - {{ BIND }} diff --git a/salt/sensoroni/files/sensoroni.json b/salt/sensoroni/files/sensoroni.json index 59ce500e3c..547e52ada1 100644 --- a/salt/sensoroni/files/sensoroni.json +++ b/salt/sensoroni/files/sensoroni.json @@ -1,6 +1,5 @@ -{%- from 'vars/globals.map.jinja' import GLOBALS %} -{%- from 'sensoroni/map.jinja' import SENSORONIMERGED %} -{%- from 'pcap/config.map.jinja' import PCAPMERGED %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{%- from 'sensoroni/map.jinja' import SENSORONIMERGED -%} { "logFilename": "/opt/sensoroni/logs/sensoroni.log", "logLevel":"info", @@ -23,16 +22,19 @@ "importer": {}, "statickeyauth": { "apiKey": "{{ GLOBALS.sensoroni_key }}" -{%- if PCAPMERGED.enabled %} +{% if GLOBALS.is_sensor %} }, "stenoquery": { "executablePath": "/opt/sensoroni/scripts/stenoquery.sh", "pcapInputPath": "/nsm/pcap", "pcapOutputPath": "/nsm/pcapout" - } -{%- else %} - } + }, + "suriquery": { + "pcapInputPath": "/nsm/suripcap", + "pcapOutputPath": "/nsm/pcapout", + "pcapMaxCount": {{ SENSORONIMERGED.config.suripcap.pcapMaxCount }} {%- endif %} + } } } } diff --git a/salt/sensoroni/soc_sensoroni.yaml b/salt/sensoroni/soc_sensoroni.yaml index f7a10c6f7a..7b8495dc58 100644 --- a/salt/sensoroni/soc_sensoroni.yaml +++ b/salt/sensoroni/soc_sensoroni.yaml @@ -37,6 +37,11 @@ sensoroni: helpLink: grid.html global: True advanced: True + suripcap: + pcapMaxCount: + description: The maximum number of PCAP packets to extract from eligible PCAP files, for PCAP jobs. If there are issues fetching excessively large packet streams consider lowering this value to reduce the number of collected packets returned to the user interface. + helpLink: sensoroni.html + advanced: True analyzers: echotrail: api_key: diff --git a/salt/soc/config.sls b/salt/soc/config.sls index 902d82ec7f..e4dad8df2e 100644 --- a/salt/soc/config.sls +++ b/salt/soc/config.sls @@ -9,9 +9,16 @@ include: - manager.sync_es_users +socdirtest: + file.directory: + - name: /opt/so/rules/elastalert/rules + - user: 939 + - group: 939 + - makedirs: True + socdir: file.directory: - - name: /opt/so/conf/soc + - name: /opt/so/conf/soc/fingerprints - user: 939 - group: 939 - makedirs: True @@ -57,6 +64,22 @@ socmotd: - mode: 600 - template: jinja +socsigmafinalpipeline: + file.managed: + - name: /opt/so/conf/soc/sigma_final_pipeline.yaml + - source: salt://soc/files/soc/sigma_final_pipeline.yaml + - user: 939 + - group: 939 + - mode: 600 + +socsigmasopipeline: + file.managed: + - name: /opt/so/conf/soc/sigma_so_pipeline.yaml + - source: salt://soc/files/soc/sigma_so_pipeline.yaml + - user: 939 + - group: 939 + - mode: 600 + socbanner: file.managed: - name: /opt/so/conf/soc/banner.md @@ -114,6 +137,13 @@ socuploaddir: - group: 939 - makedirs: True +socsigmarepo: + file.directory: + - name: /opt/so/rules + - user: 939 + - group: 939 + - mode: 775 + {% else %} {{sls}}_state_not_allowed: diff --git a/salt/soc/defaults.yaml b/salt/soc/defaults.yaml index 244a021d38..de372a98fd 100644 --- a/salt/soc/defaults.yaml +++ b/salt/soc/defaults.yaml @@ -20,7 +20,7 @@ soc: - dashboards - name: actionCorrelate description: actionCorrelateHelp - icon: fab fa-searchengin + icon: fa-magnifying-glass-arrow-right target: '' links: - '/#/hunt?q=("{:log.id.fuid}" OR "{:log.id.uid}" OR "{:network.community_id}") | groupby event.module* | groupby -sankey event.module* event.dataset | groupby event.dataset | groupby source.ip source.port destination.ip destination.port | groupby network.protocol | groupby source_geo.organization_name source.geo.country_name | groupby destination_geo.organization_name destination.geo.country_name | groupby rule.name rule.category event.severity_label | groupby dns.query.name | groupby file.mime_type | groupby http.virtual_host http.uri | groupby notice.note notice.message notice.sub_message | groupby ssl.server_name | groupby source.ip host.hostname user.name event.action event.type process.executable process.pid' @@ -64,13 +64,19 @@ soc: icon: fa-external-link-alt target: _blank links: - - 'https://{:sublime.url}/messages/{:sublime.message_group_id}' + - 'https://{:sublime.url}/messages/{:sublime.message_group_id}' + - name: actionProcessInfo + description: actionProcessInfoHelp + icon: fa-person-running + target: '' + links: + - '/#/hunt?q=(process.entity_id:"{:process.entity_id}") | groupby event.dataset | groupby -sankey event.dataset event.action | groupby event.action | groupby process.name | groupby host.name user.name | groupby source.ip source.port destination.ip destination.port | groupby dns.question.name | groupby dns.answers.data | groupby file.path | groupby registry.path | groupby dll.path' - name: actionProcessAncestors description: actionProcessAncestorsHelp icon: fa-people-roof target: '' links: - - '/#/hunt?q=(process.entity_id:"{:process.entity_id}" OR process.entity_id:"{:process.Ext.ancestry|processAncestors}") | groupby process.parent.name | groupby -sankey process.parent.name process.name | groupby process.name | groupby event.module event.dataset | table soc_timestamp event.dataset host.name user.name process.parent.name process.name process.working_directory' + - '/#/hunt?q=(process.entity_id:"{:process.entity_id}" OR process.entity_id:"{:process.Ext.ancestry|processAncestors}") | groupby event.dataset | groupby -sankey event.dataset event.action | groupby event.action | groupby process.parent.name | groupby -sankey process.parent.name process.name | groupby process.name | groupby host.name user.name | groupby source.ip source.port destination.ip destination.port | groupby dns.question.name | groupby dns.answers.data | groupby file.path | groupby registry.path | groupby dll.path' eventFields: default: - soc_timestamp @@ -995,6 +1001,69 @@ soc: - tds.header_type - log.id.uid - event.dataset + ':endpoint:events_x_api': + - soc_timestamp + - host.name + - user.name + - process.name + - process.Ext.api.name + - process.thread.Ext.call_stack_final_user_module.path + - event.dataset + ':endpoint:events_x_file': + - soc_timestamp + - host.name + - user.name + - process.name + - event.action + - file.path + - event.dataset + ':endpoint:events_x_library': + - soc_timestamp + - host.name + - user.name + - process.name + - event.action + - dll.path + - dll.code_signature.status + - dll.code_signature.subject_name + - event.dataset + ':endpoint:events_x_network': + - soc_timestamp + - host.name + - user.name + - process.name + - event.action + - source.ip + - source.port + - destination.ip + - destination.port + - network.community_id + - event.dataset + ':endpoint:events_x_process': + - soc_timestamp + - host.name + - user.name + - process.parent.name + - process.name + - event.action + - process.working_directory + - event.dataset + ':endpoint:events_x_registry': + - soc_timestamp + - host.name + - user.name + - process.name + - event.action + - registry.path + - event.dataset + ':endpoint:events_x_security': + - soc_timestamp + - host.name + - user.name + - process.executable + - event.action + - event.outcome + - event.dataset server: bindAddress: 0.0.0.0:9822 baseUrl: / @@ -1008,6 +1077,16 @@ soc: jobDir: jobs kratos: hostUrl: + elastalertengine: + allowRegex: '' + autoUpdateEnabled: false + communityRulesImportFrequencySeconds: 86400 + denyRegex: '' + elastAlertRulesFolder: /opt/sensoroni/elastalert + rulesFingerprintFile: /opt/sensoroni/fingerprints/sigma.fingerprint + sigmaRulePackages: + - core + - emerging_threats_addon elastic: hostUrl: remoteHostUrls: [] @@ -1026,6 +1105,7 @@ soc: esSearchOffsetMs: 1800000 maxLogLength: 1024 asyncThreshold: 10 + lookupTunnelParent: true influxdb: hostUrl: token: @@ -1049,6 +1129,21 @@ soc: - rbac/custom_roles userFiles: - rbac/users_roles + strelkaengine: + allowRegex: '' + autoUpdateEnabled: false + compileYaraPythonScriptPath: /opt/so/conf/strelka/compile_yara.py + denyRegex: '.*' + reposFolder: /opt/sensoroni/yara/repos + rulesRepos: + - repo: https://github.com/Security-Onion-Solutions/securityonion-yara + license: DRL + yaraRulesFolder: /opt/sensoroni/yara/rules + suricataengine: + allowRegex: '' + communityRulesFile: /nsm/rules/suricata/emerging-all.rules + denyRegex: '.*' + rulesFingerprintFile: /opt/sensoroni/fingerprints/emerging-all.fingerprint client: enableReverseLookup: false docsUrl: /docs/ @@ -1059,6 +1154,7 @@ soc: tipTimeoutMs: 6000 cacheExpirationMs: 300000 casesEnabled: true + detectionsEnabled: false inactiveTools: ['toolUnused'] tools: - name: toolKibana @@ -1114,6 +1210,9 @@ soc: - name: caseExcludeToggle filter: 'NOT _index:"*:so-case*"' enabled: true + - name: detectionsExcludeToggle + filter: 'NOT _index:"*:so-detection*"' + enabled: true - name: socExcludeToggle filter: 'NOT event.module:"soc"' enabled: true @@ -1384,6 +1483,9 @@ soc: - name: caseExcludeToggle filter: 'NOT _index:"*:so-case*"' enabled: true + - name: detectionsExcludeToggle + filter: 'NOT _index:"*:so-detection*"' + enabled: true - name: socExcludeToggle filter: 'NOT event.module:"soc"' enabled: true @@ -1417,13 +1519,22 @@ soc: query: 'event.category: network AND _exists_:process.executable AND (_exists_:dns.question.name OR _exists_:dns.answers.data) | groupby -sankey host.name dns.question.name | groupby event.dataset event.type | groupby host.name | groupby process.executable | groupby dns.question.name | groupby dns.answers.data' - name: Host Process Activity description: Process activity captured on an endpoint - query: 'event.category:process | groupby -sankey host.name user.name* | groupby event.dataset event.action | groupby host.name | groupby user.name | groupby process.working_directory | groupby process.executable | groupby process.command_line | groupby process.parent.executable | groupby process.parent.command_line | groupby -sankey process.parent.executable process.executable | table soc_timestamp event.dataset host.name user.name process.parent.name process.name process.working_directory' + query: 'event.category:process | groupby -sankey host.name user.name* | groupby event.dataset event.action | groupby host.name | groupby user.name | groupby process.working_directory | groupby process.executable | groupby process.command_line | groupby process.parent.executable | groupby process.parent.command_line | groupby -sankey process.parent.executable process.executable | table soc_timestamp host.name user.name process.parent.name process.name event.action process.working_directory event.dataset' - name: Host File Activity description: File activity captured on an endpoint query: 'event.category: file AND _exists_:process.executable | groupby -sankey host.name process.executable | groupby host.name | groupby event.dataset event.action event.type | groupby file.name | groupby process.executable' - name: Host Network & Process Mappings description: Network activity mapped to originating processes query: 'event.category: network AND _exists_:process.executable | groupby -sankey event.action host.name | groupby -sankey host.name user.name | groupby event.dataset* event.type* event.action* | groupby host.name | groupby user.name | groupby dns.question.name | groupby process.executable | groupby winlog.event_data.TargetObject | groupby process.name | groupby source.ip | groupby destination.ip | groupby destination.port' + - name: Host API Events + description: API (Application Programming Interface) events from endpoints + query: 'event.dataset:endpoint.events.api | groupby host.name | groupby -sankey host.name user.name | groupby user.name | groupby process.name | groupby process.Ext.api.name' + - name: Host Library Events + description: Library events from endpoints + query: 'event.dataset:endpoint.events.library | groupby host.name | groupby -sankey host.name user.name | groupby user.name | groupby process.name | groupby event.action | groupby dll.path | groupby dll.code_signature.status | groupby dll.code_signature.subject_name' + - name: Host Security Events + description: Security events from endpoints + query: 'event.dataset:endpoint.events.security | groupby host.name | groupby -sankey host.name user.name | groupby user.name | groupby process.executable | groupby event.action | groupby event.outcome' - name: Strelka description: Strelka file analysis query: 'event.module:strelka | groupby file.mime_type | groupby -sankey file.mime_type file.source | groupby file.source | groupby file.name' @@ -1754,3 +1865,55 @@ soc: - amber+strict - red customEnabled: false + detections: + viewEnabled: true + createLink: /detection/create + eventFetchLimit: 500 + eventItemsPerPage: 50 + groupFetchLimit: 50 + mostRecentlyUsedLimit: 5 + safeStringMaxLength: 100 + queryBaseFilter: '_index:"*:so-detection" AND so_kind:detection' + eventFields: + default: + - so_detection.title + - so_detection.isEnabled + - so_detection.language + - so_detection.severity + queries: + - name: "All Detections" + query: "_id:*" + - name: "Custom Detections" + query: "so_detection.isCommunity:false" + - name: "All Detections - Enabled" + query: "so_detection.isEnabled:true" + - name: "All Detections - Disabled" + query: "so_detection.isEnabled:false" + - name: "Detection Type - Suricata (NIDS)" + query: "so_detection.language:suricata" + - name: "Detection Type - Sigma - All" + query: "so_detection.language:sigma" + - name: "Detection Type - Sigma - Windows" + query: 'so_detection.language:sigma AND so_detection.content: "*product: windows*"' + - name: "Detection Type - Yara (Strelka)" + query: "so_detection.language:yara" + detection: + presets: + severity: + customEnabled: false + labels: + - unknown + - informational + - low + - medium + - high + - critical + language: + customEnabled: false + labels: + - suricata + - sigma + - yara + severityTranslations: + minor: low + major: high diff --git a/salt/soc/enabled.sls b/salt/soc/enabled.sls index 2661587f48..93ca07ac88 100644 --- a/salt/soc/enabled.sls +++ b/salt/soc/enabled.sls @@ -22,12 +22,18 @@ so-soc: - sobridge: - ipv4_address: {{ DOCKER.containers['so-soc'].ip }} - binds: + - /nsm/rules:/nsm/rules:rw + - /opt/so/conf/strelka:/opt/sensoroni/yara:rw + - /opt/so/rules/elastalert/rules:/opt/sensoroni/elastalert:rw + - /opt/so/conf/soc/fingerprints:/opt/sensoroni/fingerprints:rw - /nsm/soc/jobs:/opt/sensoroni/jobs:rw - /nsm/soc/uploads:/nsm/soc/uploads:rw - /opt/so/log/soc/:/opt/sensoroni/logs/:rw - /opt/so/conf/soc/soc.json:/opt/sensoroni/sensoroni.json:ro - /opt/so/conf/soc/motd.md:/opt/sensoroni/html/motd.md:ro - /opt/so/conf/soc/banner.md:/opt/sensoroni/html/login/banner.md:ro + - /opt/so/conf/soc/sigma_so_pipeline.yaml:/opt/sensoroni/sigma_so_pipeline.yaml:ro + - /opt/so/conf/soc/sigma_final_pipeline.yaml:/opt/sensoroni/sigma_final_pipeline.yaml:rw - /opt/so/conf/soc/custom.js:/opt/sensoroni/html/js/custom.js:ro - /opt/so/conf/soc/custom_roles:/opt/sensoroni/rbac/custom_roles:ro - /opt/so/conf/soc/soc_users_roles:/opt/sensoroni/rbac/users_roles:rw diff --git a/salt/soc/files/bin/compile_yara.py b/salt/soc/files/bin/compile_yara.py new file mode 100644 index 0000000000..43c8b1a09c --- /dev/null +++ b/salt/soc/files/bin/compile_yara.py @@ -0,0 +1,14 @@ +import os +import yara +import glob +import sys + +def compile_yara_rules(rules_dir: str) -> None: + compiled_rules_path: str = os.path.join(rules_dir, "rules.yar.compiled") + rule_files: list[str] = glob.glob(os.path.join(rules_dir, '**/*.yar'), recursive=True) + + if rule_files: + rules: yara.Rules = yara.compile(filepaths={os.path.basename(f): f for f in rule_files}) + rules.save(compiled_rules_path) + +compile_yara_rules(sys.argv[1]) diff --git a/salt/soc/files/soc/sigma_final_pipeline.yaml b/salt/soc/files/soc/sigma_final_pipeline.yaml new file mode 100644 index 0000000000..656bfbb3ec --- /dev/null +++ b/salt/soc/files/soc/sigma_final_pipeline.yaml @@ -0,0 +1,7 @@ +name: Security Onion - Final Pipeline +priority: 95 +transformations: + - id: override_field_name_mapping + type: field_name_mapping + mapping: + FieldNameToOverride: NewFieldName diff --git a/salt/soc/files/soc/sigma_so_pipeline.yaml b/salt/soc/files/soc/sigma_so_pipeline.yaml new file mode 100644 index 0000000000..d227c3f01e --- /dev/null +++ b/salt/soc/files/soc/sigma_so_pipeline.yaml @@ -0,0 +1,81 @@ +name: Security Onion Baseline Pipeline +priority: 90 +transformations: + - id: baseline_field_name_mapping + type: field_name_mapping + mapping: + cs-method: http.method + c-uri: http.uri + c-useragent: http.useragent + cs-version: http.version + uid: user.uid + sid: rule.uuid + answer: answers + query: dns.query.name + src_ip: source.ip.keyword + src_port: source.port + dst_ip: destination.ip.keyword + dst_port: destination.port + winlog.event_data.User: user.name + # Maps "antivirus" category to Windows Defender logs shipped by Elastic Agent Winlog Integration + # winlog.event_data.threat_name has to be renamed prior to ingestion, it is originally winlog.event_data.Threat Name + - id: antivirus_field-mappings_windows-defender + type: field_name_mapping + mapping: + Signature: winlog.event_data.threat_name + rule_conditions: + - type: logsource + category: antivirus + - id: antivirus_add-fields_windows-defender + type: add_condition + conditions: + winlog.channel: 'Microsoft-Windows-Windows Defender/Operational' + winlog.provider_name: 'Microsoft-Windows-Windows Defender' + event.code: "1116" + rule_conditions: + - type: logsource + category: antivirus + # Drops the Hashes field which is specific to Sysmon logs + # Ingested sysmon logs will have the Hashes field mapped to ECS specific fields + - id: hashes_drop_sysmon-specific-field + type: drop_detection_item + field_name_conditions: + - type: include_fields + fields: + - winlog.event_data.Hashes + rule_conditions: + - type: logsource + product: windows + - id: hashes_process-creation + type: field_name_mapping + mapping: + winlog.event_data.sha256: process.hash.sha256 + winlog.event_data.sha1: process.hash.sha1 + winlog.event_data.md5: process.hash.md5 + winlog.event_data.Imphash: process.pe.imphash + rule_conditions: + - type: logsource + product: windows + category: process_creation + - id: hashes_image-load + type: field_name_mapping + mapping: + winlog.event_data.sha256: dll.hash.sha256 + winlog.event_data.sha1: dll.hash.sha1 + winlog.event_data.md5: dll.hash.md5 + winlog.event_data.Imphash: dll.pe.imphash + rule_conditions: + - type: logsource + product: windows + category: image_load + - id: hashes_driver-load + type: field_name_mapping + mapping: + winlog.event_data.sha256: dll.hash.sha256 + winlog.event_data.sha1: dll.hash.sha1 + winlog.event_data.md5: dll.hash.md5 + winlog.event_data.Imphash: dll.pe.imphash + rule_conditions: + - type: logsource + product: windows + category: driver_load diff --git a/salt/soc/merged.map.jinja b/salt/soc/merged.map.jinja index 33c0070ade..c22ed2210d 100644 --- a/salt/soc/merged.map.jinja +++ b/salt/soc/merged.map.jinja @@ -30,6 +30,17 @@ {# since cases is not a valid soc config item and only used for the map files, remove it from being placed in the config #} {% do SOCMERGED.config.server.modules.pop('cases') %} +{# remove these modules if detections is disabled #} +{% if not SOCMERGED.config.server.client.detectionsEnabled %} +{% do SOCMERGED.config.server.modules.pop('elastalertengine') %} +{% do SOCMERGED.config.server.modules.pop('strelkaengine') %} +{% do SOCMERGED.config.server.modules.pop('suricataengine') %} +{% elif pillar.global.airgap %} + {# if system is Airgap, don't autoupdate Yara & Sigma rules #} + {% do SOCMERGED.config.server.modules.elastalertengine.update({'autoUpdateEnabled': false}) %} + {% do SOCMERGED.config.server.modules.strelkaengine.update({'autoUpdateEnabled': false}) %} +{% endif %} + {% if pillar.manager.playbook == 0 %} {% do SOCMERGED.config.server.client.inactiveTools.append('toolPlaybook') %} {% endif %} @@ -66,6 +77,14 @@ {% do SOCMERGED.config.server.client.alerts.update({'actions': standard_actions}) %} {% do SOCMERGED.config.server.client.cases.update({'actions': standard_actions}) %} +{# replace the _x_ with . for soc ui to config conversion #} +{% do SOCMERGED.config.eventFields.update({':endpoint:events.api': SOCMERGED.config.eventFields.pop(':endpoint:events_x_api') }) %} +{% do SOCMERGED.config.eventFields.update({':endpoint:events.file': SOCMERGED.config.eventFields.pop(':endpoint:events_x_file') }) %} +{% do SOCMERGED.config.eventFields.update({':endpoint:events.library': SOCMERGED.config.eventFields.pop(':endpoint:events_x_library') }) %} +{% do SOCMERGED.config.eventFields.update({':endpoint:events.network': SOCMERGED.config.eventFields.pop(':endpoint:events_x_network') }) %} +{% do SOCMERGED.config.eventFields.update({':endpoint:events.process': SOCMERGED.config.eventFields.pop(':endpoint:events_x_process') }) %} +{% do SOCMERGED.config.eventFields.update({':endpoint:events.registry': SOCMERGED.config.eventFields.pop(':endpoint:events_x_registry') }) %} +{% do SOCMERGED.config.eventFields.update({':endpoint:events.security': SOCMERGED.config.eventFields.pop(':endpoint:events_x_security') }) %} {% set standard_eventFields = SOCMERGED.config.pop('eventFields') %} {% do SOCMERGED.config.server.client.hunt.update({'eventFields': standard_eventFields}) %} {% do SOCMERGED.config.server.client.dashboards.update({'eventFields': standard_eventFields}) %} diff --git a/salt/soc/soc_soc.yaml b/salt/soc/soc_soc.yaml index 0dd39620b1..cb939f7581 100644 --- a/salt/soc/soc_soc.yaml +++ b/salt/soc/soc_soc.yaml @@ -32,6 +32,14 @@ soc: global: True advanced: True helpLink: soc-customization.html + sigma_final_pipeline__yaml: + title: Final Sigma Pipeline + description: Final Processing Pipeline for Sigma Rules (future use, not yet complete) + syntax: yaml + file: True + global: True + advanced: True + helpLink: soc-customization.html config: licenseKey: title: License Key @@ -47,10 +55,17 @@ soc: global: True forcedType: "[]{}" eventFields: - default: - description: Event fields mappings are defined by the format ":event.module:event.dataset". For example, to customize which fields show for 'syslog' events originating from 'zeek', find the eventField item in the left panel that looks like ':zeek:syslog'. This 'default' entry is used for all events that do not match an existing mapping defined in the list to the left. + default: &eventFields + description: Event fields mappings are defined by the format ":event.module:event.dataset". For example, to customize which fields show for 'syslog' events originating from 'zeek', find the eventField item in the left panel that looks like ':zeek:syslog'. The 'default' entry is used for all events that do not match an existing mapping defined in the list to the left. global: True advanced: True + ':endpoint:events_x_api': *eventFields + ':endpoint:events_x_file': *eventFields + ':endpoint:events_x_library': *eventFields + ':endpoint:events_x_network': *eventFields + ':endpoint:events_x_process': *eventFields + ':endpoint:events_x_registry': *eventFields + ':endpoint:events_x_security': *eventFields server: srvKey: description: Unique key for protecting the integrity of user submitted data via the web browser. @@ -62,6 +77,15 @@ soc: global: True advanced: True modules: + elastalertengine: + sigmaRulePackages: + description: 'Defines the Sigma Community Ruleset you want to run. One of these (core | core+ | core++ | all ) as well as an optional Add-on (emerging_threats_addon). WARNING! Changing the ruleset will remove all existing Sigma rules of the previous ruleset and their associated overrides. This removal cannot be undone. (future use, not yet complete)' + global: True + advanced: False + autoUpdateEnabled: + description: 'Set to true to enable automatic Internet-connected updates of the Sigma Community Ruleset. If this is an Airgap system, this setting will be overridden and set to false. (future use, not yet complete)' + global: True + advanced: True elastic: index: description: Comma-separated list of indices or index patterns (wildcard "*" supported) that SOC will search for records. @@ -102,6 +126,9 @@ soc: description: Maximum number of events that can be acknowledged synchronously. When acknowledging large numbers of events, where the count exceeds this value, the acknowledge update will be performed in the background, as it can take several minutes to complete. global: True advanced: True + lookupTunnelParent: + description: When true, if a pivoted event appears to be encapsulated, such as in a VXLAN packet, then SOC will pivot to the VXLAN packet stream. When false, SOC will attempt to pivot to the encapsulated packet stream itself, but at the risk that it may be unable to locate it in the stored PCAP data. + global: True sostatus: refreshIntervalMs: description: Duration (in milliseconds) between refreshes of the grid status. Shortening this duration may not have expected results, as the backend systems feeding this sostatus data will continue their updates as scheduled. @@ -120,6 +147,11 @@ soc: description: Duration (in milliseconds) to wait for a response from the Salt API when executing common grid management tasks before giving up and showing an error on the SOC UI. global: True advanced: True + strelkaengine: + autoUpdateEnabled: + description: 'Set to true to enable automatic Internet-connected updates of the Yara rulesets. If this is an Airgap system, this setting will be overridden and set to false. (future use, not yet complete)' + global: True + advanced: True client: enableReverseLookup: description: Set to true to enable reverse DNS lookups for IP addresses in the SOC UI. @@ -142,6 +174,9 @@ soc: casesEnabled: description: Set to true to enable case management in SOC. global: True + detectionsEnabled: + description: Set to true to enable the Detections module in SOC. (future use, not yet complete) + global: True inactiveTools: description: List of external tools to remove from the SOC UI. global: True diff --git a/salt/stig/enabled.sls b/salt/stig/enabled.sls index 1f1a064fd8..c35c91a552 100644 --- a/salt/stig/enabled.sls +++ b/salt/stig/enabled.sls @@ -48,15 +48,17 @@ update_stig_profile: {% if not salt['file.file_exists'](OSCAP_OUTPUT_DIR ~ '/pre-oscap-report.html') %} run_initial_scan: - module.run: - - name: openscap.xccdf - - params: 'eval --profile {{ OSCAP_PROFILE_NAME }} --results {{ OSCAP_OUTPUT_DIR }}/pre-oscap-results.xml --report {{ OSCAP_OUTPUT_DIR }}/pre-oscap-report.html {{ OSCAP_PROFILE_LOCATION }}' + cmd.run: + - name: 'oscap xccdf eval --profile {{ OSCAP_PROFILE_NAME }} --results {{ OSCAP_OUTPUT_DIR }}/pre-oscap-results.xml --report {{ OSCAP_OUTPUT_DIR }}/pre-oscap-report.html {{ OSCAP_PROFILE_LOCATION }}' + - success_retcodes: + - 2 {% endif %} run_remediate: - module.run: - - name: openscap.xccdf - - params: 'eval --remediate --profile {{ OSCAP_PROFILE_NAME }} --results {{ OSCAP_OUTPUT_DIR }}/post-oscap-results.xml --report {{ OSCAP_PROFILE_LOCATION }}' + cmd.run: + - name: 'oscap xccdf eval --remediate --profile {{ OSCAP_PROFILE_NAME }} {{ OSCAP_PROFILE_LOCATION }}' + - success_retcodes: + - 2 {# OSCAP rule id: xccdf_org.ssgproject.content_rule_disable_ctrlaltdel_burstaction #} disable_ctrl_alt_del_action: @@ -82,9 +84,10 @@ remove_nullok_from_system_auth_auth: - backup: '.bak' run_post_scan: - module.run: - - name: openscap.xccdf - - params: 'eval --profile {{ OSCAP_PROFILE_NAME }} --results {{ OSCAP_OUTPUT_DIR }}/post-oscap-results.xml --report {{ OSCAP_OUTPUT_DIR }}/post-oscap-report.html {{ OSCAP_PROFILE_LOCATION }}' + cmd.run: + - name: 'oscap xccdf eval --profile {{ OSCAP_PROFILE_NAME }} --results {{ OSCAP_OUTPUT_DIR }}/post-oscap-results.xml --report {{ OSCAP_OUTPUT_DIR }}/post-oscap-report.html /usr/share/xml/scap/ssg/content/ssg-ol9-ds.xml' + - success_retcodes: + - 2 {% else %} {{sls}}_no_license_detected: diff --git a/salt/stig/files/sos-oscap.xml b/salt/stig/files/sos-oscap.xml index 3f78af8c09..6c4c93778b 100644 --- a/salt/stig/files/sos-oscap.xml +++ b/salt/stig/files/sos-oscap.xml @@ -611,7 +611,7 @@ the release. Additionally, the original security profile has been modified by Se - + @@ -1007,8 +1007,8 @@ the release. Additionally, the original security profile has been modified by Se - - + + diff --git a/salt/strelka/backend/config.sls b/salt/strelka/backend/config.sls index d51debb1b4..db18a68ccf 100644 --- a/salt/strelka/backend/config.sls +++ b/salt/strelka/backend/config.sls @@ -50,15 +50,15 @@ backend_taste: - user: 939 - group: 939 -{% if STRELKAMERGED.rules.enabled %} +{% if STRELKAMERGED.rules.enabled %} strelkarules: - file.recurse: - - name: /opt/so/conf/strelka/rules - - source: salt://strelka/rules - - user: 939 - - group: 939 - - clean: True -{% endif %} + file.recurse: + - name: /opt/so/conf/strelka/rules + - source: salt://strelka/rules + - user: 939 + - group: 939 + - clean: True +{% endif %} {% else %} diff --git a/salt/strelka/config.sls b/salt/strelka/config.sls index 1d0f75adf4..929bef113c 100644 --- a/salt/strelka/config.sls +++ b/salt/strelka/config.sls @@ -1,5 +1,5 @@ # Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. @@ -21,6 +21,13 @@ strelkarulesdir: - group: 939 - makedirs: True +strelkareposdir: + file.directory: + - name: /opt/so/conf/strelka/repos + - user: 939 + - group: 939 + - makedirs: True + strelkadatadir: file.directory: - name: /nsm/strelka diff --git a/salt/suricata/classification/classification.config b/salt/suricata/classification/classification.config new file mode 100644 index 0000000000..220736c947 --- /dev/null +++ b/salt/suricata/classification/classification.config @@ -0,0 +1,51 @@ +# +# config classification:shortname,short description,priority +# + +config classification: not-suspicious,Not Suspicious Traffic,3 +config classification: unknown,Unknown Traffic,3 +config classification: bad-unknown,Potentially Bad Traffic, 2 +config classification: attempted-recon,Attempted Information Leak,2 +config classification: successful-recon-limited,Information Leak,2 +config classification: successful-recon-largescale,Large Scale Information Leak,2 +config classification: attempted-dos,Attempted Denial of Service,2 +config classification: successful-dos,Denial of Service,2 +config classification: attempted-user,Attempted User Privilege Gain,1 +config classification: unsuccessful-user,Unsuccessful User Privilege Gain,1 +config classification: successful-user,Successful User Privilege Gain,1 +config classification: attempted-admin,Attempted Administrator Privilege Gain,1 +config classification: successful-admin,Successful Administrator Privilege Gain,1 + +# NEW CLASSIFICATIONS +config classification: rpc-portmap-decode,Decode of an RPC Query,2 +config classification: shellcode-detect,Executable code was detected,1 +config classification: string-detect,A suspicious string was detected,3 +config classification: suspicious-filename-detect,A suspicious filename was detected,2 +config classification: suspicious-login,An attempted login using a suspicious username was detected,2 +config classification: system-call-detect,A system call was detected,2 +config classification: tcp-connection,A TCP connection was detected,4 +config classification: trojan-activity,A Network Trojan was detected, 1 +config classification: unusual-client-port-connection,A client was using an unusual port,2 +config classification: network-scan,Detection of a Network Scan,3 +config classification: denial-of-service,Detection of a Denial of Service Attack,2 +config classification: non-standard-protocol,Detection of a non-standard protocol or event,2 +config classification: protocol-command-decode,Generic Protocol Command Decode,3 +config classification: web-application-activity,access to a potentially vulnerable web application,2 +config classification: web-application-attack,Web Application Attack,1 +config classification: misc-activity,Misc activity,3 +config classification: misc-attack,Misc Attack,2 +config classification: icmp-event,Generic ICMP event,3 +config classification: inappropriate-content,Inappropriate Content was Detected,1 +config classification: policy-violation,Potential Corporate Privacy Violation,1 +config classification: default-login-attempt,Attempt to login by a default username and password,2 + +# Update +config classification: targeted-activity,Targeted Malicious Activity was Detected,1 +config classification: exploit-kit,Exploit Kit Activity Detected,1 +config classification: external-ip-check,Device Retrieving External IP Address Detected,2 +config classification: domain-c2,Domain Observed Used for C2 Detected,1 +config classification: pup-activity,Possibly Unwanted Program Detected,2 +config classification: credential-theft,Successful Credential Theft Detected,1 +config classification: social-engineering,Possible Social Engineering Attempted,2 +config classification: coin-mining,Crypto Currency Mining Activity Detected,2 +config classification: command-and-control,Malware Command and Control Activity Detected,1 diff --git a/salt/suricata/config.sls b/salt/suricata/config.sls index 3ec1324bf0..00364f3840 100644 --- a/salt/suricata/config.sls +++ b/salt/suricata/config.sls @@ -129,6 +129,13 @@ surithresholding: - group: 940 - template: jinja +suriclassifications: + file.managed: + - name: /opt/so/conf/suricata/classification.config + - source: salt://suricata/classification/classification.config + - user: 940 + - group: 940 + # BPF compilation and configuration {% if SURICATABPF %} {% set BPF_CALC = salt['cmd.script']('salt://common/tools/sbin/so-bpf-compile', GLOBALS.sensor.interface + ' ' + SURICATABPF|join(" "),cwd='/root') %} diff --git a/salt/suricata/defaults.yaml b/salt/suricata/defaults.yaml index e9e39d40ae..0252d3a813 100644 --- a/salt/suricata/defaults.yaml +++ b/salt/suricata/defaults.yaml @@ -1,5 +1,16 @@ suricata: enabled: False + pcap: + filesize: 1000mb + maxsize: 25 + compression: "none" + lz4-checksum: "no" + lz4-level: 8 + filename: "%n/so-pcap.%t" + mode: "multi" + use-stream-depth: "no" + conditional: "all" + dir: "/nsm/suripcap" config: threading: set-cpu-affinity: "no" diff --git a/salt/suricata/enabled.sls b/salt/suricata/enabled.sls index ce309e41a4..d351605276 100644 --- a/salt/suricata/enabled.sls +++ b/salt/suricata/enabled.sls @@ -27,11 +27,13 @@ so-suricata: - binds: - /opt/so/conf/suricata/suricata.yaml:/etc/suricata/suricata.yaml:ro - /opt/so/conf/suricata/threshold.conf:/etc/suricata/threshold.conf:ro + - /opt/so/conf/suricata/classification.config:/etc/suricata/classification.config:ro - /opt/so/conf/suricata/rules:/etc/suricata/rules:ro - /opt/so/log/suricata/:/var/log/suricata/:rw - /nsm/suricata/:/nsm/:rw - /nsm/suricata/extracted:/var/log/suricata//filestore:rw - /opt/so/conf/suricata/bpf:/etc/suricata/bpf:ro + - /nsm/suripcap/:/nsm/suripcap:rw {% if DOCKER.containers['so-suricata'].custom_bind_mounts %} {% for BIND in DOCKER.containers['so-suricata'].custom_bind_mounts %} - {{ BIND }} @@ -49,10 +51,12 @@ so-suricata: - file: surithresholding - file: /opt/so/conf/suricata/rules/ - file: /opt/so/conf/suricata/bpf + - file: suriclassifications - require: - file: suriconfig - file: surithresholding - file: suribpf + - file: suriclassifications delete_so-suricata_so-status.disabled: file.uncomment: diff --git a/salt/suricata/init.sls b/salt/suricata/init.sls index 64a000109d..f6ddce862b 100644 --- a/salt/suricata/init.sls +++ b/salt/suricata/init.sls @@ -7,6 +7,7 @@ {% from 'suricata/map.jinja' import SURICATAMERGED %} include: + - suricata.pcap {% if SURICATAMERGED.enabled and GLOBALS.role != 'so-import' %} - suricata.enabled {% elif GLOBALS.role == 'so-import' %} diff --git a/salt/suricata/map.jinja b/salt/suricata/map.jinja index 01d019de87..7f7b04aeff 100644 --- a/salt/suricata/map.jinja +++ b/salt/suricata/map.jinja @@ -8,6 +8,24 @@ {% set surimeta_evelog_index = [] %} {% set surimeta_filestore_index = [] %} +{# before we change outputs back to list, enable pcap-log if suricata is the pcapengine #} +{% if GLOBALS.pcap_engine in ["SURICATA", "TRANSITION"] %} +{% do SURICATAMERGED.config.outputs['pcap-log'].update({'enabled': 'yes'}) %} +{# move the items in suricata.pcap into suricata.config.outputs.pcap-log. these items were placed under suricata.config for ease of access in SOC #} +{% do SURICATAMERGED.config.outputs['pcap-log'].update({'compression': SURICATAMERGED.pcap.compression}) %} +{% do SURICATAMERGED.config.outputs['pcap-log'].update({'lz4-checksum': SURICATAMERGED.pcap['lz4-checksum']}) %} +{% do SURICATAMERGED.config.outputs['pcap-log'].update({'lz4-level': SURICATAMERGED.pcap['lz4-level']}) %} +{% do SURICATAMERGED.config.outputs['pcap-log'].update({'filename': SURICATAMERGED.pcap.filename}) %} +{% do SURICATAMERGED.config.outputs['pcap-log'].update({'limit': SURICATAMERGED.pcap.filesize}) %} +{% do SURICATAMERGED.config.outputs['pcap-log'].update({'mode': SURICATAMERGED.pcap.mode}) %} +{% do SURICATAMERGED.config.outputs['pcap-log'].update({'use-stream-depth': SURICATAMERGED.pcap['use-stream-depth']}) %} +{% do SURICATAMERGED.config.outputs['pcap-log'].update({'conditional': SURICATAMERGED.pcap.conditional}) %} +{% do SURICATAMERGED.config.outputs['pcap-log'].update({'dir': SURICATAMERGED.pcap.dir}) %} +{# multiply maxsize by 1000 since it is saved in GB, i.e. 52 = 52000MB. filesize is also saved in MB and we strip the MB and convert to int #} +{% set maxfiles = (SURICATAMERGED.pcap.maxsize * 1000 / (SURICATAMERGED.pcap.filesize[:-2] | int) / SURICATAMERGED.config['af-packet'].threads | int) | round | int %} +{% do SURICATAMERGED.config.outputs['pcap-log'].update({'max-files': maxfiles}) %} +{% endif %} + {# suricata.config.af-packet has to be rewritten here since we cant display '- interface' in the ui #} {# we are limited to only one iterface #} {% load_yaml as afpacket %} diff --git a/salt/suricata/pcap.sls b/salt/suricata/pcap.sls new file mode 100644 index 0000000000..87b568f964 --- /dev/null +++ b/salt/suricata/pcap.sls @@ -0,0 +1,28 @@ +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'suricata/map.jinja' import SURICATAMERGED %} + +# This directory needs to exist regardless of whether SURIPCAP is enabled or not, in order for +# Sensoroni to be able to look at old Suricata PCAP data +suripcapdir: + file.directory: + - name: /nsm/suripcap + - user: 940 + - group: 939 + - mode: 775 + - makedirs: True + +{% if GLOBALS.pcap_engine in ["SURICATA", "TRANSITION"] %} + +{# there should only be 1 interface in af-packet so we can just reference the first list item #} +{% for i in range(1, SURICATAMERGED.config['af-packet'][0].threads + 1) %} + +suripcapthread{{i}}dir: + file.directory: + - name: /nsm/suripcap/{{i}} + - user: 940 + - group: 939 + - mode: 775 + +{% endfor %} + +{% endif %} diff --git a/salt/suricata/soc_suricata.yaml b/salt/suricata/soc_suricata.yaml index 30f277c0a7..7decaa6d32 100644 --- a/salt/suricata/soc_suricata.yaml +++ b/salt/suricata/soc_suricata.yaml @@ -11,6 +11,60 @@ suricata: multiline: True title: SIDS helpLink: suricata.html + classification: + classification__config: + description: Classifications config file. + file: True + global: True + multiline: True + title: Classifications + helpLink: suricata.html + pcap: + filesize: + description: Max file size for individual PCAP files written by Suricata. Increasing this number could improve write performance at the expense of pcap retrieval times. + advanced: True + helplink: suricata.html + maxsize: + description: Size in GB for total usage size of PCAP on disk. + helplink: suricata.html + compression: + description: Enable compression of Suricata PCAP. + advanced: True + helpLink: suricata.html + lz4-checksum: + description: Enable PCAP lz4 checksum. + advanced: True + helpLink: suricata.html + lz4-level: + description: lz4 compression level of PCAP. 0 for no compression 16 for max compression. + advanced: True + helpLink: suricata.html + filename: + description: Filename output for Suricata PCAP. + advanced: True + readonly: True + helpLink: suricata.html + mode: + description: Suricata PCAP mode. Currently only multi is supported. + advanced: True + readonly: True + helpLink: suricata.html + use-stream-depth: + description: Set to "no" to ignore the stream depth and capture the entire flow. Set this to "yes" to truncate the flow based on the stream depth. + advanced: True + regex: ^(yes|no)$ + regexFailureMessage: You must enter either yes or no. + helpLink: suricata.html + conditional: + description: Set to "all" to capture PCAP for all flows. Set to "alerts" to capture PCAP just for alerts or set to "tag" to capture PCAP for just tagged rules. + regex: ^(all|alerts|tag)$ + regexFailureMessage: You must enter either all, alert or tag. + helpLink: suricata.html + dir: + description: Parent directory to store PCAP. + advanced: True + readonly: True + helpLink: suricata.html config: af-packet: interface: @@ -44,6 +98,7 @@ suricata: set-cpu-affinity: description: Bind(yes) or unbind(no) management and worker threads to a core or range of cores. regex: ^(yes|no)$ + regexFailureMessage: You must enter either yes or no. helpLink: suricata.html cpu-affinity: management-cpu-set: @@ -153,6 +208,12 @@ suricata: header: description: Header name where the actual IP address will be reported. helpLink: suricata.html + pcap-log: + enabled: + description: This value is ignored by SO. pcapengine in globals takes precidence. + readonly: True + helpLink: suricata.html + advanced: True asn1-max-frames: description: Maximum nuber of asn1 frames to decode. helpLink: suricata.html @@ -209,6 +270,9 @@ suricata: memcap: description: Can be specified in kb,mb,gb. helpLink: suricata.html + depth: + description: Controls how far into a stream that reassembly is done. + helpLink: suricata.html host: hash-size: description: Hash size in bytes. diff --git a/salt/telegraf/config.sls b/salt/telegraf/config.sls index 0711260b53..a35be55f51 100644 --- a/salt/telegraf/config.sls +++ b/salt/telegraf/config.sls @@ -41,6 +41,8 @@ tgraf_sync_script_{{script}}: - mode: 770 - template: jinja - source: salt://telegraf/scripts/{{script}} + - defaults: + GLOBALS: {{ GLOBALS }} {% endfor %} telegraf_sbin: diff --git a/salt/telegraf/map.jinja b/salt/telegraf/map.jinja index e6d3460d67..b56c8a64db 100644 --- a/salt/telegraf/map.jinja +++ b/salt/telegraf/map.jinja @@ -14,4 +14,11 @@ {% do TELEGRAFMERGED.scripts[GLOBALS.role.split('-')[1]].remove('zeekloss.sh') %} {% do TELEGRAFMERGED.scripts[GLOBALS.role.split('-')[1]].remove('zeekcaptureloss.sh') %} {% endif %} + +{% from 'pcap/config.map.jinja' import PCAPMERGED %} +{# PCAPMERGED.enabled is set false in soc ui or if suricata is the pcap engine #} +{% if not PCAPMERGED.enabled %} +{% do TELEGRAFMERGED.scripts[GLOBALS.role.split('-')[1]].remove('stenoloss.sh') %} +{% endif %} + {% endif %} diff --git a/salt/telegraf/scripts/oldpcap.sh b/salt/telegraf/scripts/oldpcap.sh index bb1be457f7..876ff7835a 100644 --- a/salt/telegraf/scripts/oldpcap.sh +++ b/salt/telegraf/scripts/oldpcap.sh @@ -5,13 +5,17 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. - +{%- if GLOBALS.pcap_engine in ["SURICATA", "TRANSITION"] %} +PCAPLOC=/host/nsm/suripcap +{%- else %} +PCAPLOC=/host/nsm/pcap +{%- endif %} # if this script isn't already running if [[ ! "`pidof -x $(basename $0) -o %PPID`" ]]; then # Get the data - OLDPCAP=$(find /host/nsm/pcap -type f -exec stat -c'%n %Z' {} + | sort | grep -v "\." | head -n 1 | awk {'print $2'}) + OLDPCAP=$(find $PCAPLOC -type f -exec stat -c'%n %Z' {} + | sort | grep -v "/\." | head -n 1 | awk {'print $2'}) DATE=$(date +%s) AGE=$(($DATE - $OLDPCAP)) diff --git a/salt/telegraf/scripts/stenoloss.sh b/salt/telegraf/scripts/stenoloss.sh index 5c27ee7a5d..5219dcfd0c 100644 --- a/salt/telegraf/scripts/stenoloss.sh +++ b/salt/telegraf/scripts/stenoloss.sh @@ -10,8 +10,8 @@ # if this script isn't already running if [[ ! "`pidof -x $(basename $0) -o %PPID`" ]]; then - CHECKIT=$(grep "Thread 0" /var/log/stenographer/stenographer.log |tac |head -2|wc -l) - STENOGREP=$(grep "Thread 0" /var/log/stenographer/stenographer.log |tac |head -2) + CHECKIT=$(grep "Thread 0 stats" /var/log/stenographer/stenographer.log |tac |head -2|wc -l) + STENOGREP=$(grep "Thread 0 stats" /var/log/stenographer/stenographer.log |tac |head -2) declare RESULT=($STENOGREP) diff --git a/salt/vars/globals.map.jinja b/salt/vars/globals.map.jinja index 3265cde183..ed7129678a 100644 --- a/salt/vars/globals.map.jinja +++ b/salt/vars/globals.map.jinja @@ -1,5 +1,6 @@ {% import 'vars/init.map.jinja' as INIT %} {% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'global/map.jinja' import GLOBALMERGED %} {% from 'vars/' ~ INIT.GRAINS.role.split('-')[1] ~ '.map.jinja' import ROLE_GLOBALS %} {# role is so-role so we have to split off the 'so' #} @@ -7,6 +8,7 @@ set GLOBALS = { 'hostname': INIT.GRAINS.nodename, 'is_manager': false, + 'is_sensor': false, 'manager': INIT.GRAINS.master, 'minion_id': INIT.GRAINS.id, 'main_interface': INIT.PILLAR.host.mainint, @@ -20,6 +22,7 @@ 'influxdb_host': INIT.PILLAR.global.influxdb_host, 'manager_ip': INIT.PILLAR.global.managerip, 'md_engine': INIT.PILLAR.global.mdengine, + 'pcap_engine': GLOBALMERGED.pcapengine, 'pipeline': INIT.PILLAR.global.pipeline, 'so_version': INIT.PILLAR.global.soversion, 'so_docker_gateway': DOCKER.gateway, @@ -61,5 +64,8 @@ {% do GLOBALS.update({'is_manager': true}) %} {% endif %} +{% if GLOBALS.role in GLOBALS.sensor_roles %} +{% do GLOBALS.update({'is_sensor': true}) %} +{% endif %} {% do salt['defaults.merge'](GLOBALS, ROLE_GLOBALS, merge_lists=False, in_place=True) %} diff --git a/setup/so-functions b/setup/so-functions index f0462e4d64..4aae0f5bd8 100755 --- a/setup/so-functions +++ b/setup/so-functions @@ -1812,7 +1812,7 @@ repo_sync_local() { mkdir -p /nsm/repo mkdir -p /opt/so/conf/reposync/cache echo "https://repo.securityonion.net/file/so-repo/prod/2.4/oracle/9" > /opt/so/conf/reposync/mirror.txt - echo "https://so-repo-east.s3.us-east-005.backblazeb2.com/prod/2.4/oracle/9" >> /opt/so/conf/reposync/mirror.txt + echo "https://repo-alt.securityonion.net/prod/2.4/oracle/9" >> /opt/so/conf/reposync/mirror.txt echo "[main]" > /opt/so/conf/reposync/repodownload.conf echo "gpgcheck=1" >> /opt/so/conf/reposync/repodownload.conf echo "installonly_limit=3" >> /opt/so/conf/reposync/repodownload.conf diff --git a/setup/so-setup b/setup/so-setup index ca1581ef90..e2de39f50e 100755 --- a/setup/so-setup +++ b/setup/so-setup @@ -687,10 +687,8 @@ if ! [[ -f $install_opt_file ]]; then logCmd "so-minion -o=setup" title "Creating Global SLS" - if [[ $is_airgap ]]; then - # Airgap Rules - airgap_rules - fi + # Airgap Rules + airgap_rules manager_pillar diff --git a/setup/so-whiptail b/setup/so-whiptail index ede138d26b..ff8c9fe8d5 100755 --- a/setup/so-whiptail +++ b/setup/so-whiptail @@ -195,10 +195,12 @@ whiptail_create_web_user() { [ -n "$TESTING" ] && return WEBUSER=$(whiptail --title "$whiptail_title" --inputbox \ - "Please enter an email address to create an administrator account for the Security Onion Console (SOC) web interface.\n\nThis will also be used for Elasticsearch and Kibana." 12 60 "$1" 3>&1 1>&2 2>&3) + "Please enter an email address to create an administrator account for the Security Onion Console (SOC) web interface.\n\nThis will also be used for Elasticsearch and Kibana.\n\nMust only include letters, numbers, or + - _ % . @ characters. All capitalized letters will be converted to lowercase." 15 60 "$1" 3>&1 1>&2 2>&3) local exitstatus=$? whiptail_check_exitstatus $exitstatus + + WEBUSER=${WEBUSER,,} } whiptail_create_web_user_password1() { diff --git a/sigs/securityonion-2.4.60-20240320.iso.sig b/sigs/securityonion-2.4.60-20240320.iso.sig new file mode 100644 index 0000000000..c0129ab64b Binary files /dev/null and b/sigs/securityonion-2.4.60-20240320.iso.sig differ