Skip to content

怎么使用 datastore 参数

L edited this page May 6, 2022 · 1 revision

Datastore 参数概述

数据存储选项是一种可以由用户设置的变量, 允许 Metasploit 的各种组件在使用过程中更加可配置. 例如, 在 msfconsole 中, 你可以设置 ConsoleLogging 选项以记录所有控制台输入/输出 - 这对于在渗透测试期间的文档目的来说非常方便. 当你加载一个模块时, mixin(s) 或模块会注册更多的选项. 一些常见的包括用于服务器端漏洞利用或辅助模块的 RHOSTS 和 RPORT, 用于客户端模块的 SRVHOST 等. 找出可以设置的数据存储选项的最佳方法是使用以下命令:

  • show options - 向你展示所有基本选项.
  • show advanced - 向你显示所有高级选项.
  • show missing - 显示你尚未配置的所有必需选项.
  • set - 向你展示一切. 显然, 你还使用此命令设置选项.

选项来源: ModuleDataStore, active_module, session, and framework

普通用户怎么设置 datastore 选项

在用户方面, 数据存储选项被视为全局或模块级别: 全局意味着所有模块都可以使用该选项, 可以使用 setg 命令设置. 模块级意味着只有你正在使用的特定模块会记住该数据存储选项, 其他组件不会知道它. 如果你首先加载模块, 然后使用 set 命令, 则你正在设置模块级选项, 如下所示:

msf > use exploit/windows/smb/ms08_067_netapi
msf exploit(ms08_067_netapi) > set rhost 10.0.1.3
rhost => 10.0.1.3

Metasploit 框架开发中怎么找到 datastore 选项

在开发方面, 事情有点疯狂. 数据存储选项实际上可以在至少四个不同的来源中找到: ModuleDataStore 对象, active_module, session 对象 和 framework 对象.

如果你只是在进行模块开发, 那么你可以信任的最佳来源是 ModuleDataStore 对象. 在将所需选项交给你之前, 此对象具有特定的加载顺序: 如果可以在模块的数据存储中找到该选项, 它将为你提供. 如果没有找到, 它会给你一个来自框架的. 以下是如何读取模块中的数据存储选项的示例:

current_host = datastore['RHOST']

如果你的开发工作在模块领域之外, 则很有可能甚至不用 ModuleDataStore 对象. 但在某些情况下, 你仍然可以从驱动程序的 active_module 访问器中读取. 或者, 如果你可以访问 ModuleCommandDispatcher, 那么也有一个 mod 方法可以为你提供相同的功能, 有时 mixin 在调度模块时会在 run_simple 方法中传递它. 你可以查看的一个示例是 Msf::Ui::Console::CommandDispatcher::Auxiliary 类.

在某些情况下, 例如在后期利用中运行脚本, 你可能没有 ModuleDataStore 甚至 active_module, 但你仍然应该有一个会话对象. 应该有一个 exploit_datastore, 它为你提供所有数据存储选项:

session.exploit_datastore

如果你无权访问模块或会话对象, 那么最后一个源显然是框架对象, 并且始终存在框架对象. 但是, 就像我们之前所说的, 如果用户设置了模块级选项, 其他组件将不会看到它, 这包括框架对象:

framework.datastore

所以现在你知道有多种数据存储选项来源. 并且希望在这一点上你很清楚并非所有来源都必然共享相同的东西. 如果你必须尝试一切, 作为一般规则, 这应该是你的加载顺序:

  1. 尝试 ModuleDataStore
  2. 尝试 active_module
  3. 尝试 session
  4. 尝试 framework

核心选项类型

有核心数据存储选项类型都在 option_container.rb 文件中定义为类. 你应该始终选择最合适的一个, 因为每个都有自己的输入验证器.

在数据存储注册期间初始化选项时, 它应采用以下格式:

OptSomething.new(option_name, [boolean, description, value, *enums*], aliases: *aliases*, conditions: *conditions*)
  • option_name - 明确表示数据存储选项的名称.
  • boolean - 第一个属性, true 表示这是必需选项, false 表示可选.
  • description - 关于此选项的简短说明
  • value - 一个默认值. 请注意, 如果第一个属性为 false, 则无需提供值, 它会自动设置为 nil.
  • enums - 可选, 可接受值的数组, 例如 %w[ LEFT RIGHT ].
  • aliases - 可选, 仅关键字 引用此选项的附加名称数组. 这在 重命名 datastore 选项 以保持向后兼容性时很有用. 有关详细信息, 请参阅重命名数据存储选项部分
  • conditions - 可选, 关键字 应显示选项的条件数组. 这可以用来隐藏选项, 因为它们是根据其他配置无关的. 有关详细信息, 请参阅 过滤 datastore 选项 部分.

现在让我们看看可用的类有哪些:

OptAddress

IPv4 地址的输入. 代码示例:

OptAddress.new('IP', [ true, 'Set an IP', '10.0.1.3' ])

OptAddressRange

一个 IPv4 地址范围的输入, 例如: 10.0.1.1-10.0.1.20 或 10.0.1.1/24. 你还可以提供文件路径而不是范围, 它会自动将该文件视为 IP 列表. 或者, 如果你执行 rand:3 语法, 3 表示 3 次, 它将为你生成 3 个随机 IP. 基本代码示例:

OptAddressRange.new('Range', [ true, 'Set an IP range', '10.0.1.3-10.0.1.23' ])

OptBool

布尔选项. 它将验证输入是真还是假的变量. 例如: y、yes、n、no、0、1 等. 代码示例:

OptBool.new('BLAH', [ true, 'Set a BLAH option', false ])

OptEnum

基本上, 这会将输入限制为特定的选择. 例如, 如果你希望输入是"apple"或"orange", 而不是其他, 那么 OptEnum 就是你的最佳选择. 代码示例:

# 选择 apple 或 orange, 默认为苹果
OptEnum.new('FRUIT', [ true, 'Set a fruit', 'apple', ['apple', 'orange']])

OptInt

这可以是十六进制值, 也可以是十进制值.

OptInt.new('FILE', [ true, 'A hex or decimal', 1024 ])

OptPath

如果你的数据存储选项要求提供本地文件路径, 请使用此选项.

OptPath.new('FILE', [ true, 'Load a local file' ])

OptPort

对于打算用作端口号的输入. 此数字应介于 0 - 65535 之间. 代码示例:

OptPort.new('RPORT', [ true, 'Set a port', 21 ])

OptRaw

它实际上与 OptString 的功能完全相同.

OptRegexp

选项是一个正则表达式.

OptRegexp.new('PATTERN', [true, 'Match a name', '^alien']),

其它类型:

在某些情况下, 可能没有适合你的 datastore 选项类型. 最好的例子是一个 URL: 即使没有 OptUrl 这样的东西, 你可以做的是使用 OptString 类型, 然后在你的模块中, 对其进行一些验证, 如下所示:

def valid?(input)
  if input =~ /^http:\/\/.+/i
    return true
  else
    # 这里可以考虑抛出 OptionValidateError
    return false
  end
end

if valid?(datastore['URL'])
  # 我们可以用 URL 做一些事情
else
  # 不是我们正在寻找的格式. 拒绝做任何事情. 
end

OptString

通常用于字符串选项. 如果输入以"file://"开头, OptString 也会自动假定这是一个文件, 并从中读取. 但是, 发生这种情况时没有文件路径验证, 所以如果你想加载一个文件, 你应该使用 OptPath 代替, 然后自己读取文件. 代码示例:

OptString.new('MYTEST', [ true, 'Set a MYTEST option', 'This is a default value' ])

注册和注销模块选项

register_options 方法

register_options 方法可以注册多个基本数据存储选项. 基本数据存储选项是必须配置的选项, 例如服务器端漏洞利用中的 RHOST 选项. 或者它非常常用, 例如登录模块中的各种用户名/密码选项.

以下是在一个模块中注册多个数据存储选项的示例:

register_options(
  [
    OptString.new('SUBJECT', [ true, 'Set a subject' ]),
    OptString.new('MESSAGE', [ true, 'Set a message' ])
  ])

register_advanced_options 方法

register_advanced_options 方法可以注册多个高级 datastore 选项. 高级 datastore 选项是不需要用户在使用模块之前进行配置的选项. 例如, 代理选项几乎总是被认为是"advanced". 但当然, 这也可能意味着大多数用户会觉得难以配置.

注册高级选项的示例:

register_advanced_options(
  [
    OptInt.new('Timeout', [ true, 'Set a timeout, in seconds', 60 ])
  ])

deregister_options 方法

方法可以取消注册基本或高级选项. 用法非常简单:

deregister_options('OPTION1', 'OPTION2', 'OPTION3')

更改 datastore 选项的默认值

当 mixin 已经注册了一个数据存储选项时, 仍然有办法从模块中更改默认值. 你可以使用 register_options 方法, 也可以在模块的元数据中添加 DefaultOptions 键. 首选使用 DefaultOptions 键, 因为选项的描述和其他属性将保持不变.

使用 register_options 修改默认值

使用 register_options 的优点之一是, 如选项是高级 datastore 的, 则允许它位于基本选项菜单上, 这意味着当人们在 msfconsole 上执行 show options 时, 该选项将出现. 你还可以更改选项描述, 以及是否需要使用此方法.

使用 DefaultOptions 修改默认值

当 Metasploit 初始化一个模块时, 一个 import_defaults 方法被调用. 此方法将更新所有现有的数据存储选项 (这就是为什么 register_options 可用于更新默认值的原因) , 然后它会专门从模块的元数据中检查 DefaultOptions 键, 并再次更新.

下面是一个利用 DefaultOptions 键的漏洞利用模块初始化部分的示例:

def initialize(info={})
  super(update_info(info,
    'Name'           => "Module name",
    'Description'    => %q{
      This is an example of setting the default value of RPORT using the DefaultOptions key
    },
    'License'        => MSF_LICENSE,
    'Author'         => [ 'Name' ],
    'References'     =>
      [
        [ 'URL', '' ]
      ],
    'Platform'       => 'win',
    'Targets'        =>
      [
        [ 'Windows', { 'Ret' => 0x41414141 } ]
      ],
    'Payload'        =>
      {
        'BadChars' => "\x00"
      },
    'DefaultOptions' =>
      {
        'RPORT' => 8080
      },
    'Privileged'     => false,
    'DisclosureDate' => "",
    'DefaultTarget'  => 0))
end

在运行时修改 datastore 选项

目前, 在运行时修改数据存储选项的最安全方法是覆盖方法. 例如, 一些 mixin 像这样检索 RPORT 选项:

def rport
  datastore['RPORT']
end

在这种情况下, 你可以从模块中覆盖此 rport 方法, 并返回不同的值:

def rport
  80
end

这样, 当一个 mixin 需要该信息时, 它将以 80 的值结束, 而不是 datastore['RPORT'] 中实际存在的任何值.

理想的 datastore 命名

普通选项总是大写, 高级选项是 CamelCase, 具有类似目的的高级选项是 Prefixed::CamelCase.

重命名 datastore 参数名

选项可以重命名并保持向后兼容性, 方法是使用 alias: 选项中的关键字参数. 例如, 要重命名 OldOptionNewOption, 需要定义如下

OptString.new('NewOption', [true, 'A (sort of) new option', 'hello'], aliases: %w[ OldOption ])

过滤 datastore 选项

选项可以在某些条件下根据 conditions 关键字定义的条件进行隐藏. 这允许在基于另一个选项、选定目标或选定操作的值不相关时隐藏选项.

条件的语法是 *thing* *operator* *value*.

  • thing - ACTION、TARGET 或 datastore 选项的名称之一.
  • operator - ==, !=, in, nin 之一. 在 innin (not-in) 的情况下, 该值是一个数组.
  • value - 在条件中检查的值.

当条件评估为真时, 该选项被视为活动并显示给用户. 默认情况下, 未定义条件的 datastore 选项处于活动状态.

过滤选项示例

  1. conditions: %w[VERSION == 5] - 当 VERSION 数据存储选项为 5 时处于活动状态.
  2. conditions: ['ACTION', 'in', %w[SSRF EXEC SECSTORE]] - 当 ACTIONSSRFEXECSECSTORE 之一时激活选项.
Clone this wiki locally