
简介Seay源代码审计系统是一款面向PHP代码安全审计的Windows桌面工具专为AWD攻防对抗与代码审计人员设计。它可自动发现SQL注入、命令执行、文件包含、XSS跨站及绕过转义防护等常见漏洞并配有一键审计、代码调试、自定义规则与插件扩展等功能适合安全测试者快速定位目标站点薄弱点。资源包为7z压缩格式共30个文件大小约42.16MB。其中exe文件用于主程序与升级卸载dll类为运行依赖库rar与zip内含2.1源码、插件示例及代码审计资料整理另有html/php/ini/txt等覆盖配置说明与使用文档整体结构完整便于二次开发与学习。目前已有802人学习下载。通过该包可拿到完整程序、参考插件示例与源码既能直接部署用于日常审计也能参考其实现思路扩展自定义检测项是PHP代码审计和AWD训练中实用的工具型资源。1. Seay源代码审计系统AWD现场的第一台漏洞显微镜AWD赛前或者开场三分钟赛方把本方Web应用的源码压缩包发下来别人还在解包你已经想先扫出一片危险函数。Seay源代码审计系统就是为这件事准备的老牌工具把一个目录丢进去几秒到几十秒它会按内置规则把所有PHP文件里像后门、SQL注入、命令执行的高危调用列成清单。它不读语法树不做跨文件污点定位是“快速找出值得你人工翻的几十行代码”。适合CTF里打AWD的选手、接PHP项目做代码审计的从业者也适合临时要审查一份陌生代码的人。这篇文章按实操顺序讲清它是什么、怎么扫、怎么在AWD用、坑在哪。2. 起底Seay源代码审计系统工作原理与AWD选型对比2.1 规则扫描而不是语法分析这是Seay快的原因很多第一次用Seay的人会把它当成一个完整的安全编译器拿到输出结果就照单全收。实际上它的核心工作原理特别朴素把指定目录里的PHP文件按文本读进来然后用内置规则表逐行去做正则匹配。规则表里写的是危险函数名和常见的高危组合模式比如eval、system、mysql_query、$_GET配合include。某一行命中了它就在结果列表里记下文件名、行号和命中的函数名。?php // Seay的规则会在这里命中 mysql_query第5行但不会分析第2行的来源 $id $_GET[id]; $sql SELECT * FROM users WHERE id . $id; mysql_query($sql);正因为不做语法树和跨文件污点分析它才能在几百个文件的项目里几秒钟扫完。代价是它给出的结论永远只是“这里有危险函数调用值得你看一眼”而不是“这里有漏洞”。遇到函数封装、字符串拼接拆到多行、变量动态调用时它的匹配能力会明显下降这一点在第五章我会专门讲。规则表通常按风险等级分成几组命令执行类、SQL注入类、文件操作类、代码执行类。很多AWD玩家手里的Seay是改过的往规则表里加了create_function、preg_replace配合/e这种老式后门模式。扫描前最好确认自己用的规则表是完整的而不是某个精简阉割版。我一般会在拿到工具后先在自己的测试目录上扫一遍确认它能正常命中再拿上赛场。2.2 和Fortify、RIPS、grep比AWD场景下的最终选择有人会问为什么不用Fortify这种企业级静态分析工具Fortify能做污点追踪能画出输入到危险函数的完整路径但它启动慢、配置重、报告动辄几百页AWD的十几分钟窗口根本等不起。RIPS是PHP专用静态分析器思路比Seay先进但公开可用的版本多年没更新部署还要搭PHP环境临场折腾它属于自己给自己加戏。裸grep也能搜危险函数但你得自己想全关键词少写一个create_function就漏一片。工具扫描原理AWD第一轮体验主要限制Seay正则规则匹配秒级出结果误报多需要人工复核Fortify污点分析加语法树慢、环境重报告大不适合短平快RIPS语法树分析部署费劲对PHP版本挑剔grep/ripgrep纯文本搜索极快没有规则库拼写漏一个就漏报AWD的时间窗口以分钟计我选工具只看三个标准能不能离线跑、要不要装傻大黑粗的运行时、能不能快速改规则。Seay三条都满足Fortify第一条就不满足。另外Seay不联网不会把源码片段外传。你拿到赛方源码后不要在未授权环境里上传到第三方在线扫描器用本地工具处理既快又不会给自己惹麻烦。这个习惯在AWD里非常重要。2.3 安装与启动一个老工具在Windows上的正确姿势Seay是Windows桌面程序拿到的基本是zip压缩包。我不会把它放在桌面或者带空格的“Program Files”里而是固定放到一个纯英文短路径比如D:\awd_toolkit\seay\。老程序对中文路径和特殊字符敏感这算是实践里的玄学但碰多了你会发现它其实有理可循。解压后双击Seay.exe如果被系统拦截走“更多信息→仍要运行”如果提示缺少.NET组件装对应版本的.NET Framework再试。实在跑不起来的机器我会直接开一台Windows 7虚拟机把工具、源码、验证脚本都放进去比赛环境越接近本机越省事。注意很多杀毒软件会把这类老审计工具当作可疑程序。比赛前先在隔离环境里确认工具行为不要在开赛前五分钟才第一次运行它。安装完后建议做一次冒烟测试新建一个一行漏洞的test.php扫描看能不能命中。这一步虽然简单但我见过太多人跳过它结果上了赛场才发现规则表是空的白白浪费黄金时间。3. 用Seay跑一次完整源代码审计配置、判读与本地验证3.1 源码目录的准备先复制再开扫从拿到源码到开扫最常见的错误是直接在原始目录上扫描。在AWD里赛方给你的源码包可能同时是服务端的web根目录你扫的过程中误改、误删都会直接影响线上服务。而且补丁打到一半需要回滚时没有原始备份就只能干瞪眼。所以第一步永远是做副本。mkdir -p /tmp/awd_code cp source.zip /tmp/awd_code/ unzip -q source.zip -d /tmp/awd_code/code cp -a /tmp/awd_code/code /tmp/awd_code/code_orig第一条命令建工作目录第二条把原始压缩包留底第三条解压源码第四条把刚解压的目录复制一份作为补丁前的基线。这套操作花不到半分钟但它是你调补丁时最可靠的后悔药。打完一场比赛code_orig还能拿来做复盘对比到底改过哪些文件、哪些地方差点改错。3.2 扫描参数的选择先扫业务代码还是连vendor一起扫打开Seay选代码目录点扫描。点下去之前先想想当前项目要不要带依赖目录。很多版本支持递归扫描文件扩展名我一般只留php、phtml、incjs、css、图片文件扫了只会增加干扰项。AWD里我会先只扫业务代码目录不扫vendor/。原因是依赖目录动辄上千个文件扫出来的命中基本集中在第三方框架函数上同一份报告里真假混在一起很难在十分钟内分辨。如果业务目录扫不出东西再补扫一次vendor重点看有没有已知框架漏洞特征。还有一点第一次点扫描后界面可能卡住几十秒那是它在加载规则库和遍历文件树不是死机。我见过有人以为工具坏了反复重启反而把之后的操作窗口浪费掉。真等一两分钟进度条不动再考虑排查问题。3.3 扫描结果的判读高危到底高在哪扫描完成后结果列表会按文件、行号和风险等级列出命中项。不同版本的标记方式略有差异常见是这样[c] D:/webroot/user.php 第90行 mysql_query [e] D:/webroot/util.php 第42行 system [w] D:/webroot/config.php 第10行 $$变量正确读法不是每一行都点开而是先把高危项按文件归类优先看业务入口文件比如index.php、user.php、admin/*.php。双击某一行程序会跳到对应代码位置这时候去看命中行附近十行代码重点确认三件事这个变量是不是来自请求参数中间有没有被intval、htmlspecialchars、预处理语句过滤过这个函数所在页面是不是从公网能访问到。三件事里只要有一个“否”基本可以放掉。比如下面这个例子Seay会命中mysql_query但漏洞其实已经被堵住了$id intval($_GET[id]); mysql_query(SELECT * FROM users WHERE id $id);所以当有人说“我跑了Seay就是补完了”那是把候选清单当成了最终结论。在AWD里被Seay的误报带着跑的队伍输得往往比不扫描的还快。3.4 本地验证php -S 与curl快速确认漏洞确认一个命中项是不是真漏洞最快的方式是在本地起一个PHP服务拿curl打一发。没有现成集成环境也没关系PHP自带内置服务器就够了。php -S 127.0.0.1:8000 -t /tmp/awd_code/code curl http://127.0.0.1:8000/user.php?id1%27如果服务器抛出了SQL语句相关错误说明注入点基本实锤如果页面空白可能是display_errors没开改一下PHP配置再试。对于命令执行类命中可以传一个无副作用的探测参数比如cmdid看返回里有没有uid。提示本地验证时把display_errorsOn打开很多命中项一眼就能判定。但正式比赛不要在本方服务器上开错误显示那等于把自己漏洞的位置广播给对手。4. AWD实战黄金十分钟攻防操作套路4.1 拿到源码后的黄金十分钟操作顺序AWD开场经常会把源码压缩包发下来接下来十分钟是攻防节奏最关键的一段。我见过有人前几分钟全耗在解压和等IDE索引上等Seay跑完对面补丁都上完了。推荐顺序是第0到1分钟解压、留原始备份、打开Seay。第1到4分钟扫描业务代码收集高危命中。第4到7分钟针对前2到3个命中项做本地验证。第7到10分钟验证通过的漏洞立刻补到自己服务器剩下时间转进攻。在Seay跑的同时我还会用ripgrep拉一份所有用户输入来源的清单作为交叉验证rg -n \$_(GET|POST|REQUEST|COOKIE) --type php /tmp/awd_code/code | head -50这行命令把所有引用超全局变量的行都列出来包括Seay规则没覆盖到的写法。两份列表取交集交集中的文件就是优先级最高的审计目标。Seay负责知道“哪里可能有坑”rg负责帮你补“Seay没看出来但确实存在的坑”。4.2 防守最小改动补自家漏洞别给自己留后门AWD防守的第一原则不是“修得优雅”而是“修完页面还正常”。拿SQL注入来说最稳妥的通用做法是改成预处理语句但一个老项目里几十处mysql_query临场全改PDO会改到天荒地老还容易把页面改挂。所以我会分类型处理。数值型参数直接intval收口// 原代码 $id $_GET[id]; $row mysql_fetch_array(mysql_query(SELECT * FROM news WHERE id$id)); // 最小补丁只动一行 $id intval($_GET[id]); $row mysql_fetch_array(mysql_query(SELECT * FROM news WHERE id$id));修改前先把原文件备份cp user.php user.php.bak如果补丁把页面改崩了直接把.bak复制回去几秒钟恢复服务不会因为一个补丁把整台防守服务器带走。字符型参数我不会用addslashes当最终方案它只够在十分钟内临时堵一下比赛结束后还是要用mysql_real_escape_string或者预处理语句重写。这个边界要拎清楚AWD求的是撑住这一轮不是写出教科书代码。4.3 进攻用审计结果快速造可用PayloadSeay报告不是只能用来防守它同时也是进攻的路线图。拿到一个已确认的命令执行点别在终端里一条条curl手动打了写个短脚本更高效import requests url http://目标IP/vuln.php # Seay命中system($_POST[cmd])是AWD里典型的命令执行点 resp requests.post(url, data{cmd: cat /flag}, timeout5) print(resp.text[:500])脚本里可以先在本地php -S的地址上跑一遍确认Payload不会打崩目标再改URL指向对手服务器。如果目标没有requests库就先退回curl单发不要为了环境折腾浪费比赛时间。SQL注入则可以把cmd参数换成1 AND sleep(3)这类延时探针看响应时间决定盲注是否成立。一个很容易踩的节奏问题是在某个对手身上花太多时间。Seay报告里如果还剩其他命中项打不进去就换下一个目标。AWD的进攻本质是流水线不是单挑。5. Seay实战常见的坑与排查记录5.1 扫描结果为0规则库与编码问题排查现象选择目录点扫描进度条走完结果列表空荡荡。原因最常见的三个规则库没加载或被人改坏代码文件编码不统一老工具按文本读的时候正则匹配不上PHP文件开头没有?php程序没把它当成PHP来扫。解决先创建一个只含?php system($_GET[cmd]);的测试文件扫一遍确认工具本身能出结果。再检查规则管理里的规则数量少了就恢复默认规则。最后在副本目录做编码统一再扫find /tmp/awd_code/code -name *.php -exec iconv -f gbk -t utf-8 {} {}.utf \; -exec mv {}.utf {} \;注意这条命令只该在副本上执行原始备份不要动。如果项目本来就是UTF-8编码转换会造成乱码先拿file命令确认文件真实编码再决定。5.2 误报刷屏先做减法再做判断现象一扫描三百多条“高危”一半是system、exec看起来全是后门。原因老项目经常有公共函数像run_cmd()、wlog()里面调一次system然后全项目到处调用它。Seay只看函数名不认识封装于是每一处调用都被标红。解决在规则库里把system这种公共危险函数暂时降级或者停用重新扫一遍也可以直接在结果里按文件名过滤把helper.php、function.php这类公共文件的命中先放一边。AWD时间有限误报高时不要硬刚列表先看业务文件里有没有用户输入直接触达这些函数再看公共封装。误报意味着时间黑洞学会跳过也是实战能力。5.3 漏报背后正则扫描器的真实盲区现象Seay扫完很干净结果一开场本方被人灌了复盘发现漏洞就躺在原代码里。原因多行拼接字符串、$$变量、可变函数$fn()、老式preg_replace配合/e这几种写法都能躲过单行规则。另外Seay默认规则对$_COOKIE这类输入来源覆盖不完整很多攻击入口根本没进规则。解决依赖Seay但不只依赖Seay。用rg补一轮自定义模式扫描rg -n assert\s*\(|create_function|\$_(GET|POST|REQUEST|COOKIE)\s*\[|preg_replace\s*\(.*\/e|call_user_func --type php /tmp/awd_code/code命中项不一定都是洞但这些写法比Seay更容易漏掉的模式里藏着后门。我在AWD里会把这份输出和Seay结果合并交集先看差集作为备份线。5.4 打不开、闪退兼容性与运行库排查现象双击Seay.exe没反应或者弹“应用程序无法启动”的错误框Windows 10/11上尤其常见。原因老工具依赖.NET运行库版本缺失或不对杀毒软件把主程序或规则文件当作可疑对象清了路径里有中文或空格老程序解析出错。解决按顺序做——装.NET Framework 4.x重启把工具目录放到D:\awd_toolkit\seay这种纯英文路径右键主程序属性兼容性标签里选Windows 7或Windows XP SP3最后把整个目录加进杀毒软件白名单或者干脆在一台离线Windows 7虚拟机里运行。这套东西琐碎但真在赛前遇到会非常被动。我的建议是比赛前就把跑通的环境固定下来别赌现场人品。6. 让Seay沉淀成自己的审计知识库自定义规则与验证习惯6.1 把赛场经验写进规则库Seay的规则库可编辑这是它比普通扫描器更有沉淀价值的地方。打完一场AWD把比赛里遇到的规则没覆盖的知识点整理成新规则加进去。比如遇到create_function后门规则可以写成类似这样名称create_function代码执行 正则(?i)create_function\s*\([^,],[\]\s*(eval|base64_decode|assert) 风险高加完重新扫一遍下次这个模式就不会被放过了。规则文件会慢慢长成属于自己队伍的“敌方后门清单”这个沉淀比工具本身更值钱。6.2 验证记录与“文件行号”的协作习惯AWD里我习惯开一个notes.md每一条命中写一行user.php:90 mysql_query 已确认注入补丁intval util.php:42 system 已确认命令执行禁用该功能这行记录用于团队协作和赛后复盘。比赛节奏一乱人容易忘掉自己改过哪个文件顺手记一行回来一看就续上。我自己的习惯是拿到源码先跑Seay把命中项交给人工复核结果永远只当线索不当结论。这个习惯在关键局里救过我很多次希望帮到你。本文还有配套的精品资源点击获取