ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Seay源代码审计系统实战:从解压到规则调优的PHP代码审计指南

Seay源代码审计系统实战:从解压到规则调优的PHP代码审计指南 简介Seay源代码审计系统是一款面向开发者与安全工程师的自动化代码审计工具主要用于发现并修复源代码中的潜在安全漏洞与编程错误适合具备一定编程基础、需要开展代码安全审查与质量保障的技术人员使用。资源包共25个文件以dll动态库、exe可执行程序为主辅以bin规则与编辑器数据、ini配置、html报告模板及php测试样例等压缩包约14.06MB解压后可直接运行主程序开展审计工作。系统支持一键自动审计、函数查询、代码高亮编辑、自定义审计规则、代码调试与报告生成等功能能够帮助读者快速定位问题代码、理解执行流程并输出结构化审计结果。目前已有970人学习下载可作为代码安全入门与日常审计实践的参考工具。1. 拿到一个 Seay 源代码审计系统.rar先别急着双击很多人第一次接触代码审计是从一个压缩包开始的。文件名往往就叫「Seay源代码审计系统.rar」来源可能是同事转发、论坛附件或者某个安全学习资料合集。双击解压里面通常是一个 exe 加一堆 dll 和配置文件看起来像个绿色软件但真跑起来会发现它到底在扫什么、为什么有的漏洞报有的不报、我该拿它审自己项目还是审别人的源码这些问题没人讲清楚。Seay 源代码审计系统本质是一个基于正则和词法规则匹配的静态代码扫描工具面向 PHP 为主兼顾少量 JSP、ASP 场景。它的价值不在于「一键出漏洞」而在于把人工翻几十个文件找危险函数的活自动化让你把精力放在验证和利用链构造上。适合谁用一是刚入门 Web 安全、想拿真实源码练手的同学二是甲方或乙方做代码审计、需要快速定位可疑点的工程师三是开发想自查项目里有没有明显写死的后门或注入点。这一章先把定位说清楚后面几章拆解怎么装、怎么配规则、怎么读报告、坑在哪。2. Seay 的扫描引擎到底靠什么吃饭正则匹配与词法分析的边界2.1 为什么它扫 PHP 比扫 Java 准Seay 的核心逻辑是「危险函数 上下文正则」。PHP 里eval、assert、system、preg_replace带/e、include变量包含这些模式非常固定正则命中率天然高。而 Java 的漏洞更多依赖框架注解、Spring 表达式、反序列化链纯文本正则很难判断一个readObject是否真的可达。所以你会看到 Seay 对 PHP 项目报得密密麻麻对 Java 项目几乎沉默这不是工具坏了是设计取向决定的。常见做法是审 PHP 项目直接上 Seay 初筛审 Java 项目把它当辅助只用来找硬编码密码、注释里的测试账号、明显的Runtime.exec拼接。我一般会先看项目语言占比PHP 超过七成再把它当主力。2.2 规则文件长什么样怎么读解压后通常有个rule或config目录里面是.ini或.dat文本。打开能看到类似这样的结构[SQL注入] pattern (select|insert|update|delete).*\$_(GET|POST|REQUEST) level 高危 desc 直接拼接超全局变量存在SQL注入风险 [文件包含] pattern (include|require)(_once)?\s*\(?\s*\$_(GET|POST|REQUEST) level 高危 desc 变量直接进入包含语句可导致任意文件包含每一条规则由三部分组成匹配模式、危险等级、描述。pattern是正则level决定报告里的颜色和排序desc是给你自己看的备注。想加自定义规则直接复制一段改pattern就行不用重新编译。提示改规则前先备份原文件Seay 启动时会整体加载写错一个正则可能导致整个规则集加载失败界面里一条结果都没有。2.3 一次完整扫描的四个阶段第一阶段是文件遍历按扩展名过滤默认只扫.php、.jsp、.asp、.aspx。第二阶段是逐行正则匹配把命中行和前后三行一起抓出来做上下文。第三阶段是去重和聚合同一个文件同一类漏洞合并成一条。第四阶段是生成报告通常是一个 HTML 或 CSV包含文件路径、行号、命中代码、规则描述。理解这四个阶段很重要因为后面排查「为什么没扫到」时你要能判断是文件没被遍历到、正则没命中、还是被去重合并了。3. 从解压到出第一份报告Windows 下的最小可复现流程3.1 环境准备与依赖检查Seay 是 Windows 原生程序依赖 .NET Framework 和几个 VC 运行库。如果你在 Win10/Win11 上双击没反应先装 .NET Framework 4.0 以上和 VC 2010 运行库。别在虚拟机里用精简版系统缺 dll 是常态。我一般会建一个独立目录比如D:\tools\seay\把解压出来的所有文件放进去不要放在中文路径或带空格的路径下否则扫描时读文件可能报错。杀毒软件会误报因为它的行为像在批量读取源码文件加个白名单目录即可。3.2 新建项目并指定源码根目录打开主界面后点「新建项目」项目名随便填关键是「源码目录」要选到项目的根比如D:\code\myphp\。不要选到某个子目录否则跨文件的包含关系会断。如果项目很大超过几万个文件建议先按模块拆成多个项目分别扫一次性全量扫容易卡死。配置里有个「文件扩展名」选项默认是php|jsp|asp|aspx。如果你的项目用了.inc或.module做包含文件记得手动加上否则这些文件会被跳过而它们往往藏着配置密码和数据库连接串。3.3 选择规则集并启动扫描规则集一般有「默认」「严格」「自定义」三档。默认档误报少但漏报多严格档会把所有变量拼接都报出来适合人工逐条过。第一次跑建议用默认档先看整体情况。点「开始扫描」后底部进度条会走大项目可能跑十几分钟期间不要点界面上的其他按钮容易卡死。扫描完成后左侧会列出漏洞分类右侧是具体文件和代码片段。双击某一条能跳到代码上下文这是它比纯 grep 好的地方。3.4 导出报告与二次过滤菜单里有「导出报告」选 HTML 格式会生成一个带样式的单文件方便发给同事。但导出的报告没有优先级排序我一般会再导一份 CSV用 Excel 按「规则等级」和「文件路径」排序把高危且集中在核心业务文件里的先看。# 如果你在 Linux 下拿到的是源码包想先用 grep 做一轮粗筛 grep -rnE (eval|assert|system|exec|preg_replace).*\\\$_(GET|POST|REQUEST) \ --include*.php /path/to/src rough_scan.txt这段命令不是替代 Seay而是在没有 Windows 环境时先做一轮快速定位。-r递归-n显示行号-E支持扩展正则--include限定文件类型。输出重定向到文本方便后续用编辑器跳转。注意它只匹配单行跨行拼接的漏洞会漏所以只能当预筛。4. 规则调优与误报压制让报告从一千条降到一百条4.1 用白名单排除测试目录和框架文件第一次扫完报告里一大半是test/、demo/、vendor/下的命中。这些要么是示例代码要么是第三方库修不了也不该你修。Seay 支持在项目配置里加「排除目录」把vendor、node_modules、tests、cache填进去。排除后重新扫数量通常能降一半。如果某个文件确实有漏洞但业务上不可达比如后台管理里只有管理员能访问的exec可以在规则里加一条针对该路径的忽略而不是删规则。我习惯在规则文件末尾加一个[忽略]段把已知安全的文件路径写进去这样下次升级规则也不会丢。4.2 调整正则减少「变量拼接」类误报默认规则里$_(GET|POST|REQUEST)只要出现在 SQL 语句附近就报但很多项目用了框架的 ORM 或预处理实际是安全的。你可以把规则改成更精确的[SQL注入-精确] pattern (select|insert|update|delete).*\$_(GET|POST|REQUEST).*(where|values|set) level 高危 desc 超全局变量直接进入SQL语句且出现在条件或赋值位置加了where|values|set之后像echo $_GET[id]这种就不会误报成 SQL 注入了。代价是可能漏掉一些变形写法所以精确规则和宽泛规则要配合用宽泛的用来兜底精确的用来定级。4.3 自定义规则抓业务逻辑漏洞Seay 默认规则覆盖的是通用漏洞但业务逻辑漏洞得自己加。比如你的项目里有个transfer函数参数是金额没有做上限校验这就是越权或金额篡改。可以加[金额未校验] pattern function\stransfer\s*\(.*\$amount.*\) level 中危 desc 转账函数未对金额做范围校验可能存在负数或超额转账这种规则不通用但对你自己的项目非常有用。每次审新项目先花半小时把核心业务函数名整理成规则后面扫描就能自动标出来。4.4 用「二次确认」清单降低人工成本报告出来后不要从第一条开始逐条看。先按文件路径分组把同一文件里的多条合并成一次阅读。然后建一个清单只记录「需要人工确认」的条目比如序号文件行号规则确认结果1/admin/user.php42SQL注入已用预处理误报2/api/upload.php88文件上传未校验后缀真实漏洞3/config/db.php12硬编码密码测试环境忽略这个表比直接看报告高效得多因为确认过的条目不用再看第二遍而且能统计真实漏洞比例评估项目整体安全水位。5. 避坑与排查那些让我熬夜的翻车现场5.1 扫描到一半卡死进度条不动现象大项目扫到某个文件时界面无响应任务管理器显示 CPU 占用高但内存不涨。 原因某个文件里有超长单行比如压缩后的 JS 或 base64 图片正则引擎在那一行上回溯爆炸。 解决在项目配置里加文件大小限制比如超过 500KB 的文件跳过或者先用脚本把超长行截断再扫。我一般会先跑一个find . -name *.php -size 500k把大文件挑出来单独处理。5.2 报告里全是「疑似」但没有一条能利用现象扫出来的条目点进去看变量确实来自$_GET但前面有intval或htmlspecialchars。 原因Seay 只看当前行和前后三行不追踪变量是否被过滤函数处理过。 解决把这类过滤函数名加到规则的「排除模式」里比如pattern后面加(?!.*intval)负向断言。更彻底的办法是人工确认时优先看没有过滤函数的条目有过滤的先放低优先级。5.3 中文路径下扫描结果为空现象源码放在D:\项目\源码\下扫描进度走完但一条结果都没有。 原因Seay 内部用 ANSI 编码读路径中文路径导致文件句柄打开失败但错误被静默吞掉。 解决把源码复制到纯英文路径下再扫比如D:\code\project\。这是血泪经验我因此浪费过一整个下午。5.4 规则改了但扫描结果没变化现象在规则文件里加了一条新规则重启 Seay 后扫描新规则对应的漏洞没报出来。 原因规则文件有缓存或者你改的是rule_backup目录而不是实际加载的rule目录。 解决确认规则文件路径与界面里「规则集」指向的一致改完后在界面里点「重新加载规则」而不是只重启程序如果还不行看规则文件编码是不是 UTF-8 带 BOMSeay 对 BOM 敏感用记事本另存为 ANSI 试试。5.5 导出报告乱码现象导出的 HTML 用浏览器打开中文描述全是问号或方块。 原因导出时选择的编码是 GBK而浏览器按 UTF-8 解析。 解决导出时选 UTF-8如果选项里没有导出 CSV 后用 Excel 的「数据-从文本导入」手动选 UTF-8。或者干脆在浏览器里右键切换编码但治标不治本。6. 把 Seay 嵌进日常审计流三个进阶习惯第一个习惯是「先跑 Seay 再读代码」。拿到新项目先花十分钟配好路径和规则让机器扫一遍然后带着报告去读代码。这样你读每个文件时心里有数知道哪里可能有问题效率比盲读高很多。我一般会把报告里的高危文件按路径排序从入口文件开始读顺着调用链往下跟。第二个习惯是「维护自己的规则库」。Seay 自带的规则几年没大更新了但 Web 漏洞的写法一直在变。每次审完一个项目把新发现的危险模式写成规则加进去比如call_user_func回调、unserialize反序列化、file_put_contents写 shell。日积月累你的规则库会比默认的更好用。下面是我常用的几条补充规则[反序列化] pattern unserialize\s*\(\s*\$_(GET|POST|REQUEST|COOKIE) level 高危 desc 超全局变量直接进入反序列化可导致对象注入 [动态调用] pattern call_user_func(_array)?\s*\(\s*\$_(GET|POST|REQUEST) level 高危 desc 超全局变量作为回调函数名可执行任意函数 [文件写入] pattern file_put_contents\s*\(.*\$_(GET|POST|REQUEST) level 高危 desc 超全局变量进入文件写入可写shell第三个习惯是「用版本对比看增量」。如果项目是持续迭代的每次审计不要全量扫只扫最近改动的文件。可以用git diff --name-only拿到改动列表复制到一个临时目录只扫这个目录。这样报告里全是新增代码的问题不会淹没在历史遗留里。# 拿到最近一次提交改动的 PHP 文件复制到临时目录 mkdir /tmp/changed git diff --name-only HEAD~1 HEAD -- *.php | while read f; do cp --parents $f /tmp/changed/ done # 然后用 Seay 扫描 /tmp/changed 目录这段脚本把改动文件按原目录结构复制出来--parents保留路径方便 Seay 还原包含关系。扫完后对照提交记录能快速判断新代码有没有引入新风险。最后一个技巧是「交叉验证」。Seay 报的高危用另一款工具或手工 grep 再确认一遍。我习惯用grep -rn eval( --include*.php做二次核对如果 Seay 报了但 grep 没找到可能是规则误报或文件编码问题。反过来grep 找到但 Seay 没报说明规则需要补充。工具是死的人是活的别把报告当判决书。希望帮到你。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进