Class: OpenPipeSock
- Inherits:
-
Rex::Proto::SMB::SimpleClient::OpenPipe
- Object
- Rex::Proto::SMB::SimpleClient::OpenFile
- Rex::Proto::SMB::SimpleClient::OpenPipe
- OpenPipeSock
- Defined in:
- lib/msf/core/handler/bind_named_pipe.rb
Overview
Socket interface for named pipes. Because of the way named pipes work, reads and writes each require both a sock.send (read/write request) and a sock.recv (read/write response). So, pipe.read and pipe.write need to be synchronized so the responses arent mixed up.
The packet dispatcher calls select on the socket to check for packets to read. This is an issue when there are multiple writes since it will cause select to return which triggers a read, but there is nothing to read since the pipe will already have read the response. This read will then hold the mutex while the socket read waits to timeout. A peek operation on the pipe fixes this.
Constant Summary collapse
- STATUS_BUFFER_OVERFLOW =
0x80000005
- STATUS_PIPE_BROKEN =
0xc000014b
Instance Attribute Summary collapse
-
#echo_thread ⇒ Object
Returns the value of attribute echo_thread.
-
#last_comm ⇒ Object
Returns the value of attribute last_comm.
-
#mutex ⇒ Object
Returns the value of attribute mutex.
-
#read_buff ⇒ Object
Returns the value of attribute read_buff.
-
#server_max_buffer_size ⇒ Object
Returns the value of attribute server_max_buffer_size.
-
#simple ⇒ Object
Returns the value of attribute simple.
-
#write_queue ⇒ Object
Returns the value of attribute write_queue.
-
#write_thread ⇒ Object
Returns the value of attribute write_thread.
Attributes inherited from Rex::Proto::SMB::SimpleClient::OpenPipe
Attributes inherited from Rex::Proto::SMB::SimpleClient::OpenFile
#chunk_size, #client, #file_id, #mode, #name, #tree_id, #versions
Instance Method Summary collapse
-
#close ⇒ Object
Intercepts the socket.close from the session manager when the session dies.
-
#dispatcher ⇒ Object
Runs as a thread and synchronizes writes.
-
#fd ⇒ Object
The session manager expects a socket object so we must implement fd, localinfo, and peerinfo.
-
#force_read ⇒ Object
Send echo request to force select() to return in the packet dispatcher and read from the socket.
-
#initialize(*args, simple:, server_max_buffer_size:) ⇒ OpenPipeSock
constructor
A new instance of OpenPipeSock.
- #localinfo ⇒ Object
- #peerinfo ⇒ Object
- #put(data) ⇒ Object
- #read(count) ⇒ Object
- #write(data) ⇒ Object
Methods inherited from Rex::Proto::SMB::SimpleClient::OpenPipe
#peek, #peek_rex_smb, #peek_ruby_smb, #read_buffer, #write_trans
Methods inherited from Rex::Proto::SMB::SimpleClient::OpenFile
#<<, #delete, #read_rex_smb, #read_ruby_smb
Constructor Details
#initialize(*args, simple:, server_max_buffer_size:) ⇒ OpenPipeSock
Returns a new instance of OpenPipeSock.
29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/msf/core/handler/bind_named_pipe.rb', line 29 def initialize(*args, simple:, server_max_buffer_size:) super(*args) self.simple = simple self.client = simple.client self.mutex = Mutex.new # synchronize read/writes self.last_comm = Time.now # last successfull read/write self.write_queue = Queue.new # messages to send self.write_thread = Thread.new { dispatcher } self.echo_thread = Thread.new { force_read } self.read_buff = '' self.server_max_buffer_size = server_max_buffer_size # max transaction size self.chunk_size = server_max_buffer_size - 260 # max read/write size end |
Instance Attribute Details
#echo_thread ⇒ Object
Returns the value of attribute echo_thread.
24 25 26 |
# File 'lib/msf/core/handler/bind_named_pipe.rb', line 24 def echo_thread @echo_thread end |
#last_comm ⇒ Object
Returns the value of attribute last_comm.
24 25 26 |
# File 'lib/msf/core/handler/bind_named_pipe.rb', line 24 def last_comm @last_comm end |
#mutex ⇒ Object
Returns the value of attribute mutex.
24 25 26 |
# File 'lib/msf/core/handler/bind_named_pipe.rb', line 24 def mutex @mutex end |
#read_buff ⇒ Object
Returns the value of attribute read_buff.
24 25 26 |
# File 'lib/msf/core/handler/bind_named_pipe.rb', line 24 def read_buff @read_buff end |
#server_max_buffer_size ⇒ Object
Returns the value of attribute server_max_buffer_size.
24 25 26 |
# File 'lib/msf/core/handler/bind_named_pipe.rb', line 24 def server_max_buffer_size @server_max_buffer_size end |
#simple ⇒ Object
Returns the value of attribute simple.
24 25 26 |
# File 'lib/msf/core/handler/bind_named_pipe.rb', line 24 def simple @simple end |
#write_queue ⇒ Object
Returns the value of attribute write_queue.
24 25 26 |
# File 'lib/msf/core/handler/bind_named_pipe.rb', line 24 def write_queue @write_queue end |
#write_thread ⇒ Object
Returns the value of attribute write_thread.
24 25 26 |
# File 'lib/msf/core/handler/bind_named_pipe.rb', line 24 def write_thread @write_thread end |
Instance Method Details
#close ⇒ Object
Intercepts the socket.close from the session manager when the session dies. Cleanly terminates the SMB session and closes the socket.
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/msf/core/handler/bind_named_pipe.rb', line 80 def close self.echo_thread.kill rescue nil # Give the meterpreter shutdown command a chance self.write_queue.close begin if self.write_thread.join(2.0) self.write_thread.kill end rescue end # close pipe, share, and socket super rescue nil self.simple.disconnect(self.simple.last_share) rescue nil self.client.socket.close end |
#dispatcher ⇒ Object
Runs as a thread and synchronizes writes. Allows write operations to return immediately instead of waiting for the mutex.
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/msf/core/handler/bind_named_pipe.rb', line 62 def dispatcher while not self.write_queue.closed? data = self.write_queue.pop self.mutex.synchronize do sent = 0 while sent < data.length count = [self.chunk_size, data.length-sent].min buf = data[sent, count] Rex::Proto::SMB::SimpleClient::OpenPipe.instance_method(:write).bind(self).call(buf) self.last_comm = Time.now sent += count end end end end |
#fd ⇒ Object
The session manager expects a socket object so we must implement fd, localinfo, and peerinfo. fd is passed to select while localinfo and peerinfo are used to report the addresses and ports of the connection.
141 142 143 |
# File 'lib/msf/core/handler/bind_named_pipe.rb', line 141 def fd self.simple.socket.fd end |
#force_read ⇒ Object
Send echo request to force select() to return in the packet dispatcher and read from the socket. This allows “channel -i” and “shell” to work.
45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/msf/core/handler/bind_named_pipe.rb', line 45 def force_read wait = 0.5 # smaller is faster but generates more traffic while true elapsed = Time.now - self.last_comm if elapsed > wait self.mutex.synchronize do self.client.echo() self.last_comm = Time.now end else Rex::ThreadSafe.sleep(wait-elapsed) end end end |
#localinfo ⇒ Object
145 146 147 |
# File 'lib/msf/core/handler/bind_named_pipe.rb', line 145 def localinfo self.simple.socket.localinfo end |
#peerinfo ⇒ Object
149 150 151 |
# File 'lib/msf/core/handler/bind_named_pipe.rb', line 149 def peerinfo self.simple.socket.peerinfo end |
#put(data) ⇒ Object
126 127 128 |
# File 'lib/msf/core/handler/bind_named_pipe.rb', line 126 def put (data) write(data) end |
#read(count) ⇒ Object
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 |
# File 'lib/msf/core/handler/bind_named_pipe.rb', line 97 def read(count) data = '' if count > self.read_buff.length # need more data to satisfy request self.mutex.synchronize do avail = peek self.last_comm = Time.now if avail > 0 left = [count-self.read_buff.length, avail].max while left > 0 buff = super([left, self.chunk_size].min) self.last_comm = Time.now left -= buff.length self.read_buff += buff end end end end data = self.read_buff[0, [count, self.read_buff.length].min] self.read_buff = self.read_buff[data.length..-1] if data.length == 0 # avoid full throttle polling Rex::ThreadSafe.sleep(0.2) end data end |
#write(data) ⇒ Object
130 131 132 133 |
# File 'lib/msf/core/handler/bind_named_pipe.rb', line 130 def write (data) self.write_queue.push(data) data.length end |