librex 0.0.35 → 0.0.36

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.
@@ -89,6 +89,7 @@ TLV_TYPE_KEY_NAME = TLV_META_TYPE_STRING | 1003
89
89
  TLV_TYPE_VALUE_NAME = TLV_META_TYPE_STRING | 1010
90
90
  TLV_TYPE_VALUE_TYPE = TLV_META_TYPE_UINT | 1011
91
91
  TLV_TYPE_VALUE_DATA = TLV_META_TYPE_RAW | 1012
92
+ TLV_TYPE_TARGET_HOST = TLV_META_TYPE_STRING | 1013
92
93
 
93
94
  # Config
94
95
  TLV_TYPE_COMPUTER_NAME = TLV_META_TYPE_STRING | 1040
@@ -37,10 +37,12 @@ class Console::CommandDispatcher::Stdapi::Sys
37
37
  #
38
38
  @@reg_opts = Rex::Parser::Arguments.new(
39
39
  "-d" => [ true, "The data to store in the registry value." ],
40
- "-h" => [ true, "Help menu." ],
40
+ "-h" => [ false, "Help menu." ],
41
41
  "-k" => [ true, "The registry key path (E.g. HKLM\\Software\\Foo)." ],
42
42
  "-t" => [ true, "The registry value type (E.g. REG_SZ)." ],
43
- "-v" => [ true, "The registry value name (E.g. Stuff)." ])
43
+ "-v" => [ true, "The registry value name (E.g. Stuff)." ],
44
+ "-r" => [ true, "The remote machine name to connect to (with current process credentials" ],
45
+ "-w" => [ false, "Set KEY_WOW64 flag, valid values [32|64]." ])
44
46
 
45
47
  #
46
48
  # List of supported commands.
@@ -271,10 +273,12 @@ class Console::CommandDispatcher::Stdapi::Sys
271
273
  end
272
274
 
273
275
  # Initiailze vars
274
- key = nil
275
- value = nil
276
- data = nil
277
- type = nil
276
+ key = nil
277
+ value = nil
278
+ data = nil
279
+ type = nil
280
+ wowflag = 0x0000
281
+ rem = nil
278
282
 
279
283
  @@reg_opts.parse(args) { |opt, idx, val|
280
284
  case opt
@@ -290,7 +294,7 @@ class Console::CommandDispatcher::Stdapi::Sys
290
294
  " queryclass Queries the class of the supplied key [-k <key>]\n" +
291
295
  " setval Set a registry value [-k <key> -v <val> -d <data>]\n" +
292
296
  " deleteval Delete the supplied registry value [-k <key> -v <val>]\n" +
293
- " queryval Queries the data contents of a value [-k <key> -v <val>]\n\n")
297
+ " queryval Queries the data contents of a value [-k <key> -v <val>]\n\n")
294
298
  return false
295
299
  when "-k"
296
300
  key = val
@@ -300,6 +304,14 @@ class Console::CommandDispatcher::Stdapi::Sys
300
304
  type = val
301
305
  when "-d"
302
306
  data = val
307
+ when "-r"
308
+ rem = val
309
+ when "-w"
310
+ if val == '64'
311
+ wowflag = KEY_WOW64_64KEY
312
+ elsif val == '32'
313
+ wowflag = KEY_WOW64_32KEY
314
+ end
303
315
  end
304
316
  }
305
317
 
@@ -316,7 +328,16 @@ class Console::CommandDispatcher::Stdapi::Sys
316
328
  # Rock it
317
329
  case cmd
318
330
  when "enumkey"
319
- open_key = client.sys.registry.open_key(root_key, base_key)
331
+
332
+ open_key = nil
333
+ if not rem
334
+ open_key = client.sys.registry.open_key(root_key, base_key, KEY_READ + wowflag)
335
+ else
336
+ remote_key = client.sys.registry.open_remote_key(rem, root_key)
337
+ if remote_key
338
+ open_key = remote_key.open_key(base_key, KEY_READ + wowflag)
339
+ end
340
+ end
320
341
 
321
342
  print_line(
322
343
  "Enumerating: #{key}\n")
@@ -349,12 +370,29 @@ class Console::CommandDispatcher::Stdapi::Sys
349
370
  end
350
371
 
351
372
  when "createkey"
352
- open_key = client.sys.registry.create_key(root_key, base_key)
373
+ open_key = nil
374
+ if not rem
375
+ open_key = client.sys.registry.create_key(root_key, base_key, KEY_WRITE + wowflag)
376
+ else
377
+ remote_key = client.sys.registry.open_remote_key(rem, root_key)
378
+ if remote_key
379
+ open_key = remote_key.create_key(base_key, KEY_WRITE + wowflag)
380
+ end
381
+ end
353
382
 
354
383
  print_line("Successfully created key: #{key}")
355
384
 
356
385
  when "deletekey"
357
- client.sys.registry.delete_key(root_key, base_key)
386
+ open_key = nil
387
+ if not rem
388
+ open_key = client.sys.registry.open_key(root_key, base_key, KEY_WRITE + wowflag)
389
+ else
390
+ remote_key = client.sys.registry.open_remote_key(rem, root_key)
391
+ if remote_key
392
+ open_key = remote_key.open_key(base_key, KEY_WRITE + wowflag)
393
+ end
394
+ end
395
+ open_key.delete_key(base_key)
358
396
 
359
397
  print_line("Successfully deleted key: #{key}")
360
398
 
@@ -366,7 +404,15 @@ class Console::CommandDispatcher::Stdapi::Sys
366
404
 
367
405
  type = "REG_SZ" if (type == nil)
368
406
 
369
- open_key = client.sys.registry.open_key(root_key, base_key, KEY_WRITE)
407
+ open_key = nil
408
+ if not rem
409
+ open_key = client.sys.registry.open_key(root_key, base_key, KEY_WRITE + wowflag)
410
+ else
411
+ remote_key = client.sys.registry.open_remote_key(rem, root_key)
412
+ if remote_key
413
+ open_key = remote_key.open_key(base_key, KEY_WRITE + wowflag)
414
+ end
415
+ end
370
416
 
371
417
  open_key.set_value(value, client.sys.registry.type2str(type), data)
372
418
 
@@ -378,7 +424,15 @@ class Console::CommandDispatcher::Stdapi::Sys
378
424
  return false
379
425
  end
380
426
 
381
- open_key = client.sys.registry.open_key(root_key, base_key, KEY_WRITE)
427
+ open_key = nil
428
+ if not rem
429
+ open_key = client.sys.registry.open_key(root_key, base_key, KEY_WRITE + wowflag)
430
+ else
431
+ remote_key = client.sys.registry.open_remote_key(rem, root_key)
432
+ if remote_key
433
+ open_key = remote_key.open_key(base_key, KEY_WRITE + wowflag)
434
+ end
435
+ end
382
436
 
383
437
  open_key.delete_value(value)
384
438
 
@@ -390,7 +444,15 @@ class Console::CommandDispatcher::Stdapi::Sys
390
444
  return false
391
445
  end
392
446
 
393
- open_key = client.sys.registry.open_key(root_key, base_key, KEY_READ)
447
+ open_key = nil
448
+ if not rem
449
+ open_key = client.sys.registry.open_key(root_key, base_key, KEY_READ + wowflag)
450
+ else
451
+ remote_key = client.sys.registry.open_remote_key(rem, root_key)
452
+ if remote_key
453
+ open_key = remote_key.open_key(base_key, KEY_READ + wowflag)
454
+ end
455
+ end
394
456
 
395
457
  v = open_key.query_value(value)
396
458
 
@@ -401,7 +463,15 @@ class Console::CommandDispatcher::Stdapi::Sys
401
463
  "Data: #{v.data}\n")
402
464
 
403
465
  when "queryclass"
404
- open_key = client.sys.registry.open_key(root_key, base_key, KEY_READ)
466
+ open_key = nil
467
+ if not rem
468
+ open_key = client.sys.registry.open_key(root_key, base_key, KEY_READ + wowflag)
469
+ else
470
+ remote_key = client.sys.registry.open_remote_key(rem, root_key)
471
+ if remote_key
472
+ open_key = remote_key.open_key(base_key, KEY_READ + wowflag)
473
+ end
474
+ end
405
475
 
406
476
  data = open_key.query_class
407
477
 
@@ -37,16 +37,16 @@ class Packet::Header < Hash
37
37
 
38
38
  # put the non-standard line terminations back to normal
39
39
  # gah. not having look behinds suck,
40
- header.gsub!(/([^\r])\n/,'\1' + "\r\n")
40
+ header.gsub!(/([^\r])\n/n,'\1' + "\r\n")
41
41
 
42
42
  # undo folding, kinda ugly but works for now.
43
- header.gsub!(/:\s*\r\n\s+/smi,': ')
43
+ header.gsub!(/:\s*\r\n\s+/smni,': ')
44
44
 
45
45
  # Extract the command string
46
46
  self.cmd_string = header.slice!(/.+\r\n/)
47
47
 
48
48
  # Extract each header value pair
49
- header.split(/\r\n/m).each { |str|
49
+ header.split(/\r\n/mn).each { |str|
50
50
  if (md = str.match(/^(.+?): (.+?)$/))
51
51
  if (self[md[1]])
52
52
  self[md[1]] << ", " + md[2]
@@ -0,0 +1,7 @@
1
+ module Rex
2
+ module RopBuilder
3
+
4
+ require 'rex/ropbuilder/rop'
5
+ require 'metasm/metasm'
6
+ end
7
+ end
@@ -0,0 +1,257 @@
1
+ require 'metasm'
2
+ require 'rex/compat'
3
+ require 'rex/ui/text/table'
4
+ require 'rex/ui/text/output/stdio'
5
+ require 'rex/ui/text/color'
6
+
7
+ module Rex
8
+ module RopBuilder
9
+
10
+ class RopBase
11
+ def initialize()
12
+ @stdio = Rex::Ui::Text::Output::Stdio.new
13
+ @gadgets = []
14
+ end
15
+
16
+ def to_csv(gadgets = [])
17
+ if gadgets.empty? and @gadgets.nil? or @gadgets.empty?
18
+ print_error("No gadgets collected to convert to CSV format.")
19
+ return
20
+ end
21
+
22
+ # allow the users to import gadget collections from multiple files
23
+ if @gadgets.empty? or @gadgets.nil?
24
+ @gadgets = gadgets
25
+ end
26
+
27
+ table = Rex::Ui::Text::Table.new(
28
+ 'Header' => "#{@file} ROP Gadgets",
29
+ 'Indent' => 1,
30
+ 'Columns' =>
31
+ [
32
+ "Address",
33
+ "Raw",
34
+ "Disassembly",
35
+ ])
36
+
37
+ @gadgets.each do |gadget|
38
+ table << [gadget[:address], gadget[:raw].unpack('H*')[0], gadget[:disasm].gsub(/\n/, ' | ')]
39
+ end
40
+
41
+ return table.to_csv
42
+ end
43
+
44
+ def import(file)
45
+ begin
46
+ data = File.new(file, 'r').read
47
+ rescue
48
+ print_error("Error reading #{file}")
49
+ end
50
+
51
+ data.gsub!(/\"/, '')
52
+ data.gsub!("Address,Raw,Disassembly\n", '')
53
+ @gadgets = []
54
+ data.each_line do |line|
55
+ addr, raw, disasm = line.split(',', 3)
56
+ disasm.gsub!(/: /, ":\t")
57
+ disasm.gsub!(' | ', "\n")
58
+ raw = [raw].pack('H*')
59
+ @gadgets << {:file => file, :address => addr, :raw => raw, :disasm => disasm.chomp!}
60
+ end
61
+ @gadgets
62
+ end
63
+
64
+ def print_msg(msg, color=true)
65
+ if not @stdio
66
+ @stdio = Rex::Ui::Text::Output::Stdio.new
67
+ end
68
+
69
+ if color == true
70
+ @stdio.auto_color
71
+ else
72
+ @stdio.disable_color
73
+ end
74
+ @stdio.print_raw(@stdio.substitute_colors(msg))
75
+ end
76
+ end
77
+
78
+ class RopCollect < RopBase
79
+ def initialize(file="")
80
+ @file = file if not file.empty?
81
+ @bin = Metasm::AutoExe.decode_file(file) if not file.empty?
82
+ @disassembler = @bin.disassembler if not @bin.nil?
83
+ if @disassembler
84
+ @disassembler.cpu = Metasm::Ia32.new('386_common')
85
+ end
86
+ super()
87
+ end
88
+
89
+ def collect(depth, pattern)
90
+ matches = []
91
+ gadgets = []
92
+
93
+ # find matches by scanning for the pattern
94
+ matches = @disassembler.pattern_scan(pattern)
95
+ if @bin.kind_of?(Metasm::PE)
96
+ @bin.sections.each do |section|
97
+ next if section.characteristics.include? 'MEM_EXECUTE'
98
+ # delete matches if the address is outside the virtual address space
99
+ matches.delete_if do |ea|
100
+ va = section.virtaddr + @bin.optheader.image_base
101
+ ea >= va and ea < va + section.virtsize
102
+ end
103
+ end
104
+ elsif @bin.kind_of?(Metasm::ELF)
105
+ @bin.segments.each do |seg|
106
+ next if seg.flags.include? 'X'
107
+ matches.delete_if do |ea|
108
+ ea >= seg.vaddr and ea < seg.vaddr + seg.memsz
109
+ end
110
+ end
111
+ elsif @bin.kind_of?(Metasm::MachO)
112
+ @bin.segments.each do |seg|
113
+ next if seg.initprot.include? 'EXECUTE'
114
+ matches.delete_if do |ea|
115
+ ea >= seg.virtaddr and ea < seg.virtaddr + seg.filesize
116
+ end
117
+ end
118
+ end
119
+
120
+ gadgets = process_gadgets(matches, depth)
121
+ gadgets.each do |gadget|
122
+ @gadgets << gadget
123
+ end
124
+ gadgets
125
+ end
126
+
127
+ def pattern_search(pattern)
128
+ p = Regexp.new("(" + pattern + ")")
129
+ matches = []
130
+
131
+ @gadgets.each do |gadget|
132
+ disasm = ""
133
+ addrs = []
134
+
135
+ gadget[:disasm].each_line do |line|
136
+ addr, asm = line.split("\t", 2)
137
+ addrs << addr
138
+ disasm << asm
139
+ end
140
+
141
+ if gadget[:raw] =~ p or gadget[:disasm] =~ p or disasm =~ p
142
+ matches << {:gadget => gadget, :disasm => disasm, :addrs => addrs}
143
+ end
144
+ end
145
+ matches.each do |match|
146
+ @stdio.print_status("gadget with address: %bld%cya#{match[:gadget][:address]}%clr matched")
147
+ color_pattern(match[:gadget], match[:disasm], match[:addrs], p)
148
+ end
149
+ matches
150
+ end
151
+
152
+ def color_pattern(gadget, disasm, addrs, p)
153
+ idx = disasm.index(p)
154
+ if idx.nil?
155
+ print_msg(gadget[:disasm])
156
+ return
157
+ end
158
+
159
+ disasm = disasm.insert(idx, "%bld%grn")
160
+
161
+ asm = ""
162
+ cnt = 0
163
+ colors = false
164
+ disasm.each_line do |line|
165
+ # if we find this then we are in the matching area
166
+ if line.index(/\%bld\%grn/)
167
+ colors = true
168
+ end
169
+ asm << "%clr" + addrs[cnt] + "\t"
170
+
171
+ # color the remaining parts of the gadget
172
+ if colors and line.index("%bld%grn").nil?
173
+ asm << "%bld%grn" + line
174
+ else
175
+ asm << line
176
+ end
177
+
178
+ cnt += 1
179
+ end
180
+ asm << "%clr\n"
181
+ print_msg(asm)
182
+ end
183
+
184
+ def process_gadgets(rets, num)
185
+ ret = {}
186
+ gadgets = []
187
+ tmp = []
188
+ rets.each do |ea|
189
+ insn = @disassembler.disassemble_instruction(ea)
190
+ next if not insn
191
+
192
+ xtra = insn.bin_length
193
+
194
+ 1.upto(num) do |x|
195
+ addr = ea - x
196
+
197
+ # get the disassembled instruction at this address
198
+ di = @disassembler.disassemble_instruction(addr)
199
+
200
+ # skip invalid instructions
201
+ next if not di
202
+ next if di.opcode.props[:setip]
203
+ next if di.opcode.props[:stopexec]
204
+
205
+ # get raw bytes
206
+ buf = @disassembler.read_raw_data(addr, x + xtra)
207
+
208
+
209
+ # make sure disassembling forward leads to our instruction
210
+ next if not ends_with_addr(buf, addr, ea)
211
+
212
+ dasm = ""
213
+ while addr <= ea
214
+ di = @disassembler.disassemble_instruction(addr)
215
+ dasm << ("0x%08x:\t" % addr) + di.instruction.to_s + "\n"
216
+ addr = addr + di.bin_length
217
+ end
218
+
219
+ if not tmp.include?(ea)
220
+ tmp << ea
221
+ else
222
+ next
223
+ end
224
+ # otherwise, we create a new tailchunk and add it to the list
225
+ ret = {:file => @file, :address => ("0x%08x" % (ea - x)), :raw => buf, :disasm => dasm}
226
+ gadgets << ret
227
+ end
228
+ end
229
+ gadgets
230
+ end
231
+
232
+ private
233
+ def ends_with_addr(raw, base, addr)
234
+ dasm2 = Metasm::Shellcode.decode(raw, @disassembler.cpu).disassembler
235
+ offset = 0
236
+ while ((di = dasm2.disassemble_instruction(offset)))
237
+ return true if (base + offset) == addr
238
+ return false if di.opcode.props[:setip]
239
+ return false if di.opcode.props[:stopexec]
240
+ offset = di.next_addr
241
+ end
242
+ false
243
+ end
244
+
245
+ def raw_instructions(raw)
246
+ insns = []
247
+ d2 = Metasm::Shellcode.decode(raw, @disassembler.cpu).disassembler
248
+ addr = 0
249
+ while ((di = d2.disassemble_instruction(addr)))
250
+ insns << di.instruction
251
+ addr = di.next_addr
252
+ end
253
+ insns
254
+ end
255
+ end
256
+ end
257
+ end