在本系列文章的第一部分中我向大家介绍了 Ghostwriter。并且我详细的介绍了 Ghostwriter 的制作过程、技术栈以及开发过程中的思维过程。 如果你还没有读过第一部分的文章,请点击这里查看。
技术栈概述
Ghostwriter 是一个使用 Python 编写的 web 应用程序,使用了 Django web 框架。 它是一个 Python 3.7、 HTML、 JavaScript、 CSS、Jinja和 Django 代码的集合,被划分为多个 Django 应用程序。 这个区分有助于保持代码的组织性,并且在定制或开发过程中易于阅读。
这个应用程序使用了一个 PostgreSQL 后端,Django 原生就支持这个后端。 然而,如果用户希望切换到不同类型的后端,可以在 Django 的 settings.py 里更新为使用 SQLite、 Oracle 或 MySQL,而不需要任何额外的库。 Django 也使得修改 Ghostwriter 数据库模型变得很容易。 迁移操作通常很顺利,也不会出现任何故障,特别是如果你在生产环境中使用 Ghostwriter 前定制了模型。
最后,Ghostwriter 使用 Django Q 和 Redis 进行自动队列管理处理(AQMP)。 Ghostwriter 自动化了许多事情,比如更新域分类数据和 DNS 记录。 这些任务交给 Redis 进行后台处理。
安装相对简单一些。 Ghostwriter 可以在本地运行,也可以在低功耗服务器上运行。运行的主机只需要 Redis 和 Python 3.7。 Ghostwriter 使用的非标准 Python 库和 Django 库相对较少。 Ghostwriter 与 Docker 一起打包,因此所有的东西都可以使用 Docker Compose 和一个命令进行部署。 详细信息可以在 GitHub wiki 上找到。
关于为什么选择这些特定技术的一些细节将在这篇文章中讨论:
数据库模型
尽管 Ghostwriter 由多个应用程序组成,但它们都相互通信并共享一个数据库。
如下图所示,数据库模型都彼此链接以便将所有内容联系在一起。 Wiki 中的文档为每个应用程序提供了更多的细节和单独的 UML 图。
每种类型的对象都有一个表,我们已经为这些模型中的许多模型包含了 Django “fixture”(预定义的数据集)。 这些装置被加载到 Ghostwriter 数据库中,用于预填充必要的模型,以便在几分钟内启动并运行新的部署。 Ghostwriter 支持其他模型的 CSV 文件导入,比如域名和服务器。
Ghostwriter的制作过程
在评估过去的经验、当前的工作流程和当前可用的解决方案时,我们很快发现了导致我们愤怒或对效率和生产力产生负面影响的因素。 这里的关键是在这个评估上投入时间。 我们在 SpecterOps 的办公室里呆了一个星期,向内心发问,讨论我们喜欢什么,不喜欢什么,想要什么新工具。
当一个团队实现一个新的过程时,(几乎)总是会有一些次优的变通方法、技巧或者特殊的决策,并伴随着以后修复它们的良好意图。 这些良好的意图很少转化为纠正行动。 如果这些问题得不到解决,它们就有可能成为公认的标准,并恶化。
你可以把这看作是“最小阻力原则”的效果 卡尔 · 纽波特在他的书《深度工作》中描述了这一原则:
在商业环境中,如果没有关于各种行为对底线的影响的明确反馈,我们会倾向于当下最容易的行为。
如前所述,项目管理和流程工作流程并不吸引人,所以当一个团队有时间优化某些东西时,他们不会倾向于报告是可以理解的。 这件事的阴暗面是整个团队继续被十几件小事激怒,都是自己造成的。 最终,这些不满被认为是必要的减速带,使每个人陷入困境,直到有人采取纠正行动或最终导致宇宙的爆炸:无论哪一个先到来。
因此,SpecterOps 团队制定了一个雄心勃勃的计划: 构建我们的梦想工具。 这是一个崇高的目标,但也是必要的目标。 通过射击那颗遥远的恒星,我们希望至少能够击中月球。 我们称这个项目为 SpecterOps 自动报告平台,简称 SOAR,并致力于完成这个项目。
随着“安全编排和响应”作为一个术语越来越流行,幸好我们不太喜欢这个名字; 然而,SOAR 本来是这个平台的一个很好的名字。 这就是生活。
我们改名为 Ghostwriter。
我们为这个项目制定了几个重要的原则:
灵活性
自定义管理工具的首要失败之一就是缺乏灵活性。 创建该工具是为了解决我们关切的最直接的问题,很少考虑如果该进程在未来发生变化或需要加强将会发生什么。 我们知道 Ghostwriter 必须能够很容易地改变以适应报告设计和要求的改变。
这对于将 Ghostwriter 作为开源工具发布也很重要。 对于其他人来说,当他们不需要花费数小时重写代码来改变一个简单的报表设计时,他们更容易接受 Ghostwriter 作为他们团队的一员。
为了支持这个原则,我们很早就包含了 JSON 报告,以使报告的修改变得简单,允许将 Ghostwriter 项目引入到其他报告引擎中(如果需要的话) ,并规范所有不同类型报告(如 docx、 xlsx、 pptx)的报告生成。 我们使用 Office 文档作为报表样式的模板。 这样就不需要编辑代码来调整大部分的字体、颜色或者标题样式。 所有这一切的大部分都是通过一个熟悉的、无处不在的工具来管理的,那就是微软 Office。
可扩展性
可扩展性与灵活性同样重要。 我们知道我们需要一个可以延伸到未来的解决方案。 Ghostwriter 的主要目标之一就是把所有的东西都放在一个地方。 如果 Ghostwriter 不能很容易地扩展,那么这可能意味着第二个应用程序或平台可以用来跟踪未来的新需求。 这听起来似乎是一件小事,然而,随着时间的推移,它可能会导致更多的不快乐。
我们不希望 Ghostwriter 的结构如此死板,以至于它只能提供有限的功能。 根据我们的经验,即使是伟大的定制应用程序也会过时,有时会成为使用的负担。 节省时间的负担仍然是一件不快乐的事情。
能够添加新的应用程序,可以集成到现有的 Ghostwriter 应用程序是一个福音。 我们已经在致力于向 Ghostwriter 添加新的应用程序,例如为蓝队提供一个应用程序,该应用程序利用报告引擎生成警报和检测策略(ADS)。
生成 ADS 报告的应用程序不仅对我们的团队有用,与现有应用程序的集成意味着“蓝队应用程序”也知道所有的“红队应用程序”以及所附带的客户信息、项目、报告和其他团队成员记录的活动,反之亦然。 在一个方向上扩展 Ghostwriter 不仅增加了新的功能,而且丰富了整个平台。
毕竟,Ghostwriter 是一个友好的紫色幽灵,只是想帮助大家。
弹性
我们早期的担心之一是用 $Some_Library 建立 Ghostwriter,然后 $Some_Library在某种程度上有一些改变,这对 Ghostwriter 来说是一个负面影响。 因此,我们致力于“弹性”的概念,用于所有事物的第一个版本。 当前版本的 Ghostwriter 中的所有内容都是使用核心 Python 和 Django 库构建的。 也有一些例外,但除了 Django Q (支持良好)之外,大多数第三方库都支持可以在不破坏 Ghostwriter 的情况下进行更改的特性。 即使是那些使用良好且受支持的库,比如 request。 除此之外,唯一的外部依赖是 web 框架,jQuery 和 Bootstrap,它们都很流行并且得到了很好的支持。
这一切都意味着 Ghostwriter 更容易安装和使用,而且不会因为外部库更改或安装了错误的版本而出现故障。 在某些情况下,这使得开发工作稍微困难一些。 例如,我们选择使用 jQuery 而不是第三方 Django 库。 这增加了一个学习曲线和一些最初的困难,但最终的产品会有更好的结果。
也许最值得注意的权衡是缺乏某些附加功能,比如所见即所得文本编辑器。 所见即所得编辑器当然不错,但我们故意选择避免它们,以确保有一个强大的基础,以防我们选择的任何一个编辑器插件有一天消失。 至少我们可以切除非功能的所见即所得插件,并且清楚基本的文本框也可以很好的工作。 (与此同时,所见即所得的编辑器也有了。)
自动化
我们希望 Ghostwriter 能够自动化某些单调乏味的过程,或者那些我们知道人们会忘记或忽略的过程。 这一原则不言自明,但我们必须在发展进程的早期就把它作为优先事项。 每当我们实现一个用户可以执行的新操作时,我们就不得不问,“这个过程的任何部分是否应该根据用户的输入自动化? ”
一旦我们使用触发器和计划任务实现了功能自动化(这要感谢 Django Q 和 Redis) ,我们也可以为自动化提出一些有趣的新想法,比如 Slack 通知和域名的 DNS 检查。
吃狗粮
最后,我们知道最好也是唯一能确保我们走上正确道路的方法就是尽早使用 Ghostwriter。 我们的目标一直是使用 Ghostwriter,但我们在两个月内就开始使用它,而不是等待“ beta”版本或某个“ v1.0”版本的发布。 当时,它只是一个 Python 库和一个从命令行运行的脚本,用于生成报告。 这是一些早期思想的概念验证。 后来发展成为一个基本的 web 前端,使用 Python 的 Flask web 框架创建。 研究和测试最终导致了我们所选择的框架向 Django 转变。
在每个阶段,我们尝试不同的界面设计,测试新的想法和概念,只是一般的实验。 有相当多的哑弹,但这个过程却是如此重要。 引用《 Make 》杂志创始主编马克•弗劳恩费尔德(Mark Frauenfelder)在亚当•萨维奇(Adam Savage)的著作《每种工具都是一把锤子》(Every Tool is a Hammer)中的话:
You’ve got to do at least six iterations, minimum, of any project before it starts getting good enough to share it with other people.
在任何项目开始变得足够好以便与其他人分享之前,你必须至少进行六次迭代。
不久前我们经过了 Ghostwriter 的第六次迭代。 这张动图显示了2018年9月19日 Ghostwriter 或者 SOAR 的样子。我们希望你会同意我们,等待和无数次的迭代是值得。