pwntools 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +88 -11
- data/Rakefile +5 -1
- data/lib/pwn.rb +9 -7
- data/lib/pwnlib/abi.rb +60 -0
- data/lib/pwnlib/asm.rb +146 -0
- data/lib/pwnlib/constants/constant.rb +16 -2
- data/lib/pwnlib/constants/constants.rb +35 -19
- data/lib/pwnlib/constants/linux/amd64.rb +30 -1
- data/lib/pwnlib/context.rb +25 -17
- data/lib/pwnlib/dynelf.rb +117 -54
- data/lib/pwnlib/elf/elf.rb +267 -0
- data/lib/pwnlib/ext/helper.rb +4 -4
- data/lib/pwnlib/logger.rb +87 -0
- data/lib/pwnlib/memleak.rb +58 -29
- data/lib/pwnlib/pwn.rb +19 -8
- data/lib/pwnlib/reg_sort.rb +102 -108
- data/lib/pwnlib/shellcraft/generators/amd64/common/common.rb +14 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/infloop.rb +17 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/memcpy.rb +31 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/mov.rb +127 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/nop.rb +16 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/popad.rb +27 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr.rb +64 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr_array.rb +19 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/ret.rb +32 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/setregs.rb +19 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/execve.rb +21 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/linux.rb +14 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/ls.rb +19 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/sh.rb +19 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/syscall.rb +21 -0
- data/lib/pwnlib/shellcraft/generators/helper.rb +106 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/common.rb +14 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/infloop.rb +17 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/mov.rb +90 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/nop.rb +16 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/pushstr.rb +39 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/pushstr_array.rb +19 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/setregs.rb +19 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/execve.rb +19 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/linux.rb +14 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/ls.rb +19 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/sh.rb +19 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/syscall.rb +19 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/common.rb +26 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/infloop.rb +22 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/mov.rb +15 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/pushstr.rb +15 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/pushstr_array.rb +85 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/setregs.rb +82 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/execve.rb +69 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/linux.rb +14 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/ls.rb +66 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/sh.rb +52 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/syscall.rb +52 -0
- data/lib/pwnlib/shellcraft/registers.rb +145 -0
- data/lib/pwnlib/shellcraft/shellcraft.rb +67 -0
- data/lib/pwnlib/timer.rb +60 -0
- data/lib/pwnlib/tubes/buffer.rb +96 -0
- data/lib/pwnlib/tubes/sock.rb +95 -0
- data/lib/pwnlib/tubes/tube.rb +270 -0
- data/lib/pwnlib/util/cyclic.rb +95 -94
- data/lib/pwnlib/util/fiddling.rb +256 -220
- data/lib/pwnlib/util/getdents.rb +83 -0
- data/lib/pwnlib/util/hexdump.rb +109 -108
- data/lib/pwnlib/util/lists.rb +55 -0
- data/lib/pwnlib/util/packing.rb +226 -228
- data/lib/pwnlib/util/ruby.rb +18 -0
- data/lib/pwnlib/version.rb +2 -1
- data/test/abi_test.rb +21 -0
- data/test/asm_test.rb +104 -0
- data/test/constants/constant_test.rb +1 -0
- data/test/constants/constants_test.rb +4 -2
- data/test/context_test.rb +1 -0
- data/test/data/echo.rb +20 -0
- data/test/data/elfs/Makefile +22 -0
- data/test/data/elfs/amd64.frelro.elf +0 -0
- data/test/data/elfs/amd64.frelro.pie.elf +0 -0
- data/test/data/elfs/amd64.nrelro.elf +0 -0
- data/test/data/elfs/amd64.prelro.elf +0 -0
- data/test/data/elfs/i386.frelro.pie.elf +0 -0
- data/test/data/elfs/i386.prelro.elf +0 -0
- data/test/data/elfs/source.cpp +19 -0
- data/test/data/flag +1 -0
- data/test/data/lib32/ld.so.2 +0 -0
- data/test/data/lib32/libc.so.6 +0 -0
- data/test/data/lib64/ld.so.2 +0 -0
- data/test/data/lib64/libc.so.6 +0 -0
- data/test/dynelf_test.rb +59 -24
- data/test/elf/elf_test.rb +120 -0
- data/test/ext_test.rb +3 -2
- data/test/files/use_pwnlib.rb +1 -1
- data/test/logger_test.rb +61 -0
- data/test/memleak_test.rb +4 -33
- data/test/reg_sort_test.rb +3 -1
- data/test/shellcraft/infloop_test.rb +26 -0
- data/test/shellcraft/linux/ls_test.rb +108 -0
- data/test/shellcraft/linux/sh_test.rb +119 -0
- data/test/shellcraft/linux/syscalls/execve_test.rb +136 -0
- data/test/shellcraft/linux/syscalls/syscall_test.rb +83 -0
- data/test/shellcraft/memcpy_test.rb +35 -0
- data/test/shellcraft/mov_test.rb +98 -0
- data/test/shellcraft/nop_test.rb +26 -0
- data/test/shellcraft/popad_test.rb +29 -0
- data/test/shellcraft/pushstr_array_test.rb +91 -0
- data/test/shellcraft/pushstr_test.rb +108 -0
- data/test/shellcraft/registers_test.rb +32 -0
- data/test/shellcraft/ret_test.rb +30 -0
- data/test/shellcraft/setregs_test.rb +62 -0
- data/test/shellcraft/shellcraft_test.rb +28 -0
- data/test/test_helper.rb +12 -1
- data/test/timer_test.rb +23 -0
- data/test/tubes/buffer_test.rb +45 -0
- data/test/tubes/sock_test.rb +68 -0
- data/test/tubes/tube_test.rb +241 -0
- data/test/util/cyclic_test.rb +2 -1
- data/test/util/fiddling_test.rb +2 -1
- data/test/util/getdents_test.rb +32 -0
- data/test/util/hexdump_test.rb +7 -9
- data/test/util/lists_test.rb +21 -0
- data/test/util/packing_test.rb +4 -3
- metadata +215 -25
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
require 'pwnlib/shellcraft/registers'
|
6
|
+
|
7
|
+
class RegistersTest < MiniTest::Test
|
8
|
+
include ::Pwnlib::Shellcraft::Registers
|
9
|
+
|
10
|
+
def test_get_register
|
11
|
+
assert_instance_of(::Pwnlib::Shellcraft::Registers::Register, get_register('rdi'))
|
12
|
+
assert_nil(get_register('meow'))
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_regtsiter?
|
16
|
+
assert_equal(true, register?(:ax))
|
17
|
+
assert_equal(true, register?('ax'))
|
18
|
+
assert_equal(true, register?('r8'))
|
19
|
+
assert_equal(true, register?('r15b'))
|
20
|
+
assert_equal(true, register?('r15w'))
|
21
|
+
assert_equal(false, register?('xdd'))
|
22
|
+
assert_equal(false, register?(''))
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_register
|
26
|
+
assert_equal(8, get_register('rdi').bytes)
|
27
|
+
assert_equal(16, get_register('ax').bits)
|
28
|
+
assert_equal('r10d', get_register('r10d').name)
|
29
|
+
assert_equal('r10d', get_register('r10d').to_s)
|
30
|
+
assert_equal('Register(r10d)', get_register('r10d').inspect)
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
require 'pwnlib/context'
|
6
|
+
require 'pwnlib/shellcraft/shellcraft'
|
7
|
+
|
8
|
+
class RetTest < MiniTest::Test
|
9
|
+
include ::Pwnlib::Context
|
10
|
+
|
11
|
+
def setup
|
12
|
+
@shellcraft = ::Pwnlib::Shellcraft::Shellcraft.instance
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_amd64
|
16
|
+
context.local(arch: 'amd64') do
|
17
|
+
assert_equal(" ret\n", @shellcraft.ret)
|
18
|
+
assert_equal(" mov rax, rdi\n ret\n", @shellcraft.ret(:rdi))
|
19
|
+
assert_equal(" xor eax, eax /* 0 */\n ret\n", @shellcraft.ret(0))
|
20
|
+
assert_equal(<<-'EOS', @shellcraft.ret(0x100000000))
|
21
|
+
mov rax, 0x101010201010101
|
22
|
+
push rax
|
23
|
+
mov rax, 0x101010301010101
|
24
|
+
xor [rsp], rax /* 0x100000000 == 0x101010201010101 ^ 0x101010301010101 */
|
25
|
+
pop rax
|
26
|
+
ret
|
27
|
+
EOS
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
require 'pwnlib/context'
|
6
|
+
require 'pwnlib/shellcraft/shellcraft'
|
7
|
+
|
8
|
+
class SetregsTest < MiniTest::Test
|
9
|
+
include ::Pwnlib::Context
|
10
|
+
|
11
|
+
def setup
|
12
|
+
@shellcraft = ::Pwnlib::Shellcraft::Shellcraft.instance
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_amd64
|
16
|
+
context.local(arch: 'amd64') do
|
17
|
+
assert_equal(<<-'EOS', @shellcraft.setregs(rax: 1, rbx: 'rax'))
|
18
|
+
mov rbx, rax
|
19
|
+
push 1
|
20
|
+
pop rax
|
21
|
+
EOS
|
22
|
+
assert_equal(<<-'EOS', @shellcraft.setregs(rax: 'SYS_write', rbx: 'rax'))
|
23
|
+
mov rbx, rax
|
24
|
+
push 1 /* (SYS_write) */
|
25
|
+
pop rax
|
26
|
+
EOS
|
27
|
+
assert_equal(<<-'EOS', @shellcraft.setregs(rax: 'rbx', rbx: 'rax', rcx: 'rbx'))
|
28
|
+
mov rcx, rbx
|
29
|
+
xchg rax, rbx
|
30
|
+
EOS
|
31
|
+
assert_equal(<<-'EOS', @shellcraft.setregs(rax: 1, rdx: 0))
|
32
|
+
push 1
|
33
|
+
pop rax
|
34
|
+
cdq /* rdx=0 */
|
35
|
+
EOS
|
36
|
+
# issue #50
|
37
|
+
assert_equal(<<-'EOS', @shellcraft.setregs(rdi: :rax, rsi: :rdi))
|
38
|
+
mov rsi, rdi
|
39
|
+
mov rdi, rax
|
40
|
+
EOS
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_i386
|
45
|
+
context.local(arch: 'i386') do
|
46
|
+
assert_equal(<<-EOS, @shellcraft.setregs(eax: 1, ebx: 'eax'))
|
47
|
+
mov ebx, eax
|
48
|
+
push 1
|
49
|
+
pop eax
|
50
|
+
EOS
|
51
|
+
assert_equal(<<-EOS, @shellcraft.setregs(eax: 'ebx', ebx: 'eax', ecx: 'ebx'))
|
52
|
+
mov ecx, ebx
|
53
|
+
xchg eax, ebx
|
54
|
+
EOS
|
55
|
+
assert_equal(<<-'EOS', @shellcraft.setregs(eax: 1, edx: 0))
|
56
|
+
push 1
|
57
|
+
pop eax
|
58
|
+
cdq /* edx=0 */
|
59
|
+
EOS
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
require 'pwnlib/context'
|
6
|
+
require 'pwnlib/shellcraft/shellcraft'
|
7
|
+
|
8
|
+
class ShellcraftTest < MiniTest::Test
|
9
|
+
include ::Pwnlib::Context
|
10
|
+
|
11
|
+
def setup
|
12
|
+
@shellcraft = ::Pwnlib::Shellcraft::Shellcraft.instance
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_respond
|
16
|
+
context.local(arch: 'amd64') do
|
17
|
+
# Check respond_to_missing? is well defined
|
18
|
+
assert @shellcraft.respond_to?(:mov)
|
19
|
+
assert @shellcraft.method(:sh)
|
20
|
+
end
|
21
|
+
refute @shellcraft.respond_to?(:linux)
|
22
|
+
assert_raises(NoMethodError) { @shellcraft.meow }
|
23
|
+
|
24
|
+
context.local(arch: 'arm') do
|
25
|
+
refute @shellcraft.respond_to?(:mov)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'codeclimate-test-reporter'
|
2
|
-
|
2
|
+
require 'rainbow'
|
3
3
|
require 'simplecov'
|
4
|
+
|
4
5
|
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
|
5
6
|
[SimpleCov::Formatter::HTMLFormatter, CodeClimate::TestReporter::Formatter]
|
6
7
|
)
|
@@ -11,3 +12,13 @@ end
|
|
11
12
|
require 'minitest/autorun'
|
12
13
|
require 'minitest/unit'
|
13
14
|
require 'minitest/hell'
|
15
|
+
|
16
|
+
module MiniTest
|
17
|
+
class Test
|
18
|
+
def before_setup
|
19
|
+
super
|
20
|
+
# Default to disable coloring for easier testing.
|
21
|
+
Rainbow.enabled = false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/test/timer_test.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
require 'pwnlib/timer'
|
6
|
+
|
7
|
+
class TimerTest < MiniTest::Test
|
8
|
+
include ::Pwnlib
|
9
|
+
|
10
|
+
def test_countdown
|
11
|
+
t = Timer.new
|
12
|
+
refute(t.started?)
|
13
|
+
refute(t.active?)
|
14
|
+
assert_equal('DARKHH QQ', t.countdown(0.1) { 'DARKHH QQ' })
|
15
|
+
exception = assert_raises(RuntimeError) { t.countdown(0.1) { t.countdown(0.1) {} } }
|
16
|
+
assert_equal('Nested countdown not permitted', exception.message)
|
17
|
+
t.timeout = 0.514
|
18
|
+
exception = assert_raises(RuntimeError) { t.countdown(0.1) { t.timeout = :forever } }
|
19
|
+
assert_equal("Can't change timeout when countdown", exception.message)
|
20
|
+
t.countdown(0.1) { assert(t.started?) }
|
21
|
+
t.countdown(0.1) { assert(t.active?) }
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
require 'pwnlib/tubes/buffer'
|
6
|
+
|
7
|
+
class BufferTest < MiniTest::Test
|
8
|
+
def test_add
|
9
|
+
b = ::Pwnlib::Tubes::Buffer.new
|
10
|
+
b.add('A' * 10)
|
11
|
+
b.add('B' * 10)
|
12
|
+
assert_equal(20, b.size)
|
13
|
+
assert_equal('A', b.get(1))
|
14
|
+
assert_equal(19, b.size)
|
15
|
+
assert_equal(false, b.empty?)
|
16
|
+
assert_equal('AAAAAAAAABBBBBBBBBB', b.get(9999))
|
17
|
+
assert_equal(0, b.size)
|
18
|
+
assert_equal(true, b.empty?)
|
19
|
+
assert_equal('', b.get(1))
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_unget
|
23
|
+
b = ::Pwnlib::Tubes::Buffer.new
|
24
|
+
b.add('hello')
|
25
|
+
b.add('world')
|
26
|
+
assert_equal('hello', b.get(5))
|
27
|
+
b.unget('goodbye')
|
28
|
+
assert_equal('goodbyeworld', b.get)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_buffer
|
32
|
+
b = ::Pwnlib::Tubes::Buffer.new
|
33
|
+
b2 = ::Pwnlib::Tubes::Buffer.new
|
34
|
+
b.add('hello')
|
35
|
+
b2.add('world')
|
36
|
+
b.add(b2)
|
37
|
+
assert_equal('hello', b.get(5))
|
38
|
+
assert_equal(false, b2.empty?)
|
39
|
+
assert_equal('world', b2.get)
|
40
|
+
b2.add('goodbye')
|
41
|
+
b.unget(b2)
|
42
|
+
assert_equal('goodbyeworld', b.get)
|
43
|
+
assert_equal('goodbye', b2.get)
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
require 'open3'
|
4
|
+
|
5
|
+
require 'test_helper'
|
6
|
+
|
7
|
+
require 'pwnlib/tubes/sock'
|
8
|
+
|
9
|
+
class SockTest < MiniTest::Test
|
10
|
+
include ::Pwnlib::Tubes
|
11
|
+
ECHO_FILE = File.expand_path('../data/echo.rb', __dir__)
|
12
|
+
BIND_PORT = 31_337
|
13
|
+
|
14
|
+
def popen_echo(data)
|
15
|
+
Open3.popen2("bundle exec ruby #{ECHO_FILE} #{BIND_PORT}") do |_i, o, _t|
|
16
|
+
o.gets
|
17
|
+
s = Sock.new('localhost', BIND_PORT)
|
18
|
+
yield s, data, o
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_io
|
23
|
+
popen_echo('DARKHH') do |s, data, _o|
|
24
|
+
s.io.puts(data)
|
25
|
+
rs, = IO.select([s.io])
|
26
|
+
refute_nil(rs)
|
27
|
+
assert_equal(data, s.io.readpartial(data.size))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_sock
|
32
|
+
popen_echo('DARKHH') do |s, data, o|
|
33
|
+
s.puts(data)
|
34
|
+
assert_equal(data + "\n", s.gets)
|
35
|
+
o.gets
|
36
|
+
s.puts(514)
|
37
|
+
sleep(0.1) # Wait for connection reset
|
38
|
+
assert_raises(EOFError) { s.puts(514) }
|
39
|
+
assert_raises(EOFError) { s.puts(514) }
|
40
|
+
assert_raises(EOFError) { s.recv }
|
41
|
+
assert_raises(EOFError) { s.recv }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_close
|
46
|
+
popen_echo('DARKHH') do |s, _data, _o|
|
47
|
+
s.close
|
48
|
+
assert_raises(EOFError) { s.puts(514) }
|
49
|
+
assert_raises(EOFError) { s.puts(514) }
|
50
|
+
assert_raises(EOFError) { s.recv }
|
51
|
+
assert_raises(EOFError) { s.recv }
|
52
|
+
assert_raises(ArgumentError) { s.close(:hh) }
|
53
|
+
end
|
54
|
+
|
55
|
+
popen_echo('DARKHH') do |s, _data, _o|
|
56
|
+
3.times { s.close(:read) }
|
57
|
+
3.times { s.close(:recv) }
|
58
|
+
3.times { s.close(:send) }
|
59
|
+
3.times { s.close(:write) }
|
60
|
+
assert_raises(EOFError) { s.puts(514) }
|
61
|
+
assert_raises(EOFError) { s.puts(514) }
|
62
|
+
assert_raises(EOFError) { s.recv }
|
63
|
+
assert_raises(EOFError) { s.recv }
|
64
|
+
3.times { s.close }
|
65
|
+
assert_raises(ArgumentError) { s.close(:shik) }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,241 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# This test use UTF-8 encoding for strings since the output for hexdump contains lots of UTF-8 characters.
|
4
|
+
|
5
|
+
require 'test_helper'
|
6
|
+
|
7
|
+
require 'pwnlib/context'
|
8
|
+
require 'pwnlib/logger'
|
9
|
+
require 'pwnlib/tubes/tube'
|
10
|
+
|
11
|
+
class TubeTest < MiniTest::Test
|
12
|
+
include ::Pwnlib::Context
|
13
|
+
include ::Pwnlib::Tubes
|
14
|
+
|
15
|
+
def setup
|
16
|
+
@old_log = ::Pwnlib::Logger.log.dup
|
17
|
+
@log = ::Pwnlib::Logger::LoggerType.new
|
18
|
+
|
19
|
+
class << @log
|
20
|
+
def clear
|
21
|
+
@logdev = StringIO.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def string
|
25
|
+
@logdev.string
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
::Pwnlib::Logger.instance_variable_set(:@log, @log)
|
30
|
+
end
|
31
|
+
|
32
|
+
def hello_tube
|
33
|
+
t = Tube.new
|
34
|
+
|
35
|
+
class << t
|
36
|
+
def buf
|
37
|
+
@buf ||= ''
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def recv_raw(_n)
|
43
|
+
'Hello, world'
|
44
|
+
end
|
45
|
+
|
46
|
+
def timeout_raw=(timeout)
|
47
|
+
@timeout = timeout == :forever ? nil : timeout
|
48
|
+
end
|
49
|
+
|
50
|
+
def send_raw(data)
|
51
|
+
buf << data
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
t
|
56
|
+
end
|
57
|
+
|
58
|
+
def basic_tube
|
59
|
+
t = Tube.new
|
60
|
+
|
61
|
+
class << t
|
62
|
+
def recv_raw(_n)
|
63
|
+
raise EOFError if io.eof?
|
64
|
+
io.read
|
65
|
+
end
|
66
|
+
|
67
|
+
def send_raw(data)
|
68
|
+
io.write(data)
|
69
|
+
end
|
70
|
+
|
71
|
+
def timeout_raw=(timeout)
|
72
|
+
@timeout = timeout == :forever ? nil : timeout
|
73
|
+
end
|
74
|
+
|
75
|
+
def io
|
76
|
+
@fakeio ||= Tempfile.new('pwntools_ruby_test')
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
t
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_recv
|
84
|
+
t = hello_tube
|
85
|
+
assert_equal('Hello, world', t.recv)
|
86
|
+
assert_equal('Hello, world', t.recv)
|
87
|
+
t.unrecv('Woohoo')
|
88
|
+
assert_equal('Woohoo', t.recv)
|
89
|
+
assert_equal('Hello, world', t.recv)
|
90
|
+
assert_equal('H', t.recvn(1))
|
91
|
+
assert_equal('ello, w', t.recvn(7))
|
92
|
+
assert_equal('orldH', t.recvn(5))
|
93
|
+
assert_equal('ello, world', t.recv)
|
94
|
+
|
95
|
+
context.local(log_level: 'debug') do
|
96
|
+
@log.clear
|
97
|
+
t = hello_tube
|
98
|
+
assert_equal('Hello, world', t.recv)
|
99
|
+
assert_equal(<<-'EOS', @log.string.encode('UTF-8'))
|
100
|
+
[DEBUG] Received 0xc bytes:
|
101
|
+
00000000 48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 │Hell│o, w│orld│
|
102
|
+
0000000c
|
103
|
+
EOS
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_recvuntil
|
108
|
+
t = hello_tube
|
109
|
+
assert_equal('Hello, ', t.recvuntil(' '))
|
110
|
+
assert_equal('worldHello, ', t.recvuntil(' '))
|
111
|
+
t.unrecv('Hello, world!')
|
112
|
+
assert_equal('Hello,', t.recvuntil(' wor', drop: true))
|
113
|
+
assert_equal('', t.recvuntil('DARKHH', drop: true, timeout: 0.1))
|
114
|
+
|
115
|
+
t = basic_tube
|
116
|
+
t.unrecv('meow')
|
117
|
+
assert_equal('', t.recvuntil('DARKHH'))
|
118
|
+
assert_equal('meow', t.recv)
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_recvline
|
122
|
+
t = Tube.new
|
123
|
+
t.unrecv("Foo\nBar\r\nBaz\n")
|
124
|
+
assert_equal("Foo\n", t.recvline)
|
125
|
+
assert_equal("Bar\r\n", t.recvline)
|
126
|
+
assert_equal('Baz', t.recvline(drop: true))
|
127
|
+
context.local(newline: "\r\n") do
|
128
|
+
t = Tube.new
|
129
|
+
t.unrecv("Foo\nBar\r\nBaz\n")
|
130
|
+
assert_equal("Foo\nBar", t.recvline(drop: true))
|
131
|
+
end
|
132
|
+
|
133
|
+
t = basic_tube
|
134
|
+
t.unrecv('Hello, world')
|
135
|
+
assert_equal('', t.recvline)
|
136
|
+
assert_equal('Hello, world', t.recv)
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_recvpred
|
140
|
+
t = hello_tube
|
141
|
+
r = /H.*w/
|
142
|
+
10.times { assert_match(r, t.recvpred { |data| data =~ r }) }
|
143
|
+
r = /H.*W/
|
144
|
+
assert_match('', t.recvpred(timeout: 0.01) { |data| data =~ r })
|
145
|
+
t = basic_tube
|
146
|
+
t.unrecv('darkhh')
|
147
|
+
assert_match('', t.recvpred { |data| data =~ r })
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_recvregex
|
151
|
+
t = hello_tube
|
152
|
+
r = /[aeiou]/
|
153
|
+
5.times { assert_match(r, t.recvregex(r)) }
|
154
|
+
r = /[wl][aeiou]/
|
155
|
+
5.times { assert_match(r, t.recvregex(r)) }
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_send
|
159
|
+
t = hello_tube
|
160
|
+
t.write('DARKHH')
|
161
|
+
assert_equal('DARKHH', t.buf)
|
162
|
+
t.write(' QQ')
|
163
|
+
assert_equal('DARKHH QQ', t.buf)
|
164
|
+
t.write(333)
|
165
|
+
assert_equal('DARKHH QQ333', t.buf)
|
166
|
+
|
167
|
+
context.local(log_level: 'debug') do
|
168
|
+
@log.clear
|
169
|
+
data = (0..40).map(&:chr).join
|
170
|
+
t = hello_tube
|
171
|
+
t.write(data)
|
172
|
+
assert_equal(data, t.buf)
|
173
|
+
assert_equal(<<-'EOS', @log.string.encode('UTF-8'))
|
174
|
+
[DEBUG] Sent 0x29 bytes:
|
175
|
+
00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f │····│····│····│····│
|
176
|
+
00000010 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f │····│····│····│····│
|
177
|
+
00000020 20 21 22 23 24 25 26 27 28 │ !"#│$%&'│(│
|
178
|
+
00000029
|
179
|
+
EOS
|
180
|
+
|
181
|
+
@log.clear
|
182
|
+
t.puts('meow')
|
183
|
+
assert_equal(<<-'EOS', @log.string.encode('UTF-8'))
|
184
|
+
[DEBUG] Sent 0x5 bytes:
|
185
|
+
00000000 6d 65 6f 77 0a │meow│·│
|
186
|
+
00000005
|
187
|
+
EOS
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def test_sendline
|
192
|
+
t = hello_tube
|
193
|
+
t.write('DARKHH')
|
194
|
+
assert_equal('DARKHH', t.buf)
|
195
|
+
t.puts(' QQ')
|
196
|
+
assert_equal("DARKHH QQ\n", t.buf)
|
197
|
+
end
|
198
|
+
|
199
|
+
FLAG_FILE = File.expand_path('../data/flag', __dir__)
|
200
|
+
def test_interact_send
|
201
|
+
save_stdin = $stdin.dup
|
202
|
+
$stdin = File.new(FLAG_FILE, File::RDONLY)
|
203
|
+
@log.clear
|
204
|
+
begin
|
205
|
+
t = basic_tube
|
206
|
+
t.interact
|
207
|
+
rescue EOFError
|
208
|
+
t.io.rewind
|
209
|
+
assert_equal(IO.binread(FLAG_FILE), t.io.read)
|
210
|
+
end
|
211
|
+
assert_equal("[INFO] Switching to interactive mode\n", @log.string)
|
212
|
+
$stdin.close
|
213
|
+
t.io.close
|
214
|
+
$stdin = save_stdin
|
215
|
+
end
|
216
|
+
|
217
|
+
def test_interact_recv
|
218
|
+
save_stdin = $stdin.dup
|
219
|
+
save_stdout = $stdout.dup
|
220
|
+
$stdin = UDPSocket.new
|
221
|
+
$stdout = Tempfile.new('pwntools_ruby_test')
|
222
|
+
@log.clear
|
223
|
+
begin
|
224
|
+
t = basic_tube
|
225
|
+
t.instance_variable_set(:@fakeio, File.new(FLAG_FILE, File::RDONLY))
|
226
|
+
t.interact
|
227
|
+
rescue EOFError
|
228
|
+
$stdout.rewind
|
229
|
+
assert_equal(IO.binread(FLAG_FILE), $stdout.read)
|
230
|
+
end
|
231
|
+
assert_equal("[INFO] Switching to interactive mode\n", @log.string)
|
232
|
+
$stdout.close
|
233
|
+
t.io.close
|
234
|
+
$stdin = save_stdin
|
235
|
+
$stdout = save_stdout
|
236
|
+
end
|
237
|
+
|
238
|
+
def teardown
|
239
|
+
::Pwnlib::Logger.instance_variable_set(:@log, @old_log)
|
240
|
+
end
|
241
|
+
end
|