rubypwn 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/lib/elf.rb +385 -0
  3. data/lib/rubypwn.rb +1 -0
  4. data/rubypwn.gemspec +3 -2
  5. metadata +23 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c971c49d84a195546eef55c5d6ac4f3ee330e144
4
- data.tar.gz: 8285028c5c3d82b5d80226b5ce6dc004dacb8640
3
+ metadata.gz: 6dfb84772404f79d5f5175659ca307d2cbed9fb7
4
+ data.tar.gz: bf8ebf7647eae29666a1d07e2ec0e0cf950ca0cd
5
5
  SHA512:
6
- metadata.gz: 8e07081584165b4975eeb3b3d0a2c4cbf40bc18f9e2764c849d5c6b7553650be7299cb0235966cc0591b8dfd1e9032a54b4d8085d87da14d685dbd7404bc6cc1
7
- data.tar.gz: 3aa45a8112a9f59c737d90279f8ea4bfda1549f1c3271eeb957bb37e1b57a32c676154a5010cd0ade1ec4bf21db41887ab9b0d610a9cf2e3f848ec3e16e62f0a
6
+ metadata.gz: 7a231f3caf7f2fc28d1c026aa21ceab34fc6522aaa7940de76487438f82180fae2c35a47f2a14df3e6af391ff9ae3193c0869b09b643593f30a087ca792b7743
7
+ data.tar.gz: 1166e8c4abfe7d6269750398890e3da74ed0c0045069d1e58ccde16cbbf73d5903cc0b9c2ba83056339adf4589d960415ef02979ec7c7ade7ab58991a1dabfbe
data/lib/elf.rb ADDED
@@ -0,0 +1,385 @@
1
+ require 'bindata'
2
+
3
+ class Symtab32 < BinData::Record
4
+ endian :little
5
+ int32 :st_name #/* Symbol name (string tbl index) */
6
+ int32 :st_value #/* Symbol value */
7
+ int32 :st_size #/* Symbol size */
8
+ int8 :st_info #/* Symbol type and binding */
9
+ int8 :st_other #/* Symbol visibility */
10
+ int16 :st_shndx #/* Section index */
11
+ string :name_str
12
+ end
13
+
14
+ class Symtab64 < BinData::Record
15
+ endian :little
16
+ int32 :st_name #/* Symbol name (string tbl index) */
17
+ int8 :st_info #/* Symbol type and binding */
18
+ int8 :st_other #/* Symbol visibility */
19
+ int16 :st_shndx #/* Section index */
20
+ int64 :st_value #/* Symbol value */
21
+ int64 :st_size #/* Symbol size */
22
+ string :name_str
23
+ end
24
+
25
+ class Relplt32 < BinData::Record
26
+ endian :little
27
+ uint32 :r_offset
28
+ uint32 :r_info
29
+ string :sym_index, :value => lambda{parse_sym_index(r_info)}
30
+ string :type, :value => lambda{parse_type(r_info)}
31
+
32
+ def parse_sym_index(r_info)
33
+ r_info >> 8
34
+ end
35
+
36
+ def parse_type(r_info)
37
+ r_info & 0xff
38
+ end
39
+ end
40
+
41
+ class Relplt64 < BinData::Record
42
+ endian :little
43
+ uint64 :r_offset
44
+ int64 :r_info
45
+ string :sym_index, :value => lambda{parse_sym_index(r_info)}
46
+ string :type, :value => lambda{parse_type(r_info)}
47
+
48
+ def parse_sym_index(r_info)
49
+ r_info >> 32
50
+ end
51
+
52
+ def parse_type(r_info)
53
+ r_info & 0xffffffff
54
+ end
55
+ end
56
+
57
+ class Relaplt32 < BinData::Record
58
+ endian :little
59
+ uint32 :r_offset
60
+ int32 :r_info
61
+ int32 :r_addend
62
+ string :sym_index, :value => lambda{parse_sym_index(r_info)}
63
+ string :type, :value => lambda{parse_type(r_info)}
64
+
65
+ def parse_sym_index(r_info)
66
+ r_info >> 8
67
+ end
68
+
69
+ def parse_type(r_info)
70
+ r_info & 0xff
71
+ end
72
+ end
73
+
74
+ class Relaplt64 < BinData::Record
75
+ endian :little
76
+ uint64 :r_offset
77
+ int64 :r_info
78
+ int64 :r_addend
79
+ string :sym_index, :value => lambda{parse_sym_index(r_info)}
80
+ string :type, :value => lambda{parse_type(r_info)}
81
+
82
+ def parse_sym_index(r_info)
83
+ r_info >> 32
84
+ end
85
+
86
+ def parse_type(r_info)
87
+ r_info & 0xffffffff
88
+ end
89
+ end
90
+ class ElfParser < BinData::Record
91
+ endian :little
92
+ # magic number
93
+ string :magic, :read_length => 4
94
+ struct :e_ident do
95
+ # 32bits or 64bits
96
+ int8 :ei_class
97
+ int8 :ei_data
98
+ int8 :ei_version
99
+ int8 :ei_osabi
100
+ int8 :ei_abiversion
101
+ # unused
102
+ string :ei_pad, :read_length => 7
103
+ end
104
+ int16 :e_type
105
+ # Arch
106
+ int16 :e_machine
107
+ int32 :e_version
108
+ # This is the memory address of the entry point from where the process starts executing. This field is either 32 or 64 bits long depending on the format defined earlier.
109
+ choice :e_entry, :selection => lambda{e_ident.ei_class}, :choices => {1 => :int32, 2 => :int64}
110
+ # Points to the start of the program header table. It usually follows the fi header immediately making the offset 0x40 for 64-bit ELF executables.
111
+ choice :e_phoff, :selection => lambda{e_ident.ei_class}, :choices => {1 => :uint32, 2 => :uint64}
112
+ # Points to the start of the section header table.
113
+ choice :e_shoff, :selection => lambda{e_ident.ei_class}, :choices => {1 => :uint32, 2 => :uint64}
114
+ # Interpretation of this field depends on the target architecture.
115
+ int32 :e_flags
116
+ # Contains the size of this header, normally 64 bytes for 64-bit and 52 for 32-bit format.
117
+ int16 :e_ehsize
118
+ # Contains the size of a program header tab entry.
119
+ int16 :e_phentsize
120
+ # Contains the number of entries in the program header table.
121
+ int16 :e_phnum
122
+ # Contains the size of a section header tab entry.
123
+ int16 :e_shentsize
124
+ # Contains the number of entries in the section header table.
125
+ int16 :e_shnum
126
+ # Section header string table index
127
+ int16 :e_shstrndx
128
+ skip :length => lambda{e_shoff - e_ehsize}
129
+ # Program header table
130
+ #array :ph, :initial_length => :e_phnum do
131
+ #int32 :p_type
132
+ ## Segment bit mask (RWX)
133
+ #int32 :p_flags
134
+ ## Segment file offset
135
+ #choice :p_offset, :selection => lambda{e_ident.ei_class}, :choices => {1 => :int32le, 2 => :int64le}
136
+ ## Segment virtual address
137
+ #choice :p_vaddr, :selection => lambda{e_ident.ei_class}, :choices => {1 => :int32le, 2 => :int64le}
138
+ ## Segment physical address
139
+ #choice :p_paddr, :selection => lambda{e_ident.ei_class}, :choices => {1 => :int32le, 2 => :int64le}
140
+ ## Segment size in file
141
+ #choice :p_filesz, :selection => lambda{e_ident.ei_class}, :choices => {1 => :int32le, 2 => :int64le}
142
+ ## Segment size in memory
143
+ #choice :p_memsz, :selection => lambda{e_ident.ei_class}, :choices => {1 => :int32le, 2 => :int64le}
144
+ ## Segment alignment
145
+ #choice :p_align, :selection => lambda{e_ident.ei_class}, :choices => {1 => :int32le, 2 => :int64le}
146
+ ##string :p_segment, :read_length => lambda{p_filesz - e_phentsize}
147
+ #end
148
+ # Contains index of the section header tab entry that contains the section names.
149
+ array :sh, :initial_length => lambda{e_shnum} do
150
+ # Section name (string tbl index)
151
+ int32 :sh_name
152
+ int32 :sh_type
153
+ choice :sh_flags, :selection => lambda{e_ident.ei_class}, :choices => {1 => :int32, 2 => :int64}
154
+ # Section virtual addr at execution
155
+ choice :sh_addr, :selection => lambda{e_ident.ei_class}, :choices => {1 => :int32, 2 => :int64}
156
+ # Section file offset
157
+ choice :sh_offset, :selection => lambda{e_ident.ei_class}, :choices => {1 => :uint32, 2 => :uint64}
158
+ # Section size in bytes
159
+ choice :sh_size, :selection => lambda{e_ident.ei_class}, :choices => {1 => :int32, 2 => :int64}
160
+ # Link to another section
161
+ int32 :sh_link
162
+ int32 :sh_info
163
+ # Section alignment
164
+ choice :sh_addralign, :selection => lambda{e_ident.ei_class}, :choices => {1 => :int32, 2 => :int64}
165
+ # Entry size if section holds table
166
+ choice :sh_entsize, :selection => lambda{e_ident.ei_class}, :choices => {1 => :int32, 2 => :int64}
167
+ string :type_str, :value => lambda{parse_sh_type(sh_type)}
168
+ string :flag_str, :value => lambda{parse_sh_flags(sh_flags)}
169
+ string :name_str
170
+ end
171
+
172
+ ###########################
173
+ # User defined fields #
174
+ ###########################
175
+ int8 :bits, :value => lambda{parse_bits(e_ident.ei_class)}
176
+ string :arch, :value => lambda{parse_arch(e_machine)}
177
+ string :type, :value => lambda{parse_type(e_type)}
178
+ choice :symtab, :selection => lambda{e_ident.ei_class} do
179
+ array 1, :type => :symtab32, :initial_length => 0
180
+ array 2, :type => :symtab64, :initial_length => 0
181
+ end
182
+ choice :relplt, :selection => lambda{e_ident.ei_class} do
183
+ array 1, :type => :relplt32, :initial_length => 0
184
+ array 2, :type => :relplt64, :initial_length => 0
185
+ end
186
+ choice :relaplt, :selection => lambda{e_ident.ei_class} do
187
+ array 1, :type => :relaplt32, :initial_length => 0
188
+ array 2, :type => :relaplt64, :initial_length => 0
189
+ end
190
+
191
+ def parse_bits(ei_class)
192
+ ei_class == 1 ? 32 : 64
193
+ end
194
+
195
+ def parse_arch(e_machine)
196
+ machine = {
197
+ 0x02 => "SPARC",
198
+ 0x03 => "x86",
199
+ 0x08 => "MIPS",
200
+ 0x14 => "PowerPC",
201
+ 0x28 => "ARM",
202
+ 0x2a => "SuperH",
203
+ 0x32 => "IA64",
204
+ 0x3e => "x86-64",
205
+ 0xb7 => "AArch64",
206
+ }
207
+ machine[e_machine]
208
+ end
209
+
210
+ def parse_type(e_type)
211
+ type ={
212
+ 1 => "relocatable",
213
+ 2 => "executable",
214
+ 3 => "shared",
215
+ 4 => "core",
216
+ }
217
+ type[e_type]
218
+ end
219
+
220
+ def parse_sh_type(sh_type)
221
+ type = {
222
+ 0 => "NULL", # /* Section header table entry unused */
223
+ 1 => "PROGBITS", # /* Program data */
224
+ 2 => "SYMTAB", # /* Symbol table */
225
+ 3 => "STRTAB", # /* String table */
226
+ 4 => "RELA", # /* Relocation entries with addends */
227
+ 5 => "HASH", # /* Symbol hash table */
228
+ 6 => "DYNAMIC", # /* Dynamic linking information */
229
+ 7 => "NOTE", # /* Notes */
230
+ 8 => "NOBITS", # /* Program space with no data (bss) */
231
+ 9 => "REL", # /* Relocation entries, no addends */
232
+ 10 => "SHLIB", # /* Reserved */
233
+ 11 => "DYNSYM", # /* Dynamic linker symbol table */
234
+ 14 => "INIT_ARRAY", # /* Array of constructors */
235
+ 15 => "FINI_ARRAY", # /* Array of destructors */
236
+ 16 => "PREINIT_ARRAY", # /* Array of pre-constructors */
237
+ 17 => "GROUP", # /* Section group */
238
+ 18 => "SYMTAB_SHNDX", # /* Extended section indeces */
239
+ 19 => "NUM", # /* Number of defined types. */
240
+ 0x60000000 => "LOOS", # /* Start OS-specific. */
241
+ 0x6ffffff5 => "GNU_ATTRIBUTES", # /* Object attributes. */
242
+ 0x6ffffff6 => "GNU_HASH", # /* GNU-style hash table. */
243
+ 0x6ffffff7 => "GNU_LIBLIST", # /* Prelink library list */
244
+ 0x6ffffff8 => "CHECKSUM", # /* Checksum for DSO content. */
245
+ 0x6ffffffa => "SUNW_move", #
246
+ 0x6ffffffb => "SUNW_COMDAT", #
247
+ 0x6ffffffc => "SUNW_syminfo", #
248
+ 0x6ffffffd => "GNU_verdef", # /* Version definition section. */
249
+ 0x6ffffffe => "GNU_verneed", # /* Version needs section. */
250
+ 0x6fffffff => "GNU_versym", # /* Version symbol table. */
251
+ 0x70000000 => "LOPROC", # /* Start of processor-specific */
252
+ 0x7fffffff => "HIPROC", # /* End of processor-specific */
253
+ 0x80000000 => "LOUSER", # /* Start of application-specific */
254
+ 0x8fffffff => "HIUSER", # /* End of application-specific */
255
+ }
256
+ type[sh_type]
257
+ end
258
+
259
+ def parse_sh_flags(sh_flags)
260
+ flags = {
261
+ (1 << 0) => "WRITE", # /* Writable */
262
+ (1 << 1) => "ALLOC", # /* Occupies memory during execution */
263
+ (1 << 2) => "EXECINSTR", # /* Executable */
264
+ (1 << 4) => "MERGE", # /* Might be merged */
265
+ (1 << 5) => "STRINGS", # /* Contains nul-terminated strings */
266
+ (1 << 6) => "INFO_LINK", # /* `sh_info' contains SHT index */
267
+ (1 << 7) => "LINK_ORDER", # /* Preserve order after combining */
268
+ (1 << 8) => "OS_NONCONFORMING", # /* Non-standard OS specific handling required */
269
+ (1 << 9) => "GROUP", # /* Section is member of a group. */
270
+ (1 << 10) => "TLS", # /* Section hold thread-local data. */
271
+ 0x0ff00000 => "MASKOS", # /* OS-specific. */
272
+ 0xf0000000 => "MASKPROC", # /* Processor-specific */
273
+ (1 << 30) => "ORDERED", # /* Special ordering requirement (Solaris). */
274
+ (1 << 31) => "EXCLUDE", # /* Section is excluded unless referenced or allocated (Solaris).*/
275
+ }
276
+ result = []
277
+ flags.each do |k, v|
278
+ if (sh_flags & k) > 0
279
+ result.push v
280
+ end
281
+ end
282
+ result.join "|"
283
+ end
284
+ end
285
+
286
+ class Elf
287
+ attr_accessor :gotplt
288
+
289
+ def initialize(file)
290
+ # To avoid unicode
291
+ binary = File.read(file).force_encoding('binary')
292
+ # To fix bugs leading eof, that's why here is a newline ...
293
+ @elf = ElfParser.read binary + "\n"
294
+ # Section name assignment
295
+ assign_section_name binary, @elf
296
+ # parse symbol table
297
+ parse_symtab binary, @elf
298
+ # parse rel.plt
299
+ parse_relplt binary, @elf
300
+ @gotplt = gen_gotplt @elf
301
+ end
302
+
303
+ private
304
+ def assign_section_name(binary, elf)
305
+ strtab_offset = elf.sh[elf.e_shstrndx].sh_offset.to_i
306
+ strtab = binary[(strtab_offset)..-1]
307
+ elf.e_shnum.times do |i|
308
+ sh_name = elf.sh[i].sh_name.to_i
309
+ elf.sh[i].name_str.assign BinData::Stringz.read strtab[sh_name..-1]
310
+ end
311
+ end
312
+
313
+ def parse_symtab(binary, elf)
314
+ # find dynamic symtab
315
+ symtab = nil
316
+ elf.e_shnum.times do |i|
317
+ if elf.sh[i].name_str.to_s == ".dynsym"
318
+ size = elf.sh[i].sh_size/elf.sh[i].sh_entsize
319
+ if elf.e_ident[:ei_class] == 1
320
+ symtab = BinData::Array.new(:type => :symtab32, :initial_length => size)
321
+ else
322
+ symtab = BinData::Array.new(:type => :symtab64, :initial_length => size)
323
+ end
324
+ symtab = symtab.read binary[elf.sh[i].sh_offset, elf.sh[i].sh_size]
325
+ end
326
+ end
327
+
328
+ # find dynamic strtab
329
+ strtab = nil
330
+ elf.e_shnum.times do |i|
331
+ if elf.sh[i].name_str.to_s == ".dynstr"
332
+ strtab = binary[elf.sh[i].sh_offset, elf.sh[i].sh_size]
333
+ end
334
+ end
335
+
336
+ # find the name of dynamic symbol
337
+ symtab.size.times do |i|
338
+ symtab[i].name_str.assign BinData::Stringz.read strtab[symtab[i].st_name..-1]
339
+ end
340
+
341
+ elf.symtab.assign symtab
342
+ end
343
+
344
+ def parse_relplt(binary, elf)
345
+ relplt = nil
346
+ elf.e_shnum.times do |i|
347
+ if elf.sh[i].name_str.to_s == ".rel.plt"
348
+ size = elf.sh[i].sh_size/elf.sh[i].sh_entsize
349
+ if elf.e_ident[:ei_class] == 1
350
+ relplt = BinData::Array.new(:type => :relplt32, :initial_length => size)
351
+ else
352
+ relplt = BinData::Array.new(:type => :relplt64, :initial_length => size)
353
+ end
354
+ elf.relplt.assign relplt.read binary[elf.sh[i].sh_offset, elf.sh[i].sh_size]
355
+ elsif elf.sh[i].name_str.to_s == ".rela.plt"
356
+ size = elf.sh[i].sh_size/elf.sh[i].sh_entsize
357
+ if elf.e_ident[:ei_class] == 1
358
+ relplt = BinData::Array.new(:type => :relaplt32, :initial_length => size)
359
+ else
360
+ relplt = BinData::Array.new(:type => :relaplt64, :initial_length => size)
361
+ end
362
+ elf.relaplt.assign relplt.read binary[elf.sh[i].sh_offset, elf.sh[i].sh_size]
363
+ end
364
+ end
365
+ end
366
+
367
+ def gen_gotplt(elf)
368
+ result = {}
369
+ rel = nil
370
+ if elf.relplt.size > 0
371
+ rel = elf.relplt
372
+ elsif elf.relaplt.size > 0
373
+ rel = elf.relaplt
374
+ end
375
+
376
+ rel.each do |r|
377
+ result[elf.symtab[r.sym_index.to_i].name_str.to_s] = r.r_offset.to_i
378
+ end
379
+ result
380
+ end
381
+ end
382
+
383
+ #require 'pp'
384
+ #e = Elf.new ARGV[0]
385
+ #pp e.gotplt["fgets"]
data/lib/rubypwn.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require_relative 'basic'
2
2
  require_relative 'asm'
3
3
  require_relative 'netcat'
4
+ require_relative 'elf'
4
5
 
data/rubypwn.gemspec CHANGED
@@ -1,13 +1,13 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'rubypwn'
3
- s.version = '0.0.6'
3
+ s.version = '0.0.7'
4
4
  s.date = '2015-08-26'
5
5
  s.summary = "ruby pwn tools"
6
6
  s.description = <<-DESCRIPTION.strip.gsub(/\s+/, " ")
7
7
  A simple library for CTF pwning challenges.
8
8
  Like Python's pwntools, it's used to help you write exploit quickly.
9
9
  DESCRIPTION
10
- s.authors = ["Hung Chi Su"]
10
+ s.authors = ["atdog"]
11
11
  s.email = 'atdog.tw@gmail.com'
12
12
  s.files = `git ls-files`.split("\n")
13
13
  s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
@@ -16,4 +16,5 @@ Gem::Specification.new do |s|
16
16
  s.add_runtime_dependency 'rainbow', '~> 2.0', '>= 2.0.0'
17
17
  s.add_runtime_dependency 'thread', '~> 0.2', '>= 0.2.2'
18
18
  s.add_runtime_dependency 'rest-client', '~> 1.8', '>= 1.8.0'
19
+ s.add_runtime_dependency 'bindata', '~> 2.1', '>= 2.1.0'
19
20
  end
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubypwn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
- - Hung Chi Su
7
+ - atdog
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
@@ -70,6 +70,26 @@ dependencies:
70
70
  - - ">="
71
71
  - !ruby/object:Gem::Version
72
72
  version: 1.8.0
73
+ - !ruby/object:Gem::Dependency
74
+ name: bindata
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '2.1'
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 2.1.0
83
+ type: :runtime
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.1'
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 2.1.0
73
93
  description: A simple library for CTF pwning challenges. Like Python's pwntools, it's
74
94
  used to help you write exploit quickly.
75
95
  email: atdog.tw@gmail.com
@@ -90,6 +110,7 @@ files:
90
110
  - docs/source/index.rst
91
111
  - lib/asm.rb
92
112
  - lib/basic.rb
113
+ - lib/elf.rb
93
114
  - lib/exec.rb
94
115
  - lib/netcat.rb
95
116
  - lib/rubypwn.rb