工控CTF实战复盘:从Modbus流量到组态与固件的攻击链还原

发布时间:2026/10/20 17:45:04
工控CTF实战复盘:从Modbus流量到组态与固件的攻击链还原 从上个月的工控安全专项演练回来之后我一直在整理这套内部代号“玄机”的工控题。说实话一开始我是抱着“Web题刷了小半年工控题还能翻出什么花”的心态去上手的结果第一道题就把我卡到怀疑人生。它不是让你挖个漏洞、拿个shell、读个flag就完事而是模拟了一次完整的工控现场异常事件需要你一层层从流量、组态、固件里把事件还原出来。这篇文章就是把整套题的拆解过程、思路变化和坑位全部复述一遍适合正在接触工控CTF、或者对工控安全感兴趣的人参考。所有分析都基于主办方提供的离线模拟靶场设备全部是Demo镜像不碰任何真实生产系统这点先说明白。1. 工控题的门槛比想象中高先忘掉Web题的肌肉记忆1.1 当“找Flag”变成了“还原现场”我刚开始看到题目的第一反应是先用nmap扫一扫看看上位机、PLC的开放端口再挂个漏扫找找有没有可以直接利用的Web漏洞。实际上这套题里确实有上位机但它的攻击面完全不在HTTP层。你打开流量包满眼都是Modbus/TCP的轮询报文请求———响应、请求——响应规律得像心电图一样。真正的“问题点”就藏在这些看起来毫不起眼的周期流量里一旦你还在用Web题的思路去翻目录、扫路径立刻就会迷失方向。工控题的核心并不是“找一个漏洞打进去”而是“理解现场、复现异常”。你面对的不再是一个运行着Nginx和MySQL的服务器而是一条控制链路上位机下发指令PLC执行逻辑传感器反馈状态。如果某个环节被悄悄动过手脚你要做的是把这条链路上的痕迹一点点找出来还原攻击者当时做了什么、为什么能做成然后才能看到埋在最后面的Flag。这种思维方式比单纯的漏洞利用训练更接近真实安全工作。1.2 工控三件套协议、组态、固件这套“玄机”工控题让我彻底认清了一个事实工控安全分析的常规套路基本就是三条线——一看协议流量二看组态工程三看设备固件。协议流量解决的是“发生了什么”组态工程解决的是“底层逻辑为什么这样设计”固件解决的是“设备里还藏着什么”。三道关卡层层递进缺一环都会卡住。协议层面最常见的是Modbus、S7系列私有协议以及其他现场总线协议。它们的报文不像HTTP那样有丰富的方法、路径和头字段而是靠功能码、寄存器地址、数据值这些紧凑字段表达意图。组态层面你面对的是工程师站导出的工程文件、变量表、梯形图逻辑需要读懂一个生产流程是怎么被组织起来的。固件层面则是把设备内部的文件系统解开找出出厂时、维护时或事故后被人为改动的痕迹。这套题就是把这三种能力串成了一条完整的攻击链复盘场景。2. 玄机这套题到底在考什么交付物、目标与思路陷阱2.1 题面速览一座模拟水厂加药单元的“事故”题面背景设定在一个模拟水处理厂区的加药单元核心设备是一台负责加药泵频率控制的PLC通过上位机进行日常监控和参数整定。某天凌晨值班记录显示加药泵频率被异常抬高到55Hz远超45Hz的安全上限幸好联锁机制在数分钟后触发了停机。现场工程师排查时发现上位机操作日志里并没有任何人工操作记录于是把整套现场数据封存提交作为这次工控挑战的题面。参赛者拿到的是一个精心设计过的“事故现场快照”一组捕获好的网络流量文件、一份加密的组态工程备份包、一份PLC固件镜像。没有多余的背景提示所有答案都必须靠从这三样东西里自己挖出来。题目要求最终回答三个问题攻击路径从哪里进入、哪些工艺参数被改动、设备里是否存在隐藏触发条件然后在完成这几步后拼接出Flag。2.2 交付物清单与Flag规则我梳理了一下本次题目的交付物正好对应着三层分析交付物说明分析方向cap.pcapng加药单元上位机与PLC之间的网络抓包协议流量分析engineer_project.7z加密的组态工程备份包配置、逻辑与凭据分析plc_fw_v2.binPLC固件镜像文件固件文件系统与隐藏服务排查题目没有直接给出明显的Flag位置而是要求把三层线索中的关键信息拼在一起。比如流量里发现的异常写入寄存器地址、组态包里定位到的变量名、固件里发现的隐藏标识最终组合成类似仅包含字母和数字的序列作为提交答案。这种设计很聪明因为单看任何一层都只是碎片只有全部串联起来才能理解整套攻击链。2.3 第一眼的劝退点我第一次拿到交付物的时候内心是相当绝望的。cap.pcapng打开之后是几千条Modbus/TCP轮询记录过滤器拉出来全是0x03读保持寄存器请求engineer_project.7z带密码直接解压报错plc_fw_v2.bin用binwalk扫了一下又同时报了好几种文件系统特征。任何一个环节单独拎出来都像一座小迷宫。后来复盘才明白这些“劝退点”本身就是出题人故意设置的陷阱流量不能只看有没有攻击报文组态包不能只靠爆破密码固件也不能只binwalk一把梭。所有表面障碍背后都有更省力的正门。3. 第一关卡在流量里Modbus报文中的异常写入指纹3.1 先建立通信基线再谈异常看工控流量包和看Web流量包最大的区别就是你必须先理解“正常长什么样”。我把cap.pcapng拖进Wireshark先不看具体报文而是打开统计菜单看协议分层和端点信息。很快确认这台加药单元的主要通信是上位机192.0.2.10对PLC 192.0.2.110的502端口持续发送Modbus/TCP请求。其中绝大多数是功能码0x03读保持寄存器间隔大约500毫秒值是各种浮点数的编码。这就是正常的轮询节奏。我专门用I/O图表拉了一下流量速率曲线发现整段时间里有一个明显的小尖峰在某个时间点请求数量忽然暴增随后又慢慢恢复。这个尖峰所在的时间窗口就是攻击者集中写入参数的时间段。如果不先建立这个基线你很难从几万条报文里分辨出那几十条真正关键的数据。很多人一上来就筛关键字“modbus”筛出来的东西反而让人眼花缭乱。3.2 关键过滤命令与特征提取确定异常窗口后我把tshark的过滤条件集中到写操作上。Modbus写操作通常集中在两个功能码0x06代表写单个保持寄存器0x05代表写单个线圈。我用tshark把这两类请求全部提取出来直接看源IP、目标IP、寄存器地址和写入值tshark -r cap.pcapng -Y modbus.func_code 0x06 -T fields -e ip.src -e ip.dst -e modbus.regaddr -e modbus.value16 -E separator,tshark -r cap.pcapng -Y modbus.func_code 0x05 -T fields -e ip.src -e ip.dst -e modbus.regaddr -e modbus.coilval -E separator,结果非常清晰正常情况下几乎没有0x06写寄存器请求但在时间戳20:15:20到20:15:35之间上位机对PLC连续发起了十几次写请求。写入的寄存器地址从0x0029开始连续覆盖了多个地址写入值从正常范围内的30附近一路抬升到55恰好对应加药泵频率从常规上限之上继续越级抬升。随后还有一次0x05写线圈操作目标线圈地址是0x0034写入值是0xFF00即置位状态。3.3 从寄存器地址读出攻击意图单独看这些寄存器地址一时还不能完全确定它们代表什么工艺参数。但顺着Modbus应用层往下追我发现每次异常写请求后从站都返回了正常的写确认响应这说明PLC确实接受了这些写入值而不是被拒绝。这里有一个容易踩的坑你以为只要找到攻击者发起的恶意请求就够了但如果PLC本身没有接受那这条请求可能只是撞了一下门真正的效果未必发生。我特意把请求与响应的事务标识符做了匹配确认这些写操作都成功完成加药泵频率确实被改到55Hz而且那个线圈也被置位。到这一步流量分析给出的结论是有人通过上位机所在网段向PLC的某段寄存器发起了批量写操作改写了加药泵频率设定值同时置位了一个远程维护标志线圈。但这个“远程维护标志”是什么为什么要置位它就不是流量本身能回答的了。所以我把这两条关键信息记下来异常寄存器0x0029周边区域、异常线圈0x0034然后转战组态工程包。3.4 这条链路里的三个常见坑第一个坑是只看请求不看响应容易把未生效的尝试当成攻击结果。第二个坑是忽略时间对齐流量里的时间戳如果不和报警日志、工程包里的记录比对很难定位真正的事件窗口。第三个坑是过度依赖Wireshark图形界面其实用tshark以字段方式导出配合电子表格透视反而更容易发现连续写入的规律。我后来重新复盘时用tshark把整个异常窗口的所有请求都导成了CSV然后在表格里按时间排序连续10次地址递进写入的模式一目了然。工控流量分析拼的不是一两个高级过滤技巧而是更系统的数据透视意识。4. 第二关卡在组态包里被藏起来的密码和启动触发器4.1 先扒工程包的家谱7z里都有什么流量分析告一段落我转向engineer_project.7z。很多人拿到加密压缩包的第一反应就是挂字典爆破我在这里硬生生忍住了。先用file命令确认格式再用7z查看压缩包内部结构发现它并不是一个简单的打包文件而是带着清晰的目录分层。压缩包加密但包内的文件列表居然可见里面有各类工程配置文件、数据库导出文件和梯形图逻辑片段。这意味着真正的难度不在于能不能解开包而在于解开之后能不能从海量配置里找到关键对象。我尝试直接解压提示密码错误。这本来也在预料之中。既然压缩包元数据里没有密码我就把所有附属材料翻了一遍包括题目环境里的说明文档和报警日志。报警日志最后一条记录格外有意思它显示的报警时间与流量异常窗口高度吻合而且在报警文本的尾部还跟着一串看起来很像备注的字符像是一串日期加单词的组合。我把它当作密码候选项试了一次压缩包成功解开。4.2 密码线索往往不在字典里你有没有发现很多实战场景里所谓的“加密文件密码”并不会写在什么安全手册里而是藏在工程师为了方便维护留下的备注、日志尾部、甚至工程注释里。这次也是一样压缩包密码就是报警日志里那串日期加单词组合。出题人故意模拟了一种真实存在的坏习惯操作员为了方便记忆把工程备份密码写在报警备注里。这种信息字典爆破永远撞不出来但顺着现场材料读一遍就能发现。所以工控题里遇到加密文件第一件事永远是把所有明文材料通读一遍而不是急着上字典。4.3 哈希破解只是起点变量地址映射才是命门解包之后我先翻到了工程核心配置文件里面有若干XML和数据库文件。我做的第一件事是搜索关键字包括password、user、hash、account。结果果然有收获工程师站的上位机组态账户直接以哈希形式写在配置里看哈希前缀就能判断是Linux标准的shadow哈希。我把它单独摘出来用john挂了一个常用弱口令字典john --wordlist/usr/share/wordlists/rockyou.txt hash.txt很快跑出一个结果admin账户的密码是一个极其常见的“年份英文单词”组合强度低得吓人。放到真实场景里这种账号一旦泄露整个工程师站就等同裸奔。不过哈希破解对我来说只是一个标记点我真正关心的是工程内的变量地址映射表。我打开DB块导出文件搜索之前在流量里看到的几个地址。0x0029这个寄存器地址在工程变量表里对应的名称是“加药泵频率设定值”0x0034这个线圈地址对应的名称是“远程维护标志位”。流量分析里的抽象地址到这一步终于变成了有业务含义的工艺参数。4.4 梯形图导出文件里的隐藏分支变量名确认之后我又去翻梯形图逻辑导出文件。在工程师站里梯形图通常按程序段组织我也习惯性地一段段看过去。表面逻辑看起来一切正常加药泵频率设定值来自PID输出经过上限限制模块最终送到模拟量输出通道。安全联锁的逻辑也是常规写法频率超过45Hz就强制停机。但我在一个不太起眼的程序段里发现了一个特意用注释标注为“临时维护逻辑”的隐藏分支。这段隐藏分支的逻辑并不复杂含义是当“远程维护标志位”为真时频率设定值会绕过常规PID输出和上限限制直接强设为55Hz。换句话说流量分析里看到的那个0x0034线圈置位操作就是这个隐藏分支的开关。只要这个标志位被置位即使所有正常联锁都在工作加药泵也会被强行拉到55Hz。这正好解释了为什么上位机日志里没有人工操作记录却能发生频率异常上升的现象。隐藏分支的判断条件被攻击者从网络侧直接触发导致整个逻辑保护形同虚设。4.5 把流量线索与组态线索合并到这一步前两层线索已经能拼出一条完整的逻辑链攻击者先通过上位机网段向PLC写入频率设定值的相关寄存器同时置位远程维护标志位组态工程里的隐藏分支在标志位为真时启动把频率强推至55Hz并绕过安全联锁。至于攻击者是如何进入上位机网段的、为什么能绕过工程师站的认证这两点在流量和组态包里还没有答案。我隐隐觉得这些问题很可能藏在第三个交付物——PLC固件镜像里。5. 第三关卡在固件深处从binwalk提取到后门定位5.1 binwalk只是开始文件系统识别更重要PLC固件镜像文件plc_fw_v2.bin是最后一层谜题。我照例先跑binwalk然后立刻发现一个典型陷阱binwalk在同一份固件里报出了不止一个文件系统特征既有CRC表又有SquashFS特征旁边还跟着一堆看起来像加密数据的随机区段。如果你不加思考直接binwalk -e会把大量误报内容一起解出来反而增加干扰。我重新看了binwalk输出的偏移地址结合固件的一般布局判断真正的用户态文件系统集中在后半段以SquashFS特征为主。随后解包并挂载了根文件系统binwalk -e plc_fw_v2.bin unsquashfs _plc_fw_v2.bin.extracted/xxx.squashfs5.2 解包后的重点目录排查文件系统解开之后我没有漫无目的地翻文件而是先检查几个固定的关键位置第一是/etc/passwd和/etc/shadow看有没有非默认用户第二是开机启动脚本目录看有没有额外启动的服务第三是/usr/sbin和/usr/bin对照常见固件版本找陌生文件。结果在shadow里发现了一个名叫diag的额外用户这个用户名在公开版固件里并不存在而且它的密码哈希强度同样很低。在启动脚本目录里我又看到一个单独的启动脚本会在系统启动时把telnetd绑定到管理网口地址上。如果只是到这里你可能觉得“无非是固件被人加了调试账号”。但真正让我确定这就是第三层答案的是那个叫debug_shell的二进制文件。它在/usr/sbin目录下文件名明显不是标准系统组件而且时间戳比同一目录下其他文件都要新。这个调试接口平时处于隐藏状态只有通过diag用户登录系统后才能执行它。从固件编译时间戳来看这个镜像的构建时间早于公开版本说明里标注的发布时间说明它很可能是维护中误用的非正式内部构建。5.3 弱口令不是目的隐藏调试接口才是答案于是我在模拟靶机环境中试着用diag用户和弱口令登录telnet成功后立刻定位到debug_shell。该接口提供了一套底层的维护命令里面有一项可以直接读取某个特定数据块的内容。我按提示输入命令返回了一串Base64编码的文本解码之后是一个固定格式的标识符。随后我把这个标识符与前面组态包里找到的隐藏分支信息拼接在一起组成了完整的最终Flag。到这里三层分析才算是真正闭环从固件里找到隐藏入口到通过入口读取内部数据再到和组态逻辑里的关键变量名关联最后完成题目要求的事件还原。5.4 固件分析工具箱与合规边界这次固件分析让我认识到工具只是开胃菜真正重要的是一套“解包总要先识别文件系统、排查总要先看启动脚本和账号体系”的流程。binwalk、unsquashfs是常用工具关键目录的排查顺序也很重要。必须再次强调这份固件是主办方提供的模拟镜像整个过程都在隔离环境里进行。如果你手上有一份真实设备的固件请先确认是否有分析和测试授权不要轻易对在役设备做任何形式的逆向或调试操作这一点在工控领域尤其重要。6. 解完题之后再想一步这些手法对防守有什么启发6.1 异常写报文如何变成检测规则题目里的攻击动作翻译成防守语言其实特别清晰一次对工业控制协议的非预期写操作。你完全可以把它写成检测规则比如在ICS流量出口或上位机网段旁路部署检测设备对Modbus/TCP协议做深度包解析重点监控两类现象一类是写寄存器功能码的请求频率和覆盖范围是否异于基线另一类是关键寄存器地址是否出现在白名单之外的操作来源中。题目里那几十次异常写请求如果被这样的规则捕获完全可以在攻击者修改频率的瞬间就触发事件告警而不必等到联锁停机后才去做事故复盘。6.2 组态工程文件的配置审计组态工程文件是工控环境里最容易被忽略的数据资产。这次的工程备份包里藏着弱口令账户、隐藏逻辑分支和明文关键注释放在真实环境里任何一个都是严重隐患。防守视角的做法是对工程师站、组态软件和工程备份文件建立资产管理台账重要工程文件要做加密存储和权限隔离对梯形图逻辑段做版本管理定期与基线版本做diff对工程师账户执行和IT系统同等级别的口令策略复杂度和更换周期都不能放松。6.3 固件基线与调试端口管理固件层面的问题在真实场站更隐蔽。很多工控设备部署多年固件版本停留在出厂状态内部可能存在非公开调试账号或隐藏维护接口。对防守方来说能做的事包括整理所有设备的固件版本清单计算每个设备当前固件的哈希值作为基准并定期复核关闭不使用的调试服务和物理端口把维护网段和常规控制网段做严格隔离避免攻击者从业务侧直接触达设备调试链路。这些东西听起来很基础但真正执行过就会知道光是把资产台账推进到90%的覆盖就需要相当长时间。6.4 新人怎么走工控CTF这条路如果你刚接触工控CTF我的建议是从协议分析入手先找一份带注释的Modbus/TCP数据包花一天时间把字段结构、功能码和常见错误码搞明白。第二步是组态搭一套简单的PLC模拟环境亲手把变量表、寄存器和梯形图功能块对应起来重点理解“某个地址到底对应现场哪个设备”。第三步才是固件找一个公开的固件库样本用binwalk走通解包、挂载、关键目录排查的完整流程。每一步都要在本地隔离环境完成不要拿真实系统练手。等你走完这些路再回头看“玄机”这套题思路往往就清楚了。这次复盘我前后跑了三遍最大的收获不是拿到了Flag而是把“协议—组态—固件”这三个层面彻底串联成了一条可复用的分析链路。现在我再去看真实环境的工控数据第一反应不再是找漏洞而是先问三个问题正常状态长什么样、哪里有不该出现的写操作、设备里是否藏着不该有的入口。最后再分享一个小技巧这类多文件联动的题目最好把流量时间戳、报警日志时间、组态文件修改时间全部统一成epoch秒格式放到同一张电子表格里按时间轴排序很多看似割裂的线索会自动站到你应该看到的位置上。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询