Module: Msf::Handler::BindTcp

Includes:
Msf::Handler
Defined in:
lib/msf/core/handler/bind_tcp.rb

Overview

This module implements the Bind TCP handler. This means that it will attempt to connect to a remote host on a given port for a period of time (typically the duration of an exploit) to see if a the payload has started listening. This can tend to be rather verbose in terms of traffic and in general it is preferable to use reverse payloads.

Constant Summary

Constants included from Msf::Handler

Claimed, Unused

Instance Attribute Summary collapse

Attributes included from Msf::Handler

#exploit_config, #parent_payload, #pending_connections, #session_waiter_event, #sessions

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Msf::Handler

#create_session, #handle_connection, #handler, #handler_name, #interrupt_wait_for_session, #register_session, #setup_handler, #wait_for_session, #wfs_delay

Instance Attribute Details

#conn_threadsObject (protected)

:nodoc:



237
238
239
# File 'lib/msf/core/handler/bind_tcp.rb', line 237

def conn_threads
  @conn_threads
end

#listener_pairsObject (protected)

:nodoc:



239
240
241
# File 'lib/msf/core/handler/bind_tcp.rb', line 239

def listener_pairs
  @listener_pairs
end

#listener_threadsObject (protected)

:nodoc:



238
239
240
# File 'lib/msf/core/handler/bind_tcp.rb', line 238

def listener_threads
  @listener_threads
end

Class Method Details

.general_handler_typeObject

Returns the connection oriented general handler type, in this case bind.



29
30
31
# File 'lib/msf/core/handler/bind_tcp.rb', line 29

def self.general_handler_type
  "bind"
end

.handler_typeObject

Returns the handler specific string representation, in this case ‘bind_tcp’.



22
23
24
# File 'lib/msf/core/handler/bind_tcp.rb', line 22

def self.handler_type
  return "bind_tcp"
end

Instance Method Details

#add_handler(opts = {}) ⇒ Object

Starts a new connecting thread



72
73
74
75
76
77
78
79
80
81
# File 'lib/msf/core/handler/bind_tcp.rb', line 72

def add_handler(opts={})

  # Merge the updated datastore values
  opts.each_pair do |k,v|
    datastore[k] = v
  end

  # Start a new handler
  start_handler
end

#cleanup_handlerObject

Kills off the connection threads if there are any hanging around.



61
62
63
64
65
66
67
# File 'lib/msf/core/handler/bind_tcp.rb', line 61

def cleanup_handler
  # Kill any remaining handle_connection threads that might
  # be hanging around
  conn_threads.each { |thr|
    thr.kill
  }
end

#human_nameString

A string suitable for displaying to the user

Returns:

  • (String)


36
37
38
# File 'lib/msf/core/handler/bind_tcp.rb', line 36

def human_name
  "bind TCP"
end

#initialize(info = {}) ⇒ Object

Initializes a bind handler and adds the options common to all bind payloads, such as local port.



44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/msf/core/handler/bind_tcp.rb', line 44

def initialize(info = {})
  super

  register_options(
    [
      Opt::LPORT(4444),
      OptAddress.new('RHOST', [false, 'The target address', '']),
    ], Msf::Handler::BindTcp)

  self.conn_threads = []
  self.listener_threads = []
  self.listener_pairs = {}
end

#start_handlerObject

Starts monitoring for an outbound connection to become established.



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/msf/core/handler/bind_tcp.rb', line 86

def start_handler

  # Maximum number of seconds to run the handler
  ctimeout = 150

  if (exploit_config and exploit_config['active_timeout'])
    ctimeout = exploit_config['active_timeout'].to_i
  end

  # Take a copy of the datastore options
  rhost = datastore['RHOST']
  lport = datastore['LPORT']

  # Ignore this if one of the required options is missing
  return if not rhost
  return if not lport

  # Only try the same host/port combination once
  phash = rhost + ':' + lport.to_s
  return if self.listener_pairs[phash]
  self.listener_pairs[phash] = true

  # Start a new handling thread
  self.listener_threads << framework.threads.spawn("BindTcpHandlerListener-#{lport}", false) {
    client = nil

    print_status("Started #{human_name} handler against #{rhost}:#{lport}")

    if (rhost == nil)
      raise ArgumentError,
        "RHOST is not defined; bind stager cannot function.",
        caller
    end

    stime = Time.now.to_i

    while (stime + ctimeout > Time.now.to_i)
      begin
        client = Rex::Socket::Tcp.create(
          'PeerHost' => rhost,
          'PeerPort' => lport.to_i,
          'Proxies'  => datastore['Proxies'],
          'Context'  =>
            {
              'Msf'        => framework,
              'MsfPayload' => self,
              'MsfExploit' => assoc_exploit
            })
      rescue Rex::ConnectionError => e
        vprint_error(e.message)
      rescue
        wlog("Exception caught in bind handler: #{$!.class} #{$!}")
      end

      break if client

      # Wait a second before trying again
      Rex::ThreadSafe.sleep(0.5)
    end

    # Valid client connection?
    if (client)
      # Increment the has connection counter
      self.pending_connections += 1

      # Timeout and datastore options need to be passed through to the client
      opts = {
        :datastore    => datastore,
        :expiration   => datastore['SessionExpirationTimeout'].to_i,
        :comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
        :retry_total  => datastore['SessionRetryTotal'].to_i,
        :retry_wait   => datastore['SessionRetryWait'].to_i
      }

      # Start a new thread and pass the client connection
      # as the input and output pipe.  Client's are expected
      # to implement the Stream interface.
      conn_threads << framework.threads.spawn("BindTcpHandlerSession", false, client) { |client_copy|
        begin
          handle_connection(wrap_aes_socket(client_copy), opts)
        rescue => e
          elog('Exception raised from BindTcp.handle_connection', error: e)
        end
      }
    else
      wlog("No connection received before the handler completed")
    end
  }
end

#stop_handlerObject

Nothing to speak of.



226
227
228
229
230
231
232
233
# File 'lib/msf/core/handler/bind_tcp.rb', line 226

def stop_handler
  # Stop the listener threads
  self.listener_threads.each do |t|
    t.kill
  end
  self.listener_threads = []
  self.listener_pairs = {}
end

#wrap_aes_socket(sock) ⇒ Object



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/msf/core/handler/bind_tcp.rb', line 176

def wrap_aes_socket(sock)
  if datastore["PAYLOAD"] !~ /java\// or (datastore["AESPassword"] || "") == ""
    return sock
  end

  socks = Rex::Socket::tcp_socket_pair()
  socks[0].extend(Rex::Socket::Tcp)
  socks[1].extend(Rex::Socket::Tcp)

  m = OpenSSL::Digest.new('md5')
  m.reset
  key = m.digest(datastore["AESPassword"] || "")

  Rex::ThreadFactory.spawn('AESEncryption', false) {
    c1 = OpenSSL::Cipher.new('aes-128-cfb8')
    c1.encrypt
    c1.key=key
    sock.put([0].pack('N'))
    sock.put(c1.iv=c1.random_iv)
    buf1 = socks[0].read(4096)
    while buf1 and buf1 != ""
      sock.put(c1.update(buf1))
      buf1 = socks[0].read(4096)
    end
    sock.close()
  }

  Rex::ThreadFactory.spawn('AESEncryption', false) {
    c2 = OpenSSL::Cipher.new('aes-128-cfb8')
    c2.decrypt
    c2.key=key
    iv=""
    while iv.length < 16
      iv << sock.read(16-iv.length)
    end
    c2.iv = iv
    buf2 = sock.read(4096)
    while buf2 and buf2 != ""
      socks[0].put(c2.update(buf2))
      buf2 = sock.read(4096)
    end
    socks[0].close()
  }

  return socks[1]
end