SecMindX User Guide

Local AI-Enhanced Log Security Intelligence Platform · Install / Daily Ops / Advanced Optimization · Back to the site

Quick Start (for first-time users)

0. Prerequisites

1. Download & Install

1.0 Install Elasticsearch (skip if you already have ES; Tsinghua mirror for faster downloads):

wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://mirrors.tuna.tsinghua.edu.cn/elasticstack/8.x/apt/ stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.list
sudo apt update
sudo apt install elasticsearch
# Create backup repository directory
mkdir -p /opt/secmindx/backup/es-repo
chown -R elasticsearch:elasticsearch /opt/secmindx/backup/es-repo
# Configure backup repository path (path.repo)
grep -q 'path.repo:' /etc/elasticsearch/elasticsearch.yml || echo 'path.repo: ["/opt/secmindx/backup/es-repo"]' | sudo tee -a /etc/elasticsearch/elasticsearch.yml
# Restart to apply the config
sudo systemctl daemon-reload
sudo systemctl enable --now elasticsearch.service
#sudo systemctl status elasticsearch.service
# Set the elastic password (used by the platform)
sudo /usr/share/elasticsearch/bin/elasticsearch-reset-password -u elastic -i

1.1 Download the parts, merge and extract (Linux server, as root):

wget https://www.secmindx.com/secmindx_aa && \
wget https://www.secmindx.com/secmindx_ab && \
cat secmindx_aa secmindx_ab > secmindx.tar.gz && \
tar xzf secmindx.tar.gz && \
cd secmindx && \
chmod +x install.sh && \
sudo ./install.sh

1.2 Verify the Web login:

Open http://<server-IP>:8888 in a browser; if the login page opens, installation succeeded.

Default account admin / password admin123 - change it immediately.

1.3 Services:

Common commands:

systemctl status secmindx-web secmindx-analyze.timer
journalctl -u secmindx-analyze -n 50
systemctl start secmindx-analyze   # run one round manually
systemctl restart secmindx-web

2. Login & Initial Setup

2.1 Login: default account admin, default password admin123 (change it immediately after first login).

Change password: Web -> User Management (Web Admin) -> Change Password.

2.2 Base Config:

2.3 Alerts:

2.4 License:

2.5 Keep everything else at defaults.

3. Agent Bulk Installation

3.1 Web -> [Agent Management] -> turn on "Auto Register" (for bulk installation; turn it off when done).

3.2 Linux target example:

mkdir -p /opt/smxagent
curl -o /opt/smxagent/SMXAgent-linux-amd64 \
     http://<server-IP>:8888/agent-download/SMXAgent-linux-amd64
chmod +x /opt/smxagent/SMXAgent-linux-amd64
/opt/smxagent/SMXAgent-linux-amd64 -manager=http://<server-IP>:8888 --install

3.3 Windows target example (run PowerShell as Administrator):

mkdir -p "C:\Program Files\smxagent\"
Invoke-WebRequest -Uri "http://<server-IP>:8888/agent-download/SMXAgent-windows-amd64.exe" -OutFile "C:\Program Files\smxagent\\SMXAgent.exe"
cmd
cd "C:\Program Files\smxagent\"
SMXAgent.exe -manager=http://<server-IP>:8888 --install
sc start "SMXAgent"

3.4 After installation the Agent heartbeats automatically and appears in the Agent list; with auto-register off, new Agents must be installed manually (copyable command on the Help page).

3.5 Supported platforms: Windows (key audit subcategories enabled automatically), mainstream Linux (auditd rules deployed automatically), switches / firewalls / vCenter and other network devices.

4. High-Speed Mode (Advanced) - dramatically faster

Web -> [Config] -> AI Throttling (Pro) -> High-Speed Mode: enabled by default

5. Noise Reduction

5.1 Built-in denoise:

5.2 Mark Safe Forever (the most important noise-reduction tool):

Alert Center -> a log -> "Mark Safe Forever":

5.3 Feature files:

Manage and delete them with pagination in Web Config -> AI Throttling.

6. Filter Windows / Linux

7. Agent Advanced Management

8. Log Analysis & Handling

8.1 Alert Center:

8.2 Actions:

8.3 Monitored groups (privilege monitoring): privilege_monitor.watch_local_groups (e.g. Administrators) and watch_ad_groups (e.g. Domain Admins) alert when membership changes.

8.4 Correlation (lateral movement etc.): built-in attack correlation features - RDP multi-host hops, remote task 4698, abnormal-time login, service install 7045, brute-force threshold (count + time window, configurable) and more.

9. Switch / Firewall / vCenter

10. Feature Extraction

10.1 The main process generates a feature fingerprint for every log:

10.2 Web -> Brain Logs:

10.3 Re-analyze: after clearing the "analyzed" markers in ES, the main process re-analyzes all logs (full recompute after feature-rule updates).

11. ES Optimization((This item has been automatically processed))

11.1 Query limit above 10000 results: Web -> Brain Logs -> set the ES query window size

11.2 Backup & Restore (Web -> Backup & Restore):

12. LLM Optimization

13. High-Risk Threat-Intel IP Blocking (Key)

What this is:

Relation to "risk IPs":

How to block (two ways):

Method 1: Auto block (recommended, persistent)

Web -> Config -> Auto Block card:

Method 2: Manual block (temporary)

Alert Center / Agent Management -> one-click block of a specified source IP.

Before blocking, confirm (avoid false positives):

After blocking:

FAQ

Q1 Forgot the password?

Q2 How do switches / firewalls connect?

sudo tee /etc/logstash/conf.d/beats.conf >/dev/null <<'EOF'
# AI-SIEM pipeline: beats + UDP syslog
input {
  beats { port => 5044 }
  udp {
    port => 5140
    host => "0.0.0.0"
    codec => plain { charset => "ASCII-8BIT" }
  }
}
filter {
  # GBK转UTF8,放在最前面,先处理原始消息编码
  ruby {
    code => '
        raw_msg = event.get("message")
        if raw_msg
            begin
                fixed_msg = raw_msg.force_encoding("GBK").encode("UTF-8", :invalid => :replace, :undef => :replace)
                event.set("message", fixed_msg)
            rescue
            end
        end
    '
  }

  #1. copy fields.log_type -> log_type
  if ![log_type] and [fields][log_type] {
    mutate { add_field => { "log_type" => "%{[fields][log_type]}" } }
  }
  #2. Ruby: use host[ip] to auto set log_type (log_type为空时,按来源IP自动分类)
  if ![log_type] and [host][ip] {
    ruby {
      code => '
        require "ipaddr" unless defined?(IPAddr)
        $ai_rules ||= {
          "switch"   => ["10.100.100.11", "10.100.100.12"],
          "firewall" => ["10.100.100.1", "10.100.100.4"],
          "vcenter"  => ["172.16.1.107", "172.16.1.49"]
        }
        ip = event.get("[host][ip]").to_s rescue ""
        begin
          o = IPAddr.new(ip)
          $ai_rules.each do |t, exprs|
            hit = exprs.any? do |e|
              if e.include?("/")
                IPAddr.new(e).include?(o)
              elsif e.include?("-")
                a,b = e.split("-",2)
                v = o.to_i
                v >= IPAddr.new(a.strip).to_i && v <= IPAddr.new(b.strip).to_i
              else
                e.strip == ip
              end
            end
            if hit
              event.set("log_type", t)
              break
            end
          end
        rescue => e
        end
      '
    }
  }
  #3 Windows Event
  if [log_type] == "windows_event" {
    if [winlog][event_id] not in [4624,4625,4778,4779,4672,1074,6005,6006] and [winlog][event_id] in [0,2,3,7,15,32,36,102,103,105,151,216,256,257,258,300,301,302,326,400,513,700,701,754,900,902,903,1000,1001,1003,1008,1011,1014,1015,1033,1035,1042,1066,1500,1501,1502,1503,1511,1704,1803,2001,2003,2005,2006,2048,2049,2319,2887,3006,4101,4201,4768,4771,5805,5857,6003,6394,7035,7036,7040,7041,8033,8193,8194,8197,8224,8230,9027,12289,16384,16394,16998,20021,20022,23022] {
        drop {}
    }
    mutate {
      replace => { "log_type" => "windows_event" }
      add_field => { "[@metadata][idx]" => "windows_event-log-%{+YYYY.MM.dd}" }
    }
    if [winlog][event_id] {
      mutate { add_field => { "event_id" => "%{[winlog][event_id]}" } }
    }
    if [winlog][event_id] == 4625 { mutate { add_tag => ["login_failed", "security_alert"] } }
    if [winlog][event_id] == 4624 { mutate { add_tag => ["login_success"] } }
    if [winlog][event_id] == 4720 { mutate { add_tag => ["account_created", "security_alert"] } }
    if [winlog][event_id] == 4728 { mutate { add_tag => ["domain_group_change", "security_alert"] } }
    if [winlog][event_id] == 4732 { mutate { add_tag => ["local_group_change", "security_alert"] } }
    if [winlog][event_id] == 4776 { mutate { add_tag => ["credential_validate"] } }
    if [winlog][event_id] == 4768 { mutate { add_tag => ["kerberos_tgt"] } }
    if [winlog][event_id] == 4771 { mutate { add_tag => ["kerberos_preauth_failed"] } }
    if [winlog][event_id] == 5722 { mutate { add_tag => ["secure_channel_failed", "security_alert"] } }
    if [winlog][event_id] == 7036 { mutate { add_tag => ["service_state_change"] } }
  }
  #4 Linux
  if [log_type] == "linux" {
    mutate {
      replace => { "log_type" => "linux" }
      add_field => { "[@metadata][idx]" => "linux-log-%{+YYYY.MM.dd}" }
    }
  }
  #5 Nginx
  if [log_type] == "nginx" {
    mutate {
      replace => { "log_type" => "nginx" }
      add_field => { "[@metadata][idx]" => "nginx-log-%{+YYYY.MM.dd}" }
    }
  }
  #6 MySQL
  if [log_type] == "mysql" {
    mutate {
      replace => { "log_type" => "mysql" }
      add_field => { "[@metadata][idx]" => "mysql-log-%{+YYYY.MM.dd}" }
    }
  }
  #7 Switch
  if [log_type] == "switch" {
    mutate {
      replace => { "log_type" => "switch" }
      add_field => { "[@metadata][idx]" => "switch-log-%{+YYYY.MM.dd}" }
    }
  }
  #8 Firewall Fortinet
  if [log_type] == "firewall" {
    mutate {
      replace => { "log_type" => "firewall" }
      add_field => { "[@metadata][idx]" => "firewall-log-%{+YYYY.MM.dd}" }
    }
    grok {
      match => { "message" => "<%{POSINT:syslog_pri}>%{GREEDYDATA:msg_raw}" }
    }
    kv {
      source => "msg_raw"
      field_split => " "
      value_split => "="
      trim_key => """
      trim_value => """
    }
    if [srcip] {
      mutate { add_field => { "src_zone" => "internet" } }
      cidr {
        address => [ "%{srcip}" ]
        network => [
          "10.10.10.0/24",
          "10.20.20.0/24",
          "10.0.0.0/8",
          "172.16.0.0/12",
          "192.168.0.0/16"
        ]
        add_field => { "src_zone" => "internal" }
      }
    }
    if [dstip] {
      mutate { add_field => { "dst_zone" => "internet" } }
      cidr {
        address => [ "%{dstip}" ]
        network => [
          "10.10.10.0/24",
          "10.20.20.0/24",
          "10.0.0.0/8",
          "172.16.0.0/12",
          "192.168.0.0/16"
        ]
        add_field => { "dst_zone" => "internal" }
      }
    }
    mutate {
      convert => {
        "srcport" => "integer"
        "dstport" => "integer"
        "policyid" => "integer"
      }
    }
    if [date] and [time] {
      mutate {
        add_field => {
          "[@metadata][forti_time]" => "%{[date]} %{[time]}"
        }
      }
      date {
        match => [ "[@metadata][forti_time]", "yyyy-MM-dd HH:mm:ss" ]
        target => "@timestamp"
      }
    }
  }
  #9 vCenter
  if [log_type] == "vcenter" {
    mutate {
      replace => { "log_type" => "vcenter" }
      add_field => { "[@metadata][idx]" => "vcenter-log-%{+YYYY.MM.dd}" }
    }
  }
  #10 unknown
  if ![@metadata][idx] {
    mutate {
      replace => { "log_type" => "unknown" }
      add_field => { "[@metadata][idx]" => "unknown-log-%{+YYYY.MM.dd}" }
      add_tag => ["unknown_log_type"]
    }
  }
  #11 device_ip / device_hostname
  if [log_type] in ["switch", "firewall", "vcenter", "unknown"] and [host][ip] {
    mutate {
      add_field => {
        "device_ip"       => "%{[host][ip]}"
        "device_hostname" => "%{[host][name]}"
      }
    }
  }
  #12 node_id
  if [log_type] in ["switch", "firewall", "vcenter", "unknown"] {
    if [device_hostname] and [device_hostname] != "-" {
      mutate { add_field => { "node_id" => "%{[device_hostname]}" } }
    } else if [device_ip] {
      mutate { add_field => { "node_id" => "%{[device_ip]}" } }
    } else {
      mutate { add_field => { "node_id" => "unknown-node" } }
    }
  } else if [log_type] in ["windows_event", "linux", "nginx", "mysql"] {
    if [host][id] {
      mutate { add_field => { "node_id" => "%{[host][id]}" } }
    } else if [agent][id] {
      mutate { add_field => { "node_id" => "%{[agent][id]}" } }
    } else if [host][name] {
      mutate { add_field => { "node_id" => "%{[host][name]}" } }
    }
  }
}
output {
  elasticsearch {
    hosts => ["https://127.0.0.1:9200"]
    user => "elastic"
    password => "password"
    ssl_enabled => true
    ssl_verification_mode => "none"
    index => "%{[@metadata][idx]}"
  }
  # stdout { codec => rubydebug }
}
EOF

Glossary (plain language)

Agentthe "little sentinel" on each monitored machine; collects logs and reports them to the platform
ES (Elasticsearch)the database that stores and searches logs
LLMthe AI brain; reads logs and gives risk verdicts
Hard rulesbuilt-in fixed security rules that catch common attacks without AI
Feature (ai_sig)the log "fingerprint"; identical events share the same fingerprint for batch grouping
Noise reductionfilter out harmless logs and keep only what really needs attention
Alerta notification pushed to you (DingTalk / WeCom etc.) when risk is found
Blockstop a specific IP from reaching your machines
Whitelista list of legitimate IPs / accounts that are never blocked or alerted
Handledreviewed and confirmed by a human
Analysis timewhen the AI finished reviewing this log; log time = when the log itself was produced
AI throttlinganalyze each feature once and reuse the result later, saving compute
Analyzed markerwhether a log has been reviewed by AI; clearing it makes the main process re-analyze everything