pwntools 1.0.1 → 1.1.0
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.
- checksums.yaml +5 -5
- data/README.md +4 -3
- data/Rakefile +3 -1
- data/lib/pwnlib/asm.rb +172 -2
- data/lib/pwnlib/constants/constants.rb +10 -3
- data/lib/pwnlib/context.rb +1 -3
- data/lib/pwnlib/elf/elf.rb +3 -3
- data/lib/pwnlib/errors.rb +30 -0
- data/lib/pwnlib/ext/helper.rb +1 -1
- data/lib/pwnlib/logger.rb +140 -2
- data/lib/pwnlib/pwn.rb +3 -0
- data/lib/pwnlib/reg_sort.rb +1 -1
- data/lib/pwnlib/shellcraft/generators/amd64/common/infloop.rb +9 -3
- data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr_array.rb +6 -2
- data/lib/pwnlib/shellcraft/generators/amd64/common/setregs.rb +6 -2
- data/lib/pwnlib/shellcraft/generators/amd64/linux/cat.rb +23 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/execve.rb +6 -4
- data/lib/pwnlib/shellcraft/generators/amd64/linux/exit.rb +23 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/ls.rb +6 -2
- data/lib/pwnlib/shellcraft/generators/amd64/linux/open.rb +23 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/sh.rb +6 -2
- data/lib/pwnlib/shellcraft/generators/amd64/linux/syscall.rb +6 -4
- data/lib/pwnlib/shellcraft/generators/i386/common/infloop.rb +9 -3
- data/lib/pwnlib/shellcraft/generators/i386/common/pushstr_array.rb +6 -2
- data/lib/pwnlib/shellcraft/generators/i386/common/setregs.rb +6 -2
- data/lib/pwnlib/shellcraft/generators/i386/linux/cat.rb +23 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/execve.rb +8 -4
- data/lib/pwnlib/shellcraft/generators/i386/linux/exit.rb +23 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/ls.rb +6 -2
- data/lib/pwnlib/shellcraft/generators/i386/linux/open.rb +23 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/sh.rb +6 -2
- data/lib/pwnlib/shellcraft/generators/i386/linux/syscall.rb +8 -4
- data/lib/pwnlib/shellcraft/generators/x86/linux/cat.rb +53 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/exit.rb +33 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/open.rb +46 -0
- data/lib/pwnlib/shellcraft/shellcraft.rb +3 -2
- data/lib/pwnlib/timer.rb +5 -2
- data/lib/pwnlib/tubes/process.rb +153 -0
- data/lib/pwnlib/tubes/serialtube.rb +112 -0
- data/lib/pwnlib/tubes/sock.rb +24 -25
- data/lib/pwnlib/tubes/tube.rb +191 -39
- data/lib/pwnlib/util/packing.rb +3 -9
- data/lib/pwnlib/version.rb +1 -1
- data/test/asm_test.rb +85 -2
- data/test/constants/constants_test.rb +2 -2
- data/test/data/echo.rb +2 -7
- data/test/elf/elf_test.rb +10 -15
- data/test/files/use_pwn.rb +2 -6
- data/test/logger_test.rb +38 -0
- data/test/shellcraft/linux/cat_test.rb +86 -0
- data/test/shellcraft/linux/syscalls/exit_test.rb +56 -0
- data/test/shellcraft/linux/syscalls/open_test.rb +86 -0
- data/test/shellcraft/shellcraft_test.rb +5 -4
- data/test/test_helper.rb +22 -2
- data/test/timer_test.rb +19 -1
- data/test/tubes/process_test.rb +99 -0
- data/test/tubes/serialtube_test.rb +165 -0
- data/test/tubes/sock_test.rb +20 -21
- data/test/tubes/tube_test.rb +86 -16
- metadata +75 -13
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
require 'pwnlib/shellcraft/generators/x86/common/pushstr'
|
4
|
+
require 'pwnlib/shellcraft/generators/x86/linux/linux'
|
5
|
+
require 'pwnlib/shellcraft/generators/x86/linux/syscall'
|
6
|
+
|
7
|
+
module Pwnlib
|
8
|
+
module Shellcraft
|
9
|
+
module Generators
|
10
|
+
module X86
|
11
|
+
module Linux
|
12
|
+
# Opens a file and writes its contents to the specified file descriptor.
|
13
|
+
#
|
14
|
+
# @param [String] filename
|
15
|
+
# The filename.
|
16
|
+
# @param [Integer] fd
|
17
|
+
# The file descriptor to write the file contents.
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
# context.arch = 'amd64'
|
21
|
+
# puts shellcraft.cat('/etc/passwd')
|
22
|
+
# # /* push "/etc/passwd\x00" */
|
23
|
+
# # push 0x1010101 ^ 0x647773
|
24
|
+
# # xor dword ptr [rsp], 0x1010101
|
25
|
+
# # mov rax, 0x7361702f6374652f
|
26
|
+
# # push rax
|
27
|
+
# # /* call open("rsp", 0, "O_RDONLY") */
|
28
|
+
# # push 2 /* (SYS_open) */
|
29
|
+
# # pop rax
|
30
|
+
# # mov rdi, rsp
|
31
|
+
# # xor esi, esi /* 0 */
|
32
|
+
# # cdq /* rdx=0 */
|
33
|
+
# # syscall
|
34
|
+
# # /* call sendfile(1, "rax", 0, 2147483647) */
|
35
|
+
# # push 1
|
36
|
+
# # pop rdi
|
37
|
+
# # mov rsi, rax
|
38
|
+
# # push 0x28 /* (SYS_sendfile) */
|
39
|
+
# # pop rax
|
40
|
+
# # mov r10d, 0x7fffffff
|
41
|
+
# # cdq /* rdx=0 */
|
42
|
+
# # syscall
|
43
|
+
# #=> nil
|
44
|
+
def cat(filename, fd: 1)
|
45
|
+
abi = ::Pwnlib::ABI::ABI.syscall
|
46
|
+
cat Linux.open(filename, 'O_RDONLY')
|
47
|
+
cat Linux.syscall('SYS_sendfile', fd, abi.register_arguments.first, 0, 0x7fffffff)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
require 'pwnlib/shellcraft/generators/x86/linux/linux'
|
4
|
+
|
5
|
+
module Pwnlib
|
6
|
+
module Shellcraft
|
7
|
+
module Generators
|
8
|
+
module X86
|
9
|
+
module Linux
|
10
|
+
# Exit syscall.
|
11
|
+
#
|
12
|
+
# @param [Integer] status
|
13
|
+
# Status code.
|
14
|
+
#
|
15
|
+
# @return [String]
|
16
|
+
# Assembly for invoking exit syscall.
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# puts shellcraft.exit(1)
|
20
|
+
# # /* call exit(1) */
|
21
|
+
# # push 1 /* (SYS_exit) */
|
22
|
+
# # pop eax
|
23
|
+
# # push 1
|
24
|
+
# # pop ebx
|
25
|
+
# # int 0x80
|
26
|
+
def exit(status = 0)
|
27
|
+
cat Linux.syscall('SYS_exit', status)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
require 'pwnlib/shellcraft/generators/x86/linux/linux'
|
4
|
+
|
5
|
+
module Pwnlib
|
6
|
+
module Shellcraft
|
7
|
+
module Generators
|
8
|
+
module X86
|
9
|
+
module Linux
|
10
|
+
# Push filename onto stack and perform open syscall.
|
11
|
+
#
|
12
|
+
# @param [String] filename
|
13
|
+
# The file to be opened.
|
14
|
+
# @param [String, Integer] flags
|
15
|
+
# Flags for opening a file.
|
16
|
+
# @param [Integer] mode
|
17
|
+
# If +filename+ doesn't exist and 'O_CREAT' is specified in +flags+,
|
18
|
+
# +mode+ will be used as the file permission for creating the file.
|
19
|
+
#
|
20
|
+
# @return [String]
|
21
|
+
# Assembly for syscall open.
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# puts shellcraft.open('/etc/passwd', 'O_RDONLY')
|
25
|
+
# # /* push "/etc/passwd\x00" */
|
26
|
+
# # push 0x1010101
|
27
|
+
# # xor dword ptr [esp], 0x1657672 /* 0x1010101 ^ 0x647773 */
|
28
|
+
# # push 0x7361702f
|
29
|
+
# # push 0x6374652f
|
30
|
+
# # /* call open("esp", "O_RDONLY", 0) */
|
31
|
+
# # push 5 /* (SYS_open) */
|
32
|
+
# # pop eax
|
33
|
+
# # mov ebx, esp
|
34
|
+
# # xor ecx, ecx /* (O_RDONLY) */
|
35
|
+
# # cdq /* edx=0 */
|
36
|
+
# # int 0x80
|
37
|
+
def open(filename, flags = 'O_RDONLY', mode = 0)
|
38
|
+
abi = ::Pwnlib::ABI::ABI.syscall
|
39
|
+
cat Common.pushstr(filename)
|
40
|
+
cat Linux.syscall('SYS_open', abi.stack_pointer, flags, mode)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'singleton'
|
4
4
|
|
5
5
|
require 'pwnlib/context'
|
6
|
+
require 'pwnlib/errors'
|
6
7
|
require 'pwnlib/logger'
|
7
8
|
|
8
9
|
module Pwnlib
|
@@ -48,8 +49,8 @@ module Pwnlib
|
|
48
49
|
begin
|
49
50
|
arch_module = ::Pwnlib::Shellcraft::Generators.const_get(context.arch.capitalize)
|
50
51
|
rescue NameError
|
51
|
-
|
52
|
-
|
52
|
+
raise ::Pwnlib::Errors::UnsupportedArchError,
|
53
|
+
"Can't use shellcraft under architecture #{context.arch.inspect}."
|
53
54
|
end
|
54
55
|
# try search in Common module
|
55
56
|
common_module = arch_module.const_get(:Common)
|
data/lib/pwnlib/timer.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'time'
|
4
4
|
|
5
5
|
require 'pwnlib/context'
|
6
|
+
require 'pwnlib/errors'
|
6
7
|
|
7
8
|
module Pwnlib
|
8
9
|
# A simple timer class.
|
@@ -27,7 +28,7 @@ module Pwnlib
|
|
27
28
|
end
|
28
29
|
|
29
30
|
def timeout
|
30
|
-
return @timeout || Pwnlib::Context.context.timeout unless started?
|
31
|
+
return @timeout || ::Pwnlib::Context.context.timeout unless started?
|
31
32
|
@deadline == :forever ? :forever : [@deadline - Time.now, 0].max
|
32
33
|
end
|
33
34
|
|
@@ -46,14 +47,16 @@ module Pwnlib
|
|
46
47
|
end
|
47
48
|
|
48
49
|
timeout ||= @timeout
|
49
|
-
timeout ||= Pwnlib::Context.context.timeout
|
50
|
+
timeout ||= ::Pwnlib::Context.context.timeout
|
50
51
|
|
51
52
|
@deadline = timeout == :forever ? :forever : Time.now + timeout
|
52
53
|
|
53
54
|
begin
|
54
55
|
yield
|
55
56
|
ensure
|
57
|
+
was_active = active?
|
56
58
|
@deadline = nil
|
59
|
+
raise ::Pwnlib::Errors::TimeoutError unless was_active
|
57
60
|
end
|
58
61
|
end
|
59
62
|
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
require 'pwnlib/errors'
|
4
|
+
require 'pwnlib/tubes/tube'
|
5
|
+
|
6
|
+
module Pwnlib
|
7
|
+
module Tubes
|
8
|
+
# Launch a process.
|
9
|
+
class Process < Tube
|
10
|
+
# Default options for {#initialize}.
|
11
|
+
DEFAULT_OPTIONS = {
|
12
|
+
env: ENV,
|
13
|
+
in: :pipe,
|
14
|
+
out: :pipe,
|
15
|
+
raw: true,
|
16
|
+
aslr: true
|
17
|
+
}.freeze
|
18
|
+
|
19
|
+
# Instantiate a {Pwnlib::Tubes::Process} object.
|
20
|
+
#
|
21
|
+
# @param [Array<String>, String] argv
|
22
|
+
# List of arguments to pass to the spawned process.
|
23
|
+
#
|
24
|
+
# @option opts [Hash{String => String}] env (ENV)
|
25
|
+
# Environment variables. By default, inherits from Ruby's environment.
|
26
|
+
# @option opts [Symbol] in (:pipe)
|
27
|
+
# What kind of io should be used for +stdin+.
|
28
|
+
# Candidates are: +:pipe+, +:pty+.
|
29
|
+
# @option opts [Symbol] out (:pipe)
|
30
|
+
# What kind of io should be used for +stdout+.
|
31
|
+
# Candidates are: +:pipe+, +:pty+.
|
32
|
+
# See examples for more details.
|
33
|
+
# @option opts [Boolean] raw (true)
|
34
|
+
# Set the created PTY to raw mode. i.e. disable echo and control characters.
|
35
|
+
# If no pty is created, this has no effect.
|
36
|
+
# @option opts [Boolean] aslr (true)
|
37
|
+
# If +false+ is given, the ASLR of the target process will be disabled via +setarch -R+.
|
38
|
+
# @option opts [Float?] timeout (nil)
|
39
|
+
# See {Pwnlib::Tubes::Tube#initialize}.
|
40
|
+
#
|
41
|
+
# @example
|
42
|
+
# io = Tubes::Process.new('ls')
|
43
|
+
# io.gets
|
44
|
+
# #=> "Gemfile\n"
|
45
|
+
#
|
46
|
+
# io = Tubes::Process.new('ls', out: :pty)
|
47
|
+
# io.gets
|
48
|
+
# #=> "Gemfile LICENSE\t\t\t README.md STYLE.md\t git-hooks pwntools.gemspec test\n"
|
49
|
+
# @example
|
50
|
+
# io = Tubes::Process.new('cat /proc/self/maps')
|
51
|
+
# io.gets
|
52
|
+
# #=> "55f8b8a10000-55f8b8a18000 r-xp 00000000 fd:00 9044035 /bin/cat\n"
|
53
|
+
# io.close
|
54
|
+
#
|
55
|
+
# io = Tubes::Process.new('cat /proc/self/maps', aslr: false)
|
56
|
+
# io.gets
|
57
|
+
# #=> "555555554000-55555555c000 r-xp 00000000 fd:00 9044035 /bin/cat\n"
|
58
|
+
# io.close
|
59
|
+
# @example
|
60
|
+
# io = Tubes::Process.new('env', env: { 'FOO' => 'BAR' })
|
61
|
+
# io.gets
|
62
|
+
# #=> "FOO=BAR\n"
|
63
|
+
def initialize(argv, **opts)
|
64
|
+
opts = DEFAULT_OPTIONS.merge(opts)
|
65
|
+
super(timeout: opts[:timeout])
|
66
|
+
argv = normalize_argv(argv, opts)
|
67
|
+
slave_i, slave_o = create_pipe(opts)
|
68
|
+
@pid = ::Process.spawn(opts[:env], *argv, in: slave_i, out: slave_o, unsetenv_others: true)
|
69
|
+
slave_i.close
|
70
|
+
slave_o.close unless slave_i == slave_o
|
71
|
+
end
|
72
|
+
|
73
|
+
# Close the IO.
|
74
|
+
#
|
75
|
+
# @param [:both, :recv, :read, :send, :write] direction
|
76
|
+
# Disallow further read/write of the process.
|
77
|
+
#
|
78
|
+
# @return [void]
|
79
|
+
def shutdown(direction = :both)
|
80
|
+
close_io(normalize_direction(direction))
|
81
|
+
end
|
82
|
+
|
83
|
+
# Kill the process.
|
84
|
+
#
|
85
|
+
# @return [void]
|
86
|
+
def kill
|
87
|
+
shutdown
|
88
|
+
::Process.kill('KILL', @pid)
|
89
|
+
::Process.wait(@pid)
|
90
|
+
end
|
91
|
+
alias close kill
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def io_out
|
96
|
+
@o
|
97
|
+
end
|
98
|
+
|
99
|
+
def close_io(dirs)
|
100
|
+
@o.close if dirs.include?(:read) && !@o.closed?
|
101
|
+
@i.close if dirs.include?(:write) && !@i.closed?
|
102
|
+
end
|
103
|
+
|
104
|
+
def normalize_argv(argv, opts)
|
105
|
+
# XXX(david942j): Set personality on child process will be better than using setarch
|
106
|
+
pre_cmd = opts[:aslr] ? '' : "setarch #{`uname -m`.strip} -R "
|
107
|
+
pre_cmd = pre_cmd.split if argv.is_a?(Array)
|
108
|
+
Array(pre_cmd + argv)
|
109
|
+
end
|
110
|
+
|
111
|
+
def create_pipe(opts)
|
112
|
+
if [opts[:in], opts[:out]].include?(:pty)
|
113
|
+
# Require only when we need it.
|
114
|
+
# This prevents broken on Windows, which has no pty support.
|
115
|
+
require 'io/console'
|
116
|
+
require 'pty'
|
117
|
+
mpty, spty = PTY.open
|
118
|
+
mpty.raw! if opts[:raw]
|
119
|
+
end
|
120
|
+
@o, slave_o = pipe(opts[:out], mpty, spty)
|
121
|
+
slave_i, @i = pipe(opts[:in], spty, mpty)
|
122
|
+
[slave_i, slave_o]
|
123
|
+
end
|
124
|
+
|
125
|
+
# @return [(IO, IO)]
|
126
|
+
# IO pair.
|
127
|
+
def pipe(type, mst, slv)
|
128
|
+
case type
|
129
|
+
when :pipe then IO.pipe
|
130
|
+
when :pty then [mst, slv]
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def send_raw(data)
|
135
|
+
@i.write(data)
|
136
|
+
rescue Errno::EIO, Errno::EPIPE, IOError
|
137
|
+
raise ::Pwnlib::Errors::EndOfTubeError
|
138
|
+
end
|
139
|
+
|
140
|
+
def recv_raw(size)
|
141
|
+
o, = IO.select([@o], [], [], @timeout)
|
142
|
+
return if o.nil?
|
143
|
+
@o.readpartial(size)
|
144
|
+
rescue Errno::EIO, Errno::EPIPE, IOError
|
145
|
+
raise ::Pwnlib::Errors::EndOfTubeError
|
146
|
+
end
|
147
|
+
|
148
|
+
def timeout_raw=(timeout)
|
149
|
+
@timeout = timeout
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
require 'rubyserial'
|
4
|
+
|
5
|
+
require 'pwnlib/tubes/tube'
|
6
|
+
|
7
|
+
module Pwnlib
|
8
|
+
module Tubes
|
9
|
+
# @!macro [new] raise_eof
|
10
|
+
# @raise [Pwnlib::Errors::EndOfTubeError]
|
11
|
+
# If the request is not satisfied when all data is received.
|
12
|
+
|
13
|
+
# Serial Connections
|
14
|
+
class SerialTube < Tube
|
15
|
+
# Instantiate a {Pwnlib::Tubes::SerialTube} object.
|
16
|
+
#
|
17
|
+
# @param [String] port
|
18
|
+
# A device name for rubyserial to open, e.g. /dev/ttypUSB0
|
19
|
+
# @param [Integer] baudrate
|
20
|
+
# Baud rate.
|
21
|
+
# @param [Boolean] convert_newlines
|
22
|
+
# If +true+, convert any +context.newline+s to +"\\r\\n"+ before
|
23
|
+
# sending to remote. Has no effect on bytes received.
|
24
|
+
# @param [Integer] bytesize
|
25
|
+
# Serial character byte size. The '8' in '8N1'.
|
26
|
+
# @param [Symbol] parity
|
27
|
+
# Serial character parity. The 'N' in '8N1'.
|
28
|
+
def initialize(port = nil, baudrate: 115_200,
|
29
|
+
convert_newlines: true,
|
30
|
+
bytesize: 8, parity: :none)
|
31
|
+
super()
|
32
|
+
|
33
|
+
# go hunting for a port
|
34
|
+
port ||= Dir.glob('/dev/tty.usbserial*').first
|
35
|
+
port ||= '/dev/ttyUSB0'
|
36
|
+
|
37
|
+
@convert_newlines = convert_newlines
|
38
|
+
@conn = Serial.new(port, baudrate, bytesize, parity)
|
39
|
+
@serial_timer = Timer.new
|
40
|
+
end
|
41
|
+
|
42
|
+
# Closes the active connection
|
43
|
+
def close
|
44
|
+
@conn.close if @conn && !@conn.closed?
|
45
|
+
@conn = nil
|
46
|
+
end
|
47
|
+
|
48
|
+
# Implementation of the methods required for tube
|
49
|
+
private
|
50
|
+
|
51
|
+
# Gets bytes over the serial connection until some bytes are received, or
|
52
|
+
# +@timeout+ has passed. It is an error for it to return no data in less
|
53
|
+
# than +@timeout+ seconds. It is ok for it to return some data in less
|
54
|
+
# time.
|
55
|
+
#
|
56
|
+
# @param [Integer] numbytes
|
57
|
+
# An upper limit on the number of bytes to get.
|
58
|
+
#
|
59
|
+
# @return [String]
|
60
|
+
# A string containing read bytes.
|
61
|
+
#
|
62
|
+
# @!macro raise_eof
|
63
|
+
def recv_raw(numbytes)
|
64
|
+
raise ::Pwnlib::Errors::EndOfTubeError if @conn.nil?
|
65
|
+
|
66
|
+
@serial_timer.countdown do
|
67
|
+
data = ''
|
68
|
+
begin
|
69
|
+
while @serial_timer.active?
|
70
|
+
data += @conn.read(numbytes - data.length)
|
71
|
+
break unless data.empty?
|
72
|
+
sleep 0.1
|
73
|
+
end
|
74
|
+
# XXX(JonathanBeverley): should we reverse @convert_newlines here?
|
75
|
+
return data
|
76
|
+
rescue RubySerial::Error
|
77
|
+
close
|
78
|
+
raise ::Pwnlib::Errors::EndOfTubeError
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Sends bytes over the serial connection. This call will block until all the bytes are sent or an error occurs.
|
84
|
+
#
|
85
|
+
# @param [String] data
|
86
|
+
# A string of the bytes to send.
|
87
|
+
#
|
88
|
+
# @return [Integer]
|
89
|
+
# The number of bytes successfully written.
|
90
|
+
#
|
91
|
+
# @!macro raise_eof
|
92
|
+
def send_raw(data)
|
93
|
+
raise ::Pwnlib::Errors::EndOfTubeError if @conn.nil?
|
94
|
+
|
95
|
+
data.gsub!(context.newline, "\r\n") if @convert_newlines
|
96
|
+
begin
|
97
|
+
return @conn.write(data)
|
98
|
+
rescue RubySerial::Error
|
99
|
+
close
|
100
|
+
raise ::Pwnlib::Errors::EndOfTubeError
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Sets the +timeout+ to use for subsequent +recv_raw+ calls.
|
105
|
+
#
|
106
|
+
# @param [Float] timeout
|
107
|
+
def timeout_raw=(timeout)
|
108
|
+
@serial_timer.timeout = timeout
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|