librex 0.0.35 → 0.0.36

Sign up to get free protection for your applications and to get access to all the features.
@@ -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