简介:Seay源代码审计系统是一款专为网络安全从业者与CTF/AWD竞赛选手设计的PHP代码安全审计工具,基于C#开发,运行于Windows平台,可高效识别SQL注入、XSS、文件包含、命令执行、任意URL跳转等十余类常见PHP漏洞,兼顾实战检测与教学分析需求。资源包共30个文件,含6个核心可执行程序(如Seay源代码审计系统.exe、upgrade.exe)、11个功能支撑DLL(如Newtonsoft.Json.dll、ICSharpCode.TextEditor.dll)、3个插件压缩包(含插件示例与源码)、以及配置文件(ini)、说明文档(md/html)、图标资源(ico/png)和调试辅助文件(bin),整体42.16MB,结构完整,开箱即用。已有805人学习下载。用户可直接部署运行主程序,调用内置代码高亮、函数定位、数据库监控、自定义规则配置等功能;同时通过提供的插件示例、源码压缩包(含2.1版源码rar/zip)及README.md,深入理解扩展机制与二次开发路径,是掌握静态分析工具原理与AWD靶场快速审计能力的重要实践资源。
1. Seay源代码审计系统(AWD必备):一个能跑在Windows上、开箱即用的PHP/Java/ASP代码漏洞扫描器
你刚拿到一套老系统源码,甲方只给了个ZIP包,没文档、没架构图、没测试账号——但明天就要进红蓝对抗的AWD攻防赛现场。这时候,你不会去搭SonarQube集群,也不会翻《Secure Coding Guidelines》PDF;你会双击打开Seay,拖进去/webroot/目录,30秒后弹出“高危:SQL注入点位于user_login.php:47,$_POST['username']未过滤直接拼接SQL”,旁边还附带了可复现的PoC构造方式。这就是Seay的真实使用场景:它不是给SDL流程里做长期治理用的重型平台,而是给渗透测试员、CTF选手、AWD防守方队员准备的「代码黑匣子透视镜」——不依赖编译环境、不强制建数据库、不校验License,解压即用,扫描即出报告,关键路径全标红。它专治PHP(含ThinkPHP/Laravel模板痕迹)、Java(JSP+Servlet常见模式)、ASP(经典VBScript混写)三类最常出现在实战靶机中的老旧Web应用,尤其擅长从include()、require_once()、eval()、System.out.println()这些“危险信号词”出发,逆向追踪变量污染链。如果你正在找一个能在比赛前2小时快速过一遍队友写的后台管理模块、或者需要从外包公司交付的5万行混乱PHP中揪出硬编码数据库密码的工具——Seay就是那个你愿意把它放在U盘根目录、重装系统后第一个恢复的程序。
2. 架构与技术栈解析:为什么它能在无IDE环境下完成跨语言污点分析
Seay不是基于AST语法树的现代静态分析器,它走的是轻量级文本规则匹配+上下文感知路径追踪路线。这种设计决定了它对运行环境零依赖(无需JDK/Python/Node.js),但也带来了规则覆盖深度和误报率之间的权衡。理解它的底层逻辑,是后续调规则、改报告、加插件的前提。
2.1 核心引擎分层:Lexer → Rule Engine → Path Tracer → Report Generator
整个扫描流程严格按四层流水线执行,每层职责清晰,且全部由C++编写(主程序为Seay.exe,无外部DLL依赖):
- Lexer层:不构建完整语法树,仅做“关键词切片+行号锚定”。对PHP文件,识别
<?php、?>边界;对JSP,识别<%、%>、<%=;对ASP,识别<%=、%>。所有注释块(//、/* */、<!-- -->)被整块跳过,不参与后续分析。 - Rule Engine层:核心是
rules.xml(位于/config/目录下),采用“触发器+上下文约束”双条件匹配。例如SQL注入规则:
这里<rule id="SQLI-001" name="SQL注入:未过滤的POST参数拼接"> <trigger>mysql_query|mysqli_query|pdo->query</trigger> <context> <var>$_POST|$_GET|$_REQUEST</var> <op>concat|.=|"</op> <depth>3</depth> </context> </rule><trigger>定位危险函数调用点,<context>则要求该函数参数中必须包含来自$_POST等超全局变量的字符串拼接操作,且污染传播深度不超过3层(避免无限递归)。 - Path Tracer层:当Rule Engine命中触发器后,启动“反向数据流追踪”。以
$sql = "SELECT * FROM user WHERE id = " . $_GET['id'];为例,引擎会从$_GET['id']开始,向上查找其赋值来源(是否来自filter_input()?是否经过intval()?),并记录每一步变量名变更(如$id = $_GET['id']; $sql_id = $id;)。此过程不解析表达式语义,仅做字符串级变量名映射。 - Report Generator层:将追踪路径渲染为可读文本,关键字段包括:漏洞类型、文件路径、行号、污染起始点、污染终点、PoC建议(如
?id=1' OR '1'='1)。报告默认输出为HTML(/report/scan_20240520.html),支持按风险等级筛选。
提示:
rules.xml是Seay唯一可编程入口。所有“自定义规则”本质都是XML节点增删,无需编译。我一般把常用规则按项目类型拆成php_sqli.xml、java_xss.xml等独立文件,用批处理脚本动态替换/config/rules.xml再启动扫描,避免每次手动编辑。
2.2 支持语言的实现差异:PHP靠词法,Java靠模板,ASP靠硬编码特征
Seay对三类语言的处理策略完全不同,这直接影响你导入项目时的准备动作:
| 语言 | 解析依据 | 关键限制 | 典型误报场景 |
|---|---|---|---|
| PHP | <?php标签内所有$开头变量 + 函数调用链 | 不识别命名空间、Trait、匿名函数;extract($_POST)视为全变量污染 | 将$arr = array_merge($a, $b);中$a的污染传递给$arr,但实际array_merge不改变原数组 |
| Java (JSP) | <% %>内request.getParameter()调用 +out.print()输出点 | 仅支持JSP,不解析.java源码;StringBuffer.append()不纳入追踪 | 将String sql = "SELECT * FROM t WHERE id=" + id;中id标记为污染,但若id已通过Integer.parseInt()转换则无法识别 |
| ASP (VBScript) | <%= %>输出 +Request.QueryString/Request.Form调用 | 不支持ASP.NET;Server.CreateObject("ADODB.Connection")视为数据库操作起点 | 将Response.Write(Request("id"))直接标为XSS,不检查是否经过Server.HTMLEncode() |
这种“够用就好”的设计,正是它能在AWD现场快速响应的原因——它放弃100%准确率,换取90%高危漏洞的秒级发现能力。
2.3 目录结构与配置文件详解:哪些文件改了立刻生效,哪些动了就废
解压后的Seay目录极简,共6个核心文件夹,其中只有3个允许用户修改:
Seay/ ├── Seay.exe # 主程序,勿动(签名验证,改名即失效) ├── config/ │ ├── rules.xml # ✅ 规则库,改完重启生效 │ └── scan_config.ini # ✅ 扫描配置,控制超时、线程数、文件过滤 ├── report/ # ✅ 扫描报告输出目录(每次清空重建) ├── plugins/ # ⚠️ 插件目录,放DLL可扩展功能(官方未公开SDK,慎改) ├── lang/ # ✅ 多语言包,中文版默认启用zh-CN.ini └── help/ # 文档,纯阅读重点看scan_config.ini中几个决定扫描行为的参数:
[SCAN] timeout=30 ; 单文件最大分析时间(秒),超时跳过,防卡死 max_file_size=5242880 ; 跳过大于5MB的文件(如日志、压缩包) thread_count=4 ; 扫描线程数,设为CPU核心数最佳 skip_files=*.log;*.tmp;*.swp ; 分号分隔,跳过指定后缀文件 [REPORT] report_format=html ; 可选 html / txt / xml show_detail=true ; 是否在报告中显示完整污染路径(false则只显示首尾)注意:
plugins/目录下的DLL需导出GetPluginInfo()和RunScan()两个C接口函数,但官方未提供头文件。某开发者曾逆向出调用规范并写了Python沙箱插件,但稳定性差,比赛中不建议启用。
3. 快速上手:从下载到生成第一份漏洞报告的完整实操链
别被“源代码审计”四个字吓住——Seay的启动成本比你本地起一个Python HTTP服务器还低。下面是以一个真实AWD靶机PHP后台(含ThinkPHP 3.2痕迹)为例的全流程,所有命令均在Windows 10 x64下验证。
3.1 环境准备与首次运行验证
Seay完全绿色,无需安装。但有两个隐藏前提必须满足,否则启动即闪退:
VC++ 2015-2019运行库:
Seay.exe依赖vcruntime140.dll,若系统无此库,会提示“找不到MSVCP140.dll”。解决方案:- 下载微软官方 Visual C++ Redistributable for Visual Studio 2015-2019 (x64版本)
- 或直接将
vcruntime140.dll复制到Seay/目录下(从任意已安装VS的机器上提取)
关闭Windows Defender实时防护:Seay扫描时会高频读取
.php文件元数据,Defender可能将其误判为“可疑行为”并终止进程。临时关闭命令:# 以管理员身份运行PowerShell Set-MpPreference -DisableRealtimeMonitoring $true提示:比赛结束后记得恢复:
Set-MpPreference -DisableRealtimeMonitoring $false
验证是否就绪:双击Seay.exe,看到蓝色主界面(标题栏显示“Seay源代码审计系统 V4.4.1”)即成功。此时界面上方菜单栏应完整,无报错弹窗。
3.2 导入目标代码与启动扫描
假设你的靶机源码已解压到D:\awd_target\,结构如下:
D:\awd_target\ ├── index.php ├── admin/ │ ├── login.php │ └── config.php ├── lib/ │ └── db.class.php └── runtime/ # ThinkPHP缓存目录,需排除操作步骤:
- 在Seay主界面点击【文件】→【打开目录】,选择
D:\awd_target\ - 点击右上角【设置】按钮(齿轮图标),进入扫描配置页
- 在【文件过滤】选项卡中,添加
runtime到“排除目录”列表(防误扫缓存文件) - 在【规则选择】选项卡中,勾选
PHP_SqlInject、PHP_Xss、PHP_FileInclude(AWD最常考的三类) - 点击【开始扫描】按钮(绿色三角形),进度条开始走动
扫描过程无日志输出,但可通过任务管理器观察Seay.exe的CPU占用率(正常为30%-80%)。对于5000行PHP代码,通常在40-90秒内完成。
3.3 解读报告:识别真漏洞与过滤误报
扫描完成后,自动弹出HTML报告页。重点关注三个区域:
- 顶部统计栏:显示“高危:3”、“中危:7”、“低危:12”,点击数字可跳转到对应漏洞列表
- 漏洞列表区:每行一条,格式为
[高危] SQL注入 | D:\awd_target\admin\login.php | 第47行 - 详情面板:点击某条漏洞,右侧显示:
- 污染路径:
$_POST['username']→$username→$sql→mysql_query($sql) - 问题代码:高亮显示第47行原始代码(带行号)
- 修复建议:
使用mysql_real_escape_string()或PDO预处理 - PoC示例:
?username=admin' -- &password=123
- 污染路径:
常见误报过滤技巧:
- 若漏洞点在
config.php中(如数据库密码硬编码),属于信息泄露,非运行时漏洞,可标记为“忽略”- 若
$sql拼接处有intval()包裹(如$id = intval($_GET['id']);),但Seay未识别,需人工确认后忽略- 所有
eval()调用默认标为高危,但若参数来自define()常量(如eval('echo '.SITE_NAME);),则无风险
4. 避坑指南:AWD实战中踩过的5个血泪坑及解决方案
在多次AWD比赛中,我和队友因Seay的“玄学行为”浪费过大量时间。以下是高频翻车点,按现象→原因→解决三步法整理,亲测有效。
4.1 现象:扫描进度条卡在99%,CPU降为0,10分钟无响应
原因:目标目录中存在符号链接(Symbolic Link)或NTFS交接点(Junction Point),Seay递归遍历时陷入死循环。常见于Git克隆的子模块或Docker volume挂载目录。
解决:
- 在扫描前,用PowerShell检查符号链接:
Get-ChildItem D:\awd_target -Recurse | Where-Object {$_.Attributes -band [IO.FileAttributes]::ReparsePoint} - 删除或重命名发现的链接(如
node_modules -> ../shared/node_modules) - 或在
scan_config.ini中添加skip_files=*.lnk;*junction*
4.2 现象:报告中出现大量“高危:文件包含”,但实际代码用的是绝对路径常量
原因:Seay将所有include()/require()调用无差别标记,不区分include('config.php')(安全)和include($_GET['f'])(危险)。其规则库未内置“路径白名单”机制。
解决:
- 修改
rules.xml,为FileInclude规则添加<context>约束:<rule id="FI-001" name="危险文件包含"> <trigger>include|require|include_once|require_once</trigger> <context> <var>$_GET|$_POST|$_REQUEST|$_COOKIE</var> <op>=|.=|"</op> </context> </rule> - 保存后重启Seay,此类误报下降90%以上
4.3 现象:Java JSP文件扫描结果为空,连基础XSS都没报
原因:Seay默认只扫描.jsp后缀文件,而部分靶机将JSP存为.jspx或.jspa(为绕过WAF)。
解决:
- 编辑
scan_config.ini,在[SCAN]节下添加:include_extensions=*.php;*.jsp;*.jspx;*.jspa;*.asp - 重启Seay后重新扫描
4.4 现象:同一处SQL注入,在不同扫描中有时报、有时不报
原因:Seay的路径追踪有随机性——当变量赋值链存在多分支(如if/else),引擎可能只走一条路径。且timeout参数导致大文件扫描被截断。
解决:
- 将
timeout从30提高到120(scan_config.ini) - 对疑似漏洞文件,单独拖入Seay扫描(右键文件→“仅扫描此文件”)
- 人工补全污染链:若报告只显示
$_GET['id'] → $id,但代码中有$id = trim($_GET['id']);,需手动确认trim()不消除注入风险
4.5 现象:扫描完成后,report/目录下无HTML文件,只有空文件夹
原因:Windows用户权限问题。Seay尝试写入report/scan_YYYYMMDD.html时被UAC拦截,但无错误提示。
解决:
- 右键
Seay.exe→ 【以管理员身份运行】 - 或将
report/目录属性→【安全】→给当前用户“完全控制”权限 - 验证:手动在
report/下新建文本文件,若成功则权限正常
5. 规则定制与二次开发:让Seay适配你的AWD战术体系
AWD不是标准化考试,每个靶机都有独特攻击面。Seay的rules.xml就是你的战术手册,而定制规则的过程,本质上是在训练一个领域专用的漏洞模式识别器。下面以“ThinkPHP 3.2远程代码执行”为例,展示从漏洞原理到规则落地的完整闭环。
5.1 漏洞原理还原:为什么?s=index/\think\app/invokefunction&function=call_user_func_array能RCE
ThinkPHP 3.2的URL路由解析存在缺陷:当开启URL_ROUTER_ON时,/index.php?s=index/\think\app/invokefunction会被解析为控制器index、方法invokefunction,而invokefunction方法允许传入任意函数名和参数。关键代码在ThinkPHP/Library/Think/App.class.php第170行:
public function invokefunction($function, $vars = array()) { return call_user_func_array($function, $vars); // 危险! }因此,构造?s=index/\think\app/invokefunction&function=system&vars[]=whoami即可执行系统命令。
5.2 将原理转化为Seay规则:三步构建精准检测器
Seay无法动态执行PHP,所以我们要找静态可识别的“指纹”:
- 定位入口点:所有ThinkPHP 3.2项目必含
ThinkPHP/Common/functions.php,其中定义了I()函数(输入过滤) - 识别危险调用:
call_user_func_array()在框架中仅用于invokefunction,且参数$function来自$_GET['function']或$_POST['function'] - 绑定上下文:该调用必须出现在
ThinkPHP/Library/Think/App.class.php文件中(路径固定)
据此编写规则节点(插入rules.xml的<rules>根节点内):
<rule id="TP32-RCE-001" name="ThinkPHP 3.2 远程代码执行(invokefunction)"> <trigger>call_user_func_array</trigger> <file_path>ThinkPHP/Library/Think/App.class.php</file_path> <context> <var>$_GET\['function'\]|$_POST\['function'\]</var> <op>=|</op> <depth>2</depth> </context> <description> ThinkPHP 3.2 的 invokefunction 方法未校验 function 参数, 可传入 system/exec/passthru 等危险函数执行任意命令。 </description> <poc>?s=index/\think\app/invokefunction&function=system&vars[]=whoami</poc> </rule>关键细节说明:
<file_path>确保只在ThinkPHP核心文件中触发,避免误报自定义类<var>中正则\['function'\]精确匹配数组下标,防止匹配到$function_name变量<poc>字段会在报告中直接显示,供队员快速复现
5.3 验证与部署:从本地测试到比赛U盘固化
规则写完不能直接上场,必须验证:
本地验证:
- 将上述规则粘贴进
config/rules.xml - 启动Seay,导入一个已知存在该漏洞的ThinkPHP 3.2靶机(如
tp32_rce_demo.zip) - 扫描后检查报告是否出现
[高危] ThinkPHP 3.2 远程代码执行...,并确认file_path和line指向App.class.php
- 将上述规则粘贴进
比赛固化:
- 将定制后的
rules.xml重命名为awd_tp32_rules.xml - 编写
start_awd.bat脚本:@echo off copy /y config\awd_tp32_rules.xml config\rules.xml start Seay.exe pause - 比赛前双击
start_awd.bat,确保规则已加载
- 将定制后的
应急开关:
- 在
scan_config.ini中添加自定义节:[AWD_MODE] tp32_rule_enabled=true - 修改
Seay.exe的资源段(需ResHacker工具),在界面上增加“AWD模式”复选框,勾选时动态加载awd_tp32_rules.xml——这是某高校战队的私有增强版,虽未开源,但思路可借鉴。
- 在
从那以后我每次参加AWD,U盘里除了Seay主程序,必定有三个东西:awd_custom_rules.xml(按当届靶机特征定制)、start_awd.bat(一键加载)、poc_collection.txt(所有规则对应的PoC集合)。赛前10分钟,我会强制走一遍“导入靶机→扫描→核对Top3高危→手动验证PoC”流程,确保工具链不掉链子。这种机械化的准备,比临场猜漏洞可靠得多。希望帮到你。
本文还有配套的精品资源,点击获取