在Metasploit Framework,TCP套接字被实现为 Rex::Socket::Tcp,它扩展了内建的Ruby Socket基类。你应该总是使用Rex套接字,而不是原生的Ruby套接字.因为如果不是的话,你的套接字是不能被框架本身管理的,当然一些功能会丢失,比如pivoting。Metasploit的文档目录中的Developer's Guide解释了它是怎么工作的很好的 对于模块开发,通常你不会直接使用Rex,相反你应该会使用 msf::Exploit::Remote::Tcp mixin.mixin已经提供了一些有用功能M,在开发过程中你并不需要担心,例如TCP规避,代理,SSL等等。你所要做的就是建立连接,发送东西,接收东西,你就能完成。 听起来很简单对吧?
要使用mixin,只需在模块的class Metasploit3
(或class Metasploit4
)范围内添加以下语句:
include Msf::Exploit::Remote::Tcp
当包含mixin时,请注意将在您的模块下注册以下数据存储选项:
- SSL - Negotiate SSL for outgoing connections.
- SSLVersion - The SSL version used: SSL2, SSL3, TLS1. Default is TLS1.
- SSLVerifyMode - Verification mode: CLIENT_ONCE, FAIL_IF_NO_PEER_CERT, NONE, PEER. Default is PEER.
- Proxies - Allows your module to support proxies.
- ConnectTimeout - Default is 10 seconds.
- TCP::max_send_size - Evasive option. Maxiumum TCP segment size.
- TCP::send_delay - Evasive option. Delays inserted before every send.
如果您想了解如何更改数据存储区选项的默认值,请查看"Changing the default value for a datastore option"
要建立连接,只需执行以下操作:
connect
当你这样做的时候 ,connect
将会调用Rex::Socket::Tcp.create
来创造套接字,和在框架注册它.它自动确认RHOST/RPORT数据储存选项(所以它知道连接到哪里),但是你也可以手动改变它:
# This connects to 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 - 相当不言自明
如果您对所有这些异常的抛出感到好奇,你能在lib/rex/socket/comm/local.rb找到
有几种方法可以用Tcp mixin发送数据。为了使事情变得更简单和安全,我们建议您只使用以下这个put方法
sock.put "Hello, World!"
put方法更安全的原因是因为它不允许例程永久挂起。默认情况下,它不会等待,但是如果要使其更灵活,可以这样做:
begin
sock.put("data", {'Timeout'=>5})
rescue ::Timeout::Error
# You can decide what to do if the writing times out
end
现在,我们来谈谈如何接收数据。主要有三种方法可以使用:get_once,get和timed_read。区别在于get_once只会尝试轮询流直到有一些读取数据可用 一次.但是这个get方法会一直读取,直到没有更多。至于timed_read,它基本上是read用Timeout包装起来的方法。
一般来说,我们希望您使用get_once
,因为它更安全一些。以下演示如何使用它:
begin
buf = sock.get_once
rescue ::EOFError
end
请注意,get_once如果没有读取数据,也可能返回nil,或者如果数据为零,则返回EOFError。所以请确保你在模块中捕获到nil。
数据读取方法可以在lib/rex/io/stream.rb找到.
要断开一个连接,只需要
disconnect
在ensure块中.断开连接是非常重要的.显然要确保在出现问题时总是断开连接。如果你不这样做,你可能会得到一个只能向服务器发送一个请求(第一个请求)的模块,其余的都是坏的。
下面的例子应该演示了 你通常会如何使用Tcp mixin:
# Sends data to the remote machine
#
# @param data [String] The data to send
# @return [String] The received data
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