SecMindX User Guide
Quick Start (for first-time users)
- Step 1: Install the platform (Section 1), open the Web; default account admin / password admin123 - change the password right after first login
- Step 2: Fill in the ES and LLM endpoints in [Config -> Base Config] (see 2.2) and save
- Step 3: Install the Agent on the machines/servers you want to monitor (Section 3); logs are uploaded automatically once installed
- Step 4: Open [Security Dashboard]; click into any red high-risk alert for details
- Step 5: Confirmed attack -> block the high-risk threat-intel source IP (Section 13); confirmed false positive -> click "Mark Safe Forever" so it stops bothering you
- Step 6: Too many logs to review -> enable high-speed mode and noise reduction (Sections 4, 5); it gets more accurate over time
0. Prerequisites
- Server: Ubuntu 24.04 / 26 (64-bit), 4 cores / 8 GB RAM recommended
- Elasticsearch 8.x (self-provided): reachable on this host or the same network; default connection
- Local LLM (recommended, optional): Ollama or vLLM + model (e.g. qwen2.5:3b); RTX 30/40 series 12 GB+ GPU recommended; hard rules still run fully offline without a GPU
- Target hosts: Windows (Server 2016+ / Win10+) or Linux (Ubuntu / CentOS / Debian / openEuler etc.), must be able to reach platform port 8888
- License file license.lic (issued by the vendor, bound to the server)
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
- The installer deploys to /opt/secmindx and registers systemd services
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:
- secmindx-analyze: batch analysis task (oneshot), started by a timer every 5 minutes by default (adjust with ANALYZE_INTERVAL_MIN=5 ./install.sh)
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:
- ES connection: [Config] -> [Base Config] -> [elasticsearch] -> elasticsearch.hosts / username / password: set to your actual ES address and credentials
- LLM connection: [Config] -> [Base Config] -> [llm] -> llm.ollama.api_url / llm.vllm.api_url: set to your local LLM service endpoint
2.3 Alerts:
- Entry: [Config] -> [Base Config] -> [alert]
- alert.min_risk: minimum alert level (critical / high / medium)
- Alert channels (enable in the config.json alert section): DingTalk (webhook_url + secret), WeCom, Feishu, Telegram, Slack
- bilingual.enabled: bilingual alert content (Chinese summary + English copy)
- Auto block (high-risk threat-intel IP blocking, Web Config -> Auto Block)
- Levels: high / critical / medium
- Scope: all nodes / this host only
- Duration: configurable, auto-unblock on expiry
- Dry run: enable dry_run first to rehearse
2.4 License:
- License: upload license.lic to /opt/secmindx/ (the main process refuses to start without a 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:
- noise.system_accounts: SYSTEM / LOCAL SERVICE and other system accounts
- denoise.linux_commands / linux_contains / windows_event_ids: whitelists of common harmless commands and event IDs
5.2 Mark Safe Forever (the most important noise-reduction tool):
Alert Center -> a log -> "Mark Safe Forever":
- All documents with the same feature (log type + host + account + event ID, based on cleaned features) get ai_skip_user=true automatically; they no longer enter analysis or alert
- Also marked handled, recording the handler / time / note
5.3 Feature files:
- user_skip_features.json: user-defined safe features
- secmindx_skip_features.json: built-in safe features
Manage and delete them with pagination in Web Config -> AI Throttling.
6. Filter Windows / Linux
- config.json: windows_security.enable / linux_security.enable switches
- Log types: windows_event / linux / switch / firewall / vcenter / nginx / mysql / unknown
- Alert Center filters: host / source IP / tactic (ATT&CK) multi-condition filtering
7. Agent Advanced Management
- Groups: Agent Management -> Groups, organize by department / region
- Upgrade: put new Agent packages in /opt/secmindx/releases/, the platform pushes updates
- IP blocking: auto-block switch (level / scope / duration) + manual block
- Whitelist push: windows_security.rdp_safe_ips / linux_security.safe_ips / device_security.switch_safe_ips / firewall_safe_ips / vcenter_safe_ips
- Quick ban: quick_ban fast-block API (configure the key)
- ES key update: Agents reconnect and rotate keys after the es_key_map mapping is updated
8. Log Analysis & Handling
8.1 Alert Center:
- High-risk (critical/high) / medium / all risks / all logs (incl. Info)
- Status: unhandled / handled; filter by host, source IP, tactic
8.2 Actions:
- Handle: mark as handled, write the handling time and operator
- Mark Safe Forever: batch-skip the same features + mark handled (see Section 5)
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
- Supports mainstream switches (Huawei / H3C / Cisco etc.), firewalls (e.g. FortiGate), vCenter
- device_security: login-failure alerts, non-safe-IP login alert switches
10. Feature Extraction
10.1 The main process generates a feature fingerprint for every log:
- ai_sig_global: global feature (type|event|cleaned message)
- ai_sig_host: host feature (type|host|user|event|cleaned message)
10.2 Web -> Brain Logs:
- Feature stats: aggregate by global feature / host feature; supports excluding Info, sorting by count or field, filtering by time range (e.g. last 1 day)
- Results are used to observe convergence quality of the same feature and debug false positives
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):
- Scheduled backup: runs automatically every day at 00:00 (dedicated thread)
- Manual backup: one-click immediate backup
- Backup directory: /opt/secmindx/backup/
- Restore ES snapshot: run in a maintenance window; can restore Agent keys and other ES data
- Configure in elasticsearch.yml:
path.repo: ["/opt/secmindx/backup/es-repo"](restart ES after editing) - Initialize the snapshot repository directory (run once after configuring path.repo):
mkdir -p /opt/secmindx/backup/es-repo chown -R elasticsearch:elasticsearch /opt/secmindx/backup/es-repo systemctl restart elasticsearch
12. LLM Optimization
- workers.max_workers: analysis concurrency (default 50)
- llm.vllm / llm.ollama: api_url, model, timeout (default 120s), temperature (default 0.1), max_tokens (default 256)
- analysis.max_logs_per_batch: maximum logs per batch
- If concurrency is too high, lower max_workers / raise timeout to avoid overloading the LLM service
13. High-Risk Threat-Intel IP Blocking (Key)
What this is:
- The platform compares against public threat-intel sources (publicly maintained high-risk IP feeds); any IP that hits the feed is treated as a high-risk attack source and can be auto-blocked at the source
- Such IPs are usually flagged in the feeds as malicious / brute-forcing / botnet / scanner; they are not your normal internal IPs
Relation to "risk IPs":
- Threat-intel hit -> high-risk threat-intel IP (what this section blocks)
- AI-identified attack source -> normal risk IP (also manually blockable, see "manual block" below)
How to block (two ways):
Method 1: Auto block (recommended, persistent)
Web -> Config -> Auto Block card:
- Levels: choose the levels to block (high / critical / medium)
- Scope: all nodes (every machine with the Agent) or this host only
- Duration: how long to block (hours), auto-unblock on expiry
- Dry run: enable dry_run first for a few days to see "which IPs would be blocked" without real blocking; go live only after confirming no false positives
Method 2: Manual block (temporary)
Alert Center / Agent Management -> one-click block of a specified source IP.
Before blocking, confirm (avoid false positives):
- Public feeds can occasionally misreport; whitelist your company egress, O&M and bastion IPs first (Section 7: rdp_safe_ips / safe_ips etc.); whitelisted IPs are never blocked
- When unsure, block "this host only" first for the smallest impact
After blocking:
- Auto-unblock on expiry; manual unblock also possible
- Blocking is "first aid"; combine it with handling: keep investigating confirmed attacks, mark false positives "Mark Safe Forever" so the same IP is not repeatedly blocked
FAQ
Q1 Forgot the password?
- Default admin/admin123; if you changed it and forgot it, reset web.password_hash in config.json to sha256("new password") and restart web.
Q2 How do switches / firewalls connect?
- sudo apt install logstash -y
- Logstash config below:
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)
| Agent | the "little sentinel" on each monitored machine; collects logs and reports them to the platform |
| ES (Elasticsearch) | the database that stores and searches logs |
| LLM | the AI brain; reads logs and gives risk verdicts |
| Hard rules | built-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 reduction | filter out harmless logs and keep only what really needs attention |
| Alert | a notification pushed to you (DingTalk / WeCom etc.) when risk is found |
| Block | stop a specific IP from reaching your machines |
| Whitelist | a list of legitimate IPs / accounts that are never blocked or alerted |
| Handled | reviewed and confirmed by a human |
| Analysis time | when the AI finished reviewing this log; log time = when the log itself was produced |
| AI throttling | analyze each feature once and reuse the result later, saving compute |
| Analyzed marker | whether a log has been reviewed by AI; clearing it makes the main process re-analyze everything |