Skip to content

怎么编写 check() 方法

L edited this page May 18, 2022 · 1 revision

在 Metasploit 中, 漏洞利用和辅助模块支持检查命令, 使用户能够在使用模块之前确定易受攻击的状态. 对于那些需要在不实际弹出 shell 的情况下验证漏洞的人来说, 此功能非常方便, 并用于快速识别网络上所有易受攻击或可能被利用的机器.

尽管漏洞检查不是 Metasploit 的重点, 因为它不是像 Nexpose 这样的漏洞扫描器, 我们实际上鼓励人们实现 check() 方法以增加模块的价值. 如果你确实写了一篇, 请务必牢记以下准则:

check 方法输出

模块消息对用户很重要, 因为它们让用户了解模块正在做什么, 并且通常使模块更易于调试. 但是, 你还希望将消息保持在详细模式, 因为如果对多个目标使用检查, 它会变得非常嘈杂. 理想情况下, 你应该只使用以下打印方法:

方法 描述
vprint_line() verbose 模式的 print_line
vprint_status() verbose 模式的 print_status 开头会有 "[*]"
vprint_error() verbose 模式的 print_error 开头会有 "[x]"
vprint_warning() verbose 模式的 print_warning 开头会有黄色的 "[!]"
vprint_debug() verbose 模式的 print_debug 开头会有蓝色的 "[!]"

更好的是, 使用 CheckCode 描述来提供附加信息 (见下文) .

注意: 如果目标易受攻击, 则不应打印, 因为当你的方法返回检查代码时, 框架会自动处理.

CheckCode

一旦你确定了易受攻击的状态, 你应该返回一个 CheckCode. 检查代码是在 Msf::Exploit::CheckCode 中定义的常量, 你可以使用以下代码:

CheckCode 描述
Exploit::CheckCode::Unknown 如果模块未能从目标机器检索到足够的信息 (例如由于超时) , 则使用该模块.
Exploit::CheckCode::Safe 如果检查未能触发漏洞, 甚至无法检测到服务, 则使用此选项.
Exploit::CheckCode::Detected 目标正在运行有问题的服务, 但检查无法确定目标是否易受攻击.
Exploit::CheckCode::Appears 如果漏洞是基于被动侦察确定的, 则使用此选项. 例如: 版本、旗帜抓取或只是拥有已知易受攻击的资源.
Exploit::CheckCode::Vulnerable 仅在检查能够实际利用错误并获得某种确凿证据时使用. 例如: 对于命令执行类型的 bug, 从目标系统获取命令输出. 对于目录遍历, 从目标读取文件等. 由于这种级别的检查本质上是非常激进的, 因此你不应该尝试通过 DoS 主机来证明漏洞.
Exploit::CheckCode::Unsupported 该漏洞利用不支持检查方法. 如果是这种情况, 那么你实际上不必添加检查方法.

CheckCode 还支持在检查方法完成时由框架打印的可选描述. 例如:

return CheckCode::Appears('Vulnerable component XYZ is installed')

远程检查示例

这是一个如何编写 Metasploit check() 的示例:

#
# 返回一个 CheckCode, 指示在 OS X 上运行的应用程序的易受攻击状态
#
def check
  if exec_cmd_via_http("id") =~ /uid=\d+\(.+\)/
    # 找到正确的 ID 输出, 很好的说明我们的命令执行了
    return Exploit::CheckCode::Vulnerable
  end

  http_body = get_http_body
  if http_body
    if http_body =~ /Something CMS v1\.0/
      # 我们能够找到更精确的关于 vuln 状态的版本
      return Exploit::CheckCode::Appears
    elsif http_body =~ /Something CMS/
      # 我们只能告诉易受攻击的应用程序正在运行, 但没有更多信息判断漏洞
      return Exploit::CheckCode::Detected
    end
  else
    vprint_error("Unable to determine due to a HTTP connection timeout")
    return Exploit::CheckCode::Unknown
  end

  Exploit::CheckCode::Safe
end

注意: 如果你正在使用 Msf::Auxiliary::Scanner mixin 编写辅助模块, 你应该像这样声明你的检查方法:

def check_host(ip)
  # Do your thing
end

本地漏洞检查示例

大多数本地漏洞利用检查都是通过检查易受攻击文件的版本来完成的, 这被认为是被动的, 因此它们应该标记 Exploit::CheckCode::Appears. 被动本地漏洞检查并不一定意味着它们不太可靠, 事实上, 它们还不错. 但是要获得 Exploit::CheckCode::Vulnerable 的资格, 你的检查应该加倍努力, 这意味着你要么以某种方式使程序返回易受攻击的响应, 要么检查易受攻击的代码.

使程序返回易受攻击的响应的一个示例是 ShellShock (以下是特定于 VMWare 的) :

def check
  check_str = Rex::Text.rand_text_alphanumeric(5)
  # 确保它们容易受到 bash 环境变量错误的影响
  if cmd_exec("env x='() { :;}; echo #{check_str}' bash -c echo").include?(check_str) &&
     cmd_exec("file '#{datastore['VMWARE_PATH']}'") !~ /cannot open/

     Exploit::CheckCode::Vulnerable
  else
    Exploit::CheckCode::Safe
  end
end

检查易受攻击代码的一种方法是提出一个签名, 并查看它是否存在于易受攻击的进程中. 以下是 adobe_sandbox_adobecollabsync.rb 的示例:

# 'AdobeCollabSyncTriggerSignature' => "\x56\x68\xBC\x00\x00\x00\xE8\xF5\xFD\xFF\xFF"
# 'AdobeCollabSyncTrigger' => 0x18fa0

def check_trigger
  signature = session.railgun.memread(@addresses['AcroRd32.exe'] + target['AdobeCollabSyncTrigger'], target['AdobeCollabSyncTriggerSignature'].length)
  if signature == target['AdobeCollabSyncTriggerSignature']
    return true
  end

  return false
end

def check
  @addresses = {}
  acrord32 = session.railgun.kernel32.GetModuleHandleA("AcroRd32.exe")
  @addresses['AcroRd32.exe'] = acrord32["return"]
  if @addresses['AcroRd32.exe'] == 0
    return Msf::Exploit::CheckCode::Unknown
  elsif check_trigger
    return Msf::Exploit::CheckCode::Vulnerable
  else
    return Msf::Exploit::CheckCode::Detected
  end
end

一种可能的检查方法是获取易受攻击的文件, 并使用 Metasm. 但当然, 这要慢得多, 并且会产生更多的网络流量.

Clone this wiki locally