Seay源代码审计入门:危险函数扫描、规则扩展与AWD实战避坑
发布时间:2026/10/29 11:33:57 锦皓数字建站

简介Seay源代码审计系统是一款基于C#开发、主要运行于Windows平台的PHP代码安全审计工具面向网络安全初学者、代码审计人员及AWD参赛选手用于快速发现SQL注入、命令执行、文件包含、文件上传、XSS、信息泄露与任意URL跳转等常见漏洞。压缩包共30个文件以11个dll、6个exe等程序组件为主辅以rar、zip源码与资料包以及ini、md、php、html等配置和说明文件整体约42.16MB解压后可直接部署使用。目前已有805人学习下载适合搭建本地审计环境。其价值在于支持一键审计、函数定位、插件扩展、自定义规则、代码高亮、编码转换和数据库执行监控等功能并附带插件示例与2.1版本源码资料便于理解工具机制、练习漏洞定位和复盘AWD审计思路。1. 代码审计入门的第一把尺Seay 能替你看什么很多做 AWD 的团队在拿到源码后的前十分钟真正卡住的往往不是漏洞会不会挖而是“从哪个文件下手”。一个压缩包解出来动辄几千个 PHP 文件靠grep一页页翻翻到第三个目录就精神涣散了。Seay 源代码审计系统解决的正是这个阶段的问题它是一个运行在本地的代码审计工具把源码目录一键导入自动做危险函数定位、变量覆盖排查、敏感配置提取并把可疑文件按风险归类成一张清单。你不需要先把整份代码读懂先看它给出的可疑点再回头对着源码确认这个流程对刚接触代码审计、正在准备 AWD 的新手特别顺。它适合三类人一是想入门代码审计但不知道从哪切进去的开发二是打 AWD 需要赛前快速摸一遍靶场源码的选手三是接手了历史遗留 PHP 项目、想快速了解哪里存在高危写法的维护者。它不做的事情也很明确——它不是 SAST 平台不替代人工验证很多结果需要你看源码二次判断。把它当成“可疑点的筛子”而不是“漏洞的判决书”心态就对了。2. 环境与上手从解压到跑出第一份审计清单2.1 运行环境与启动方式Seay 是桌面端的 Windows 应用不需要装 Web 容器也不需要配数据库解压后双击主程序即可。这个设计在当年的审计工具里算很省事的不用先折腾 PHP 环境、不用起 Apache省掉的这部分时间正好用来读代码。实际使用中我一般把它放在一台干净的 Windows 机器或虚拟机里跑原因后面避坑章节会细说。启动后的界面大致分三块左侧是项目与文件树中间是代码查看区下侧或右侧是审计结果列表。第一次打开是空的需要先建项目。用命令行解压和校验压缩包的完整性是个好习惯尤其从网盘拖下来的时候# 校验下载到的包是否完整先看文件大小和类型 file SeaySourceAudit.zip unzip -l SeaySourceAudit.zip | head -30 # 解压到独立目录避免和系统盘其他工具混在一起 unzip -q SeaySourceAudit.zip -d ./seay_toolfile用来确认是不是真的 zip 而不是被加了壳的可执行文件unzip -l只列目录不解压先看清楚里面有没有可疑的附加文件-d指定解压目录让工具和被测代码分开放在不同路径下这是后面做隔离的基础。2.2 新建项目并导入源码进来第一件事是新建项目。菜单里选新建填项目名选中被测源码的根目录。这里有个细节一定要选源码根目录而不是它的上一层或子目录。选错层级会直接影响后续的文件树展示和函数调用链还原。导入时通常有几个可选项我一般这样勾选项建议原因文件类型过滤只保留 php、inc、phtml 等减少图片、字体等无关文件干扰检索自动备份关闭审计是只读操作不需要改动源码递归子目录开启否则只扫根目录一层会漏掉大半入口文件索引缓存开启二次打开同一项目时省掉重复解析时间导入完成后左侧文件树会按目录展开。工具会先建一份索引文件量大时这一步要等一会儿别以为卡死了去看任务栏的进度提示。2.3 用危险函数规则跑第一轮扫描导入完成就直奔核心功能危险函数扫描。它的原理是把源码里的函数调用和内置规则表做匹配命中的位置在结果区列出来点击可以直接跳到对应代码行。?php // 一段典型的、会被规则命中的代码片段用来理解工具在找什么 $cmd $_GET[cmd]; // 外部可控输入 system($cmd); // 危险函数命令执行 $file $_POST[file]; include($file); // 危险函数文件包含 $sql select * from t where id . $_GET[id]; mysql_query($sql); // 危险函数SQL 拼接工具不会替你做数据流分析到每一层它的匹配逻辑接近“函数名 参数形态”的组合判定。上面三段会被分别标记为命令执行、文件包含、SQL 注入风险。看到结果之后的关键动作是逐个回源码确认入参是否真的来自外部、中间有没有过滤函数、过滤是否可绕过。这一步没有捷径工具的命中是起点不是结论。规则表本身是可维护的一般放在工具的规则目录下按函数名或正则组织。想加公司内部框架的自定义危险函数比如某个自己封装过的执行方法往里追加一条就行重启生效。2.4 变量覆盖与敏感信息提取除了危险函数Seay 还有两块很实用的功能。一块是变量覆盖检测专门找extract()、parse_str()、$$var这类可以把外部输入写成同名变量的写法——在 PHP 里这类代码极容易造成绕过人工翻的时候眼睛容易滑过去。?php // 变量覆盖的典型形态 foreach ($_GET as $k $v) { $$k $v; // 动态变量名覆盖作用域内已有变量 } extract($_POST); // 直接把表单字段铺成变量 parse_str($_SERVER[QUERY_STRING]); // 不传第二参数同样铺变量这三行的共同点是“变量名由外部决定”。工具会把它们单独归类因为这类问题不像命令执行那样一眼看到system但危害一点不小常常能绕过前置的鉴权判断。另一块是敏感配置提取扫配置文件里的数据库账号、密钥、调试开关之类。这在 AWD 赛前尤其省事靶场源码里经常留着默认管理员密码或者调试模式没关直接看结果列表比翻config.php快得多。3. 核心模块拆解规则引擎、解析器与结果列表怎么配合3.1 规则引擎从函数名匹配到正则匹配理解规则引擎的分层决定了你后面能不能自己加规则。它的匹配大致分两层第一层是函数名精确匹配速度快、误报低适合system、eval、assert这类确定的高危函数第二层是正则匹配用于捕捉参数形态特征比如“include后面跟的不是字符串字面量”这种更细的条件。打个比方第一层像海关的黑名单名字对上就拦第二层像行为识别看的是形态。两层配合能覆盖大部分常见写法但也意味着层与层之间没有强制关联——它不会自动判断“这个$_GET是否流到了这个system”。这个数据流追踪的活儿得你自己做。自定义规则一般长这样写在一个配置或规则文件里// 规则条目示意函数名 危险等级 说明 [ name dangerous_call, pattern /\b(system|exec|shell_exec|passthru|popen)\s*\(/i, level high, desc 命令执行类函数调用需确认参数是否外部可控 ] // 正则型规则匹配未加引号的 include 参数 [ name dynamic_include, pattern /\b(include|require)(_once)?\s*\(\s*\$[a-zA-Z_]/i, level medium, desc 包含参数为变量检查是否可控且未做白名单校验 ]pattern是核心写正则时把\b边界带上能显著减少误命中level决定结果列表里的排序和颜色方便你先看高危desc建议写清“要确认什么”因为过几周再回来看没说明的规则你自己都不敢信。加规则之后一定要拿几个已知的安全写法测一遍确认不会大面积误报再全量跑。3.2 源码解析文件树与语法层面的轻量处理Seay 的另一块骨架是解析器负责把源码读进来、切出 token、还原文件之间的引用关系。它做的是轻量语法处理不会构建完整的 AST 调用图但对审计来说够用能识别函数定义位置、能定位变量在文件内的出现行、能把include的目标文件关联出来。这个能力直接体现在两个交互上。一是点击函数名可以跳到定义处翻大型项目时不用手搜二是文件树里能按目录结构看谁被谁引用。我一般先看入口文件index.php、admin/、api/这类因为外部流量总是从这里进来从入口往下的调用链才是攻击面最集中的地方。需要提醒的是解析器的边界它对动态拼接的文件名、vendor里的第三方库、被混淆过的代码基本无能为力。遇到这类文件工具给出的结果会特别少这时候别以为是安全的往往说明它没看懂。3.3 结果列表怎么读才能不当误报收割机结果列表是整个工具的出口也是新手最容易翻车的地方——把所有命中当成漏洞逐条写报告最后发现一半是误报。正确读法是三档过滤第一档高危 参数明确来自 $_GET/$_POST/$_REQUEST → 立即人工确认 第二档高危 参数是变量但来源未明 → 往上追两层赋值 第三档中危 参数为字面量或来自配置 → 记下低优先级第一档通常能在几分钟内就能定位到真问题这也是它作为 AWD 赛前工具的价值——比赛前时间紧你需要的是快速缩小范围而不是完整覆盖。第三档不是不重要而是投入产出比在赛前不划算赛后复盘时再补。3.4 一份可复用的审计流程把上面的模块串起来我通常按这个顺序走一个中型项目大概两小时内能出第一版结论# 1. 先确认源码指纹判断框架类型框架决定审计重点 grep -rl ThinkPHP\|Laravel\|CodeIgniter ./src --include*.php | head -5 # 2. 找入口文件确定外部可访问的路径 find ./src -maxdepth 2 -name index.php -o -name api.php | head -20 # 3. 把高危函数全量列出来和工具结果互相印证 grep -rn system\|eval\|assert\|include(\$\|require(\$ ./src --include*.php | wc -l第一步用框架特征定位技术栈ThinkPHP 和原生代码的审计重点完全不同第二步收敛攻击面只访问不到的代码优先级低第三步用命令行做交叉验证工具漏掉的地方命令行有时能补上两边结果对不上的地方恰好是最值得看的。这套动作跑熟之后再打开 Seay 导入你对结果的判断会快很多。4. 避坑与排查五条真实踩过的坑4.1 导入后文件树是空的现象选了目录进度条走完左侧树里什么都没有。原因多半是选了源码的上层目录工具按扩展名过滤后没匹配到任何 PHP 文件或者路径里带了中文和空格导致解析异常。解决确认选中的目录下直接就有.php文件用ls看一眼路径改成纯英文、无空格再试一次。4.2 扫描结果少得离谱现象一个几万行的项目只命中十几条。原因有两个常见来源一是过滤规则里排除了vendor和inc目录而项目的核心逻辑正好写在这两类目录里二是源码用了大量动态调用call_user_func、变量函数$fn()规则表匹配不到。解决临时放开过滤目录重扫一次同时用grep -rn call_user_func手动补一遍动态调用点。4.3 中文注释导致结果行号偏移现象点击结果跳到的行和实际代码对不上差了几行。原因是文件编码是 GBK工具按 UTF-8 读中文注释被拆成多字节后行计数出错。解决先把源码统一转成 UTF-8iconv -f gbk -t utf-8再重新导入。这个坑在对老项目时特别常见。4.4 工具被杀软拦截或提示风险现象解压后主程序打不开或者被安全软件直接隔离。原因是这类审计工具的二进制文件没有签名行为特征又容易被误判。解决在隔离环境里给它加白名单别在主力办公机上跑同时确认下载来源只从可信渠道取包。提示审计工具本身接触的是别人的源码跑在隔离的虚拟机里比跑在开发机上稳妥得多快照也能随时回滚。4.5 把工具结果直接当漏洞报告现象交上去的清单被逐条打回说大部分不可利用。原因是工具只做模式匹配不判断可达性和过滤有效性。解决每条结果都回源码确认三件事——参数是否外部可达、中间有无过滤、过滤能否绕过。确认不了的标为“待验证”不要写成“确认漏洞”。这条是血泪经验报告的可信度比数量重要得多。5. 二次开发与规则扩展让 Seay 适配你自己的代码库工具自带规则覆盖的是通用写法真正落到具体项目上一定要做扩展否则你会一直被大量误报和漏报夹击。我在改造上的做法分三步优先级从高到低。第一步是补自定义危险函数。内部框架通常会把执行、查询、文件操作封装一层比如Db::query()、Util::run()。这类封装在通用规则里根本不在名单上但危险程度和原生函数一样。做法是把这些方法名加进规则表正则写成能匹配静态调用和实例调用两种形态// 覆盖静态调用 Db::query(...) 与实例调用 $db-query(...) [ name inner_db_query, pattern /(?:[A-Za-z_\\\\]::|\$[a-zA-Z_][a-zA-Z0-9_]*\s*-)\s*query\s*\(/i, level high, desc 内部数据库封装检查 SQL 是否拼接了外部输入 ](?:...)是非捕获分组用来把两种调用形态并列\\\\是为了匹配命名空间里的反斜杠。写完先在一份已知安全的代码上跑误报率高就收紧正则别急着全量。第二步是给结果列表加自己的优先级维度。通用规则只有高中低三档但实际项目里“未授权访问”比“命令执行”更值得先看因为它不需要构造复杂 payload。我的做法是给规则加一个自定义标签比如auth_bypass、file_read结果区按标签再筛一遍先看未授权和数据读取类再看执行类。这一步带来的效率提升比多加一百条规则都明显。第三步是固化一套验证脚本。规则改完不能只靠肉眼看我一般写个小脚本做回归验证项方法通过标准已知漏洞样本放几个故意写坏的 PHP 文件进测试目录全部被命中已知安全样本放参数化查询、白名单包含的写法命中数为 0编码兼容同一份代码分别用 UTF-8 和 GBK 存一遍结果一致、行号正确大文件性能塞一个 5000 行的单文件扫描不卡死、耗时在可接受范围# 回归脚本的核心逻辑对比两次扫描结果数量 scan() { ./seay_cli --project $1 --rule ./rules/custom.rule --output out.txt; } scan ./samples/vuln grep -c high out.txt # 期望 0 scan ./samples/safe grep -c high out.txt # 期望 0--rule指向自定义规则文件--output把结果落到文本便于比对。这里要注意命令行接口在不同版本上可能不存在或参数名不同先确认你的版本支持哪些参数别照抄。没有命令行接口的话就退化成手动导入两个样本目录做对比结论一样成立。从那以后我每次动规则表都会先把上面这四个验证项走一遍再提交因为规则这东西改一处很容易影响全局没回归的话过两周你都不知道误报是从哪条规则冒出来的。希望这套流程能帮你在自己的项目上把工具用顺。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。