CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/tools/exploit/java_deserializer.rb
Views: 11768
1
#!/usr/bin/env ruby
2
3
##
4
# This module requires Metasploit: https://metasploit.com/download
5
# Current source: https://github.com/rapid7/metasploit-framework
6
##
7
begin
8
msf_base = __FILE__
9
while File.symlink?(msf_base)
10
msf_base = File.expand_path(File.readlink(msf_base), File.dirname(msf_base))
11
end
12
13
$:.unshift(File.expand_path(File.join(File.dirname(msf_base), '..', '..', 'lib')))
14
require 'rex/java/serialization'
15
require 'pp'
16
require 'optparse'
17
18
# This class allows to deserialize Java Streams from
19
# files
20
class JavaDeserializer
21
22
# @!attribute file
23
# @return [String] the file's path to deserialize
24
attr_accessor :file
25
26
# @param file [String] the file's path to deserialize
27
def initialize(file = nil)
28
self.file = file
29
end
30
31
# Deserializes a Java stream from a file and prints the result.
32
#
33
# @return [Rex::Java::Serialization::Model::Stream] if succeeds
34
# @return [nil] if error
35
def run(options = {})
36
if file.nil?
37
print_error("file path with serialized java stream required")
38
return
39
end
40
41
print_status("Deserializing...")
42
print_line
43
44
begin
45
f = File.new(file, 'rb')
46
stream = Rex::Java::Serialization::Model::Stream.decode(f)
47
f.close
48
rescue ::Exception => e
49
print_exception(e)
50
return
51
end
52
53
if options[:array]
54
print_array(stream.contents[options[:array].to_i])
55
elsif options[:object]
56
print_object(stream.contents[options[:object].to_i])
57
else
58
puts stream
59
end
60
end
61
62
private
63
64
# @param msg [String] String to print as a status message.
65
def print_status(msg='')
66
$stdout.puts "[*] #{msg}"
67
end
68
69
# @param msg [String] String to print as a error message.
70
def print_error(msg='')
71
$stdout.puts "[-] #{msg}"
72
end
73
74
# @param e [Exception] Exception to print
75
def print_exception(e)
76
print_error(e.message)
77
e.backtrace.each do |line|
78
$stdout.puts("\t#{line}")
79
end
80
end
81
82
def print_line
83
$stdout.puts("\n")
84
end
85
86
# @param [Rex::Java::Serialization::Model::NewObject] obj the object to print
87
# @param [Integer] level the indentation level when printing super classes
88
def print_object(obj, level = 0)
89
prefix = " " * level
90
if obj.class_desc.description.class == Rex::Java::Serialization::Model::NewClassDesc
91
puts "#{prefix}Object Class Description:"
92
print_class(obj.class_desc.description, level + 1)
93
else
94
puts "#{prefix}Object Class Description: #{obj.class_desc.description}"
95
end
96
puts "#{prefix}Object Data: #{obj.class_data}"
97
end
98
99
# @param [Rex::Java::Serialization::Model::NewClassDesc] c the class to print
100
# @param [Integer] level the indentation level when printing super classes
101
def print_class(c, level = 0)
102
prefix = " " * level
103
puts "#{prefix}Class Name: #{c.class_name}"
104
puts "#{prefix}Serial Version: #{c.serial_version}"
105
puts "#{prefix}Flags: #{c.flags}"
106
puts "#{prefix}Fields ##{c.fields.length}"
107
c.fields.each do |f|
108
puts "#{prefix}Field: #{f}"
109
end
110
puts "#{prefix}Class Annotations ##{c.class_annotation.contents.length}"
111
c.class_annotation.contents.each do |c|
112
puts "#{prefix}Annotation: #{c}"
113
end
114
puts "#{prefix}Super Class: #{c.super_class}"
115
if c.super_class.description.class == Rex::Java::Serialization::Model::NewClassDesc
116
print_class(c.super_class.description, level + 1)
117
end
118
end
119
120
# @param [Rex::Java::Serialization::Model::NewArray] arr the array to print
121
# @param [Integer] level the indentation level when printing super classes
122
def print_array(arr, level = 0)
123
prefix = " " * level
124
if arr.array_description.description.class == Rex::Java::Serialization::Model::NewClassDesc
125
puts "#{prefix}Array Description"
126
print_class(arr.array_description.description, 1)
127
else
128
puts "#{prefix}Array Description: #{arr.array_description.description}"
129
end
130
puts "#{prefix}Array Type: #{arr.type}"
131
puts "#{prefix}Array Values ##{arr.values.length}"
132
arr.values.each do |v|
133
puts "Array value: #{prefix}#{v} (#{v.class})"
134
if v.class == Rex::Java::Serialization::Model::NewObject
135
print_object(v, level + 1)
136
end
137
end
138
end
139
end
140
141
if __FILE__ == $PROGRAM_NAME
142
143
options = {}
144
OptionParser.new do |opts|
145
opts.banner = "Usage: java_deserializer.rb <file> [option]"
146
147
opts.on("-aID", "--array=ID", "Print detailed information about content array") do |id|
148
options[:array] = id
149
end
150
151
opts.on("-oID", "--object=ID", "Print detailed information about content object") do |id|
152
options[:object] = id
153
end
154
155
opts.on("-h", "--help", "Prints this help") do
156
puts opts
157
exit
158
end
159
end.parse!
160
161
if options.length > 1
162
$stdout.puts "[-] Don't provide more than one option"
163
exit
164
end
165
166
deserializer = JavaDeserializer.new(ARGV[0])
167
deserializer.run(options)
168
end
169
rescue SignalException => e
170
puts("Aborted! #{e}")
171
end
172
173