Method: Rex::Proto::DCERPC::Client#read

Defined in:
lib/rex/proto/dcerpc/client.rb

#readObject



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
175
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
# File 'lib/rex/proto/dcerpc/client.rb', line 134

def read()

  max_read = self.options['pipe_read_max_size'] || 1024*1024
  min_read = self.options['pipe_read_min_size'] || max_read

  raw_response = ''

  # Are we reading from a remote pipe over SMB?
  if (self.socket.class == Rex::Proto::SMB::SimpleClient::OpenPipe)
    begin

      # Max SMB read is 65535, cap it at 64000
      max_read = [64000, max_read].min
      min_read = [64000, min_read].min

      read_limit = nil

      while(true)
        # Random read offsets will not work on Windows NT 4.0 (thanks Dave!)

        read_cnt = (rand(max_read-min_read)+min_read)
        if(read_limit)
          if(read_cnt + raw_response.length > read_limit)
            read_cnt = raw_response.length - read_limit
          end
        end

        data = self.socket.read( read_cnt, rand(1024)+1)
        break if !(data and data.length > 0)
        raw_response += data

        # Keep reading until we have at least the DCERPC header
        next if raw_response.length < 10

        # We now have to process the raw_response and parse out the DCERPC fragment length
        # if we have read enough data. Once we have the length value, we need to make sure
        # that we don't read beyond this amount, or it can screw up the SMB state
        if (not read_limit)
          begin
            check = Rex::Proto::DCERPC::Response.new(raw_response)
            read_limit = check.frag_len
          rescue ::Rex::Proto::DCERPC::Exceptions::InvalidPacket
          end
        end
        break if (read_limit and read_limit <= raw_response.length)
      end

    rescue Rex::Proto::SMB::Exceptions::NoReply
      # I don't care if I didn't get a reply...
    rescue Rex::Proto::SMB::Exceptions::ErrorCode => exception
      if exception.error_code != 0xC000014B
        raise exception
      end
    end
  # This must be a regular TCP or UDP socket
  else
    if (self.socket.type? == 'tcp')
      if (false and max_read)
        while (true)
          data = self.socket.get_once((rand(max_read-min_read)+min_read), self.options['read_timeout'])
          break if not data
          break if not data.length
          raw_response << data
        end
      else
        # Just read the entire response in one go
        raw_response = self.socket.get_once(-1, self.options['read_timeout'])
      end
    else
      # No segmented read support for non-TCP sockets
      raw_response = self.socket.read(0xFFFFFFFF / 2 - 1)  # read max data
    end
  end

  raw_response
end