pwntools 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +88 -11
  3. data/Rakefile +5 -1
  4. data/lib/pwn.rb +9 -7
  5. data/lib/pwnlib/abi.rb +60 -0
  6. data/lib/pwnlib/asm.rb +146 -0
  7. data/lib/pwnlib/constants/constant.rb +16 -2
  8. data/lib/pwnlib/constants/constants.rb +35 -19
  9. data/lib/pwnlib/constants/linux/amd64.rb +30 -1
  10. data/lib/pwnlib/context.rb +25 -17
  11. data/lib/pwnlib/dynelf.rb +117 -54
  12. data/lib/pwnlib/elf/elf.rb +267 -0
  13. data/lib/pwnlib/ext/helper.rb +4 -4
  14. data/lib/pwnlib/logger.rb +87 -0
  15. data/lib/pwnlib/memleak.rb +58 -29
  16. data/lib/pwnlib/pwn.rb +19 -8
  17. data/lib/pwnlib/reg_sort.rb +102 -108
  18. data/lib/pwnlib/shellcraft/generators/amd64/common/common.rb +14 -0
  19. data/lib/pwnlib/shellcraft/generators/amd64/common/infloop.rb +17 -0
  20. data/lib/pwnlib/shellcraft/generators/amd64/common/memcpy.rb +31 -0
  21. data/lib/pwnlib/shellcraft/generators/amd64/common/mov.rb +127 -0
  22. data/lib/pwnlib/shellcraft/generators/amd64/common/nop.rb +16 -0
  23. data/lib/pwnlib/shellcraft/generators/amd64/common/popad.rb +27 -0
  24. data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr.rb +64 -0
  25. data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr_array.rb +19 -0
  26. data/lib/pwnlib/shellcraft/generators/amd64/common/ret.rb +32 -0
  27. data/lib/pwnlib/shellcraft/generators/amd64/common/setregs.rb +19 -0
  28. data/lib/pwnlib/shellcraft/generators/amd64/linux/execve.rb +21 -0
  29. data/lib/pwnlib/shellcraft/generators/amd64/linux/linux.rb +14 -0
  30. data/lib/pwnlib/shellcraft/generators/amd64/linux/ls.rb +19 -0
  31. data/lib/pwnlib/shellcraft/generators/amd64/linux/sh.rb +19 -0
  32. data/lib/pwnlib/shellcraft/generators/amd64/linux/syscall.rb +21 -0
  33. data/lib/pwnlib/shellcraft/generators/helper.rb +106 -0
  34. data/lib/pwnlib/shellcraft/generators/i386/common/common.rb +14 -0
  35. data/lib/pwnlib/shellcraft/generators/i386/common/infloop.rb +17 -0
  36. data/lib/pwnlib/shellcraft/generators/i386/common/mov.rb +90 -0
  37. data/lib/pwnlib/shellcraft/generators/i386/common/nop.rb +16 -0
  38. data/lib/pwnlib/shellcraft/generators/i386/common/pushstr.rb +39 -0
  39. data/lib/pwnlib/shellcraft/generators/i386/common/pushstr_array.rb +19 -0
  40. data/lib/pwnlib/shellcraft/generators/i386/common/setregs.rb +19 -0
  41. data/lib/pwnlib/shellcraft/generators/i386/linux/execve.rb +19 -0
  42. data/lib/pwnlib/shellcraft/generators/i386/linux/linux.rb +14 -0
  43. data/lib/pwnlib/shellcraft/generators/i386/linux/ls.rb +19 -0
  44. data/lib/pwnlib/shellcraft/generators/i386/linux/sh.rb +19 -0
  45. data/lib/pwnlib/shellcraft/generators/i386/linux/syscall.rb +19 -0
  46. data/lib/pwnlib/shellcraft/generators/x86/common/common.rb +26 -0
  47. data/lib/pwnlib/shellcraft/generators/x86/common/infloop.rb +22 -0
  48. data/lib/pwnlib/shellcraft/generators/x86/common/mov.rb +15 -0
  49. data/lib/pwnlib/shellcraft/generators/x86/common/pushstr.rb +15 -0
  50. data/lib/pwnlib/shellcraft/generators/x86/common/pushstr_array.rb +85 -0
  51. data/lib/pwnlib/shellcraft/generators/x86/common/setregs.rb +82 -0
  52. data/lib/pwnlib/shellcraft/generators/x86/linux/execve.rb +69 -0
  53. data/lib/pwnlib/shellcraft/generators/x86/linux/linux.rb +14 -0
  54. data/lib/pwnlib/shellcraft/generators/x86/linux/ls.rb +66 -0
  55. data/lib/pwnlib/shellcraft/generators/x86/linux/sh.rb +52 -0
  56. data/lib/pwnlib/shellcraft/generators/x86/linux/syscall.rb +52 -0
  57. data/lib/pwnlib/shellcraft/registers.rb +145 -0
  58. data/lib/pwnlib/shellcraft/shellcraft.rb +67 -0
  59. data/lib/pwnlib/timer.rb +60 -0
  60. data/lib/pwnlib/tubes/buffer.rb +96 -0
  61. data/lib/pwnlib/tubes/sock.rb +95 -0
  62. data/lib/pwnlib/tubes/tube.rb +270 -0
  63. data/lib/pwnlib/util/cyclic.rb +95 -94
  64. data/lib/pwnlib/util/fiddling.rb +256 -220
  65. data/lib/pwnlib/util/getdents.rb +83 -0
  66. data/lib/pwnlib/util/hexdump.rb +109 -108
  67. data/lib/pwnlib/util/lists.rb +55 -0
  68. data/lib/pwnlib/util/packing.rb +226 -228
  69. data/lib/pwnlib/util/ruby.rb +18 -0
  70. data/lib/pwnlib/version.rb +2 -1
  71. data/test/abi_test.rb +21 -0
  72. data/test/asm_test.rb +104 -0
  73. data/test/constants/constant_test.rb +1 -0
  74. data/test/constants/constants_test.rb +4 -2
  75. data/test/context_test.rb +1 -0
  76. data/test/data/echo.rb +20 -0
  77. data/test/data/elfs/Makefile +22 -0
  78. data/test/data/elfs/amd64.frelro.elf +0 -0
  79. data/test/data/elfs/amd64.frelro.pie.elf +0 -0
  80. data/test/data/elfs/amd64.nrelro.elf +0 -0
  81. data/test/data/elfs/amd64.prelro.elf +0 -0
  82. data/test/data/elfs/i386.frelro.pie.elf +0 -0
  83. data/test/data/elfs/i386.prelro.elf +0 -0
  84. data/test/data/elfs/source.cpp +19 -0
  85. data/test/data/flag +1 -0
  86. data/test/data/lib32/ld.so.2 +0 -0
  87. data/test/data/lib32/libc.so.6 +0 -0
  88. data/test/data/lib64/ld.so.2 +0 -0
  89. data/test/data/lib64/libc.so.6 +0 -0
  90. data/test/dynelf_test.rb +59 -24
  91. data/test/elf/elf_test.rb +120 -0
  92. data/test/ext_test.rb +3 -2
  93. data/test/files/use_pwnlib.rb +1 -1
  94. data/test/logger_test.rb +61 -0
  95. data/test/memleak_test.rb +4 -33
  96. data/test/reg_sort_test.rb +3 -1
  97. data/test/shellcraft/infloop_test.rb +26 -0
  98. data/test/shellcraft/linux/ls_test.rb +108 -0
  99. data/test/shellcraft/linux/sh_test.rb +119 -0
  100. data/test/shellcraft/linux/syscalls/execve_test.rb +136 -0
  101. data/test/shellcraft/linux/syscalls/syscall_test.rb +83 -0
  102. data/test/shellcraft/memcpy_test.rb +35 -0
  103. data/test/shellcraft/mov_test.rb +98 -0
  104. data/test/shellcraft/nop_test.rb +26 -0
  105. data/test/shellcraft/popad_test.rb +29 -0
  106. data/test/shellcraft/pushstr_array_test.rb +91 -0
  107. data/test/shellcraft/pushstr_test.rb +108 -0
  108. data/test/shellcraft/registers_test.rb +32 -0
  109. data/test/shellcraft/ret_test.rb +30 -0
  110. data/test/shellcraft/setregs_test.rb +62 -0
  111. data/test/shellcraft/shellcraft_test.rb +28 -0
  112. data/test/test_helper.rb +12 -1
  113. data/test/timer_test.rb +23 -0
  114. data/test/tubes/buffer_test.rb +45 -0
  115. data/test/tubes/sock_test.rb +68 -0
  116. data/test/tubes/tube_test.rb +241 -0
  117. data/test/util/cyclic_test.rb +2 -1
  118. data/test/util/fiddling_test.rb +2 -1
  119. data/test/util/getdents_test.rb +32 -0
  120. data/test/util/hexdump_test.rb +7 -9
  121. data/test/util/lists_test.rb +21 -0
  122. data/test/util/packing_test.rb +4 -3
  123. metadata +215 -25
@@ -0,0 +1,18 @@
1
+ # encoding: ASCII-8BIT
2
+
3
+ module Pwnlib
4
+ module Util
5
+ # module for some utilities for Ruby metaprogramming.
6
+ module Ruby
7
+ def self.private_class_method_block
8
+ define_singleton_method(:singleton_method_added) do |m|
9
+ private_class_method m
10
+ end
11
+ yield
12
+ class << self
13
+ remove_method(:singleton_method_added)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,5 +1,6 @@
1
1
  # encoding: ASCII-8BIT
2
2
 
3
3
  module Pwnlib
4
- VERSION = '0.1.0'.freeze
4
+ # version of pwntools-ruby
5
+ VERSION = '1.0.0'.freeze
5
6
  end
@@ -0,0 +1,21 @@
1
+ # encoding: ASCII-8BIT
2
+
3
+ require 'test_helper'
4
+
5
+ require 'pwnlib/abi'
6
+ require 'pwnlib/context'
7
+
8
+ class AbiTest < MiniTest::Test
9
+ include ::Pwnlib::Context
10
+ ABI = ::Pwnlib::ABI
11
+
12
+ def test_default
13
+ context.local(arch: 'i386', os: 'linux') { assert_same ABI::DEFAULT[[32, 'i386', 'linux']], ABI::ABI.default }
14
+ context.local(arch: 'amd64', os: 'linux') { assert_same ABI::DEFAULT[[64, 'amd64', 'linux']], ABI::ABI.default }
15
+ end
16
+
17
+ def test_syscall
18
+ context.local(arch: 'i386', os: 'linux') { assert_same ABI::SYSCALL[[32, 'i386', 'linux']], ABI::ABI.syscall }
19
+ context.local(arch: 'amd64', os: 'linux') { assert_same ABI::SYSCALL[[64, 'amd64', 'linux']], ABI::ABI.syscall }
20
+ end
21
+ end
@@ -0,0 +1,104 @@
1
+ # encoding: ASCII-8BIT
2
+
3
+ require 'test_helper'
4
+
5
+ require 'pwnlib/asm'
6
+ require 'pwnlib/shellcraft/shellcraft'
7
+
8
+ class AsmTest < MiniTest::Test
9
+ include ::Pwnlib::Context
10
+ Asm = ::Pwnlib::Asm
11
+
12
+ def setup
13
+ skip 'Not test asm/disasm on Windows' if TTY::Platform.new.windows?
14
+ @shellcraft = ::Pwnlib::Shellcraft::Shellcraft.instance
15
+ end
16
+
17
+ def test_i386_asm
18
+ context.local(arch: 'i386') do
19
+ assert_equal("\x90", Asm.asm('nop'))
20
+ assert_equal("\xeb\xfe", Asm.asm(@shellcraft.infloop))
21
+ assert_equal("jhh///sh/binj\x0bX\x89\xe31\xc9\x99\xcd\x80", Asm.asm(@shellcraft.sh))
22
+ # issue #51
23
+ assert_equal("j\x01\xfe\x0c$h\x01\x01\x01\x01\x814$\xf2\xf3\x0b\xfe",
24
+ Asm.asm(@shellcraft.pushstr("\xf3\xf2\x0a\xff")))
25
+ end
26
+ end
27
+
28
+ def test_amd64_asm
29
+ context.local(arch: 'amd64') do
30
+ assert_equal("\x90", Asm.asm('nop'))
31
+ assert_equal("\xeb\xfe", Asm.asm(@shellcraft.infloop))
32
+ assert_equal("jhH\xb8/bin///sPj;XH\x89\xe71\xf6\x99\x0f\x05", Asm.asm(@shellcraft.sh))
33
+ assert_equal("j\x01\xfe\x0c$H\xb8\x01\x01\x01\x01\x01\x01\x01\x01PH\xb8\xfe\xfe\xfe\xfe\xfe\xfe\x0b\xfeH1\x04$",
34
+ Asm.asm(@shellcraft.pushstr("\xff\xff\xff\xff\xff\xff\x0a\xff")))
35
+ end
36
+ end
37
+
38
+ def test_i386_disasm
39
+ context.local(arch: 'i386') do
40
+ str = Asm.disasm("h\x01\x01\x01\x01\x814$ri\x01\x011\xd2"\
41
+ "Rj\x04Z\x01\xe2R\x89\xe2jhh///sh/binj\x0bX\x89\xe3\x89\xd1\x99\xcd\x80")
42
+ assert_equal(<<-EOS, str)
43
+ 0: 68 01 01 01 01 push 0x1010101
44
+ 5: 81 34 24 72 69 01 01 xor dword ptr [esp], 0x1016972
45
+ c: 31 d2 xor edx, edx
46
+ e: 52 push edx
47
+ f: 6a 04 push 4
48
+ 11: 5a pop edx
49
+ 12: 01 e2 add edx, esp
50
+ 14: 52 push edx
51
+ 15: 89 e2 mov edx, esp
52
+ 17: 6a 68 push 0x68
53
+ 19: 68 2f 2f 2f 73 push 0x732f2f2f
54
+ 1e: 68 2f 62 69 6e push 0x6e69622f
55
+ 23: 6a 0b push 0xb
56
+ 25: 58 pop eax
57
+ 26: 89 e3 mov ebx, esp
58
+ 28: 89 d1 mov ecx, edx
59
+ 2a: 99 cdq
60
+ 2b: cd 80 int 0x80
61
+ EOS
62
+ assert_equal(<<-EOS, Asm.disasm("\xb8\x5d\x00\x00\x00"))
63
+ 0: b8 5d 00 00 00 mov eax, 0x5d
64
+ EOS
65
+ end
66
+ end
67
+
68
+ def test_amd64_disasm
69
+ context.local(arch: 'amd64') do
70
+ str = Asm.disasm("hri\x01\x01\x814$\x01\x01\x01\x011\xd2" \
71
+ "Rj\x08ZH\x01\xe2RH\x89\xe2jhH\xb8/bin///sPj;XH\x89\xe7H\x89\xd6\x99\x0f\x05", vma: 0xfff)
72
+
73
+ assert_equal(<<-EOS, str)
74
+ fff: 68 72 69 01 01 push 0x1016972
75
+ 1004: 81 34 24 01 01 01 01 xor dword ptr [rsp], 0x1010101
76
+ 100b: 31 d2 xor edx, edx
77
+ 100d: 52 push rdx
78
+ 100e: 6a 08 push 8
79
+ 1010: 5a pop rdx
80
+ 1011: 48 01 e2 add rdx, rsp
81
+ 1014: 52 push rdx
82
+ 1015: 48 89 e2 mov rdx, rsp
83
+ 1018: 6a 68 push 0x68
84
+ 101a: 48 b8 2f 62 69 6e 2f 2f 2f 73 movabs rax, 0x732f2f2f6e69622f
85
+ 1024: 50 push rax
86
+ 1025: 6a 3b push 0x3b
87
+ 1027: 58 pop rax
88
+ 1028: 48 89 e7 mov rdi, rsp
89
+ 102b: 48 89 d6 mov rsi, rdx
90
+ 102e: 99 cdq
91
+ 102f: 0f 05 syscall
92
+ EOS
93
+ assert_equal(<<-EOS, Asm.disasm("\xb8\x17\x00\x00\x00"))
94
+ 0: b8 17 00 00 00 mov eax, 0x17
95
+ EOS
96
+ end
97
+ end
98
+
99
+ # To ensure coverage
100
+ def test_require
101
+ err = assert_raises(LoadError) { Asm.__send__(:require_message, 'no_such_lib', 'meow') }
102
+ assert_match(/meow/, err.message)
103
+ end
104
+ end
@@ -1,6 +1,7 @@
1
1
  # encoding: ASCII-8BIT
2
2
 
3
3
  require 'test_helper'
4
+
4
5
  require 'pwnlib/constants/constant'
5
6
 
6
7
  class ConstantTest < MiniTest::Test
@@ -1,6 +1,7 @@
1
1
  # encoding: ASCII-8BIT
2
2
 
3
3
  require 'test_helper'
4
+
4
5
  require 'pwnlib/constants/constants'
5
6
  require 'pwnlib/context'
6
7
 
@@ -13,8 +14,9 @@ class ConstantsTest < MiniTest::Test
13
14
  assert_equal('Constant("SYS_read", 0x0)', Constants.SYS_read.inspect)
14
15
  assert_equal('__NR_arch_prctl', Constants.__NR_arch_prctl.to_s)
15
16
  assert_equal('Constant("(O_CREAT)", 0x40)', Constants.eval('O_CREAT').inspect)
16
- # TODO(david942j): implement 'real' Constants.eval
17
- # assert_equal('Constant("(O_CREAT | O_WRONLY)", 0x41)', Constants.eval('O_CREAT | O_WRONLY').inspect)
17
+ assert_equal('Constant("(O_CREAT | O_WRONLY)", 0x41)', Constants.eval('O_CREAT | O_WRONLY').inspect)
18
+ err = assert_raises(NameError) { Constants.eval('rax') }
19
+ assert_equal('no value provided for variables: rax', err.message)
18
20
  end
19
21
  end
20
22
 
@@ -1,6 +1,7 @@
1
1
  # encoding: ASCII-8BIT
2
2
 
3
3
  require 'test_helper'
4
+
4
5
  require 'pwnlib/context'
5
6
 
6
7
  class ContextTest < MiniTest::Test
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'socket'
4
+
5
+ if ARGV.empty?
6
+ puts "Usage #{__FILE__} port"
7
+ exit 1
8
+ end
9
+
10
+ server = TCPServer.open('127.0.0.1', ARGV[0].to_i)
11
+
12
+ STDOUT.puts 'Start!'
13
+ STDOUT.flush
14
+
15
+ client = server.accept
16
+ s = client.gets
17
+ client.puts(s)
18
+ client.close
19
+
20
+ STDOUT.puts 'Bye!'
@@ -0,0 +1,22 @@
1
+ source=source.cpp
2
+ FLAGS=
3
+ PIE_FLAGS=-pie
4
+ NOPIE_FLAGS=-no-pie
5
+ FULL_RELRO_FLAGS=-Wl,-z,relro,-z,now
6
+ PARTIAL_RELRO_FLAGS=-Wl,-z,relro
7
+ NO_RELRO_FLAGS=-Wl,-z,norelro
8
+ TARGETS=amd64 i386
9
+ .PHONY: clean
10
+ all: ${TARGETS}
11
+
12
+ amd64: ${source}
13
+ g++ -m64 ${source} -o amd64.frelro.elf ${FLAGS} ${FULL_RELRO_FLAGS} ${NOPIE_FLAGS}
14
+ g++ -m64 ${source} -o amd64.frelro.pie.elf ${FLAGS} ${FULL_RELRO_FLAGS} ${PIE_FLAGS}
15
+ g++ -m64 ${source} -o amd64.prelro.elf ${FLAGS} ${PARTIAL_RELRO_FLAGS} ${NOPIE_FLAGS}
16
+ g++ -m64 ${source} -o amd64.nrelro.elf ${FLAGS} ${NO_RELRO_FLAGS} ${NOPIE_FLAGS}
17
+ i386: ${source}
18
+ g++ -m32 ${source} -o i386.prelro.elf ${FLAGS} ${PARTIAL_RELRO_FLAGS} ${NOPIE_FLAGS}
19
+ g++ -m32 ${source} -o i386.frelro.pie.elf ${FLAGS} ${FULL_RELRO_FLAGS} ${PIE_FLAGS}
20
+
21
+ clean:
22
+ rm -f *.elf
@@ -0,0 +1,19 @@
1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+ char s[101];
4
+ void func() {
5
+ static int test = 0;
6
+ test++;
7
+ puts("In func:");
8
+ printf("test = %d\n", test);
9
+ }
10
+ int main() {
11
+ fgets(s, 100, stdin);
12
+ printf("%s", s);
13
+ int n;
14
+ scanf("%d", &n);
15
+ while(n--) {
16
+ func();
17
+ }
18
+ return 0;
19
+ }
@@ -0,0 +1 @@
1
+ flag{pwntools_ruby}
Binary file
Binary file
Binary file
Binary file
@@ -5,43 +5,78 @@ require 'open3'
5
5
  require 'tty-platform'
6
6
 
7
7
  require 'test_helper'
8
+
9
+ require 'pwnlib/context'
8
10
  require 'pwnlib/dynelf'
11
+ require 'pwnlib/elf/elf'
9
12
 
10
13
  class DynELFTest < MiniTest::Test
11
- def test_lookup
14
+ include ::Pwnlib
15
+ include ::Pwnlib::Context
16
+ include ::Pwnlib::ELF
17
+
18
+ def setup
12
19
  skip 'Only tested on linux' unless TTY::Platform.new.linux?
20
+ end
21
+
22
+ # popen victim with specific libc.so.6
23
+ def popen_victim(b)
24
+ lib_path = File.expand_path("data/lib#{b}/", __dir__)
25
+ libc_path = File.expand_path('libc.so.6', lib_path)
26
+ ld_path = File.expand_path('ld.so.2', lib_path)
27
+ victim_path = File.expand_path("data/victim#{b}", __dir__)
28
+
29
+ Open3.popen2("#{ld_path} --library-path #{lib_path} #{victim_path}") do |i, o, t|
30
+ main_ra = Integer(o.readline)
31
+ mem = open("/proc/#{t.pid}/mem", 'rb')
32
+ d = DynELF.new(main_ra) do |addr|
33
+ mem.seek(addr)
34
+ mem.getc
35
+ end
36
+
37
+ yield d, { libc: libc_path, main_ra: main_ra, pid: t.pid }
38
+
39
+ mem.close
40
+ i.write('bye')
41
+ end
42
+ end
43
+
44
+ def test_find_base
13
45
  [32, 64].each do |b|
14
- # TODO(hh): Use process instead of popen2
15
- Open3.popen2(File.expand_path("../data/victim#{b}", __FILE__)) do |i, o, t|
16
- main_ra = Integer(o.readline)
17
- libc_path = nil
18
- IO.readlines("/proc/#{t.pid}/maps").map(&:split).each do |s|
46
+ popen_victim(b) do |d, options|
47
+ main_ra = options[:main_ra]
48
+ realbase = nil
49
+ IO.readlines("/proc/#{options[:pid]}/maps").map(&:split).each do |s|
19
50
  st, ed = s[0].split('-').map { |x| x.to_i(16) }
20
51
  next unless main_ra.between?(st, ed)
21
- libc_path = s[-1]
52
+ realbase = st
22
53
  break
23
54
  end
24
- refute_nil(libc_path)
25
-
26
- # TODO(hh): Use ELF instead of objdump
27
- # Methods in libc might have multi-versions, so we record and check if
28
- # we can find one of them.
29
- h = Hash.new { |hsh, key| hsh[key] = [] }
30
- symbols = `objdump -T #{libc_path}`.lines.map(&:split).select { |a| a[2] == 'DF' }
31
- symbols.map { |a| h[a[-1]] << a[0].to_i(16) }
32
-
33
- mem = open("/proc/#{t.pid}/mem", 'rb')
34
- d = ::Pwnlib::DynELF.new(main_ra) do |addr|
35
- mem.seek(addr)
36
- mem.getc
37
- end
55
+ refute_nil(realbase)
56
+ assert_equal(realbase, d.libbase)
57
+ end
58
+ end
59
+ end
38
60
 
61
+ def test_lookup
62
+ [32, 64].each do |b|
63
+ popen_victim(b) do |d, options|
39
64
  assert_nil(d.lookup('pipi_hao_wei!'))
40
- h.each do |sym, off|
41
- assert_includes(off, d.lookup(sym) - d.libbase)
65
+ elf = ELF.new(options[:libc], checksec: false)
66
+ %i(system open read write execve printf puts sprintf mmap mprotect).each do |sym|
67
+ assert_equal(d.libbase + elf.symbols[sym], d.lookup(sym))
42
68
  end
69
+ end
70
+ end
71
+ end
43
72
 
44
- i.write('bye')
73
+ def test_build_id
74
+ [
75
+ [32, 'ac333186c6b532511a68d16aca4c61422eb772da', 'i386'],
76
+ [64, '088a6e00a1814622219f346b41e775b8dd46c518', 'amd64']
77
+ ].each do |b, answer, arch|
78
+ context.local(arch: arch) do
79
+ popen_victim(b) { |d| assert_equal(answer, d.build_id) }
45
80
  end
46
81
  end
47
82
  end
@@ -0,0 +1,120 @@
1
+ # encoding: ASCII-8BIT
2
+
3
+ require 'test_helper'
4
+
5
+ require 'pwnlib/elf/elf'
6
+ require 'pwnlib/logger'
7
+
8
+ class ELFTest < MiniTest::Test
9
+ include ::Pwnlib::Logger
10
+
11
+ def setup
12
+ @path_of = ->(file) { File.join(__dir__, '..', 'data', 'elfs', file) }
13
+ @elf = ::Pwnlib::ELF::ELF.new(@path_of.call('i386.prelro.elf'), checksec: false)
14
+ end
15
+
16
+ # check stdout when loaded
17
+ def test_load
18
+ file = @path_of.call('amd64.prelro.elf')
19
+ assert_output(<<-EOS) { log_stdout { ::Pwnlib::ELF::ELF.new(file) } }
20
+ [INFO] #{File.realpath(file).inspect}
21
+ RELRO: Partial RELRO
22
+ Stack: Canary found
23
+ NX: NX enabled
24
+ PIE: No PIE (0x400000)
25
+ EOS
26
+
27
+ file = @path_of.call('amd64.frelro.elf')
28
+ assert_output(<<-EOS) { log_stdout { ::Pwnlib::ELF::ELF.new(file) } }
29
+ [WARN] No REL.PLT section found, PLT not loaded
30
+ [INFO] #{File.realpath(file).inspect}
31
+ RELRO: Full RELRO
32
+ Stack: Canary found
33
+ NX: NX enabled
34
+ PIE: No PIE (0x400000)
35
+ EOS
36
+ end
37
+
38
+ def test_checksec
39
+ assert_equal(<<-EOS.strip, @elf.checksec)
40
+ RELRO: Partial RELRO
41
+ Stack: Canary found
42
+ NX: NX enabled
43
+ PIE: No PIE (0x8048000)
44
+ EOS
45
+
46
+ nrelro_elf = ::Pwnlib::ELF::ELF.new(@path_of.call('amd64.nrelro.elf'), checksec: false)
47
+ assert_equal(<<-EOS.strip, nrelro_elf.checksec)
48
+ RELRO: No RELRO
49
+ Stack: Canary found
50
+ NX: NX enabled
51
+ PIE: No PIE (0x400000)
52
+ EOS
53
+
54
+ frelro_elf = ::Pwnlib::ELF::ELF.new(@path_of.call('amd64.frelro.elf'), checksec: false)
55
+ assert_equal(<<-EOS.strip, frelro_elf.checksec)
56
+ RELRO: Full RELRO
57
+ Stack: Canary found
58
+ NX: NX enabled
59
+ PIE: No PIE (0x400000)
60
+ EOS
61
+ end
62
+
63
+ def test_got
64
+ assert_same(8, @elf.got.to_h.size)
65
+ assert_same(0x8049ff8, @elf.got['__gmon_start__'])
66
+ assert_same(0x8049ff8, @elf.got[:__gmon_start__])
67
+ assert_same(0x804a000, @elf.symbols['_GLOBAL_OFFSET_TABLE_'])
68
+ assert_same(0x804856d, @elf.symbols['main'])
69
+ assert_same(@elf.symbols.main, @elf.symbols[:main])
70
+ end
71
+
72
+ def test_plt
73
+ assert_same(6, @elf.plt.to_h.size)
74
+ assert_same(0x80483b0, @elf.plt.printf)
75
+ assert_same(0x80483f0, @elf.plt[:scanf])
76
+
77
+ elf = ::Pwnlib::ELF::ELF.new(@path_of.call('amd64.frelro.pie.elf'), checksec: false)
78
+ assert_nil(elf.plt)
79
+ end
80
+
81
+ def test_address
82
+ old_address = @elf.address
83
+ assert_equal(0x8048000, @elf.address)
84
+ old_main = @elf.symbols.main
85
+ new_address = 0x12340000
86
+ @elf.address = new_address
87
+ assert_equal(old_main - old_address + new_address, @elf.symbols.main)
88
+
89
+ elf = ::Pwnlib::ELF::ELF.new(@path_of.call('i386.frelro.pie.elf'), checksec: false)
90
+ assert_equal(0, elf.address)
91
+ assert_same(0x6c2, elf.symbols.main)
92
+ elf.address = 0xdeadbeef0000
93
+ # use 'equal' instead of 'same' because their +object_id+ are different on Windows.
94
+ assert_equal(0xdeadbeef06c2, elf.symbols.main)
95
+ end
96
+
97
+ def test_search
98
+ elf = ::Pwnlib::ELF::ELF.new(File.join(__dir__, '..', 'data', 'lib32', 'libc.so.6'), checksec: false)
99
+ assert_equal([0x1, 0x15e613], elf.search('ELF').to_a)
100
+ assert_equal(0x15900b, elf.find('/bin/sh').next)
101
+
102
+ result = elf.find(/E.F/)
103
+ assert_equal(0x1, result.next)
104
+ assert_equal(0xc8efa, result.next)
105
+ assert_equal(0xc9118, result.next)
106
+ assert_equal(0x158284, result.next)
107
+ assert_equal(0x158285, result.next)
108
+
109
+ elf.address = 0x1234000
110
+ assert_equal([0x1234001, 0x1392613], elf.search('ELF').to_a)
111
+ assert_equal(0x138d00b, elf.find('/bin/sh').next)
112
+ end
113
+
114
+ def log_stdout
115
+ old = log.instance_variable_get(:@logdev)
116
+ log.instance_variable_set(:@logdev, $stdout)
117
+ yield
118
+ log.instance_variable_set(:@logdev, old)
119
+ end
120
+ end