rapid7/metasploit-framework

View on GitHub
docs/metasploit-framework.wiki/How-to-use-the-Msf-Exploit-Remote-Tcp-mixin.md

Summary

Maintainability
Test Coverage
# How to use the Msf::Exploit::Remote::Tcp mixin
In Metasploit Framework, TCP sockets are implemented as Rex::Socket::Tcp, which extends the built-in Ruby Socket base class. You should always use the Rex socket instead of the native Ruby one because if not, your sockets are not manageable by the framework itself, and of course some features will be missing such as pivoting. The [Developer's Guide](https://github.com/rapid7/metasploit-framework/blob/master/documentation/developers_guide.pdf) in Metasploit's documentation directory explains how this works pretty well.

For module development, normally you wouldn't be using Rex directly, so instead you'd be using the Msf::Exploit::Remote::Tcp mixin. The mixin already provides some useful features you don't really have to worry about during development, such as TCP evasions, proxies, SSL, etc. All you have to do is make that connection, send something, receive something, and you're done.

Sounds pretty easy, right?

## Using the mixin

To use the mixin, simply add the following statement within your module's ```class Metasploit3``` (or ```class Metasploit4```) scope:

```ruby
include Msf::Exploit::Remote::Tcp
```

When the mixin is included, notice there will be the following datastore options registered under your module:

* **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. Maximum TCP segment size.
* **TCP::send_delay** - Evasive option. Delays inserted before every send.

If you wish to learn how to change the default value of a datastore option, please read "[[Changing the default value for a datastore option|./How-to-use-datastore-options.md]]"

## Make a connection

To make a connection, simply do the following:

```ruby
connect
```

When you do this, what happens is that the ```connect``` method will call ```Rex::Socket::Tcp.create``` to create the socket, and register it to framework. It automatically checks with the RHOST/RPORT datastore options (so it knows where to connect to), but you can also manually change this:

```ruby
# This connects to metasploit.com
connect(true, {'RHOST'=>'208.118.237.137', 'RPORT'=>80})
```

The ```connect``` method will then return the Socket object, which is also accessible globally.

But you see, there's a little more to it. The ```connect``` method can also raise some Rex exceptions that you might want to catch, including:

* **Rex::AddressInUse** - Possible when it actually binds to the same IP/port.
* **::Errno::ETIMEDOUT** - When Timeout.timeout() waits to long to connect.
* **Rex::HostUnreachable** - Pretty self-explanatory.
* **Rex::ConnectionTimeout** - Pretty self-explanatory.
* **Rex::ConnectionRefused** - Pretty self-explanatory.

So to sum it up, ideally when you use the ```connect``` method, you should rescue these:

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

If you are curious where all these exceptions are raised, you can find them in [rex/socket/comm/local.rb](https://github.com/rapid7/rex-socket/blob/45b41ef8735aa19ef2c65b6d19eccaf56eaf1e5a/lib/rex/socket/comm/local.rb).

## Sending data

There are several ways to send data with the Tcp mixin. To make things easier and safer, we recommend just use the ```put``` method:

```ruby
sock.put "Hello, World!"
```

The reason the ```put``` method is safer is because it does not allow the routine to hang forever. By default, it doesn't wait, but if you want to make this more flexible, you can do this:

```ruby
begin
    sock.put("data", {'Timeout'=>5})
rescue ::Timeout::Error
    # You can decide what to do if the writing times out
end
```

## Receiving data

Now, let's talk about how to receive data. Mainly there are three methods you can use: `get_once`, `get`, and `timed_read`. The difference is that `get_once` will only try to poll the stream to see if there's any read data available **one time**, but the ```get``` method will keep reading until there is no more. As for ```timed_read```, it's basically the ```read``` method wrapped around with a Timeout.

The following demonstrates how `get_once` is used:

```ruby
begin
    buf = sock.get_once
rescue ::EOFError
end
```

Note that ```get_once``` may also return nil if there is no data read, or it hits a EOFError if it receives nil as data. So please make sure you're catching nil in your module.

The data reading methods can be found in [lib/rex/io/stream.rb](https://github.com/rapid7/rex-core/blob/2ee010fb196116f96419c42ab2b2f0c1dd62c63a/lib/rex/io/stream.rb).

## Disconnecting

To disconnect the connection, simply do:

```ruby
disconnect
```

It is VERY important you disconnect in an ```ensure``` block, obviously to make sure you always disconnect if something goes wrong. If you don't do this, you may end up with a module that can only one request to the server (that very first one), and the rest are broken.

## Full example

The following example should demonstrate how you would typically want to use the Tcp mixin:

```ruby
# 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
```