Skip to content

使用 HTTPClient 发送 HTTP 请求

L edited this page May 12, 2020 · 2 revisions

这是一个如何编写使用 HttpClient mixin 发送基本 HTTP 请求的模块的示例.

你将主要看到两种常见方法:

  • send_request_raw - 你可以使用它发送原始的 HTTP 请求. 通常, 如果你需要非常规协议的内容, 则将需要此方法. 在大多数其他情况下, 你应该使用 send_request_cgi. 如果你想了解此方法的工作原理, 请查看 Rex::Proto::Http::Client#request_raw.

send_request_raw 基本使用示例:

  send_request_raw({'uri'=>'/index.php'})

send_request_cgi 基本使用示例:

  send_request_cgi({
    'method'   => 'GET',
    'uri'      => '/hello_world.php',
    'vars_get' => {
      'param_1' => 'abc',
      'param_2' => '123'
    }
  })

请注意: 如果存在超时, send_request_rawsend_request_cgi 将返回 nil, 因此请确保在处理返回值时考虑该情况.

URI 解析

在发送 HTTP 请求之前, 你很可能必须进行一些 URI 解析. 这是一项棘手的任务, 因为有时在加入路径时, 你可能会不小心得到双斜杠, 如下所示: "/test//index.php". 或者由于某种原因, 你缺少斜杠. 这些确实是常见的错误. 因此, 这是你可以安全处理的方法:

1 - 注册 datastore 的 'TARGETURI' 默认 URL:

示例:

  register_options(
    [
      OptString.new('TARGETURI', [true, 'The base path to XXX application', '/xxx_v1/'])
    ])

2 - 使用 target_uri 加载 TARGETURI, 这样将启动 URI 输入验证, 然后你将获得一个真实的 URI 对象:

在此示例中, 我们将加载 URL 路径:

  uri = target_uri.path

3 - 当你要连接路径时, 请使用 normalize_uri:

示例:

  # Returns: "/xxx_v1/admin/upload.php"
  uri = normalize_uri(uri, 'admin', 'upload.php')

4 - 完成 URI 标准化后, 就可以使用 send_request_cgisend_request_raw

请注意: normalize_uri 方法会遵循以下规则:

  1. URI 应该始终以斜杠开头.
  2. 需要自己决定是否结尾带斜杠.
  3. 不应有双斜杠.

完整示例

  require 'msf/core'

  class MetasploitModule < Msf::Auxiliary

    include Msf::Exploit::Remote::HttpClient

    def initialize(info = {})
      super(update_info(info,
        'Name'           => 'HttpClient Example',
        'Description'    => %q{
          Do a send_request_cgi()
        },
        'Author'         => [ 'sinn3r' ],
        'License'        => MSF_LICENSE
      ))

      register_options([
          OptString.new('TARGETURI', [true, 'The base path', '/'])
        ])
    end


    def run
      uri = target_uri.path

      res = send_request_cgi({
        'method'   => 'GET',
        'uri'      => normalize_uri(uri, 'admin', 'index.php'),
        'vars_get' => {
          'p1' => "This is param 1",
          'p2' => "This is param 2"
        }
      })

      if res && res.code == 200
        print_good("I got a 200, awesome")
      else
        print_error("No 200, feeling blue")
      end
    end
  end

其他常见问题:

1 - 我可以 vars_getvars_post 一起使用吗?

可以. 当你向 vars_get 提供 Hash 时, 基本上意味着 "将所有这些数据放入 query 字符串". 当你向 vars_post 提供 Hash 时, 这意味着 "将所有这些数据放入 body 中". 所有这些都将在同一请求中. 当然, 你需要确保使用的是 send_request_cgi.

2 - 由于某些奇怪的原因, 我无法使用 vars_getvars_post, 该怎么办?

请在代码中提及此问题 (作为注释) . 如果你不能使用 vars_post, 则可以改用 data, 它将发送原始数据. 通常, 解决 vars_get 的最常见解决方案是将你的内容留在 uri 中. msftidy 将对此进行标记, 但仅将其标记为 "Info", 而不是警告, 这意味着仍能通过 msftidy. 如果这是一个常见问题, 我们可以随时更改 msftidy.

3 - 我需要手动进行基本身份验证吗?

你无需在请求中手动进行基本身份验证, 因为 HttpClient 会自动为你执行此操作. 你要做的就是在数据存储区选项中设置 usernamepassword, 然后当 Web 服务器验证时, mixin 将使用该用户名和密码.

参考

https://github.com/rapid7/metasploit-framework/wiki/How-to-send-an-HTTP-request-using-Rex-Proto-Http-Client

Clone this wiki locally