pwntools 0.1.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (168) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +96 -15
  3. data/Rakefile +8 -2
  4. data/lib/pwn.rb +10 -7
  5. data/lib/pwnlib/abi.rb +61 -0
  6. data/lib/pwnlib/asm.rb +357 -0
  7. data/lib/pwnlib/constants/constant.rb +19 -3
  8. data/lib/pwnlib/constants/constants.rb +46 -20
  9. data/lib/pwnlib/constants/linux/amd64.rb +32 -1
  10. data/lib/pwnlib/constants/linux/i386.rb +2 -0
  11. data/lib/pwnlib/context.rb +128 -27
  12. data/lib/pwnlib/dynelf.rb +122 -54
  13. data/lib/pwnlib/elf/elf.rb +340 -0
  14. data/lib/pwnlib/errors.rb +31 -0
  15. data/lib/pwnlib/ext/array.rb +2 -1
  16. data/lib/pwnlib/ext/helper.rb +6 -5
  17. data/lib/pwnlib/ext/integer.rb +2 -1
  18. data/lib/pwnlib/ext/string.rb +3 -2
  19. data/lib/pwnlib/logger.rb +245 -0
  20. data/lib/pwnlib/memleak.rb +59 -29
  21. data/lib/pwnlib/pwn.rb +27 -9
  22. data/lib/pwnlib/reg_sort.rb +109 -110
  23. data/lib/pwnlib/runner.rb +53 -0
  24. data/lib/pwnlib/shellcraft/generators/amd64/common/common.rb +16 -0
  25. data/lib/pwnlib/shellcraft/generators/amd64/common/infloop.rb +24 -0
  26. data/lib/pwnlib/shellcraft/generators/amd64/common/memcpy.rb +35 -0
  27. data/lib/pwnlib/shellcraft/generators/amd64/common/mov.rb +131 -0
  28. data/lib/pwnlib/shellcraft/generators/amd64/common/nop.rb +18 -0
  29. data/lib/pwnlib/shellcraft/generators/amd64/common/popad.rb +28 -0
  30. data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr.rb +66 -0
  31. data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr_array.rb +24 -0
  32. data/lib/pwnlib/shellcraft/generators/amd64/common/ret.rb +33 -0
  33. data/lib/pwnlib/shellcraft/generators/amd64/common/setregs.rb +24 -0
  34. data/lib/pwnlib/shellcraft/generators/amd64/linux/cat.rb +24 -0
  35. data/lib/pwnlib/shellcraft/generators/amd64/linux/execve.rb +24 -0
  36. data/lib/pwnlib/shellcraft/generators/amd64/linux/exit.rb +24 -0
  37. data/lib/pwnlib/shellcraft/generators/amd64/linux/linux.rb +16 -0
  38. data/lib/pwnlib/shellcraft/generators/amd64/linux/ls.rb +24 -0
  39. data/lib/pwnlib/shellcraft/generators/amd64/linux/open.rb +24 -0
  40. data/lib/pwnlib/shellcraft/generators/amd64/linux/sh.rb +24 -0
  41. data/lib/pwnlib/shellcraft/generators/amd64/linux/sleep.rb +24 -0
  42. data/lib/pwnlib/shellcraft/generators/amd64/linux/syscall.rb +24 -0
  43. data/lib/pwnlib/shellcraft/generators/helper.rb +115 -0
  44. data/lib/pwnlib/shellcraft/generators/i386/common/common.rb +16 -0
  45. data/lib/pwnlib/shellcraft/generators/i386/common/infloop.rb +24 -0
  46. data/lib/pwnlib/shellcraft/generators/i386/common/memcpy.rb +34 -0
  47. data/lib/pwnlib/shellcraft/generators/i386/common/mov.rb +93 -0
  48. data/lib/pwnlib/shellcraft/generators/i386/common/nop.rb +18 -0
  49. data/lib/pwnlib/shellcraft/generators/i386/common/pushstr.rb +41 -0
  50. data/lib/pwnlib/shellcraft/generators/i386/common/pushstr_array.rb +24 -0
  51. data/lib/pwnlib/shellcraft/generators/i386/common/setregs.rb +24 -0
  52. data/lib/pwnlib/shellcraft/generators/i386/linux/cat.rb +24 -0
  53. data/lib/pwnlib/shellcraft/generators/i386/linux/execve.rb +24 -0
  54. data/lib/pwnlib/shellcraft/generators/i386/linux/exit.rb +24 -0
  55. data/lib/pwnlib/shellcraft/generators/i386/linux/linux.rb +16 -0
  56. data/lib/pwnlib/shellcraft/generators/i386/linux/ls.rb +24 -0
  57. data/lib/pwnlib/shellcraft/generators/i386/linux/open.rb +24 -0
  58. data/lib/pwnlib/shellcraft/generators/i386/linux/sh.rb +24 -0
  59. data/lib/pwnlib/shellcraft/generators/i386/linux/sleep.rb +24 -0
  60. data/lib/pwnlib/shellcraft/generators/i386/linux/syscall.rb +24 -0
  61. data/lib/pwnlib/shellcraft/generators/x86/common/common.rb +29 -0
  62. data/lib/pwnlib/shellcraft/generators/x86/common/infloop.rb +24 -0
  63. data/lib/pwnlib/shellcraft/generators/x86/common/memcpy.rb +17 -0
  64. data/lib/pwnlib/shellcraft/generators/x86/common/mov.rb +17 -0
  65. data/lib/pwnlib/shellcraft/generators/x86/common/pushstr.rb +17 -0
  66. data/lib/pwnlib/shellcraft/generators/x86/common/pushstr_array.rb +86 -0
  67. data/lib/pwnlib/shellcraft/generators/x86/common/setregs.rb +84 -0
  68. data/lib/pwnlib/shellcraft/generators/x86/linux/cat.rb +54 -0
  69. data/lib/pwnlib/shellcraft/generators/x86/linux/execve.rb +72 -0
  70. data/lib/pwnlib/shellcraft/generators/x86/linux/exit.rb +34 -0
  71. data/lib/pwnlib/shellcraft/generators/x86/linux/linux.rb +16 -0
  72. data/lib/pwnlib/shellcraft/generators/x86/linux/ls.rb +67 -0
  73. data/lib/pwnlib/shellcraft/generators/x86/linux/open.rb +47 -0
  74. data/lib/pwnlib/shellcraft/generators/x86/linux/sh.rb +53 -0
  75. data/lib/pwnlib/shellcraft/generators/x86/linux/sleep.rb +52 -0
  76. data/lib/pwnlib/shellcraft/generators/x86/linux/syscall.rb +52 -0
  77. data/lib/pwnlib/shellcraft/registers.rb +148 -0
  78. data/lib/pwnlib/shellcraft/shellcraft.rb +73 -0
  79. data/lib/pwnlib/timer.rb +67 -0
  80. data/lib/pwnlib/tubes/buffer.rb +99 -0
  81. data/lib/pwnlib/tubes/process.rb +155 -0
  82. data/lib/pwnlib/tubes/serialtube.rb +114 -0
  83. data/lib/pwnlib/tubes/sock.rb +101 -0
  84. data/lib/pwnlib/tubes/tube.rb +442 -0
  85. data/lib/pwnlib/ui.rb +21 -0
  86. data/lib/pwnlib/util/cyclic.rb +97 -94
  87. data/lib/pwnlib/util/fiddling.rb +288 -220
  88. data/lib/pwnlib/util/getdents.rb +85 -0
  89. data/lib/pwnlib/util/hexdump.rb +116 -112
  90. data/lib/pwnlib/util/lists.rb +58 -0
  91. data/lib/pwnlib/util/packing.rb +223 -228
  92. data/lib/pwnlib/util/ruby.rb +19 -0
  93. data/lib/pwnlib/version.rb +3 -1
  94. data/test/abi_test.rb +22 -0
  95. data/test/asm_test.rb +177 -0
  96. data/test/constants/constant_test.rb +2 -0
  97. data/test/constants/constants_test.rb +5 -2
  98. data/test/context_test.rb +14 -3
  99. data/test/data/assembly/aarch64.s +19 -0
  100. data/test/data/assembly/amd64.s +21 -0
  101. data/test/data/assembly/arm.s +9 -0
  102. data/test/data/assembly/i386.s +21 -0
  103. data/test/data/assembly/mips.s +16 -0
  104. data/test/data/assembly/mips64.s +6 -0
  105. data/test/data/assembly/powerpc.s +18 -0
  106. data/test/data/assembly/powerpc64.s +36 -0
  107. data/test/data/assembly/sparc.s +33 -0
  108. data/test/data/assembly/sparc64.s +5 -0
  109. data/test/data/assembly/thumb.s +37 -0
  110. data/test/data/echo.rb +16 -0
  111. data/test/data/elfs/Makefile +24 -0
  112. data/test/data/elfs/amd64.frelro.elf +0 -0
  113. data/test/data/elfs/amd64.frelro.pie.elf +0 -0
  114. data/test/data/elfs/amd64.nrelro.elf +0 -0
  115. data/test/data/elfs/amd64.prelro.elf +0 -0
  116. data/test/data/elfs/amd64.static.elf +0 -0
  117. data/test/data/elfs/i386.frelro.pie.elf +0 -0
  118. data/test/data/elfs/i386.prelro.elf +0 -0
  119. data/test/data/elfs/source.cpp +19 -0
  120. data/test/data/flag +1 -0
  121. data/test/data/lib32/ld.so.2 +0 -0
  122. data/test/data/lib32/libc.so.6 +0 -0
  123. data/test/data/lib64/ld.so.2 +0 -0
  124. data/test/data/lib64/libc.so.6 +0 -0
  125. data/test/dynelf_test.rb +62 -25
  126. data/test/elf/elf_test.rb +147 -0
  127. data/test/ext_test.rb +4 -2
  128. data/test/files/use_pwn.rb +3 -6
  129. data/test/files/use_pwnlib.rb +2 -1
  130. data/test/full_file_test.rb +6 -0
  131. data/test/logger_test.rb +120 -0
  132. data/test/memleak_test.rb +5 -33
  133. data/test/reg_sort_test.rb +4 -1
  134. data/test/runner_test.rb +32 -0
  135. data/test/shellcraft/infloop_test.rb +27 -0
  136. data/test/shellcraft/linux/cat_test.rb +87 -0
  137. data/test/shellcraft/linux/ls_test.rb +109 -0
  138. data/test/shellcraft/linux/sh_test.rb +120 -0
  139. data/test/shellcraft/linux/sleep_test.rb +68 -0
  140. data/test/shellcraft/linux/syscalls/execve_test.rb +137 -0
  141. data/test/shellcraft/linux/syscalls/exit_test.rb +57 -0
  142. data/test/shellcraft/linux/syscalls/open_test.rb +87 -0
  143. data/test/shellcraft/linux/syscalls/syscall_test.rb +84 -0
  144. data/test/shellcraft/memcpy_test.rb +50 -0
  145. data/test/shellcraft/mov_test.rb +99 -0
  146. data/test/shellcraft/nop_test.rb +27 -0
  147. data/test/shellcraft/popad_test.rb +30 -0
  148. data/test/shellcraft/pushstr_array_test.rb +92 -0
  149. data/test/shellcraft/pushstr_test.rb +109 -0
  150. data/test/shellcraft/registers_test.rb +33 -0
  151. data/test/shellcraft/ret_test.rb +31 -0
  152. data/test/shellcraft/setregs_test.rb +63 -0
  153. data/test/shellcraft/shellcraft_test.rb +30 -0
  154. data/test/test_helper.rb +61 -2
  155. data/test/timer_test.rb +42 -0
  156. data/test/tubes/buffer_test.rb +46 -0
  157. data/test/tubes/process_test.rb +105 -0
  158. data/test/tubes/serialtube_test.rb +162 -0
  159. data/test/tubes/sock_test.rb +68 -0
  160. data/test/tubes/tube_test.rb +320 -0
  161. data/test/ui_test.rb +18 -0
  162. data/test/util/cyclic_test.rb +3 -1
  163. data/test/util/fiddling_test.rb +12 -3
  164. data/test/util/getdents_test.rb +33 -0
  165. data/test/util/hexdump_test.rb +9 -10
  166. data/test/util/lists_test.rb +22 -0
  167. data/test/util/packing_test.rb +5 -3
  168. metadata +357 -37
@@ -0,0 +1,36 @@
1
+ # These tests are fetched from Capstone's test_ppc.c
2
+
3
+ # context: endian: big
4
+ # !skip asm
5
+ # PPC-64
6
+ 1000: 43 20 0c 07 bdnzla+ 0xc04
7
+ 1004: 41 56 7f 17 bdztla 4*cr5+eq, 0x7f14
8
+ # Inconsistent output between capstone3 and later versions, skip
9
+ ; 1008: 80 20 00 00 lwz r1, 0(0)
10
+ ; 100c: 80 3f 00 00 lwz r1, 0(r31)
11
+ 1008: 10 43 23 0e vpkpx v2, v3, v4
12
+ 100c: d0 44 00 80 stfs f2, 0x80(r4)
13
+ 1010: 4c 43 22 02 crand 2, 3, 4
14
+ 1014: 2d 03 00 80 cmpwi cr2, r3, 0x80
15
+ 1018: 7c 43 20 14 addc r2, r3, r4
16
+ 101c: 7c 43 20 93 mulhd. r2, r3, r4
17
+ 1020: 4f 20 00 21 bdnzlrl+
18
+ 1024: 4c c8 00 21 bgelrl- cr2
19
+ 1028: 40 82 00 14 bne 0x103c
20
+
21
+ # context: endian: big
22
+ # !skip disasm
23
+ # PPC-64
24
+ 1000: 43 20 0c 07 bdnzla+ 0xc04
25
+ 1004: 41 56 7f 17 bdztla 4*cr5+eq, 0x7f14
26
+ 1008: 80 20 00 00 lwz 1, 0(0)
27
+ 1010: 80 3f 00 00 lwz 1, 0(31)
28
+ 1014: 10 43 23 0e vpkpx 2, 3, 4
29
+ 1018: d0 44 00 80 stfs 2, 0x80(4)
30
+ 101c: 4c 43 22 02 crand 2, 3, 4
31
+ 1020: 2d 03 00 80 cmpwi cr2, 3, 0x80
32
+ 1024: 7c 43 20 14 addc 2, 3, 4
33
+ 1028: 7c 43 20 93 mulhd. 2, 3, 4
34
+ 102c: 4f 20 00 21 bdnzlrl+
35
+ 1030: 4c c8 00 21 bgelrl- cr2
36
+ 1034: 40 82 00 14 bne 0x1044
@@ -0,0 +1,33 @@
1
+ # These tests are fetched from Capstone's test_sparc.c
2
+
3
+ # !skip asm # because of keystone-engine/keystone#405
4
+ 1000: 80 a0 40 02 cmp %g1, %g2
5
+ 1004: 85 c2 60 08 jmpl %o1+8, %g2
6
+ 1008: 85 e8 20 01 restore %g0, 1, %g2
7
+ 100c: 81 e8 00 00 restore
8
+ 1010: 90 10 20 01 mov 1, %o0
9
+ 1014: d5 f6 10 16 casx [%i0], %l6, %o2
10
+ 1018: 21 00 00 0a sethi 0xa, %l0
11
+ 101c: 86 00 40 02 add %g1, %g2, %g3
12
+ 1020: 01 00 00 00 nop
13
+ 1024: 12 bf ff ff bne 0x1020
14
+ 1028: 10 bf ff ff ba 0x1024
15
+ 102c: a0 02 00 09 add %o0, %o1, %l0
16
+ 1030: 0d bf ff ff fbg 0x102c
17
+ 1034: d4 20 40 00 st %o2, [%g1]
18
+ 1038: d4 4e 00 16 ldsb [%i0+%l6], %o2
19
+ # The output between objdump/llvm/capstone is inconsistent
20
+ ; 103c: 2a c2 80 03 brnz,a,pn %o2, 0x1048
21
+
22
+ # Copied from above, ignored branch instructions
23
+ 1000: 80 a0 40 02 cmp %g1, %g2
24
+ 1004: 85 e8 20 01 restore %g0, 1, %g2
25
+ 1008: 81 e8 00 00 restore
26
+ 100c: 90 10 20 01 mov 1, %o0
27
+ 1010: d5 f6 10 16 casx [%i0], %l6, %o2
28
+ 1014: 21 00 00 0a sethi 0xa, %l0
29
+ 1018: 86 00 40 02 add %g1, %g2, %g3
30
+ 101c: 01 00 00 00 nop
31
+ 1020: a0 02 00 09 add %o0, %o1, %l0
32
+ 1024: d4 20 40 00 st %o2, [%g1]
33
+ 1028: d4 4e 00 16 ldsb [%i0+%l6], %o2
@@ -0,0 +1,5 @@
1
+ # These tests are fetched from Capstone's test_sparc.c
2
+ 1000: 81 a8 0a 24 fcmps %f0, %f4
3
+ 1004: 89 a0 10 20 fstox %f0, %f4
4
+ 1008: 89 a0 1a 60 fqtoi %f0, %f4
5
+ 100c: 89 a0 00 e0 fnegq %f0, %f4
@@ -0,0 +1,37 @@
1
+ # These tests are fetched from Capstone's test_arm.c
2
+ # Thumb
3
+ # PC-relative instructions are buggy in Capstone3, two lines are commented.
4
+ 80001000: 60 f9 1f 04 vld3.8 {d16, d17, d18}, [r0:0x40]
5
+ 80001004: e0 f9 4f 07 vld4.16 {d16[1], d17[1], d18[1], d19[1]}, [r0]
6
+ 80001008: 70 47 bx lr
7
+ ; 8000100a: 00 f0 10 e8 blx #0x8000102c
8
+ 8000100a: eb 46 mov fp, sp
9
+ 8000100c: 83 b0 sub sp, #0xc
10
+ 8000100e: c9 68 ldr r1, [r1, #0xc]
11
+ ; 80001010: 1f b1 cbz r7, #0x8000101e
12
+ 80001010: 30 bf wfi
13
+ 80001012: af f3 20 84 cpsie.w f
14
+ 80001016: 52 f8 23 f0 ldr.w pc, [r2, r3, lsl #2]
15
+
16
+ # Thumb-mixed
17
+ 80001000: d1 e8 00 f0 tbb [r1, r0]
18
+ 80001004: f0 24 movs r4, #0xf0
19
+ 80001006: 04 07 lsls r4, r0, #0x1c
20
+ 80001008: 1f 3c subs r4, #0x1f
21
+ 8000100a: f2 c0 stm r0!, {r1, r4, r5, r6, r7}
22
+ 8000100c: 00 00 movs r0, r0
23
+ 8000100e: 4f f0 00 01 mov.w r1, #0
24
+ 80001012: 46 6c ldr r6, [r0, #0x44]
25
+
26
+ # Thumb-2 & register named with numbers
27
+ # An `iteet` instruction is removed to make the `it` instruction valid
28
+ 80001000: 4f f0 00 01 mov.w r1, #0
29
+ 80001004: bd e8 00 88 pop.w {fp, pc}
30
+ 80001008: d1 e8 00 f0 tbb [r1, r0]
31
+ 8000100c: 18 bf it ne
32
+ ; 8000100e: ad bf iteet ge
33
+ 8000100e: f3 ff 0b 0c vdupne.8 d16, d11[1]
34
+ 80001012: 86 f3 00 89 msr cpsr_fc, r6
35
+ 80001016: 80 f3 00 8c msr apsr_nzcvqg, r0
36
+ 8000101a: 4f fa 99 f6 sxtb.w r6, sb, ror #8
37
+ 8000101e: d0 ff a2 01 vaddw.u16 q8, q8, d18
data/test/data/echo.rb ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'socket'
5
+
6
+ server = TCPServer.open('127.0.0.1', 0)
7
+
8
+ $stdout.puts "Start with port #{server.addr[1]}"
9
+ $stdout.flush
10
+
11
+ client = server.accept
12
+ s = client.gets
13
+ client.puts(s)
14
+ client.close
15
+
16
+ $stdout.puts 'Bye!'
@@ -0,0 +1,24 @@
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
+ STATIC_FLAGS=-static
9
+ TARGETS=amd64 i386
10
+ .PHONY: clean
11
+ all: ${TARGETS}
12
+
13
+ amd64: ${source}
14
+ g++ -m64 ${source} -o amd64.frelro.elf ${FLAGS} ${FULL_RELRO_FLAGS} ${NOPIE_FLAGS}
15
+ g++ -m64 ${source} -o amd64.frelro.pie.elf ${FLAGS} ${FULL_RELRO_FLAGS} ${PIE_FLAGS}
16
+ g++ -m64 ${source} -o amd64.prelro.elf ${FLAGS} ${PARTIAL_RELRO_FLAGS} ${NOPIE_FLAGS}
17
+ g++ -m64 ${source} -o amd64.nrelro.elf ${FLAGS} ${NO_RELRO_FLAGS} ${NOPIE_FLAGS}
18
+ g++ -m64 ${source} -o amd64.static.elf ${FLAGS} ${STATIC_FLAGS} ${NOPIE_FLAGS}
19
+ i386: ${source}
20
+ g++ -m32 ${source} -o i386.prelro.elf ${FLAGS} ${PARTIAL_RELRO_FLAGS} ${NOPIE_FLAGS}
21
+ g++ -m32 ${source} -o i386.frelro.pie.elf ${FLAGS} ${FULL_RELRO_FLAGS} ${PIE_FLAGS}
22
+
23
+ clean:
24
+ rm -f *.elf
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -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
+ }
data/test/data/flag ADDED
@@ -0,0 +1 @@
1
+ flag{pwntools_ruby}
Binary file
Binary file
Binary file
Binary file
data/test/dynelf_test.rb CHANGED
@@ -1,47 +1,84 @@
1
1
  # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'open3'
4
5
 
5
6
  require 'tty-platform'
6
7
 
7
8
  require 'test_helper'
9
+
10
+ require 'pwnlib/context'
8
11
  require 'pwnlib/dynelf'
12
+ require 'pwnlib/elf/elf'
9
13
 
10
14
  class DynELFTest < MiniTest::Test
11
- def test_lookup
12
- skip 'Only tested on linux' unless TTY::Platform.new.linux?
15
+ include ::Pwnlib
16
+ include ::Pwnlib::Context
17
+ include ::Pwnlib::ELF
18
+
19
+ def setup
20
+ linux_only
21
+ end
22
+
23
+ # popen victim with specific libc.so.6
24
+ def popen_victim(b)
25
+ lib_path = File.expand_path("data/lib#{b}/", __dir__)
26
+ libc_path = File.expand_path('libc.so.6', lib_path)
27
+ ld_path = File.expand_path('ld.so.2', lib_path)
28
+ victim_path = File.expand_path("data/victim#{b}", __dir__)
29
+
30
+ Open3.popen2("#{ld_path} --library-path #{lib_path} #{victim_path}") do |i, o, t|
31
+ main_ra = Integer(o.readline)
32
+ mem = open("/proc/#{t.pid}/mem", 'rb')
33
+ d = DynELF.new(main_ra) do |addr|
34
+ mem.seek(addr)
35
+ mem.getc
36
+ end
37
+
38
+ yield d, { libc: libc_path, main_ra: main_ra, pid: t.pid }
39
+
40
+ mem.close
41
+ i.write('bye')
42
+ end
43
+ end
44
+
45
+ def test_find_base
13
46
  [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|
47
+ popen_victim(b) do |d, options|
48
+ main_ra = options[:main_ra]
49
+ realbase = nil
50
+ IO.readlines("/proc/#{options[:pid]}/maps").map(&:split).each do |s|
19
51
  st, ed = s[0].split('-').map { |x| x.to_i(16) }
20
52
  next unless main_ra.between?(st, ed)
21
- libc_path = s[-1]
53
+
54
+ realbase = st
22
55
  break
23
56
  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
57
+ refute_nil(realbase)
58
+ assert_equal(realbase, d.libbase)
59
+ end
60
+ end
61
+ end
38
62
 
63
+ def test_lookup
64
+ [32, 64].each do |b|
65
+ popen_victim(b) do |d, options|
39
66
  assert_nil(d.lookup('pipi_hao_wei!'))
40
- h.each do |sym, off|
41
- assert_includes(off, d.lookup(sym) - d.libbase)
67
+ elf = ELF.new(options[:libc], checksec: false)
68
+ %i(system open read write execve printf puts sprintf mmap mprotect).each do |sym|
69
+ assert_equal(d.libbase + elf.symbols[sym], d.lookup(sym))
42
70
  end
71
+ end
72
+ end
73
+ end
43
74
 
44
- i.write('bye')
75
+ def test_build_id
76
+ [
77
+ [32, 'ac333186c6b532511a68d16aca4c61422eb772da', 'i386'],
78
+ [64, '088a6e00a1814622219f346b41e775b8dd46c518', 'amd64']
79
+ ].each do |b, answer, arch|
80
+ context.local(arch: arch) do
81
+ popen_victim(b) { |d| assert_equal(answer, d.build_id) }
45
82
  end
46
83
  end
47
84
  end
@@ -0,0 +1,147 @@
1
+ # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
3
+
4
+ require 'test_helper'
5
+
6
+ require 'pwnlib/context'
7
+ require 'pwnlib/elf/elf'
8
+ require 'pwnlib/logger'
9
+
10
+ class ELFTest < MiniTest::Test
11
+ include ::Pwnlib::Context
12
+
13
+ def setup
14
+ @path_of = ->(file) { File.join(__dir__, '..', 'data', 'elfs', file) }
15
+ @elf = to_elf_silent('i386.prelro.elf')
16
+ end
17
+
18
+ def to_elf_silent(filename)
19
+ log_null { ::Pwnlib::ELF::ELF.new(@path_of.call(filename), checksec: false) }
20
+ end
21
+
22
+ # check stdout when loaded
23
+ def test_load
24
+ file = @path_of.call('amd64.prelro.elf')
25
+ assert_output(<<-EOS) { log_stdout { ::Pwnlib::ELF::ELF.new(file) } }
26
+ [INFO] #{File.realpath(file).inspect}
27
+ RELRO: Partial RELRO
28
+ Stack: Canary found
29
+ NX: NX enabled
30
+ PIE: No PIE (0x400000)
31
+ EOS
32
+
33
+ file = @path_of.call('amd64.frelro.elf')
34
+ assert_output(<<-EOS) { log_stdout { ::Pwnlib::ELF::ELF.new(file) } }
35
+ [WARN] No REL.PLT section found, PLT not loaded
36
+ [INFO] #{File.realpath(file).inspect}
37
+ RELRO: Full RELRO
38
+ Stack: Canary found
39
+ NX: NX enabled
40
+ PIE: No PIE (0x400000)
41
+ EOS
42
+ end
43
+
44
+ def test_checksec
45
+ assert_equal(<<-EOS.strip, @elf.checksec)
46
+ RELRO: Partial RELRO
47
+ Stack: Canary found
48
+ NX: NX enabled
49
+ PIE: No PIE (0x8048000)
50
+ EOS
51
+
52
+ nrelro_elf = to_elf_silent('amd64.nrelro.elf')
53
+ assert_equal(<<-EOS.strip, nrelro_elf.checksec)
54
+ RELRO: No RELRO
55
+ Stack: Canary found
56
+ NX: NX enabled
57
+ PIE: No PIE (0x400000)
58
+ EOS
59
+
60
+ frelro_elf = to_elf_silent('amd64.frelro.elf')
61
+ assert_equal(<<-EOS.strip, frelro_elf.checksec)
62
+ RELRO: Full RELRO
63
+ Stack: Canary found
64
+ NX: NX enabled
65
+ PIE: No PIE (0x400000)
66
+ EOS
67
+ end
68
+
69
+ def test_inspect
70
+ assert_match(/#<Pwnlib::ELF::ELF:0x[0-9a-f]+>/, @elf.inspect)
71
+ end
72
+
73
+ def test_got
74
+ assert_same(8, @elf.got.to_h.size)
75
+ assert_same(0x8049ff8, @elf.got['__gmon_start__'])
76
+ assert_same(0x8049ff8, @elf.got[:__gmon_start__])
77
+ assert_same(0x804a000, @elf.symbols['_GLOBAL_OFFSET_TABLE_'])
78
+ assert_same(0x804856d, @elf.symbols['main'])
79
+ assert_same(@elf.symbols.main, @elf.symbols[:main])
80
+ end
81
+
82
+ def test_plt
83
+ assert_same(6, @elf.plt.to_h.size)
84
+ assert_same(0x80483b0, @elf.plt.printf)
85
+ assert_same(0x80483f0, @elf.plt[:scanf])
86
+
87
+ elf = to_elf_silent('amd64.frelro.pie.elf')
88
+ assert_nil(elf.plt)
89
+ end
90
+
91
+ def test_address
92
+ old_address = @elf.address
93
+ assert_equal(0x8048000, @elf.address)
94
+ old_main = @elf.symbols.main
95
+ new_address = 0x12340000
96
+ @elf.address = new_address
97
+ assert_equal(old_main - old_address + new_address, @elf.symbols.main)
98
+
99
+ elf = to_elf_silent('i386.frelro.pie.elf')
100
+ assert_equal(0, elf.address)
101
+ assert_same(0x6c2, elf.symbols.main)
102
+ elf.address = 0xdeadbeef0000
103
+ # use 'equal' instead of 'same' because their +object_id+ are different on Windows.
104
+ assert_equal(0xdeadbeef06c2, elf.symbols.main)
105
+ end
106
+
107
+ def test_static
108
+ elf = to_elf_silent('amd64.static.elf')
109
+ assert_equal(<<-EOS.strip, elf.checksec)
110
+ RELRO: Partial RELRO
111
+ Stack: Canary found
112
+ NX: NX enabled
113
+ PIE: No PIE (0x400000)
114
+ EOS
115
+ end
116
+
117
+ def test_search
118
+ elf = ::Pwnlib::ELF::ELF.new(File.join(__dir__, '..', 'data', 'lib32', 'libc.so.6'), checksec: false)
119
+ assert_equal([0x1, 0x15e613], elf.search('ELF').to_a)
120
+ assert_equal(0x15900b, elf.find('/bin/sh').next)
121
+
122
+ result = elf.find(/E.F/)
123
+ assert_equal(0x1, result.next)
124
+ assert_equal(0xc8efa, result.next)
125
+ assert_equal(0xc9118, result.next)
126
+ assert_equal(0x158284, result.next)
127
+ assert_equal(0x158285, result.next)
128
+
129
+ elf.address = 0x1234000
130
+ assert_equal([0x1234001, 0x1392613], elf.search('ELF').to_a)
131
+ assert_equal(0x138d00b, elf.find('/bin/sh').next)
132
+ end
133
+
134
+ def test_one_gadgets
135
+ libc = ::Pwnlib::ELF::ELF.new(File.join(__dir__, '..', 'data', 'lib64', 'libc.so.6'), checksec: false)
136
+ # Well.. one_gadget(s) may change in the future, so we just check the return type
137
+ val = libc.one_gadgets.first
138
+ assert(val.is_a?(Integer))
139
+ assert_equal(libc.one_gadgets[0], val)
140
+ assert_equal(libc.one_gadgets[-1], libc.one_gadgets.last)
141
+
142
+ libc.address = 0xdeadf000
143
+ assert_equal(0xdeadf000 + val, libc.one_gadgets[0])
144
+
145
+ assert_output(/execve/) { log_stdout { context.local(log_level: :debug) { libc.one_gadgets[0] } } }
146
+ end
147
+ end