Class: Pwnlib::Tubes::Tube
- Inherits:
-
Object
- Object
- Pwnlib::Tubes::Tube
- Defined in:
- lib/pwnlib/tubes/tube.rb
Overview
Things common to all tubes (sockets, tty, …)
Direct Known Subclasses
Constant Summary collapse
- BUFSIZE =
Receive 4096 bytes each time.
4096
Instance Method Summary collapse
-
#gets(sep = context.newline, drop: false, timeout: nil) ⇒ String
Receives the next “line” from the tube; lines are separated by
sep
. -
#initialize(timeout: nil) ⇒ Tube
constructor
Instantiate a Tube object.
-
#interact ⇒ Object
Does simultaneous reading and writing to the tube.
-
#puts(*objs) ⇒ Integer
Sends the given object(s).
-
#recv(num_bytes = nil, timeout: nil) ⇒ String
(also: #read)
Receives up to
num_bytes
bytes of data from the tube, and returns as soon as any quantity of data is available. -
#recvall(timeout: nil) ⇒ String
(also: #readall)
Receives data until reaching EOF or a timeout is occurred.
-
#recvline(drop: false, timeout: nil) ⇒ String
Receives a single line from the tube.
-
#recvn(num_bytes, timeout: nil) ⇒ String
(also: #readn)
Receives exactly
num_bytes
bytes. -
#recvpred(timeout: nil) {|data| ... } ⇒ String
Receives one byte at a time from the tube, until the predicate evaluates to
true
. -
#recvregex(regex, timeout: nil) ⇒ String
Wrapper around
recvpred
, which will return when a regex matches the string in the buffer. -
#recvuntil(delims, drop: false, timeout: nil) ⇒ String
Receives data until one of
delims
is encountered. -
#send(data) ⇒ Integer
(also: #write)
Sends data.
-
#sendline(obj) ⇒ Integer
Sends the given object with
context.newline
. -
#unrecv(data) ⇒ Integer
Puts the specified data back at the beginning of the receive buffer.
Constructor Details
#initialize(timeout: nil) ⇒ Tube
Instantiate a Pwnlib::Tubes::Tube object.
43 44 45 46 |
# File 'lib/pwnlib/tubes/tube.rb', line 43 def initialize(timeout: nil) @timer = Timer.new(timeout) @buffer = Buffer.new end |
Instance Method Details
#gets(sep = context.newline, drop: false, timeout: nil) ⇒ String
Receives the next “line” from the tube; lines are separated by sep
. The difference with IO#gets is using context.newline
as default newline.
250 251 252 253 254 255 256 257 258 259 |
# File 'lib/pwnlib/tubes/tube.rb', line 250 def gets(sep = context.newline, drop: false, timeout: nil) case sep when Integer recvn(sep, timeout: timeout) when String recvuntil(sep, drop: drop, timeout: timeout) else raise ArgumentError, 'only Integer and String are supported' end end |
#interact ⇒ Object
Does simultaneous reading and writing to the tube. In principle this just connects the tube to standard in and standard out.
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 |
# File 'lib/pwnlib/tubes/tube.rb', line 357 def interact log.info('Switching to interactive mode') $stdout.write(@buffer.get) until io_out.closed? rs, = IO.select([$stdin, io_out]) if rs.include?($stdin) s = $stdin.readpartial(BUFSIZE) write(s) end if rs.include?(io_out) s = recv $stdout.write(s) end end rescue ::Pwnlib::Errors::EndOfTubeError log.info('Got EOF in interactive mode') end |
#puts(*objs) ⇒ Integer
Sends the given object(s). The difference with IO#puts is using context.newline
as default newline.
343 344 345 346 347 348 349 350 351 352 353 |
# File 'lib/pwnlib/tubes/tube.rb', line 343 def puts(*objs) return write(context.newline) if objs.empty? objs = *objs.flatten s = +'' objs.map(&:to_s).each do |elem| s << elem s << context.newline unless elem.end_with?(context.newline) end write(s) end |
#recv(num_bytes = nil, timeout: nil) ⇒ String Also known as: read
Receives up to num_bytes
bytes of data from the tube, and returns as soon as any quantity of data is available.
61 62 63 64 65 |
# File 'lib/pwnlib/tubes/tube.rb', line 61 def recv(num_bytes = nil, timeout: nil) return '' if @buffer.empty? && !fillbuffer(timeout: timeout) @buffer.get(num_bytes) end |
#recvall(timeout: nil) ⇒ String Also known as: readall
Receives data until reaching EOF or a timeout is occurred.
280 281 282 283 284 |
# File 'lib/pwnlib/tubes/tube.rb', line 280 def recvall(timeout: nil) recvn(1 << 63, timeout: timeout) rescue ::Pwnlib::Errors::EndOfTubeError, ::Pwnlib::Errors::TimeoutError @buffer.get end |
#recvline(drop: false, timeout: nil) ⇒ String
Receives a single line from the tube. A “line” is any sequence of bytes terminated by the byte sequence set in context.newline
, which defaults to “\n”.
215 216 217 |
# File 'lib/pwnlib/tubes/tube.rb', line 215 def recvline(drop: false, timeout: nil) recvuntil(context.newline, drop: drop, timeout: timeout) end |
#recvn(num_bytes, timeout: nil) ⇒ String Also known as: readn
Receives exactly num_bytes
bytes. If the request is not satisfied before timeout
seconds pass, all data is buffered and an empty string '' is returned.
138 139 140 141 142 143 |
# File 'lib/pwnlib/tubes/tube.rb', line 138 def recvn(num_bytes, timeout: nil) @timer.countdown(timeout) do fillbuffer while @timer.active? && @buffer.size < num_bytes @buffer.size >= num_bytes ? @buffer.get(num_bytes) : '' end end |
#recvpred(timeout: nil) {|data| ... } ⇒ String
Receives one byte at a time from the tube, until the predicate evaluates to true
.
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/pwnlib/tubes/tube.rb', line 102 def recvpred(timeout: nil) raise ArgumentError, 'Need a block for recvpred' unless block_given? @timer.countdown(timeout) do data = +'' begin until yield(data) return '' unless @timer.active? c = recv(1) return '' if c.empty? data << c end data.slice!(0..-1) ensure unrecv(data) end end end |
#recvregex(regex, timeout: nil) ⇒ String
Wrapper around recvpred
, which will return when a regex matches the string in the buffer.
270 271 272 |
# File 'lib/pwnlib/tubes/tube.rb', line 270 def recvregex(regex, timeout: nil) recvpred(timeout: timeout) { |data| data =~ regex } end |
#recvuntil(delims, drop: false, timeout: nil) ⇒ String
Receives data until one of delims
is encountered. If the request is not satisfied before timeout
seconds pass, all data is buffered and an empty string is returned.
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 |
# File 'lib/pwnlib/tubes/tube.rb', line 163 def recvuntil(delims, drop: false, timeout: nil) delims = Array(delims) max_len = delims.map(&:size).max @timer.countdown(timeout) do data = Buffer.new matching = +'' begin while @timer.active? s = recv(1) return '' if s.empty? matching << s sidx = matching.size match_len = 0 delims.each do |d| idx = matching.index(d) next unless idx if idx + d.size <= sidx + match_len sidx = idx match_len = d.size end end if sidx < matching.size r = data.get + matching.slice!(0, sidx + match_len) r.slice!(-match_len..-1) if drop return r end data << matching.slice!(0...-max_len) if matching.size > max_len end '' ensure unrecv(matching) unrecv(data) end end end |
#send(data) ⇒ Integer Also known as: write
Sends data.
293 294 295 296 297 298 299 |
# File 'lib/pwnlib/tubes/tube.rb', line 293 def send(data) data = data.to_s log.debug(format('Sent %#x bytes:', data.size)) log.indented(::Pwnlib::Util::HexDump.hexdump(data), level: DEBUG) send_raw(data) data.size end |
#sendline(obj) ⇒ Integer
Sends the given object with context.newline
.
308 309 310 311 |
# File 'lib/pwnlib/tubes/tube.rb', line 308 def sendline(obj) s = obj.to_s + context.newline write(s) end |
#unrecv(data) ⇒ Integer
Puts the specified data back at the beginning of the receive buffer.
75 76 77 78 |
# File 'lib/pwnlib/tubes/tube.rb', line 75 def unrecv(data) @buffer.unget(data) data.size end |