Skip to content

怎么使用 Msf::Exploit::Remote::Tcp mixin

L edited this page May 18, 2022 · 1 revision

怎么使用 Msf::Exploit::Remote::Tcp mixin

在 Metasploit 框架中, TCP 套接字被实现为 Rex::Socket::Tcp, 它扩展了内置的 Ruby Socket 基类. 你应该始终使用 Rex 套接字而不是本机 Ruby 套接字, 因为如果不这样做, 你的套接字将无法由框架本身管理, 并且当然会缺少某些功能, 例如转发. Metasploit 文档目录中的 开发人员指南 解释了它是如何工作的.

对于模块开发, 通常你不会直接使用 Rex, 而是使用 Msf::Exploit::Remote::Tcp 混合. mixin 已经提供了一些你在开发过程中不必担心的有用功能, 例如 TCP 规避、代理、SSL 等. 你所要做的就是建立连接、发送某些内容、接收某些内容, 然后你就可以完毕.

听起来很容易, 对吧?

使用 mixin

要使用 mixin, 只需在模块的 class MetasploitModule 范围内添加以下语句:

include Msf::Exploit::Remote::Tcp

当包含 mixin 时, 请注意将在你的模块下注册以下 datastore 选项:

  • SSL - 协商 SSL 连接
  • SSLVersion - SSL 使用的版本: SSL2, SSL3, TLS1. 默认为 TLS1.
  • SSLVerifyMode - 验证模式: CLIENT_ONCE, FAIL_IF_NO_PEER_CERT, NONE, PEER. 默认是 PEER.
  • Proxies - 允许模块支持代理.
  • ConnectTimeout - 默认 10 秒.
  • TCP::max_send_size - 回避选项. 最大 TCP 段大小.
  • TCP::send_delay - 回避选项. 在每次发送之前插入延迟.

如果你想了解如何更改 datastore 选项的默认值, 请阅读 "更改 datastore 选项的默认值"

创建连接

要建立连接, 只需执行以下操作:

connect

执行此操作时, connect 方法将调用 Rex::Socket::Tcp.create 来创建套接字, 并将其注册到框架. 它会自动检查 RHOST/RPORT 数据存储选项 (因此它知道连接到哪里) , 但你也可以手动更改:

# 连接到 metasploit.com
connect(true, {'RHOST'=>'208.118.237.137', 'RPORT'=>80})

然后 connect 方法将返回 Socket 对象, 该对象也可以全局访问.

connect 方法还可以引发一些你可能想要捕获的 Rex 异常, 包括:

  • Rex::AddressInUse - 当它可能实际绑定到相同的 IP/端口时.
  • ::Errno::ETIMEDOUT - 当 Timeout.timeout() 等待很长时间才能连接时.
  • Rex::HostUnreachable - 主机不可达.
  • Rex::ConnectionTimeout - 连接超时.
  • Rex::ConnectionRefused - 连接中断.

所以总结一下, 理想情况下, 当你使用 connect 方法时, 你应该 rescue 这些:

rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused

如果你好奇所有这些异常是在哪里引发的, 你可以在 lib/rex/socket/comm/local.rb 中查看.

发送数据

有几种方法可以使用 Tcp mixin 发送数据. 为了让事情变得更容易和更安全, 我们建议只使用 put 方法:

sock.put "Hello, World!"

put 方法更安全的原因是它不允许线程永远挂起. 默认情况下, 它不会等待, 但如果你想让它更灵活, 你可以这样做:

begin
	sock.put("data", {'Timeout'=>5})
rescue ::Timeout::Error
	# 如果写入超时, 你可以决定该怎么做
end

接受数据

现在, 我们来谈谈如何接收数据. 主要可以使用三种方法: get_once, gettimed_read.不同之处在于 get_once 只会尝试轮询流以查看是否有任何读取数据可用一次, 但 get 方法将继续读取, 直到没有更多内容为止. 至于 timed_read, 它基本上是用 Timeout 包裹的 read 方法.

下面演示了如何使用 get_once:

begin
	buf = sock.get_once
rescue ::EOFError
end

请注意, 如果没有读取数据, get_once 也可能返回 nil, 或者如果它接收到 nil 作为数据, 它会遇到 EOFError. 所以请确保你在你的模块中捕捉到 nil .

数据读取方法可以在 lib/rex/io/stream.rb 中找到.

断开连接

要断开连接, 只需执行以下操作:

disconnect

ensure 块中断开连接非常重要, 显然是为了确保在出现问题时始终断开连接. 如果你不这样做, 你最终可能会得到一个模块, 该模块只能向服务器发出一个请求 (即第一个请求) , 其余的都被破坏了.

完整示例

以下示例应演示你通常希望如何使用 Tcp mixin:

# 发送一些数据到远程机器
#
# @param data [String] 需要发送的数据
# @return [String] 接受的数据
def send_recv_once(data)
	buf = ''
	begin
		connect
		sock.put(data)
		buf = sock.get_once || ''
	rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e
		elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
	ensure
		disconnect
	end

	buf
end
Clone this wiki locally