diff --git a/lib/msf/util/java_deserialization.rb b/lib/msf/util/java_deserialization.rb index df3316dfd2..4c214f7ff5 100644 --- a/lib/msf/util/java_deserialization.rb +++ b/lib/msf/util/java_deserialization.rb @@ -4,12 +4,12 @@ module Util require 'json' require 'base64' -PAYLOAD_FILENAME="ysoserial_payloads.json" - #TODO: Support ysoserial alongside ysoserial-modified payloads (including cmd, bash, powershell, none) class JavaDeserialization + PAYLOAD_FILENAME = "ysoserial_payloads.json" + def self.ysoserial_payload(payloadName, command=nil) # Open the JSON file and parse it begin diff --git a/spec/lib/msf/util/java_deserialization_spec.rb b/spec/lib/msf/util/java_deserialization_spec.rb new file mode 100644 index 0000000000..409947d87e --- /dev/null +++ b/spec/lib/msf/util/java_deserialization_spec.rb @@ -0,0 +1,80 @@ +require 'rex' +require 'msf/util/java_deserialization' + +RSpec.describe Msf::Util::JavaDeserialization do + let(:payload_name) do + 'PAYLOAD_NAME' + end + + let(:default_command) do + nil + end + + describe '#ysoserial_payload' do + context 'when default payload name is changed' do + it 'raises a RuntimeError' do + payload_filename_constant = Msf::Util::JavaDeserialization.const_get(:PAYLOAD_FILENAME) + Msf::Util::JavaDeserialization.const_set(:PAYLOAD_FILENAME, 'INVALID') + expect{Msf::Util::JavaDeserialization::ysoserial_payload(payload_name, default_command)}.to raise_error(RuntimeError) + Msf::Util::JavaDeserialization.const_set(:PAYLOAD_FILENAME, payload_filename_constant) + end + end + + context 'when default payload is not found' do + it 'raises a RuntimeError' do + allow(File).to receive(:join).and_return('INVALID') + expect{Msf::Util::JavaDeserialization::ysoserial_payload(payload_name, default_command)}.to raise_error(RuntimeError) + end + end + + context 'when default payload is not JSON format' do + it 'raises a JSON::ParserError error' do + allow(File).to receive(:read).and_return('BAD DATA') + expect{Msf::Util::JavaDeserialization::ysoserial_payload(payload_name, default_command)}.to raise_error(JSON::ParserError) + end + end + + context 'when payload status is unsupported' do + it 'raises a unsupported error' do + json_data = %Q|{"BeanShell1":{"status":"unsupported","bytes":"AAAA"}}| + allow(File).to receive(:read).and_return(json_data) + expect{Msf::Util::JavaDeserialization::ysoserial_payload(payload_name, default_command)}.to raise_error(ArgumentError) + end + end + + context 'when payload status is static' do + let(:payload_name) do + 'BeanShell1' + end + + it 'returns a Base64 string' do + original_bytes = 'AAAA' + b64 = Rex::Text.encode_base64(original_bytes) + json_data = %Q|{"BeanShell1":{"status":"static","bytes":"#{b64}"}}| + allow(File).to receive(:read).and_return(json_data) + p = Msf::Util::JavaDeserialization::ysoserial_payload(payload_name, default_command) + expect(p).to eq(original_bytes) + end + end + + context 'when payload status is dynamic' do + let(:payload_name) do + 'BeanShell1' + end + + context 'when missing a command' do + it 'raises an argument error' do + expect{Msf::Util::JavaDeserialization::ysoserial_payload(payload_name, default_command)}.to raise_error(ArgumentError) + end + end + + context 'when a command is provided' do + it 'returns serialized data' do + default_command = 'id' + p = Msf::Util::JavaDeserialization::ysoserial_payload(payload_name, default_command) + expect(p).to include('java.awt.event') + end + end + end + end +end