Metasploit开发笔记之编写 Python 模块

一、为 Metasploit 编写 Python 模块

这是一个如何为 Metasploit 框架编写 Python 模块的示例,该模块通过 JSON-RPC 使用 Python 的 metasploit 库与框架进行通信,采用 stdin/stdout。外部 Python 模块应支持 Python 3.5 及更高版本,不再支持 Python 2.7。

1、执行

在模块的顶部包含以下行:
#!/usr/bin/env python3
确保文件被标记为可执行文件。

2、Python 库

该库目前支持几个函数调用,可以用来向 Metasploit 框架报告信息。可以通过以下代码将 metasploit 库加载到你的 Python 模块中:

from metasploit import module

Metasploit 库的位置会在执行 Python 模块之前自动添加到 PYTHONPATH 环境变量中。

3、描述模块

Metasploit 模块包含有关模块作者、与漏洞相关的其他信息来源的引用、模块描述、选项等内容。

Python 模块也需要包含这些元数据。数据的结构与 Ruby 编写的模块类似。以下是一个元数据的示例模板:

metadata = {
    'name': '<name>',
    'description': '''
        <description>
    ''',
    'authors': [
        '<author>',
        '<author>'
    ],
    'date': 'YYYY-MM-DD',
    'license': '<license>',
    'references': [
        {'type': 'url', 'ref': '<url>'},
        {'type': 'cve', 'ref': 'YYYY-#'},
        {'type': 'edb', 'ref': '#'},
        {'type': 'aka', 'ref': '<name>'}
    ],
    'type': '<module type>',
    'options': {
        '<name>': {'type': 'address', 'description': '<description>', 'required': <True/False>, 'default': None},
        '<name>': {'type': 'string', 'description': '<description>', 'required': <True/False>, 'default': None},
        '<name>': {'type': 'string', 'description': '<description>', 'required': <True/False>, 'default': None}
    }
}

4、模块类型

如元数据模板信息所示,模块还包括一个类型。模块类型用于选择一个 ERB 模板,该模板生成该模块的 Ruby 文档。可以在这里找到 ERB 模板。目前可用的模板如下:

  • remote_exploit_cmd_stager

  • capture_server

  • dos

  • single_scanner

  • multi_scanner

  • remote_exploit_cmd_stager 模块类型用于编写命令执行或代码注入漏洞的利用,并根据指定的命令启动器(command stager)提供要注入到易受攻击代码中的命令。

  • capture_server 模块类型用于设计一个模拟服务的模块,用于捕获连接客户端的凭据。

  • dos 模块类型用于发送数据包到远程服务,导致该服务崩溃或使其无法使用。

  • single_scanner 模块类型用于创建扫描主机的模块,不进行批处理。

  • multi_scanner 模块类型用于批量扫描主机的模块。batch_size 选项在 multi_scanner ERB 模板中注册,默认为 200。

5、选项

元数据中的选项字典是模块在加载到 msfconsole 时可用的选项。选项可以是必需的(对于模块运行是必要的)或非必需的(提供附加功能)。

6、通信

为了将元数据以及 Python 模块的启动函数传递给 msfconsole,可以使用 module.run() 函数。module.run() 函数接受两个参数,第一个是元数据,第二个是执行模块时 msfconsole 调用的回调函数。代码示例如下:

def run(args):
    # 你的代码在这里
    pass

if __name__ == '__main__':
    module.run(metadata, run)

当 msfconsole 向 Python 模块发送 describe 请求时,模块会返回元数据。当 msfconsole 向模块发送 run 请求时,回调函数(在本例中为 run)将会被调用,并传入 msfconsole 提供的参数。

7、日志处理

可以设置并使用 LogHandler 来在 Python 模块执行过程中向框架传递状态信息。以下是使用 LogHandler 的代码示例:

import logging
from metasploit import module

module.LogHandler.setup(msg_prefix='logging test: ')
logging.info('info')
logging.error('error')
logging.warning('warning')
logging.debug('debug')

module.LogHandler.setup() 函数用于创建一个 Handler 和 Formatter,这将调用 module.log() 并传递适当的日志级别。

二、完整示例

1、示例代码

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 标准模块
import logging

# 附加模块
dependencies_missing = False
try:
    import requests
except ImportError:
    dependencies_missing = True

from metasploit import module


metadata = {
    'name': 'Python Module Example',
    'description': '''
        Python 与 msfconsole 的通信。
    ''',
    'authors': [
        'Jacob Robles'
    ],
    'date': '2018-03-22',
    'license': 'MSF_LICENSE',
    'references': [
        {'type': 'url', 'ref': 'https://blog.rapid7.com/2017/12/28/regifting-python-in-metasploit/'},
        {'type': 'aka', 'ref': 'Coldstone'}
    ],
    'type': 'single_scanner',
    'options': {
        'targeturi': {'type': 'string', 'description': '基础路径', 'required': True, 'default': '/'},
        'rhost': {'type': 'address', 'description': '目标地址', 'required': True, 'default': None}
    }
}


def run(args):
    module.LogHandler.setup(msg_prefix='{} - '.format(args['rhost']))
    if dependencies_missing:
        logging.error('模块依赖 (requests) 丢失,无法继续')
        return

    # 你的代码在这里
    try:
        r = requests.get('https://{}/{}'.format(args['rhost'], args['targeturi']), verify=False)
    except requests.exceptions.RequestException as e:
        logging.error('{}'.format(e))
        return

    logging.info('{}...'.format(r.text[0:50]))


if __name__ == '__main__':
    module.run(metadata, run)

2、说明

该示例向指定的 rhosttargeturi 发送一个 GET 请求,并调用 logging.info() 显示返回结果的前 50 个字符,输出将在 msfconsole 中显示。

3、调试 Python 模块

如果你想直接在 Metasploit 框架文件夹中作为独立程序运行外部模块,可以指定 Python 路径来包含 Metasploit 库支持,并直接运行模块:

$ PYTHONPATH=./lib/msf/core/modules/external/python:$PYTHONPATH python3 ./modules/auxiliary/scanner/wproxy/att_open_proxy.py

Python 模块将等待从 stdin 接收 JSON-RPC 输入。输入请求以运行模块:

{ "jsonrpc": "2.0", "id": "1337", "method": "run", "params": { "rhosts": ["127.0.0.1"], "rport": "49152" } }

你会看到 JSON-RPC 响应打印到 stdout:

{"jsonrpc": "2.0", "method": "message", "params": {"level": "debug", "message": "127.0.0.1:49152 - Connected"}}
{"jsonrpc": "2.0", "method": "message", "params": {"level": "debug", "message": "127.0.0.1:49152 - Received 5 bytes"}}
{"jsonrpc": "2.0", "method": "message", "params": {"level": "info", "message": "127.0.0.1:49152 - Does not match"}}
{"jsonrpc": "2.0", "method": "message", "params": {"level": "debug", "message": "127.0.0.1:49152 - Does not match with: bytearray(b'xxxxx')"}}

你也可以通过管道传输 JSON-RPC 请求进行自动化:

echo '{ "jsonrpc": "2.0", "id": "1337", "method": "run", "params": { "rhosts": ["127.0.0.1"], "rport": "49152" } }' | PYTHONPATH=./lib/msf/core/modules/external/python:$PYTHONPATH python3 ./modules/auxiliary/scanner/wproxy/att_open_proxy.py

Python 外部模块也可以通过命令行选项直接运行:

$ PYTHONPATH=./lib/msf/core/modules/external/python:$PYTHONPATH python3.9 ./modules/auxiliary/scanner/wproxy/att_open_proxy.py --help

输出:

usage: att_open_proxy.py [-h] --rhosts RHOSTS [--rport RPORT] [ACTION]

The Arris NVG589 and NVG599 routers configured with AT&T U-verse firmware 9.2.2h0d83 expose an un-authenticated proxy that allows connecting from WAN to LAN by MAC address.

positional arguments:
  ACTION           The action to take (['run'])

optional arguments:
  -h, --help       show this help message and exit
  --rport RPORT    The target port, (default: 49152)

required arguments:
  --rhosts RHOSTS  The target address

例如,运行:

PYTHONPATH=./lib/msf/core/modules/external/python:$PYTHONPATH python3 ./modules/auxiliary/scanner/wproxy/att_open_proxy.py --rhosts 127.0.0.1 --rport 49152

对于漏洞利用模块,负载使用 Base64 编码并通过顶层 payload_encoded 键进行指定,这里实现了该功能。以下是(现在已删除的)ms17_010_eternalblue_win8.py 模块运行的示例:

$ cat options.json
{
    "jsonrpc": "2.0",
    "id": "1337",
    "method": "run",
    "params": {
        "VERBOSE": true,
        "RHOST": "192.168.144.131",
        "RPORT": "445",
        "GroomAllocations": 13,
        "ProcessName": "spoolsv.exe",
        "SMBUser": "test",
        "SMBPass": "123456",
        "payload_encoded": "/EiD5PDozAAA...etc...==="
    }
}

$ cat options.json | PYTHONPATH=./lib/msf/core/modules/external/python:$PYTHONPATH python3 modules/exploits/windows/smb/ms17_010_eternalblue_win8.py
{"jsonrpc": "2.0", "method": "message", "params": {"level": "info", "message": "shellcode size: 1221"}}
{"jsonrpc": "2.0", "method": "message", "params": {"level": "info", "message": "numGroomConn: 13"}}
{"jsonrpc": "2.0", "method": "message", "params": {"level": "info", "message": "Target OS: Windows 10 Pro 10240"}}
{"jsonrpc": "2.0", "method": "message", "params": {"level": "info", "message": "got good NT Trans response"}}
{"jsonrpc": "2.0", "method": "message", "params": {"level": "info", "message": "got good NT Trans response"}}
{"jsonrpc": "2.0", "method": "message", "params": {"level": "info", "message": "SMB1 session setup allocate nonpaged pool success"}}
{"jsonrpc": "2.0", "method": "message", "params": {"level": "info", "message": "SMB1 session setup allocate nonpaged pool success"}}

3、添加断点到 Python 代码

要在 Python 代码中添加断点,可以使用以下代码片段。请注意,交互式断点只会在作为独立 Python 脚本运行外部模块时有效,而在 msfconsole 中运行时不会生效:

import pdb; pdb.pry

4、编码风格

Metasploit 中的所有 Python 代码都应遵循 PEP 8 标准。与 Metasploit 的 Ruby 风格相比,最大的差异在于:

  • 函数之间有两个空行(但类方法之间不需要)
  • 不同类型的代码(如导入和元数据)之间需要两个空行(见上文)
  • 使用四个空格进行缩进

编写模块时的一些编码注意事项:

  • 使用 "foo {}".format('bar') 替代 % 插值
  • 保持回调方法简短且易读。如果方法变得复杂,可以将子任务拆分为命名清晰的函数
  • 变量名应具有描述性、可读且简短(参考命名指南)
  • 如果需要使用 Python 3 特性,在模块中使用 #!/usr/bin/env python3 作为 shebang
  • 如果你有很多 Python 2.7 的遗留代码或需要一个 2.7 库,可以使用 #!/usr/bin/env python2.7(特别是 macOS 默认不提供 python2 执行文件)
  • 如果可能,保持模块兼容 Python 2 和 3,并使用 #!/usr/bin/env python 作为 shebang

5、常见问题解答

为什么在 msfconsole 中搜索不到该模块?
模块可能存在错误并且未能在 msfconsole 中加载。检查框架日志文件 ~/.msf4/logs/framework.log 查看错误信息。此外,如果模块没有标记为可执行文件,它在 msfconsole 中也不会显示。

为什么 Python 模块的输出没有显示在 msfconsole 中?
外部模块通过 JSON-RPC 与框架进行通信。如果你的 Python 模块包含 print 语句,框架可能不会识别这些作为 JSON-RPC 请求。使用 LogHandlermodule.log() 来发送状态信息,这些信息将显示在 msfconsole 中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

人间酒中仙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值