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.
- data/README.markdown +1 -1
- data/lib/rex/exploitation/javascriptosdetect.rb +3 -22
- data/lib/rex/exploitation/jsobfu.rb +489 -0
- data/lib/rex/io/stream_abstraction.rb +4 -3
- data/lib/rex/parser/acunetix_nokogiri.rb +394 -0
- data/lib/rex/parser/appscan_nokogiri.rb +366 -0
- data/lib/rex/parser/burp_session_nokogiri.rb +290 -0
- data/lib/rex/parser/nokogiri_doc_mixin.rb +5 -3
- data/lib/rex/pescan/scanner.rb +2 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/constants.rb +2 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_netapi32.rb +5 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb +30 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/remote_registry_key.rb +188 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb +1 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +84 -14
- data/lib/rex/proto/http/header.rb +3 -3
- data/lib/rex/ropbuilder.rb +7 -0
- data/lib/rex/ropbuilder/rop.rb +257 -0
- data/lib/rex/ui/text/table.rb +9 -0
- metadata +10 -3
@@ -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" => [
|
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
|
275
|
-
value
|
276
|
-
data
|
277
|
-
type
|
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
|
-
|
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 =
|
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
|
-
|
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 =
|
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 =
|
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 =
|
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 =
|
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
|
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+/
|
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/
|
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,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
|