Wazuh安全检测实验室搭建与规则调优实战全记录
在安全运营里最怕的不是攻击者有多强而是部署了一堆安全设备之后根本不知道它在关键时刻能不能发现问题。Wazuh这类开源平台之所以这几年越来越火就是因为它把采集、解析、规则匹配、告警、可视化和响应串成了一条完整链路而且所有环节都可以自己动手调特别适合用来搭建检测实验室。这篇文章我打算以一套真实的Wazuh检测实验环境为主线完整记录从选型、部署、Agent接入到规则编写、攻击模拟、问题排查的全过程。目标只有一个让你看完之后能自己复现出这套环境并且掌握最基本的检测规则调优方法。这套实验环境我是按照一个“小型SOC”的模型来搭的包含1台Wazuh管理端、2台不同用途的Agent主机以及1台攻击机。整体思路是先让平台运转起来再用三种高频攻击手法去验证检测能力最后再针对踩过的坑做一轮系统性的排查和优化。无论你是安全工程师、运维人员还是刚入门SIEM/HIDS的学生都可以把这套流程当作一个低成本练手项目很多调优逻辑和排查思路也能平移到商业SIEM产品上。1. 检测实验室整体设计与核心思路1.1 为什么用Wazuh搭检测实验室通俗一点说Wazuh是一个开源的统一安全监控平台可以把它理解成“OSSEC的现代化升级版加SIEM外壳”。它在主机侧安装Agent收集系统日志、文件变化、进程行为、注册表改动等信息上传到服务端做集中分析和告警服务端再配合底层的Elasticsearch索引和Kibana可视化面板把海量日志变成可检索、可下钻的安全事件。它同时具备HIDS主机入侵检测、日志分析、FIM文件完整性监控、rootkit检测、漏洞管理和主动响应能力很多小型安全团队甚至直接拿它替代商业日志审计系统。之所以选Wazuh来做“检测实验室”有一个很现实的原因商业SIEM的规则引擎大多不透明规则写错了很难看到底层到底为什么没触发而Wazuh的整个链路从解码器到规则匹配都是开放的出了问题能一层一层往下查。这种透明度对学习检测逻辑、培养告警调优手感特别关键。打个比方商业SIEM像一个装修好的暗房你只能看到报警灯亮不亮Wazuh则是一间通透的操作间每一根电线都能顺着摸到非常适合做实验和踩坑。从成本和复现角度看Wazuh完全开源免费虚拟机上就能部署。你不需要有真实的生产环境只要在实验网段里模拟几台主机就能把恶意登录、Webshell上传、rootkit隐藏这些攻击场景原样跑一遍观察告警从无到有的完整过程。这就是我决定用它搭检测实验室最直接的理由可控、可反复操作、数据透明。1.2 检测数据流与核心模块的角色分工理解Wazuh的数据流是后面所有规则调优的基础。一条日志从产生到变成告警大致经历四个环节Agent采集、Manager解析与匹配、Indexer索引存储、Dashboard展示。Agent端主要跑三个模块logcollector负责读取各种日志文件syscheck负责监控文件/目录的完整性变化rootcheck负责周期性地扫描主机上的rootkit特征。采集到的数据通过加密通道发送给Manager端。Manager端内部有一个规则引擎会先用“解码器”把原始日志翻译成统一的JSON结构再交给规则库逐条比对一旦匹配到规则且level达到告警阈值就生成一条告警事件。Manager输出的告警和事件会被送到Indexer做全文索引最终在Dashboard上以图表、表格和详情页的形式呈现出来。你可以这样理解这条链路Agent像派驻在每台主机上的“观察员”负责记录现场Manager是“情报分析中心”把各个观察员的报告解析成标准化格式后再按规则研判Indexer就是“档案库”把所有研判结果分门别类存好Dashboard则是“指挥大屏”让安全人员一眼看到当前态势。这套架构最大的好处是每一层职责单一出问题的时候定位路径非常清晰日志没到Manager就是采集问题到了Manager没触发告警就是解码或规则问题告警有了但看不到就是索引或展示问题。1.3 实验环境拓扑与版本选型我做实验时使用了4台虚拟机全部跑在VirtualBox上虚拟网卡同处于一个Host-Only网络这样既隔离了外网干扰也方便复现和重置。具体拓扑如下主机角色操作系统与配置安装组件用途Manager节点Ubuntu 22.044核8G内存80G磁盘Wazuh Manager Indexer Dashboard服务端集成环境承担解码、规则匹配、存储、展示Web靶机AgentUbuntu 22.042核4G内存40G磁盘Wazuh Agent Apache PHP模拟对外Web业务用于Webshell检测实验文件服务器AgentUbuntu 22.042核2G内存40G磁盘Wazuh Agent模拟内网文件服务器用于文件完整性与rootkit检测实验攻击机Kali Linux2核4G内存40G磁盘hydra、curl、nmap等模拟攻击者视角向靶机发起定向攻击版本选型上我选择了Wazuh 4.x的当前稳定版本。这里有一个建议不要盲目追最新版尽量选发布超过半年、社区反馈稳定的大版本。毕竟实验室要的是可重复的实验结果版本迭代太频繁会导致网上查到的规则语法和老版本不兼容反而浪费时间。网络规划相对简单所有节点处于192.168.56.0/24网段Manager固定为192.168.56.10Web靶机为192.168.56.20文件服务器为192.168.56.30攻击机为192.168.56.100。Agent与Manager之间的通信固定使用1514/TCP数据和1515/TCP注册这两条端口在实验环境里必须在防火墙上放行。2. 环境部署与Agent接入完整流程2.1 实验机准备与系统初始化很多人装Wazuh失败问题往往不在Wazuh本身而是底层系统环境没准备好。建议所有虚拟机安装Ubuntu Server 22.04安装时选择最小化不装任何额外的图形界面。系统起来之后第一件事是设置静态IP避免虚拟网卡DHCP分配导致IP漂移否则Agent配好之后一旦IP变了整个链路就断了排查起来非常痛苦。时间同步这件事特别容易被忽略但SIEM系统对时间一致性极其敏感。如果管理端和Agent的系统时间差了十几秒告警时间线就会出现错乱攻击还原时前后顺序根本对不上。我习惯在每台虚拟机上安装chrony并指向同一个时间源做实验之前先确认各节点timedatectl输出基本一致。除此之外8G内存的Manager节点建议加上4G的swap因为Elasticsearch全家桶启动时内存波动比较大物理内存不够容易被OOM Killer杀掉进程加swap虽然性能一般但能保证实验不中断。2.2 Wazuh服务端快速部署管理端快速部署最省事的方式是官方提供的集成脚本它会自动把Wazuh Manager、Indexer和Dashboard全部装好并生成初始证书和密码。在Manager节点上执行curl -s https://packages.wazuh.com/4.x/wazuh-install.sh | bash -s这个脚本跑完之后屏幕会输出Dashboard的访问地址和初始用户名、密码同时在当前目录生成wazuh-install-files.tar.gz里面保存了证书和密码文件。不少第一次用的人栽在“没有备份密码文件”上装完重启后找不到密码只能重置admin用户这点一定要留意——安装完成先把这个压缩包复制到安全位置保存起来。脚本执行完毕后浏览器访问https://192.168.56.10使用admin用户登录。这里有两个注意点一是Dashboard默认使用自签名证书浏览器首次访问会提示不信任实验环境直接放行即可二是首次登录之后建议立即修改admin密码修改命令在Manager节点上执行/var/ossec/bin/wazuh-passwords-tool -u admin -p NewStrongPassword内存规划方面官方集成脚本默认给Indexer的JVM堆内存设置为4G如果你手头只有8G内存的机器这套配置跑起来会很紧。建议安装完成后编辑/etc/wazuh-indexer/jvm.options把-Xms和-Xmx都改成2G然后重启wazuh-indexer服务否则后续做攻击模拟时极容易出现Indexer无响应的情况。2.3 Agent安装注册与状态验证Agent注册是整套实验里最容易出乱子的环节但原理理清了其实很简单Agent先向Manager的1515端口发起注册请求由authd服务下发Agent证书然后Agent拿着证书和Manager建立长连接。在Web靶机上安装Agent执行curl -s https://packages.wazuh.com/4.x/wazuh-install.sh | bash -s -- agent 192.168.56.10 web-agent这个命令会把Agent包装好并自动把Manager地址写入配置文件。如果没有自动配置需要手动编辑/var/ossec/etc/ossec.conf找到clientserver段将address改为Manager的IPclient server address192.168.56.10/address port1514/port protocoltcp/protocol /server /client然后执行Agent注册把Agent加到Manager的信任列表里/var/ossec/bin/agent-auth -m 192.168.56.10 -A web-agent systemctl enable wazuh-agent systemctl restart wazuh-agent回到Manager节点可以查看Agent是否成功注册/var/ossec/bin/manage_agents -l你会在输出里看到Agent ID、名称和状态。随后到Dashboard的“Agents”页面正常情况下能看到web-agent状态由“Disconnected”变成“Active”。如果一直是“Active”之后又掉回“Disconnected”先检查Manager防火墙是否放行1514端口再查看Agent日志tail -f /var/ossec/logs/ossec.log如果日志里出现“ERROR: Invalid agent ID”或者“Could not connect to server”多半是证书没配对或者Manager握手失败。文件服务器Agent的安装流程完全一样把主机名改成file-server-agent即可。3. 规则引擎初识与日志告警逻辑3.1 从日志到告警的三层链路规则引擎是Wazuh检测能力的核心。很多人直接跳到“写规则”那一步结果完全看不懂语法其实是因为没搞懂它处理日志的流程。原始日志要经过三层处理才会变成告警预解码、解码、规则匹配。预解码阶段负责从原始日志里提取最基础的时间、主机名、程序名等字段解码阶段则由“解码器”接手识别日志的具体格式。比如一条Apache访问日志解码器会把它拆解成srcip、srcport、user、method、url等结构化字段。最后就是规则库逐条比对判断这行日志是否可疑如果命中规则且level够高就生成告警。解码器的作用相当于“翻译官”它输出的JSON结构才是规则真正依赖的字段来源。level范围含义典型场景0-3普通事件不产生告警正常访问、系统启动、服务进程状态4-6较低风险需要关注认证失败、配置变更、非标准端口连接7-9明显可疑建议告警多次登录失败、定时任务变化、异常文件权限10-12较高风险需尽快处理webshell访问、提权行为、恶意命令执行13-15严重风险立即响应攻击成功、病毒传播、严重配置漏洞规则文件分布在/var/ossec/etc/rules/目录架构下分系统规则和本地规则两部分。本地规则文件名叫local_rules.xml专门用于放自定义规则系统升级时不会被覆盖。理解了这个结构你就明白为什么建议所有自定义规则都写在local_rules.xml里——这相当于给你的检测逻辑留了一块长期有效的“自定义区域”。3.2 自定义第一条检测规则识别Web目录下的可疑PHP访问规则语法看着陌生但核心就几个关键字段。我们用一个实际场景来演示Web靶机在/var/www/html目录下被上传了一个shell.php攻击者访问/shell.php?cmdwhoami我们要让这条访问在日志里现出原形。打开Manager端的/var/ossec/etc/rules/local_rules.xml追加以下规则group namelocal,web, rule id100001 level10 if_sid31000/if_sid matchshell\.php/match description可疑的Webshell访问请求/description groupwebshell_attack,/group /rule /group这条规则的意思很直白当Apache访问日志经过解码器进入规则引擎后如果匹配了31000号系统规则Apache访问日志的通用规则并且日志里出现shell.php这个关键字就触发100001号规则告警level为10。match字段做的是简单字符串匹配适合这种固定特征明显的场景。改完规则后必须重启Manager才能生效systemctl restart wazuh-manager然后在Web靶机上模拟一次访问curl http://192.168.56.20/shell.php?cmdwhoami回到Manager节点查看告警tail -f /var/ossec/logs/alerts/alerts.json正常情况下十几秒内就会出现100001号规则的告警里面能看到来源IP192.168.56.100、目标主机web-agent、告警level 10这些关键信息。如果等了两分钟还没动静下一步马上进入我下面要说的问题排查环节。3.3 告警去噪与优先级调整有告警很爽但告警太多就是灾难。第一次把Web靶机的Apache日志接入后我发现满屏都是搜索引擎爬虫的404记录和监控探针的HEAD请求真正的攻击告警全被淹没了。这种情况下要做的是“去噪”和“优先级重排”。去噪最常见的方式是用overwrite重写系统规则的level。比如系统规则31100可能把某个常规的404访问定为level 3但404本身在业务环境里极常见完全可以压低到level 0。在local_rules.xml里这么写rule id31100 level0 overwriteyes if_sid31100/if_sid descriptionIgnored/description /ruleoverwriteyes的含义就是“用这条规则覆盖系统规则”。这样设置之后相同字段的日志就会命中新规则level被压到0不再产生告警。此时我通常还会配合一个准备动作先看一周的真实告警分布按告警数量从高到低排序优先处理top N的噪音源。噪音降下去之后再把那些真正关键但容易被忽略的攻击特征挑出来加高level比如Webshell访问直接提到12级这样告警页面才真正有了优先级。4. 三个高频攻击场景复现与告警验证4.1 场景一SSH暴力破解检测实战SSH暴力破解是所有对外主机都会遇上的问题Wazuh默认规则库对认证失败已经有比较成熟的覆盖。我先在Web靶机上确认SSH服务正常启动然后在Kali攻击机上用hydra跑一个简单的字典爆破hydra -l root -P /usr/share/wordlists/metasploit/unix_passwords.txt ssh://192.168.56.20由于靶机允许密码登录hydra会连续发起几百次认证尝试失败日志会不断写入/var/log/auth.log。Wazuh的logcollector默认就会采集这个文件由sshd解码器解析后交给规则引擎匹配。回到Dashboard的“Security events”面板检索rule.id:5710 OR rule.id:5715。5710号规则表示单次SSH认证失败5715号规则表示短时间内出现多次认证失败。实际观察中爆破开始后几秒内就会看到5715号告警连续刷新level通常是5或10取决于失败次数和频率阈值。不过生产环境里还有一个更经典的需求对root用户的连续失败登录单独加高告警级别。我尝试过用自定义规则实现逻辑是先匹配5710号规则在解码字段中发现目标用户是root同时结合frequency参数做聚合rule id100002 level12 frequency8 timeframe60 if_matched_sid5710/if_matched_sid matchroot/match description短时间内多次针对root用户的SSH登录失败/description groupauthentication_failures,sshd,/group /rulefrequency8 timeframe60表示60秒内命中8次满足条件的日志时触发。这个聚合逻辑相当于把单点失败的“杂音”聚合成一个有方向性的攻击信号非常实用。验证下来爆破持续15秒左右就会看到100002号告警级别12足以触发进一步的人工研判。4.2 场景二Webshell上传与执行检测实战Webshell检测是企业安全绕不开的话题但也是单点规则很难做好的事情。我设计了双链路检测方案一条走日志一条走文件完整性监控。先造一个实验用的Webshell。在Web靶机的/var/www/html目录下写入一个极其精简的shell.php?php eval($_POST[cmd]);?在Kali上用curl上传这个文件到靶机的Web目录实验环境我直接通过scp或者FTP写入模拟攻击者拿下一个上传点之后的行为curl -F fileshell.php http://192.168.56.20/upload.php文件落盘之后Wazuh的syscheck模块会检测到/var/www/html/目录下新增了shell.php默认规则会生成一条“File added to the system”的告警。但仅仅知道“新增了文件”还不够我们要的是把“新增文件可疑请求”组合起来判断。第一层自定义规则匹配访问日志里的Webshell特征rule id100003 level12 if_sid31000/if_sid regex(\/shell\.php|eval\(|base64_decode\(|assert\()/regex descriptionWeb访问日志中检测到Webshell特征/description groupwebshell_attack,/group /rule这条规则比刚才的纯字符串匹配更进了一步用regex同时匹配shell.php、eval(、base64_decode(、assert(等常见Webshell关键字即使攻击者改了文件名只要请求参数里带高危函数特征也能命中。第二层规则针对syscheck的文件新增事件加上路径限定。在/var/ossec/etc/rules/local_rules.xml中可以基于系统规则554文件新增告警扩展rule id100004 level10 if_sid554/if_sid regex/var/www/html/.*\.(php|jsp|asp)$/regex descriptionWeb目录下新增可疑脚本文件/description groupwebshell_attack,fim,/group /rule实际操作中我在Kali上用curl访问http://192.168.56.20/shell.php并提交一个POST命令几秒之内Dashboard上就会同时出现两条告警一条来自access.log的可疑Webshell访问一条来自syscheck的Web目录新增PHP文件告警。两条告警的srcip都是192.168.56.100前后时间间隔在个位数秒级。到了这一步就算不是自动化关联人工判断也已经可以确认这是一次Webshell攻击行为。4.3 场景三主机完整性监控与Rootkit检测最后这个场景我来模拟主机侧攻击篡改系统二进制文件和植入隐藏目录。首先是修改/bin/ls的可执行文件模拟恶意替代系统命令。在文件服务器Agent上执行echo fake binary /bin/ls chmod x /bin/lssyscheck默认监控/bin目录md5和sha256校验值会立刻发生变化告警里会明确写出/bin/ls的checksum changed。这一步原理很简单文件完整性监控就是提前为关键文件做指纹一旦指纹变化就报警。真正容易被忽略的是这个告警的处置价值——大多数rootkit和后门都会替换系统命令来隐藏恶意进程所以/bin/ls、/bin/ps、/usr/bin/ss这些常用命令的任何改动都应该被视为高优先级事件。接着模拟一个rootkit特征。安全测试里最典型的手法是在/dev下创建隐藏目录或者部署ld.so.preload劫持文件。rootcheck模块启动时会扫描/var/ossec/etc/shared/rootkit_files.txt里记录的已知特征路径如果匹配到就告警。我先把自定义特征加入文件列表echo 10|/dev/.tmp_hide||Rootkit隐藏目录特征|1 /var/ossec/etc/shared/rootkit_files.txt然后在文件服务器Agent上创建这个隐藏目录mkdir -p /dev/.tmp_hiderootcheck默认周期是多久跑一次取决于ossec.conf里的rootcheckfrequency默认值一般不会低于一小时如果不愿意等可以临时把频率调小。从实践角度出发我建议做实验时把它调到600秒等告警验证通过之后再改回去。等到告警出现时你能在Dashboard的告警详情里看到“Rootkit detected”和对应的特征路径level通常为10级以上。这三个场景组合起来恰好形成一个立体化的检测视角SSH爆破盯着“身份认证异常”Webshell盯着“业务流量异常”rootkit和文件篡改盯着“主机系统异常”。单看任何一角都可能漏报但三层告警交叉验证攻击者无论从哪个方向切入总会被某一层捕获。5. 实际问题排查实录与解决建议5.1 Agent断连问题排查顺序实验过程中Agent状态在“Active”和“Disconnected”之间反复横跳的问题我遇到了不止一次。后来总结出一套固定排查顺序。第一步先看网络层在Agent上执行nc -vz 192.168.56.10 1514 nc -vz 192.168.56.10 15151515是authd注册端口1514是数据通信端口只要有一个不通Agent就不可能保持Active。接着检查Agent本地证书/var/ossec/etc/client.keys这个文件是Agent和Manager之间的信任凭证如果文件之前被误删或者被替换也会导致断连。最后在Manager端重启核心服务这里有个重启顺序先wazuh-indexer再wazuh-manager最后wazuh-dashboard如果先重启manager再重启indexerDashboard在短时间内会出现很多的红色错误提示容易误导判断。还有一次Agent一直显示Disconnected但网络和证书都没问题最后发现是Manager节点的/var/ossec/etc/ossec.conf里authd配置被改错了导致1515端口没有监听。排查端口监听直接看ss -tlnp | grep -E 1514|1515如果没有输出检查authd进程和配置文件。5.2 规则不生效先查这三样规则写好了但告警不出现这个问题的频率仅次于Agent断连。按我的经验九成是三个原因。第一日志根本没被采集。确认Manager端/var/ossec/etc/ossec.conf里的localfile配置覆盖了目标日志路径Agent端路径写错是最常见的失误Web访问日志如果配置成/var/log/apache2/access.log但系统实际日志路径是/var/log/apache2/access.log.1那就什么都收不到。第二解码器没识别出来。Wazuh提供了一个非常好用的调试工具/var/ossec/bin/wazuh-logtest能实时模拟一条日志从解码到规则匹配的完整过程。我调试自定义规则时基本都会先用它/var/ossec/bin/wazuh-logtest启动后粘贴一条实际的攻击访问日志工具会显示这条日志被哪个解码器解析、解析出哪些字段、命中哪条规则。如果显示“No rule matched”说明解码阶段就没成功规则写得再好也没用如果显示解码成功但没匹配自定义规则再检查规则id和if_sid逻辑是否对得上。第三规则文件语法错误。检查/var/ossec/logs/rules.log有XML语法错误会直接在这里报出来。规则文件改完必须重启Manager这个动作容易被忽略我一开始就犯过“改完半天没反应”的错后来把“改规则-重启-验证alerts.json”变成了固定动作序列。5.3 日志量太大与磁盘空间的处置方案实验环境中日志量通常不会很快冲垮磁盘但你在调规则时如果开启了某些调试选项问题就来了。比如曾经为了调试打开了logall选项它会把所有日志都保存下来一天下来轻松多出几个GB。所以实验室场景下我建议保持logall关闭状态只保留alerts.json和索引后的告警数据。Disk使用率一旦上涨优先处理的是Indexer的索引生命周期。Wazuh Dashboard里有索引管理策略可以把历史索引的保留期从默认的90天缩短到7天实验数据留太久意义不大。另外那些写得很“激进”的规则也可能成为日志量放大器——比如用regex匹配过宽的Web特征导致正常页面的URL里有个“e”都触发告警。经验是写完规则后用前几天的历史日志回放看误报率某条规则的告警数量如果占了总告警量的50%以上就要怀疑这条规则是不是过宽了。我实际统计过这套4节点实验环境正常运行时Manager的CPU占用率长期在10%以下内存占用在5GB左右。也就是说4C8G的虚拟机跑完整实验完全够用真正吃资源的大头始终是Indexer的JVM堆所以前面提到的堆内存调整对稳定运行确实有帮助。处理这些细节的过程本身就比照着教程点鼠标更能帮人理解一个SIEM系统是怎么运转的。最后再分享一点个人体会。我做了几次攻防对抗演练之后最大的感受是检测规则永远不是“写完就完事”它和攻击手法是一个不断博弈的过程。实验室里可以放心大胆地折腾把规则写狠一点看它会不会大面积误报把攻击手法换着花样试看告警会不会漏。这种反复“破坏-修复-验证”的循环才是真正积累手感的路径。还有一个小技巧每新增一条规则都建议顺手在local_rules.xml里写明添加日期和适用场景等你积累到几十条规则之后就会发现这个习惯能帮你省下大把维护时间。后续如果觉得单靠Wazuh自身不够过瘾还可以把它的告警通过API推到TheHive这类案件管理平台做闭环的告警处置流程这套实验环境依然可以作为底层检测源直接复用。