ssl_scan 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,369 @@
1
+ # -*- coding: binary -*-
2
+ #
3
+ # This class implements a ring buffer with "cursors" in the form of sequence numbers.
4
+ # To use this class, pass in a file descriptor and a ring size, the class will read
5
+ # data from the file descriptor and store it in the ring. If the ring becomes full,
6
+ # the oldest item will be overwritten. To emulate a stream interface, call read_data
7
+ # to grab the last sequence number and any buffered data, call read_data again,
8
+ # passing in the sequence number and all data newer than that sequence will be
9
+ # returned, along with a new sequence to read from.
10
+ #
11
+
12
+ require 'rex/socket'
13
+
14
+ module Rex
15
+ module IO
16
+
17
+ class RingBuffer
18
+
19
+ attr_accessor :queue # The data queue, essentially an array of two-element arrays, containing a sequence and data buffer
20
+ attr_accessor :seq # The next available sequence number
21
+ attr_accessor :fd # The associated socket or IO object for this ring buffer
22
+ attr_accessor :size # The number of available slots in the queue
23
+ attr_accessor :mutex # The mutex locking access to the queue
24
+ attr_accessor :beg # The index of the earliest data fragment in the ring
25
+ attr_accessor :cur # The sequence number of the earliest data fragment in the ring
26
+ attr_accessor :monitor # The thread handle of the built-in monitor when used
27
+ attr_accessor :monitor_thread_error # :nodoc: #
28
+
29
+ #
30
+ # Create a new ring buffer
31
+ #
32
+ def initialize(socket, opts={})
33
+ self.size = opts[:size] || (1024 * 4)
34
+ self.fd = socket
35
+ self.seq = 0
36
+ self.beg = 0
37
+ self.cur = 0
38
+ self.queue = Array.new( self.size )
39
+ self.mutex = Mutex.new
40
+ end
41
+
42
+ def inspect
43
+ "#<Rex::IO::RingBuffer @size=#{size} @fd=#{fd} @seq=#{seq} @beg=#{beg} @cur=#{cur}>"
44
+ end
45
+
46
+ #
47
+ # Start the built-in monitor, not called when used in a larger framework
48
+ #
49
+ def start_monitor
50
+ self.monitor = monitor_thread if not self.monitor
51
+ end
52
+
53
+ #
54
+ # Stop the built-in monitor
55
+ #
56
+ def stop_monitor
57
+ self.monitor.kill if self.monitor
58
+ self.monitor = nil
59
+ end
60
+
61
+ #
62
+ # The built-in monitor thread (normally unused with Metasploit)
63
+ #
64
+ def monitor_thread
65
+ Thread.new do
66
+ begin
67
+ while self.fd
68
+ buff = self.fd.get_once(-1, 1.0)
69
+ next if not buff
70
+ store_data(buff)
71
+ end
72
+ rescue ::Exception => e
73
+ self.monitor_thread_error = e
74
+ end
75
+ end
76
+ end
77
+
78
+ #
79
+ # Push data back into the associated stream socket. Logging must occur
80
+ # elsewhere, this function is simply a passthrough.
81
+ #
82
+ def put(data, opts={})
83
+ self.fd.put(data, opts={})
84
+ end
85
+
86
+ #
87
+ # The clear_data method wipes the ring buffer
88
+ #
89
+ def clear_data
90
+ self.mutex.synchronize do
91
+ self.seq = 0
92
+ self.beg = 0
93
+ self.cur = 0
94
+ self.queue = Array.new( self.size )
95
+ end
96
+ end
97
+
98
+ #
99
+ # The store_data method is used to insert data into the ring buffer.
100
+ #
101
+ def store_data(data)
102
+ self.mutex.synchronize do
103
+ # self.cur points to the array index of queue containing the last item
104
+ # adding data will result in cur + 1 being used to store said data
105
+ # if cur is larger than size - 1, it will wrap back around. If cur
106
+ # is *smaller* beg, beg is increemnted to cur + 1 (and wrapped if
107
+ # necessary
108
+
109
+ loc = 0
110
+ if self.seq > 0
111
+ loc = ( self.cur + 1 ) % self.size
112
+
113
+ if loc <= self.beg
114
+ self.beg = (self.beg + 1) % self.size
115
+ end
116
+ end
117
+
118
+ self.queue[loc] = [self.seq += 1, data]
119
+ self.cur = loc
120
+ end
121
+ end
122
+
123
+ #
124
+ # The read_data method returns a two element array with the new reader cursor (a sequence number)
125
+ # and the returned data buffer (if any). A result of nil/nil indicates that no data is available
126
+ #
127
+ def read_data(ptr=nil)
128
+ self.mutex.synchronize do
129
+
130
+ # Verify that there is data in the queue
131
+ return [nil,nil] if not self.queue[self.beg]
132
+
133
+ # Configure the beginning read pointer (sequence number, not index)
134
+ ptr ||= self.queue[self.beg][0]
135
+ return [nil,nil] if not ptr
136
+
137
+ # If the pointer is below our baseline, we lost some data, so jump forward
138
+ if ptr < self.queue[self.beg][0]
139
+ ptr = self.queue[self.beg][0]
140
+ end
141
+
142
+ # Calculate how many blocks exist between the current sequence number
143
+ # and the requested pointer, this becomes the number of blocks we will
144
+ # need to read to satisfy the result. Due to the mutex block, we do
145
+ # not need to scan to find the sequence of the starting block or
146
+ # check the sequence of the ending block.
147
+ dis = self.seq - ptr
148
+
149
+ # If the requested sequnce number is less than our base pointer, it means
150
+ # that no new data is available and we should return empty.
151
+ return [nil,nil] if dis < 0
152
+
153
+ # Calculate the beginning block index and number of blocks to read
154
+ off = ptr - self.queue[self.beg][0]
155
+ set = (self.beg + off) % self.size
156
+
157
+
158
+ # Build the buffer by reading forward by the number of blocks needed
159
+ # and return the last read sequence number, plus one, as the new read
160
+ # pointer.
161
+ buff = ""
162
+ cnt = 0
163
+ lst = ptr
164
+ ptr.upto(self.seq) do |i|
165
+ block = self.queue[ (set + cnt) % self.size ]
166
+ lst,data = block[0],block[1]
167
+ buff += data
168
+ cnt += 1
169
+ end
170
+
171
+ return [lst + 1, buff]
172
+
173
+ end
174
+ end
175
+
176
+ #
177
+ # The base_sequence method returns the earliest sequence number in the queue. This is zero until
178
+ # all slots are filled and the ring rotates.
179
+ #
180
+ def base_sequence
181
+ self.mutex.synchronize do
182
+ return 0 if not self.queue[self.beg]
183
+ return self.queue[self.beg][0]
184
+ end
185
+ end
186
+
187
+ #
188
+ # The last_sequence method returns the "next" sequence number where new data will be
189
+ # available.
190
+ #
191
+ def last_sequence
192
+ self.seq
193
+ end
194
+
195
+ #
196
+ # The create_steam method assigns a IO::Socket compatible object to the ringer buffer
197
+ #
198
+ def create_stream
199
+ Stream.new(self)
200
+ end
201
+
202
+ #
203
+ # The select method returns when there is a chance of new data
204
+ # XXX: This is mostly useless and requires a rewrite to use a
205
+ # real select or notify mechanism
206
+ #
207
+ def select
208
+ ::IO.select([ self.fd ], nil, [ self.fd ], 0.10)
209
+ end
210
+
211
+ #
212
+ # The wait method blocks until new data is available
213
+ #
214
+ def wait(seq)
215
+ nseq = nil
216
+ while not nseq
217
+ nseq,data = read_data(seq)
218
+ select
219
+ end
220
+ end
221
+
222
+ #
223
+ # The wait_for method blocks until new data is available or the timeout is reached
224
+ #
225
+ def wait_for(seq,timeout=1)
226
+ begin
227
+ ::Timeout.timeout(timeout) do
228
+ wait(seq)
229
+ end
230
+ rescue ::Timeout::Error
231
+ end
232
+ end
233
+
234
+ #
235
+ # This class provides a backwards compatible "stream" socket that uses
236
+ # the parents ring buffer.
237
+ #
238
+ class Stream
239
+ attr_accessor :ring
240
+ attr_accessor :seq
241
+ attr_accessor :buff
242
+
243
+ def initialize(ring)
244
+ self.ring = ring
245
+ self.seq = ring.base_sequence
246
+ self.buff = ''
247
+ end
248
+
249
+ def read(len=nil)
250
+ if len and self.buff.length >= len
251
+ data = self.buff.slice!(0,len)
252
+ return data
253
+ end
254
+
255
+ while true
256
+ lseq, data = self.ring.read_data( self.seq )
257
+ return if not lseq
258
+
259
+ self.seq = lseq
260
+ self.buff << data
261
+ if len
262
+ if self.buff.length >= len
263
+ return self.buff.slice!(0,len)
264
+ else
265
+ IO.select(nil, nil, nil, 0.25)
266
+ next
267
+ end
268
+ end
269
+
270
+ data = self.buff
271
+ self.buff = ''
272
+
273
+ return data
274
+
275
+ # Not reached
276
+ break
277
+ end
278
+
279
+ end
280
+
281
+ def write(data)
282
+ self.ring.write(data)
283
+ end
284
+ end
285
+
286
+ end
287
+
288
+ end
289
+ end
290
+
291
+ =begin
292
+
293
+ server = Rex::Socket.create_tcp_server('LocalPort' => 0)
294
+ lport = server.getsockname[2]
295
+ client = Rex::Socket.create_tcp('PeerHost' => '127.0.0.1', 'PeerPort' => lport)
296
+ conn = server.accept
297
+
298
+ r = Rex::IO::RingBuffer.new(conn, {:size => 1024*1024})
299
+ client.put("1")
300
+ client.put("2")
301
+ client.put("3")
302
+
303
+ s,d = r.read_data
304
+
305
+ client.put("4")
306
+ client.put("5")
307
+ client.put("6")
308
+ s,d = r.read_data(s)
309
+
310
+ client.put("7")
311
+ client.put("8")
312
+ client.put("9")
313
+ s,d = r.read_data(s)
314
+
315
+ client.put("0")
316
+ s,d = r.read_data(s)
317
+
318
+ test_counter = 11
319
+ 1.upto(100) do
320
+ client.put( "X" )
321
+ test_counter += 1
322
+ end
323
+
324
+ sleep(1)
325
+
326
+ s,d = r.read_data
327
+ p s
328
+ p d
329
+
330
+ fdata = ''
331
+ File.open("/bin/ls", "rb") do |fd|
332
+ fdata = fd.read(fd.stat.size)
333
+ fdata = fdata * 10
334
+ client.put(fdata)
335
+ end
336
+
337
+ sleep(1)
338
+
339
+ s,vdata = r.read_data(s)
340
+
341
+ if vdata != fdata
342
+ puts "DATA FAILED"
343
+ else
344
+ puts "DATA VERIFIED"
345
+ end
346
+
347
+ r.clear_data
348
+
349
+ a = r.create_stream
350
+ b = r.create_stream
351
+
352
+ client.put("ABC123")
353
+ sleep(1)
354
+
355
+ p a.read
356
+ p b.read
357
+
358
+ client.put("$$$$$$")
359
+ sleep(1)
360
+
361
+ p a.read
362
+ p b.read
363
+
364
+ c = r.create_stream
365
+ p c.read
366
+
367
+ =end
368
+
369
+
@@ -0,0 +1,312 @@
1
+ # -*- coding: binary -*-
2
+ require 'ssl_scan/sync/thread_safe'
3
+
4
+ module SSLScan
5
+ module IO
6
+
7
+ ###
8
+ #
9
+ # This mixin is an abstract representation of a streaming connection. Streams
10
+ # extend classes that must implement the following methods:
11
+ #
12
+ # syswrite(buffer)
13
+ # sysread(length)
14
+ # shutdown(how)
15
+ # close
16
+ # peerinfo
17
+ # localinfo
18
+ #
19
+ ###
20
+ module Stream
21
+
22
+ ##
23
+ #
24
+ # Abstract methods
25
+ #
26
+ ##
27
+
28
+ #
29
+ # This method writes the supplied buffer to the stream. This method
30
+ # intelligent reduces the size of supplied buffers so that ruby doesn't get
31
+ # into a potential global thread blocking state when used on blocking
32
+ # sockets. That is, this method will send the supplied buffer in chunks
33
+ # of, at most, 32768 bytes.
34
+ #
35
+ def write(buf, opts = {})
36
+ total_sent = 0
37
+ total_length = buf.length
38
+ block_size = 32768
39
+
40
+ begin
41
+ while( total_sent < total_length )
42
+ s = SSLScan::ThreadSafe.select( nil, [ fd ], nil, 0.2 )
43
+ if( s == nil || s[0] == nil )
44
+ next
45
+ end
46
+ data = buf[total_sent, block_size]
47
+ sent = fd.write_nonblock( data )
48
+ if sent > 0
49
+ total_sent += sent
50
+ end
51
+ end
52
+ rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
53
+ # Sleep for a half a second, or until we can write again
54
+ SSLScan::ThreadSafe.select( nil, [ fd ], nil, 0.5 )
55
+ # Decrement the block size to handle full sendQs better
56
+ block_size = 1024
57
+ # Try to write the data again
58
+ retry
59
+ rescue ::IOError, ::Errno::EPIPE
60
+ return nil
61
+ end
62
+
63
+ total_sent
64
+ end
65
+
66
+ #
67
+ # This method reads data of the supplied length from the stream.
68
+ #
69
+ def read(length = nil, opts = {})
70
+
71
+ begin
72
+ return fd.read_nonblock( length )
73
+ rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
74
+ # Sleep for a half a second, or until we can read again
75
+ SSLScan::ThreadSafe.select( [ fd ], nil, nil, 0.5 )
76
+ # Decrement the block size to handle full sendQs better
77
+ retry
78
+ rescue ::IOError, ::Errno::EPIPE
79
+ return nil
80
+ end
81
+ end
82
+
83
+ #
84
+ # Polls the stream to see if there is any read data available. Returns
85
+ # true if data is available for reading, otherwise false is returned.
86
+ #
87
+ def has_read_data?(timeout = nil)
88
+
89
+ # Allow a timeout of "0" that waits almost indefinitely for input, this
90
+ # mimics the behavior of SSLScan::ThreadSafe.select() and fixes some corner
91
+ # cases of unintentional no-wait timeouts.
92
+ timeout = 3600 if (timeout and timeout == 0)
93
+
94
+ begin
95
+ if ((rv = ::IO.select([ fd ], nil, nil, timeout)) and
96
+ (rv[0]) and
97
+ (rv[0][0] == fd))
98
+ true
99
+ else
100
+ false
101
+ end
102
+ rescue ::Errno::EBADF, ::Errno::ENOTSOCK
103
+ raise ::EOFError
104
+ rescue StreamClosedError, ::IOError, ::EOFError, ::Errno::EPIPE
105
+ # Return false if the socket is dead
106
+ return false
107
+ end
108
+ end
109
+
110
+ #
111
+ # This method returns the selectable file descriptor, or self by default.
112
+ #
113
+ def fd
114
+ self
115
+ end
116
+
117
+ ##
118
+ #
119
+ # Common methods
120
+ #
121
+ ##
122
+
123
+ #
124
+ # This method writes the supplied buffer to the stream by calling the write
125
+ # routine.
126
+ #
127
+ def <<(buf)
128
+ return write(buf.to_s)
129
+ end
130
+
131
+ #
132
+ # This method calls get_once() to read pending data from the socket
133
+ #
134
+ def >>
135
+ get_once
136
+ end
137
+
138
+ #
139
+ # This method writes to the stream, optionally timing out after a period of
140
+ # time.
141
+ #
142
+ def timed_write(buf, wait = def_write_timeout, opts = {})
143
+ if (wait and wait > 0)
144
+ Timeout.timeout(wait) {
145
+ return write(buf, opts)
146
+ }
147
+ else
148
+ return write(buf, opts)
149
+ end
150
+ end
151
+
152
+ #
153
+ # This method reads from the stream, optionally timing out after a period
154
+ # of time.
155
+ #
156
+ def timed_read(length = nil, wait = def_read_timeout, opts = {})
157
+ if (wait and wait > 0)
158
+ Timeout.timeout(wait) {
159
+ return read(length, opts)
160
+ }
161
+ else
162
+ return read(length, opts)
163
+ end
164
+ end
165
+
166
+ #
167
+ # This method writes the full contents of the supplied buffer, optionally
168
+ # with a timeout.
169
+ #
170
+ def put(buf, opts = {})
171
+ return 0 if (buf == nil or buf.length == 0)
172
+
173
+ send_len = buf.length
174
+ send_idx = 0
175
+ wait = opts['Timeout'] || 0
176
+
177
+ # Keep writing until our send length drops to zero
178
+ while (send_idx < send_len)
179
+ curr_len = timed_write(buf[send_idx, buf.length-send_idx], wait, opts)
180
+
181
+ # If the write operation failed due to an IOError, then we fail.
182
+ return buf.length - send_len if (curr_len == nil)
183
+
184
+ send_len -= curr_len
185
+ send_idx += curr_len
186
+ end
187
+
188
+ return buf.length - send_len
189
+ end
190
+
191
+
192
+ #
193
+ # This method emulates the behavior of Pex::Socket::Recv in MSF2
194
+ #
195
+ def get_once(length = -1, timeout = def_read_timeout)
196
+
197
+ if (has_read_data?(timeout) == false)
198
+ return nil
199
+ end
200
+
201
+ bsize = (length == -1) ? def_block_size : length
202
+ data = read(bsize)
203
+ raise EOFError if data.nil?
204
+ data
205
+ end
206
+
207
+ #
208
+ # This method reads as much data as it can from the wire given a maximum
209
+ # timeout.
210
+ #
211
+ def get(timeout = nil, ltimeout = def_read_loop_timeout, opts = {})
212
+ # For those people who are used to being able to use a negative timeout!
213
+ if (timeout and timeout.to_i < 0)
214
+ timeout = nil
215
+ end
216
+
217
+ # No data in the first place? bust.
218
+ if (has_read_data?(timeout) == false)
219
+ return nil
220
+ end
221
+
222
+ buf = ""
223
+ lps = 0
224
+ eof = false
225
+
226
+ # Keep looping until there is no more data to be gotten..
227
+ while (has_read_data?(ltimeout) == true)
228
+ # Catch EOF errors so that we can handle them properly.
229
+ begin
230
+ temp = read(def_block_size)
231
+ rescue EOFError
232
+ eof = true
233
+ end
234
+
235
+ # If we read zero bytes and we had data, then we've hit EOF
236
+ if (temp and temp.length == 0)
237
+ eof = true
238
+ end
239
+
240
+ # If we reached EOF and there are no bytes in the buffer we've been
241
+ # reading into, then throw an EOF error.
242
+ if (eof)
243
+ # If we've already read at least some data, then it's time to
244
+ # break out and let it be processed before throwing an EOFError.
245
+ if (buf.length > 0)
246
+ break
247
+ else
248
+ raise EOFError
249
+ end
250
+ end
251
+
252
+ break if (temp == nil or temp.empty? == true)
253
+
254
+ buf += temp
255
+ lps += 1
256
+
257
+ break if (lps >= def_max_loops)
258
+ end
259
+
260
+ # Return the entire buffer we read in
261
+ return buf
262
+ end
263
+
264
+ ##
265
+ #
266
+ # Defaults
267
+ #
268
+ ##
269
+
270
+ #
271
+ # The default number of seconds to wait for a write operation to timeout.
272
+ #
273
+ def def_write_timeout
274
+ 10
275
+ end
276
+
277
+ #
278
+ # The default number of seconds to wait for a read operation to timeout.
279
+ #
280
+ def def_read_timeout
281
+ 10
282
+ end
283
+
284
+ #
285
+ # The default number of seconds to wait while in a read loop after read
286
+ # data has been found.
287
+ #
288
+ def def_read_loop_timeout
289
+ 0.1
290
+ end
291
+
292
+ #
293
+ # The maximum number of read loops to perform before returning to the
294
+ # caller.
295
+ #
296
+ def def_max_loops
297
+ 1024
298
+ end
299
+
300
+ #
301
+ # The default block size to read in chunks from the wire.
302
+ #
303
+ def def_block_size
304
+ 16384
305
+ end
306
+
307
+ protected
308
+
309
+ end
310
+
311
+ end end
312
+