#!/usr/bin/env ruby ## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## msf_base = __FILE__ while File.symlink?(msf_base) msf_base = File.expand_path(File.readlink(msf_base), File.dirname(msf_base)) end $:.unshift(File.expand_path(File.join(File.dirname(msf_base), '..', '..', 'lib'))) require 'rex/java/serialization' require 'pp' require 'optparse' # This class allows to deserialize Java Streams from # files class JavaDeserializer # @!attribute file # @return [String] the file's path to deserialize attr_accessor :file # @param file [String] the file's path to deserialize def initialize(file = nil) self.file = file end # Deserializes a Java stream from a file and prints the result. # # @return [Rex::Java::Serialization::Model::Stream] if succeeds # @return [nil] if error def run(options = {}) if file.nil? print_error("file path with serialized java stream required") return end print_status("Deserializing...") print_line begin f = File.new(file, 'rb') stream = Rex::Java::Serialization::Model::Stream.decode(f) f.close rescue ::Exception => e print_exception(e) return end if options[:array] print_array(stream.contents[options[:array].to_i]) elsif options[:object] print_object(stream.contents[options[:object].to_i]) else puts stream end end private # @param [String] string to print as status def print_status(msg='') $stdout.puts "[*] #{msg}" end # @param [String] string to print as error def print_error(msg='') $stdout.puts "[-] #{msg}" end # @param [Exception] exception to print def print_exception(e) print_error(e.message) e.backtrace.each do |line| $stdout.puts("\t#{line}") end end def print_line $stdout.puts("\n") end # @param [Rex::Java::Serialization::Model::NewObject] obj the object to print # @param [Integer] level the indentation level when printing super classes def print_object(obj, level = 0) prefix = " " * level if obj.class_desc.description.class == Rex::Java::Serialization::Model::NewClassDesc puts "#{prefix}Object Class Description:" print_class(obj.class_desc.description, level + 1) else puts "#{prefix}Object Class Description: #{obj.class_desc.description}" end puts "#{prefix}Object Data: #{obj.class_data}" end # @param [Rex::Java::Serialization::Model::NewClassDesc] c the class to print # @param [Integer] level the indentation level when printing super classes def print_class(c, level = 0) prefix = " " * level puts "#{prefix}Class Name: #{c.class_name}" puts "#{prefix}Serial Version: #{c.serial_version}" puts "#{prefix}Flags: #{c.flags}" puts "#{prefix}Fields ##{c.fields.length}" c.fields.each do |f| puts "#{prefix}Field: #{f}" end puts "#{prefix}Class Annotations ##{c.class_annotation.contents.length}" c.class_annotation.contents.each do |c| puts "#{prefix}Annotation: #{c}" end puts "#{prefix}Super Class: #{c.super_class}" if c.super_class.description.class == Rex::Java::Serialization::Model::NewClassDesc print_class(c.super_class.description, level + 1) end end # @param [Rex::Java::Serialization::Model::NewArray] arr the array to print # @param [Integer] level the indentation level when printing super classes def print_array(arr, level = 0) prefix = " " * level if arr.array_description.description.class == Rex::Java::Serialization::Model::NewClassDesc puts "#{prefix}Array Description" print_class(arr.array_description.description, 1) else puts "#{prefix}Array Description: #{arr.array_description.description}" end puts "#{prefix}Array Type: #{arr.type}" puts "#{prefix}Array Values ##{arr.values.length}" arr.values.each do |v| puts "Array value: #{prefix}#{v} (#{v.class})" if v.class == Rex::Java::Serialization::Model::NewObject print_object(v, level + 1) end end end end if __FILE__ == $PROGRAM_NAME options = {} OptionParser.new do |opts| opts.banner = "Usage: java_deserializer.rb [option]" opts.on("-aID", "--array=ID", "Print detailed information about content array") do |id| options[:array] = id end opts.on("-oID", "--object=ID", "Print detailed information about content object") do |id| options[:object] = id end opts.on("-h", "--help", "Prints this help") do puts opts exit end end.parse! if options.length > 1 $stdout.puts "[-] Don't provide more than one option" exit end deserializer = JavaDeserializer.new(ARGV[0]) deserializer.run(options) end