news 2026/10/18 6:57:38

SILENTTRINITY模块开发实战:用Boo语言编写后渗透侦察模块

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SILENTTRINITY模块开发实战:用Boo语言编写后渗透侦察模块

“SILENTTRINITY”这个词,我在好几年前第一次看到时,第一反应是“又一个 C2 框架”。真正上手用了一个星期后,我改变了对它的看法——它最大的亮点不是通信方式多花哨,而是模块扩展机制:用 Boo 语言写后渗透模块。你不需要重新编译整个框架,不用去啃 C# 底层,只要放一个.boo文件进目录,几秒钟后这个新功能就能在当前任务会话里被调用。这篇文章就是我沉淀了这段时间的经验之后整理出来的,从环境搭建、Boo 语法、模块结构,到一个完整的信息侦察模块实现,全部走一遍。适合正在做红队工具建设、渗透测试流程自动化,或者刚接触 SILENTTRINITY 但不知道模块怎么写的同学。

1. 整体设计与开发思路

1.1 SILENTTRINITY 的模块化设计

先看官方源码结构,你会发现模块就是服务端和客户端之间的“翻译层”。框架本身是一个标准的 C2 架构:服务端负责控制、生成 payload、维护会话;客户端(植入目标机器的那部分)负责执行任务并回传结果。传统的 C2 框架里,如果你想加一个新功能,往往要改服务端逻辑、改客户端逻辑、重新编译一个完全不同的 agent,维护成本非常重。

SILENTTRINITY 的做法是把“任务逻辑”单独抽象成一个模块。任务从服务端下发时,实际上发给客户端的是一段经过编译的 Boo 脚本引用信息,客户端会匹配到对应的模块类,实例化,然后调用它的Execute方法。你写的模块只需要关心“怎么执行、返回什么结果”,至于通信协议、加解密、载荷交换这些,全都有框架处理。

这样的好处就是你写的新模块能立刻被所有在线客户端使用。不需要为不同架构的 payload 各维护一份模块代码,因为模块是在服务端这边定义、编译、注入到客户端的。这个设计思路对做红队自动化特别友好,因为我可以在一个项目里积累大量模块,按需启用,而不是维护一整套重复的工具链。

1.2 模块类型与应用场景

从功能性质上来分,后渗透模块大致可以分成这几类:信息侦察、文件操作、进程管理、权限操作、横向移动辅助、持久化。一般来说,凡是“单次操作、返回结果”的功能都适合做成 SILENTTRINITY 模块。比如你想获取目标系统信息,那就是一个典型的侦察模块,调用 .NET 的System.Environment拿版本、拿用户、拿机器名,然后拼一个字符串返回。复杂一点的像横向移动,会涉及很多前置条件和参数处理,但只要拆解清楚,同样可以做进模块里。

我在实际做模块规划时有一个经验:先写最简单的一类,也就是“无参数或只有一个参数”的侦察模块。这样能快速验证框架的加载流程、数据回传流程和理解上下文对象的工作方式。等你有了感觉,再去做带多个参数、带交互过程的复杂模块,难度就不是线性上升,而是模块化思考带来的友好扩展了。

1.3 模块开发的完整流程

一个模块从想法到落地,遵循下面的闭环:

  1. 确认接口:阅读你当前版本的 SILENTTRINITY 源码,找到模块基类、命名空间和方法签名。
  2. 搭建 Boo 环境:不用真的单独装一个 Boo 解释器,但准备一个简单的 Boo 脚本调试工具能让语法检查更快。
  3. 编写模块代码:把功能拆成几个 .NET API 调用,处理好参数和异常。
  4. 放置文件并加载:把.boo文件放到模块目录,框架会自动发现它。
  5. 执行测试:通过控制台或监听器调用该模块,观察回显和日志。
  6. 迭代:根据日志修正问题,优化输出格式和异常处理。

很多新手会跳过第一步,上来就套用网上旧的示例,结果在新版本框架上加载报错,然后一头雾水。接口版本对不上的问题可能是你遇到的第一个大坑,所以后面我会专门留一节讲模块加载时的排查。

2. 环境准备与 Boo 语言快速入门

2.1 搭建开发环境

SILENTTRINITY 是基于 .NET 环境构建的,所以你的开发机器需要对应版本的 .NET SDK。我建议从项目主页获取最新 release 或直接 clone 源码,按照 README 的说明编译服务端和客户端组件。这个过程里你可能需要装一些 NuGet 依赖,如果网络状态不好,可能会卡在下载这一步,解决办法是配置镜像源或者提前把依赖缓存好。

编译好之后,重点看源码目录下的 Modules 文件夹。你新增的每个.boo文件都应该放在这个目录里,框架启动时会扫描这个目录,把模块注册到列表。你要留意文件名不能有中文和特殊符号,尽量用大小写敏感的英文命名,因为 Boo 编译时对文件名和类名的对应关系比较敏感。

另外我建议准备一个单独的文本编辑器加 Boo 语法高亮插件,或者直接用支持 Boo 语言扩展的编辑器。虽然 Boo 语法比较轻量,但好的高亮能帮你提前发现缩进和括号问题。这个语言对缩进有要求,虽然不是像 Python 那样完全以缩进界定代码块,但整体风格非常接近 Python 和 C# 的混合体。

2.2 Boo 语法速览

Boo 是一个运行在 .NET 平台上的动态语言,语法流畅,对 C# 开发者很友好,对 Python 开发者也不会陌生。下面几个语法点是你写 SILENTTRINITY 模块时最常用的。

  • 变量定义:
# 显式类型 name as string = "zhangsan" count as int = 10 # 使用 def 定义变量 def value = 3.14
  • 方法定义:
def Add(a as int, b as int) as int: return a + b
  • 类和继承:
class MyModule(AbstractModule): Name as string: get: return "my_module"
  • 调用 .NET API:
import System.Diagnostics process = Process.Start("cmd.exe", "/c whoami") output = process.StandardOutput.ReadToEnd() return output
  • 列表和字典:
items = [] items.Add("a") users = {"admin": "1", "guest": "0"} for key in users: print("$key = ${users[key]}")

你可能会发现 Boo 的def关键字非常有用,它既能定义变量,也能定义方法。这个“鸭子类型”特性让你可以在不确定返回类型时直接使用def,然后在运行时获得 NET 对象。

有一个坑需要提前提醒:Boo 对字符串插值用$而不是 C# 的插值写法,并且字典的遍历顺序不像 Python 3.7 以后那样保持插入顺序,所以如果你用字典收集数据再输出,要注意顺序问题。

2.3 编写第一个 Hello World 模块

在你深刻理解所有框架 API 之前,先把一个最小的模块跑通比什么都重要。下面这个模块只做一件事:返回一段文本。

namespace MyModules import System import SilentTrinity.Core class HelloWorld(AbstractModule): Name as string: get: return "hello_world" Description as string: get: return "返回一句问候语" Author as string: get: return "author" [Params] _message as string = "Hello from Boo!" def Execute(self, context as AbstractContext) as string: return _message

把这段代码保存为hello_world.boo,放在 Modules 目录下。启动服务端后,在控制台执行use hello_world,然后运行,你会看到返回的问候语。如果这里失败了,排查方向就是:

  1. 文件是否放到了正确目录。
  2. 类名和文件名是否匹配。
  3. import SilentTrinity.Core是不是当前源码命名空间的准确名称。
  4. 基类名是否正确,比如有的版本叫AbstractModule,有的版本叫ModuleBase。

这个试错过程非常培养直觉,因为你会慢慢掌握“模块编译错误信息”的解读方式。

3. 实战开发:从零实现一个系统信息侦察模块

3.1 模块需求分析

Helloworld 太玩具了,我们要来一个真正能用的系统信息侦察模块。这个模块的作用是:执行之后,帮我们快速拿到目标机器的操作系统版本、当前用户名、计算机名、环境变量列表、运行进程数量、网络连接数量等基础信息。

我把模块设计成支持一个可选参数mode,默认是全量输出。如果你只想看进程列表,就可以在调用时传process;只想看网络连接,就传network。这样做的目的是让模块在常规信息收集时足够快,不需要每次把所有数据都拖回来,也能避免结果太长导致回传不稳定。

输出格式我会选择易读的纯文本,每行一个字段。因为后渗透场景里,结果通常会被人工审阅,纯文本比 JSON 更容易初筛。如果你自己有二次分析工具,也可以把代码里的字符串拼接改成 JSON 序列化。

3.2 核心代码实现

下面是核心模块的完整示例,请根据你当前源码实际接口微调:

namespace MyModules import System import System.Diagnostics import System.Net.NetworkInformation import SilentTrinity.Core class SysInfo(AbstractModule): Name as string: get: return "sysinfo" Description as string: get: return "获取系统基本信息、进程和网络连接概况" Author as string: get: return "author" [Params] _mode as string = "all" def Execute(self, context as AbstractContext) as string: output = "" try: if _mode == "all" or _mode == "os": output += self.GetOsInfo() if _mode == "all" or _mode == "network": output += self.GetNetworkInfo() if _mode == "all" or _mode == "process": output += self.GetProcessInfo() except ex as Exception: return "ERROR: ${ex.ToString()}" return output def GetOsInfo(self) as string: line = "OS: " + System.Environment.OSVersion.ToString() + "\n" line += "MachineName: " + System.Environment.MachineName + "\n" line += "UserName: " + System.Environment.UserName + "\n" line += "SystemDirectory: " + System.Environment.SystemDirectory + "\n" line += "Version: " + System.Environment.Version.ToString() + "\n" return line def GetProcessInfo(self) as string: output = "[Processes]\n" processes = Process.GetProcesses() output += "Total: ${processes.Length}\n" for p in processes: output += " ${p.Id}: ${p.ProcessName}\n" return output def GetNetworkInfo(self) as string: output = "[Network]\n" interfaces = NetworkInterface.GetAllNetworkInterfaces() output += "Interfaces: ${interfaces.Length}\n" for ni as NetworkInterface in interfaces: output += " ${ni.Name} (${ni.NetworkInterfaceType})\n" return output

这个模块有几点设计值得注意:

  • Params特性或者属性命名方式在不同版本里可能不一样,你要去源码里确认。我习惯在类里定义一个带默认值的字段,然后通过特性把它变成可传入参数。
  • Execute里面我用了大量字符串拼接。在 Boo 里字符串插值非常方便,但多层嵌套时要注意括号和引号。
  • GetProcessInfo里直接遍历全部进程,当目标机器进程数量非常多时输出会很长,所以在实际部署时,我会加一个数量上限,比如只要前 50 个进程,防止结果回传超时。
  • NetworkInterface.GetAllNetworkInterfaces()在权限不足时可能抛出异常,但因为我外面包了try...except,异常会转成字符串回传,不会导致客户端直接崩溃。

3.3 与上下文对象的交互

模块执行的时候,context对象承载了非常重要的运行时信息。你需要搞清楚它提供哪些属性和方法,比如获取当前会话标识、获取已传入的参数、引用当前目标机器的基本状态等。不同版本的 SILENTTRINITY 对上下文对象的名字和接口定义有差异,但思路是一致的:上下文是模块和框架之间的“会话管家”。

模块自己不应该直接发起网络连接、直接传递控制指令,这些都应该由框架完成。你只需要“本地执行、返回结果”。如果你在模块里想做一些更复杂的操作,比如上传文件内容,那也是把文件作为一个二进制数组返回,由框架负责传输。

回传结果有个小技巧:如果你希望结果在服务端能被漂亮地打印出来,记得在输出末尾保留一个换行符,或者干脆只用\n而不是\r\n,避免在某些终端环境里出现多余空行。这个问题我当时调试了很久才发现是换行符差异导致的显示错乱。

3.4 模块测试与验证

写完了代码,把它命名为sysinfo.boo放进模块目录。重新启动服务端,然后在控制台输入:

list modules

如果列表中出现了sysinfo,说明加载成功。接着选择一个处于活跃状态的会话或者监听器,运行:

use sysinfo set mode all execute

正常情况下你会看到返回的系统信息文本。如果出现编译错误,控制台或日志文件会有异常信息,最常见的错误包括命名空间找不到、方法签名不匹配、类型转换失败。

我之前在测试时遇到过一个很隐蔽的问题:Process.GetProcesses()返回的是进程对象数组,但我在 Boo 里对数组调用Length属性,某些版本会识别为.Count,结果编译报错。解决办法就是统一使用集合的Count属性,或者先复制到一个列表再统计。这个坑在文档里很难第一时间发现,所以建议大家多写几行很小的测试代码,逐步验证某个 API 是否可用。

4. 常见问题与排查技巧

4.1 模块加载失败的定位

模块加载失败是新手最容易遇到的问题。常见原因有以下几种:

现象可能原因排查方向
列表中看不到模块文件路径不对或扩展名错误确认文件是.boo且处于正确的 Modules 目录
出现编译错误基类名或命名空间不对对比当前源码中的模块接口定义
模块加载成功但执行报错方法签名冲突或参数特性错误检查Params特性、方法名、返回类型
执行时没有任何输出异常被吞掉或结果为空字符串在Execute中增加try...except并返回具体的异常信息

模块加载的日志通常在框架的日志模块里,你可以通过控制台日志或文件日志看到 Boo 编译错误的具体行号。Boole 错误提示一般比较明确,比如“unexpected token”说明有括号或缩进问题,“method not found”说明类的接口定义不对。

另外要注意的是,模块文件不会热加载。我见过很多人在服务端运行状态下复制模块进去,然后发现列表没更新,以为路径错了,其实只需要重启服务端或者让框架重新扫描模块目录。

4.2 执行时的运行时异常

运行时的异常五花八门,但归结起来主要就是权限问题、参数问题和 API 可用性问题。

权限问题最常见的是目标机器上当前进程权限不够。比如你想枚举某些高权限服务的可执行文件,可能会遇到拒绝访问。这种情况下,我通常会在代码里捕获异常,然后返回“Permission denied”而不是让整个模块崩溃。这类错误信息在模块开发阶段是宝贝,因为你能快速知道目标环境下什么能做什么不能做。

参数问题则是因为用户在使用模块时,传入了空值或类型不匹配的值。你可以在Execute开头就对参数做校验,比如:

if _mode is null or _mode == "": return "Usage: mode=all|os|process|network"

API 可用性问题主要集中在不同版本 .NET 里接口被移除或改名。这时最快的排查方法是在本地写一个小的 Boo 脚本,直接调用这个 API,看能不能正常运行。如果本地能运行,那问题多半出在模块上下文或权限环境里。

4.3 数据回传与传输稳定性

当模块返回的数据量比较大的时候,比如遍历了上千个进程,SILENTTRINITY 的回传链路可能会遇到截断或超时。这类问题的表面现象是:控制台只看到一部分结果,或者模块执行看起来卡了很久。

经验上你会从几个方向解决:

  1. 限制输出大小。模块内部做截断,只返回最关键的 N 条数据。
  2. 增加超时控制。在读取进程列表前设置一个合理的最大耗时,避免模块执行时间过长导致告警或者会话掉线。
  3. 结果分段返回。如果真的需要完整大数据,可以拆成多次小批量,比如每次返回 500 行,客户端约定好分批上传。

另外,编码问题也经常出现。默认情况下,目标机器的代码页和中国开发机的 UTF-8 可能不一致,导致中文乱码。我通常会在模块里统一使用 ASCII 可打印字符,或把输出转成 Base64 后再交给框架处理,这样能最大程度避免编码带来的脏数据。

4.4 安全使用与模块库维护

写后渗透模块,天然和攻击面相关,所以我必须很明确地提一句:所有操作只应该在你有权限授权的环境中进行。做红队演练、安全测试、培训验证,一切都以合同授权和合规要求为前提。不要尝试把这个框架和模块用于任何未经授权的场景,这不仅是对自己负责,也是保护整个安全研究环境。

在此基础上,我建议你对自己的模块库做版本管理和分类管理。可以按功能前缀命名,比如collect_、exec_、persist_,方便在大量模块中快速检索。每次修改模块都记录一下变更原因,尤其是 API 适配方面的调整。等模块数量多了,这套管理习惯能帮你省下大量时间。

还有一个小技巧:保留一个“最小模板模块”,每次写新模块从它拷贝,而不是从旧模块里改。这样可以避免把旧模块里的参数残留和依赖项带到新模块里,减少调试成本。

最后一点个人体会

如果你已经折腾完上面的流程,大概率能感受到 Boo 模块体系真正厉害的地方:它把开发重心从“理解编译链路”转移到了“表达功能意图”。你不需要知道 C# 工程是怎么把客户端喂给主机的,只需要清楚 .NET 平台上哪个 API 能帮你完成想要的动作。这就为那些熟悉操作逻辑但不熟悉底层 C2 实现的同学提供了一个非常顺滑的切入点。

我最初上手的时候,被模块基类名称和一些参数特性的细节卡了整整一个下午。那种看着源码但不确定该继承哪个类、该覆写哪个方法的状态确实很磨人。但等你摸索出第一个能跑的模块,后面就像打开了一个工具箱。我现在写一个简单的侦察模块,从设计到验证,十分钟左右完成,而且很多代码模式是复用的。希望这篇教程能让你少走我走过的弯路,顺利进入 SILENTTRINITY 模块开发的大门。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/18 6:52:22

MATLAB手写KNN:解构距离度量、自适应k与懒惰学习的本质

简介:本资源是一份面向模式识别与机器学习初学者的KNN算法Matlab实现教学包,聚焦监督学习中的经典分类方法,适用于课程实验、课程设计及算法原理验证场景。压缩包共3个文件,全部为Matlab源码(.m格式)&#…

作者头像 李华
网站建设 2026/10/18 6:49:11

赊销账期怎么管?一套“合约客户“结算系统的设计与实现

做批发、餐饮供货、生鲜配送这类 B2B 生意,"先拿货、后付款"是常态。口头约定一句"月底一起结",看似简单,落到系统里却涉及合约管理、账单生成、结算核销、逾期提醒一整套链路。最近在团队里做了一版"合约客户"…

作者头像 李华
网站建设 2026/10/18 6:46:27

从拆解到提交:开放式任务的高效完成路径

拿到“第五章作业”这个标题,我愣了几秒钟。没有正文、没有关键词、甚至没有摘要,就这五个字,反而让我想起很多相似的局面——期末周深夜的宿舍、临时通知的项目报告、还有那些“就剩最后一章没搞定”的焦虑时刻。这一章通常不是什么开篇序曲…

作者头像 李华
网站建设 2026/10/18 6:41:16

现代AI计算硬件与基础设施技术体系完整拆解

这些年做AI基础设施相关工作,我有一个很深的感触:大部分团队讨论AI项目时,优先聊的是模型结构、训练技巧和数据质量,但真正决定项目上限的,往往是那些不怎么上发布会PPT的东西——现代AI计算硬件与基础设施技术体系。同…

作者头像 李华
网站建设 2026/10/18 6:41:16

DVWA暴力破解实验:从认证漏洞到防御工程全解析

1. 这不是“暴力破解演示”,而是一次对认证机制脆弱性的深度解剖DVWA靶场里的Brute Force模块,常被新手当成“练手小玩具”——点几下按钮、跑个字典、看到“登录成功”就截图发朋友圈。但我在某高校网络安全实训课带过三届学生后发现:超过70…

作者头像 李华