SecMindX 使用说明
SecMindX 使用说明(完整版)
SecMindX —— 本地 AI 增强型日志安全智能研判平台。
主程序负责定时批量分析日志(硬规则 + 本地大模型双引擎),Web 提供仪表盘、告警中心、Agent 管理、配置管理等功能。
本文按使用流程从安装到进阶逐项说明,供部署与日常运维参考。
一句话理解这个系统:
Agent 负责"收日志",主程序负责"读日志、找问题",Web 负责"给你看结果、让你动手处置"。
★ 快速上手(写给第一次用的人)
第 1 步:装好平台(见第 1 节),登录 Web,默认账号 admin / 密码 admin123,登录后马上改密码
第 2 步:把 ES 和大模型的地址填进【配置管理 → 基础配置】(见 2.2),保存
第 3 步:给要监控的电脑/服务器装上 Agent(见第 3 节),装完 Agent 自动把日志送上来
第 4 步:打开【安全仪表盘】,看到红色高危告警就点进去看详情
第 5 步:确认是攻击 → 封掉高危公开情报源 IP(见第 13 节);确认是误报 → 点"永久标记安全",让它以后别再吵
第 6 步:日志多了看不过来 → 开高速模式、做降噪(见第 4、5 节),越用越准
0、前置条件
- 平台服务器:Ubuntu 24.04 / 26(64 位),建议 4 核 8G 起步
- Elasticsearch 8.x(自备):本机或同网段可达;默认连接
- 本地大模型(推荐,可选):Ollama 或 vLLM + 模型(如 qwen2.5:3b),建议 RTX 30/40 系列 12G 及以上显卡;无显卡也可纯硬规则离线运行
- 目标机(被采集主机):Windows(Server 2016+ / Win10+)或 Linux(Ubuntu / CentOS / Debian / openEuler 等),需能访问平台 8888 端口
- 授权文件 license.lic(由厂商签发,与服务器绑定)
1、下载安装
1.0 安装 Elasticsearch(未自备 ES 时;使用清华镜像,解决官方源下载慢):
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 # 创建备份仓库目录 mkdir -p /opt/secmindx/backup/es-repo chown -R elasticsearch:elasticsearch /opt/secmindx/backup/es-repo # 配置备份仓库路径(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 # 重启使配置生效 sudo systemctl daemon-reload sudo systemctl enable --now elasticsearch.service #sudo systemctl status elasticsearch.service # 修改 elastic 用户密码(平台连接用) sudo /usr/share/elasticsearch/bin/elasticsearch-reset-password -u elastic -i
1.1 下载分卷并合并解压(Linux 服务器,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
- 安装脚本会部署到 /opt/secmindx 并注册 systemd 服务
1.2 验证Web登录:
浏览器访问 http://<平台IP>:8888,能打开登录页即安装成功。
默认账号:admin 密码:admin123 建议立即改密码
1.3 服务说明:
- secmindx-analyze:批处理分析任务(oneshot),由 timer 定时拉起,默认每 5 分钟一轮(可用 ANALYZE_INTERVAL_MIN=5 ./install.sh 调整)
常用命令:
systemctl status secmindx-web secmindx-analyze.timer journalctl -u secmindx-analyze -n 50 systemctl start secmindx-analyze # 手动立即跑一轮 systemctl restart secmindx-web
2、登录与初始设置
2.1 登录:默认账号 admin,默认密码 admin123(首次登录后请立即改密)。
改密位置:Web → 用户管理(Web 管理)→ 修改密码。
2.2 基础配置
- ES 连接:【配置管理】→【基础配置】→【elasticsearch】→ elasticsearch.hosts / username / password:改成你的 ES 实际地址与账号
- LLM 连接:【配置管理】→【基础配置】→【llm】→ llm.ollama.api_url / llm.vllm.api_url:改成你本地大模型服务地址
2.3 设置告警:
- 入口:【配置管理】→【基础配置】→【alert】
- alert.min_risk:告警最低级别(critical / high / medium)
- 告警通道(在 config.json alert 段开启):钉钉(webhook_url + secret)、企业微信、飞书、Telegram、Slack
- bilingual.enabled:告警内容中英双语(summary 中文 + 英文副本)
- 自动封禁(高危公开情报源 IP 封禁,Web 配置管理 → 自动封禁)
- 启用级别:high / critical / medium
- 作用域:全部节点 / 仅本机
- 时长:可设,到期自动解封
- 演练:封禁前可开 dry_run 演练
2.4 授权文件:
- License:上传 license.lic 放入 /opt/secmindx/(无授权主程序拒绝启动)。
2.5 其他保持默认即可。
3、Agent 批量安装
3.1 Web →【Agent 管理】 → 打开“自动注册”(批量安装用,装完关闭)。
3.2 Linux 目标机安装示例:
mkdir -p /opt/smxagent curl -o /opt/smxagent/SMXAgent-linux-amd64 \ http://<平台IP>:8888/agent-download/SMXAgent-linux-amd64 chmod +x /opt/smxagent/SMXAgent-linux-amd64 /opt/smxagent/SMXAgent-linux-amd64 -manager=http://<平台IP>:8888 --install
3.3 Windows 目标机安装示例:
管理员运行 PowerShell 代码:
mkdir -p "C:\Program Files\smxagent\" Invoke-WebRequest -Uri "http://<平台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://<平台IP>:8888 --install sc start "SMXAgent"
3.4 安装完成后 Agent 自动心跳上报,出现在 Agent 列表;
关闭自动注册后,新 Agent 需手动安装(帮助页有可复制命令)。
3.5 已支持平台:Windows(自动开启关键审计子类目)、主流 Linux(自动部署 auditd 规则)、交换机 / 防火墙 / vCenter 等网络设备。
4、高速模式(进阶)-大幅提升处理速度
Web →【配置管理】→ AI 节流(Pro) → 高速模式:默认打开
5、降噪
5.1 内置降噪:
- noise.system_accounts:SYSTEM / LOCAL SERVICE 等系统账户
- denoise.linux_commands / linux_contains / windows_event_ids:常见无害命令与事件 ID 白名单
5.2 永久标记安全(最重要的降噪手段):
告警中心 → 某条日志 → “永久标记安全”:
- 同特征(日志类型 + 主机 + 账号 + 事件 ID,按清洗后特征)的全部文档自动 ai_skip_user=true,之后不再进分析、不再告警
- 同时标记已处理,记录处置人 / 时间 / 备注。
5.3 特征文件:
- user_skip_features.json:用户自建安全特征
- secmindx_skip_features.json:内置安全特征
可在 Web 配置管理 → AI 节流中分页管理、删除。
6、过滤 Windows / Linux
- config.json:windows_security.enable / linux_security.enable 开关
- 日志类型:windows_event / linux / switch / firewall / vcenter / nginx / mysql / unknown
- 告警中心筛选:主机 / 来源 IP / 战术(ATT&CK)多条件过滤
7、Agent 进阶管理
- 分组:Agent 管理 → 分组,按部门/区域组织
- 升级:新 Agent 包放入 /opt/secmindx/releases/,平台下发更新
- 封禁 IP:自动封禁开关(级别/作用域/时长)+ 手动封禁
- 下发白名单:windows_security.rdp_safe_ips / linux_security.safe_ips / device_security.switch_safe_ips / firewall_safe_ips / vcenter_safe_ips
- 封禁高危:quick_ban 快速封禁接口(配置密钥)
- 更新 ES key:ES 加密密钥映射(es_key_map)更新后 Agent 重连自动换钥
8、日志分析处置
8.1 告警中心:
- 高危告警(critical/high)/ 中危(medium)/ 全部风险 / 全部日志(含 Info)
- 状态:未处理 / 已处理;支持主机、来源 IP、战术筛选
8.2 处置动作:
- 处置:标记已处理,写入处置时间与操作人
- 永久标记安全:同特征批量跳过 + 标记已处理(见第 5 节)
8.3 监控组(权限监控):
privilege_monitor.watch_local_groups(如 Administrators)与 watch_ad_groups(如 Domain Admins)组变更即告警。
8.4 关联分析(横向移动等):
内置攻击关联特征:RDP 多主机跳转、远程任务 4698、异常时间登录、服务安装 7045、暴力破解阈值(次数 + 时间窗口,可自定义)等。
9、交换机 / 防火墙/vcneter处理
- 支持主流交换机(华为 / 华三 / 思科等)、防火墙(如 FortiGate)、vCenter
- device_security:登录失败告警、非安全 IP 登录告警开关
10、特征提取
10.1 主程序对每条日志生成特征指纹:
- ai_sig_global:全局特征(type|event|清洗后消息)
- ai_sig_host:主机特征(type|host|user|event|清洗后消息)
10.2 Web → 智脑日志:
- 特征统计:按全局特征 / 主机特征聚合,支持排除 Info、按数量或字段排序、按时间区间(如近 1 天)过滤查询
- 查询结果用于观察同特征收敛质量、排查误伤
10.3 重新分析:
从 ES 清除“已分析标记”后,主程序会对全部日志重新分析(用于特征规则更新后的全量重算)
11、ES 优化(该项已自动处理)
11.1 查询超 10000 条限制:
WEB → 智脑日志 → 设置 ES 查询窗口大小
11.2 备份与还原(Web → 备份还原):
- 定时备份:每天 00:00 自动执行(独立线程)
- 手动备份:一键立即备份
- 备份目录:/opt/secmindx/backup/
- 恢复 ES 快照:维护窗口执行,可恢复 Agent key 等 ES 内数据
- 需在 elasticsearch.yml 配置 path.repo:
path.repo: ["/opt/secmindx/backup/es-repo"](编辑后重启 ES) - 初始化备份仓库目录(配置 path.repo 后执行一次):
mkdir -p /opt/secmindx/backup/es-repo chown -R elasticsearch:elasticsearch /opt/secmindx/backup/es-repo systemctl restart elasticsearch
12、大模型优化
- workers.max_workers:分析并发(默认 50)
- llm.vllm / llm.ollama:api_url、model、timeout(默认 120s)、temperature(默认 0.1)、max_tokens(默认 256)
- analysis.max_logs_per_batch:每批最大日志数
- 并发过高时可调低 max_workers / 调大 timeout,避免 LLM 服务超载
13、高危公开情报源 IP 封禁(重点)
这是什么:
- 平台会比对公开威胁情报源(业界公开维护的高危 IP 情报库),
凡是命中情报库的 IP 视为高危攻击源,可自动下发封禁,从源头阻断攻击。
- 这类 IP 通常在情报库中被标记为恶意 / 暴力破解 / 僵尸网络 / 扫描器等,
不是你们公司内部的正常 IP。
和"风险 IP"的关系:
- 情报源命中 → 高危公开情报源 IP(本节能封的对象)
- AI 分析出的攻击源 → 普通风险 IP(也可手动封,见下"手动封禁")
怎么封(两种方式):
方式一:自动封禁(推荐,长期有效)
Web → 配置管理 → 自动封禁卡片:
- 启用级别:勾选要封的级别(high 高危 / critical 极危 / medium 中危)
- 作用域:全部节点(所有装了 Agent 的机器都封)或 仅本机
- 时长:封多久(小时),到期自动解封
- 演练开关(dry_run):建议先打开"演练"跑几天,只观察"会封哪些 IP"但不下真封,确认没有误伤后再真正启用
方式二:手动封禁(临时应急)
告警中心 / Agent 管理 → 对指定的来源 IP 一键封禁。
封禁前必须确认(防误伤):
- 个别情况下公开情报库可能误报,先把你们公司出口、运维、堡垒机 IP
提前加进白名单(见第 7 节:rdp_safe_ips / safe_ips 等),
白名单里的 IP 永不封禁
- 拿不准的,先只封"仅本机",影响最小
封禁后:
- 时长到期自动解封,也可手动解除
- 封禁是"止血",还要配合处置:确认是攻击的继续溯源,是误报的做
"永久标记安全",避免同一个 IP 反复误封
常见问题
Q1 忘记密码?
- 默认 admin/admin123;改过密码后遗忘,可重置 config.json 中 web.password_hash 为 sha256("新密码") 后重启 web。
Q2 交换机防火墙如何接入?
- sudo apt install logstash -y
- logstash 配置如下:
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
名词解释(通俗版)
| Agent | 装在每台被监控机器上的"小哨兵",负责采集日志上报平台 |
| ES(Elasticsearch) | 存放和检索日志的数据库 |
| 大模型(LLM) | AI 大脑,读日志并给出风险结论 |
| 硬规则 | 内置的固定安全规则,不依赖 AI 也能识别常见攻击 |
| 特征(ai_sig) | 日志的"指纹",同类事件指纹相同,用于批量归类 |
| 降噪 | 把无害日志过滤掉,只留真正需要看的 |
| 告警 | 发现风险后通过钉钉/企微等推送给你的通知 |
| 封禁 | 阻断某个 IP 访问你的机器 |
| 白名单 | 永不封禁、永不告警的合法 IP / 账号清单 |
| 处置 / 已处理 | 人工看完确认处理过 |
| 分析时间 | AI 看完这条日志的时刻;日志时间 = 日志本身产生的时刻 |
| AI 节流 | 相同特征只分析一次,后续直接复用结果,省算力 |
| 已分析标记 | 日志是否被 AI 看过的记号;清除后主程序会重新分析全部 |