pwntools 0.1.0 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +96 -15
- data/Rakefile +8 -2
- data/lib/pwn.rb +10 -7
- data/lib/pwnlib/abi.rb +61 -0
- data/lib/pwnlib/asm.rb +357 -0
- data/lib/pwnlib/constants/constant.rb +19 -3
- data/lib/pwnlib/constants/constants.rb +46 -20
- data/lib/pwnlib/constants/linux/amd64.rb +32 -1
- data/lib/pwnlib/constants/linux/i386.rb +2 -0
- data/lib/pwnlib/context.rb +128 -27
- data/lib/pwnlib/dynelf.rb +122 -54
- data/lib/pwnlib/elf/elf.rb +340 -0
- data/lib/pwnlib/errors.rb +31 -0
- data/lib/pwnlib/ext/array.rb +2 -1
- data/lib/pwnlib/ext/helper.rb +6 -5
- data/lib/pwnlib/ext/integer.rb +2 -1
- data/lib/pwnlib/ext/string.rb +3 -2
- data/lib/pwnlib/logger.rb +245 -0
- data/lib/pwnlib/memleak.rb +59 -29
- data/lib/pwnlib/pwn.rb +27 -9
- data/lib/pwnlib/reg_sort.rb +109 -110
- data/lib/pwnlib/runner.rb +53 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/common.rb +16 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/infloop.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/memcpy.rb +35 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/mov.rb +131 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/nop.rb +18 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/popad.rb +28 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr.rb +66 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr_array.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/ret.rb +33 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/setregs.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/cat.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/execve.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/exit.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/linux.rb +16 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/ls.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/open.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/sh.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/sleep.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/syscall.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/helper.rb +115 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/common.rb +16 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/infloop.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/memcpy.rb +34 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/mov.rb +93 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/nop.rb +18 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/pushstr.rb +41 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/pushstr_array.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/setregs.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/cat.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/execve.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/exit.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/linux.rb +16 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/ls.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/open.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/sh.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/sleep.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/syscall.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/common.rb +29 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/infloop.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/memcpy.rb +17 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/mov.rb +17 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/pushstr.rb +17 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/pushstr_array.rb +86 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/setregs.rb +84 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/cat.rb +54 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/execve.rb +72 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/exit.rb +34 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/linux.rb +16 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/ls.rb +67 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/open.rb +47 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/sh.rb +53 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/sleep.rb +52 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/syscall.rb +52 -0
- data/lib/pwnlib/shellcraft/registers.rb +148 -0
- data/lib/pwnlib/shellcraft/shellcraft.rb +73 -0
- data/lib/pwnlib/timer.rb +67 -0
- data/lib/pwnlib/tubes/buffer.rb +99 -0
- data/lib/pwnlib/tubes/process.rb +155 -0
- data/lib/pwnlib/tubes/serialtube.rb +114 -0
- data/lib/pwnlib/tubes/sock.rb +101 -0
- data/lib/pwnlib/tubes/tube.rb +442 -0
- data/lib/pwnlib/ui.rb +21 -0
- data/lib/pwnlib/util/cyclic.rb +97 -94
- data/lib/pwnlib/util/fiddling.rb +288 -220
- data/lib/pwnlib/util/getdents.rb +85 -0
- data/lib/pwnlib/util/hexdump.rb +116 -112
- data/lib/pwnlib/util/lists.rb +58 -0
- data/lib/pwnlib/util/packing.rb +223 -228
- data/lib/pwnlib/util/ruby.rb +19 -0
- data/lib/pwnlib/version.rb +3 -1
- data/test/abi_test.rb +22 -0
- data/test/asm_test.rb +177 -0
- data/test/constants/constant_test.rb +2 -0
- data/test/constants/constants_test.rb +5 -2
- data/test/context_test.rb +14 -3
- data/test/data/assembly/aarch64.s +19 -0
- data/test/data/assembly/amd64.s +21 -0
- data/test/data/assembly/arm.s +9 -0
- data/test/data/assembly/i386.s +21 -0
- data/test/data/assembly/mips.s +16 -0
- data/test/data/assembly/mips64.s +6 -0
- data/test/data/assembly/powerpc.s +18 -0
- data/test/data/assembly/powerpc64.s +36 -0
- data/test/data/assembly/sparc.s +33 -0
- data/test/data/assembly/sparc64.s +5 -0
- data/test/data/assembly/thumb.s +37 -0
- data/test/data/echo.rb +16 -0
- data/test/data/elfs/Makefile +24 -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/amd64.static.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 +62 -25
- data/test/elf/elf_test.rb +147 -0
- data/test/ext_test.rb +4 -2
- data/test/files/use_pwn.rb +3 -6
- data/test/files/use_pwnlib.rb +2 -1
- data/test/full_file_test.rb +6 -0
- data/test/logger_test.rb +120 -0
- data/test/memleak_test.rb +5 -33
- data/test/reg_sort_test.rb +4 -1
- data/test/runner_test.rb +32 -0
- data/test/shellcraft/infloop_test.rb +27 -0
- data/test/shellcraft/linux/cat_test.rb +87 -0
- data/test/shellcraft/linux/ls_test.rb +109 -0
- data/test/shellcraft/linux/sh_test.rb +120 -0
- data/test/shellcraft/linux/sleep_test.rb +68 -0
- data/test/shellcraft/linux/syscalls/execve_test.rb +137 -0
- data/test/shellcraft/linux/syscalls/exit_test.rb +57 -0
- data/test/shellcraft/linux/syscalls/open_test.rb +87 -0
- data/test/shellcraft/linux/syscalls/syscall_test.rb +84 -0
- data/test/shellcraft/memcpy_test.rb +50 -0
- data/test/shellcraft/mov_test.rb +99 -0
- data/test/shellcraft/nop_test.rb +27 -0
- data/test/shellcraft/popad_test.rb +30 -0
- data/test/shellcraft/pushstr_array_test.rb +92 -0
- data/test/shellcraft/pushstr_test.rb +109 -0
- data/test/shellcraft/registers_test.rb +33 -0
- data/test/shellcraft/ret_test.rb +31 -0
- data/test/shellcraft/setregs_test.rb +63 -0
- data/test/shellcraft/shellcraft_test.rb +30 -0
- data/test/test_helper.rb +61 -2
- data/test/timer_test.rb +42 -0
- data/test/tubes/buffer_test.rb +46 -0
- data/test/tubes/process_test.rb +105 -0
- data/test/tubes/serialtube_test.rb +162 -0
- data/test/tubes/sock_test.rb +68 -0
- data/test/tubes/tube_test.rb +320 -0
- data/test/ui_test.rb +18 -0
- data/test/util/cyclic_test.rb +3 -1
- data/test/util/fiddling_test.rb +12 -3
- data/test/util/getdents_test.rb +33 -0
- data/test/util/hexdump_test.rb +9 -10
- data/test/util/lists_test.rb +22 -0
- data/test/util/packing_test.rb +5 -3
- metadata +357 -37
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'test_helper'
|
5
|
+
|
6
|
+
require 'pwnlib/shellcraft/registers'
|
7
|
+
|
8
|
+
class RegistersTest < MiniTest::Test
|
9
|
+
include ::Pwnlib::Shellcraft::Registers
|
10
|
+
|
11
|
+
def test_get_register
|
12
|
+
assert_instance_of(::Pwnlib::Shellcraft::Registers::Register, get_register('rdi'))
|
13
|
+
assert_nil(get_register('meow'))
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_regtsiter?
|
17
|
+
assert_equal(true, register?(:ax))
|
18
|
+
assert_equal(true, register?('ax'))
|
19
|
+
assert_equal(true, register?('r8'))
|
20
|
+
assert_equal(true, register?('r15b'))
|
21
|
+
assert_equal(true, register?('r15w'))
|
22
|
+
assert_equal(false, register?('xdd'))
|
23
|
+
assert_equal(false, register?(''))
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_register
|
27
|
+
assert_equal(8, get_register('rdi').bytes)
|
28
|
+
assert_equal(16, get_register('ax').bits)
|
29
|
+
assert_equal('r10d', get_register('r10d').name)
|
30
|
+
assert_equal('r10d', get_register('r10d').to_s)
|
31
|
+
assert_equal('Register(r10d)', get_register('r10d').inspect)
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'test_helper'
|
5
|
+
|
6
|
+
require 'pwnlib/context'
|
7
|
+
require 'pwnlib/shellcraft/shellcraft'
|
8
|
+
|
9
|
+
class RetTest < MiniTest::Test
|
10
|
+
include ::Pwnlib::Context
|
11
|
+
|
12
|
+
def setup
|
13
|
+
@shellcraft = ::Pwnlib::Shellcraft::Shellcraft.instance
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_amd64
|
17
|
+
context.local(arch: 'amd64') do
|
18
|
+
assert_equal(" ret\n", @shellcraft.ret)
|
19
|
+
assert_equal(" mov rax, rdi\n ret\n", @shellcraft.ret(:rdi))
|
20
|
+
assert_equal(" xor eax, eax /* 0 */\n ret\n", @shellcraft.ret(0))
|
21
|
+
assert_equal(<<-'EOS', @shellcraft.ret(0x100000000))
|
22
|
+
mov rax, 0x101010201010101
|
23
|
+
push rax
|
24
|
+
mov rax, 0x101010301010101
|
25
|
+
xor [rsp], rax /* 0x100000000 == 0x101010201010101 ^ 0x101010301010101 */
|
26
|
+
pop rax
|
27
|
+
ret
|
28
|
+
EOS
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'test_helper'
|
5
|
+
|
6
|
+
require 'pwnlib/context'
|
7
|
+
require 'pwnlib/shellcraft/shellcraft'
|
8
|
+
|
9
|
+
class SetregsTest < MiniTest::Test
|
10
|
+
include ::Pwnlib::Context
|
11
|
+
|
12
|
+
def setup
|
13
|
+
@shellcraft = ::Pwnlib::Shellcraft::Shellcraft.instance
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_amd64
|
17
|
+
context.local(arch: 'amd64') do
|
18
|
+
assert_equal(<<-'EOS', @shellcraft.setregs({ rax: 1, rbx: 'rax' }))
|
19
|
+
mov rbx, rax
|
20
|
+
push 1
|
21
|
+
pop rax
|
22
|
+
EOS
|
23
|
+
assert_equal(<<-'EOS', @shellcraft.setregs({ rax: 'SYS_write', rbx: 'rax' }))
|
24
|
+
mov rbx, rax
|
25
|
+
push 1 /* (SYS_write) */
|
26
|
+
pop rax
|
27
|
+
EOS
|
28
|
+
assert_equal(<<-'EOS', @shellcraft.setregs({ rax: 'rbx', rbx: 'rax', rcx: 'rbx' }))
|
29
|
+
mov rcx, rbx
|
30
|
+
xchg rax, rbx
|
31
|
+
EOS
|
32
|
+
assert_equal(<<-'EOS', @shellcraft.setregs({ rax: 1, rdx: 0 }))
|
33
|
+
push 1
|
34
|
+
pop rax
|
35
|
+
cdq /* rdx=0 */
|
36
|
+
EOS
|
37
|
+
# issue #50
|
38
|
+
assert_equal(<<-'EOS', @shellcraft.setregs({ rdi: :rax, rsi: :rdi }))
|
39
|
+
mov rsi, rdi
|
40
|
+
mov rdi, rax
|
41
|
+
EOS
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_i386
|
46
|
+
context.local(arch: 'i386') do
|
47
|
+
assert_equal(<<-EOS, @shellcraft.setregs({ eax: 1, ebx: 'eax' }))
|
48
|
+
mov ebx, eax
|
49
|
+
push 1
|
50
|
+
pop eax
|
51
|
+
EOS
|
52
|
+
assert_equal(<<-EOS, @shellcraft.setregs({ eax: 'ebx', ebx: 'eax', ecx: 'ebx' }))
|
53
|
+
mov ecx, ebx
|
54
|
+
xchg eax, ebx
|
55
|
+
EOS
|
56
|
+
assert_equal(<<-'EOS', @shellcraft.setregs({ eax: 1, edx: 0 }))
|
57
|
+
push 1
|
58
|
+
pop eax
|
59
|
+
cdq /* edx=0 */
|
60
|
+
EOS
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'test_helper'
|
5
|
+
|
6
|
+
require 'pwnlib/context'
|
7
|
+
require 'pwnlib/shellcraft/shellcraft'
|
8
|
+
|
9
|
+
class ShellcraftTest < MiniTest::Test
|
10
|
+
include ::Pwnlib::Context
|
11
|
+
|
12
|
+
def setup
|
13
|
+
@shellcraft = ::Pwnlib::Shellcraft::Shellcraft.instance
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_respond
|
17
|
+
context.local(arch: 'amd64') do
|
18
|
+
# Check respond_to_missing? is well defined
|
19
|
+
assert(@shellcraft.respond_to?(:mov))
|
20
|
+
assert(@shellcraft.method(:sh))
|
21
|
+
end
|
22
|
+
refute(@shellcraft.respond_to?(:linux))
|
23
|
+
assert_raises(NoMethodError) { @shellcraft.meow }
|
24
|
+
|
25
|
+
context.local(arch: 'arm') do
|
26
|
+
err = assert_raises(::Pwnlib::Errors::UnsupportedArchError) { @shellcraft.respond_to?(:mov) }
|
27
|
+
assert_equal("Can't use shellcraft under architecture \"arm\".", err.message)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'rainbow'
|
3
4
|
require 'simplecov'
|
5
|
+
require 'tty/platform'
|
6
|
+
|
4
7
|
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
|
5
|
-
[SimpleCov::Formatter::HTMLFormatter
|
8
|
+
[SimpleCov::Formatter::HTMLFormatter]
|
6
9
|
)
|
7
10
|
SimpleCov.start do
|
8
11
|
add_filter '/test/'
|
@@ -11,3 +14,59 @@ end
|
|
11
14
|
require 'minitest/autorun'
|
12
15
|
require 'minitest/unit'
|
13
16
|
require 'minitest/hell'
|
17
|
+
|
18
|
+
module MiniTest
|
19
|
+
class Test
|
20
|
+
def before_setup
|
21
|
+
super
|
22
|
+
# Default to disable coloring for easier testing.
|
23
|
+
Rainbow.enabled = false
|
24
|
+
end
|
25
|
+
|
26
|
+
def linux_only(msg = 'Only tested on Linux')
|
27
|
+
skip msg unless TTY::Platform.new.linux?
|
28
|
+
end
|
29
|
+
|
30
|
+
def skip_windows(msg = 'Skip on Windows')
|
31
|
+
skip msg if TTY::Platform.new.windows?
|
32
|
+
end
|
33
|
+
|
34
|
+
# Methods for hooking logger,
|
35
|
+
# require 'pwnlib/logger' before using these methods.
|
36
|
+
|
37
|
+
def log_null(&block)
|
38
|
+
File.open(File::NULL, 'w') { |f| log_hook(f, &block) }
|
39
|
+
end
|
40
|
+
|
41
|
+
def log_stdout(&block)
|
42
|
+
log_hook($stdout, &block)
|
43
|
+
end
|
44
|
+
|
45
|
+
def log_hook(obj)
|
46
|
+
old = ::Pwnlib::Logger.log.instance_variable_get(:@logdev)
|
47
|
+
::Pwnlib::Logger.log.instance_variable_set(:@logdev, obj)
|
48
|
+
begin
|
49
|
+
yield
|
50
|
+
ensure
|
51
|
+
::Pwnlib::Logger.log.instance_variable_set(:@logdev, old)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Hooks +$stdin+.
|
56
|
+
#
|
57
|
+
# @param [IO] io
|
58
|
+
# IO object to be used as +$stdin+.
|
59
|
+
#
|
60
|
+
# @return [Object]
|
61
|
+
# Returns what the block returned.
|
62
|
+
def hook_stdin(io)
|
63
|
+
org_stdin = $stdin
|
64
|
+
$stdin = io
|
65
|
+
begin
|
66
|
+
yield
|
67
|
+
ensure
|
68
|
+
$stdin = org_stdin
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/test/timer_test.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'test_helper'
|
5
|
+
|
6
|
+
require 'pwnlib/timer'
|
7
|
+
|
8
|
+
class TimerTest < MiniTest::Test
|
9
|
+
include ::Pwnlib
|
10
|
+
|
11
|
+
def test_countdown
|
12
|
+
t = Timer.new
|
13
|
+
refute(t.started?)
|
14
|
+
refute(t.active?)
|
15
|
+
assert_equal('DARKHH QQ', t.countdown(0.1) { 'DARKHH QQ' })
|
16
|
+
|
17
|
+
exception = assert_raises(RuntimeError) { t.countdown(0.1) { t.countdown(0.1) {} } }
|
18
|
+
assert_equal('Nested countdown not permitted', exception.message)
|
19
|
+
|
20
|
+
t.timeout = 0.514
|
21
|
+
exception = assert_raises(RuntimeError) do
|
22
|
+
t.countdown(0.1) { t.timeout = :forever }
|
23
|
+
end
|
24
|
+
assert_equal("Can't change timeout when countdown", exception.message)
|
25
|
+
|
26
|
+
t.countdown(0.1) { assert(t.started?) }
|
27
|
+
t.countdown(0.1) { assert(t.active?) }
|
28
|
+
|
29
|
+
assert_raises(::Pwnlib::Errors::TimeoutError) do
|
30
|
+
t.countdown(0.1) { sleep(0.2) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Check #115 fixed
|
35
|
+
def test_nested_countdown_false_positve_115
|
36
|
+
t = Timer.new
|
37
|
+
assert_raises(::Pwnlib::Errors::TimeoutError) do
|
38
|
+
t.countdown(0.01) { sleep(1) }
|
39
|
+
end
|
40
|
+
t.countdown(0.01) {}
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'test_helper'
|
5
|
+
|
6
|
+
require 'pwnlib/tubes/buffer'
|
7
|
+
|
8
|
+
class BufferTest < MiniTest::Test
|
9
|
+
def test_add
|
10
|
+
b = ::Pwnlib::Tubes::Buffer.new
|
11
|
+
b.add('A' * 10)
|
12
|
+
b.add('B' * 10)
|
13
|
+
assert_equal(20, b.size)
|
14
|
+
assert_equal('A', b.get(1))
|
15
|
+
assert_equal(19, b.size)
|
16
|
+
assert_equal(false, b.empty?)
|
17
|
+
assert_equal('AAAAAAAAABBBBBBBBBB', b.get(9999))
|
18
|
+
assert_equal(0, b.size)
|
19
|
+
assert_equal(true, b.empty?)
|
20
|
+
assert_equal('', b.get(1))
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_unget
|
24
|
+
b = ::Pwnlib::Tubes::Buffer.new
|
25
|
+
b.add('hello')
|
26
|
+
b.add('world')
|
27
|
+
assert_equal('hello', b.get(5))
|
28
|
+
b.unget('goodbye')
|
29
|
+
assert_equal('goodbyeworld', b.get)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_buffer
|
33
|
+
b = ::Pwnlib::Tubes::Buffer.new
|
34
|
+
b2 = ::Pwnlib::Tubes::Buffer.new
|
35
|
+
b.add('hello')
|
36
|
+
b2.add('world')
|
37
|
+
b.add(b2)
|
38
|
+
assert_equal('hello', b.get(5))
|
39
|
+
assert_equal(false, b2.empty?)
|
40
|
+
assert_equal('world', b2.get)
|
41
|
+
b2.add('goodbye')
|
42
|
+
b.unget(b2)
|
43
|
+
assert_equal('goodbyeworld', b.get)
|
44
|
+
assert_equal('goodbye', b2.get)
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'socket'
|
5
|
+
require 'tty-platform'
|
6
|
+
|
7
|
+
require 'test_helper'
|
8
|
+
|
9
|
+
require 'pwnlib/context'
|
10
|
+
require 'pwnlib/errors'
|
11
|
+
require 'pwnlib/tubes/process'
|
12
|
+
|
13
|
+
class ProcessTest < MiniTest::Test
|
14
|
+
include ::Pwnlib::Context
|
15
|
+
|
16
|
+
def setup
|
17
|
+
skip_windows
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_io
|
21
|
+
cat = ::Pwnlib::Tubes::Process.new('cat')
|
22
|
+
cat.puts('HAHA')
|
23
|
+
assert_equal("HAHA\n", cat.gets)
|
24
|
+
assert_raises(::Pwnlib::Errors::TimeoutError) { cat.gets(timeout: 0.1) }
|
25
|
+
cat.puts('HAHA2')
|
26
|
+
assert_equal("HAHA2\n", cat.gets)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_env
|
30
|
+
data = ::Pwnlib::Tubes::Process.new('env').read
|
31
|
+
assert_match('PATH=', data)
|
32
|
+
data = ::Pwnlib::Tubes::Process.new('env', env: { 'FOO' => 'BAR' }).read
|
33
|
+
assert_equal("FOO=BAR\n", data)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_aslr
|
37
|
+
linux_only
|
38
|
+
|
39
|
+
map1 = ::Pwnlib::Tubes::Process.new('cat /proc/self/maps', aslr: false).read
|
40
|
+
map2 = ::Pwnlib::Tubes::Process.new(['cat', '/proc/self/maps'], aslr: false).read
|
41
|
+
assert_match('/bin/cat', map1) # make sure it read something
|
42
|
+
assert_equal(map1, map2)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_eof
|
46
|
+
ls = ::Pwnlib::Tubes::Process.new(['ls', '-la'])
|
47
|
+
assert_match(/total/, ls.gets)
|
48
|
+
assert_raises(::Pwnlib::Errors::EndOfTubeError) { loop { ls.write('anything') } }
|
49
|
+
assert_raises(::Pwnlib::Errors::EndOfTubeError) { loop { ls.gets } }
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_shutdown
|
53
|
+
cat = ::Pwnlib::Tubes::Process.new('cat')
|
54
|
+
assert_raises(::Pwnlib::Errors::TimeoutError) { cat.recvn(1, timeout: 0.1) }
|
55
|
+
cat.shutdown(:write) # This should cause `cat` dead
|
56
|
+
assert_raises(::Pwnlib::Errors::EndOfTubeError) { cat.recvn(1, timeout: 0.1) }
|
57
|
+
cat.shutdown
|
58
|
+
|
59
|
+
cat = ::Pwnlib::Tubes::Process.new('cat')
|
60
|
+
cat.shutdown(:read)
|
61
|
+
assert_raises(::Pwnlib::Errors::EndOfTubeError) { cat.recvn(1) }
|
62
|
+
cat.shutdown
|
63
|
+
assert_raises(ArgumentError) { cat.shutdown(:zz) }
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_kill
|
67
|
+
cat = ::Pwnlib::Tubes::Process.new('cat')
|
68
|
+
cat.kill
|
69
|
+
assert_raises(::Pwnlib::Errors::EndOfTubeError) { cat.recvn(1) }
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_tty
|
73
|
+
tty_test = proc do |*args, raw: true|
|
74
|
+
in_, out = args.map { |v| v ? :pty : :pipe }
|
75
|
+
process = ::Pwnlib::Tubes::Process.new('ruby -e "p [STDIN.tty?, STDOUT.tty?]"',
|
76
|
+
in: in_, out: out, raw: raw)
|
77
|
+
process.gets
|
78
|
+
end
|
79
|
+
assert_equal("[false, false]\n", tty_test.call(false, false))
|
80
|
+
assert_equal("[true, false]\n", tty_test.call(true, false))
|
81
|
+
assert_equal("[false, true]\n", tty_test.call(false, true))
|
82
|
+
assert_equal("[false, true]\r\n", tty_test.call(false, true, raw: false))
|
83
|
+
|
84
|
+
cat = ::Pwnlib::Tubes::Process.new('cat', in: :pty, out: :pty, raw: false)
|
85
|
+
cat.puts('Hi')
|
86
|
+
# In cooked mode, tty should echo the input, so we can gets twice.
|
87
|
+
assert_equal("Hi\r\n", cat.gets)
|
88
|
+
assert_equal("Hi\r\n", cat.gets)
|
89
|
+
class << cat
|
90
|
+
# hook shutdown to silence the +cat: -: Input/output error+ message.
|
91
|
+
def shutdown; end
|
92
|
+
end
|
93
|
+
cat.close
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_interact
|
97
|
+
ls = ::Pwnlib::Tubes::Process.new('ls Gemfile*')
|
98
|
+
saved = $stdin
|
99
|
+
# prevents stdin being closed
|
100
|
+
$stdin = UDPSocket.new
|
101
|
+
assert_output("Gemfile\nGemfile.lock\n") { context.local(log_level: :fatal) { ls.interact } }
|
102
|
+
$stdin.close
|
103
|
+
$stdin = saved
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'open3'
|
5
|
+
|
6
|
+
require 'test_helper'
|
7
|
+
|
8
|
+
require 'pwnlib/tubes/serialtube'
|
9
|
+
|
10
|
+
module Pwnlib
|
11
|
+
module Tubes
|
12
|
+
class SerialTube
|
13
|
+
def break_encapsulation
|
14
|
+
@conn.close
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class SerialTest < MiniTest::Test
|
21
|
+
include ::Pwnlib::Tubes
|
22
|
+
|
23
|
+
def open_pair
|
24
|
+
Open3.popen3('socat -d -d pty,raw,echo=0 pty,raw,echo=0') do |_i, _o, stderr, thread|
|
25
|
+
devs = []
|
26
|
+
2.times do
|
27
|
+
devs << stderr.readline.chomp.split.last
|
28
|
+
# First pattern matches Linux, second is macOS
|
29
|
+
raise IOError, 'Could not create serial crosslink' if devs.last !~ %r{^(/dev/pts/[0-9]+|/dev/ttys[0-9]+)$}
|
30
|
+
end
|
31
|
+
# To ensure socat have finished setup
|
32
|
+
stderr.gets('starting data transfer loop')
|
33
|
+
|
34
|
+
serial = SerialTube.new devs[1], convert_newlines: false
|
35
|
+
|
36
|
+
begin
|
37
|
+
File.open devs[0], 'r+' do |file|
|
38
|
+
file.set_encoding 'default'.encoding
|
39
|
+
yield file, serial, thread
|
40
|
+
end
|
41
|
+
ensure
|
42
|
+
::Process.kill('SIGTERM', thread.pid) if thread.alive?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def random_string(length)
|
48
|
+
Random.rand(36**length).to_s(36).rjust(length, '0')
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_raise
|
52
|
+
skip_windows
|
53
|
+
open_pair do |_file, serial, thread|
|
54
|
+
::Process.kill('SIGTERM', thread.pid)
|
55
|
+
# ensure the process has been killed
|
56
|
+
thread.value
|
57
|
+
assert_raises(Pwnlib::Errors::EndOfTubeError) { serial.puts('a') }
|
58
|
+
end
|
59
|
+
open_pair do |_file, serial|
|
60
|
+
serial.break_encapsulation
|
61
|
+
assert_raises(Pwnlib::Errors::EndOfTubeError) { serial.recv(1, timeout: 2) }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_recv
|
66
|
+
skip_windows
|
67
|
+
open_pair do |file, serial|
|
68
|
+
# recv, recvline
|
69
|
+
rs = random_string 24
|
70
|
+
file.puts rs
|
71
|
+
result = serial.recv 8, timeout: 1
|
72
|
+
|
73
|
+
assert_equal(rs[0...8], result)
|
74
|
+
result = serial.recv 8
|
75
|
+
assert_equal(rs[8...16], result)
|
76
|
+
result = serial.recvline.chomp
|
77
|
+
assert_equal(rs[16..-1], result)
|
78
|
+
|
79
|
+
assert_raises(Pwnlib::Errors::TimeoutError) { serial.recv(1, timeout: 0.2) }
|
80
|
+
|
81
|
+
# recvpred
|
82
|
+
rs = random_string 12
|
83
|
+
file.print rs
|
84
|
+
result = serial.recvpred do |data|
|
85
|
+
data[-6..-1] == rs[-6..-1]
|
86
|
+
end
|
87
|
+
assert_equal rs, result
|
88
|
+
|
89
|
+
assert_raises(Pwnlib::Errors::TimeoutError) { serial.recv(1, timeout: 0.2) }
|
90
|
+
|
91
|
+
# recvn
|
92
|
+
rs = random_string 6
|
93
|
+
file.print rs
|
94
|
+
result = ''
|
95
|
+
assert_raises(Pwnlib::Errors::TimeoutError) do
|
96
|
+
result = serial.recvn 120, timeout: 1
|
97
|
+
end
|
98
|
+
assert_empty result
|
99
|
+
file.print rs
|
100
|
+
result = serial.recvn 12
|
101
|
+
assert_equal rs * 2, result
|
102
|
+
|
103
|
+
assert_raises(Pwnlib::Errors::TimeoutError) { serial.recv(1, timeout: 0.2) }
|
104
|
+
|
105
|
+
# recvuntil
|
106
|
+
rs = random_string 12
|
107
|
+
file.print "#{rs}|"
|
108
|
+
result = serial.recvuntil('|').chomp('|')
|
109
|
+
assert_equal rs, result
|
110
|
+
|
111
|
+
assert_raises(Pwnlib::Errors::TimeoutError) { serial.recv(1, timeout: 0.2) }
|
112
|
+
|
113
|
+
# gets
|
114
|
+
rs = random_string 24
|
115
|
+
file.puts rs
|
116
|
+
result = serial.gets 12
|
117
|
+
assert_equal rs[0...12], result
|
118
|
+
result = serial.gets.chomp
|
119
|
+
assert_equal rs[12..-1], result
|
120
|
+
|
121
|
+
assert_raises(Pwnlib::Errors::TimeoutError) { serial.recv(1, timeout: 0.2) }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_send
|
126
|
+
skip_windows
|
127
|
+
open_pair do |file, serial|
|
128
|
+
# send, sendline
|
129
|
+
rs = random_string 24
|
130
|
+
# rubocop:disable Style/Send
|
131
|
+
# Justification: This isn't Object#send, false positive.
|
132
|
+
serial.send rs[0...12]
|
133
|
+
# rubocop:enable Style/Send
|
134
|
+
serial.sendline rs[12...24]
|
135
|
+
result = file.readline.chomp
|
136
|
+
assert_equal rs, result
|
137
|
+
|
138
|
+
# puts
|
139
|
+
r1 = random_string 4
|
140
|
+
r2 = random_string 4
|
141
|
+
r3 = random_string 4
|
142
|
+
serial.puts r1, r2, r3
|
143
|
+
result = ''
|
144
|
+
3.times do
|
145
|
+
result += file.readline.chomp
|
146
|
+
end
|
147
|
+
assert_equal r1 + r2 + r3, result
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_close
|
152
|
+
skip_windows
|
153
|
+
open_pair do |_file, serial|
|
154
|
+
serial.close
|
155
|
+
assert_raises(::Pwnlib::Errors::EndOfTubeError) { serial.puts(514) }
|
156
|
+
assert_raises(::Pwnlib::Errors::EndOfTubeError) { serial.puts(514) }
|
157
|
+
assert_raises(::Pwnlib::Errors::EndOfTubeError) { serial.recv }
|
158
|
+
assert_raises(::Pwnlib::Errors::EndOfTubeError) { serial.recv }
|
159
|
+
assert_raises(ArgumentError) { serial.close(:hh) }
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|