本节摘要:SOURCE 2.1:框架由 Ruby 编写,分用户接口层、核心框架层、基础库层;模块管理器、事件调度、插件系统协同。
Kali 上默认路径 /usr/share/metasploit-framework/;模块按类型分目录:
# 观察框架目录与模块组织 ls /usr/share/metasploit-framework/ ls /usr/share/metasploit-framework/modules/
modules/exploits/ modules/payloads/ modules/auxiliary/ modules/post/ modules/encoders/ modules/nops/
msfconsole 内 show exploits 即索引这些 Ruby 模块。目录即分类法:exploit/windows/smb/... 依次是"类型/平台/服务/模块名"。这是 Metasploit 最强的一个设计——模块路径本身就是文档。
理解这张图的关键是分清三层职责。以一次 SMB 扫描为例,数据在层间流动:msfconsole 收到命令 → Core 调度模块 → 模块调用 Rex 的 socket 能力发网络包 → 结果回填数据库。用户只面对最外层,看不到底层细节。
Rex(Ruby Extension Library)是地基。它封装了网络协议栈:Rex::Proto::Http 处理 HTTP/HTTPS 与 chunked 编码,Rex::Proto::SMB 封装 SMB 握手,Rex::Socket 提供跨平台 socket。开发者写 FTP 攻击模块时,不必亲手处理 TCP 握手、超时重传、协议状态机——这些脏活全部由 Rex 承担。
Rex 还处理渗透中的经典难题——坏字符。很多协议的字符串会被空字节 0x00、换行 0x0A 截断,Rex::Text 提供字符集转换、XOR 编码、Base64 变体等工具,保证生成的 shellcode 符合目标环境的字符约束。
# 简化示意:Rex 如何把底层细节藏起来 require 'rex/socket' sock = Rex::Socket.create_tcp('PeerHost' => '192.168.56.10', 'PeerPort' => 445) sock.put("\x00\x05..." + payload) # 开发者只关心业务数据 # 连接、超时、重传全部由 Rex 处理
MSF Core 不碰网络字节流,只做三件事:模块生命周期调度、会话管理、事件分发。它维护单例 Msf::Framework 实例,持有模块数据库、会话列表、任务调度器与线程池。控制台输入命令被封装为事件进入队列,由调度器统一处理——这保证了某个模块执行暴力破解等耗时操作时,框架不会假死。
Core 的 API 对用户太底层,Base 层做了面向接口的封装。Msf::Simple::Exploit、Msf::Simple::SessionManager 等类隐藏了线程管理、会话绑定等细节,只暴露"运行""停止""获取结果"等直观语义。同时 Base 层承担插件系统:插件可以通过监听器订阅 session_open 事件,而不必改动 Core 的事件循环。
# 通过控制台观察三层协作(隔离 lab) msfconsole -q use auxiliary/scanner/smb/smb_version set RHOSTS 192.168.56.10 run -j # 后台运行,观察事件驱动调度 jobs -l # Core 层任务列表
动态语言便于模块热加载与 mixin;开发者写 exploit 继承 Msf::Exploit 等基类,统一选项 OptAddress、OptPort。模块加载、验证选项、执行 cleanup 的标准流程由 Core 统一提供,新模块只需实现 exploit / run 方法。
⚠️ 常见坑:混用系统 Ruby 与框架 bundled gem——用发行版打包的
msfconsole启动最稳。手动改 gem 路径常常导致"找不到模块"或神秘崩溃。
💡 关键直觉:Base 层是「插件 OS」,接口层是「shell」。把 Metasploit 想成操作系统:Rex 是驱动,Core 是内核,Base 是系统调用库,模块是应用程序。
MSF Core 采用事件驱动模型。控制台输入命令被封装为事件,进入调度队列统一处理。以一次后台扫描为例:
# 观察后台任务与事件(隔离 lab) use auxiliary/scanner/portscan/tcp set RHOSTS 192.168.56.0/24 set PORTS 22,80,443,445 run -j # [*] Starting module as a background job # [*] 192.168.56.10:445 - TCP OPEN jobs -l # Id Name Payload Payload opts # 0 Auxiliary: portscan/tcp normal Normal
run -j 把扫描放进后台线程,控制台立即恢复响应;jobs -l 查看任务。这种异步机制确保某个模块执行耗时操作时,框架不会假死。事件在 Core 层产生,也通过 Base 层的插件接口被订阅——比如 session_open 事件可以触发报告生成插件。
插件是 Base 层提供的标准扩展机制。插件可以订阅框架事件、注册新命令、修改模块行为,而不触碰 Core 的事件循环代码。典型用途:自动保存每次 run 的屏幕输出、按项目归集会话、在 session_open 时自动执行后渗透命令。
# 查看与加载插件(隔离环境) msf6 > load -h # Usage: load <path> [var=val] msf6 > load db_tracker # 示例:加载数据库追踪插件 msf6 > plugins # 列出已加载插件
插件与模块是两种不同的扩展维度:模块扩展"攻击能力",插件扩展"框架行为"。理解这个区别,是二次开发的基础。
一次 SMB 版本探测请求,数据在三层间的流转如下:
msfconsole(用户接口层) └─ 解析 use auxiliary/scanner/smb/smb_version MSF Base(简化层) └─ 实例化模块、绑定参数 MSF Core(控制层) └─ 调度器启动任务线程,创建 Session 对象上下文 Rex(基础层) └─ Rex::Socket 建立 TCP 连接,Rex::Proto::SMB 封装协议包 目标主机 └─ 返回 banner → 沿原路回传 → 数据库记录
每一层只关心自己分内的职责,改动的涟漪被限制在单层之内。这正是 SOURCE 所称"三位一体架构之美"的工程意义。